github.com/argoproj/argo-cd/v2@v2.10.9/docs/operator-manual/applicationset/Generators-Matrix.md (about)

     1  # Matrix Generator
     2  
     3  The Matrix generator combines the parameters generated by two child generators, iterating through every combination of each generator's generated parameters.
     4  
     5  By combining both generators parameters, to produce every possible combination, this allows you to gain the intrinsic properties of both generators. For example, a small subset of the many possible use cases include:
     6  
     7  - *SCM Provider Generator + Cluster Generator*: Scanning the repositories of a GitHub organization for application resources, and targeting those resources to all available clusters.
     8  - *Git File Generator + List Generator*: Providing a list of applications to deploy via configuration files, with optional configuration options, and deploying them to a fixed list of clusters.
     9  - *Git Directory Generator + Cluster Decision Resource Generator*: Locate application resources contained within folders of a Git repository, and deploy them to a list of clusters provided via an external custom resource.
    10  - And so on...
    11  
    12  Any set of generators may be used, with the combined values of those generators inserted into the `template` parameters, as usual.
    13  
    14  **Note**: If both child generators are Git generators, one or both of them must use the `pathParamPrefix` option to avoid conflicts when merging the child generators’ items.
    15  
    16  ## Example: Git Directory generator + Cluster generator
    17  
    18  As an example, imagine that we have two clusters:
    19  
    20  - A `staging` cluster (at `https://1.2.3.4`)
    21  - A `production` cluster (at `https://2.4.6.8`)
    22  
    23  And our application YAMLs are defined in a Git repository:
    24  
    25  - Argo Workflows controller (examples/git-generator-directory/cluster-addons/argo-workflows)
    26  - Prometheus operator (/examples/git-generator-directory/cluster-addons/prometheus-operator)
    27  
    28  Our goal is to deploy both applications onto both clusters, and, more generally, in the future to automatically deploy new applications in the Git repository, and to new clusters defined within Argo CD, as well.
    29  
    30  For this we will use the Matrix generator, with the Git and the Cluster as child generators:
    31  
    32  ```yaml
    33  apiVersion: argoproj.io/v1alpha1
    34  kind: ApplicationSet
    35  metadata:
    36    name: cluster-git
    37  spec:
    38    goTemplate: true
    39    goTemplateOptions: ["missingkey=error"]
    40    generators:
    41      # matrix 'parent' generator
    42      - matrix:
    43          generators:
    44            # git generator, 'child' #1
    45            - git:
    46                repoURL: https://github.com/argoproj/argo-cd.git
    47                revision: HEAD
    48                directories:
    49                  - path: applicationset/examples/matrix/cluster-addons/*
    50            # cluster generator, 'child' #2
    51            - clusters:
    52                selector:
    53                  matchLabels:
    54                    argocd.argoproj.io/secret-type: cluster
    55    template:
    56      metadata:
    57        name: '{{.path.basename}}-{{.name}}'
    58      spec:
    59        project: '{{index .metadata.labels "environment"}}'
    60        source:
    61          repoURL: https://github.com/argoproj/argo-cd.git
    62          targetRevision: HEAD
    63          path: '{{.path.path}}'
    64        destination:
    65          server: '{{.server}}'
    66          namespace: '{{.path.basename}}'
    67  ```
    68  
    69  First, the Git directory generator will scan the Git repository, discovering directories under the specified path. It discovers the argo-workflows and prometheus-operator applications, and produces two corresponding sets of parameters:
    70  ```yaml
    71  - path: /examples/git-generator-directory/cluster-addons/argo-workflows
    72    path.basename: argo-workflows
    73  
    74  - path: /examples/git-generator-directory/cluster-addons/prometheus-operator
    75    path.basename: prometheus-operator
    76  ```
    77  
    78  Next, the Cluster generator scans the [set of clusters defined in Argo CD](Generators-Cluster.md), finds the staging and production cluster secrets, and produce two corresponding sets of parameters:
    79  ```yaml
    80  - name: staging
    81    server: https://1.2.3.4
    82  
    83  - name: production
    84    server: https://2.4.6.8
    85  ```
    86  
    87  Finally, the Matrix generator will combine both sets of outputs, and produce:
    88  ```yaml
    89  - name: staging
    90    server: https://1.2.3.4
    91    path: /examples/git-generator-directory/cluster-addons/argo-workflows
    92    path.basename: argo-workflows
    93  
    94  - name: staging
    95    server: https://1.2.3.4
    96    path: /examples/git-generator-directory/cluster-addons/prometheus-operator
    97    path.basename: prometheus-operator
    98  
    99  - name: production
   100    server: https://2.4.6.8
   101    path: /examples/git-generator-directory/cluster-addons/argo-workflows
   102    path.basename: argo-workflows
   103  
   104  - name: production
   105    server: https://2.4.6.8
   106    path: /examples/git-generator-directory/cluster-addons/prometheus-operator
   107    path.basename: prometheus-operator
   108  ```
   109  (*The full example can be found [here](https://github.com/argoproj/argo-cd/tree/master/applicationset/examples/matrix).*)
   110  
   111  ## Using Parameters from one child generator in another child generator
   112  
   113  The Matrix generator allows using the parameters generated by one child generator inside another child generator. 
   114  Below is an example that uses a git-files generator in conjunction with a cluster generator.
   115  
   116  ```yaml
   117  apiVersion: argoproj.io/v1alpha1
   118  kind: ApplicationSet
   119  metadata:
   120    name: cluster-git
   121  spec:
   122    goTemplate: true
   123    goTemplateOptions: ["missingkey=error"]
   124    generators:
   125      # matrix 'parent' generator
   126      - matrix:
   127          generators:
   128            # git generator, 'child' #1
   129            - git:
   130                repoURL: https://github.com/argoproj/applicationset.git
   131                revision: HEAD
   132                files:
   133                  - path: "examples/git-generator-files-discovery/cluster-config/**/config.json"
   134            # cluster generator, 'child' #2
   135            - clusters:
   136                selector:
   137                  matchLabels:
   138                    argocd.argoproj.io/secret-type: cluster
   139                    kubernetes.io/environment: '{{.path.basename}}'
   140    template:
   141      metadata:
   142        name: '{{.name}}-guestbook'
   143      spec:
   144        project: default
   145        source:
   146          repoURL: https://github.com/argoproj/applicationset.git
   147          targetRevision: HEAD
   148          path: "examples/git-generator-files-discovery/apps/guestbook"
   149        destination:
   150          server: '{{.server}}'
   151          namespace: guestbook
   152  ```
   153  Here is the corresponding folder structure for the git repository used by the git-files generator:
   154  
   155  ```
   156  ├── apps
   157  │   └── guestbook
   158  │       ├── guestbook-ui-deployment.yaml
   159  │       ├── guestbook-ui-svc.yaml
   160  │       └── kustomization.yaml
   161  ├── cluster-config
   162  │   └── engineering
   163  │       ├── dev
   164  │       │   └── config.json
   165  │       └── prod
   166  │           └── config.json
   167  └── git-generator-files.yaml
   168  ```
   169  In the above example, the `{{.path.basename}}` parameters produced by the git-files generator will resolve to `dev` and `prod`.
   170  In the 2nd child generator, the label selector with label `kubernetes.io/environment: {{.path.basename}}` will resolve with the values produced by the first child generator's parameters (`kubernetes.io/environment: prod` and `kubernetes.io/environment: dev`). 
   171  
   172  So in the above example, clusters with the label `kubernetes.io/environment: prod` will have only prod-specific configuration (ie. `prod/config.json`) applied to it, wheres clusters
   173  with the label `kubernetes.io/environment: dev` will have only dev-specific configuration (ie. `dev/config.json`)
   174  
   175  ## Overriding parameters from one child generator in another child generator
   176  
   177  The Matrix Generator allows parameters with the same name to be defined in multiple child generators. This is useful, for example, to define default values for all stages in one generator and override them with stage-specific values in another generator. The example below generates a Helm-based application using a matrix generator with two git generators: the first provides stage-specific values (one directory per stage) and the second provides global values for all stages.
   178  
   179  ```yaml
   180  apiVersion: argoproj.io/v1alpha1
   181  kind: ApplicationSet
   182  metadata:
   183    name: parameter-override-example
   184  spec:
   185    generators:
   186      - matrix:
   187          generators:
   188            - git:
   189                repoURL: https://github.com/example/values.git
   190                revision: HEAD
   191                files:
   192                  - path: "**/stage.values.yaml"
   193            - git:
   194                 repoURL: https://github.com/example/values.git
   195                 revision: HEAD
   196                 files:
   197                    - path: "global.values.yaml"
   198    goTemplate: true
   199    template:
   200      metadata:
   201        name: example
   202      spec:
   203        project: default
   204        source:
   205          repoURL: https://github.com/example/example-app.git
   206          targetRevision: HEAD
   207          path: .
   208          helm:
   209            values: |
   210              {{ `{{ . | mustToPrettyJson }}` }}
   211        destination:
   212          server: in-cluster
   213          namespace: default
   214  ```
   215  
   216  Given the following structure/content of the example/values repository:
   217  
   218  ```
   219  ├── test
   220  │   └── stage.values.yaml
   221  │         stageName: test
   222  │         cpuRequest: 100m
   223  │         debugEnabled: true
   224  ├── staging
   225  │   └── stage.values.yaml
   226  │         stageName: staging
   227  ├── production
   228  │   └── stage.values.yaml
   229  │         stageName: production
   230  │         memoryLimit: 512Mi
   231  │         debugEnabled: false
   232  └── global.values.yaml
   233        cpuRequest: 200m
   234        memoryLimit: 256Mi
   235        debugEnabled: true
   236  ```
   237  
   238  The matrix generator above would yield the following results:
   239  
   240  ```yaml
   241  - stageName: test
   242    cpuRequest: 100m
   243    memoryLimit: 256Mi
   244    debugEnabled: true
   245    
   246  - stageName: staging
   247    cpuRequest: 200m
   248    memoryLimit: 256Mi
   249    debugEnabled: true
   250  
   251  - stageName: production
   252    cpuRequest: 200m
   253    memoryLimit: 512Mi
   254    debugEnabled: false
   255  ```
   256  
   257  ## Example: Two Git Generators Using `pathParamPrefix`
   258  
   259  The matrix generator will fail if its children produce results containing identical keys with differing values.
   260  This poses a problem for matrix generators where both children are Git generators since they auto-populate `path`-related parameters in their outputs.
   261  To avoid this problem, specify a `pathParamPrefix` on one or both of the child generators to avoid conflicting parameter keys in the output.
   262  
   263  ```yaml
   264  apiVersion: argoproj.io/v1alpha1
   265  kind: ApplicationSet
   266  metadata:
   267    name: two-gits-with-path-param-prefix
   268  spec:
   269    goTemplate: true
   270    goTemplateOptions: ["missingkey=error"]
   271    generators:
   272      - matrix:
   273          generators:
   274            # git file generator referencing files containing details about each
   275            # app to be deployed (e.g., `appName`).
   276            - git:
   277                repoURL: https://github.com/some-org/some-repo.git
   278                revision: HEAD
   279                files:
   280                  - path: "apps/*.json"
   281                pathParamPrefix: app
   282            # git file generator referencing files containing details about
   283            # locations to which each app should deploy (e.g., `region` and
   284            # `clusterName`).
   285            - git:
   286                repoURL: https://github.com/some-org/some-repo.git
   287                revision: HEAD
   288                files:
   289                  - path: "targets/{{.appName}}/*.json"
   290                pathParamPrefix: target
   291    template: {} # ...
   292  ```
   293  
   294  Then, given the following file structure/content:
   295  
   296  ```
   297  ├── apps
   298  │   ├── app-one.json
   299  │   │   { "appName": "app-one" }
   300  │   └── app-two.json
   301  │       { "appName": "app-two" }
   302  └── targets
   303      ├── app-one
   304      │   ├── east-cluster-one.json
   305      │   │   { "region": "east", "clusterName": "cluster-one" }
   306      │   └── east-cluster-two.json
   307      │       { "region": "east", "clusterName": "cluster-two" }
   308      └── app-two
   309          ├── east-cluster-one.json
   310          │   { "region": "east", "clusterName": "cluster-one" }
   311          └── west-cluster-three.json
   312              { "region": "west", "clusterName": "cluster-three" }
   313  ```
   314  
   315  …the matrix generator above would yield the following results:
   316  
   317  ```yaml
   318  - appName: app-one
   319    app.path: /apps
   320    app.path.filename: app-one.json
   321    # plus additional path-related parameters from the first child generator, all
   322    # prefixed with "app".
   323    region: east
   324    clusterName: cluster-one
   325    target.path: /targets/app-one
   326    target.path.filename: east-cluster-one.json
   327    # plus additional path-related parameters from the second child generator, all
   328    # prefixed with "target".
   329  
   330  - appName: app-one
   331    app.path: /apps
   332    app.path.filename: app-one.json
   333    region: east
   334    clusterName: cluster-two
   335    target.path: /targets/app-one
   336    target.path.filename: east-cluster-two.json
   337  
   338  - appName: app-two
   339    app.path: /apps
   340    app.path.filename: app-two.json
   341    region: east
   342    clusterName: cluster-one
   343    target.path: /targets/app-two
   344    target.path.filename: east-cluster-one.json
   345  
   346  - appName: app-two
   347    app.path: /apps
   348    app.path.filename: app-two.json
   349    region: west
   350    clusterName: cluster-three
   351    target.path: /targets/app-two
   352    target.path.filename: west-cluster-three.json
   353  ```
   354  
   355  ## Restrictions
   356  
   357  1. The Matrix generator currently only supports combining the outputs of only two child generators (eg does not support generating combinations for 3 or more).
   358  
   359  1. You should specify only a single generator per array entry, eg this is not valid:
   360  
   361          - matrix:
   362              generators:
   363              - list: # (...)
   364                git: # (...)
   365  
   366      - While this *will* be accepted by Kubernetes API validation, the controller will report an error on generation. Each generator should be specified in a separate array element, as in the examples above.
   367  
   368  1. The Matrix generator does not currently support [`template` overrides](Template.md#generator-templates) specified on child generators, eg this `template` will not be processed:
   369  
   370          - matrix:
   371              generators:
   372                - list:
   373                    elements:
   374                      - # (...)
   375                    template: { } # Not processed
   376  
   377  1. Combination-type generators (matrix or merge) can only be nested once. For example, this will not work:
   378  
   379          - matrix:
   380              generators:
   381                - matrix:
   382                    generators:
   383                      - matrix:  # This third level is invalid.
   384                          generators:
   385                            - list:
   386                                elements:
   387                                  - # (...)
   388  
   389  1. When using parameters from one child generator inside another child generator, the child generator that *consumes* the parameters **must come after** the child generator that *produces* the parameters.
   390  For example, the below example would be invalid (cluster-generator must come after the git-files generator):
   391  
   392          - matrix:
   393              generators:
   394                # cluster generator, 'child' #1
   395                - clusters:
   396                    selector:
   397                      matchLabels:
   398                        argocd.argoproj.io/secret-type: cluster
   399                        kubernetes.io/environment: '{{.path.basename}}' # {{.path.basename}} is produced by git-files generator
   400                # git generator, 'child' #2
   401                - git:
   402                    repoURL: https://github.com/argoproj/applicationset.git
   403                    revision: HEAD
   404                    files:
   405                      - path: "examples/git-generator-files-discovery/cluster-config/**/config.json"
   406  
   407  1. You cannot have both child generators consuming parameters from each another. In the example below, the cluster generator is consuming the `{{.path.basename}}` parameter produced by the git-files generator, whereas the git-files generator is consuming the `{{.name}}` parameter produced by the cluster generator. This will result in a circular dependency, which is invalid.
   408  
   409          - matrix:
   410              generators:
   411                # cluster generator, 'child' #1
   412                - clusters:
   413                    selector:
   414                      matchLabels:
   415                        argocd.argoproj.io/secret-type: cluster
   416                        kubernetes.io/environment: '{{.path.basename}}' # {{.path.basename}} is produced by git-files generator
   417                # git generator, 'child' #2
   418                - git:
   419                    repoURL: https://github.com/argoproj/applicationset.git
   420                    revision: HEAD
   421                    files:
   422                      - path: "examples/git-generator-files-discovery/cluster-config/engineering/{{.name}}**/config.json" # {{.name}} is produced by cluster generator
   423  
   424  1. When using a Matrix generator nested inside another Matrix or Merge generator, [Post Selectors](Generators-Post-Selector.md) for this nested generator's generators will only be applied when enabled via `spec.applyNestedSelectors`. You may also need to enable this even if your Post Selectors are not within the nested matrix or Merge generator, but are instead a sibling of a nested Matrix or Merge generator.
   425  
   426          - matrix:
   427              generators:
   428                - matrix:
   429                    generators:
   430                      - list
   431                          elements:
   432                            - # (...)
   433                        selector: { } # Only applied when applyNestedSelectors is true