mirror of
https://github.com/kubevela/kubevela.git
synced 2026-08-18 20:17:04 +00:00
move template out from extension
This commit is contained in:
@@ -68,6 +68,16 @@ type WorkloadDefinitionSpec struct {
|
||||
// +optional
|
||||
Status *Status `json:"status,omitempty"`
|
||||
|
||||
// Template defines the abstraction template data of the workload, it will replace the old template in extension field.
|
||||
// the data format depends on templateType, by default it's CUE
|
||||
// +optional
|
||||
Template string `json:"template,omitempty"`
|
||||
|
||||
// TemplateType defines the data format of the template, by default it's CUE format
|
||||
// Terraform HCL, Helm Chart will also be candidates in the near future.
|
||||
// +optional
|
||||
TemplateType string `json:"templateType,omitempty"`
|
||||
|
||||
// Extension is used for extension needs by OAM platform builders
|
||||
// +optional
|
||||
// +kubebuilder:pruning:PreserveUnknownFields
|
||||
@@ -140,6 +150,16 @@ type TraitDefinitionSpec struct {
|
||||
// +optional
|
||||
ConflictsWith []string `json:"conflictsWith,omitempty"`
|
||||
|
||||
// Template defines the abstraction template data of the workload, it will replace the old template in extension field.
|
||||
// the data format depends on templateType, by default it's CUE
|
||||
// +optional
|
||||
Template string `json:"template,omitempty"`
|
||||
|
||||
// TemplateType defines the data format of the template, by default it's CUE format
|
||||
// Terraform HCL, Helm Chart will also be candidates in the near future.
|
||||
// +optional
|
||||
TemplateType string `json:"templateType,omitempty"`
|
||||
|
||||
// Status defines the custom health policy and status message for trait
|
||||
// +optional
|
||||
Status *Status `json:"status,omitempty"`
|
||||
|
||||
@@ -18,12 +18,10 @@ package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"cuelang.org/go/cue"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/spf13/pflag"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// Source record the source of Capability
|
||||
@@ -107,20 +105,6 @@ type Parameter struct {
|
||||
Alias string `json:"alias,omitempty"`
|
||||
}
|
||||
|
||||
// ConvertTemplateJSON2Object convert spec.extension to object
|
||||
func ConvertTemplateJSON2Object(in *runtime.RawExtension) (Capability, error) {
|
||||
var t Capability
|
||||
var extension Capability
|
||||
if in == nil || in.Raw == nil {
|
||||
return t, fmt.Errorf("no template found")
|
||||
}
|
||||
err := json.Unmarshal(in.Raw, &extension)
|
||||
if err == nil {
|
||||
t = extension
|
||||
}
|
||||
return t, err
|
||||
}
|
||||
|
||||
// SetFlagBy set cli flag from Parameter
|
||||
func SetFlagBy(flags *pflag.FlagSet, v Parameter) {
|
||||
name := v.Name
|
||||
|
||||
@@ -78,6 +78,12 @@ spec:
|
||||
description: HealthPolicy defines the health check policy for the abstraction
|
||||
type: string
|
||||
type: object
|
||||
template:
|
||||
description: Template defines the abstraction template data of the workload, it will replace the old template in extension field. the data format depends on templateType, by default it's CUE
|
||||
type: string
|
||||
templateType:
|
||||
description: TemplateType defines the data format of the template, by default it's CUE format Terraform HCL, Helm Chart will also be candidates in the near future.
|
||||
type: string
|
||||
workloadRefPath:
|
||||
description: WorkloadRefPath indicates where/if a trait accepts a workloadRef object
|
||||
type: string
|
||||
|
||||
@@ -92,6 +92,12 @@ spec:
|
||||
description: HealthPolicy defines the health check policy for the abstraction
|
||||
type: string
|
||||
type: object
|
||||
template:
|
||||
description: Template defines the abstraction template data of the workload, it will replace the old template in extension field. the data format depends on templateType, by default it's CUE
|
||||
type: string
|
||||
templateType:
|
||||
description: TemplateType defines the data format of the template, by default it's CUE format Terraform HCL, Helm Chart will also be candidates in the near future.
|
||||
type: string
|
||||
required:
|
||||
- definitionRef
|
||||
type: object
|
||||
|
||||
@@ -20,51 +20,50 @@ spec:
|
||||
appliesToWorkloads:
|
||||
- webservice
|
||||
- worker
|
||||
extension:
|
||||
template: |
|
||||
parameter: {
|
||||
domain: string
|
||||
http: [string]: int
|
||||
}
|
||||
|
||||
// trait template can have multiple outputs in one trait
|
||||
outputs: service: {
|
||||
apiVersion: "v1"
|
||||
kind: "Service"
|
||||
metadata:
|
||||
name: context.name
|
||||
spec: {
|
||||
selector:
|
||||
"app.oam.dev/component": context.name
|
||||
ports: [
|
||||
for k, v in parameter.http {
|
||||
port: v
|
||||
targetPort: v
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
outputs: ingress: {
|
||||
apiVersion: "networking.k8s.io/v1beta1"
|
||||
kind: "Ingress"
|
||||
metadata:
|
||||
name: context.name
|
||||
spec: {
|
||||
rules: [{
|
||||
host: parameter.domain
|
||||
http: {
|
||||
paths: [
|
||||
for k, v in parameter.http {
|
||||
path: k
|
||||
backend: {
|
||||
serviceName: context.name
|
||||
servicePort: v
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
template: |
|
||||
parameter: {
|
||||
domain: string
|
||||
http: [string]: int
|
||||
}
|
||||
|
||||
// trait template can have multiple outputs in one trait
|
||||
outputs: service: {
|
||||
apiVersion: "v1"
|
||||
kind: "Service"
|
||||
metadata:
|
||||
name: context.name
|
||||
spec: {
|
||||
selector:
|
||||
"app.oam.dev/component": context.name
|
||||
ports: [
|
||||
for k, v in parameter.http {
|
||||
port: v
|
||||
targetPort: v
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
outputs: ingress: {
|
||||
apiVersion: "networking.k8s.io/v1beta1"
|
||||
kind: "Ingress"
|
||||
metadata:
|
||||
name: context.name
|
||||
spec: {
|
||||
rules: [{
|
||||
host: parameter.domain
|
||||
http: {
|
||||
paths: [
|
||||
for k, v in parameter.http {
|
||||
path: k
|
||||
backend: {
|
||||
serviceName: context.name
|
||||
servicePort: v
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,18 +12,17 @@ spec:
|
||||
definitionRef:
|
||||
name: manualscalertraits.core.oam.dev
|
||||
workloadRefPath: spec.workloadRef
|
||||
extension:
|
||||
template: |-
|
||||
output: {
|
||||
apiVersion: "core.oam.dev/v1alpha2"
|
||||
kind: "ManualScalerTrait"
|
||||
spec: {
|
||||
replicaCount: parameter.replicas
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
//+short=r
|
||||
//+usage=Replicas of the workload
|
||||
replicas: *1 | int
|
||||
}
|
||||
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "core.oam.dev/v1alpha2"
|
||||
kind: "ManualScalerTrait"
|
||||
spec: {
|
||||
replicaCount: parameter.replicas
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
//+short=r
|
||||
//+usage=Replicas of the workload
|
||||
replicas: *1 | int
|
||||
}
|
||||
|
||||
|
||||
@@ -8,40 +8,39 @@ metadata:
|
||||
spec:
|
||||
definitionRef:
|
||||
name: jobs.batch
|
||||
extension:
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "batch/v1"
|
||||
kind: "Job"
|
||||
spec: {
|
||||
parallelism: parameter.count
|
||||
completions: parameter.count
|
||||
template: spec: {
|
||||
restartPolicy: parameter.restart
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
|
||||
if parameter["cmd"] != _|_ {
|
||||
command: parameter.cmd
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
// +usage=specify number of tasks to run in parallel
|
||||
// +short=c
|
||||
count: *1 | int
|
||||
|
||||
// +usage=Which image would you like to use for your service
|
||||
// +short=i
|
||||
image: string
|
||||
|
||||
// +usage=Define the job restart policy, the value can only be Never or OnFailure. By default, it's Never.
|
||||
restart: *"Never" | string
|
||||
|
||||
// +usage=Commands to run in the container
|
||||
cmd?: [...string]
|
||||
}
|
||||
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "batch/v1"
|
||||
kind: "Job"
|
||||
spec: {
|
||||
parallelism: parameter.count
|
||||
completions: parameter.count
|
||||
template: spec: {
|
||||
restartPolicy: parameter.restart
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
|
||||
if parameter["cmd"] != _|_ {
|
||||
command: parameter.cmd
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
// +usage=specify number of tasks to run in parallel
|
||||
// +short=c
|
||||
count: *1 | int
|
||||
|
||||
// +usage=Which image would you like to use for your service
|
||||
// +short=i
|
||||
image: string
|
||||
|
||||
// +usage=Define the job restart policy, the value can only be Never or OnFailure. By default, it's Never.
|
||||
restart: *"Never" | string
|
||||
|
||||
// +usage=Commands to run in the container
|
||||
cmd?: [...string]
|
||||
}
|
||||
|
||||
|
||||
@@ -9,84 +9,83 @@ metadata:
|
||||
spec:
|
||||
definitionRef:
|
||||
name: deployments.apps
|
||||
extension:
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
spec: {
|
||||
selector: matchLabels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
|
||||
template: {
|
||||
metadata: labels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
|
||||
spec: {
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
|
||||
if parameter["cmd"] != _|_ {
|
||||
command: parameter.cmd
|
||||
}
|
||||
|
||||
if parameter["env"] != _|_ {
|
||||
env: parameter.env
|
||||
}
|
||||
|
||||
if context["config"] != _|_ {
|
||||
env: context.config
|
||||
}
|
||||
|
||||
ports: [{
|
||||
containerPort: parameter.port
|
||||
}]
|
||||
|
||||
if parameter["cpu"] != _|_ {
|
||||
resources: {
|
||||
limits:
|
||||
cpu: parameter.cpu
|
||||
requests:
|
||||
cpu: parameter.cpu
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Which image would you like to use for your service
|
||||
// +short=i
|
||||
image: string
|
||||
|
||||
// +usage=Commands to run in the container
|
||||
cmd?: [...string]
|
||||
|
||||
// +usage=Which port do you want customer traffic sent to
|
||||
// +short=p
|
||||
port: *80 | int
|
||||
// +usage=Define arguments by using environment variables
|
||||
env?: [...{
|
||||
// +usage=Environment variable name
|
||||
name: string
|
||||
// +usage=The value of the environment variable
|
||||
value?: string
|
||||
// +usage=Specifies a source the value of this var should come from
|
||||
valueFrom?: {
|
||||
// +usage=Selects a key of a secret in the pod's namespace
|
||||
secretKeyRef: {
|
||||
// +usage=The name of the secret in the pod's namespace to select from
|
||||
name: string
|
||||
// +usage=The key of the secret to select from. Must be a valid secret key
|
||||
key: string
|
||||
}
|
||||
}
|
||||
}]
|
||||
// +usage=Number of CPU units for the service, like `0.5` (0.5 CPU core), `1` (1 CPU core)
|
||||
cpu?: string
|
||||
}
|
||||
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
spec: {
|
||||
selector: matchLabels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
|
||||
template: {
|
||||
metadata: labels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
|
||||
spec: {
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
|
||||
if parameter["cmd"] != _|_ {
|
||||
command: parameter.cmd
|
||||
}
|
||||
|
||||
if parameter["env"] != _|_ {
|
||||
env: parameter.env
|
||||
}
|
||||
|
||||
if context["config"] != _|_ {
|
||||
env: context.config
|
||||
}
|
||||
|
||||
ports: [{
|
||||
containerPort: parameter.port
|
||||
}]
|
||||
|
||||
if parameter["cpu"] != _|_ {
|
||||
resources: {
|
||||
limits:
|
||||
cpu: parameter.cpu
|
||||
requests:
|
||||
cpu: parameter.cpu
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Which image would you like to use for your service
|
||||
// +short=i
|
||||
image: string
|
||||
|
||||
// +usage=Commands to run in the container
|
||||
cmd?: [...string]
|
||||
|
||||
// +usage=Which port do you want customer traffic sent to
|
||||
// +short=p
|
||||
port: *80 | int
|
||||
// +usage=Define arguments by using environment variables
|
||||
env?: [...{
|
||||
// +usage=Environment variable name
|
||||
name: string
|
||||
// +usage=The value of the environment variable
|
||||
value?: string
|
||||
// +usage=Specifies a source the value of this var should come from
|
||||
valueFrom?: {
|
||||
// +usage=Selects a key of a secret in the pod's namespace
|
||||
secretKeyRef: {
|
||||
// +usage=The name of the secret in the pod's namespace to select from
|
||||
name: string
|
||||
// +usage=The key of the secret to select from. Must be a valid secret key
|
||||
key: string
|
||||
}
|
||||
}
|
||||
}]
|
||||
// +usage=Number of CPU units for the service, like `0.5` (0.5 CPU core), `1` (1 CPU core)
|
||||
cpu?: string
|
||||
}
|
||||
|
||||
|
||||
@@ -8,40 +8,39 @@ metadata:
|
||||
spec:
|
||||
definitionRef:
|
||||
name: deployments.apps
|
||||
extension:
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
spec: {
|
||||
selector: matchLabels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
|
||||
template: {
|
||||
metadata: labels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
|
||||
spec: {
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
|
||||
if parameter["cmd"] != _|_ {
|
||||
command: parameter.cmd
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parameter: {
|
||||
// +usage=Which image would you like to use for your service
|
||||
// +short=i
|
||||
image: string
|
||||
// +usage=Commands to run in the container
|
||||
cmd?: [...string]
|
||||
}
|
||||
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
spec: {
|
||||
selector: matchLabels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
|
||||
template: {
|
||||
metadata: labels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
|
||||
spec: {
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
|
||||
if parameter["cmd"] != _|_ {
|
||||
command: parameter.cmd
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parameter: {
|
||||
// +usage=Which image would you like to use for your service
|
||||
// +short=i
|
||||
image: string
|
||||
// +usage=Commands to run in the container
|
||||
cmd?: [...string]
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: WorkloadDefinition
|
||||
metadata:
|
||||
name: worker
|
||||
name: nworker
|
||||
annotations:
|
||||
definition.oam.dev/description: "Describes long-running, scalable, containerized services that running at backend. They do NOT have network endpoint to receive external network traffic."
|
||||
spec:
|
||||
@@ -12,60 +12,57 @@ spec:
|
||||
isHealth: (context.output.status.readyReplicas > 0) && (context.output.status.readyReplicas == context.output.status.replicas)
|
||||
customStatus: |-
|
||||
message: "type: " + context.output.spec.template.spec.containers[0].image + ",\t enemies:" + context.outputs.gameconfig.data.enemies
|
||||
extension:
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
spec: {
|
||||
selector: matchLabels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
spec: {
|
||||
selector: matchLabels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
|
||||
template: {
|
||||
metadata: labels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
template: {
|
||||
metadata: labels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
|
||||
spec: {
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
envFrom: [{
|
||||
configMapRef: name: context.name + "game-config"
|
||||
}]
|
||||
if parameter["cmd"] != _|_ {
|
||||
command: parameter.cmd
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outputs: gameconfig: {
|
||||
apiVersion: "v1"
|
||||
kind: "ConfigMap"
|
||||
metadata: {
|
||||
name: context.name + "game-config"
|
||||
}
|
||||
data: {
|
||||
enemies: parameter.enemies
|
||||
lives: parameter.lives
|
||||
}
|
||||
}
|
||||
|
||||
parameter: {
|
||||
// +usage=Which image would you like to use for your service
|
||||
// +short=i
|
||||
image: string
|
||||
// +usage=Commands to run in the container
|
||||
cmd?: [...string]
|
||||
lives: string
|
||||
enemies: string
|
||||
}
|
||||
spec: {
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
envFrom: [{
|
||||
configMapRef: name: context.name + "game-config"
|
||||
}]
|
||||
if parameter["cmd"] != _|_ {
|
||||
command: parameter.cmd
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outputs: gameconfig: {
|
||||
apiVersion: "v1"
|
||||
kind: "ConfigMap"
|
||||
metadata: {
|
||||
name: context.name + "game-config"
|
||||
}
|
||||
data: {
|
||||
enemies: parameter.enemies
|
||||
lives: parameter.lives
|
||||
}
|
||||
}
|
||||
|
||||
parameter: {
|
||||
// +usage=Which image would you like to use for your service
|
||||
// +short=i
|
||||
image: string
|
||||
// +usage=Commands to run in the container
|
||||
cmd?: [...string]
|
||||
lives: string
|
||||
enemies: string
|
||||
}
|
||||
|
||||
---
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
@@ -78,46 +75,45 @@ spec:
|
||||
message: "type: "+ context.outputs.service.spec.type +",\t clusterIP:"+ context.outputs.service.spec.clusterIP+",\t ports:"+ "\(context.outputs.service.spec.ports[0].port)"+",\t domain"+context.outputs.ingress.spec.rules[0].host
|
||||
healthPolicy: |
|
||||
isHealth: len(context.outputs.service.spec.clusterIP) > 0
|
||||
extension:
|
||||
template: |
|
||||
parameter: {
|
||||
domain: string
|
||||
http: [string]: int
|
||||
}
|
||||
// trait template can have multiple outputs in one trait
|
||||
outputs: service: {
|
||||
apiVersion: "v1"
|
||||
kind: "Service"
|
||||
spec: {
|
||||
selector:
|
||||
app: context.name
|
||||
ports: [
|
||||
for k, v in parameter.http {
|
||||
port: v
|
||||
targetPort: v
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
outputs: ingress: {
|
||||
apiVersion: "networking.k8s.io/v1beta1"
|
||||
kind: "Ingress"
|
||||
metadata:
|
||||
name: context.name
|
||||
spec: {
|
||||
rules: [{
|
||||
host: parameter.domain
|
||||
http: {
|
||||
paths: [
|
||||
for k, v in parameter.http {
|
||||
path: k
|
||||
backend: {
|
||||
serviceName: context.name
|
||||
servicePort: v
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
template: |
|
||||
parameter: {
|
||||
domain: string
|
||||
http: [string]: int
|
||||
}
|
||||
// trait template can have multiple outputs in one trait
|
||||
outputs: service: {
|
||||
apiVersion: "v1"
|
||||
kind: "Service"
|
||||
spec: {
|
||||
selector:
|
||||
app: context.name
|
||||
ports: [
|
||||
for k, v in parameter.http {
|
||||
port: v
|
||||
targetPort: v
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
outputs: ingress: {
|
||||
apiVersion: "networking.k8s.io/v1beta1"
|
||||
kind: "Ingress"
|
||||
metadata:
|
||||
name: context.name
|
||||
spec: {
|
||||
rules: [{
|
||||
host: parameter.domain
|
||||
http: {
|
||||
paths: [
|
||||
for k, v in parameter.http {
|
||||
path: k
|
||||
backend: {
|
||||
serviceName: context.name
|
||||
servicePort: v
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,5 +19,4 @@ spec:
|
||||
appliesToWorkloads:
|
||||
- webservice
|
||||
- worker
|
||||
extension:
|
||||
template: |
|
||||
template: |
|
||||
|
||||
@@ -11,5 +11,4 @@ spec:
|
||||
definitionRef:
|
||||
name: manualscalertraits.core.oam.dev
|
||||
workloadRefPath: spec.workloadRef
|
||||
extension:
|
||||
template: |-
|
||||
template: |
|
||||
|
||||
@@ -7,5 +7,4 @@ metadata:
|
||||
spec:
|
||||
definitionRef:
|
||||
name: jobs.batch
|
||||
extension:
|
||||
template: |
|
||||
template: |
|
||||
|
||||
@@ -8,5 +8,4 @@ metadata:
|
||||
spec:
|
||||
definitionRef:
|
||||
name: deployments.apps
|
||||
extension:
|
||||
template: |
|
||||
template: |
|
||||
|
||||
@@ -7,5 +7,4 @@ metadata:
|
||||
spec:
|
||||
definitionRef:
|
||||
name: deployments.apps
|
||||
extension:
|
||||
template: |
|
||||
template: |
|
||||
|
||||
@@ -16,7 +16,7 @@ echo "# Code generated by KubeVela templates. DO NOT EDIT." >> tmpC
|
||||
for filename in `ls cue`; do
|
||||
cat "cue/${filename}" > tmp
|
||||
echo "" >> tmp
|
||||
sed -i.bak 's/^/ /' tmp
|
||||
sed -i.bak 's/^/ /' tmp
|
||||
|
||||
nameonly="${filename%.*}"
|
||||
|
||||
|
||||
@@ -77,6 +77,12 @@ spec:
|
||||
description: HealthPolicy defines the health check policy for the abstraction
|
||||
type: string
|
||||
type: object
|
||||
template:
|
||||
description: Template defines the abstraction template data of the workload, it will replace the old template in extension field. the data format depends on templateType, by default it's CUE
|
||||
type: string
|
||||
templateType:
|
||||
description: TemplateType defines the data format of the template, by default it's CUE format Terraform HCL, Helm Chart will also be candidates in the near future.
|
||||
type: string
|
||||
workloadRefPath:
|
||||
description: WorkloadRefPath indicates where/if a trait accepts a workloadRef object
|
||||
type: string
|
||||
|
||||
@@ -91,6 +91,12 @@ spec:
|
||||
description: HealthPolicy defines the health check policy for the abstraction
|
||||
type: string
|
||||
type: object
|
||||
template:
|
||||
description: Template defines the abstraction template data of the workload, it will replace the old template in extension field. the data format depends on templateType, by default it's CUE
|
||||
type: string
|
||||
templateType:
|
||||
description: TemplateType defines the data format of the template, by default it's CUE format Terraform HCL, Helm Chart will also be candidates in the near future.
|
||||
type: string
|
||||
required:
|
||||
- definitionRef
|
||||
type: object
|
||||
|
||||
@@ -230,7 +230,7 @@ func (p *Parser) GenerateApplicationConfiguration(app *Appfile, ns string) (*v1a
|
||||
}
|
||||
for _, tr := range wl.Traits {
|
||||
if err := tr.EvalContext(pCtx); err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, errors.Wrapf(err, "evaluate template trait=%s app=%s", tr.Name, wl.Name)
|
||||
}
|
||||
}
|
||||
comp, acComp, err := evalWorkloadWithContext(pCtx, wl, app.Name, wl.Name)
|
||||
@@ -266,7 +266,7 @@ func evalWorkloadWithContext(pCtx process.Context, wl *Workload, appName, compNa
|
||||
base, assists := pCtx.Output()
|
||||
componentWorkload, err := base.Unstructured()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, errors.Wrapf(err, "evaluate base template component=%s app=%s", compName, appName)
|
||||
}
|
||||
|
||||
labels := map[string]string{
|
||||
@@ -284,7 +284,7 @@ func evalWorkloadWithContext(pCtx process.Context, wl *Workload, appName, compNa
|
||||
for _, assist := range assists {
|
||||
tr, err := assist.Ins.Unstructured()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, errors.Wrapf(err, "evaluate trait=%s template for component=%s app=%s", assist.Name, compName, appName)
|
||||
}
|
||||
labels := map[string]string{
|
||||
oam.TraitTypeLabel: assist.Type,
|
||||
@@ -314,12 +314,12 @@ func PrepareProcessContext(k8sClient client.Client, wl *Workload, applicationNam
|
||||
var envName = namespace
|
||||
data, err := cg.GetConfigData(config.GenConfigMapName(applicationName, wl.Name, userConfig), envName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrapf(err, "get config=%s for app=%s in namespace=%s", userConfig, applicationName, namespace)
|
||||
}
|
||||
pCtx.SetConfigs(data)
|
||||
}
|
||||
if err := wl.EvalContext(pCtx); err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrapf(err, "evaluate base template app=%s in namespace=%s", applicationName, namespace)
|
||||
}
|
||||
return pCtx, nil
|
||||
}
|
||||
|
||||
@@ -1227,58 +1227,57 @@ spec:
|
||||
isHealth: (context.output.status.readyReplicas > 0) && (context.output.status.readyReplicas == context.output.status.replicas)
|
||||
customStatus: |-
|
||||
message: "type: " + context.output.spec.template.spec.containers[0].image + ",\t enemies:" + context.outputs.gameconfig.data.enemies
|
||||
extension:
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
spec: {
|
||||
selector: matchLabels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
spec: {
|
||||
selector: matchLabels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
|
||||
template: {
|
||||
metadata: labels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
template: {
|
||||
metadata: labels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
|
||||
spec: {
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
envFrom: [{
|
||||
configMapRef: name: context.name + "game-config"
|
||||
}]
|
||||
if parameter["cmd"] != _|_ {
|
||||
command: parameter.cmd
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
spec: {
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
envFrom: [{
|
||||
configMapRef: name: context.name + "game-config"
|
||||
}]
|
||||
if parameter["cmd"] != _|_ {
|
||||
command: parameter.cmd
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outputs: gameconfig: {
|
||||
apiVersion: "v1"
|
||||
kind: "ConfigMap"
|
||||
metadata: {
|
||||
name: context.name + "game-config"
|
||||
}
|
||||
data: {
|
||||
enemies: parameter.enemies
|
||||
lives: parameter.lives
|
||||
}
|
||||
}
|
||||
outputs: gameconfig: {
|
||||
apiVersion: "v1"
|
||||
kind: "ConfigMap"
|
||||
metadata: {
|
||||
name: context.name + "game-config"
|
||||
}
|
||||
data: {
|
||||
enemies: parameter.enemies
|
||||
lives: parameter.lives
|
||||
}
|
||||
}
|
||||
|
||||
parameter: {
|
||||
// +usage=Which image would you like to use for your service
|
||||
// +short=i
|
||||
image: string
|
||||
// +usage=Commands to run in the container
|
||||
cmd?: [...string]
|
||||
lives: string
|
||||
enemies: string
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Which image would you like to use for your service
|
||||
// +short=i
|
||||
image: string
|
||||
// +usage=Commands to run in the container
|
||||
cmd?: [...string]
|
||||
lives: string
|
||||
enemies: string
|
||||
}
|
||||
`
|
||||
tDDefYaml = `
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
@@ -1394,49 +1393,49 @@ spec:
|
||||
message: "type: "+ context.outputs.service.spec.type +",\t clusterIP:"+ context.outputs.service.spec.clusterIP+",\t ports:"+ "\(context.outputs.service.spec.ports[0].port)"+",\t domain"+context.outputs.ingress.spec.rules[0].host
|
||||
healthPolicy: |
|
||||
isHealth: len(context.outputs.service.spec.clusterIP) > 0
|
||||
extension:
|
||||
template: |
|
||||
parameter: {
|
||||
domain: string
|
||||
http: [string]: int
|
||||
}
|
||||
// trait template can have multiple outputs in one trait
|
||||
outputs: service: {
|
||||
apiVersion: "v1"
|
||||
kind: "Service"
|
||||
spec: {
|
||||
selector:
|
||||
app: context.name
|
||||
ports: [
|
||||
for k, v in parameter.http {
|
||||
port: v
|
||||
targetPort: v
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
outputs: ingress: {
|
||||
apiVersion: "networking.k8s.io/v1beta1"
|
||||
kind: "Ingress"
|
||||
metadata:
|
||||
name: context.name
|
||||
spec: {
|
||||
rules: [{
|
||||
host: parameter.domain
|
||||
http: {
|
||||
paths: [
|
||||
for k, v in parameter.http {
|
||||
path: k
|
||||
backend: {
|
||||
serviceName: context.name
|
||||
servicePort: v
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}]
|
||||
}
|
||||
}`
|
||||
template: |
|
||||
parameter: {
|
||||
domain: string
|
||||
http: [string]: int
|
||||
}
|
||||
// trait template can have multiple outputs in one trait
|
||||
outputs: service: {
|
||||
apiVersion: "v1"
|
||||
kind: "Service"
|
||||
spec: {
|
||||
selector:
|
||||
app: context.name
|
||||
ports: [
|
||||
for k, v in parameter.http {
|
||||
port: v
|
||||
targetPort: v
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
outputs: ingress: {
|
||||
apiVersion: "networking.k8s.io/v1beta1"
|
||||
kind: "Ingress"
|
||||
metadata:
|
||||
name: context.name
|
||||
spec: {
|
||||
rules: [{
|
||||
host: parameter.domain
|
||||
http: {
|
||||
paths: [
|
||||
for k, v in parameter.http {
|
||||
path: k
|
||||
backend: {
|
||||
serviceName: context.name
|
||||
servicePort: v
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
`
|
||||
)
|
||||
|
||||
func NewMock() *httptest.Server {
|
||||
|
||||
@@ -48,7 +48,7 @@ func LoadTemplate(cli client.Reader, key string, kd types.CapType) (*Template, e
|
||||
if wd.Annotations["type"] == string(types.TerraformCategory) {
|
||||
capabilityCategory = types.TerraformCategory
|
||||
}
|
||||
tmpl, err := NewTemplate(wd.Spec.Extension, wd.Spec.Status)
|
||||
tmpl, err := NewTemplate(wd.Spec.Template, wd.Spec.Status, wd.Spec.Extension)
|
||||
if err != nil {
|
||||
return nil, errors.WithMessagef(err, "LoadTemplate [%s] ", key)
|
||||
}
|
||||
@@ -67,7 +67,7 @@ func LoadTemplate(cli client.Reader, key string, kd types.CapType) (*Template, e
|
||||
if td.Annotations["type"] == string(types.TerraformCategory) {
|
||||
capabilityCategory = types.TerraformCategory
|
||||
}
|
||||
tmpl, err := NewTemplate(td.Spec.Extension, td.Spec.Status)
|
||||
tmpl, err := NewTemplate(td.Spec.Template, td.Spec.Status, td.Spec.Extension)
|
||||
if err != nil {
|
||||
return nil, errors.WithMessagef(err, "LoadTemplate [%s] ", key)
|
||||
}
|
||||
@@ -79,18 +79,24 @@ func LoadTemplate(cli client.Reader, key string, kd types.CapType) (*Template, e
|
||||
case types.TypeScope:
|
||||
// TODO: add scope template support
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("kind(%s) of %s not supported", kd, key)
|
||||
}
|
||||
|
||||
// NewTemplate will create CUE template for inner AbstractEngine using.
|
||||
func NewTemplate(raw *runtime.RawExtension, status *v1alpha2.Status) (*Template, error) {
|
||||
func NewTemplate(template string, status *v1alpha2.Status, raw *runtime.RawExtension) (*Template, error) {
|
||||
extension := map[string]interface{}{}
|
||||
if err := json.Unmarshal(raw.Raw, &extension); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tmp := &Template{
|
||||
TemplateStr: fmt.Sprint(extension["template"]),
|
||||
TemplateStr: template,
|
||||
}
|
||||
if tmp.TemplateStr == "" && raw != nil {
|
||||
if err := json.Unmarshal(raw.Raw, &extension); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if extTemplate, ok := extension["template"]; ok {
|
||||
if tmpStr, ok := extTemplate.(string); ok {
|
||||
tmp.TemplateStr = tmpStr
|
||||
}
|
||||
}
|
||||
}
|
||||
if status != nil {
|
||||
tmp.CustomStatus = status.CustomStatus
|
||||
@@ -98,3 +104,24 @@ func NewTemplate(raw *runtime.RawExtension, status *v1alpha2.Status) (*Template,
|
||||
}
|
||||
return tmp, nil
|
||||
}
|
||||
|
||||
// ConvertTemplateJSON2Object convert spec.extension to object
|
||||
func ConvertTemplateJSON2Object(in *runtime.RawExtension, specTemplate string) (types.Capability, error) {
|
||||
var t types.Capability
|
||||
capTemplate, err := NewTemplate(specTemplate, nil, in)
|
||||
if err != nil {
|
||||
return t, errors.Wrapf(err, "parse cue template")
|
||||
}
|
||||
var extension types.Capability
|
||||
if in != nil && in.Raw != nil {
|
||||
err := json.Unmarshal(in.Raw, &extension)
|
||||
if err != nil {
|
||||
return t, errors.Wrapf(err, "parse extension fail")
|
||||
}
|
||||
t = extension
|
||||
}
|
||||
if capTemplate.TemplateStr != "" {
|
||||
t.CueTemplate = capTemplate.TemplateStr
|
||||
}
|
||||
return t, err
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"cuelang.org/go/cue"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/test"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@@ -13,7 +15,7 @@ import (
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
)
|
||||
|
||||
func TestTemplate(t *testing.T) {
|
||||
func TestLoadWorkloadTemplate(t *testing.T) {
|
||||
cueTemplate := `
|
||||
context: {
|
||||
name: "test"
|
||||
@@ -110,3 +112,173 @@ spec:
|
||||
t.Errorf("parsered template is not correct")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadTraitTemplate(t *testing.T) {
|
||||
cueTemplate := `
|
||||
parameter: {
|
||||
domain: string
|
||||
http: [string]: int
|
||||
}
|
||||
context: {
|
||||
name: "test"
|
||||
}
|
||||
// trait template can have multiple outputs in one trait
|
||||
outputs: service: {
|
||||
apiVersion: "v1"
|
||||
kind: "Service"
|
||||
metadata:
|
||||
name: context.name
|
||||
spec: {
|
||||
selector:
|
||||
"app.oam.dev/component": context.name
|
||||
ports: [
|
||||
for k, v in parameter.http {
|
||||
port: v
|
||||
targetPort: v
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
outputs: ingress: {
|
||||
apiVersion: "networking.k8s.io/v1beta1"
|
||||
kind: "Ingress"
|
||||
metadata:
|
||||
name: context.name
|
||||
spec: {
|
||||
rules: [{
|
||||
host: parameter.domain
|
||||
http: {
|
||||
paths: [
|
||||
for k, v in parameter.http {
|
||||
path: k
|
||||
backend: {
|
||||
serviceName: context.name
|
||||
servicePort: v
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
var traitDefintion = `
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: "Configures K8s ingress and service to enable web traffic for your service.
|
||||
Please use route trait in cap center for advanced usage."
|
||||
name: ingress
|
||||
spec:
|
||||
status:
|
||||
customStatus: |-
|
||||
if len(context.outputs.ingress.status.loadBalancer.ingress) > 0 {
|
||||
message: "Visiting URL: " + context.outputs.ingress.spec.rules[0].host + ", IP: " + context.outputs.ingress.status.loadBalancer.ingress[0].ip
|
||||
}
|
||||
if len(context.outputs.ingress.status.loadBalancer.ingress) == 0 {
|
||||
message: "No loadBalancer found, visiting by using 'vela port-forward " + context.appName + " --route'\n"
|
||||
}
|
||||
healthPolicy: |
|
||||
isHealth: len(context.outputs.service.spec.clusterIP) > 0
|
||||
appliesToWorkloads:
|
||||
- webservice
|
||||
- worker
|
||||
template: |
|
||||
` + cueTemplate
|
||||
|
||||
// Create mock client
|
||||
tclient := test.MockClient{
|
||||
MockGet: func(ctx context.Context, key ktypes.NamespacedName, obj runtime.Object) error {
|
||||
switch o := obj.(type) {
|
||||
case *v1alpha2.TraitDefinition:
|
||||
wd, err := UnMarshalStringToTraitDefinition(traitDefintion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*o = *wd
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
temp, err := LoadTemplate(&tclient, "ingress", types.TypeTrait)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
var r cue.Runtime
|
||||
inst, err := r.Compile("-", temp.TemplateStr)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
instDest, err := r.Compile("-", cueTemplate)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
s1, _ := inst.Value().String()
|
||||
s2, _ := instDest.Value().String()
|
||||
if s1 != s2 {
|
||||
t.Errorf("parsered template is not correct")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewTemplate(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
tmp string
|
||||
status *v1alpha2.Status
|
||||
ext *runtime.RawExtension
|
||||
exp *Template
|
||||
}{
|
||||
"only tmp": {
|
||||
tmp: "t1",
|
||||
exp: &Template{
|
||||
TemplateStr: "t1",
|
||||
},
|
||||
},
|
||||
"no tmp,but has extension": {
|
||||
ext: &runtime.RawExtension{Raw: []byte(`{"template":"t1"}`)},
|
||||
exp: &Template{
|
||||
TemplateStr: "t1",
|
||||
},
|
||||
},
|
||||
"no tmp,but has extension without temp": {
|
||||
ext: &runtime.RawExtension{Raw: []byte(`{"template":{"t1":"t2"}}`)},
|
||||
exp: &Template{
|
||||
TemplateStr: "",
|
||||
},
|
||||
},
|
||||
"tmp with status": {
|
||||
tmp: "t1",
|
||||
status: &v1alpha2.Status{
|
||||
CustomStatus: "s1",
|
||||
HealthPolicy: "h1",
|
||||
},
|
||||
exp: &Template{
|
||||
TemplateStr: "t1",
|
||||
CustomStatus: "s1",
|
||||
Health: "h1",
|
||||
},
|
||||
},
|
||||
"no tmp only status": {
|
||||
status: &v1alpha2.Status{
|
||||
CustomStatus: "s1",
|
||||
HealthPolicy: "h1",
|
||||
},
|
||||
exp: &Template{
|
||||
CustomStatus: "s1",
|
||||
Health: "h1",
|
||||
},
|
||||
},
|
||||
}
|
||||
for reason, casei := range testCases {
|
||||
gtmp, err := NewTemplate(casei.tmp, casei.status, casei.ext)
|
||||
assert.NoError(t, err, reason)
|
||||
assert.Equal(t, gtmp, casei.exp, reason)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,14 +175,14 @@ func ParseAndSyncCapability(data []byte, syncDir string) (types.Capability, erro
|
||||
if err != nil {
|
||||
return types.Capability{}, err
|
||||
}
|
||||
return HandleDefinition(rd.Name, syncDir, rd.Spec.Reference.Name, rd.Annotations, rd.Spec.Extension, types.TypeWorkload, nil)
|
||||
return HandleDefinition(rd.Name, syncDir, rd.Spec.Reference.Name, rd.Annotations, rd.Spec.Extension, types.TypeWorkload, nil, rd.Spec.Template)
|
||||
case "TraitDefinition":
|
||||
var td v1alpha2.TraitDefinition
|
||||
err = yaml.Unmarshal(data, &td)
|
||||
if err != nil {
|
||||
return types.Capability{}, err
|
||||
}
|
||||
return HandleDefinition(td.Name, syncDir, td.Spec.Reference.Name, td.Annotations, td.Spec.Extension, types.TypeTrait, td.Spec.AppliesToWorkloads)
|
||||
return HandleDefinition(td.Name, syncDir, td.Spec.Reference.Name, td.Annotations, td.Spec.Extension, types.TypeTrait, td.Spec.AppliesToWorkloads, td.Spec.Template)
|
||||
case "ScopeDefinition":
|
||||
// TODO(wonderflow): support scope definition here.
|
||||
}
|
||||
|
||||
+18
-18
@@ -61,7 +61,7 @@ func GetWorkloadsFromCluster(ctx context.Context, namespace string, c types.Args
|
||||
|
||||
var templateErrors []error
|
||||
for _, wd := range workloadDefs.Items {
|
||||
tmp, err := HandleDefinition(wd.Name, syncDir, wd.Spec.Reference.Name, wd.Annotations, wd.Spec.Extension, types.TypeWorkload, nil)
|
||||
tmp, err := HandleDefinition(wd.Name, syncDir, wd.Spec.Reference.Name, wd.Annotations, wd.Spec.Extension, types.TypeWorkload, nil, wd.Spec.Template)
|
||||
if err != nil {
|
||||
templateErrors = append(templateErrors, errors.Wrapf(err, "handle workload template `%s` failed", wd.Name))
|
||||
continue
|
||||
@@ -93,7 +93,7 @@ func GetTraitsFromCluster(ctx context.Context, namespace string, c types.Args, s
|
||||
|
||||
var templateErrors []error
|
||||
for _, td := range traitDefs.Items {
|
||||
tmp, err := HandleDefinition(td.Name, syncDir, td.Spec.Reference.Name, td.Annotations, td.Spec.Extension, types.TypeTrait, td.Spec.AppliesToWorkloads)
|
||||
tmp, err := HandleDefinition(td.Name, syncDir, td.Spec.Reference.Name, td.Annotations, td.Spec.Extension, types.TypeTrait, td.Spec.AppliesToWorkloads, td.Spec.Template)
|
||||
if err != nil {
|
||||
templateErrors = append(templateErrors, errors.Wrapf(err, "handle trait template `%s` failed", td.Name))
|
||||
continue
|
||||
@@ -134,9 +134,9 @@ func validateCapabilities(tmp types.Capability, dm discoverymapper.DiscoveryMapp
|
||||
}
|
||||
|
||||
// HandleDefinition will handle definition to capability
|
||||
func HandleDefinition(name, syncDir, crdName string, annotation map[string]string, extension *runtime.RawExtension, tp types.CapType, applyTo []string) (types.Capability, error) {
|
||||
func HandleDefinition(name, syncDir, crdName string, annotation map[string]string, extension *runtime.RawExtension, tp types.CapType, applyTo []string, template string) (types.Capability, error) {
|
||||
var tmp types.Capability
|
||||
tmp, err := HandleTemplate(extension, name, syncDir)
|
||||
tmp, err := HandleTemplate(extension, template, name, syncDir)
|
||||
if err != nil {
|
||||
return types.Capability{}, err
|
||||
}
|
||||
@@ -162,31 +162,31 @@ func GetDescription(annotation map[string]string) string {
|
||||
}
|
||||
|
||||
// HandleTemplate will handle definition template to capability
|
||||
func HandleTemplate(in *runtime.RawExtension, name, syncDir string) (types.Capability, error) {
|
||||
tmp, err := types.ConvertTemplateJSON2Object(in)
|
||||
func HandleTemplate(in *runtime.RawExtension, specTemplate, name, syncDir string) (types.Capability, error) {
|
||||
tmp, err := util.ConvertTemplateJSON2Object(in, specTemplate)
|
||||
if err != nil {
|
||||
return types.Capability{}, err
|
||||
}
|
||||
tmp.Name = name
|
||||
|
||||
var cueTemplate string
|
||||
// if spec.template is not empty it should has the highest priority
|
||||
if specTemplate != "" {
|
||||
tmp.CueTemplate = specTemplate
|
||||
tmp.CueTemplateURI = ""
|
||||
}
|
||||
if tmp.CueTemplateURI != "" {
|
||||
b, err := common.HTTPGet(context.Background(), tmp.CueTemplateURI)
|
||||
if err != nil {
|
||||
return types.Capability{}, err
|
||||
}
|
||||
cueTemplate = string(b)
|
||||
tmp.CueTemplate = cueTemplate
|
||||
} else {
|
||||
if tmp.CueTemplate == "" {
|
||||
return types.Capability{}, errors.New("template not exist in definition")
|
||||
}
|
||||
cueTemplate = tmp.CueTemplate
|
||||
tmp.CueTemplate = string(b)
|
||||
}
|
||||
if tmp.CueTemplate == "" {
|
||||
return types.Capability{}, errors.New("template not exist in definition")
|
||||
}
|
||||
_, _ = system.CreateIfNotExist(syncDir)
|
||||
filePath := filepath.Join(syncDir, name+".cue")
|
||||
//nolint:gosec
|
||||
err = ioutil.WriteFile(filePath, []byte(cueTemplate), 0644)
|
||||
err = ioutil.WriteFile(filePath, []byte(tmp.CueTemplate), 0644)
|
||||
if err != nil {
|
||||
return types.Capability{}, err
|
||||
}
|
||||
@@ -245,7 +245,7 @@ func SyncDefinitionToLocal(ctx context.Context, c types.Args, localDefinitionDir
|
||||
}
|
||||
if foundCapability {
|
||||
template, err := HandleDefinition(capabilityName, localDefinitionDir, workloadDef.Spec.Reference.Name,
|
||||
workloadDef.Annotations, workloadDef.Spec.Extension, types.TypeWorkload, nil)
|
||||
workloadDef.Annotations, workloadDef.Spec.Extension, types.TypeWorkload, nil, workloadDef.Spec.Template)
|
||||
if err == nil {
|
||||
return &template, nil
|
||||
}
|
||||
@@ -259,7 +259,7 @@ func SyncDefinitionToLocal(ctx context.Context, c types.Args, localDefinitionDir
|
||||
}
|
||||
if foundCapability {
|
||||
template, err := HandleDefinition(capabilityName, localDefinitionDir, traitDef.Spec.Reference.Name,
|
||||
traitDef.Annotations, traitDef.Spec.Extension, types.TypeTrait, nil)
|
||||
traitDef.Annotations, traitDef.Spec.Extension, types.TypeTrait, nil, workloadDef.Spec.Template)
|
||||
if err == nil {
|
||||
return &template, nil
|
||||
}
|
||||
|
||||
@@ -2,10 +2,11 @@ package traitdefinition
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
|
||||
admissionv1beta1 "k8s.io/api/admission/v1beta1"
|
||||
"k8s.io/klog"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
@@ -123,17 +124,11 @@ func ValidateDefinitionReference(_ context.Context, td v1alpha2.TraitDefinition)
|
||||
if len(td.Spec.Reference.Name) > 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if td.Spec.Extension == nil || len(td.Spec.Extension.Raw) < 1 {
|
||||
return errors.New(failInfoDefRefOmitted)
|
||||
}
|
||||
|
||||
tmp := map[string]interface{}{}
|
||||
if err := json.Unmarshal(td.Spec.Extension.Raw, &tmp); err != nil {
|
||||
tmp, err := util.NewTemplate(td.Spec.Template, td.Spec.Status, td.Spec.Extension)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errValidateDefRef)
|
||||
}
|
||||
template, ok := tmp["template"]
|
||||
if !ok || len(fmt.Sprint(template)) < 1 {
|
||||
if len(tmp.TemplateStr) == 0 {
|
||||
return errors.New(failInfoDefRefOmitted)
|
||||
}
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user