--- title: Built-in Workflow Operations --- This document introduces the CUE operations that can be used in the workflow step definitions. You need to import the `vela/op` package to use these operations. :::tip Before reading this section, make sure you understand how to [customize workflow](./workflow.md) and learn the basics of [CUE](../cue/basic.md) ::: ## Process Control ### ConditionalWait Makes the workflow step wait until the condition is met. **Parameters** ``` #ConditionalWait: { // +usage=If continue is false, the step will wait for continue to be true. continue: bool // +usage=Optional message that will be shown in workflow step status, note that the message might be override by other actions. message?: string } ``` **Example** ``` import "vela/op" myRead: op.#Read & { value: { kind: "Deployment" apiVersion: "apps/v1" metadata: name: "test-app" } } wait: op.#ConditionalWait & { continue: myRead.value.status.phase == "running" } ``` ### Fail Make the workflow step failed. **Parameters** ``` #Fail: { // +usage=Optional message that will be shown in workflow step status, note that the message might be override by other actions. message?: string } ``` **Example** ``` import "vela/op" fail: op.#Fail & { message: "error in the step" } ``` ## Data Control ### Log Output the log or configure the log source for this step. If `op.#Log` is used in a step definition, then you can use `vela workflow logs ` to view the log for that step. **Parameters** ``` #Log: { // +usage=The data to print in the controller logs data?: {...} | string // +usage=The log level of the data level: *3 | int // +usage=The log source of this step. You can specify it from a url or resources. Note that if you set source in multiple op.#Log, only the latest one will work source?: close({ // +usage=Specify the log source url of this step url: string }) | close({ // +usage=Specify the log resources of this step resources?: [...{ // +usage=Specify the name of the resource name?: string // +usage=Specify the cluster of the resource cluster?: string // +usage=Specify the namespace of the resource namespace?: string // +usage=Specify the label selector of the resource labelSelector?: {...} }] }) } ``` **Example** ``` import "vela/op" myLog: op.#Log & { data: "my custom log" resources: [{ labelsSelector: {"test-key": "test-value"} }] } ``` ### Message Write message to the workflow step status. **Parameters** ``` #Message: { // +usage=Optional message that will be shown in workflow step status, note that the message might be override by other actions. message?: string } ``` **Example** ``` import "vela/op" msg: op.#Message & { message: "custom message" } ``` ### DoVar Used to save or read user-defined data in the context of workflow. **Parameters** ``` #DoVar: { // +usage=The method to call on the variable method: *"Get" | "Put" // +usage=The path to the variable path: string // +usage=The value of the variable value?: _ } ``` **Example** ``` put: op.ws.#DoVar & { method: "Put" path: "foo.score" value: 100 } // The user can get the data saved above through get.value (100) get: op.ws.#DoVar & { method: "Get" path: "foo.score" } ``` ## Requests ### HTTPDo Send HTTP request to the specified URL. **Parameters** ``` #HTTPDo: { // +usage=The method of HTTP request method: *"GET" | "POST" | "PUT" | "DELETE" // +usage=The url to request url: string // +usage=The request config request?: { // +usage=The timeout of this request timeout?: string // +usage=The request body body?: string // +usage=The header of the request header?: [string]: string // +usage=The trailer of the request trailer?: [string]: string // +usage=The rate limiter of the request ratelimiter?: { limit: int period: string } } // +usgae=The tls config of the request tls_config?: secret: string // +usage=The response of the request will be filled in this field after the action is executed response: { // +usage=The body of the response body: string // +usage=The header of the response header?: [string]: [...string] // +usage=The trailer of the response trailer?: [string]: [...string] // +usage=The status code of the response statusCode: int } } ``` **Example** ``` import "vela/op" myRequest: op.#HTTPDo & { method: "POST" url: "http://my-url.com" request: { body: { "hello": "body" } } } ``` ### HTTPGet Send HTTP GET request to the specified URL. **Parameters** Same as HTTPDo, but `method` has been specified as GET. **Example** Please refer the example in HTTPDo. ### HTTPPost Send HTTP POST request to the specified URL. **Parameters** Same as HTTPDo, but `method` has been specified as POST. **Example** Please refer the example in HTTPDo. ### HTTPPut Send HTTP PUT request to the specified URL. **Parameters** Same as HTTPDo, but `method` has been specified as PUT. **Example** Please refer the example in HTTPDo. ### HTTPDelete Send HTTP DELETE request to the specified URL. **Parameters** Same as HTTPDo, but `method` has been specified as DELETE. **Example** Please refer the example in HTTPDo. ### SendEmail Send emails. **Parameters** ``` #SendEmail { // +usage=The info of the sender from: { // +usage=The address of the sender address: string // +usage=The alias of the sender alias?: string // +usage=The password of the sender password: string // +usage=The host of the sender server host: string // +usage=The port of the sender server port: int } // +usgae=The email address list of the recievers to: [...string] // +usage=The content of the email content: { // +usage=The subject of the email subject: string // +usage=The body of the email body: string } } ``` **Example** ``` import "vela/op" myEmail: op.#SendEmail & { from: { address: "hello@mail.com" password: "password" host: "myhost" port: 465 } to: ["world@mail.com", "next@workflow.com"] content: { subject: "Hello Vela" body: "Hello Vela, this is a test email" } } ``` ## Resource Management ### Apply Apply resources in the Kubernetes cluster. **Parameters** ``` #Apply: { // +usage=The cluster to use cluster: *"" | string // +usage=The resource to apply value: {...} } ``` **Example** ``` import "vela/op" myApply: op.#Apply & { value: { kind: "Deployment" apiVersion: "apps/v1" metadata: name: "test-app" spec: { replicas: 2 ... } } } ``` ### ApplyInParallel Apply resources in parallel in the Kubernetes cluster. **Parameters** ``` #ApplyInParallel: { // +usage=The cluster to use cluster: *"" | string // +usage=The resources to apply in parallel value: [...{...}] } ``` **Example** ``` import "vela/op" myApply: op.#ApplyInParallel & { value: [{ kind: "Deployment" apiVersion: "apps/v1" metadata: name: "test-app" spec: { replicas: 2 ... } }, { kind: "Deployment" apiVersion: "apps/v1" metadata: name: "test-app2" spec: { replicas: 2 ... } }] } ``` ### Read Read resources in the Kubernetes cluster. **Parameters** ``` #Read: { // +usage=The cluster to use cluster: *"" | string // +usage=The resource to read, this field will be filled with the resource read from the cluster after the action is executed value?: {...} ... } ``` **Example** ``` import "vela/op" myRead: op.#Read & { value: { kind: "Deployment" apiVersion: "apps/v1" metadata: name: "test-app" } } ``` ### List List resources in the Kubernetes cluster. **Parameters** ``` #List: { // +usage=The cluster to use cluster: *"" | string // +usage=The resource to list resource: { // +usage=The api version of the resource apiVersion: string // +usage=The kind of the resource kind: string } // +usage=The filter to list the resources filter?: { // +usage=The namespace to list the resources namespace?: *"" | string // +usage=The label selector to filter the resources matchingLabels?: {...} } // +usage=The listed resources will be filled in this field after the action is executed list?: {...} ... } ``` **Example** ``` import "vela/op" myList: op.#List & { resource: { kind: "Deployment" apiVersion: "apps/v1" } filter: { matchingLabels: { "mylabel": "myvalue" } } } ``` ### Delete Delete resources in the Kubernetes cluster. **Parameters** ``` #Delete: { // +usage=The cluster to use cluster: *"" | string // +usage=The resource to delete value: { // +usage=The api version of the resource apiVersion: string // +usage=The kind of the resource kind: string // +usage=The metadata of the resource metadata: { // +usage=The name of the resource name?: string // +usage=The namespace of the resource namespace: *"default" | string } } // +usage=The filter to delete the resources filter?: { // +usage=The namespace to list the resources namespace?: string // +usage=The label selector to filter the resources matchingLabels?: {...} } } ``` **Example** ``` import "vela/op" myDelete: op.#Delete & { resource: { kind: "Deployment" apiVersion: "apps/v1" metadata: name: "my-app" } } ``` ## Application Operations ### Load Load all the components and its traits in the application. **Parameters** ``` #Load: { // +usage=If specify `app`, use specified application to load its component resources otherwise use current application app?: string // +usage=The value of the components will be filled in this field after the action is executed, you can use value[componentName] to refer a specified component value?: {...} } ``` **Example** ``` import "vela/op" // You can use `load.value.[componentName] to refer the component. load: op.#Load & {} mycomp: load.value["my-comp"] ``` ### ApplyComponent Create or update resources corresponding to the component in Kubernetes cluster. Note that need to use `Load` first to apply the resources. **Parameters** ``` #ApplyComponent: { // +usage=The cluster to use cluster: *"" | string // +usage=The env to use env: *"" | string // +usage=The namespace to apply namespace: *"" | string // +usage=Whether to wait healthy of the applied component waitHealthy: *true | bool // +usage=The value of the component resource value: {...} // +usage=The patcher that will be applied to the resource, you can define the strategy of list merge through comments. Reference doc here: https://kubevela.io/docs/platform-engineers/traits/patch-trait#patch-in-workflow-step patch?: {...} } ``` **Example** ``` import "vela/op" load: op.#Load & {} apply: op.#ApplyComponent & { value: load.value["my-comp"] } ``` ### ApplyApplication Create or update resources corresponding to the application in Kubernetes cluster. **Parameters** ``` #ApplyApplication: {} ``` **Example** ``` import "vela/op" apply: op.#ApplyApplication & {} ``` ## Special Operations ### Steps A combination of a set of operations that can be used to implement complex operation logic. **Parameters** ``` #Steps: {} ``` **Example** ``` import "vela/op" env: "prod" app: op.#Steps & { if env == "prod" { load: op.#Load & { component: "component-name" } apply: op.#Apply & { value: load.value.workload } } if env != "prod" { request: op.#HTTPGet & { url: "http://my-url.com" } } } ``` ## Deprecated Operations ### Slack Send a request to the specified Slack URL. `#Slack` is actually a secondary wrapper for `#HTTPPost`, we will deprecate this operation in the next version. You can use `#HTTPPost` instead, like: ``` import ( "vela/op" "encoding/json" ) message: { "hello": "world" } mySlack: op.#HTTPPost & { url: "slackURL" request: { body: json.Marshal(message) header: "Content-Type": "application/json" } } ``` **Parameters** ``` #Slack: { message: {...} slackUrl: string } ``` **Example** ``` import "vela/op" myMessage: { "hello": "world" } myRequest: op.#Slack & { message: myMessage slackUrl: "slackURL" } ``` ### DingTalk Send a request to the specified DingTalk URL. `#DingTalk` is actually a secondary wrapper of `#HTTPPost`, we will deprecate this operation in the next version. You can use `#HTTPPost` instead, please refer to the example in Slack action. **Parameters** ``` #DingTalk: { message: {...} dingUrl: string } ``` **Example** ``` import "vela/op" myMessage: { "hello": "world" } myRequest: op.#DingTalk & { message: myMessage dingUrl: "dingURL" } ``` ### Lark Send a request to the specified Lark URL. `#Lark` is actually a secondary wrapper of `#HTTPPost`, we will deprecate this operation in the next version. You can use `#HTTPPost` instead, please refer to the example in Slack action. **Parameters** ``` #Lark: { message: {...} larkUrl: string } ``` **Example** ``` import "vela/op" myMessage: { "hello": "world" } myRequest: op.#Lark & { message: myMessage larkUrl: "larkURL" } ```