github.com/oam-dev/kubevela@v1.9.11/design/vela-cli/def.md (about) 1 --- 2 title: Writing X-Definitions with Vela CLI 3 --- 4 5 ## Introduction 6 7 `vela def` is a group of commands designed for helping users managing definitions in KubeVela. 8 9 ## Background 10 11 In KubeVela, the main capability of definition is defined by the cue-format template. However, as a JSON-based language, cue-format template is not capatible with the original Kubernetes YAML format, which means we need to transform cue-format template into raw string while embedding it into the Kubernetes YAML objects. This made it relatively difficult to view or edit KubeVela definitions through native **kubectl** tool. For example, when we access a trait definition that attach labels to components, we can run `kubectl get trait labels -n vela-system -o yaml`, the result is as below 12 13 ```yaml 14 apiVersion: core.oam.dev/v1beta1 15 kind: TraitDefinition 16 metadata: 17 annotations: 18 definition.oam.dev/description: Add labels for your Workload. 19 meta.helm.sh/release-name: kubevela 20 meta.helm.sh/release-namespace: vela-system 21 creationTimestamp: "2021-08-05T07:06:58Z" 22 generation: 1 23 labels: 24 app.kubernetes.io/managed-by: Helm 25 name: labels 26 namespace: vela-system 27 resourceVersion: "8423" 28 uid: 51a7f8b1-f14d-4776-b538-02ac54a55661 29 spec: 30 appliesToWorkloads: 31 - deployments.apps 32 podDisruptive: true 33 schematic: 34 cue: 35 template: "patch: spec: template: metadata: labels: {\n\tfor k, v in parameter 36 {\n\t\t\"\\(k)\": v\n\t}\n}\nparameter: [string]: string\n" 37 status: 38 configMapRef: schema-labels 39 latestRevision: 40 name: labels-v1 41 revision: 1 42 revisionHash: fe7fa9da440dc9d3 43 ``` 44 45 We can see that the core ability of the *labels* definition locates at `spec.schematic.cue.template` and is escaped into raw string. It is hard to identify and manipulate. 46 47 On the other hand, although cuelang has very strong expression capabilities, it is still relatively new to many Kubernetes developers who might takes some extra time to learn when leveraging the power of cuelang. 48 49 Therefore, KubeVela team introduce a series of functions in the `vela` CLI tool, aiming to help developers design all kinds of definitions conveniently. 50 51 ## Design 52 53 As mentioned above, the CUE-YAML-mixed-style KubeVela definition, is represented by a single cue-format definition file in v1.1, which expresses the content and description of defintiion more clearly and briefly. The `labels` definition above can be represented by the following file 54 55 ```json 56 // labels.cue 57 labels: { 58 annotations: {} 59 attributes: { 60 appliesToWorkloads: ["deployments.apps"] 61 podDisruptive: true 62 } 63 description: "Add labels for your Workload." 64 labels: {} 65 type: "trait" 66 } 67 template: { 68 patch: spec: template: metadata: labels: { 69 for k, v in parameter { 70 "\(k)": v 71 } 72 } 73 parameter: [string]: string 74 } 75 ``` 76 77 The first part `labels: {...}` expresses the basic information of the definition, including its type, description, labels, annotations and attributes. The second part `template: {...}` describes the capability of the definition. With the `vela def` command group,KubeVela users can directly interact with the CUE-format file instead of facing the complex YAML file. 78 79 ## Details 80 81 ### init 82 83 `vela def init` is a command that helps users bootstrap new definitions. To create an empty trait definition, run `vela def init my-trait -t trait --desc "My trait description."` 84 85 ```json 86 "my-trait": { 87 annotations: {} 88 attributes: { 89 appliesToWorkloads: [] 90 conflictsWith: [] 91 definitionRef: "" 92 podDisruptive: false 93 workloadRefPath: "" 94 } 95 description: "My trait description." 96 labels: {} 97 type: "trait" 98 } 99 template: { 100 patch: {} 101 parameter: {} 102 } 103 ``` 104 105 Or you can use `vela def init my-comp --interactive` to initiate definitions interactively. 106 107 ```bash 108 $ vela def init my-comp --interactive 109 Please choose one definition type from the following values: component, trait, policy, workload, scope, workflow-step 110 > Definition type: component 111 > Definition description: My component definition. 112 Please enter the location the template YAML file to build definition. Leave it empty to generate default template. 113 > Definition template filename: 114 Please enter the output location of the generated definition. Leave it empty to print definition to stdout. 115 > Definition output filename: my-component.cue 116 Definition written to my-component.cue 117 ``` 118 119 In addition, users can create definitions from existing YAML files. For example, if a user want to create a ComponentDefinition which is designed to generate a deployment, and this deployment has already been created elsewhere, he/she can use the `--template-yaml` flag to complete the transformation. The YAML file is as below 120 121 ```yaml 122 apiVersion: apps/v1 123 kind: Deployment 124 metadata: 125 name: hello-world 126 spec: 127 replicas: 1 128 selector: 129 matchLabels: 130 app.kubernetes.io/name: hello-world 131 template: 132 metadata: 133 labels: 134 app.kubernetes.io/name: hello-world 135 spec: 136 containers: 137 - name: hello-world 138 image: somefive/hello-world 139 ports: 140 - name: http 141 containerPort: 80 142 protocol: TCP 143 --- 144 apiVersion: v1 145 kind: Service 146 metadata: 147 name: hello-world-service 148 spec: 149 selector: 150 app: hello-world 151 ports: 152 - name: http 153 protocol: TCP 154 port: 80 155 targetPort: 8080 156 type: LoadBalancer 157 ``` 158 159 Running `vela def init my-comp -t component --desc "My component." --template-yaml ./my-deployment.yaml` to get the CUE-format ComponentDefinition 160 161 ```json 162 "my-comp": { 163 annotations: {} 164 attributes: workload: definition: { 165 apiVersion: "<change me> apps/v1" 166 kind: "<change me> Deployment" 167 } 168 description: "My component." 169 labels: {} 170 type: "component" 171 } 172 template: { 173 output: { 174 metadata: name: "hello-world" 175 spec: { 176 replicas: 1 177 selector: matchLabels: "app.kubernetes.io/name": "hello-world" 178 template: { 179 metadata: labels: "app.kubernetes.io/name": "hello-world" 180 spec: containers: [{ 181 name: "hello-world" 182 image: "somefive/hello-world" 183 ports: [{ 184 name: "http" 185 containerPort: 80 186 protocol: "TCP" 187 }] 188 }] 189 } 190 } 191 apiVersion: "apps/v1" 192 kind: "Deployment" 193 } 194 outputs: "hello-world-service": { 195 metadata: name: "hello-world-service" 196 spec: { 197 ports: [{ 198 name: "http" 199 protocol: "TCP" 200 port: 80 201 targetPort: 8080 202 }] 203 selector: app: "hello-world" 204 type: "LoadBalancer" 205 } 206 apiVersion: "v1" 207 kind: "Service" 208 } 209 parameter: {} 210 211 } 212 ``` 213 214 Then the user can make further modifications based on the definition file above, like removing *\<change me\>* in **workload.definition**。 215 216 ### vet 217 218 After initializing definition files, run `vela def vet my-comp.cue` to validate if there are any syntax error in the definition file. It can be used to detect some simple errors such as missing brackets. 219 220 ```bash 221 $ vela def vet my-comp.cue 222 Validation succeed. 223 ``` 224 225 ### render / apply 226 227 After confirming the definition file has correct syntax. users can run `vela def apply my-comp.cue --namespace my-namespace` to apply this definition in the `my-namespace` namespace。If you want to check the transformed Kubernetes YAML file, `vela def apply my-comp.cue --dry-run` or `vela def render my-comp.cue -o my-comp.yaml` can achieve that. 228 229 ```yaml 230 apiVersion: core.oam.dev/v1beta1 231 kind: ComponentDefinition 232 metadata: 233 annotations: 234 definition.oam.dev/description: My component. 235 labels: {} 236 name: my-comp 237 namespace: vela-system 238 spec: 239 schematic: 240 cue: 241 template: | 242 output: { 243 metadata: name: "hello-world" 244 spec: { 245 replicas: 1 246 selector: matchLabels: "app.kubernetes.io/name": "hello-world" 247 template: { 248 metadata: labels: "app.kubernetes.io/name": "hello-world" 249 spec: containers: [{ 250 name: "hello-world" 251 image: "somefive/hello-world" 252 ports: [{ 253 name: "http" 254 containerPort: 80 255 protocol: "TCP" 256 }] 257 }] 258 } 259 } 260 apiVersion: "apps/v11" 261 kind: "Deployment" 262 } 263 outputs: "hello-world-service": { 264 metadata: name: "hello-world-service" 265 spec: { 266 ports: [{ 267 name: "http" 268 protocol: "TCP" 269 port: 80 270 targetPort: 8080 271 }] 272 selector: app: "hello-world" 273 type: "LoadBalancer" 274 } 275 apiVersion: "v1" 276 kind: "Service" 277 } 278 parameter: {} 279 workload: 280 definition: 281 apiVersion: apps/v1 282 kind: Deployment 283 ``` 284 285 ```bash 286 $ vela def apply my-comp.cue -n my-namespace 287 ComponentDefinition my-comp created in namespace my-namespace. 288 ``` 289 290 ### get / list / edit / del 291 292 While you can use native kubectl tools to confirm the results of the apply command, as mentioned above, the YAML object mixed with raw CUE template string is complex. Using `vela def get` will automatically convert the YAML object into the CUE-format definition. 293 294 ```bash 295 $ vela def get my-comp -t component 296 ``` 297 298 Or you can list all defintions installed through `vela def list` 299 300 ```bash 301 $ vela def list -n my-namespace -t component 302 NAME TYPE NAMESPACE DESCRIPTION 303 my-comp ComponentDefinition my-namespace My component. 304 ``` 305 306 Similarly, using `vela def edit` to edit definitions in pure CUE-format. The transformation between CUE-format definition and YAML object is done by the command. Besides, you can specify the `EDITOR` environment variable to use your favourate editor. 307 308 ```bash 309 $ EDITOR=vim vela def edit my-comp 310 ``` 311 312 Finally, `vela def del` can be utilized to delete existing definitions. 313 314 ```bash 315 $ vela def del my-comp -n my-namespace 316 Are you sure to delete the following definition in namespace my-namespace? 317 ComponentDefinition my-comp: My component. 318 [yes|no] > yes 319 ComponentDefinition my-comp in namespace my-namespace deleted. 320 ``` 321