github.com/argoproj/argo-cd/v3@v3.2.1/applicationset/generators/matrix.go (about) 1 package generators 2 3 import ( 4 "errors" 5 "fmt" 6 "time" 7 8 "dario.cat/mergo" 9 "sigs.k8s.io/controller-runtime/pkg/client" 10 11 "github.com/argoproj/argo-cd/v3/applicationset/utils" 12 argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1" 13 ) 14 15 var _ Generator = (*MatrixGenerator)(nil) 16 17 var ( 18 ErrMoreThanTwoGenerators = errors.New("found more than two generators, Matrix support only two") 19 ErrLessThanTwoGenerators = errors.New("found less than two generators, Matrix support only two") 20 ErrMoreThenOneInnerGenerators = errors.New("found more than one generator in matrix.Generators") 21 ) 22 23 type MatrixGenerator struct { 24 // The inner generators supported by the matrix generator (cluster, git, list...) 25 supportedGenerators map[string]Generator 26 } 27 28 func NewMatrixGenerator(supportedGenerators map[string]Generator) Generator { 29 m := &MatrixGenerator{ 30 supportedGenerators: supportedGenerators, 31 } 32 return m 33 } 34 35 func (m *MatrixGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet, client client.Client) ([]map[string]any, error) { 36 if appSetGenerator.Matrix == nil { 37 return nil, ErrEmptyAppSetGenerator 38 } 39 40 if len(appSetGenerator.Matrix.Generators) < 2 { 41 return nil, ErrLessThanTwoGenerators 42 } 43 44 if len(appSetGenerator.Matrix.Generators) > 2 { 45 return nil, ErrMoreThanTwoGenerators 46 } 47 48 res := []map[string]any{} 49 50 g0, err := m.getParams(appSetGenerator.Matrix.Generators[0], appSet, nil, client) 51 if err != nil { 52 return nil, fmt.Errorf("error failed to get params for first generator in matrix generator: %w", err) 53 } 54 for _, a := range g0 { 55 g1, err := m.getParams(appSetGenerator.Matrix.Generators[1], appSet, a, client) 56 if err != nil { 57 return nil, fmt.Errorf("failed to get params for second generator in the matrix generator: %w", err) 58 } 59 for _, b := range g1 { 60 if appSet.Spec.GoTemplate { 61 tmp := map[string]any{} 62 if err := mergo.Merge(&tmp, b, mergo.WithOverride); err != nil { 63 return nil, fmt.Errorf("failed to merge params from the second generator in the matrix generator with temp map: %w", err) 64 } 65 if err := mergo.Merge(&tmp, a, mergo.WithOverride); err != nil { 66 return nil, fmt.Errorf("failed to merge params from the second generator in the matrix generator with the first: %w", err) 67 } 68 res = append(res, tmp) 69 } else { 70 val, err := utils.CombineStringMaps(a, b) 71 if err != nil { 72 return nil, fmt.Errorf("failed to combine string maps with merging params for the matrix generator: %w", err) 73 } 74 res = append(res, val) 75 } 76 } 77 } 78 79 return res, nil 80 } 81 82 func (m *MatrixGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.ApplicationSetNestedGenerator, appSet *argoprojiov1alpha1.ApplicationSet, params map[string]any, client client.Client) ([]map[string]any, error) { 83 matrixGen, err := getMatrixGenerator(appSetBaseGenerator) 84 if err != nil { 85 return nil, err 86 } 87 mergeGen, err := getMergeGenerator(appSetBaseGenerator) 88 if err != nil { 89 return nil, fmt.Errorf("error retrieving merge generator: %w", err) 90 } 91 92 t, err := Transform( 93 argoprojiov1alpha1.ApplicationSetGenerator{ 94 List: appSetBaseGenerator.List, 95 Clusters: appSetBaseGenerator.Clusters, 96 Git: appSetBaseGenerator.Git, 97 SCMProvider: appSetBaseGenerator.SCMProvider, 98 ClusterDecisionResource: appSetBaseGenerator.ClusterDecisionResource, 99 PullRequest: appSetBaseGenerator.PullRequest, 100 Plugin: appSetBaseGenerator.Plugin, 101 Matrix: matrixGen, 102 Merge: mergeGen, 103 Selector: appSetBaseGenerator.Selector, 104 }, 105 m.supportedGenerators, 106 argoprojiov1alpha1.ApplicationSetTemplate{}, 107 appSet, 108 params, 109 client) 110 if err != nil { 111 return nil, fmt.Errorf("child generator returned an error on parameter generation: %w", err) 112 } 113 114 if len(t) == 0 { 115 return nil, errors.New("child generator generated no parameters") 116 } 117 118 if len(t) > 1 { 119 return nil, ErrMoreThenOneInnerGenerators 120 } 121 122 return t[0].Params, nil 123 } 124 125 const maxDuration time.Duration = 1<<63 - 1 126 127 func (m *MatrixGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) time.Duration { 128 res := maxDuration 129 var found bool 130 131 for _, r := range appSetGenerator.Matrix.Generators { 132 matrixGen, _ := getMatrixGenerator(r) 133 mergeGen, _ := getMergeGenerator(r) 134 base := &argoprojiov1alpha1.ApplicationSetGenerator{ 135 List: r.List, 136 Clusters: r.Clusters, 137 Git: r.Git, 138 PullRequest: r.PullRequest, 139 Plugin: r.Plugin, 140 SCMProvider: r.SCMProvider, 141 ClusterDecisionResource: r.ClusterDecisionResource, 142 Matrix: matrixGen, 143 Merge: mergeGen, 144 } 145 generators := GetRelevantGenerators(base, m.supportedGenerators) 146 147 for _, g := range generators { 148 temp := g.GetRequeueAfter(base) 149 if temp < res && temp != NoRequeueAfter { 150 found = true 151 res = temp 152 } 153 } 154 } 155 156 if found { 157 return res 158 } 159 return NoRequeueAfter 160 } 161 162 func getMatrixGenerator(r argoprojiov1alpha1.ApplicationSetNestedGenerator) (*argoprojiov1alpha1.MatrixGenerator, error) { 163 if r.Matrix == nil { 164 return nil, nil 165 } 166 matrix, err := argoprojiov1alpha1.ToNestedMatrixGenerator(r.Matrix) 167 if err != nil { 168 return nil, err 169 } 170 return matrix.ToMatrixGenerator(), nil 171 } 172 173 func (m *MatrixGenerator) GetTemplate(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) *argoprojiov1alpha1.ApplicationSetTemplate { 174 return &appSetGenerator.Matrix.Template 175 }