github.com/oam-dev/kubevela@v1.9.11/references/cli/traits_test.go (about)

     1  /*
     2  Copyright 2021 The KubeVela Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package cli
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"os"
    23  	"strings"
    24  
    25  	. "github.com/onsi/ginkgo/v2"
    26  	. "github.com/onsi/gomega"
    27  	"sigs.k8s.io/yaml"
    28  
    29  	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
    30  	util2 "github.com/oam-dev/kubevela/pkg/oam/util"
    31  	common2 "github.com/oam-dev/kubevela/pkg/utils/common"
    32  	"github.com/oam-dev/kubevela/pkg/utils/util"
    33  )
    34  
    35  var _ = Describe("Test trait cli", func() {
    36  
    37  	When("there are container-image and configmap traits", func() {
    38  		BeforeEach(func() {
    39  			// Install trait locally
    40  			containerImage := v1beta1.TraitDefinition{}
    41  			Expect(yaml.Unmarshal([]byte(containerImageYaml), &containerImage)).Should(BeNil())
    42  			Expect(k8sClient.Create(context.Background(), &containerImage)).Should(SatisfyAny(BeNil(), util2.AlreadyExistMatcher{}))
    43  
    44  			configMap := v1beta1.TraitDefinition{}
    45  			Expect(yaml.Unmarshal([]byte(configmapYaml), &configMap)).Should(BeNil())
    46  			Expect(k8sClient.Create(context.Background(), &configMap)).Should(SatisfyAny(BeNil(), util2.AlreadyExistMatcher{}))
    47  		})
    48  
    49  		It("should not have any err", func() {
    50  			arg := common2.Args{}
    51  			arg.SetClient(k8sClient)
    52  			buffer := bytes.NewBuffer(nil)
    53  			ioStreams := util.IOStreams{In: os.Stdin, Out: buffer, ErrOut: buffer}
    54  			cmd := NewTraitCommand(arg, "", ioStreams)
    55  			Expect(cmd.Execute()).Should(BeNil())
    56  			buf, ok := ioStreams.Out.(*bytes.Buffer)
    57  			Expect(ok).Should(BeTrue())
    58  			Expect(strings.Contains(buf.String(), "error")).Should(BeFalse())
    59  		})
    60  	})
    61  })
    62  
    63  const (
    64  	containerImageYaml = `apiVersion: core.oam.dev/v1beta1
    65  kind: TraitDefinition
    66  metadata:
    67    annotations:
    68      definition.oam.dev/description: Set the image of the container.
    69    name: container-image
    70    namespace: vela-system
    71  spec:
    72    appliesToWorkloads:
    73      - '*'
    74    podDisruptive: true
    75    schematic:
    76      cue:
    77        template: |
    78          #PatchParams: {
    79          	// +usage=Specify the name of the target container, if not set, use the component name
    80          	containerName: *"" | string
    81          	// +usage=Specify the image of the container
    82          	image: string
    83          	// +usage=Specify the image pull policy of the container
    84          	imagePullPolicy: *"" | "IfNotPresent" | "Always" | "Never"
    85          }
    86          PatchContainer: {
    87          	_params:         #PatchParams
    88          	name:            _params.containerName
    89          	_baseContainers: context.output.spec.template.spec.containers
    90          	_matchContainers_: [ for _container_ in _baseContainers if _container_.name == name {_container_}]
    91          	_baseContainer: *_|_ | {...}
    92          	if len(_matchContainers_) == 0 {
    93          		err: "container \(name) not found"
    94          	}
    95          	if len(_matchContainers_) > 0 {
    96          		// +patchStrategy=retainKeys
    97          		image: _params.image
    98  
    99          		if _params.imagePullPolicy != "" {
   100          			// +patchStrategy=retainKeys
   101          			imagePullPolicy: _params.imagePullPolicy
   102          		}
   103          	}
   104          }
   105          patch: spec: template: spec: {
   106          	if parameter.containers == _|_ {
   107          		// +patchKey=name
   108          		containers: [{
   109          			PatchContainer & {_params: {
   110          				if parameter.containerName == "" {
   111          					containerName: context.name
   112          				}
   113          				if parameter.containerName != "" {
   114          					containerName: parameter.containerName
   115          				}
   116          				image:           parameter.image
   117          				imagePullPolicy: parameter.imagePullPolicy
   118          			}}
   119          		}]
   120          	}
   121          	if parameter.containers != _|_ {
   122          		// +patchKey=name
   123          		containers: [ for c in parameter.containers {
   124          			if c.containerName == "" {
   125          				err: "containerName must be set for containers"
   126          			}
   127          			if c.containerName != "" {
   128          				PatchContainer & {_params: c}
   129          			}
   130          		}]
   131          	}
   132          }
   133          parameter: *#PatchParams | close({
   134          	// +usage=Specify the container image for multiple containers
   135          	containers: [...#PatchParams]
   136          })
   137          errs: [ for c in patch.spec.template.spec.containers if c.err != _|_ {c.err}]
   138  `
   139  	configmapYaml = `apiVersion: core.oam.dev/v1beta1
   140  kind: TraitDefinition
   141  metadata:
   142    annotations:
   143      definition.oam.dev/description: Create/Attach configmaps on K8s pod for your workload which follows the pod spec in path 'spec.template'. This definition is DEPRECATED, please specify configmap in 'storage' instead.
   144    labels:
   145      custom.definition.oam.dev/deprecated: "true"
   146    name: configmap
   147    namespace: vela-system
   148  spec:
   149    appliesToWorkloads:
   150      - '*'
   151    podDisruptive: true
   152    schematic:
   153      cue:
   154        template: |
   155          patch: spec: template: spec: {
   156          	containers: [{
   157          		// +patchKey=name
   158          		volumeMounts: [
   159          			for v in parameter.volumes {
   160          				{
   161          					name:      "volume-\(v.name)"
   162          					mountPath: v.mountPath
   163          					readOnly:  v.readOnly
   164          				}
   165          			},
   166          		]
   167          	}, ...]
   168          	// +patchKey=name
   169          	volumes: [
   170          		for v in parameter.volumes {
   171          			{
   172          				name: "volume-\(v.name)"
   173          				configMap: name: v.name
   174          			}
   175          		},
   176          	]
   177          }
   178          outputs: {
   179          	for v in parameter.volumes {
   180          		if v.data != _|_ {
   181          			"\(v.name)": {
   182          				apiVersion: "v1"
   183          				kind:       "ConfigMap"
   184          				metadata: name: v.name
   185          				data: v.data
   186          			}
   187          		}
   188          	}
   189          }
   190          parameter: {
   191          	// +usage=Specify mounted configmap names and their mount paths in the container
   192          	volumes: [...{
   193          		name:      string
   194          		mountPath: string
   195          		readOnly:  *false | bool
   196          		data?: [string]: string
   197          	}]
   198          }
   199  `
   200  )