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  }