github.com/oam-dev/kubevela@v1.9.11/pkg/workflow/step/generator.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 step 18 19 import ( 20 "context" 21 "encoding/json" 22 "reflect" 23 24 workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1" 25 wftypes "github.com/kubevela/workflow/pkg/types" 26 "github.com/pkg/errors" 27 "k8s.io/apimachinery/pkg/types" 28 "sigs.k8s.io/controller-runtime/pkg/client" 29 30 "github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha1" 31 "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" 32 "github.com/oam-dev/kubevela/pkg/oam/util" 33 ) 34 35 // WorkflowStepGenerator generator generates workflow steps 36 type WorkflowStepGenerator interface { 37 Generate(app *v1beta1.Application, existingSteps []workflowv1alpha1.WorkflowStep) ([]workflowv1alpha1.WorkflowStep, error) 38 } 39 40 // ChainWorkflowStepGenerator chains multiple workflow step generators 41 type ChainWorkflowStepGenerator struct { 42 generators []WorkflowStepGenerator 43 } 44 45 // Generate generate workflow steps 46 func (g *ChainWorkflowStepGenerator) Generate(app *v1beta1.Application, existingSteps []workflowv1alpha1.WorkflowStep) (steps []workflowv1alpha1.WorkflowStep, err error) { 47 steps = existingSteps 48 for _, generator := range g.generators { 49 steps, err = generator.Generate(app, steps) 50 if err != nil { 51 return steps, errors.Wrapf(err, "generate step failed in WorkflowStepGenerator %s", reflect.TypeOf(generator).Name()) 52 } 53 } 54 return steps, nil 55 } 56 57 // NewChainWorkflowStepGenerator create ChainWorkflowStepGenerator 58 func NewChainWorkflowStepGenerator(generators ...WorkflowStepGenerator) WorkflowStepGenerator { 59 return &ChainWorkflowStepGenerator{generators: generators} 60 } 61 62 // RefWorkflowStepGenerator generate workflow steps from ref workflow 63 type RefWorkflowStepGenerator struct { 64 context.Context 65 client.Client 66 } 67 68 // Generate generate workflow steps 69 func (g *RefWorkflowStepGenerator) Generate(app *v1beta1.Application, existingSteps []workflowv1alpha1.WorkflowStep) (steps []workflowv1alpha1.WorkflowStep, err error) { 70 if app.Spec.Workflow == nil || app.Spec.Workflow.Ref == "" { 71 return existingSteps, nil 72 } 73 if app.Spec.Workflow.Steps != nil { 74 return nil, errors.Errorf("cannot set steps and ref in workflow at the same time") 75 } 76 wf := &workflowv1alpha1.Workflow{} 77 if err = g.Client.Get(g.Context, types.NamespacedName{Namespace: app.GetNamespace(), Name: app.Spec.Workflow.Ref}, wf); err != nil { 78 return 79 } 80 return wf.Steps, nil 81 } 82 83 // ApplyComponentWorkflowStepGenerator generate apply-component workflow steps for all components in the application 84 type ApplyComponentWorkflowStepGenerator struct{} 85 86 // Generate generate workflow steps 87 func (g *ApplyComponentWorkflowStepGenerator) Generate(app *v1beta1.Application, existingSteps []workflowv1alpha1.WorkflowStep) (steps []workflowv1alpha1.WorkflowStep, err error) { 88 if len(existingSteps) > 0 { 89 return existingSteps, nil 90 } 91 for _, comp := range app.Spec.Components { 92 steps = append(steps, workflowv1alpha1.WorkflowStep{ 93 WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{ 94 Name: comp.Name, 95 Type: wftypes.WorkflowStepTypeApplyComponent, 96 Properties: util.Object2RawExtension(map[string]string{ 97 "component": comp.Name, 98 }), 99 }, 100 }) 101 } 102 return 103 } 104 105 // Deploy2EnvWorkflowStepGenerator generate deploy2env workflow steps for all envs in the application 106 type Deploy2EnvWorkflowStepGenerator struct{} 107 108 // Generate generate workflow steps 109 func (g *Deploy2EnvWorkflowStepGenerator) Generate(app *v1beta1.Application, existingSteps []workflowv1alpha1.WorkflowStep) (steps []workflowv1alpha1.WorkflowStep, err error) { 110 if len(existingSteps) > 0 { 111 return existingSteps, nil 112 } 113 for _, policy := range app.Spec.Policies { 114 if policy.Type == v1alpha1.EnvBindingPolicyType && policy.Properties != nil { 115 spec := &v1alpha1.EnvBindingSpec{} 116 if err = json.Unmarshal(policy.Properties.Raw, spec); err != nil { 117 return 118 } 119 for _, env := range spec.Envs { 120 steps = append(steps, workflowv1alpha1.WorkflowStep{ 121 WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{ 122 Name: "deploy-" + policy.Name + "-" + env.Name, 123 Type: "deploy2env", 124 Properties: util.Object2RawExtension(map[string]string{ 125 "policy": policy.Name, 126 "env": env.Name, 127 }), 128 }, 129 }) 130 } 131 } 132 } 133 return 134 } 135 136 // DeployWorkflowStepGenerator generate deploy workflow steps for all topology & override in the application 137 type DeployWorkflowStepGenerator struct{} 138 139 // Generate generate workflow steps 140 func (g *DeployWorkflowStepGenerator) Generate(app *v1beta1.Application, existingSteps []workflowv1alpha1.WorkflowStep) (steps []workflowv1alpha1.WorkflowStep, err error) { 141 if len(existingSteps) > 0 { 142 return existingSteps, nil 143 } 144 var topologies []string 145 var overrides []string 146 for _, policy := range app.Spec.Policies { 147 switch policy.Type { 148 case v1alpha1.TopologyPolicyType: 149 topologies = append(topologies, policy.Name) 150 case v1alpha1.OverridePolicyType: 151 overrides = append(overrides, policy.Name) 152 } 153 } 154 for _, topology := range topologies { 155 steps = append(steps, workflowv1alpha1.WorkflowStep{ 156 WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{ 157 Name: "deploy-" + topology, 158 Type: "deploy", 159 Properties: util.Object2RawExtension(map[string]interface{}{ 160 "policies": append(overrides, topology), 161 }), 162 }, 163 }) 164 } 165 if len(topologies) == 0 { 166 containsRefObjects := false 167 for _, comp := range app.Spec.Components { 168 if comp.Type == v1alpha1.RefObjectsComponentType { 169 containsRefObjects = true 170 break 171 } 172 } 173 if containsRefObjects || len(overrides) > 0 { 174 steps = append(steps, workflowv1alpha1.WorkflowStep{ 175 WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{ 176 Name: "deploy", 177 Type: DeployWorkflowStep, 178 Properties: util.Object2RawExtension(map[string]interface{}{"policies": append([]string{}, overrides...)}), 179 }, 180 }) 181 } 182 } 183 return steps, nil 184 } 185 186 // IsBuiltinWorkflowStepType checks if workflow step type is builtin type 187 func IsBuiltinWorkflowStepType(wfType string) bool { 188 for _, _type := range []string{ 189 wftypes.WorkflowStepTypeSuspend, 190 wftypes.WorkflowStepTypeApplyComponent, 191 wftypes.WorkflowStepTypeBuiltinApplyComponent, 192 wftypes.WorkflowStepTypeStepGroup, 193 } { 194 if _type == wfType { 195 return true 196 } 197 } 198 return false 199 }