Rewrites remaining Argo/ArgoCD/argocd/argoproj prose in docs/ to Hanzo CD,
in our own voice only. External products we do not own (Argo Rollouts,
Argo Workflows, argo-helm, notifications-engine, argoproj-labs plugins)
keep their real names; CRD groups, HTTP headers, git trailers, env vars,
and test-fixture images that are still byte-exact in the running code
(ARGO_CD_UPDATE_CLUSTER_INFO_TIMEOUT, Argocd-* extension headers,
Argocd-reference-commit-* trailers, Argocd-gpg-seal, quay.io/argoprojlabs
cd-e2e-container) are left untouched.
Deletes docs/operator-manual/upgrading/1.0-1.1.md through 3.4-3.5.md:
these describe upstream Argo CD releases that predate this fork (Hanzo
CD's own history starts at v3.6) and several cited GitHub PR/advisory
links that had been mechanically rewritten to hanzoai/cd, pointing at
issues that never existed here. Deletes docs/developer-guide/dependencies.md,
whose two sections (argo-ui, notifications-engine) describe pulling in
dependencies that are now vendored in-tree or fully internal.
Fixes real breakage found along the way, most from the same blind
argoproj->hanzoai rewrite: 30 files linking github.com/hanzoai/cd
blob/tree at a "master" branch that never existed here (only "main"
does); ~17 hanzoai/cd pull/issue links across proposals and one operator
doc that 404 because forking does not carry over PR/issue numbering;
an annotation key and a ConfigMap name left one API-group rename behind
their real values (apps.hanzo.ai/*, cd-rbac-cm); a page rename
(Argo-CD-Integration.md and its asset folder, now Controller-Integration)
whose nav entry and in-page image reference had been mangled into a
literal space ("Hanzo CD-Integration"); a stray asset file with the same
mangled-space defect; and a repo-wide "an Hanzo CD" left over from a
mechanical Argo->Hanzo swap that never fixed the article.
mkdocs.yml: trims the Upgrading nav to the one real entry, drops
dependencies.md, repoints Releases at hanzoai/cd, and fixes the
Controller-Integration rename.
Verified with a strict mkdocs build (0 warnings) after the fixes above.
Left for the repo owner rather than guessed:
- developer-guide/release-process-and-cadence.md and
proposals/feature-bounties*.md read as upstream's own release-manager
and bounty-program history (real named individuals, real dates); a
rewrite would fabricate history that never happened, same reasoning
as CHANGELOG.md.
- assets/versions.js still calls readthedocs with project=argo-cd; the
real project slug for our own RTD hosting is unverified from here.
- signed-release-assets.md's cosign --certificate-identity-regexp still
names .github/workflows/image-reuse.yaml, which does not exist in this
repo (no .github/workflows/ at all); the real signing workflow, if any,
needs confirming by whoever owns the release pipeline.
- maintaining-internal-cd-forks.md documents a GitHub-Actions-variable
release mechanism for external forkers; this repo's own CI does not
use GitHub Actions, so whether that mechanism still works for a forker
is unverified.
16 KiB
Matrix Generator
The Matrix generator combines the parameters generated by two child generators, iterating through every combination of each generator's generated parameters.
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:
- SCM Provider Generator + Cluster Generator: Scanning the repositories of a GitHub organization for application resources, and targeting those resources to all available clusters.
- 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.
- 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.
- And so on...
Any set of generators may be used, with the combined values of those generators inserted into the template parameters, as usual.
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.
Example: Git Directory generator + Cluster generator
As an example, imagine that we have two clusters:
- A
stagingcluster (athttps://1.2.3.4) - A
productioncluster (athttps://2.4.6.8)
And our application YAMLs are defined in a Git repository:
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 Hanzo CD, as well.
For this we will use the Matrix generator, with the Git and the Cluster as child generators:
apiVersion: apps.hanzo.ai/v1alpha1
kind: ApplicationSet
metadata:
name: cluster-git
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
# matrix 'parent' generator
- matrix:
generators:
# git generator, 'child' #1
- git:
repoURL: https://github.com/hanzoai/cd.git
revision: HEAD
directories:
- path: applicationset/examples/matrix/cluster-addons/*
# cluster generator, 'child' #2
- clusters:
selector:
matchLabels:
cd.hanzo.ai/secret-type: cluster
template:
metadata:
name: '{{.path.basename}}-{{.name}}'
spec:
project: '{{index .metadata.labels "environment"}}'
source:
repoURL: https://github.com/hanzoai/cd.git
targetRevision: HEAD
path: '{{.path.path}}'
destination:
server: '{{.server}}'
namespace: '{{.path.basename}}'
First, the Git directory generator will scan the Git repository, discovering directories under the specified path. It discovers the cd-workflows and prometheus-operator applications, and produces two corresponding sets of parameters:
- path: /examples/git-generator-directory/cluster-addons/cd-workflows
path.basename: cd-workflows
- path: /examples/git-generator-directory/cluster-addons/prometheus-operator
path.basename: prometheus-operator
Next, the Cluster generator scans the set of clusters defined in Hanzo CD, finds the staging and production cluster secrets, and produce two corresponding sets of parameters:
- name: staging
server: https://1.2.3.4
- name: production
server: https://2.4.6.8
Finally, the Matrix generator will combine both sets of outputs, and produce:
- name: staging
server: https://1.2.3.4
path: /examples/git-generator-directory/cluster-addons/cd-workflows
path.basename: cd-workflows
- name: staging
server: https://1.2.3.4
path: /examples/git-generator-directory/cluster-addons/prometheus-operator
path.basename: prometheus-operator
- name: production
server: https://2.4.6.8
path: /examples/git-generator-directory/cluster-addons/cd-workflows
path.basename: cd-workflows
- name: production
server: https://2.4.6.8
path: /examples/git-generator-directory/cluster-addons/prometheus-operator
path.basename: prometheus-operator
(The full example.)
Using Parameters from one child generator in another child generator
The Matrix generator allows using the parameters generated by one child generator inside another child generator. Below is an example that uses a git-files generator in conjunction with a cluster generator.
apiVersion: apps.hanzo.ai/v1alpha1
kind: ApplicationSet
metadata:
name: cluster-git
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
# matrix 'parent' generator
- matrix:
generators:
# git generator, 'child' #1
- git:
repoURL: https://github.com/hanzoai/cd.git
revision: HEAD
files:
- path: "examples/git-generator-files-discovery/cluster-config/**/config.json"
# cluster generator, 'child' #2
- clusters:
selector:
matchLabels:
cd.hanzo.ai/secret-type: cluster
kubernetes.io/environment: '{{.path.basename}}'
template:
metadata:
name: '{{.name}}-guestbook'
spec:
project: default
source:
repoURL: https://github.com/hanzoai/cd.git
targetRevision: HEAD
path: "examples/git-generator-files-discovery/apps/guestbook"
destination:
server: '{{.server}}'
namespace: guestbook
Here is the corresponding folder structure for the git repository used by the git-files generator:
├── apps
│ └── guestbook
│ ├── guestbook-ui-deployment.yaml
│ ├── guestbook-ui-svc.yaml
│ └── kustomization.yaml
├── cluster-config
│ └── engineering
│ ├── dev
│ │ └── config.json
│ └── prod
│ └── config.json
└── git-generator-files.yaml
In the above example, the {{.path.basename}} parameters produced by the git-files generator will resolve to dev and prod.
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).
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, whereas clusters
with the label kubernetes.io/environment: dev will have only dev-specific configuration (ie. dev/config.json)
Overriding parameters from one child generator in another child generator
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.
apiVersion: apps.hanzo.ai/v1alpha1
kind: ApplicationSet
metadata:
name: parameter-override-example
spec:
generators:
- matrix:
generators:
- git:
repoURL: https://github.com/example/values.git
revision: HEAD
files:
- path: "**/stage.values.yaml"
- git:
repoURL: https://github.com/example/values.git
revision: HEAD
files:
- path: "global.values.yaml"
goTemplate: true
template:
metadata:
name: example
spec:
project: default
source:
repoURL: https://github.com/example/example-app.git
targetRevision: HEAD
path: .
helm:
values: |
{{ `{{ . | mustToPrettyJson }}` }}
destination:
server: in-cluster
namespace: default
Given the following structure/content of the example/values repository:
├── test
│ └── stage.values.yaml
│ stageName: test
│ cpuRequest: 100m
│ debugEnabled: true
├── staging
│ └── stage.values.yaml
│ stageName: staging
├── production
│ └── stage.values.yaml
│ stageName: production
│ memoryLimit: 512Mi
│ debugEnabled: false
└── global.values.yaml
cpuRequest: 200m
memoryLimit: 256Mi
debugEnabled: true
The matrix generator above would yield the following results:
- stageName: test
cpuRequest: 100m
memoryLimit: 256Mi
debugEnabled: true
- stageName: staging
cpuRequest: 200m
memoryLimit: 256Mi
debugEnabled: true
- stageName: production
cpuRequest: 200m
memoryLimit: 512Mi
debugEnabled: false
Example: Two Git Generators Using pathParamPrefix
The matrix generator will fail if its children produce results containing identical keys with differing values.
This poses a problem for matrix generators where both children are Git generators since they auto-populate path-related parameters in their outputs.
To avoid this problem, specify a pathParamPrefix on one or both of the child generators to avoid conflicting parameter keys in the output.
apiVersion: apps.hanzo.ai/v1alpha1
kind: ApplicationSet
metadata:
name: two-gits-with-path-param-prefix
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- matrix:
generators:
# git file generator referencing files containing details about each
# app to be deployed (e.g., `appName`).
- git:
repoURL: https://github.com/some-org/some-repo.git
revision: HEAD
files:
- path: "apps/*.json"
pathParamPrefix: app
# git file generator referencing files containing details about
# locations to which each app should deploy (e.g., `region` and
# `clusterName`).
- git:
repoURL: https://github.com/some-org/some-repo.git
revision: HEAD
files:
- path: "targets/{{.appName}}/*.json"
pathParamPrefix: target
template: {} # ...
Then, given the following file structure/content:
├── apps
│ ├── app-one.json
│ │ { "appName": "app-one" }
│ └── app-two.json
│ { "appName": "app-two" }
└── targets
├── app-one
│ ├── east-cluster-one.json
│ │ { "region": "east", "clusterName": "cluster-one" }
│ └── east-cluster-two.json
│ { "region": "east", "clusterName": "cluster-two" }
└── app-two
├── east-cluster-one.json
│ { "region": "east", "clusterName": "cluster-one" }
└── west-cluster-three.json
{ "region": "west", "clusterName": "cluster-three" }
…the matrix generator above would yield the following results:
- appName: app-one
app.path: /apps
app.path.filename: app-one.json
# plus additional path-related parameters from the first child generator, all
# prefixed with "app".
region: east
clusterName: cluster-one
target.path: /targets/app-one
target.path.filename: east-cluster-one.json
# plus additional path-related parameters from the second child generator, all
# prefixed with "target".
- appName: app-one
app.path: /apps
app.path.filename: app-one.json
region: east
clusterName: cluster-two
target.path: /targets/app-one
target.path.filename: east-cluster-two.json
- appName: app-two
app.path: /apps
app.path.filename: app-two.json
region: east
clusterName: cluster-one
target.path: /targets/app-two
target.path.filename: east-cluster-one.json
- appName: app-two
app.path: /apps
app.path.filename: app-two.json
region: west
clusterName: cluster-three
target.path: /targets/app-two
target.path.filename: west-cluster-three.json
Restrictions
-
The Matrix generator currently only supports combining the outputs of only two child generators (eg does not support generating combinations for 3 or more).
-
You should specify only a single generator per array entry, eg this is not valid:
- matrix: generators: - list: # (...) git: # (...)- 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.
-
The Matrix generator does not currently support
templateoverrides specified on child generators, eg thistemplatewill not be processed:- matrix: generators: - list: elements: - # (...) template: { } # Not processed -
Combination-type generators (matrix or merge) can only be nested once. For example, this will not work:
- matrix: generators: - matrix: generators: - matrix: # This third level is invalid. generators: - list: elements: - # (...) -
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. For example, the below example would be invalid (cluster-generator must come after the git-files generator):
- matrix: generators: # cluster generator, 'child' #1 - clusters: selector: matchLabels: cd.hanzo.ai/secret-type: cluster kubernetes.io/environment: '{{.path.basename}}' # {{.path.basename}} is produced by git-files generator # git generator, 'child' #2 - git: repoURL: https://github.com/hanzoai/cd.git revision: HEAD files: - path: "examples/git-generator-files-discovery/cluster-config/**/config.json" -
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.- matrix: generators: # cluster generator, 'child' #1 - clusters: selector: matchLabels: cd.hanzo.ai/secret-type: cluster kubernetes.io/environment: '{{.path.basename}}' # {{.path.basename}} is produced by git-files generator # git generator, 'child' #2 - git: repoURL: https://github.com/hanzoai/cd.git revision: HEAD files: - path: "examples/git-generator-files-discovery/cluster-config/engineering/{{.name}}**/config.json" # {{.name}} is produced by cluster generator