mirror of
https://github.com/kubevela/kubevela.git
synced 2026-08-19 04:26:39 +00:00
Feat(workflow): Add op.#Task action (#2220)
* Feat(workflow): tekton task * Feat(tools): random string * Fix(example): defintion fmt * Fix(rand): gosec weak random
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: WorkflowStepDefinition
|
||||
metadata:
|
||||
name: build
|
||||
namespace: vela-system
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |-
|
||||
import ("vela/op")
|
||||
|
||||
parameter: {
|
||||
repoUrl: string
|
||||
dockerfile: string
|
||||
image: string
|
||||
}
|
||||
|
||||
let pushImage=image
|
||||
|
||||
build: op.#Task & {
|
||||
name: "\(context.name)-\(context.stepId)"
|
||||
namespace: context.namespace
|
||||
|
||||
// Declare workspaces that used to share data.
|
||||
workspace: {
|
||||
"code-dir": {}
|
||||
}
|
||||
|
||||
steps: [
|
||||
// git clone code repo.
|
||||
{
|
||||
name: "git-clone"
|
||||
image: "git-image-with-pull-ssh"
|
||||
workspaceMounts: [{workspace: workspace["code-dir"], mountPath: "/data/code"}]
|
||||
script: """
|
||||
#! /bin/bash
|
||||
git clone \(repourl) /data/code
|
||||
"""
|
||||
},
|
||||
// build and push image.
|
||||
{
|
||||
name: "build-image"
|
||||
image: "gcr.io/kaniko-project/executor:v1.3.0"
|
||||
workspaceMounts: [{workspace: workspace["code-dir"], mountPath: "/data/build"}]
|
||||
script: """
|
||||
#! /bin/bash
|
||||
/kaniko/executor --dockerfile=/data/build/\(dockerfile) --context=/data/build --destination=\(pushImage)
|
||||
"""
|
||||
}]
|
||||
}
|
||||
|
||||
// wait until deployment ready
|
||||
wait: op.#ConditionalWait & {
|
||||
continue: build.do.status.phase == "successed"
|
||||
}
|
||||
+35
-32
@@ -1,6 +1,8 @@
|
||||
import (
|
||||
"encoding/yaml"
|
||||
"encoding/json"
|
||||
"encoding/base64"
|
||||
"strings"
|
||||
)
|
||||
|
||||
#ConditionalWait: {
|
||||
@@ -16,13 +18,13 @@ import (
|
||||
#Apply: kube.#Apply
|
||||
|
||||
#ApplyApplication: #Steps & {
|
||||
load: ws.#Load @step(1)
|
||||
load: ws.#Load @step(1)
|
||||
components: #Steps & {
|
||||
for name, c in load.value {
|
||||
"\(name)": #Steps & {
|
||||
workload: kube.#Apply & {value: c.workload}
|
||||
if c.auxiliaries != _|_ {
|
||||
_key: "trait.oam.dev/resource"
|
||||
_key: "trait.oam.dev/resource"
|
||||
for index, o in c.auxiliaries {
|
||||
"\(o.metadata.labels[_key])": kube.#Apply & {value: o}
|
||||
}
|
||||
@@ -34,35 +36,34 @@ import (
|
||||
|
||||
#ApplyComponent: #Steps & {
|
||||
|
||||
component: string
|
||||
_componentName: component
|
||||
load: ws.#Load & {
|
||||
component: _componentName
|
||||
} @step(1)
|
||||
component: string
|
||||
_componentName: component
|
||||
load: ws.#Load & {
|
||||
component: _componentName
|
||||
} @step(1)
|
||||
|
||||
traits: #Steps & {
|
||||
_key: "trait.oam.dev/resource"
|
||||
_manWlKey: "trait.oam.dev/manage-workload"
|
||||
skipApplyWorkload: *false | bool
|
||||
if load.value.auxiliaries != _|_ {
|
||||
for o in load.value.auxiliaries {
|
||||
"\(o.metadata.labels[_key])": kube.#Apply & {value: o}
|
||||
if o.metadata.labels[_manWlKey] != _|_ {
|
||||
skipApplyWorkload: true
|
||||
}
|
||||
}
|
||||
}
|
||||
} @step(2)
|
||||
|
||||
workload__: {
|
||||
if !traits.skipApplyWorkload {
|
||||
kube.#Apply & {
|
||||
value: load.value.workload
|
||||
...
|
||||
}
|
||||
}
|
||||
} @step(3)
|
||||
traits: #Steps & {
|
||||
_key: "trait.oam.dev/resource"
|
||||
_manWlKey: "trait.oam.dev/manage-workload"
|
||||
skipApplyWorkload: *false | bool
|
||||
if load.value.auxiliaries != _|_ {
|
||||
for o in load.value.auxiliaries {
|
||||
"\(o.metadata.labels[_key])": kube.#Apply & {value: o}
|
||||
if o.metadata.labels[_manWlKey] != _|_ {
|
||||
skipApplyWorkload: true
|
||||
}
|
||||
}
|
||||
}
|
||||
} @step(2)
|
||||
|
||||
workload__: {
|
||||
if !traits.skipApplyWorkload {
|
||||
kube.#Apply & {
|
||||
value: load.value.workload
|
||||
...
|
||||
}
|
||||
}
|
||||
} @step(3)
|
||||
}
|
||||
|
||||
#ApplyRemaining: #Steps & {
|
||||
@@ -110,9 +111,9 @@ import (
|
||||
}
|
||||
|
||||
#DingTalk: #Steps & {
|
||||
message: dingDing.#DingMessage
|
||||
dingUrl: string
|
||||
do: http.#Do & {
|
||||
message: dingDing.#DingMessage
|
||||
dingUrl: string
|
||||
do: http.#Do & {
|
||||
method: "POST"
|
||||
url: dingUrl
|
||||
request: {
|
||||
@@ -194,4 +195,6 @@ import (
|
||||
...
|
||||
}
|
||||
|
||||
#Task: task.#Task
|
||||
|
||||
NoExist: _|_
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
|
||||
let toolImage = "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/entrypoint:v0.27.2"
|
||||
let baseImage = "gcr.io/distroless/base@sha256:aa4fd987555ea10e1a4ec8765da8158b5ffdfef1e72da512c7ede509bc9966c4"
|
||||
|
||||
#Task: {
|
||||
#do: "steps"
|
||||
name: string
|
||||
namespace: string
|
||||
workspace: [_name_=string]: #workspace & {name: "\(_name_)"}
|
||||
steps: [...#Script]
|
||||
|
||||
_name: name
|
||||
_namespace: namespace
|
||||
_generate_scripts: [ for i, x in steps {"""
|
||||
scriptfile="/vela/scripts/script-\(i)"
|
||||
touch ${scriptfile} && chmod +x ${scriptfile}
|
||||
cat > ${scriptfile} << '_EOF_'
|
||||
\(base64.Encode(null, x.script))
|
||||
_EOF_
|
||||
"""}]
|
||||
do: {
|
||||
value: #PodTask & {
|
||||
_scripts: strings.Join(_generate_scripts, "")
|
||||
_workspace: workspace
|
||||
metadata: {
|
||||
name: _name
|
||||
namespace: _namespace
|
||||
}
|
||||
spec: containers: [ for i, step in steps {
|
||||
#StepContainer
|
||||
name: step.name
|
||||
image: step.image
|
||||
env: step.envs
|
||||
_workspaceMounts: workspace
|
||||
_index: i
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Script: {
|
||||
name: string
|
||||
image: string
|
||||
script: string
|
||||
envs: [...{name: string, value: string}]
|
||||
workspaceMounts: [...{workspace: #workspace, mountPath: string}]
|
||||
}
|
||||
|
||||
#workspace: {
|
||||
name: string
|
||||
}
|
||||
|
||||
#PodTask: {
|
||||
_scripts: string
|
||||
_workspace: {...}
|
||||
_volumes: [ for x in _workspace {name: x.name, emptyDir: {}}]
|
||||
apiVersion: "v1"
|
||||
kind: "Pod"
|
||||
metadata: {
|
||||
annotations: "vela.dev/ready": "READY"
|
||||
namespace: *"default" | string
|
||||
name: string
|
||||
}
|
||||
spec: {
|
||||
containers: [...#StepContainer]
|
||||
initContainers: [
|
||||
{
|
||||
name: "place-tools"
|
||||
command: ["/ko-app/entrypoint", "cp", "/ko-app/entrypoint", "/vela/tools/entrypoint"]
|
||||
image: toolImage
|
||||
imagePullPolicy: "IfNotPresent"
|
||||
volumeMounts: [{name: "vela-internal-tools", mountPath: "/vela/tools"}]
|
||||
}, {
|
||||
name: "place-scripts"
|
||||
imagePullPolicy: "IfNotPresent"
|
||||
image: baseImage
|
||||
command: ["sh"]
|
||||
args: ["-c", _scripts + "\n/vela/tools/entrypoint decode-script \"${scriptfile}\""]
|
||||
volumeMounts: [{name: "vela-internal-scripts", mountPath: "/vela/scripts"}, {name: "vela-internal-tools", mountPath: "/vela/tools"}]
|
||||
}]
|
||||
volumes: [
|
||||
{emptyDir: {}
|
||||
name: "vela-internal-workspace"
|
||||
},
|
||||
{emptyDir: {}
|
||||
name: "vela-internal-home"
|
||||
},
|
||||
{emptyDir: {}
|
||||
name: "vela-internal-results"
|
||||
},
|
||||
{emptyDir: {}
|
||||
name: "vela-internal-steps"
|
||||
},
|
||||
{emptyDir: {}
|
||||
name: "vela-internal-scripts"
|
||||
},
|
||||
{emptyDir: {}
|
||||
name: "vela-internal-tools"
|
||||
},
|
||||
{downwardAPI: {
|
||||
defaultMode: 420
|
||||
items: [{
|
||||
fieldRef: {
|
||||
apiVersion: "v1"
|
||||
fieldPath: "metadata.annotations['vela.dev/ready']"
|
||||
}
|
||||
path: "ready"
|
||||
}]
|
||||
}
|
||||
name: "vela-internal-downward"
|
||||
}] + _volumes
|
||||
restartPolicy: "Never"
|
||||
}
|
||||
}
|
||||
|
||||
#StepContainer: {
|
||||
_index: int
|
||||
_waitFile: *"/vela/downward/ready" | string
|
||||
if _index != 0 {
|
||||
_waitFile: "/vela/tools/\(_index)"
|
||||
}
|
||||
_workspaceMounts: {...}
|
||||
_volumeMounts: [ for v in _workspaceMounts {name: v.workspace.name, mountPath: v.mountPath}]
|
||||
|
||||
name: string
|
||||
args: ["-wait_file", _waitFile, "-wait_file_content", "-post_file", "/vela/tools/\(_index)", "-termination_path", "/vela/termination", "-step_metadata_dir", "/vela/steps/step-\(name)", "-step_metadata_dir_link", "/vela/steps/\(_index)", "-entrypoint", "/vela/scripts/script-\(_index)", "--"]
|
||||
command: ["/vela/tools/entrypoint"]
|
||||
env?: _
|
||||
image: string
|
||||
imagePullPolicy: "Always"
|
||||
terminationMessagePath: "/vela/termination"
|
||||
terminationMessagePolicy: "File"
|
||||
volumeMounts: [{
|
||||
name: "vela-internal-scripts"
|
||||
mountPath: "/vela/scripts"
|
||||
}, {
|
||||
name: "vela-internal-tools"
|
||||
mountPath: "/vela/tools"
|
||||
}, {
|
||||
name: "vela-internal-downward"
|
||||
mountPath: "/vela/downward"
|
||||
}, {
|
||||
name: "vela-internal-workspace"
|
||||
mountPath: "/workspace"
|
||||
}, {
|
||||
name: "vela-internal-home"
|
||||
mountPath: "/vela/home"
|
||||
}, {
|
||||
name: "vela-internal-results"
|
||||
mountPath: "/vela/results"
|
||||
}, {
|
||||
name: "vela-internal-steps"
|
||||
mountPath: "/vela/steps"
|
||||
}] + _volumeMounts
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
var letters = []rune("abcdefghijklmnopqrstuvwxyz123456789")
|
||||
|
||||
// RandomString generate random string.
|
||||
func RandomString(n int) string {
|
||||
randSrc := rand.NewSource(time.Now().UnixNano())
|
||||
b := make([]rune, n)
|
||||
for i := range b {
|
||||
b[i] = letters[randSrc.Int63()%int64(len(letters))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRandom(t *testing.T) {
|
||||
s1 := RandomString(10)
|
||||
s2 := RandomString(10)
|
||||
if s1 == s2 {
|
||||
t.Error("random generate same string")
|
||||
}
|
||||
if len(s1) != 10 {
|
||||
t.Error("s1 length != 10")
|
||||
}
|
||||
if len(s2) != 10 {
|
||||
t.Error("s2 length != 10")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user