Feat: envbinding support cloud resource deploy and share (#2734)

* Feat: envbinding support cloud resource deploy and bind

* Fix: change bind-cloud-resource to share-cloud-resource
This commit is contained in:
Somefive
2021-11-20 13:07:27 +08:00
committed by GitHub
parent b38aa1cdf0
commit 34aa74ff48
18 changed files with 911 additions and 26 deletions
@@ -0,0 +1,32 @@
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
# Definition source cue file: vela-templates/definitions/internal/deploy-cloud-resource.cue
apiVersion: core.oam.dev/v1beta1
kind: WorkflowStepDefinition
metadata:
annotations:
definition.oam.dev/description: Deploy cloud resource and bind secret to clusters
name: deploy-cloud-resource
namespace: {{.Values.systemDefinitionNamespace}}
spec:
schematic:
cue:
template: |
import (
"vela/op"
)
app: op.#DeployCloudResource & {
env: parameter.env
policy: parameter.policy
// context.namespace indicates the namespace of the app
namespace: context.namespace
// context.namespace indicates the name of the app
name: context.name
}
parameter: {
// +usage=Declare the name of the env-binding policy, if empty, the first env-binding policy will be used
policy: *"" | string
// +usage=Declare the name of the env in policy
env: string
}
@@ -23,8 +23,8 @@ spec:
namespace: context.namespace
}
parameter: {
// +usage=Declare the name of the policy
policy: string
// +usage=Declare the name of the env-binding policy, if empty, the first env-binding policy will be used
policy: *"" | string
// +usage=Declare the name of the env in policy
env: string
}
@@ -0,0 +1,39 @@
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
# Definition source cue file: vela-templates/definitions/internal/share-cloud-resource.cue
apiVersion: core.oam.dev/v1beta1
kind: WorkflowStepDefinition
metadata:
annotations:
definition.oam.dev/description: Sync secrets created by terraform component to runtime clusters so that runtime clusters can share the created cloud resource.
name: share-cloud-resource
namespace: {{.Values.systemDefinitionNamespace}}
spec:
schematic:
cue:
template: |
import (
"vela/op"
)
app: op.#ShareCloudResource & {
env: parameter.env
policy: parameter.policy
placements: parameter.placements
// context.namespace indicates the namespace of the app
namespace: context.namespace
// context.namespace indicates the name of the app
name: context.name
}
parameter: {
env: string
// +usage=Declare the location to bind
placements: [...{
namespace?: string
cluster?: string
}]
// +usage=Declare the name of the env-binding policy, if empty, the first env-binding policy will be used
policy: *"" | string
// +usage=Declare the name of the env in policy
env: string
}
@@ -0,0 +1,39 @@
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
# Definition source cue file: vela-templates/definitions/internal/bind-cloud-resource.cue
apiVersion: core.oam.dev/v1beta1
kind: WorkflowStepDefinition
metadata:
annotations:
definition.oam.dev/description: Sync secrets created by terraform component to runtime clusters
name: bind-cloud-resource
namespace: {{.Values.systemDefinitionNamespace}}
spec:
schematic:
cue:
template: |
import (
"vela/op"
)
app: op.#BindCloudResource & {
env: parameter.env
policy: parameter.policy
placements: parameter.placements
// context.namespace indicates the namespace of the app
namespace: context.namespace
// context.namespace indicates the name of the app
name: context.name
}
parameter: {
env: string
// +usage=Declare the location to bind
placements: [...{
namespace?: string
cluster?: string
}]
// +usage=Declare the name of the env-binding policy, if empty, the first env-binding policy will be used
policy: *"" | string
// +usage=Declare the name of the env in policy
env: string
}
@@ -0,0 +1,32 @@
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
# Definition source cue file: vela-templates/definitions/internal/deploy-cloud-resource.cue
apiVersion: core.oam.dev/v1beta1
kind: WorkflowStepDefinition
metadata:
annotations:
definition.oam.dev/description: Deploy cloud resource and bind secret to clusters
name: deploy-cloud-resource
namespace: {{.Values.systemDefinitionNamespace}}
spec:
schematic:
cue:
template: |
import (
"vela/op"
)
app: op.#DeployCloudResource & {
env: parameter.env
policy: parameter.policy
// context.namespace indicates the namespace of the app
namespace: context.namespace
// context.namespace indicates the name of the app
name: context.name
}
parameter: {
// +usage=Declare the name of the env-binding policy, if empty, the first env-binding policy will be used
policy: *"" | string
// +usage=Declare the name of the env in policy
env: string
}
@@ -0,0 +1,39 @@
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
# Definition source cue file: vela-templates/definitions/internal/share-cloud-resource.cue
apiVersion: core.oam.dev/v1beta1
kind: WorkflowStepDefinition
metadata:
annotations:
definition.oam.dev/description: Sync secrets created by terraform component to runtime clusters so that runtime clusters can share the created cloud resource.
name: share-cloud-resource
namespace: {{.Values.systemDefinitionNamespace}}
spec:
schematic:
cue:
template: |
import (
"vela/op"
)
app: op.#ShareCloudResource & {
env: parameter.env
policy: parameter.policy
placements: parameter.placements
// context.namespace indicates the namespace of the app
namespace: context.namespace
// context.namespace indicates the name of the app
name: context.name
}
parameter: {
env: string
// +usage=Declare the location to bind
placements: [...{
namespace?: string
cluster?: string
}]
// +usage=Declare the name of the env-binding policy, if empty, the first env-binding policy will be used
policy: *"" | string
// +usage=Declare the name of the env in policy
env: string
}
@@ -0,0 +1,78 @@
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: rds-app
namespace: project-1
spec:
components:
- name: db
type: alibaba-rds
properties:
instance_name: db
account_name: kubevela
password: my-password
writeConnectionSecretToRef:
name: project-1-rds-conn-credential
policies:
- name: env-policy
type: env-binding
properties:
envs:
# 部署 RDS 给杭州集群
- name: hangzhou
placement:
clusterSelector:
name: cluster-hangzhou
patch:
components:
- name: db
type: alibaba-rds
properties:
# region: hangzhou
instance_name: hangzhou_db
# 部署 RDS 给香港集群
- name: hongkong
placement:
clusterSelector:
name: cluster-hongkong
namespaceSelector:
name: hk-project-1
patch:
components:
- name: db
type: alibaba-rds
properties:
# region: hongkong
instance_name: hongkong_db
writeConnectionSecretToRef:
name: hk-project-rds-credential
workflow:
steps:
# 部署 RDS 给杭州区用
- name: deploy-hangzhou-rds
type: deploy-cloud-resource
properties:
env: hangzhou
# 将给杭州区用的 RDS 共享给北京区
- name: share-hangzhou-rds-to-beijing
type: share-cloud-resource
properties:
env: hangzhou
placements:
- cluster: cluster-beijing
# 部署 RDS 给香港区用
- name: deploy-hongkong-rds
type: deploy-cloud-resource
properties:
env: hongkong
# 将给香港区用的 RDS 共享给香港区其他项目用
- name: share-hongkong-rds-to-other-namespace
type: share-cloud-resource
properties:
env: hongkong
placements:
- cluster: cluster-hongkong
namespace: hk-project-2
- cluster: cluster-hongkong
namespace: hk-project-3
@@ -41,6 +41,7 @@ import (
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
velatypes "github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/appfile"
common2 "github.com/oam-dev/kubevela/pkg/controller/common"
core "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev"
"github.com/oam-dev/kubevela/pkg/controller/core.oam.dev/v1alpha2/application/assemble"
"github.com/oam-dev/kubevela/pkg/cue/packages"
@@ -88,7 +89,7 @@ type Reconciler struct {
// Reconcile process app event
// nolint:gocyclo
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
ctx, cancel := context.WithTimeout(ctx, time.Minute)
ctx, cancel := context.WithTimeout(ctx, common2.ReconcileTimeout)
defer cancel()
logCtx := monitorContext.NewTraceContext(ctx, "").AddTag("application", req.String(), "controller", "application")
@@ -37,6 +37,7 @@ import (
"github.com/oam-dev/kubevela/pkg/workflow/providers/kube"
multiclusterProvider "github.com/oam-dev/kubevela/pkg/workflow/providers/multicluster"
oamProvider "github.com/oam-dev/kubevela/pkg/workflow/providers/oam"
terraformProvider "github.com/oam-dev/kubevela/pkg/workflow/providers/terraform"
"github.com/oam-dev/kubevela/pkg/workflow/tasks"
wfTypes "github.com/oam-dev/kubevela/pkg/workflow/types"
)
@@ -54,6 +55,9 @@ func (h *AppHandler) GenerateApplicationSteps(ctx context.Context,
appParser, appRev, af), h.renderComponentFunc(appParser, appRev, af))
taskDiscover := tasks.NewTaskDiscover(handlerProviders, h.r.pd, h.r.Client, h.r.dm)
multiclusterProvider.Install(handlerProviders, h.r.Client, app)
terraformProvider.Install(handlerProviders, app, func(comp common.ApplicationComponent) (*appfile.Workload, error) {
return appParser.ParseWorkloadFromRevision(comp, appRev)
})
var tasks []wfTypes.TaskRunner
for _, step := range af.WorkflowSteps {
options := &wfTypes.GeneratorOptions{
+4
View File
@@ -107,6 +107,10 @@ import (
#ApplyEnvBindApp: multicluster.#ApplyEnvBindApp
#DeployCloudResource: terraform.#DeployCloudResource
#ShareCloudResource: terraform.#ShareCloudResource
#LoadPolicies: oam.#LoadPolicies
#ListClusters: multicluster.#ListClusters
+70 -19
View File
@@ -68,35 +68,64 @@
...
}
#ApplyEnvBindApp: {
#do: "steps"
env: string
policy: string
app: string
namespace: string
#LoadEnvBindingEnv: #Steps & {
inputs: {
env: string
policy: string
}
loadPolicies: oam.#LoadPolicies @step(1)
loadPolicy: loadPolicies.value["\(policy)"]
policy_: string
if inputs.policy == "" {
envBindingPolicies: [ for k, v in loadPolicies.value if v.type == "env-binding" {k}]
policy_: envBindingPolicies[0]
}
if inputs.policy != "" {
policy_: inputs.policy
}
loadPolicy: loadPolicies.value["\(policy_)"]
envMap: {
for ev in loadPolicy.properties.envs {
"\(ev.name)": ev
}
...
}
envConfig: envMap["\(env)"]
envConfig_: envMap["\(inputs.env)"]
placementDecisions: multicluster.#MakePlacementDecisions & {
outputs: {
policy: policy_
envConfig: envConfig_
}
}
#PrepareEnvBinding: #Steps & {
inputs: {
env: string
policy: string
}
env_: inputs.env
policy_: inputs.policy
loadEnv: #LoadEnvBindingEnv & {
inputs: {
policyName: policy
envName: env
env: env_
policy: policy_
}
} @step(1)
envConfig: loadEnv.outputs.envConfig
placementDecisions: #MakePlacementDecisions & {
inputs: {
policyName: loadEnv.outputs.policy
envName: env_
placement: envConfig.placement
}
} @step(2)
patchedApp: multicluster.#PatchApplication & {
patchedApp: #PatchApplication & {
inputs: {
envName: env
envName: env_
if envConfig.selector != _|_ {
selector: envConfig.selector
}
@@ -106,10 +135,32 @@
}
} @step(3)
components: patchedApp.outputs.spec.components
apply: #Steps & {
for decision in placementDecisions.outputs.decisions {
for key, comp in components {
outputs: {
components: patchedApp.outputs.spec.components
decisions: placementDecisions.outputs.decisions
}
}
#ApplyEnvBindApp: {
#do: "steps"
env: string
policy: string
app: string
namespace: string
env_: env
policy_: policy
prepare: #PrepareEnvBinding & {
inputs: {
env: env_
policy: policy_
}
} @step(1)
apply: #Steps & {
for decision in prepare.outputs.decisions {
for key, comp in prepare.outputs.components {
"\(decision.cluster)-\(decision.namespace)-\(key)": #ApplyComponent & {
value: comp
if decision.cluster != _|_ {
@@ -118,7 +169,7 @@
if decision.namespace != _|_ {
namespace: decision.namespace
}
} @step(4)
} @step(2)
}
}
}
+280
View File
@@ -0,0 +1,280 @@
#LoadTerraformComponents: {
#provider: "terraform"
#do: "load-terraform-components"
outputs: {
components: [...multicluster.#Component]
}
}
#GetConnectionStatus: {
#provider: "terraform"
#do: "get-connection-status"
inputs: {
componentName: string
}
outputs: {
healthy?: bool
}
}
#PrepareTerraformEnvBinding: #Steps & {
inputs: {
env: string
policy: string
}
env_: inputs.env
policy_: inputs.policy
prepare: multicluster.#PrepareEnvBinding & {
inputs: {
env: env_
policy: policy_
}
} @step(1)
loadTerraformComponents: #LoadTerraformComponents @step(2)
terraformComponentMap: {
for _, comp in loadTerraformComponents.outputs.components {
"\(comp.name)": comp
}
...
}
components_: [ for comp in prepare.outputs.components if terraformComponentMap["\(comp.name)"] != _|_ {comp}]
outputs: {
components: components_
decisions: prepare.outputs.decisions
}
}
#loadSecretInfo: {
component: {...}
appNamespace: string
name: string
namespace: string
env: string
if component.properties != _|_ && component.properties.writeConnectionSecretToRef != _|_ {
if component.properties.writeConnectionSecretToRef.name != _|_ {
name: component.properties.writeConnectionSecretToRef.name
}
if component.properties.writeConnectionSecretToRef.name == _|_ {
name: component.name
}
if component.properties.writeConnectionSecretToRef.namespace != _|_ {
namespace: component.properties.writeConnectionSecretToRef.namespace
}
if component.properties.writeConnectionSecretToRef.namespace == _|_ {
namespace: appNamespace
}
}
envName: "\(name)-\(env)"
}
#bindTerraformComponentToCluster: #Steps & {
comp: {...}
secret: {...}
env: string
decisions: [...{...}]
status: terraform.#GetConnectionStatus & {
inputs: componentName: "\(comp.name)-\(env)"
} @step(1)
read: kube.#Read & {
value: {
apiVersion: "v1"
kind: "Secret"
metadata: {
name: secret.envName
namespace: secret.namespace
...
}
...
}
} @step(2)
wait: {
#do: "wait"
continue: status.outputs.healthy && read.err == _|_
} @step(3)
sync: #Steps & {
for decision in decisions {
"\(decision.cluster)-\(decision.namespace)": kube.#Apply & {
cluster: decision.cluster
value: {
apiVersion: "v1"
kind: "Secret"
metadata: {
name: secret.name
if decision.namespace != _|_ && decision.namespace != "" {
namespace: decision.namespace
}
if decision.namespace == _|_ || decision.namespace == "" {
namespace: secret.namespace
}
...
}
type: "Opaque"
data: read.value.data
...
}
}
}
} @step(4)
}
#DeployCloudResource: {
#do: "steps"
env: string
name: string
policy: string
namespace: string
env_: env
policy_: policy
prepareDeploy: #PrepareTerraformEnvBinding & {
inputs: {
env: env_
policy: policy_
}
} @step(1)
deploy: #Steps & {
for comp in prepareDeploy.outputs.components {
"\(comp.name)": #Steps & {
secretMeta: #loadSecretInfo & {
component: comp
env: env_
appNamespace: namespace
}
apply: #ApplyComponent & {
value: {
name: "\(comp.name)-\(env)"
properties: {
writeConnectionSecretToRef: {
name: secretMeta.envName
namespace: secretMeta.namespace
}
if comp.properties != _|_ {
for k, v in comp.properties {
if k != "writeConnectionSecretToRef" {
"\(k)": v
}
}
}
...
}
for k, v in comp {
if k != "name" && k != "properties" {
"\(k)": v
}
}
...
}
} @step(1)
comp_: comp
bind: #bindTerraformComponentToCluster & {
comp: comp_
secret: secretMeta
env: env_
decisions: prepareDeploy.outputs.decisions
} @step(2)
secret: bind.read.value
update: kube.#Apply & {
value: {
metadata: {
for k, v in secret.metadata {
if k != "labels" {
"\(k)": v
}
}
labels: {
"app.oam.dev/name": name
"app.oam.dev/namespace": namespace
"app.oam.dev/component": comp.name
"app.oam.dev/env-name": env
"app.oam.dev/sync-alias": secretMeta.name
if secret.metadata.labels != _|_ {
for k, v in secret.metadata.labels {
if k != "app.oam.dev/name" && k != "app.oam.dev/sync-alias" && k != "app.oam.dev/env-name" {
"\(k)": v
}
}
}
...
}
}
for k, v in secret {
if k != "metadata" {
"\(k)": v
}
}
...
}
} @step(6)
}
}
...
} @step(2)
}
#ShareCloudResource: {
#do: "steps"
env: string
name: string
policy: string
namespace: string
namespace_: namespace
placements: [...multicluster.#PlacementDecision]
env_: env
policy_: policy
prepareBind: #PrepareTerraformEnvBinding & {
inputs: {
env: env_
policy: policy_
}
} @step(1)
decisions_: [ for placement in placements {
namespace: *"" | string
if placement.namespace != _|_ {
namespace: placement.namespace
}
if placement.namespace == _|_ {
namespace: namespace_
}
cluster: *"local" | string
if placement.cluster != _|_ {
cluster: placement.cluster
}
}]
deploy: #Steps & {
for comp in prepareBind.outputs.components {
"\(comp.name)": #Steps & {
secretMeta: #loadSecretInfo & {
component: comp
env: env_
appNamespace: namespace
}
comp_: comp
bind: #bindTerraformComponentToCluster & {
comp: comp_
secret: secretMeta
env: env_
decisions: decisions_
} @step(1)
}
}
} @step(2)
}
+1 -2
View File
@@ -19,12 +19,11 @@ package kube
import (
"context"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/pkg/cue/model"
"github.com/oam-dev/kubevela/pkg/cue/model/value"
"github.com/oam-dev/kubevela/pkg/multicluster"
@@ -0,0 +1,80 @@
/*
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 terraform
import (
"github.com/pkg/errors"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/appfile"
"github.com/oam-dev/kubevela/pkg/cue/model/value"
wfContext "github.com/oam-dev/kubevela/pkg/workflow/context"
"github.com/oam-dev/kubevela/pkg/workflow/providers"
wfTypes "github.com/oam-dev/kubevela/pkg/workflow/types"
)
const (
// ProviderName is provider name for install.
ProviderName = "terraform"
)
// WorkloadRenderer renderer to render application component into workload
type WorkloadRenderer func(comp common.ApplicationComponent) (*appfile.Workload, error)
type provider struct {
app *v1beta1.Application
renderer WorkloadRenderer
}
func (p *provider) LoadTerraformComponents(ctx wfContext.Context, v *value.Value, act wfTypes.Action) error {
var components []common.ApplicationComponent
for _, comp := range p.app.Spec.Components {
wl, err := p.renderer(comp)
if err != nil {
return errors.Wrapf(err, "failed to render component into workload")
}
if wl.CapabilityCategory != types.TerraformCategory {
continue
}
components = append(components, comp)
}
return v.FillObject(components, "outputs", "components")
}
func (p *provider) GetConnectionStatus(ctx wfContext.Context, v *value.Value, act wfTypes.Action) error {
componentName, err := v.GetString("inputs", "componentName")
if err != nil {
return errors.Wrapf(err, "failed to get component name")
}
for _, svc := range p.app.Status.Services {
if svc.Name == componentName {
return v.FillObject(svc.Healthy, "outputs", "healthy")
}
}
return v.FillObject(false, "outputs", "healthy")
}
// Install register handlers to provider discover.
func Install(p providers.Providers, app *v1beta1.Application, renderer WorkloadRenderer) {
prd := &provider{app: app, renderer: renderer}
p.Register(ProviderName, map[string]providers.Handler{
"load-terraform-components": prd.LoadTerraformComponents,
"get-connection-status": prd.GetConnectionStatus,
})
}
@@ -0,0 +1,146 @@
/*
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 terraform
import (
"strings"
"testing"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
apicommon "github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/appfile"
"github.com/oam-dev/kubevela/pkg/cue/model/value"
"github.com/oam-dev/kubevela/pkg/workflow/providers/mock"
)
func fakeWorkloadRenderer(comp apicommon.ApplicationComponent) (*appfile.Workload, error) {
if strings.HasPrefix(comp.Name, "error") {
return nil, errors.New(comp.Name)
}
if strings.HasPrefix(comp.Name, "terraform") {
return &appfile.Workload{CapabilityCategory: types.TerraformCategory}, nil
}
return &appfile.Workload{CapabilityCategory: types.CUECategory}, nil
}
func TestLoadTerraformComponents(t *testing.T) {
r := require.New(t)
testCases := []struct {
Inputs []apicommon.ApplicationComponent
HasError bool
Outputs []apicommon.ApplicationComponent
}{{
Inputs: []apicommon.ApplicationComponent{{Name: "error"}},
HasError: true,
}, {
Inputs: []apicommon.ApplicationComponent{{Name: "terraform-1"}, {Name: "cue"}, {Name: "terraform-2"}},
Outputs: []apicommon.ApplicationComponent{{Name: "terraform-1"}, {Name: "terraform-2"}},
}, {
Inputs: []apicommon.ApplicationComponent{{Name: "cue"}},
Outputs: []apicommon.ApplicationComponent{},
}}
for _, testCase := range testCases {
app := &v1beta1.Application{}
app.Spec.Components = testCase.Inputs
p := &provider{
app: app,
renderer: fakeWorkloadRenderer,
}
act := &mock.Action{}
v, err := value.NewValue("", nil, "")
r.NoError(err)
err = p.LoadTerraformComponents(nil, v, act)
if testCase.HasError {
r.Error(err)
continue
}
r.NoError(err)
outputs, err := v.LookupValue("outputs", "components")
r.NoError(err)
var comps []apicommon.ApplicationComponent
r.NoError(outputs.UnmarshalTo(&comps))
r.Equal(testCase.Outputs, comps)
}
}
func TestGetConnectionStatus(t *testing.T) {
r := require.New(t)
testCases := []struct {
ComponentName string
Services []apicommon.ApplicationComponentStatus
Healthy bool
Error string
}{{
ComponentName: "",
Error: "failed to get component name",
}, {
ComponentName: "comp",
Services: []apicommon.ApplicationComponentStatus{{
Name: "not-comp",
Healthy: true,
}},
Healthy: false,
}, {
ComponentName: "comp",
Services: []apicommon.ApplicationComponentStatus{{
Name: "not-comp",
Healthy: true,
}, {
Name: "comp",
Healthy: true,
}},
Healthy: true,
}, {
ComponentName: "comp",
Services: []apicommon.ApplicationComponentStatus{{
Name: "not-comp",
Healthy: true,
}, {
Name: "comp",
Healthy: false,
}},
Healthy: false,
}}
for _, testCase := range testCases {
app := &v1beta1.Application{}
app.Status.Services = testCase.Services
p := &provider{
app: app,
renderer: fakeWorkloadRenderer,
}
act := &mock.Action{}
v, err := value.NewValue("", nil, "")
r.NoError(err)
if testCase.ComponentName != "" {
r.NoError(v.FillObject(map[string]string{"componentName": testCase.ComponentName}, "inputs"))
}
err = p.GetConnectionStatus(nil, v, act)
if testCase.Error != "" {
r.Error(err)
r.Contains(err.Error(), testCase.Error)
continue
}
r.NoError(err)
healthy, err := v.GetBool("outputs", "healthy")
r.NoError(err)
r.Equal(testCase.Healthy, healthy)
}
}
@@ -0,0 +1,27 @@
import (
"vela/op"
)
"deploy-cloud-resource": {
type: "workflow-step"
annotations: {}
labels: {}
description: "Deploy cloud resource and bind secret to clusters"
}
template: {
app: op.#DeployCloudResource & {
env: parameter.env
policy: parameter.policy
// context.namespace indicates the namespace of the app
namespace: context.namespace
// context.namespace indicates the name of the app
name: context.name
}
parameter: {
// +usage=Declare the name of the env-binding policy, if empty, the first env-binding policy will be used
policy: *"" | string
// +usage=Declare the name of the env in policy
env: string
}
}
@@ -18,8 +18,8 @@ template: {
}
parameter: {
// +usage=Declare the name of the policy
policy: string
// +usage=Declare the name of the env-binding policy, if empty, the first env-binding policy will be used
policy: *"" | string
// +usage=Declare the name of the env in policy
env: string
}
@@ -0,0 +1,34 @@
import (
"vela/op"
)
"share-cloud-resource": {
type: "workflow-step"
annotations: {}
labels: {}
description: "Sync secrets created by terraform component to runtime clusters so that runtime clusters can share the created cloud resource."
}
template: {
app: op.#ShareCloudResource & {
env: parameter.env
policy: parameter.policy
placements: parameter.placements
// context.namespace indicates the namespace of the app
namespace: context.namespace
// context.namespace indicates the name of the app
name: context.name
}
parameter: {
env: string
// +usage=Declare the location to bind
placements: [...{
namespace?: string
cluster?: string
}]
// +usage=Declare the name of the env-binding policy, if empty, the first env-binding policy will be used
policy: *"" | string
// +usage=Declare the name of the env in policy
env: string
}
}