2021-03-10 11:51:53 +08:00
|
|
|
/*
|
|
|
|
|
Copyright 2021 The KubeVela Authors.
|
|
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
|
limitations under the License.
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
2021-03-10 10:44:58 +08:00
|
|
|
package utils
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"fmt"
|
|
|
|
|
"regexp"
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
"cuelang.org/go/cue"
|
2021-04-08 20:35:21 +08:00
|
|
|
"cuelang.org/go/cue/build"
|
2021-03-10 10:44:58 +08:00
|
|
|
"github.com/getkin/kin-openapi/openapi3"
|
2021-03-26 23:02:58 +08:00
|
|
|
"github.com/pkg/errors"
|
2021-03-10 10:44:58 +08:00
|
|
|
v1 "k8s.io/api/core/v1"
|
|
|
|
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
|
"k8s.io/utils/pointer"
|
|
|
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
|
|
|
|
2021-03-24 13:27:29 +08:00
|
|
|
commontypes "github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
2021-04-09 12:28:04 +08:00
|
|
|
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
2021-03-10 10:44:58 +08:00
|
|
|
"github.com/oam-dev/kubevela/apis/types"
|
2021-04-11 14:10:16 +08:00
|
|
|
"github.com/oam-dev/kubevela/pkg/appfile"
|
2021-03-23 00:16:17 +08:00
|
|
|
"github.com/oam-dev/kubevela/pkg/appfile/helm"
|
2021-06-02 15:37:06 +08:00
|
|
|
velacue "github.com/oam-dev/kubevela/pkg/cue"
|
|
|
|
|
"github.com/oam-dev/kubevela/pkg/cue/packages"
|
2021-03-10 10:44:58 +08:00
|
|
|
"github.com/oam-dev/kubevela/pkg/oam/util"
|
|
|
|
|
"github.com/oam-dev/kubevela/pkg/utils/common"
|
|
|
|
|
)
|
|
|
|
|
|
2021-03-29 17:20:33 +08:00
|
|
|
// ErrNoSectionParameterInCue means there is not parameter section in Cue template of a workload
|
|
|
|
|
const ErrNoSectionParameterInCue = "capability %s doesn't contain section `parameter`"
|
|
|
|
|
|
2021-03-10 10:44:58 +08:00
|
|
|
// CapabilityDefinitionInterface is the interface for Capability (WorkloadDefinition and TraitDefinition)
|
|
|
|
|
type CapabilityDefinitionInterface interface {
|
2021-03-29 17:20:33 +08:00
|
|
|
GetCapabilityObject(ctx context.Context, k8sClient client.Client, namespace, name string) (*types.Capability, error)
|
|
|
|
|
GetOpenAPISchema(ctx context.Context, k8sClient client.Client, namespace, name string) ([]byte, error)
|
2021-03-10 10:44:58 +08:00
|
|
|
}
|
|
|
|
|
|
2021-03-15 11:08:46 +08:00
|
|
|
// CapabilityComponentDefinition is the struct for ComponentDefinition
|
|
|
|
|
type CapabilityComponentDefinition struct {
|
2021-04-09 12:28:04 +08:00
|
|
|
Name string `json:"name"`
|
|
|
|
|
ComponentDefinition v1beta1.ComponentDefinition `json:"componentDefinition"`
|
2021-03-17 17:18:54 +08:00
|
|
|
|
|
|
|
|
WorkloadType util.WorkloadType `json:"workloadType"`
|
|
|
|
|
WorkloadDefName string `json:"workloadDefName"`
|
|
|
|
|
|
2021-03-24 13:27:29 +08:00
|
|
|
Helm *commontypes.Helm `json:"helm"`
|
2021-03-26 23:02:58 +08:00
|
|
|
Kube *commontypes.Kube `json:"kube"`
|
2021-03-10 10:44:58 +08:00
|
|
|
CapabilityBaseDefinition
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-17 22:47:57 +08:00
|
|
|
// NewCapabilityComponentDef will create a CapabilityComponentDefinition
|
|
|
|
|
func NewCapabilityComponentDef(componentDefinition *v1beta1.ComponentDefinition) CapabilityComponentDefinition {
|
|
|
|
|
var def CapabilityComponentDefinition
|
|
|
|
|
def.Name = componentDefinition.Name
|
|
|
|
|
if componentDefinition.Spec.Workload.Definition == (commontypes.WorkloadGVK{}) && componentDefinition.Spec.Workload.Type != "" {
|
|
|
|
|
def.WorkloadType = util.ReferWorkload
|
|
|
|
|
def.WorkloadDefName = componentDefinition.Spec.Workload.Type
|
|
|
|
|
}
|
|
|
|
|
if componentDefinition.Spec.Schematic != nil && componentDefinition.Spec.Schematic.HELM != nil {
|
|
|
|
|
def.WorkloadType = util.HELMDef
|
|
|
|
|
def.Helm = componentDefinition.Spec.Schematic.HELM
|
|
|
|
|
}
|
|
|
|
|
if componentDefinition.Spec.Schematic != nil && componentDefinition.Spec.Schematic.KUBE != nil {
|
|
|
|
|
def.WorkloadType = util.KubeDef
|
|
|
|
|
def.Kube = componentDefinition.Spec.Schematic.KUBE
|
|
|
|
|
}
|
|
|
|
|
def.ComponentDefinition = *componentDefinition.DeepCopy()
|
|
|
|
|
return def
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-10 10:44:58 +08:00
|
|
|
// GetOpenAPISchema gets OpenAPI v3 schema by WorkloadDefinition name
|
2021-06-02 15:37:06 +08:00
|
|
|
func (def *CapabilityComponentDefinition) GetOpenAPISchema(pd *packages.PackageDiscover, name string) ([]byte, error) {
|
2021-05-23 14:16:06 +08:00
|
|
|
capability, err := appfile.ConvertTemplateJSON2Object(name, def.ComponentDefinition.Spec.Extension, def.ComponentDefinition.Spec.Schematic)
|
2021-03-10 10:44:58 +08:00
|
|
|
if err != nil {
|
2021-05-23 14:16:06 +08:00
|
|
|
return nil, fmt.Errorf("failed to convert ComponentDefinition to Capability Object")
|
2021-03-10 10:44:58 +08:00
|
|
|
}
|
2021-05-23 14:16:06 +08:00
|
|
|
return getOpenAPISchema(capability, pd)
|
2021-03-10 10:44:58 +08:00
|
|
|
}
|
|
|
|
|
|
2021-05-26 21:16:40 +08:00
|
|
|
// GetKubeSchematicOpenAPISchema gets OpenAPI v3 schema based on kube schematic parameters for component and trait definition
|
|
|
|
|
func GetKubeSchematicOpenAPISchema(params []commontypes.KubeParameter) ([]byte, error) {
|
2021-03-26 23:02:58 +08:00
|
|
|
required := []string{}
|
|
|
|
|
properties := map[string]*openapi3.Schema{}
|
|
|
|
|
for _, p := range params {
|
|
|
|
|
var tmp *openapi3.Schema
|
|
|
|
|
switch p.ValueType {
|
|
|
|
|
case commontypes.StringType:
|
|
|
|
|
tmp = openapi3.NewStringSchema()
|
|
|
|
|
case commontypes.NumberType:
|
|
|
|
|
tmp = openapi3.NewFloat64Schema()
|
|
|
|
|
case commontypes.BooleanType:
|
|
|
|
|
tmp = openapi3.NewBoolSchema()
|
|
|
|
|
default:
|
|
|
|
|
tmp = openapi3.NewStringSchema()
|
|
|
|
|
}
|
|
|
|
|
if p.Required != nil && *p.Required {
|
|
|
|
|
required = append(required, p.Name)
|
|
|
|
|
}
|
2021-05-26 21:16:40 +08:00
|
|
|
|
2021-03-26 23:02:58 +08:00
|
|
|
if p.Description != nil {
|
2021-05-26 21:16:40 +08:00
|
|
|
tmp.Description = fmt.Sprintf("%s %s", tmp.Description, *p.Description)
|
|
|
|
|
} else {
|
|
|
|
|
// save FieldPaths into description
|
|
|
|
|
tmp.Description = fmt.Sprintf("The value will be applied to fields: [%s].", strings.Join(p.FieldPaths, ","))
|
2021-03-26 23:02:58 +08:00
|
|
|
}
|
|
|
|
|
properties[p.Name] = tmp
|
|
|
|
|
}
|
|
|
|
|
s := openapi3.NewObjectSchema().WithProperties(properties)
|
|
|
|
|
if len(required) > 0 {
|
|
|
|
|
s.Required = required
|
|
|
|
|
}
|
|
|
|
|
b, err := s.MarshalJSON()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, errors.Wrap(err, "cannot marshal generated schema into json")
|
|
|
|
|
}
|
|
|
|
|
return b, nil
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-10 10:44:58 +08:00
|
|
|
// StoreOpenAPISchema stores OpenAPI v3 schema in ConfigMap from WorkloadDefinition
|
2021-04-26 10:07:55 +08:00
|
|
|
func (def *CapabilityComponentDefinition) StoreOpenAPISchema(ctx context.Context, k8sClient client.Client,
|
2021-06-02 15:37:06 +08:00
|
|
|
pd *packages.PackageDiscover, namespace, name, revName string) (string, error) {
|
2021-03-23 00:16:17 +08:00
|
|
|
var jsonSchema []byte
|
|
|
|
|
var err error
|
|
|
|
|
switch def.WorkloadType {
|
|
|
|
|
case util.HELMDef:
|
|
|
|
|
jsonSchema, err = helm.GetChartValuesJSONSchema(ctx, def.Helm)
|
2021-03-26 23:02:58 +08:00
|
|
|
case util.KubeDef:
|
2021-05-26 21:16:40 +08:00
|
|
|
jsonSchema, err = GetKubeSchematicOpenAPISchema(def.Kube.Parameters)
|
2021-03-23 00:16:17 +08:00
|
|
|
default:
|
2021-05-23 14:16:06 +08:00
|
|
|
jsonSchema, err = def.GetOpenAPISchema(pd, name)
|
2021-03-23 00:16:17 +08:00
|
|
|
}
|
2021-03-10 10:44:58 +08:00
|
|
|
if err != nil {
|
2021-05-23 14:16:06 +08:00
|
|
|
return "", fmt.Errorf("failed to generate OpenAPI v3 JSON schema for capability %s: %w", def.Name, err)
|
2021-03-10 10:44:58 +08:00
|
|
|
}
|
2021-03-15 11:08:46 +08:00
|
|
|
componentDefinition := def.ComponentDefinition
|
2021-03-10 10:44:58 +08:00
|
|
|
ownerReference := []metav1.OwnerReference{{
|
2021-03-15 11:08:46 +08:00
|
|
|
APIVersion: componentDefinition.APIVersion,
|
|
|
|
|
Kind: componentDefinition.Kind,
|
|
|
|
|
Name: componentDefinition.Name,
|
|
|
|
|
UID: componentDefinition.GetUID(),
|
2021-03-10 10:44:58 +08:00
|
|
|
Controller: pointer.BoolPtr(true),
|
|
|
|
|
BlockOwnerDeletion: pointer.BoolPtr(true),
|
|
|
|
|
}}
|
2021-03-15 11:08:46 +08:00
|
|
|
cmName, err := def.CreateOrUpdateConfigMap(ctx, k8sClient, namespace, componentDefinition.Name, jsonSchema, ownerReference)
|
|
|
|
|
if err != nil {
|
2021-05-23 14:16:06 +08:00
|
|
|
return cmName, err
|
2021-03-15 11:08:46 +08:00
|
|
|
}
|
2021-04-26 10:07:55 +08:00
|
|
|
|
|
|
|
|
_, err = def.CreateOrUpdateConfigMap(ctx, k8sClient, namespace, revName, jsonSchema, ownerReference)
|
|
|
|
|
if err != nil {
|
2021-05-23 14:16:06 +08:00
|
|
|
return cmName, err
|
2021-04-26 10:07:55 +08:00
|
|
|
}
|
2021-05-23 14:16:06 +08:00
|
|
|
return cmName, nil
|
2021-03-10 10:44:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CapabilityTraitDefinition is the Capability struct for TraitDefinition
|
|
|
|
|
type CapabilityTraitDefinition struct {
|
2021-04-26 10:07:55 +08:00
|
|
|
Name string `json:"name"`
|
|
|
|
|
TraitDefinition v1beta1.TraitDefinition `json:"traitDefinition"`
|
2021-05-26 21:16:40 +08:00
|
|
|
|
|
|
|
|
DefCategoryType util.WorkloadType `json:"defCategoryType"`
|
|
|
|
|
|
|
|
|
|
Kube *commontypes.Kube `json:"kube"`
|
|
|
|
|
|
2021-03-10 10:44:58 +08:00
|
|
|
CapabilityBaseDefinition
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-26 21:16:40 +08:00
|
|
|
// NewCapabilityTraitDef will create a CapabilityTraitDefinition
|
|
|
|
|
func NewCapabilityTraitDef(traitdefinition *v1beta1.TraitDefinition) CapabilityTraitDefinition {
|
|
|
|
|
var def CapabilityTraitDefinition
|
|
|
|
|
def.Name = traitdefinition.Name // or def.Name = req.NamespacedName.Name
|
|
|
|
|
if traitdefinition.Spec.Schematic != nil && traitdefinition.Spec.Schematic.KUBE != nil {
|
|
|
|
|
def.DefCategoryType = util.KubeDef
|
|
|
|
|
def.Kube = traitdefinition.Spec.Schematic.KUBE
|
|
|
|
|
}
|
|
|
|
|
def.TraitDefinition = *traitdefinition.DeepCopy()
|
|
|
|
|
return def
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-10 10:44:58 +08:00
|
|
|
// GetOpenAPISchema gets OpenAPI v3 schema by TraitDefinition name
|
2021-06-02 15:37:06 +08:00
|
|
|
func (def *CapabilityTraitDefinition) GetOpenAPISchema(pd *packages.PackageDiscover, name string) ([]byte, error) {
|
2021-05-23 14:16:06 +08:00
|
|
|
capability, err := appfile.ConvertTemplateJSON2Object(name, def.TraitDefinition.Spec.Extension, def.TraitDefinition.Spec.Schematic)
|
2021-03-10 10:44:58 +08:00
|
|
|
if err != nil {
|
2021-05-23 14:16:06 +08:00
|
|
|
return nil, fmt.Errorf("failed to convert WorkloadDefinition to Capability Object")
|
2021-03-10 10:44:58 +08:00
|
|
|
}
|
2021-05-23 14:16:06 +08:00
|
|
|
return getOpenAPISchema(capability, pd)
|
2021-03-10 10:44:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// StoreOpenAPISchema stores OpenAPI v3 schema from TraitDefinition in ConfigMap
|
2021-06-02 15:37:06 +08:00
|
|
|
func (def *CapabilityTraitDefinition) StoreOpenAPISchema(ctx context.Context, k8sClient client.Client, pd *packages.PackageDiscover, namespace, name string, revName string) (string, error) {
|
2021-05-26 21:16:40 +08:00
|
|
|
var jsonSchema []byte
|
|
|
|
|
var err error
|
|
|
|
|
switch def.DefCategoryType {
|
|
|
|
|
case util.KubeDef: // Kube template
|
|
|
|
|
jsonSchema, err = GetKubeSchematicOpenAPISchema(def.Kube.Parameters)
|
|
|
|
|
default: // CUE template
|
|
|
|
|
jsonSchema, err = def.GetOpenAPISchema(pd, name)
|
|
|
|
|
}
|
2021-03-10 10:44:58 +08:00
|
|
|
if err != nil {
|
2021-05-26 21:16:40 +08:00
|
|
|
return "", fmt.Errorf("failed to generate OpenAPI v3 JSON schema for capability %s: %w", def.Name, err)
|
2021-03-10 10:44:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
traitDefinition := def.TraitDefinition
|
|
|
|
|
ownerReference := []metav1.OwnerReference{{
|
|
|
|
|
APIVersion: traitDefinition.APIVersion,
|
|
|
|
|
Kind: traitDefinition.Kind,
|
|
|
|
|
Name: traitDefinition.Name,
|
|
|
|
|
UID: traitDefinition.GetUID(),
|
|
|
|
|
Controller: pointer.BoolPtr(true),
|
|
|
|
|
BlockOwnerDeletion: pointer.BoolPtr(true),
|
|
|
|
|
}}
|
2021-03-15 11:08:46 +08:00
|
|
|
cmName, err := def.CreateOrUpdateConfigMap(ctx, k8sClient, namespace, traitDefinition.Name, jsonSchema, ownerReference)
|
|
|
|
|
if err != nil {
|
2021-05-23 14:16:06 +08:00
|
|
|
return cmName, err
|
2021-03-15 11:08:46 +08:00
|
|
|
}
|
|
|
|
|
def.TraitDefinition.Status.ConfigMapRef = cmName
|
2021-05-23 14:16:06 +08:00
|
|
|
|
|
|
|
|
_, err = def.CreateOrUpdateConfigMap(ctx, k8sClient, namespace, revName, jsonSchema, ownerReference)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return cmName, err
|
|
|
|
|
}
|
|
|
|
|
return cmName, nil
|
2021-03-10 10:44:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CapabilityBaseDefinition is the base struct for CapabilityWorkloadDefinition and CapabilityTraitDefinition
|
|
|
|
|
type CapabilityBaseDefinition struct {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CreateOrUpdateConfigMap creates ConfigMap to store OpenAPI v3 schema or or updates data in ConfigMap
|
2021-05-23 14:16:06 +08:00
|
|
|
func (def *CapabilityBaseDefinition) CreateOrUpdateConfigMap(ctx context.Context, k8sClient client.Client, namespace,
|
|
|
|
|
definitionName string, jsonSchema []byte, ownerReferences []metav1.OwnerReference) (string, error) {
|
2021-03-10 10:44:58 +08:00
|
|
|
cmName := fmt.Sprintf("%s%s", types.CapabilityConfigMapNamePrefix, definitionName)
|
|
|
|
|
var cm v1.ConfigMap
|
|
|
|
|
var data = map[string]string{
|
|
|
|
|
types.OpenapiV3JSONSchema: string(jsonSchema),
|
|
|
|
|
}
|
|
|
|
|
// No need to check the existence of namespace, if it doesn't exist, API server will return the error message
|
2021-04-26 10:07:55 +08:00
|
|
|
// before it's to be reconciled by ComponentDefinition/TraitDefinition controller.
|
2021-03-10 10:44:58 +08:00
|
|
|
err := k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: cmName}, &cm)
|
|
|
|
|
if err != nil && apierrors.IsNotFound(err) {
|
|
|
|
|
cm = v1.ConfigMap{
|
|
|
|
|
TypeMeta: metav1.TypeMeta{
|
|
|
|
|
APIVersion: "v1",
|
|
|
|
|
Kind: "ConfigMap",
|
|
|
|
|
},
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: cmName,
|
|
|
|
|
Namespace: namespace,
|
|
|
|
|
OwnerReferences: ownerReferences,
|
|
|
|
|
Labels: map[string]string{
|
2021-05-18 21:10:47 +08:00
|
|
|
"definition.oam.dev": "schema",
|
|
|
|
|
"definition.oam.dev/name": definitionName,
|
2021-03-10 10:44:58 +08:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
Data: data,
|
|
|
|
|
}
|
|
|
|
|
err = k8sClient.Create(ctx, &cm)
|
|
|
|
|
if err != nil {
|
2021-03-15 11:08:46 +08:00
|
|
|
return cmName, fmt.Errorf(util.ErrUpdateCapabilityInConfigMap, definitionName, err)
|
2021-03-10 10:44:58 +08:00
|
|
|
}
|
2021-03-15 11:08:46 +08:00
|
|
|
return cmName, nil
|
2021-03-10 10:44:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cm.Data = data
|
|
|
|
|
if err = k8sClient.Update(ctx, &cm); err != nil {
|
2021-03-15 11:08:46 +08:00
|
|
|
return cmName, fmt.Errorf(util.ErrUpdateCapabilityInConfigMap, definitionName, err)
|
2021-03-10 10:44:58 +08:00
|
|
|
}
|
2021-03-15 11:08:46 +08:00
|
|
|
return cmName, nil
|
2021-03-10 10:44:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// getDefinition is the main function for GetDefinition API
|
2021-06-02 15:37:06 +08:00
|
|
|
func getOpenAPISchema(capability types.Capability, pd *packages.PackageDiscover) ([]byte, error) {
|
2021-04-08 20:35:21 +08:00
|
|
|
openAPISchema, err := generateOpenAPISchemaFromCapabilityParameter(capability, pd)
|
2021-03-10 10:44:58 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2021-03-29 17:20:33 +08:00
|
|
|
schema, err := ConvertOpenAPISchema2SwaggerObject(openAPISchema)
|
2021-03-10 10:44:58 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
fixOpenAPISchema("", schema)
|
|
|
|
|
|
|
|
|
|
parameter, err := schema.MarshalJSON()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return parameter, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// generateOpenAPISchemaFromCapabilityParameter returns the parameter of a definition in cue.Value format
|
2021-06-02 15:37:06 +08:00
|
|
|
func generateOpenAPISchemaFromCapabilityParameter(capability types.Capability, pd *packages.PackageDiscover) ([]byte, error) {
|
2021-04-08 20:35:21 +08:00
|
|
|
template, err := prepareParameterCue(capability.Name, capability.CueTemplate)
|
2021-03-10 10:44:58 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2021-04-09 12:28:04 +08:00
|
|
|
|
2021-06-02 15:37:06 +08:00
|
|
|
template += velacue.BaseTemplate
|
2021-04-08 20:35:21 +08:00
|
|
|
if pd == nil {
|
|
|
|
|
var r cue.Runtime
|
2021-04-09 12:28:04 +08:00
|
|
|
cueInst, err := r.Compile("-", template)
|
2021-04-08 20:35:21 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2021-04-09 12:28:04 +08:00
|
|
|
return common.GenOpenAPI(cueInst)
|
|
|
|
|
}
|
|
|
|
|
bi := build.NewContext().NewInstance("", nil)
|
|
|
|
|
err = bi.AddFile("-", template)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2021-03-10 10:44:58 +08:00
|
|
|
|
2021-04-09 20:15:02 +08:00
|
|
|
cueInst, err := pd.ImportPackagesAndBuildInstance(bi)
|
2021-04-09 12:28:04 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
2021-03-10 10:44:58 +08:00
|
|
|
}
|
|
|
|
|
return common.GenOpenAPI(cueInst)
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-08 20:35:21 +08:00
|
|
|
// GenerateOpenAPISchemaFromDefinition returns the parameter of a definition
|
|
|
|
|
func GenerateOpenAPISchemaFromDefinition(definitionName, cueTemplate string) ([]byte, error) {
|
|
|
|
|
capability := types.Capability{
|
|
|
|
|
Name: definitionName,
|
|
|
|
|
CueTemplate: cueTemplate,
|
|
|
|
|
}
|
|
|
|
|
return generateOpenAPISchemaFromCapabilityParameter(capability, nil)
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-10 10:44:58 +08:00
|
|
|
// prepareParameterCue cuts `parameter` section form definition .cue file
|
|
|
|
|
func prepareParameterCue(capabilityName, capabilityTemplate string) (string, error) {
|
|
|
|
|
var template string
|
|
|
|
|
var withParameterFlag bool
|
2021-05-19 20:08:51 +08:00
|
|
|
r := regexp.MustCompile(`[[:space:]]*parameter:[[:space:]]*`)
|
|
|
|
|
trimRe := regexp.MustCompile(`\s+`)
|
2021-03-10 10:44:58 +08:00
|
|
|
|
|
|
|
|
for _, text := range strings.Split(capabilityTemplate, "\n") {
|
|
|
|
|
if r.MatchString(text) {
|
|
|
|
|
// a variable has to be refined as a definition which starts with "#"
|
2021-05-19 20:08:51 +08:00
|
|
|
// text may be start with space or tab, we should clean up text
|
|
|
|
|
text = fmt.Sprintf("parameter: #parameter\n#%s", trimRe.ReplaceAllString(text, ""))
|
2021-03-10 10:44:58 +08:00
|
|
|
withParameterFlag = true
|
|
|
|
|
}
|
|
|
|
|
template += fmt.Sprintf("%s\n", text)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !withParameterFlag {
|
2021-03-29 17:20:33 +08:00
|
|
|
return "", fmt.Errorf(ErrNoSectionParameterInCue, capabilityName)
|
2021-03-10 10:44:58 +08:00
|
|
|
}
|
|
|
|
|
return template, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// fixOpenAPISchema fixes tainted `description` filed, missing of title `field`.
|
|
|
|
|
func fixOpenAPISchema(name string, schema *openapi3.Schema) {
|
|
|
|
|
t := schema.Type
|
|
|
|
|
switch t {
|
|
|
|
|
case "object":
|
|
|
|
|
for k, v := range schema.Properties {
|
|
|
|
|
s := v.Value
|
|
|
|
|
fixOpenAPISchema(k, s)
|
|
|
|
|
}
|
|
|
|
|
case "array":
|
|
|
|
|
fixOpenAPISchema("", schema.Items.Value)
|
|
|
|
|
}
|
|
|
|
|
if name != "" {
|
|
|
|
|
schema.Title = name
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
description := schema.Description
|
2021-04-11 14:10:16 +08:00
|
|
|
if strings.Contains(description, appfile.UsageTag) {
|
|
|
|
|
description = strings.Split(description, appfile.UsageTag)[1]
|
2021-03-10 10:44:58 +08:00
|
|
|
}
|
2021-04-11 14:10:16 +08:00
|
|
|
if strings.Contains(description, appfile.ShortTag) {
|
|
|
|
|
description = strings.Split(description, appfile.ShortTag)[0]
|
2021-03-10 10:44:58 +08:00
|
|
|
description = strings.TrimSpace(description)
|
|
|
|
|
}
|
|
|
|
|
schema.Description = description
|
|
|
|
|
}
|
2021-03-29 17:20:33 +08:00
|
|
|
|
|
|
|
|
// ConvertOpenAPISchema2SwaggerObject converts OpenAPI v2 JSON schema to Swagger Object
|
|
|
|
|
func ConvertOpenAPISchema2SwaggerObject(data []byte) (*openapi3.Schema, error) {
|
|
|
|
|
swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(data)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-02 15:37:06 +08:00
|
|
|
schemaRef, ok := swagger.Components.Schemas[velacue.ParameterTag]
|
2021-03-29 17:20:33 +08:00
|
|
|
if !ok {
|
|
|
|
|
return nil, errors.New(util.ErrGenerateOpenAPIV2JSONSchemaForCapability)
|
|
|
|
|
}
|
|
|
|
|
return schemaRef.Value, nil
|
|
|
|
|
}
|