diff --git a/README.md b/README.md index 6605388d..35e64e3f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Start Here -If you've followed a link to this repo, but are not really sure what it contains +If you've followed a link to this repository, but are not really sure what it contains or how to use it, head over to [Multicloud GitOps](http://hybrid-cloud-patterns.io/multicloud-gitops/) for additional context and installation instructions diff --git a/common/.ansible-lint b/common/.ansible-lint index 138ae765..f8066ff0 100644 --- a/common/.ansible-lint +++ b/common/.ansible-lint @@ -1,3 +1,7 @@ # Vim filetype=yaml --- offline: false +skip_list: + - name[template] # Allow Jinja templating inside task and play names + - template-instead-of-copy # Templated files should use template instead of copy + - yaml[line-length] # too long lines diff --git a/common/.github/workflows/ansible-lint.yml b/common/.github/workflows/ansible-lint.yml index f0943b53..ae3e9caf 100644 --- a/common/.github/workflows/ansible-lint.yml +++ b/common/.github/workflows/ansible-lint.yml @@ -11,8 +11,8 @@ jobs: - uses: actions/checkout@v2 - name: Lint Ansible Playbook - # Using the latest as of today (2022-06-23) v6.2.1 - uses: ansible/ansible-lint-action@v6.2.1 + # Using the latest as of today (2022-09-02) v6.6.1 + uses: ansible/ansible-lint-action@v6.6.1 # Let's point it to the path with: path: "ansible/" diff --git a/common/.github/workflows/superlinter.yml b/common/.github/workflows/superlinter.yml index 0141598c..a3e22028 100644 --- a/common/.github/workflows/superlinter.yml +++ b/common/.github/workflows/superlinter.yml @@ -27,11 +27,11 @@ jobs: DEFAULT_BRANCH: main GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # These are the validation we disable atm + VALIDATE_ANSIBLE: false VALIDATE_BASH: false VALIDATE_JSCPD: false VALIDATE_KUBERNETES_KUBEVAL: false VALIDATE_YAML: false - # VALIDATE_ANSIBLE: false # VALIDATE_DOCKERFILE_HADOLINT: false # VALIDATE_MARKDOWN: false # VALIDATE_NATURAL_LANGUAGE: false diff --git a/common/Changes.md b/common/Changes.md new file mode 100644 index 00000000..0c1f9731 --- /dev/null +++ b/common/Changes.md @@ -0,0 +1,24 @@ +# Changes + +## October 3, 2022 + +* Restore the ability to install a non-default site: `make TARGET_SITE=mysite install` +* Revised tests (new output and filenames, requires adding new result files to git) +* ACM 2.6 required for ACM-based managed sites +* Introduced global.clusterDomain template variable (without the `apps.` prefix) +* Removed the ability to send specific charts to another cluster, use hosted argo sites instead +* Added the ability to have the hub host `values-{site}.yaml` for spoke clusters. + + The following example would deploy the namespaces, subscriptions, and + applications defined in `values-group-one.yaml` to the `perth` cluster + directly from ArgoCD on the hub. + + ```yaml + managedClusterGroups: + - name: group-one + hostedArgoSites: + - name: perth + domain: perth1.beekhof.net + bearerKeyPath: secret/data/hub/cluster_perth + caKeyPath: secret/data/hub/cluster_perth_ca + ``` diff --git a/common/Makefile b/common/Makefile index 3f371774..7ddcc947 100644 --- a/common/Makefile +++ b/common/Makefile @@ -1,6 +1,10 @@ NAME=$(shell basename `pwd`) # This is to ensure that whether we start with a git@ or https:// URL, we end up with an https:// URL # This is because we expect to use tokens for repo authentication as opposed to SSH keys +ifneq ($(origin TARGET_SITE), undefined) + TARGET_SITE_OPT=--set main.clusterGroupName=$(TARGET_SITE) +endif + TARGET_ORIGIN ?= origin TARGET_REPO=$(shell git remote show $(TARGET_ORIGIN) | grep Push | sed -e 's/.*URL:[[:space:]]*//' -e 's%^git@%%' -e 's%^https://%%' -e 's%:%/%' -e 's%^%https://%') # git branch --show-current is also available as of git 2.22, but we will use this for compatibility @@ -9,10 +13,10 @@ HUBCLUSTER_APPS_DOMAIN=$(shell oc get ingresses.config/cluster -o jsonpath={.spe # --set values always take precedence over the contents of -f HELM_OPTS=-f values-global.yaml --set main.git.repoURL="$(TARGET_REPO)" --set main.git.revision=$(TARGET_BRANCH) \ - --set global.hubClusterDomain=$(HUBCLUSTER_APPS_DOMAIN) + --set global.hubClusterDomain=$(HUBCLUSTER_APPS_DOMAIN) $(TARGET_SITE_OPT) TEST_OPTS= -f common/examples/values-secret.yaml -f values-global.yaml --set global.repoURL="https://github.com/pattern-clone/mypattern" \ --set main.git.repoURL="https://github.com/pattern-clone/mypattern" --set main.git.revision=main --set global.pattern="mypattern" \ - --set global.namespace="pattern-namespace" --set global.hubClusterDomain=hub.example.com --set global.localClusterDomain=region.example.com \ + --set global.namespace="pattern-namespace" --set global.hubClusterDomain=apps.hub.example.com --set global.localClusterDomain=apps.region.example.com --set global.clusterDomain=region.example.com\ --set "clusterGroup.imperative.jobs[0].name"="test" --set "clusterGroup.imperative.jobs[0].playbook"="ansible/test.yml" \ --set clusterGroup.insecureUnsealVaultInsideCluster=true PATTERN_OPTS=-f common/examples/values-example.yaml @@ -29,10 +33,7 @@ show: ## show the starting template without installing it CHARTS=$(shell find . -type f -iname 'Chart.yaml' -exec dirname "{}" \; | sed -e 's/.\///') test: ## run helm tests -# Test that all values used by the chart are in values.yaml with the same defaults as the pattern - @for t in $(CHARTS); do common/scripts/test.sh $$t naked ""; if [ $$? != 0 ]; then exit 1; fi; done -# Test the charts as the pattern would drive them - @for t in $(CHARTS); do common/scripts/test.sh $$t normal "$(TEST_OPTS) $(PATTERN_OPTS)"; if [ $$? != 0 ]; then exit 1; fi; done + @for t in $(CHARTS); do common/scripts/test.sh $$t all "$(TEST_OPTS) $(PATTERN_OPTS)"; if [ $$? != 0 ]; then exit 1; fi; done helmlint: ## run helm lint @for t in $(CHARTS); do helm lint $(TEST_OPTS) $(PATTERN_OPTS) $$t; if [ $$? != 0 ]; then exit 1; fi; done diff --git a/common/acm/templates/policies/application-policies.yaml b/common/acm/templates/policies/application-policies.yaml index dd9a4658..dfb29a90 100644 --- a/common/acm/templates/policies/application-policies.yaml +++ b/common/acm/templates/policies/application-policies.yaml @@ -1,6 +1,7 @@ # TODO: Also create a GitOpsCluster.apps.open-cluster-management.io {{- range .Values.clusterGroup.managedClusterGroups }} {{- $group := . }} +{{- if not .hostedArgoSites }} apiVersion: policy.open-cluster-management.io/v1 kind: Policy metadata: @@ -60,6 +61,11 @@ spec: value: {{ $.Values.global.hubClusterDomain }} - name: global.localClusterDomain value: '{{ `{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain }}` }}' + # Requires ACM 2.6 or higher + - name: global.clusterDomain + value: '{{ `{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain | replace "apps." "" }}` }}' + - name: clusterGroup.name + value: {{ $group.name }} {{- range .helmOverrides }} - name: {{ .name }} value: {{ .value | quote }} @@ -113,12 +119,21 @@ spec: type: ManagedClusterConditionAvailable {{- if .clusterSelector }} clusterSelector: {{ .clusterSelector | toPrettyJson }} + {{- else if (not $group.acmlabels) }} + clusterSelector: + matchLabels: + clusterGroup: {{ $group.name }} + {{- else if eq (len $group.acmlabels) 0 }} + clusterSelector: + matchLabels: + clusterGroup: {{ $group.name }} {{- else }} clusterSelector: matchLabels: - {{- range .labels }} + {{- range .acmlabels }} {{ .name }}: {{ .value }} {{- end }} {{- end }} --- {{- end }} +{{- end }} diff --git a/common/acm/templates/provision/clusterpool.yaml b/common/acm/templates/provision/clusterpool.yaml index b8cf1ade..0ac851c5 100644 --- a/common/acm/templates/provision/clusterpool.yaml +++ b/common/acm/templates/provision/clusterpool.yaml @@ -14,7 +14,7 @@ spec: {{- range .clusterPools }} {{- $pool := . }} -{{- $poolName := cat .name $group.name | replace " " "-" }} +{{- $poolName := print .name "-" $group.name }} {{- $cloud := "None" }} {{- $region := "None" }} @@ -52,8 +52,6 @@ spec: name: img{{ .openshiftVersion }}-x86-64-appsub pullSecretRef: name: {{ $poolName }}-pull-secret - sshPrivateKeySecretRef: - name: {{ $poolName }}-ssh-private-key skipMachinePools: true # Disable MachinePool as using custom install-config platform: {{ $cloud }}: @@ -71,9 +69,15 @@ metadata: cluster.open-cluster-management.io/createmanagedcluster: "true" labels: clusterClaimName: {{ . }}-{{ $group.name }} - {{- range $group.labels }} + {{- if (not $group.acmlabels) }} + clusterGroup: {{ $group.name }} + {{- else if eq (len $group.acmlabels) 0 }} + clusterGroup: {{ $group.name }} + {{- else }} + {{- range $group.acmlabels }} {{ .name }}: {{ .value }} {{- end }} + {{- end }} spec: clusterPoolName: {{ $pool.name }} --- diff --git a/common/acm/templates/provision/secrets-aws.yaml b/common/acm/templates/provision/secrets-aws.yaml index 99022df6..002c9247 100644 --- a/common/acm/templates/provision/secrets-aws.yaml +++ b/common/acm/templates/provision/secrets-aws.yaml @@ -1,7 +1,7 @@ {{- range .Values.clusterGroup.managedClusterGroups }} {{- $group := . }} {{- range .clusterPools }} -{{- $poolName := cat .name $group.name | replace " " "-" }} +{{- $poolName := print .name "-" $group.name }} {{- if .platform.aws }} apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret diff --git a/common/acm/templates/provision/secrets-azure.yaml b/common/acm/templates/provision/secrets-azure.yaml index 66b470c1..7fe6271b 100644 --- a/common/acm/templates/provision/secrets-azure.yaml +++ b/common/acm/templates/provision/secrets-azure.yaml @@ -1,7 +1,7 @@ {{- range .Values.clusterGroup.managedClusterGroups }} {{- $group := . }} {{- range .clusterPools }} -{{- $poolName := cat .name $group.name | replace " " "-" }} +{{- $poolName := print .name "-" $group.name }} {{- if .platform.azure }} apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret @@ -78,6 +78,7 @@ spec: httpsProxy: "" noProxy: "" additionalTrustBundle: "" +--- +{{- end }} {{- end }} {{- end }} -{{- end }} \ No newline at end of file diff --git a/common/acm/templates/provision/secrets-common.yaml b/common/acm/templates/provision/secrets-common.yaml index 62641dde..21a03b73 100644 --- a/common/acm/templates/provision/secrets-common.yaml +++ b/common/acm/templates/provision/secrets-common.yaml @@ -1,7 +1,7 @@ {{- range .Values.clusterGroup.managedClusterGroups }} {{- $group := . }} {{- range .clusterPools }} -{{- $poolName := cat .name $group.name | replace " " "-" }} +{{- $poolName := print .name "-" $group.name }} apiVersion: v1 kind: Secret metadata: @@ -56,5 +56,6 @@ spec: data: ssh-privatekey: |- {{ "{{ .sshPrivateKey | toString }}" }} +--- +{{- end }} {{- end }} -{{- end }} \ No newline at end of file diff --git a/common/acm/test.yaml b/common/acm/test.yaml index 225f4bf8..669daf07 100644 --- a/common/acm/test.yaml +++ b/common/acm/test.yaml @@ -27,7 +27,7 @@ clusterGroup: clusters: - Two - Three - labels: + acmlabels: - name: clusterGroup value: region-one helmOverrides: diff --git a/common/ansible/roles/vault_utils/tasks/push_secrets.yaml b/common/ansible/roles/vault_utils/tasks/push_secrets.yaml index 3569d24a..784da4d2 100644 --- a/common/ansible/roles/vault_utils/tasks/push_secrets.yaml +++ b/common/ansible/roles/vault_utils/tasks/push_secrets.yaml @@ -65,12 +65,12 @@ loop: "{{ file_secrets | dict2items }}" -- name: debug file_stat +- name: Debug file_stat ansible.builtin.debug: var: file_stat when: debug | default(False) | bool -- name: debug file_values +- name: Debug file_values ansible.builtin.debug: var: file_values when: debug | default(False) | bool diff --git a/common/clustergroup/templates/catalog-sources.yaml b/common/clustergroup/templates/core/catalog-sources.yaml similarity index 79% rename from common/clustergroup/templates/catalog-sources.yaml rename to common/clustergroup/templates/core/catalog-sources.yaml index 35208b37..2f0c2a95 100644 --- a/common/clustergroup/templates/catalog-sources.yaml +++ b/common/clustergroup/templates/core/catalog-sources.yaml @@ -1,3 +1,4 @@ +{{- if not (eq .Values.enabled "plumbing") }} {{- range .Values.clusterGroup.indexImages }} apiVersion: operators.coreos.com/v1alpha1 kind: CatalogSource @@ -7,4 +8,6 @@ metadata: spec: sourceType: grpc image: {{ .image }}:{{ .version }} +--- +{{- end -}} {{- end -}} diff --git a/common/clustergroup/templates/namespaces.yaml b/common/clustergroup/templates/core/namespaces.yaml similarity index 83% rename from common/clustergroup/templates/namespaces.yaml rename to common/clustergroup/templates/core/namespaces.yaml index b3bc86a5..6d2ad164 100644 --- a/common/clustergroup/templates/namespaces.yaml +++ b/common/clustergroup/templates/core/namespaces.yaml @@ -1,3 +1,4 @@ +{{- if not (eq .Values.enabled "plumbing") }} {{- range .Values.clusterGroup.namespaces }} apiVersion: v1 kind: Namespace @@ -9,3 +10,4 @@ metadata: spec: --- {{- end }} +{{- end }} diff --git a/common/clustergroup/templates/operatorgroup.yaml b/common/clustergroup/templates/core/operatorgroup.yaml similarity index 90% rename from common/clustergroup/templates/operatorgroup.yaml rename to common/clustergroup/templates/core/operatorgroup.yaml index 0180a912..74febe94 100644 --- a/common/clustergroup/templates/operatorgroup.yaml +++ b/common/clustergroup/templates/core/operatorgroup.yaml @@ -1,3 +1,4 @@ +{{- if not (eq .Values.enabled "plumbing") }} {{- range .Values.clusterGroup.namespaces }} {{- if empty $.Values.clusterGroup.operatorgroupExcludes }} @@ -23,3 +24,4 @@ spec: {{- end }} {{- end }} +{{- end }} diff --git a/common/clustergroup/templates/subscriptions.yaml b/common/clustergroup/templates/core/subscriptions.yaml similarity index 97% rename from common/clustergroup/templates/subscriptions.yaml rename to common/clustergroup/templates/core/subscriptions.yaml index 3fcd2d1a..bdaeff84 100644 --- a/common/clustergroup/templates/subscriptions.yaml +++ b/common/clustergroup/templates/core/subscriptions.yaml @@ -1,3 +1,4 @@ +{{- if not (eq .Values.enabled "plumbing") }} {{- range .Values.clusterGroup.subscriptions }} {{- $subs := . }} {{- $installPlanValue := .installPlanApproval }} @@ -65,3 +66,4 @@ spec: {{- end }} {{- end }} --- +{{- end }} diff --git a/common/clustergroup/templates/imperative/clusterrole.yaml b/common/clustergroup/templates/imperative/clusterrole.yaml index 17e33d8d..b893d0e2 100644 --- a/common/clustergroup/templates/imperative/clusterrole.yaml +++ b/common/clustergroup/templates/imperative/clusterrole.yaml @@ -1,3 +1,4 @@ +{{- if not (eq .Values.enabled "plumbing") }} {{/* Define this if needed (jobs defined or insecure unseal configured) */}} {{- if or (gt (len $.Values.clusterGroup.imperative.jobs) 0) (and $.Values.clusterGroup.insecureUnsealVaultInsideCluster $.Values.clusterGroup.isHubCluster) -}} @@ -20,3 +21,4 @@ rules: - watch {{- end }} {{- end }} +{{- end }} diff --git a/common/clustergroup/templates/imperative/configmap.yaml b/common/clustergroup/templates/imperative/configmap.yaml index 5cde2d37..5abb473b 100644 --- a/common/clustergroup/templates/imperative/configmap.yaml +++ b/common/clustergroup/templates/imperative/configmap.yaml @@ -1,3 +1,4 @@ +{{- if not (eq .Values.enabled "plumbing") }} {{/* Define this if needed (jobs defined or insecure unseal configured) */}} {{- if or (gt (len $.Values.clusterGroup.imperative.jobs) 0) (and $.Values.clusterGroup.insecureUnsealVaultInsideCluster $.Values.clusterGroup.isHubCluster) -}} @@ -5,9 +6,10 @@ apiVersion: v1 kind: ConfigMap metadata: - name: {{ $.Values.clusterGroup.imperative.valuesConfigMap }} + name: {{ $.Values.clusterGroup.imperative.valuesConfigMap }}-{{ $.Values.clusterGroup.name }} namespace: {{ $.Values.clusterGroup.imperative.namespace}} data: values.yaml: | {{ tpl $valuesyaml . | indent 4 }} -{{ end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/common/clustergroup/templates/imperative/job.yaml b/common/clustergroup/templates/imperative/job.yaml index b237e11f..b9437c3f 100644 --- a/common/clustergroup/templates/imperative/job.yaml +++ b/common/clustergroup/templates/imperative/job.yaml @@ -1,3 +1,4 @@ +{{- if not (eq .Values.enabled "plumbing") }} {{/* Define this if needed (jobs defined */}} {{- if (gt (len $.Values.clusterGroup.imperative.jobs) 0) -}} --- @@ -62,6 +63,7 @@ spec: emptyDir: {} - name: values-volume configMap: - name: {{ $.Values.clusterGroup.imperative.valuesConfigMap }} + name: {{ $.Values.clusterGroup.imperative.valuesConfigMap }}-{{ $.Values.clusterGroup.name }} restartPolicy: Never -{{ end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/common/clustergroup/templates/imperative/namespace.yaml b/common/clustergroup/templates/imperative/namespace.yaml index 827bbee5..fd4569c6 100644 --- a/common/clustergroup/templates/imperative/namespace.yaml +++ b/common/clustergroup/templates/imperative/namespace.yaml @@ -1,3 +1,4 @@ +{{- if not (eq .Values.enabled "plumbing") }} {{/* Define this if needed (jobs defined or insecure unseal configured) */}} {{- if or (gt (len $.Values.clusterGroup.imperative.jobs) 0) (and $.Values.clusterGroup.insecureUnsealVaultInsideCluster $.Values.clusterGroup.isHubCluster) -}} @@ -8,4 +9,5 @@ metadata: name: {{ $.Values.clusterGroup.imperative.namespace }} argocd.argoproj.io/managed-by: {{ $.Values.global.pattern }}-{{ $.Values.clusterGroup.name }} name: {{ $.Values.clusterGroup.imperative.namespace }} -{{ end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/common/clustergroup/templates/imperative/rbac.yaml b/common/clustergroup/templates/imperative/rbac.yaml index f62b23ac..1b73ca3e 100644 --- a/common/clustergroup/templates/imperative/rbac.yaml +++ b/common/clustergroup/templates/imperative/rbac.yaml @@ -1,3 +1,4 @@ +{{- if not (eq .Values.enabled "plumbing") }} {{/* Define this if needed (jobs defined or insecure unseal configured) */}} {{- if or (gt (len $.Values.clusterGroup.imperative.jobs) 0) (and $.Values.clusterGroup.insecureUnsealVaultInsideCluster $.Values.clusterGroup.isHubCluster) -}} @@ -28,4 +29,5 @@ subjects: - kind: ServiceAccount name: {{ $.Values.clusterGroup.imperative.serviceAccountName }} namespace: {{ $.Values.clusterGroup.imperative.namespace }} -{{ end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/common/clustergroup/templates/imperative/role.yaml b/common/clustergroup/templates/imperative/role.yaml index f4909c76..79b7b7a7 100644 --- a/common/clustergroup/templates/imperative/role.yaml +++ b/common/clustergroup/templates/imperative/role.yaml @@ -1,3 +1,4 @@ +{{- if not (eq .Values.enabled "plumbing") }} {{/* Define this if needed (jobs defined or insecure unseal configured) */}} {{- if or (gt (len $.Values.clusterGroup.imperative.jobs) 0) (and $.Values.clusterGroup.insecureUnsealVaultInsideCluster $.Values.clusterGroup.isHubCluster) -}} @@ -19,3 +20,4 @@ rules: - '*' {{- end }} {{- end }} +{{- end }} diff --git a/common/clustergroup/templates/imperative/serviceaccount.yaml b/common/clustergroup/templates/imperative/serviceaccount.yaml index bb500deb..b90ac2a4 100644 --- a/common/clustergroup/templates/imperative/serviceaccount.yaml +++ b/common/clustergroup/templates/imperative/serviceaccount.yaml @@ -1,3 +1,4 @@ +{{- if not (eq .Values.enabled "plumbing") }} {{/* Define this if needed (jobs defined or insecure unseal configured) */}} {{- if or (gt (len $.Values.clusterGroup.imperative.jobs) 0) (and $.Values.clusterGroup.insecureUnsealVaultInsideCluster $.Values.clusterGroup.isHubCluster) -}} @@ -9,3 +10,4 @@ metadata: namespace: {{ $.Values.clusterGroup.imperative.namespace }} {{- end }} {{- end }} +{{- end }} diff --git a/common/clustergroup/templates/imperative/unsealjob.yaml b/common/clustergroup/templates/imperative/unsealjob.yaml index 0fae9071..76fbd135 100644 --- a/common/clustergroup/templates/imperative/unsealjob.yaml +++ b/common/clustergroup/templates/imperative/unsealjob.yaml @@ -1,3 +1,4 @@ +{{- if not (eq .Values.enabled "plumbing") }} {{/* Only define this if the values.insecureUnsealVaultInsideCluster is set to tre and we're on the cluster */}} {{- if and $.Values.clusterGroup.insecureUnsealVaultInsideCluster $.Values.clusterGroup.isHubCluster }} --- @@ -54,6 +55,7 @@ spec: emptyDir: {} - name: values-volume configMap: - name: {{ $.Values.clusterGroup.imperative.valuesConfigMap }} + name: {{ $.Values.clusterGroup.imperative.valuesConfigMap }}-{{ $.Values.clusterGroup.name }} restartPolicy: Never -{{ end }} +{{- end }} +{{- end }} diff --git a/common/clustergroup/templates/applications.yaml b/common/clustergroup/templates/plumbing/applications.yaml similarity index 92% rename from common/clustergroup/templates/applications.yaml rename to common/clustergroup/templates/plumbing/applications.yaml index 3ffd6a0f..c9a6667d 100644 --- a/common/clustergroup/templates/applications.yaml +++ b/common/clustergroup/templates/plumbing/applications.yaml @@ -1,4 +1,8 @@ -{{- $namespace := cat $.Values.global.pattern $.Values.clusterGroup.name | replace " " "-" }} +{{- if not (eq .Values.enabled "core") }} +{{- $namespace := print $.Values.global.pattern "-" $.Values.clusterGroup.name }} +{{- if (eq .Values.enabled "plumbing") }} +{{- $namespace = "openshift-gitops" }} +{{- end }} {{- range .Values.clusterGroup.applications }} {{- if or (.generators) (.generatorFile) (.useGeneratorValues) (.destinationServer) (.destinationNamespace) }} apiVersion: argoproj.io/v1alpha1 @@ -60,6 +64,8 @@ spec: {{ `{{ values }}` }} {{- end }} parameters: + - name: global.clusterDomain + value: {{ $.Values.global.clusterDomain }} - name: global.hubClusterDomain value: {{ $.Values.global.hubClusterDomain }} - name: global.localClusterDomain @@ -72,6 +78,8 @@ spec: value: {{ $.Values.global.namespace }} - name: global.pattern value: {{ $.Values.global.pattern }} + - name: clusterGroup.name + value: {{ .Values.clusterGroup.name }} {{- range .extraHubClusterDomainFields }} - name: {{ . }} value: {{ $.Values.global.hubClusterDomain }} @@ -117,7 +125,7 @@ metadata: - resources-finalizer.argocd.argoproj.io/foreground spec: destination: - name: {{ coalesce .clusterName "in-cluster" }} + name: {{ $.Values.clusterGroup.targetCluster }} namespace: {{ default $namespace .namespace }} project: {{ .project }} source: @@ -149,6 +157,8 @@ spec: value: $ARGOCD_APP_NAMESPACE - name: global.pattern value: {{ $.Values.global.pattern }} + - name: global.clusterDomain + value: {{ $.Values.global.clusterDomain }} - name: global.hubClusterDomain value: {{ $.Values.global.hubClusterDomain }} - name: global.localClusterDomain @@ -205,3 +215,4 @@ spec: --- {{- end }} {{- end }} +{{- end }} diff --git a/common/clustergroup/templates/argocd-super-role.yaml b/common/clustergroup/templates/plumbing/argocd-super-role.yaml similarity index 97% rename from common/clustergroup/templates/argocd-super-role.yaml rename to common/clustergroup/templates/plumbing/argocd-super-role.yaml index 78af462d..2d5f8f76 100644 --- a/common/clustergroup/templates/argocd-super-role.yaml +++ b/common/clustergroup/templates/plumbing/argocd-super-role.yaml @@ -1,3 +1,4 @@ +{{- if (eq .Values.enabled "all") }} # WARNING: ONLY USE THIS FOR MANAGING CLUSTERS NOT FOR REGULAR USERS apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding @@ -39,3 +40,4 @@ subjects: - kind: ServiceAccount name: {{ .Values.clusterGroup.name }}-gitops-argocd-dex-server namespace: {{ $.Values.global.pattern }}-{{ .Values.clusterGroup.name }} +{{- end }} diff --git a/common/clustergroup/templates/argocd.yaml b/common/clustergroup/templates/plumbing/argocd.yaml similarity index 99% rename from common/clustergroup/templates/argocd.yaml rename to common/clustergroup/templates/plumbing/argocd.yaml index 0126c0a5..68400b95 100644 --- a/common/clustergroup/templates/argocd.yaml +++ b/common/clustergroup/templates/plumbing/argocd.yaml @@ -1,4 +1,5 @@ -{{- $namespace := cat $.Values.global.pattern $.Values.clusterGroup.name | replace " " "-" }} +{{- if (eq .Values.enabled "all") }} +{{- $namespace := print $.Values.global.pattern "-" $.Values.clusterGroup.name }} apiVersion: argoproj.io/v1alpha1 kind: ArgoCD metadata: @@ -37,8 +38,10 @@ spec: --set global.targetRevision=$ARGOCD_APP_SOURCE_TARGET_REVISION --set global.namespace=$ARGOCD_APP_NAMESPACE --set global.pattern={{ .Values.global.pattern }} + --set global.clusterDomain={{ .Values.global.clusterDomain }} --set global.hubClusterDomain={{ .Values.global.hubClusterDomain }} --set global.localClusterDomain={{ coalesce .Values.global.localClusterDomain .Values.global.hubClusterDomain }} + --set clusterGroup.name={{ .Values.clusterGroup.name }} --post-renderer ./kustomize"] applicationSet: resources: @@ -121,3 +124,4 @@ spec: href: 'https://{{ .Values.clusterGroup.name }}-gitops-server-{{ $namespace }}.{{ coalesce .Values.global.localClusterDomain .Values.global.hubClusterDomain }}' location: ApplicationMenu text: '{{ title .Values.clusterGroup.name }} ArgoCD' +{{- end }} diff --git a/common/clustergroup/templates/cluster-external-secrets.yaml b/common/clustergroup/templates/plumbing/cluster-external-secrets.yaml similarity index 58% rename from common/clustergroup/templates/cluster-external-secrets.yaml rename to common/clustergroup/templates/plumbing/cluster-external-secrets.yaml index b01e3e3d..dfb6bc6b 100644 --- a/common/clustergroup/templates/cluster-external-secrets.yaml +++ b/common/clustergroup/templates/plumbing/cluster-external-secrets.yaml @@ -1,12 +1,10 @@ -{{- $namespace := cat $.Values.global.pattern $.Values.clusterGroup.name | replace " " "-" }} -{{ if .Values.clusterGroup.isHubCluster }} -{{- range .Values.clusterGroup.externalClusters }} ---- +{{- if (eq .Values.enabled "plumbing") }} +{{- $namespace := print $.Values.global.pattern "-" $.Values.clusterGroup.name }} apiVersion: "external-secrets.io/v1beta1" kind: ExternalSecret metadata: - name: {{ . | kebabcase }}-secret - namespace: {{ $namespace }} + name: {{ .Values.clusterGroup.targetCluster | kebabcase }}-secret + namespace: openshift-gitops annotations: argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true argocd.argoproj.io/sync-wave: "100" @@ -16,16 +14,15 @@ spec: name: {{ $.Values.secretStore.name }} kind: {{ $.Values.secretStore.kind }} target: - name: {{ . | kebabcase }}-secret + name: {{ .Values.clusterGroup.targetCluster | kebabcase }}-secret template: type: Opaque metadata: labels: argocd.argoproj.io/secret-type: cluster data: - name: {{ . }} - server: |- - {{ "{{ .kubeServer | toString }}" }} + name: {{ .Values.clusterGroup.targetCluster }} + server: https://api.{{ .Values.global.clusterDomain }}:6443 config: | { "bearerToken": {{ "{{ .kubeBearer | toString | quote }}" }}, @@ -35,17 +32,12 @@ spec: } } data: - - secretKey: kubeServer - remoteRef: - key: {{ $.Values.secretsBase.key }}/cluster_{{ . }} - property: server - secretKey: kubeBearer remoteRef: - key: {{ $.Values.secretsBase.key }}/cluster_{{ . }} + key: {{ $.Values.clusterGroup.hostedSite.bearerKeyPath }} property: bearerToken - secretKey: kubeCA remoteRef: - key: {{ $.Values.secretsBase.key }}/cluster_{{ . }}_ca + key: {{ $.Values.clusterGroup.hostedSite.caKeyPath }} property: b64content {{- end }} -{{ end }} diff --git a/common/clustergroup/templates/gitops-namespace.yaml b/common/clustergroup/templates/plumbing/gitops-namespace.yaml similarity index 87% rename from common/clustergroup/templates/gitops-namespace.yaml rename to common/clustergroup/templates/plumbing/gitops-namespace.yaml index 785ef75f..3cd7608d 100644 --- a/common/clustergroup/templates/gitops-namespace.yaml +++ b/common/clustergroup/templates/plumbing/gitops-namespace.yaml @@ -1,3 +1,4 @@ +{{- if not (eq .Values.enabled "plumbing") }} apiVersion: v1 kind: Namespace metadata: @@ -9,3 +10,4 @@ metadata: # - any references to secrets and route URLs in documentation name: {{ $.Values.global.pattern }}-{{ .Values.clusterGroup.name }} spec: {} +{{- end }} diff --git a/common/clustergroup/templates/plumbing/hosted-sites.yaml b/common/clustergroup/templates/plumbing/hosted-sites.yaml new file mode 100644 index 00000000..1f11dbe4 --- /dev/null +++ b/common/clustergroup/templates/plumbing/hosted-sites.yaml @@ -0,0 +1,177 @@ +{{- if (eq .Values.enabled "all") }} +{{- range .Values.clusterGroup.managedClusterGroups }} +{{- $group := . }} +{{- if .hostedArgoSites }} +apiVersion: argoproj.io/v1alpha1 +kind: AppProject +metadata: + name: {{ .name }} + namespace: openshift-gitops +spec: + description: "Cluster Group {{ $group.name }}" + destinations: + - namespace: '*' + server: '*' + clusterResourceWhitelist: + - group: '*' + kind: '*' + namespaceResourceWhitelist: + - group: '*' + kind: '*' + sourceRepos: + - '*' +status: {} +--- +{{- end }} +{{- range .hostedArgoSites }} +{{ $bearerDefault := print "secret/data/hub/cluster_" .name }} +{{ $caDefault := print "secret/data/hub/cluster_" .name "_ca" }} +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: {{ $.Values.global.pattern }}-{{ $group.name }}-{{ .name }} + namespace: openshift-gitops + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground +spec: + project: {{ $group.name }} + source: + repoURL: {{ coalesce $group.repoURL $.Values.global.repoURL }} + targetRevision: {{ coalesce $group.targetRevision $.Values.global.targetRevision }} + path: {{ default "common/clustergroup" $group.path }} + helm: + ignoreMissingValueFiles: true + valueFiles: + - "/values-global.yaml" + - "/values-{{ $group.name }}.yaml" + {{- range $valueFile := $group.extraValueFiles }} + - {{ $valueFile | quote }} + {{- end }} + parameters: + - name: global.repoURL + value: $ARGOCD_APP_SOURCE_REPO_URL + - name: global.targetRevision + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + - name: global.namespace + value: $ARGOCD_APP_NAMESPACE + - name: global.pattern + value: {{ $.Values.global.pattern }} + - name: global.hubClusterDomain + value: {{ $.Values.global.hubClusterDomain }} + - name: global.localClusterDomain + value: apps.{{ .domain }} + - name: global.clusterDomain + value: {{ .domain }} + - name: enabled + value: core + - name: clusterGroup.name + value: {{ $group.name }} + - name: clusterGroup.targetCluster + value: {{ .name }} + - name: clusterGroup.hostedSite.bearerKeyPath + value: {{ default $bearerDefault .bearerKeyPath }} + - name: clusterGroup.hostedSite.caKeyPath + value: {{ default $caDefault .caKeyPath }} + {{- range $group.helmOverrides }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end }} + {{- if $group.fileParameters }} + fileParameters: + {{- range $group.fileParameters }} + - name: {{ .name }} + path: {{ .path }} + {{- end }} + {{- end }} + destination: + name: {{ .name }} + namespace: {{ $.Values.global.pattern }}-{{ $group.name }} + syncPolicy: + automated: + selfHeal: true + ignoreDifferences: + - group: apps + kind: Deployment + jsonPointers: + - /spec/replicas + - group: route.openshift.io + kind: Route + jsonPointers: + - /status +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: {{ $.Values.global.pattern }}-{{ $group.name }}-{{ .name }}-plumbing + namespace: openshift-gitops + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground +spec: + project: {{ $group.name }} + source: + repoURL: {{ coalesce $group.repoURL $.Values.global.repoURL }} + targetRevision: {{ coalesce $group.targetRevision $.Values.global.targetRevision }} + path: {{ default "common/clustergroup" $group.path }} + helm: + ignoreMissingValueFiles: true + valueFiles: + - "/values-global.yaml" + - "/values-{{ $group.name }}.yaml" + {{- range $valueFile := $group.extraValueFiles }} + - {{ $valueFile | quote }} + {{- end }} + parameters: + - name: global.repoURL + value: $ARGOCD_APP_SOURCE_REPO_URL + - name: global.targetRevision + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + - name: global.namespace + value: $ARGOCD_APP_NAMESPACE + - name: global.pattern + value: {{ $.Values.global.pattern }} + - name: global.hubClusterDomain + value: {{ $.Values.global.hubClusterDomain }} + - name: global.localClusterDomain + value: apps.{{ .domain }} + - name: global.clusterDomain + value: {{ .domain }} + - name: enabled + value: plumbing + - name: clusterGroup.name + value: {{ $group.name }} + - name: clusterGroup.targetCluster + value: {{ .name }} + - name: clusterGroup.hostedSite.bearerKeyPath + value: {{ default $bearerDefault .bearerKeyPath }} + - name: clusterGroup.hostedSite.caKeyPath + value: {{ default $caDefault .caKeyPath }} + {{- range $group.helmOverrides }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end }} + {{- if $group.fileParameters }} + fileParameters: + {{- range $group.fileParameters }} + - name: {{ .name }} + path: {{ .path }} + {{- end }} + {{- end }} + destination: + name: in-cluster + namespace: openshift-gitops + syncPolicy: + automated: + selfHeal: true + ignoreDifferences: + - group: apps + kind: Deployment + jsonPointers: + - /spec/replicas + - group: route.openshift.io + kind: Route + jsonPointers: + - /status +--- +{{- end }} +{{- end }} +{{- end }} diff --git a/common/clustergroup/templates/projects.yaml b/common/clustergroup/templates/plumbing/projects.yaml similarity index 58% rename from common/clustergroup/templates/projects.yaml rename to common/clustergroup/templates/plumbing/projects.yaml index d74e2cba..7f3b8c22 100644 --- a/common/clustergroup/templates/projects.yaml +++ b/common/clustergroup/templates/plumbing/projects.yaml @@ -1,9 +1,15 @@ +{{- if not (eq .Values.enabled "core") }} +{{- $namespace := print $.Values.global.pattern "-" $.Values.clusterGroup.name }} {{- range .Values.clusterGroup.projects }} apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: name: {{ . }} - namespace: {{ $.Values.global.pattern }}-{{ $.Values.clusterGroup.name }} +{{- if (eq $.Values.enabled "plumbing") }} + namespace: openshift-gitops +{{- else }} + namespace: {{ $namespace }} +{{- end }} spec: description: "Pattern {{ . }}" destinations: @@ -20,3 +26,4 @@ spec: status: {} --- {{- end }} +{{- end }} diff --git a/common/clustergroup/test.yaml b/common/clustergroup/test.yaml index 0ab52838..5db2e4a6 100644 --- a/common/clustergroup/test.yaml +++ b/common/clustergroup/test.yaml @@ -96,9 +96,9 @@ clusterGroup: managedClusterGroups: region-one: name: region-one - labels: - - name: clusterGroup - value: region-one + hostedArgoSites: + - perth + - sydney helmOverrides: - name: clusterGroup.isHubCluster value: false diff --git a/common/clustergroup/values.yaml b/common/clustergroup/values.yaml index b6c802e6..fac5d56c 100644 --- a/common/clustergroup/values.yaml +++ b/common/clustergroup/values.yaml @@ -1,14 +1,18 @@ global: pattern: common + targetRevision: main options: useCSV: True syncPolicy: Automatic installPlanApproval: Automatic +enabled: "all" + # Note that sometimes changing helm values might require a hard refresh (https://github.com/helm/helm/issues/3486) clusterGroup: name: example isHubCluster: true + targetCluster: in-cluster # Note: setting this to true stores the vault unseal keys inside a cluster secret and # is fundamentally insecure insecureUnsealVaultInsideCluster: false diff --git a/common/examples/values-example.yaml b/common/examples/values-example.yaml index 7b3237fc..81bbcf10 100644 --- a/common/examples/values-example.yaml +++ b/common/examples/values-example.yaml @@ -47,32 +47,58 @@ clusterGroup: namespace: application-ci project: datacenter path: charts/datacenter/pipelines - external: - name: external-app - namespace: demo - project: datacenter - clusterName: example managedClusterGroups: - - name: edge + - name: acm-edge # Optional - Point to a different repo - # repoURL: https://github.com/dagger-refuse-cool/mySite.git + # repoURL: https://github.com/hybrid-cloud-patterns/mySite.git # Must contain values-{clustergroupname}.yaml at the top level targetRevision: main helmOverrides: # Values must be strings! - name: clusterGroup.isHubCluster value: "false" - clusterSelector: -# matchLabels: -# clusterGroup: factory - matchExpressions: - - key: vendor - operator: In - values: - - OpenShift - - # Create an ExternalSecret with a label that ArgoCD - # will detect and register as a new Cluster - externalClusters: - - example # Will read the key: cluster_example + acmlabels: + - name: clusterGroup + value: acm-region + - name: acm-provision-edge + targetRevision: main + helmOverrides: + - name: clusterGroup.isHubCluster + value: "false" + clusterPools: + exampleAWSPool: + size: 3 + name: aws-ap + openshiftVersion: 4.10.18 + baseDomain: blueprints.rhecoeng.com + platform: + aws: + region: ap-southeast-2 + clusters: + - One + exampleAzurePool: + name: azure-us + openshiftVersion: 4.10.18 + baseDomain: blueprints.rhecoeng.com + platform: + azure: + baseDomainResourceGroupName: dojo-dns-zones + region: eastus + clusters: + - Two + - Three + acmlabels: + - name: clusterGroup + value: region + - name: argo-edge + hostedArgoSites: + - name: perth + domain: perth1.beekhof.net + bearerKeyPath: secret/data/hub/cluster_perth + caKeyPath: secret/data/hub/cluster_perth_ca + - name: sydney + domain: syd.beekhof.net + helmOverrides: + - name: clusterGroup.isHubCluster + value: "false" diff --git a/common/scripts/pattern-util.sh b/common/scripts/pattern-util.sh index d2be2e97..5d2c9bae 100755 --- a/common/scripts/pattern-util.sh +++ b/common/scripts/pattern-util.sh @@ -4,14 +4,27 @@ if [ -z "$PATTERN_UTILITY_CONTAINER" ]; then PATTERN_UTILITY_CONTAINER="quay.io/hybridcloudpatterns/hybridcloudpatterns-utility-ee" fi +# This is one of the most concise ways to get a readlink -f command work without going too complicated +# Across Linux and MacOSX +function real_path() { + echo $(cd $(dirname $1) ; pwd -P) +} + # Copy Kubeconfig from current environment. The utilities will pick up ~/.kube/config if set so it's not mandatory # /home/runner is the normal homedir # $HOME is mounted as itself for any files that are referenced with absolute paths # $HOME is mounted to /root because the UID in the container is 0 and that's where SSH looks for credentials +# We bind mount the SSH_AUTH_SOCK socket if it is set, so ssh works without user prompting +SSH_SOCK_MOUNTS="" +if [ -n "$SSH_AUTH_SOCK" ]; then + SSH_SOCK_MOUNTS="-v $(real_path $SSH_AUTH_SOCK):/ssh-agent -e SSH_AUTH_SOCK=/ssh-agent" +fi podman run -it \ --security-opt label=disable \ -e KUBECONFIG="${KUBECONFIG}" \ + ${SSH_SOCK_MOUNTS} \ + -e GIT_SSH_COMMAND="ssh -o IgnoreUnknown=pubkeyacceptedalgorithms" \ -v ${HOME}:/home/runner \ -v ${HOME}:${HOME} \ -v ${HOME}:/root \ diff --git a/common/scripts/test.sh b/common/scripts/test.sh index 5790b5de..a4077fb6 100755 --- a/common/scripts/test.sh +++ b/common/scripts/test.sh @@ -4,47 +4,119 @@ # This won't protect us if a user has ~/.kube # Also call helm template with a non existing --kubeconfig while we're at it unset KUBECONFIG - target=$1 name=$(echo $1 | sed -e s@/@-@g -e s@charts-@@) -TEST_VARIANT="$2" -CHART_OPTS="$3" - -TESTDIR=tests -REFERENCE=${TESTDIR}/${name}-${TEST_VARIANT}.expected.yaml -OUTPUT=${TESTDIR}/.${name}-${TEST_VARIANT}.expected.yaml -#REFERENCE=${TESTDIR}/${name}.expected.yaml -#OUTPUT=${TESTDIR}/.${name}.expected.yaml - -echo "Testing $1 chart (${TEST_VARIANT})" >&2 -helm template --kubeconfig /tmp/doesnotexistever $target --name-template $name ${CHART_OPTS} > ${OUTPUT} -rc=$? -if [ $rc -ne 0 ]; then - echo "FAIL on helm template $target --name-template $name ${CHART_OPTS}" - exit 1 -fi -#cp ${OUTPUT} ${REFERENCE} -if [ ! -e ${REFERENCE} ]; then - touch ${REFERENCE} -fi -diff -u ${REFERENCE} ${OUTPUT} -rc=$? -if [ $rc = 0 ]; then - rm -f ${OUTPUT} -fi -if [ $TEST_VARIANT = normal -a $rc = 0 ]; then +function doTest() { + TEST_VARIANT=$1 + CHART_OPTS="$2" + TESTDIR=tests + TEST=${name}-${TEST_VARIANT} + FILENAME=${TEST}.expected.yml + OUTPUT=${TESTDIR}/.${FILENAME} + REFERENCE=${TESTDIR}/${FILENAME} + + echo -e "\nTesting $name chart (${TEST_VARIANT}) with opts [$CHART_OPTS]" >&2 + helm template --kubeconfig /tmp/doesnotexistever $target --name-template $name ${CHART_OPTS} > ${OUTPUT} + rc=$? + if [ $rc -ne 0 ]; then + echo "FAIL on helm template $target --name-template $name ${CHART_OPTS}" >&2 + exit 1 + fi + if [ ! -e ${REFERENCE} ]; then + cp ${OUTPUT} ${REFERENCE} + echo -e "\n\n#### Created test output\007\n#### Now add ${REFERENCE} to Git\n\n\007" >&2 + exit 2 + fi + diff -u ${REFERENCE} ${OUTPUT} + rc=$? + if [ $rc = 0 ]; then + rm -f ${OUTPUT} + echo "PASS" >&2 + elif [ -z $GITHUB_ACTIONS ]; then + read -p "Are these changes expected? [y/N] " EXPECTED + case $EXPECTED in + y*|Y*) + echo "Updating ${REFERENCE}" + cp ${OUTPUT} ${REFERENCE} + rm -f ${OUTPUT} + rc=0 + ;; + *) ;; + esac + fi + if [ $rc != 0 ]; then + echo "FAIL" >&2 + exit $rc + fi +} + +function doTestCompare() { + TEST_VARIANT="differences" + TESTDIR=tests + TEST=${name} + FILENAME=${TEST}.expected.yml + OUTPUT=${TESTDIR}/.${FILENAME} + REFERENCE=${TESTDIR}/${FILENAME} + + echo -e "\nTesting $name chart (${TEST_VARIANT})" >&2 # Another method of finding variables missing from values.yaml, eg. # - name: -datacenter # + name: pattern-name-datacenter - # Alas we can't make it fatal because there *should* be some differences - diff -u ${TESTDIR}/${name}-naked.expected.yaml ${TESTDIR}/${name}-normal.expected.yaml -fi -if [ $rc = 0 ]; then - echo "PASS on $target $TEST_VARIANT with opts [$CHART_OPTS]" + TEST=${name} + FILENAME=${TEST}.expected.diff + OUTPUT=${TESTDIR}/.${FILENAME} + REFERENCE=${TESTDIR}/${FILENAME} + + # Drop the date from the diff output, it will not be stable + diff -u ${TESTDIR}/${name}-naked.expected.yml ${TESTDIR}/${name}-normal.expected.yml | sed 's/\.yml.*20[0-9][0-9].*/.yml/g' > ${OUTPUT} + + if [ ! -e ${REFERENCE} -a -z $GITHUB_ACTIONS ]; then + cp ${OUTPUT} ${REFERENCE} + git add ${REFERENCE} + echo -e "\n\n#### Created test output\007\n\n\007" >&2 + fi + + diff -u ${REFERENCE} ${OUTPUT} + rc=$? + + if [ $rc = 0 ]; then + rm -f ${OUTPUT} + echo "PASS" >&2 + elif [ -z $GITHUB_ACTIONS ]; then + read -p "Are these changes expected? [y/N] " EXPECTED + case $EXPECTED in + y*|Y*) + echo "Updating ${REFERENCE}" + cp ${OUTPUT} ${REFERENCE} + rm -f ${OUTPUT} + rc=0 + ;; + *) ;; + esac + fi + if [ $rc != 0 ]; then + echo "FAIL" >&2 + exit $rc + fi +} + +if [ $2 = "all" ]; then + echo -e "\n#####################" >&2 + echo "### ${name}" >&2 + echo "#####################" >&2 + + # Test that all values used by the chart are in values.yaml with the same defaults as the pattern + doTest naked + + # Test the charts as the pattern would drive them + doTest normal "$3" + + # Ensure the differences between the two results are also stable + doTestCompare else - echo "FAIL on $target $TEST_VARIANT with opts [$CHART_OPTS]" + doTest $2 "$3" fi -exit $rc +exit 0 diff --git a/common/tests/acm-naked.expected.yaml b/common/tests/acm-naked.expected.yml similarity index 100% rename from common/tests/acm-naked.expected.yaml rename to common/tests/acm-naked.expected.yml diff --git a/common/tests/acm-normal.expected.yaml b/common/tests/acm-normal.expected.yaml deleted file mode 100644 index 29af29a8..00000000 --- a/common/tests/acm-normal.expected.yaml +++ /dev/null @@ -1,204 +0,0 @@ ---- -# Source: acm/templates/multiclusterhub.yaml -apiVersion: operator.open-cluster-management.io/v1 -kind: MultiClusterHub -metadata: - name: multiclusterhub - namespace: open-cluster-management - annotations: - argocd.argoproj.io/sync-wave: "-1" -spec: {} ---- -# Source: acm/templates/policies/application-policies.yaml -apiVersion: policy.open-cluster-management.io/v1 -kind: PlacementBinding -metadata: - name: edge-placement-binding - annotations: - argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true -placementRef: - name: edge-placement - kind: PlacementRule - apiGroup: apps.open-cluster-management.io -subjects: - - name: edge-clustergroup-policy - kind: Policy - apiGroup: policy.open-cluster-management.io ---- -# Source: acm/templates/policies/ocp-gitops-policy.yaml -apiVersion: policy.open-cluster-management.io/v1 -kind: PlacementBinding -metadata: - name: openshift-gitops-placement-binding - annotations: - argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true -placementRef: - name: openshift-gitops-placement - kind: PlacementRule - apiGroup: apps.open-cluster-management.io -subjects: - - name: openshift-gitops-policy - kind: Policy - apiGroup: policy.open-cluster-management.io ---- -# Source: acm/templates/policies/application-policies.yaml -apiVersion: apps.open-cluster-management.io/v1 -kind: PlacementRule -metadata: - name: edge-placement -spec: - clusterConditions: - - status: 'True' - type: ManagedClusterConditionAvailable - clusterSelector: { - "matchExpressions": [ - { - "key": "vendor", - "operator": "In", - "values": [ - "OpenShift" - ] - } - ] -} ---- -# Source: acm/templates/policies/ocp-gitops-policy.yaml -apiVersion: apps.open-cluster-management.io/v1 -kind: PlacementRule -metadata: - name: openshift-gitops-placement -spec: - clusterConditions: - - status: 'True' - type: ManagedClusterConditionAvailable - clusterSelector: - matchExpressions: - - key: vendor - operator: In - values: - - OpenShift ---- -# Source: acm/templates/policies/application-policies.yaml -# TODO: Also create a GitOpsCluster.apps.open-cluster-management.io -apiVersion: policy.open-cluster-management.io/v1 -kind: Policy -metadata: - name: edge-clustergroup-policy - annotations: - argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true - argocd.argoproj.io/compare-options: IgnoreExtraneous -spec: - remediationAction: enforce - disabled: false - policy-templates: - - objectDefinition: - apiVersion: policy.open-cluster-management.io/v1 - kind: ConfigurationPolicy - metadata: - name: edge-clustergroup-config - spec: - remediationAction: enforce - severity: medium - namespaceSelector: - include: - - default - object-templates: - - complianceType: mustonlyhave - objectDefinition: - apiVersion: argoproj.io/v1alpha1 - kind: Application - metadata: - name: mypattern-edge - namespace: openshift-gitops - finalizers: - - resources-finalizer.argocd.argoproj.io/foreground - spec: - project: default - source: - repoURL: https://github.com/pattern-clone/mypattern - targetRevision: main - path: common/clustergroup - helm: - ignoreMissingValueFiles: true - valueFiles: - - "/values-global.yaml" - - "/values-edge.yaml" - parameters: - - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL - - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION - - name: global.namespace - value: $ARGOCD_APP_NAMESPACE - - name: global.pattern - value: mypattern - - name: global.hubClusterDomain - value: hub.example.com - - name: global.localClusterDomain - value: '{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain }}' - - name: clusterGroup.isHubCluster - value: "false" - destination: - server: https://kubernetes.default.svc - namespace: mypattern-edge - syncPolicy: - automated: - prune: false - selfHeal: true - ignoreDifferences: - - group: apps - kind: Deployment - jsonPointers: - - /spec/replicas - - group: route.openshift.io - kind: Route - jsonPointers: - - /status ---- -# Source: acm/templates/policies/ocp-gitops-policy.yaml -apiVersion: policy.open-cluster-management.io/v1 -kind: Policy -metadata: - name: openshift-gitops-policy - annotations: - policy.open-cluster-management.io/standards: NIST-CSF - policy.open-cluster-management.io/categories: PR.DS Data Security - policy.open-cluster-management.io/controls: PR.DS-1 Data-at-rest - argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true - argocd.argoproj.io/compare-options: IgnoreExtraneous -spec: - remediationAction: enforce - disabled: false - policy-templates: - - objectDefinition: - apiVersion: policy.open-cluster-management.io/v1 - kind: ConfigurationPolicy - metadata: - name: openshift-gitops-config - spec: - remediationAction: enforce - severity: medium - namespaceSelector: - include: - - default - object-templates: - - complianceType: mustonlyhave - objectDefinition: - # This is an auto-generated file. DO NOT EDIT - apiVersion: operators.coreos.com/v1alpha1 - kind: Subscription - metadata: - name: openshift-gitops-operator - namespace: openshift-operators - labels: - operators.coreos.com/openshift-gitops-operator.openshift-operators: '' - spec: - channel: stable - installPlanApproval: Automatic - name: openshift-gitops-operator - source: redhat-operators - sourceNamespace: openshift-marketplace - config: - env: - - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES - value: "*" diff --git a/common/tests/acm-normal.expected.yml b/common/tests/acm-normal.expected.yml new file mode 100644 index 00000000..42b9452b --- /dev/null +++ b/common/tests/acm-normal.expected.yml @@ -0,0 +1,694 @@ +--- +# Source: acm/templates/provision/secrets-common.yaml +apiVersion: v1 +kind: Secret +metadata: + name: aws-ap-acm-provision-edge-install-config +data: + # Base64 encoding of install-config yaml + install-config.yaml: CgphcGlWZXJzaW9uOiB2MQptZXRhZGF0YToKICBuYW1lOiAnYXdzLWFwJyAKYmFzZURvbWFpbjogYmx1ZXByaW50cy5yaGVjb2VuZy5jb20KY29udHJvbFBsYW5lOgogIGFyY2hpdGVjdHVyZTogYW1kNjQKICBoeXBlcnRocmVhZGluZzogRW5hYmxlZAogIG5hbWU6IGNvbnRyb2xQbGFuZQogIHJlcGxpY2FzOiAzCiAgcGxhdGZvcm06CiAgICBhd3M6CiAgICAgIHR5cGU6IG01LnhsYXJnZQpjb21wdXRlOgotIGh5cGVydGhyZWFkaW5nOiBFbmFibGVkCiAgYXJjaGl0ZWN0dXJlOiBhbWQ2NAogIG5hbWU6ICd3b3JrZXInCiAgcmVwbGljYXM6IDMKICBwbGF0Zm9ybToKICAgIGF3czoKICAgICAgdHlwZTogbTUueGxhcmdlCm5ldHdvcmtpbmc6CiAgY2x1c3Rlck5ldHdvcms6CiAgLSBjaWRyOiAxMC4xMjguMC4wLzE0CiAgICBob3N0UHJlZml4OiAyMwogIG1hY2hpbmVOZXR3b3JrOgogIC0gY2lkcjogMTAuMC4wLjAvMTYKICBuZXR3b3JrVHlwZTogT3BlblNoaWZ0U0ROCiAgc2VydmljZU5ldHdvcms6CiAgLSAxNzIuMzAuMC4wLzE2CnBsYXRmb3JtOiB7CiAgImF3cyI6IHsKICAgICJyZWdpb24iOiAiYXAtc291dGhlYXN0LTIiCiAgfQp9CnB1bGxTZWNyZXQ6ICIiICMgc2tpcCwgaGl2ZSB3aWxsIGluamVjdCBiYXNlZCBvbiBpdCdzIHNlY3JldHMKc3NoS2V5OiAiIiAgICAgIyBza2lwLCBoaXZlIHdpbGwgaW5qZWN0IGJhc2VkIG9uIGl0J3Mgc2VjcmV0cw== +type: Opaque +--- +# Source: acm/templates/provision/secrets-common.yaml +apiVersion: v1 +kind: Secret +metadata: + name: azure-us-acm-provision-edge-install-config +data: + # Base64 encoding of install-config yaml + install-config.yaml: CgphcGlWZXJzaW9uOiB2MQptZXRhZGF0YToKICBuYW1lOiAnYXp1cmUtdXMnIApiYXNlRG9tYWluOiBibHVlcHJpbnRzLnJoZWNvZW5nLmNvbQpjb250cm9sUGxhbmU6CiAgYXJjaGl0ZWN0dXJlOiBhbWQ2NAogIGh5cGVydGhyZWFkaW5nOiBFbmFibGVkCiAgbmFtZTogY29udHJvbFBsYW5lCiAgcmVwbGljYXM6IDMKICBwbGF0Zm9ybToKICAgIGF6dXJlOgogICAgICB0eXBlOiBTdGFuZGFyZF9EOHNfdjMKY29tcHV0ZToKLSBoeXBlcnRocmVhZGluZzogRW5hYmxlZAogIGFyY2hpdGVjdHVyZTogYW1kNjQKICBuYW1lOiAnd29ya2VyJwogIHJlcGxpY2FzOiAzCiAgcGxhdGZvcm06CiAgICBhenVyZToKICAgICAgdHlwZTogU3RhbmRhcmRfRDhzX3YzCm5ldHdvcmtpbmc6CiAgY2x1c3Rlck5ldHdvcms6CiAgLSBjaWRyOiAxMC4xMjguMC4wLzE0CiAgICBob3N0UHJlZml4OiAyMwogIG1hY2hpbmVOZXR3b3JrOgogIC0gY2lkcjogMTAuMC4wLjAvMTYKICBuZXR3b3JrVHlwZTogT3BlblNoaWZ0U0ROCiAgc2VydmljZU5ldHdvcms6CiAgLSAxNzIuMzAuMC4wLzE2CnBsYXRmb3JtOiB7CiAgImF6dXJlIjogewogICAgImJhc2VEb21haW5SZXNvdXJjZUdyb3VwTmFtZSI6ICJkb2pvLWRucy16b25lcyIsCiAgICAicmVnaW9uIjogImVhc3R1cyIKICB9Cn0KcHVsbFNlY3JldDogIiIgIyBza2lwLCBoaXZlIHdpbGwgaW5qZWN0IGJhc2VkIG9uIGl0J3Mgc2VjcmV0cwpzc2hLZXk6ICIiICAgICAjIHNraXAsIGhpdmUgd2lsbCBpbmplY3QgYmFzZWQgb24gaXQncyBzZWNyZXRz +type: Opaque +--- +# Source: acm/templates/provision/clusterpool.yaml +apiVersion: hive.openshift.io/v1 +kind: ClusterClaim +metadata: + name: 'One-acm-provision-edge' + annotations: + argocd.argoproj.io/sync-wave: "20" + cluster.open-cluster-management.io/createmanagedcluster: "true" + labels: + clusterClaimName: One-acm-provision-edge + clusterGroup: region +spec: + clusterPoolName: aws-ap +--- +# Source: acm/templates/provision/clusterpool.yaml +apiVersion: hive.openshift.io/v1 +kind: ClusterClaim +metadata: + name: 'Two-acm-provision-edge' + annotations: + argocd.argoproj.io/sync-wave: "20" + cluster.open-cluster-management.io/createmanagedcluster: "true" + labels: + clusterClaimName: Two-acm-provision-edge + clusterGroup: region +spec: + clusterPoolName: azure-us +--- +# Source: acm/templates/provision/clusterpool.yaml +apiVersion: hive.openshift.io/v1 +kind: ClusterClaim +metadata: + name: 'Three-acm-provision-edge' + annotations: + argocd.argoproj.io/sync-wave: "20" + cluster.open-cluster-management.io/createmanagedcluster: "true" + labels: + clusterClaimName: Three-acm-provision-edge + clusterGroup: region +spec: + clusterPoolName: azure-us +--- +# Source: acm/templates/provision/clusterpool.yaml +apiVersion: hive.openshift.io/v1 +kind: ClusterPool +metadata: + name: "aws-ap-acm-provision-edge" + annotations: + argocd.argoproj.io/sync-wave: "10" + labels: + cloud: aws + region: 'ap-southeast-2' + vendor: OpenShift + cluster.open-cluster-management.io/clusterset: aws-ap +spec: + size: 3 + runningCount: 1 + baseDomain: blueprints.rhecoeng.com + installConfigSecretTemplateRef: + name: aws-ap-acm-provision-edge-install-config + imageSetRef: + name: img4.10.18-x86-64-appsub + pullSecretRef: + name: aws-ap-acm-provision-edge-pull-secret + skipMachinePools: true # Disable MachinePool as using custom install-config + platform: + aws: + credentialsSecretRef: + name: aws-ap-acm-provision-edge-creds + region: ap-southeast-2 +--- +# Source: acm/templates/provision/clusterpool.yaml +apiVersion: hive.openshift.io/v1 +kind: ClusterPool +metadata: + name: "azure-us-acm-provision-edge" + annotations: + argocd.argoproj.io/sync-wave: "10" + labels: + cloud: azure + region: 'eastus' + vendor: OpenShift + cluster.open-cluster-management.io/clusterset: azure-us +spec: + size: 2 + runningCount: 2 + baseDomain: blueprints.rhecoeng.com + installConfigSecretTemplateRef: + name: azure-us-acm-provision-edge-install-config + imageSetRef: + name: img4.10.18-x86-64-appsub + pullSecretRef: + name: azure-us-acm-provision-edge-pull-secret + skipMachinePools: true # Disable MachinePool as using custom install-config + platform: + azure: + credentialsSecretRef: + name: azure-us-acm-provision-edge-creds + region: eastus +--- +# Source: acm/templates/provision/secrets-aws.yaml +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: aws-ap-acm-provision-edge-creds +spec: + dataFrom: + - extract: + # Expects entries called: aws_access_key_id and aws_secret_access_key + key: secret/data/hub/aws + refreshInterval: 24h0m0s + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: aws-ap-acm-provision-edge-creds + creationPolicy: Owner + template: + type: Opaque +--- +# Source: acm/templates/provision/secrets-aws.yaml +# For use when manually creating clusters with ACM +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: aws-ap-acm-provision-edge-infra-creds +spec: + data: + - secretKey: openshiftPullSecret + remoteRef: + key: secret/data/hub/openshiftPullSecret + property: content + - secretKey: awsKeyId + remoteRef: + key: secret/data/hub/aws + property: aws_access_key_id + - secretKey: awsAccessKey + remoteRef: + key: secret/data/hub/aws + property: aws_secret_access_key + - secretKey: sshPublicKey + remoteRef: + key: secret/data/hub/publickey + property: content + - secretKey: sshPrivateKey + remoteRef: + key: secret/data/hub/privatekey + property: content + refreshInterval: 24h0m0s + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: aws-ap-acm-provision-edge-infra-creds + creationPolicy: Owner + template: + type: Opaque + metadata: + labels: + cluster.open-cluster-management.io/credentials: "" + cluster.open-cluster-management.io/type: aws + data: + baseDomain: "blueprints.rhecoeng.com" + pullSecret: |- + {{ .openshiftPullSecret | toString }} + aws_access_key_id: |- + {{ .awsKeyId | toString }} + aws_secret_access_key: |- + {{ .awsAccessKey | toString }} + ssh-privatekey: |- + {{ .sshPrivateKey | toString }} + ssh-publickey: |- + {{ .sshPublicKey | toString }} + httpProxy: "" + httpsProxy: "" + noProxy: "" + additionalTrustBundle: "" +--- +# Source: acm/templates/provision/secrets-azure.yaml +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: azure-us-acm-provision-edge-creds +spec: + data: + - secretKey: azureOsServicePrincipal + remoteRef: + key: secret/data/hub/azureOsServicePrincipal + property: content + refreshInterval: 24h0m0s + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: azure-us-acm-provision-edge-creds + creationPolicy: Owner + template: + type: Opaque + data: + osServicePrincipal.json: |- + {{ .azureOsServicePrincipal | toString }} +--- +# Source: acm/templates/provision/secrets-azure.yaml +# For use when manually creating clusters with ACM +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: azure-us-acm-provision-edge-infra-creds +spec: + data: + - secretKey: openshiftPullSecret + remoteRef: + key: secret/data/hub/openshiftPullSecret + property: content + - secretKey: sshPublicKey + remoteRef: + key: secret/data/hub/publickey + property: content + - secretKey: sshPrivateKey + remoteRef: + key: secret/data/hub/privatekey + property: content + - secretKey: azureOsServicePrincipal + remoteRef: + key: secret/data/hub/azureOsServicePrincipal + property: content + refreshInterval: 24h0m0s + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: azure-us-acm-provision-edge-infra-creds + creationPolicy: Owner + template: + type: Opaque + metadata: + labels: + cluster.open-cluster-management.io/credentials: "" + cluster.open-cluster-management.io/type: aws + data: + cloudName: AzurePublicCloud + osServicePrincipal.json: |- + {{ .azureOsServicePrincipal | toString }} + baseDomain: "blueprints.rhecoeng.com" + baseDomainResourceGroupName: "dojo-dns-zones" + pullSecret: |- + {{ .openshiftPullSecret | toString }} + ssh-privatekey: |- + {{ .sshPrivateKey | toString }} + ssh-publickey: |- + {{ .sshPublicKey | toString }} + httpProxy: "" + httpsProxy: "" + noProxy: "" + additionalTrustBundle: "" +--- +# Source: acm/templates/provision/secrets-common.yaml +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: aws-ap-acm-provision-edge-pull-secret +spec: + data: + - secretKey: openshiftPullSecret + remoteRef: + key: secret/data/hub/openshiftPullSecret + property: content + refreshInterval: 24h0m0s + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: aws-ap-acm-provision-edge-pull-secret + creationPolicy: Owner + template: + type: kubernetes.io/dockerconfigjson + data: + .dockerconfigjson: |- + {{ .openshiftPullSecret | toString }} +--- +# Source: acm/templates/provision/secrets-common.yaml +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: aws-ap-acm-provision-edge-ssh-private-key +spec: + data: + - secretKey: sshPrivateKey + remoteRef: + key: secret/data/hub/privatekey + property: content + refreshInterval: 24h0m0s + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: aws-ap-acm-provision-edge-ssh-private-key + creationPolicy: Owner + template: + type: Opaque + data: + ssh-privatekey: |- + {{ .sshPrivateKey | toString }} +--- +# Source: acm/templates/provision/secrets-common.yaml +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: azure-us-acm-provision-edge-pull-secret +spec: + data: + - secretKey: openshiftPullSecret + remoteRef: + key: secret/data/hub/openshiftPullSecret + property: content + refreshInterval: 24h0m0s + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: azure-us-acm-provision-edge-pull-secret + creationPolicy: Owner + template: + type: kubernetes.io/dockerconfigjson + data: + .dockerconfigjson: |- + {{ .openshiftPullSecret | toString }} +--- +# Source: acm/templates/provision/secrets-common.yaml +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: azure-us-acm-provision-edge-ssh-private-key +spec: + data: + - secretKey: sshPrivateKey + remoteRef: + key: secret/data/hub/privatekey + property: content + refreshInterval: 24h0m0s + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: azure-us-acm-provision-edge-ssh-private-key + creationPolicy: Owner + template: + type: Opaque + data: + ssh-privatekey: |- + {{ .sshPrivateKey | toString }} +--- +# Source: acm/templates/provision/clusterpool.yaml +apiVersion: cluster.open-cluster-management.io/v1beta1 +kind: ManagedClusterSet +metadata: + annotations: + cluster.open-cluster-management.io/submariner-broker-ns: acm-provision-edge-broker + name: acm-provision-edge +spec: + clusterSelector: + selectorType: LegacyClusterSetLabel +--- +# Source: acm/templates/multiclusterhub.yaml +apiVersion: operator.open-cluster-management.io/v1 +kind: MultiClusterHub +metadata: + name: multiclusterhub + namespace: open-cluster-management + annotations: + argocd.argoproj.io/sync-wave: "-1" +spec: {} +--- +# Source: acm/templates/policies/application-policies.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: acm-edge-placement-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: acm-edge-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: acm-edge-clustergroup-policy + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +# Source: acm/templates/policies/application-policies.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: acm-provision-edge-placement-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: acm-provision-edge-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: acm-provision-edge-clustergroup-policy + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: openshift-gitops-placement-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: openshift-gitops-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: openshift-gitops-policy + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +# Source: acm/templates/policies/application-policies.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: acm-edge-placement +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchLabels: + clusterGroup: acm-region +--- +# Source: acm/templates/policies/application-policies.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: acm-provision-edge-placement +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchLabels: + clusterGroup: region +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: openshift-gitops-placement +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: vendor + operator: In + values: + - OpenShift +--- +# Source: acm/templates/policies/application-policies.yaml +# TODO: Also create a GitOpsCluster.apps.open-cluster-management.io +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: acm-edge-clustergroup-policy + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + argocd.argoproj.io/compare-options: IgnoreExtraneous +spec: + remediationAction: enforce + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: acm-edge-clustergroup-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + apiVersion: argoproj.io/v1alpha1 + kind: Application + metadata: + name: mypattern-acm-edge + namespace: openshift-gitops + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground + spec: + project: default + source: + repoURL: https://github.com/pattern-clone/mypattern + targetRevision: main + path: common/clustergroup + helm: + ignoreMissingValueFiles: true + valueFiles: + - "/values-global.yaml" + - "/values-acm-edge.yaml" + parameters: + - name: global.repoURL + value: $ARGOCD_APP_SOURCE_REPO_URL + - name: global.targetRevision + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + - name: global.namespace + value: $ARGOCD_APP_NAMESPACE + - name: global.pattern + value: mypattern + - name: global.hubClusterDomain + value: apps.hub.example.com + - name: global.localClusterDomain + value: '{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain }}' + # Requires ACM 2.6 or higher + - name: global.clusterDomain + value: '{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain | replace "apps." "" }}' + - name: clusterGroup.name + value: acm-edge + - name: clusterGroup.isHubCluster + value: "false" + destination: + server: https://kubernetes.default.svc + namespace: mypattern-acm-edge + syncPolicy: + automated: + prune: false + selfHeal: true + ignoreDifferences: + - group: apps + kind: Deployment + jsonPointers: + - /spec/replicas + - group: route.openshift.io + kind: Route + jsonPointers: + - /status +--- +# Source: acm/templates/policies/application-policies.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: acm-provision-edge-clustergroup-policy + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + argocd.argoproj.io/compare-options: IgnoreExtraneous +spec: + remediationAction: enforce + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: acm-provision-edge-clustergroup-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + apiVersion: argoproj.io/v1alpha1 + kind: Application + metadata: + name: mypattern-acm-provision-edge + namespace: openshift-gitops + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground + spec: + project: default + source: + repoURL: https://github.com/pattern-clone/mypattern + targetRevision: main + path: common/clustergroup + helm: + ignoreMissingValueFiles: true + valueFiles: + - "/values-global.yaml" + - "/values-acm-provision-edge.yaml" + parameters: + - name: global.repoURL + value: $ARGOCD_APP_SOURCE_REPO_URL + - name: global.targetRevision + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + - name: global.namespace + value: $ARGOCD_APP_NAMESPACE + - name: global.pattern + value: mypattern + - name: global.hubClusterDomain + value: apps.hub.example.com + - name: global.localClusterDomain + value: '{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain }}' + # Requires ACM 2.6 or higher + - name: global.clusterDomain + value: '{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain | replace "apps." "" }}' + - name: clusterGroup.name + value: acm-provision-edge + - name: clusterGroup.isHubCluster + value: "false" + destination: + server: https://kubernetes.default.svc + namespace: mypattern-acm-provision-edge + syncPolicy: + automated: + prune: false + selfHeal: true + ignoreDifferences: + - group: apps + kind: Deployment + jsonPointers: + - /spec/replicas + - group: route.openshift.io + kind: Route + jsonPointers: + - /status +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: openshift-gitops-policy + annotations: + policy.open-cluster-management.io/standards: NIST-CSF + policy.open-cluster-management.io/categories: PR.DS Data Security + policy.open-cluster-management.io/controls: PR.DS-1 Data-at-rest + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + argocd.argoproj.io/compare-options: IgnoreExtraneous +spec: + remediationAction: enforce + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: openshift-gitops-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + # This is an auto-generated file. DO NOT EDIT + apiVersion: operators.coreos.com/v1alpha1 + kind: Subscription + metadata: + name: openshift-gitops-operator + namespace: openshift-operators + labels: + operators.coreos.com/openshift-gitops-operator.openshift-operators: '' + spec: + channel: stable + installPlanApproval: Automatic + name: openshift-gitops-operator + source: redhat-operators + sourceNamespace: openshift-marketplace + config: + env: + - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES + value: "*" diff --git a/common/tests/acm.expected.diff b/common/tests/acm.expected.diff new file mode 100644 index 00000000..9cf23621 --- /dev/null +++ b/common/tests/acm.expected.diff @@ -0,0 +1,633 @@ +--- tests/acm-naked.expected.yml ++++ tests/acm-normal.expected.yml +@@ -1,6 +1,386 @@ + --- +-# Source: acm/templates/policies/application-policies.yaml +-# TODO: Also create a GitOpsCluster.apps.open-cluster-management.io ++# Source: acm/templates/provision/secrets-common.yaml ++apiVersion: v1 ++kind: Secret ++metadata: ++ name: aws-ap-acm-provision-edge-install-config ++data: ++ # Base64 encoding of install-config yaml ++ install-config.yaml: CgphcGlWZXJzaW9uOiB2MQptZXRhZGF0YToKICBuYW1lOiAnYXdzLWFwJyAKYmFzZURvbWFpbjogYmx1ZXByaW50cy5yaGVjb2VuZy5jb20KY29udHJvbFBsYW5lOgogIGFyY2hpdGVjdHVyZTogYW1kNjQKICBoeXBlcnRocmVhZGluZzogRW5hYmxlZAogIG5hbWU6IGNvbnRyb2xQbGFuZQogIHJlcGxpY2FzOiAzCiAgcGxhdGZvcm06CiAgICBhd3M6CiAgICAgIHR5cGU6IG01LnhsYXJnZQpjb21wdXRlOgotIGh5cGVydGhyZWFkaW5nOiBFbmFibGVkCiAgYXJjaGl0ZWN0dXJlOiBhbWQ2NAogIG5hbWU6ICd3b3JrZXInCiAgcmVwbGljYXM6IDMKICBwbGF0Zm9ybToKICAgIGF3czoKICAgICAgdHlwZTogbTUueGxhcmdlCm5ldHdvcmtpbmc6CiAgY2x1c3Rlck5ldHdvcms6CiAgLSBjaWRyOiAxMC4xMjguMC4wLzE0CiAgICBob3N0UHJlZml4OiAyMwogIG1hY2hpbmVOZXR3b3JrOgogIC0gY2lkcjogMTAuMC4wLjAvMTYKICBuZXR3b3JrVHlwZTogT3BlblNoaWZ0U0ROCiAgc2VydmljZU5ldHdvcms6CiAgLSAxNzIuMzAuMC4wLzE2CnBsYXRmb3JtOiB7CiAgImF3cyI6IHsKICAgICJyZWdpb24iOiAiYXAtc291dGhlYXN0LTIiCiAgfQp9CnB1bGxTZWNyZXQ6ICIiICMgc2tpcCwgaGl2ZSB3aWxsIGluamVjdCBiYXNlZCBvbiBpdCdzIHNlY3JldHMKc3NoS2V5OiAiIiAgICAgIyBza2lwLCBoaXZlIHdpbGwgaW5qZWN0IGJhc2VkIG9uIGl0J3Mgc2VjcmV0cw== ++type: Opaque ++--- ++# Source: acm/templates/provision/secrets-common.yaml ++apiVersion: v1 ++kind: Secret ++metadata: ++ name: azure-us-acm-provision-edge-install-config ++data: ++ # Base64 encoding of install-config yaml ++ install-config.yaml: CgphcGlWZXJzaW9uOiB2MQptZXRhZGF0YToKICBuYW1lOiAnYXp1cmUtdXMnIApiYXNlRG9tYWluOiBibHVlcHJpbnRzLnJoZWNvZW5nLmNvbQpjb250cm9sUGxhbmU6CiAgYXJjaGl0ZWN0dXJlOiBhbWQ2NAogIGh5cGVydGhyZWFkaW5nOiBFbmFibGVkCiAgbmFtZTogY29udHJvbFBsYW5lCiAgcmVwbGljYXM6IDMKICBwbGF0Zm9ybToKICAgIGF6dXJlOgogICAgICB0eXBlOiBTdGFuZGFyZF9EOHNfdjMKY29tcHV0ZToKLSBoeXBlcnRocmVhZGluZzogRW5hYmxlZAogIGFyY2hpdGVjdHVyZTogYW1kNjQKICBuYW1lOiAnd29ya2VyJwogIHJlcGxpY2FzOiAzCiAgcGxhdGZvcm06CiAgICBhenVyZToKICAgICAgdHlwZTogU3RhbmRhcmRfRDhzX3YzCm5ldHdvcmtpbmc6CiAgY2x1c3Rlck5ldHdvcms6CiAgLSBjaWRyOiAxMC4xMjguMC4wLzE0CiAgICBob3N0UHJlZml4OiAyMwogIG1hY2hpbmVOZXR3b3JrOgogIC0gY2lkcjogMTAuMC4wLjAvMTYKICBuZXR3b3JrVHlwZTogT3BlblNoaWZ0U0ROCiAgc2VydmljZU5ldHdvcms6CiAgLSAxNzIuMzAuMC4wLzE2CnBsYXRmb3JtOiB7CiAgImF6dXJlIjogewogICAgImJhc2VEb21haW5SZXNvdXJjZUdyb3VwTmFtZSI6ICJkb2pvLWRucy16b25lcyIsCiAgICAicmVnaW9uIjogImVhc3R1cyIKICB9Cn0KcHVsbFNlY3JldDogIiIgIyBza2lwLCBoaXZlIHdpbGwgaW5qZWN0IGJhc2VkIG9uIGl0J3Mgc2VjcmV0cwpzc2hLZXk6ICIiICAgICAjIHNraXAsIGhpdmUgd2lsbCBpbmplY3QgYmFzZWQgb24gaXQncyBzZWNyZXRz ++type: Opaque ++--- ++# Source: acm/templates/provision/clusterpool.yaml ++apiVersion: hive.openshift.io/v1 ++kind: ClusterClaim ++metadata: ++ name: 'One-acm-provision-edge' ++ annotations: ++ argocd.argoproj.io/sync-wave: "20" ++ cluster.open-cluster-management.io/createmanagedcluster: "true" ++ labels: ++ clusterClaimName: One-acm-provision-edge ++ clusterGroup: region ++spec: ++ clusterPoolName: aws-ap ++--- ++# Source: acm/templates/provision/clusterpool.yaml ++apiVersion: hive.openshift.io/v1 ++kind: ClusterClaim ++metadata: ++ name: 'Two-acm-provision-edge' ++ annotations: ++ argocd.argoproj.io/sync-wave: "20" ++ cluster.open-cluster-management.io/createmanagedcluster: "true" ++ labels: ++ clusterClaimName: Two-acm-provision-edge ++ clusterGroup: region ++spec: ++ clusterPoolName: azure-us ++--- ++# Source: acm/templates/provision/clusterpool.yaml ++apiVersion: hive.openshift.io/v1 ++kind: ClusterClaim ++metadata: ++ name: 'Three-acm-provision-edge' ++ annotations: ++ argocd.argoproj.io/sync-wave: "20" ++ cluster.open-cluster-management.io/createmanagedcluster: "true" ++ labels: ++ clusterClaimName: Three-acm-provision-edge ++ clusterGroup: region ++spec: ++ clusterPoolName: azure-us ++--- ++# Source: acm/templates/provision/clusterpool.yaml ++apiVersion: hive.openshift.io/v1 ++kind: ClusterPool ++metadata: ++ name: "aws-ap-acm-provision-edge" ++ annotations: ++ argocd.argoproj.io/sync-wave: "10" ++ labels: ++ cloud: aws ++ region: 'ap-southeast-2' ++ vendor: OpenShift ++ cluster.open-cluster-management.io/clusterset: aws-ap ++spec: ++ size: 3 ++ runningCount: 1 ++ baseDomain: blueprints.rhecoeng.com ++ installConfigSecretTemplateRef: ++ name: aws-ap-acm-provision-edge-install-config ++ imageSetRef: ++ name: img4.10.18-x86-64-appsub ++ pullSecretRef: ++ name: aws-ap-acm-provision-edge-pull-secret ++ skipMachinePools: true # Disable MachinePool as using custom install-config ++ platform: ++ aws: ++ credentialsSecretRef: ++ name: aws-ap-acm-provision-edge-creds ++ region: ap-southeast-2 ++--- ++# Source: acm/templates/provision/clusterpool.yaml ++apiVersion: hive.openshift.io/v1 ++kind: ClusterPool ++metadata: ++ name: "azure-us-acm-provision-edge" ++ annotations: ++ argocd.argoproj.io/sync-wave: "10" ++ labels: ++ cloud: azure ++ region: 'eastus' ++ vendor: OpenShift ++ cluster.open-cluster-management.io/clusterset: azure-us ++spec: ++ size: 2 ++ runningCount: 2 ++ baseDomain: blueprints.rhecoeng.com ++ installConfigSecretTemplateRef: ++ name: azure-us-acm-provision-edge-install-config ++ imageSetRef: ++ name: img4.10.18-x86-64-appsub ++ pullSecretRef: ++ name: azure-us-acm-provision-edge-pull-secret ++ skipMachinePools: true # Disable MachinePool as using custom install-config ++ platform: ++ azure: ++ credentialsSecretRef: ++ name: azure-us-acm-provision-edge-creds ++ region: eastus ++--- ++# Source: acm/templates/provision/secrets-aws.yaml ++apiVersion: external-secrets.io/v1beta1 ++kind: ExternalSecret ++metadata: ++ name: aws-ap-acm-provision-edge-creds ++spec: ++ dataFrom: ++ - extract: ++ # Expects entries called: aws_access_key_id and aws_secret_access_key ++ key: secret/data/hub/aws ++ refreshInterval: 24h0m0s ++ secretStoreRef: ++ name: vault-backend ++ kind: ClusterSecretStore ++ target: ++ name: aws-ap-acm-provision-edge-creds ++ creationPolicy: Owner ++ template: ++ type: Opaque ++--- ++# Source: acm/templates/provision/secrets-aws.yaml ++# For use when manually creating clusters with ACM ++apiVersion: external-secrets.io/v1beta1 ++kind: ExternalSecret ++metadata: ++ name: aws-ap-acm-provision-edge-infra-creds ++spec: ++ data: ++ - secretKey: openshiftPullSecret ++ remoteRef: ++ key: secret/data/hub/openshiftPullSecret ++ property: content ++ - secretKey: awsKeyId ++ remoteRef: ++ key: secret/data/hub/aws ++ property: aws_access_key_id ++ - secretKey: awsAccessKey ++ remoteRef: ++ key: secret/data/hub/aws ++ property: aws_secret_access_key ++ - secretKey: sshPublicKey ++ remoteRef: ++ key: secret/data/hub/publickey ++ property: content ++ - secretKey: sshPrivateKey ++ remoteRef: ++ key: secret/data/hub/privatekey ++ property: content ++ refreshInterval: 24h0m0s ++ secretStoreRef: ++ name: vault-backend ++ kind: ClusterSecretStore ++ target: ++ name: aws-ap-acm-provision-edge-infra-creds ++ creationPolicy: Owner ++ template: ++ type: Opaque ++ metadata: ++ labels: ++ cluster.open-cluster-management.io/credentials: "" ++ cluster.open-cluster-management.io/type: aws ++ data: ++ baseDomain: "blueprints.rhecoeng.com" ++ pullSecret: |- ++ {{ .openshiftPullSecret | toString }} ++ aws_access_key_id: |- ++ {{ .awsKeyId | toString }} ++ aws_secret_access_key: |- ++ {{ .awsAccessKey | toString }} ++ ssh-privatekey: |- ++ {{ .sshPrivateKey | toString }} ++ ssh-publickey: |- ++ {{ .sshPublicKey | toString }} ++ httpProxy: "" ++ httpsProxy: "" ++ noProxy: "" ++ additionalTrustBundle: "" ++--- ++# Source: acm/templates/provision/secrets-azure.yaml ++apiVersion: external-secrets.io/v1beta1 ++kind: ExternalSecret ++metadata: ++ name: azure-us-acm-provision-edge-creds ++spec: ++ data: ++ - secretKey: azureOsServicePrincipal ++ remoteRef: ++ key: secret/data/hub/azureOsServicePrincipal ++ property: content ++ refreshInterval: 24h0m0s ++ secretStoreRef: ++ name: vault-backend ++ kind: ClusterSecretStore ++ target: ++ name: azure-us-acm-provision-edge-creds ++ creationPolicy: Owner ++ template: ++ type: Opaque ++ data: ++ osServicePrincipal.json: |- ++ {{ .azureOsServicePrincipal | toString }} ++--- ++# Source: acm/templates/provision/secrets-azure.yaml ++# For use when manually creating clusters with ACM ++apiVersion: external-secrets.io/v1beta1 ++kind: ExternalSecret ++metadata: ++ name: azure-us-acm-provision-edge-infra-creds ++spec: ++ data: ++ - secretKey: openshiftPullSecret ++ remoteRef: ++ key: secret/data/hub/openshiftPullSecret ++ property: content ++ - secretKey: sshPublicKey ++ remoteRef: ++ key: secret/data/hub/publickey ++ property: content ++ - secretKey: sshPrivateKey ++ remoteRef: ++ key: secret/data/hub/privatekey ++ property: content ++ - secretKey: azureOsServicePrincipal ++ remoteRef: ++ key: secret/data/hub/azureOsServicePrincipal ++ property: content ++ refreshInterval: 24h0m0s ++ secretStoreRef: ++ name: vault-backend ++ kind: ClusterSecretStore ++ target: ++ name: azure-us-acm-provision-edge-infra-creds ++ creationPolicy: Owner ++ template: ++ type: Opaque ++ metadata: ++ labels: ++ cluster.open-cluster-management.io/credentials: "" ++ cluster.open-cluster-management.io/type: aws ++ data: ++ cloudName: AzurePublicCloud ++ osServicePrincipal.json: |- ++ {{ .azureOsServicePrincipal | toString }} ++ baseDomain: "blueprints.rhecoeng.com" ++ baseDomainResourceGroupName: "dojo-dns-zones" ++ pullSecret: |- ++ {{ .openshiftPullSecret | toString }} ++ ssh-privatekey: |- ++ {{ .sshPrivateKey | toString }} ++ ssh-publickey: |- ++ {{ .sshPublicKey | toString }} ++ httpProxy: "" ++ httpsProxy: "" ++ noProxy: "" ++ additionalTrustBundle: "" ++--- ++# Source: acm/templates/provision/secrets-common.yaml ++apiVersion: external-secrets.io/v1beta1 ++kind: ExternalSecret ++metadata: ++ name: aws-ap-acm-provision-edge-pull-secret ++spec: ++ data: ++ - secretKey: openshiftPullSecret ++ remoteRef: ++ key: secret/data/hub/openshiftPullSecret ++ property: content ++ refreshInterval: 24h0m0s ++ secretStoreRef: ++ name: vault-backend ++ kind: ClusterSecretStore ++ target: ++ name: aws-ap-acm-provision-edge-pull-secret ++ creationPolicy: Owner ++ template: ++ type: kubernetes.io/dockerconfigjson ++ data: ++ .dockerconfigjson: |- ++ {{ .openshiftPullSecret | toString }} ++--- ++# Source: acm/templates/provision/secrets-common.yaml ++apiVersion: external-secrets.io/v1beta1 ++kind: ExternalSecret ++metadata: ++ name: aws-ap-acm-provision-edge-ssh-private-key ++spec: ++ data: ++ - secretKey: sshPrivateKey ++ remoteRef: ++ key: secret/data/hub/privatekey ++ property: content ++ refreshInterval: 24h0m0s ++ secretStoreRef: ++ name: vault-backend ++ kind: ClusterSecretStore ++ target: ++ name: aws-ap-acm-provision-edge-ssh-private-key ++ creationPolicy: Owner ++ template: ++ type: Opaque ++ data: ++ ssh-privatekey: |- ++ {{ .sshPrivateKey | toString }} ++--- ++# Source: acm/templates/provision/secrets-common.yaml ++apiVersion: external-secrets.io/v1beta1 ++kind: ExternalSecret ++metadata: ++ name: azure-us-acm-provision-edge-pull-secret ++spec: ++ data: ++ - secretKey: openshiftPullSecret ++ remoteRef: ++ key: secret/data/hub/openshiftPullSecret ++ property: content ++ refreshInterval: 24h0m0s ++ secretStoreRef: ++ name: vault-backend ++ kind: ClusterSecretStore ++ target: ++ name: azure-us-acm-provision-edge-pull-secret ++ creationPolicy: Owner ++ template: ++ type: kubernetes.io/dockerconfigjson ++ data: ++ .dockerconfigjson: |- ++ {{ .openshiftPullSecret | toString }} ++--- ++# Source: acm/templates/provision/secrets-common.yaml ++apiVersion: external-secrets.io/v1beta1 ++kind: ExternalSecret ++metadata: ++ name: azure-us-acm-provision-edge-ssh-private-key ++spec: ++ data: ++ - secretKey: sshPrivateKey ++ remoteRef: ++ key: secret/data/hub/privatekey ++ property: content ++ refreshInterval: 24h0m0s ++ secretStoreRef: ++ name: vault-backend ++ kind: ClusterSecretStore ++ target: ++ name: azure-us-acm-provision-edge-ssh-private-key ++ creationPolicy: Owner ++ template: ++ type: Opaque ++ data: ++ ssh-privatekey: |- ++ {{ .sshPrivateKey | toString }} ++--- ++# Source: acm/templates/provision/clusterpool.yaml ++apiVersion: cluster.open-cluster-management.io/v1beta1 ++kind: ManagedClusterSet ++metadata: ++ annotations: ++ cluster.open-cluster-management.io/submariner-broker-ns: acm-provision-edge-broker ++ name: acm-provision-edge ++spec: ++ clusterSelector: ++ selectorType: LegacyClusterSetLabel + --- + # Source: acm/templates/multiclusterhub.yaml + apiVersion: operator.open-cluster-management.io/v1 +@@ -12,6 +392,38 @@ + argocd.argoproj.io/sync-wave: "-1" + spec: {} + --- ++# Source: acm/templates/policies/application-policies.yaml ++apiVersion: policy.open-cluster-management.io/v1 ++kind: PlacementBinding ++metadata: ++ name: acm-edge-placement-binding ++ annotations: ++ argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true ++placementRef: ++ name: acm-edge-placement ++ kind: PlacementRule ++ apiGroup: apps.open-cluster-management.io ++subjects: ++ - name: acm-edge-clustergroup-policy ++ kind: Policy ++ apiGroup: policy.open-cluster-management.io ++--- ++# Source: acm/templates/policies/application-policies.yaml ++apiVersion: policy.open-cluster-management.io/v1 ++kind: PlacementBinding ++metadata: ++ name: acm-provision-edge-placement-binding ++ annotations: ++ argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true ++placementRef: ++ name: acm-provision-edge-placement ++ kind: PlacementRule ++ apiGroup: apps.open-cluster-management.io ++subjects: ++ - name: acm-provision-edge-clustergroup-policy ++ kind: Policy ++ apiGroup: policy.open-cluster-management.io ++--- + # Source: acm/templates/policies/ocp-gitops-policy.yaml + apiVersion: policy.open-cluster-management.io/v1 + kind: PlacementBinding +@@ -28,6 +440,32 @@ + kind: Policy + apiGroup: policy.open-cluster-management.io + --- ++# Source: acm/templates/policies/application-policies.yaml ++apiVersion: apps.open-cluster-management.io/v1 ++kind: PlacementRule ++metadata: ++ name: acm-edge-placement ++spec: ++ clusterConditions: ++ - status: 'True' ++ type: ManagedClusterConditionAvailable ++ clusterSelector: ++ matchLabels: ++ clusterGroup: acm-region ++--- ++# Source: acm/templates/policies/application-policies.yaml ++apiVersion: apps.open-cluster-management.io/v1 ++kind: PlacementRule ++metadata: ++ name: acm-provision-edge-placement ++spec: ++ clusterConditions: ++ - status: 'True' ++ type: ManagedClusterConditionAvailable ++ clusterSelector: ++ matchLabels: ++ clusterGroup: region ++--- + # Source: acm/templates/policies/ocp-gitops-policy.yaml + apiVersion: apps.open-cluster-management.io/v1 + kind: PlacementRule +@@ -44,6 +482,169 @@ + values: + - OpenShift + --- ++# Source: acm/templates/policies/application-policies.yaml ++# TODO: Also create a GitOpsCluster.apps.open-cluster-management.io ++apiVersion: policy.open-cluster-management.io/v1 ++kind: Policy ++metadata: ++ name: acm-edge-clustergroup-policy ++ annotations: ++ argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true ++ argocd.argoproj.io/compare-options: IgnoreExtraneous ++spec: ++ remediationAction: enforce ++ disabled: false ++ policy-templates: ++ - objectDefinition: ++ apiVersion: policy.open-cluster-management.io/v1 ++ kind: ConfigurationPolicy ++ metadata: ++ name: acm-edge-clustergroup-config ++ spec: ++ remediationAction: enforce ++ severity: medium ++ namespaceSelector: ++ include: ++ - default ++ object-templates: ++ - complianceType: mustonlyhave ++ objectDefinition: ++ apiVersion: argoproj.io/v1alpha1 ++ kind: Application ++ metadata: ++ name: mypattern-acm-edge ++ namespace: openshift-gitops ++ finalizers: ++ - resources-finalizer.argocd.argoproj.io/foreground ++ spec: ++ project: default ++ source: ++ repoURL: https://github.com/pattern-clone/mypattern ++ targetRevision: main ++ path: common/clustergroup ++ helm: ++ ignoreMissingValueFiles: true ++ valueFiles: ++ - "/values-global.yaml" ++ - "/values-acm-edge.yaml" ++ parameters: ++ - name: global.repoURL ++ value: $ARGOCD_APP_SOURCE_REPO_URL ++ - name: global.targetRevision ++ value: $ARGOCD_APP_SOURCE_TARGET_REVISION ++ - name: global.namespace ++ value: $ARGOCD_APP_NAMESPACE ++ - name: global.pattern ++ value: mypattern ++ - name: global.hubClusterDomain ++ value: apps.hub.example.com ++ - name: global.localClusterDomain ++ value: '{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain }}' ++ # Requires ACM 2.6 or higher ++ - name: global.clusterDomain ++ value: '{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain | replace "apps." "" }}' ++ - name: clusterGroup.name ++ value: acm-edge ++ - name: clusterGroup.isHubCluster ++ value: "false" ++ destination: ++ server: https://kubernetes.default.svc ++ namespace: mypattern-acm-edge ++ syncPolicy: ++ automated: ++ prune: false ++ selfHeal: true ++ ignoreDifferences: ++ - group: apps ++ kind: Deployment ++ jsonPointers: ++ - /spec/replicas ++ - group: route.openshift.io ++ kind: Route ++ jsonPointers: ++ - /status ++--- ++# Source: acm/templates/policies/application-policies.yaml ++apiVersion: policy.open-cluster-management.io/v1 ++kind: Policy ++metadata: ++ name: acm-provision-edge-clustergroup-policy ++ annotations: ++ argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true ++ argocd.argoproj.io/compare-options: IgnoreExtraneous ++spec: ++ remediationAction: enforce ++ disabled: false ++ policy-templates: ++ - objectDefinition: ++ apiVersion: policy.open-cluster-management.io/v1 ++ kind: ConfigurationPolicy ++ metadata: ++ name: acm-provision-edge-clustergroup-config ++ spec: ++ remediationAction: enforce ++ severity: medium ++ namespaceSelector: ++ include: ++ - default ++ object-templates: ++ - complianceType: mustonlyhave ++ objectDefinition: ++ apiVersion: argoproj.io/v1alpha1 ++ kind: Application ++ metadata: ++ name: mypattern-acm-provision-edge ++ namespace: openshift-gitops ++ finalizers: ++ - resources-finalizer.argocd.argoproj.io/foreground ++ spec: ++ project: default ++ source: ++ repoURL: https://github.com/pattern-clone/mypattern ++ targetRevision: main ++ path: common/clustergroup ++ helm: ++ ignoreMissingValueFiles: true ++ valueFiles: ++ - "/values-global.yaml" ++ - "/values-acm-provision-edge.yaml" ++ parameters: ++ - name: global.repoURL ++ value: $ARGOCD_APP_SOURCE_REPO_URL ++ - name: global.targetRevision ++ value: $ARGOCD_APP_SOURCE_TARGET_REVISION ++ - name: global.namespace ++ value: $ARGOCD_APP_NAMESPACE ++ - name: global.pattern ++ value: mypattern ++ - name: global.hubClusterDomain ++ value: apps.hub.example.com ++ - name: global.localClusterDomain ++ value: '{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain }}' ++ # Requires ACM 2.6 or higher ++ - name: global.clusterDomain ++ value: '{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain | replace "apps." "" }}' ++ - name: clusterGroup.name ++ value: acm-provision-edge ++ - name: clusterGroup.isHubCluster ++ value: "false" ++ destination: ++ server: https://kubernetes.default.svc ++ namespace: mypattern-acm-provision-edge ++ syncPolicy: ++ automated: ++ prune: false ++ selfHeal: true ++ ignoreDifferences: ++ - group: apps ++ kind: Deployment ++ jsonPointers: ++ - /spec/replicas ++ - group: route.openshift.io ++ kind: Route ++ jsonPointers: ++ - /status ++--- + # Source: acm/templates/policies/ocp-gitops-policy.yaml + apiVersion: policy.open-cluster-management.io/v1 + kind: Policy diff --git a/common/tests/clustergroup-naked.expected.yaml b/common/tests/clustergroup-naked.expected.yml similarity index 99% rename from common/tests/clustergroup-naked.expected.yaml rename to common/tests/clustergroup-naked.expected.yml index 993e6bb5..4d5c5eee 100644 --- a/common/tests/clustergroup-naked.expected.yaml +++ b/common/tests/clustergroup-naked.expected.yml @@ -1,5 +1,5 @@ --- -# Source: pattern-clustergroup/templates/gitops-namespace.yaml +# Source: pattern-clustergroup/templates/plumbing/gitops-namespace.yaml apiVersion: v1 kind: Namespace metadata: @@ -12,7 +12,7 @@ metadata: name: common-example spec: {} --- -# Source: pattern-clustergroup/templates/argocd-super-role.yaml +# Source: pattern-clustergroup/templates/plumbing/argocd-super-role.yaml # WARNING: ONLY USE THIS FOR MANAGING CLUSTERS NOT FOR REGULAR USERS apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding @@ -31,7 +31,7 @@ subjects: name: openshift-gitops-argocd-server namespace: openshift-gitops --- -# Source: pattern-clustergroup/templates/argocd-super-role.yaml +# Source: pattern-clustergroup/templates/plumbing/argocd-super-role.yaml # WARNING: ONLY USE THIS FOR MANAGING CLUSTERS NOT FOR REGULAR USERS apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding @@ -56,7 +56,7 @@ subjects: name: example-gitops-argocd-dex-server namespace: common-example --- -# Source: pattern-clustergroup/templates/argocd.yaml +# Source: pattern-clustergroup/templates/plumbing/argocd.yaml apiVersion: argoproj.io/v1alpha1 kind: ArgoCD metadata: @@ -95,8 +95,10 @@ spec: --set global.targetRevision=$ARGOCD_APP_SOURCE_TARGET_REVISION --set global.namespace=$ARGOCD_APP_NAMESPACE --set global.pattern=common + --set global.clusterDomain= --set global.hubClusterDomain= --set global.localClusterDomain= + --set clusterGroup.name=example --post-renderer ./kustomize"] applicationSet: resources: @@ -167,7 +169,7 @@ spec: ca: {} status: --- -# Source: pattern-clustergroup/templates/argocd.yaml +# Source: pattern-clustergroup/templates/plumbing/argocd.yaml apiVersion: console.openshift.io/v1 kind: ConsoleLink metadata: diff --git a/common/tests/clustergroup-normal.expected.yaml b/common/tests/clustergroup-normal.expected.yml similarity index 84% rename from common/tests/clustergroup-normal.expected.yaml rename to common/tests/clustergroup-normal.expected.yml index 2af41cbb..50a8fb46 100644 --- a/common/tests/clustergroup-normal.expected.yaml +++ b/common/tests/clustergroup-normal.expected.yml @@ -1,45 +1,45 @@ --- -# Source: pattern-clustergroup/templates/gitops-namespace.yaml +# Source: pattern-clustergroup/templates/core/namespaces.yaml apiVersion: v1 kind: Namespace metadata: labels: - name: mypattern-example - # The name here needs to be consistent with - # - acm/templates/policies/application-policies.yaml - # - clustergroup/templates/applications.yaml - # - any references to secrets and route URLs in documentation - name: mypattern-example -spec: {} + name: pattern + argocd.argoproj.io/managed-by: mypattern-example + name: open-cluster-management +spec: --- -# Source: pattern-clustergroup/templates/imperative/namespace.yaml +# Source: pattern-clustergroup/templates/core/namespaces.yaml apiVersion: v1 kind: Namespace metadata: labels: - name: imperative + name: pattern argocd.argoproj.io/managed-by: mypattern-example - name: imperative + name: application-ci +spec: --- -# Source: pattern-clustergroup/templates/namespaces.yaml +# Source: pattern-clustergroup/templates/imperative/namespace.yaml apiVersion: v1 kind: Namespace metadata: labels: - name: pattern + name: imperative argocd.argoproj.io/managed-by: mypattern-example - name: open-cluster-management -spec: + name: imperative --- -# Source: pattern-clustergroup/templates/namespaces.yaml +# Source: pattern-clustergroup/templates/plumbing/gitops-namespace.yaml apiVersion: v1 kind: Namespace metadata: labels: - name: pattern - argocd.argoproj.io/managed-by: mypattern-example - name: application-ci -spec: + name: mypattern-example + # The name here needs to be consistent with + # - acm/templates/policies/application-policies.yaml + # - clustergroup/templates/applications.yaml + # - any references to secrets and route URLs in documentation + name: mypattern-example +spec: {} --- # Source: pattern-clustergroup/templates/imperative/serviceaccount.yaml apiVersion: v1 @@ -52,7 +52,7 @@ metadata: apiVersion: v1 kind: ConfigMap metadata: - name: helm-values-configmap + name: helm-values-configmap-example namespace: imperative data: values.yaml: | @@ -68,18 +68,11 @@ data: namespace: open-cluster-management path: common/acm project: datacenter - external: - clusterName: example - name: external-app - namespace: demo - project: datacenter pipe: name: pipelines namespace: application-ci path: charts/datacenter/pipelines project: datacenter - externalClusters: - - example imperative: activeDeadlineSeconds: 3600 clusterRoleName: imperative-cluster-role @@ -103,17 +96,55 @@ data: insecureUnsealVaultInsideCluster: true isHubCluster: true managedClusterGroups: - - clusterSelector: - matchExpressions: - - key: vendor - operator: In - values: - - OpenShift + - acmlabels: + - name: clusterGroup + value: acm-region + helmOverrides: + - name: clusterGroup.isHubCluster + value: "false" + name: acm-edge + targetRevision: main + - acmlabels: + - name: clusterGroup + value: region + clusterPools: + exampleAWSPool: + baseDomain: blueprints.rhecoeng.com + clusters: + - One + name: aws-ap + openshiftVersion: 4.10.18 + platform: + aws: + region: ap-southeast-2 + size: 3 + exampleAzurePool: + baseDomain: blueprints.rhecoeng.com + clusters: + - Two + - Three + name: azure-us + openshiftVersion: 4.10.18 + platform: + azure: + baseDomainResourceGroupName: dojo-dns-zones + region: eastus helmOverrides: - name: clusterGroup.isHubCluster value: "false" - name: edge + name: acm-provision-edge targetRevision: main + - helmOverrides: + - name: clusterGroup.isHubCluster + value: "false" + hostedArgoSites: + - bearerKeyPath: secret/data/hub/cluster_perth + caKeyPath: secret/data/hub/cluster_perth_ca + domain: perth1.beekhof.net + name: perth + - domain: syd.beekhof.net + name: sydney + name: argo-edge name: example namespaces: - open-cluster-management @@ -134,16 +165,19 @@ data: pipelines: csv: redhat-openshift-pipelines.v1.5.2 name: openshift-pipelines-operator-rh + targetCluster: in-cluster + enabled: all files: cluster_example_ca: /path/to/ca.file global: + clusterDomain: region.example.com git: account: hybrid-cloud-patterns dev_revision: main email: someone@somewhere.com hostname: github.com - hubClusterDomain: hub.example.com - localClusterDomain: region.example.com + hubClusterDomain: apps.hub.example.com + localClusterDomain: apps.region.example.com namespace: pattern-namespace options: installPlanApproval: Automatic @@ -151,6 +185,7 @@ data: useCSV: false pattern: mypattern repoURL: https://github.com/pattern-clone/mypattern + targetRevision: main main: clusterGroupName: example git: @@ -189,7 +224,21 @@ rules: - list - watch --- -# Source: pattern-clustergroup/templates/argocd-super-role.yaml +# Source: pattern-clustergroup/templates/imperative/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: imperative-cluster-admin-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: imperative-cluster-role +subjects: + - kind: ServiceAccount + name: imperative-sa + namespace: imperative +--- +# Source: pattern-clustergroup/templates/plumbing/argocd-super-role.yaml # WARNING: ONLY USE THIS FOR MANAGING CLUSTERS NOT FOR REGULAR USERS apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding @@ -208,7 +257,7 @@ subjects: name: openshift-gitops-argocd-server namespace: openshift-gitops --- -# Source: pattern-clustergroup/templates/argocd-super-role.yaml +# Source: pattern-clustergroup/templates/plumbing/argocd-super-role.yaml # WARNING: ONLY USE THIS FOR MANAGING CLUSTERS NOT FOR REGULAR USERS apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding @@ -233,20 +282,6 @@ subjects: name: example-gitops-argocd-dex-server namespace: mypattern-example --- -# Source: pattern-clustergroup/templates/imperative/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: imperative-cluster-admin-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: imperative-cluster-role -subjects: - - kind: ServiceAccount - name: imperative-sa - namespace: imperative ---- # Source: pattern-clustergroup/templates/imperative/role.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: Role @@ -306,7 +341,7 @@ spec: command: - 'sh' - '-c' - - "mkdir /git/{repo,home};git clone --single-branch --branch --depth 1 -- https://github.com/pattern-clone/mypattern /git/repo;chmod 0770 /git/{repo,home}" + - "mkdir /git/{repo,home};git clone --single-branch --branch main --depth 1 -- https://github.com/pattern-clone/mypattern /git/repo;chmod 0770 /git/{repo,home}" volumeMounts: - name: git mountPath: "/git" @@ -347,7 +382,7 @@ spec: emptyDir: {} - name: values-volume configMap: - name: helm-values-configmap + name: helm-values-configmap-example restartPolicy: Never --- # Source: pattern-clustergroup/templates/imperative/unsealjob.yaml @@ -380,7 +415,7 @@ spec: command: - 'sh' - '-c' - - "mkdir /git/{repo,home};git clone --single-branch --branch --depth 1 -- https://github.com/pattern-clone/mypattern /git/repo;chmod 0770 /git/{repo,home}" + - "mkdir /git/{repo,home};git clone --single-branch --branch main --depth 1 -- https://github.com/pattern-clone/mypattern /git/repo;chmod 0770 /git/{repo,home}" volumeMounts: - name: git mountPath: "/git" @@ -425,13 +460,34 @@ spec: emptyDir: {} - name: values-volume configMap: - name: helm-values-configmap + name: helm-values-configmap-example restartPolicy: Never --- -# Source: pattern-clustergroup/templates/subscriptions.yaml +# Source: pattern-clustergroup/templates/core/subscriptions.yaml +--- --- +# Source: pattern-clustergroup/templates/plumbing/hosted-sites.yaml +apiVersion: argoproj.io/v1alpha1 +kind: AppProject +metadata: + name: argo-edge + namespace: openshift-gitops +spec: + description: "Cluster Group argo-edge" + destinations: + - namespace: '*' + server: '*' + clusterResourceWhitelist: + - group: '*' + kind: '*' + namespaceResourceWhitelist: + - group: '*' + kind: '*' + sourceRepos: + - '*' +status: {} --- -# Source: pattern-clustergroup/templates/projects.yaml +# Source: pattern-clustergroup/templates/plumbing/projects.yaml apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: @@ -452,7 +508,7 @@ spec: - '*' status: {} --- -# Source: pattern-clustergroup/templates/applications.yaml +# Source: pattern-clustergroup/templates/plumbing/applications.yaml apiVersion: argoproj.io/v1alpha1 kind: Application metadata: @@ -467,7 +523,7 @@ spec: project: datacenter source: repoURL: https://github.com/pattern-clone/mypattern - targetRevision: + targetRevision: main path: common/acm helm: ignoreMissingValueFiles: true @@ -484,10 +540,12 @@ spec: value: $ARGOCD_APP_NAMESPACE - name: global.pattern value: mypattern + - name: global.clusterDomain + value: region.example.com - name: global.hubClusterDomain - value: hub.example.com + value: apps.hub.example.com - name: global.localClusterDomain - value: region.example.com + value: apps.region.example.com ignoreDifferences: [ { "group": "internal.open-cluster-management.io", @@ -501,23 +559,23 @@ spec: automated: {} # selfHeal: true --- -# Source: pattern-clustergroup/templates/applications.yaml +# Source: pattern-clustergroup/templates/plumbing/applications.yaml apiVersion: argoproj.io/v1alpha1 kind: Application metadata: - name: external-app + name: pipelines namespace: mypattern-example finalizers: - resources-finalizer.argocd.argoproj.io/foreground spec: destination: - name: example - namespace: demo + name: in-cluster + namespace: application-ci project: datacenter source: repoURL: https://github.com/pattern-clone/mypattern - targetRevision: - path: + targetRevision: main + path: charts/datacenter/pipelines helm: ignoreMissingValueFiles: true valueFiles: @@ -533,55 +591,265 @@ spec: value: $ARGOCD_APP_NAMESPACE - name: global.pattern value: mypattern + - name: global.clusterDomain + value: region.example.com - name: global.hubClusterDomain - value: hub.example.com + value: apps.hub.example.com - name: global.localClusterDomain - value: region.example.com + value: apps.region.example.com syncPolicy: automated: {} # selfHeal: true --- -# Source: pattern-clustergroup/templates/applications.yaml +# Source: pattern-clustergroup/templates/plumbing/hosted-sites.yaml apiVersion: argoproj.io/v1alpha1 kind: Application metadata: - name: pipelines - namespace: mypattern-example + name: mypattern-argo-edge-perth + namespace: openshift-gitops finalizers: - resources-finalizer.argocd.argoproj.io/foreground spec: + project: argo-edge + source: + repoURL: https://github.com/pattern-clone/mypattern + targetRevision: main + path: common/clustergroup + helm: + ignoreMissingValueFiles: true + valueFiles: + - "/values-global.yaml" + - "/values-argo-edge.yaml" + parameters: + - name: global.repoURL + value: $ARGOCD_APP_SOURCE_REPO_URL + - name: global.targetRevision + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + - name: global.namespace + value: $ARGOCD_APP_NAMESPACE + - name: global.pattern + value: mypattern + - name: global.hubClusterDomain + value: apps.hub.example.com + - name: global.localClusterDomain + value: apps.perth1.beekhof.net + - name: global.clusterDomain + value: perth1.beekhof.net + - name: enabled + value: core + - name: clusterGroup.name + value: argo-edge + - name: clusterGroup.targetCluster + value: perth + - name: clusterGroup.hostedSite.bearerKeyPath + value: secret/data/hub/cluster_perth + - name: clusterGroup.hostedSite.caKeyPath + value: secret/data/hub/cluster_perth_ca + - name: clusterGroup.isHubCluster + value: "false" + destination: + name: perth + namespace: mypattern-argo-edge + syncPolicy: + automated: + selfHeal: true + ignoreDifferences: + - group: apps + kind: Deployment + jsonPointers: + - /spec/replicas + - group: route.openshift.io + kind: Route + jsonPointers: + - /status +--- +# Source: pattern-clustergroup/templates/plumbing/hosted-sites.yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: mypattern-argo-edge-perth-plumbing + namespace: openshift-gitops + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground +spec: + project: argo-edge + source: + repoURL: https://github.com/pattern-clone/mypattern + targetRevision: main + path: common/clustergroup + helm: + ignoreMissingValueFiles: true + valueFiles: + - "/values-global.yaml" + - "/values-argo-edge.yaml" + parameters: + - name: global.repoURL + value: $ARGOCD_APP_SOURCE_REPO_URL + - name: global.targetRevision + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + - name: global.namespace + value: $ARGOCD_APP_NAMESPACE + - name: global.pattern + value: mypattern + - name: global.hubClusterDomain + value: apps.hub.example.com + - name: global.localClusterDomain + value: apps.perth1.beekhof.net + - name: global.clusterDomain + value: perth1.beekhof.net + - name: enabled + value: plumbing + - name: clusterGroup.name + value: argo-edge + - name: clusterGroup.targetCluster + value: perth + - name: clusterGroup.hostedSite.bearerKeyPath + value: secret/data/hub/cluster_perth + - name: clusterGroup.hostedSite.caKeyPath + value: secret/data/hub/cluster_perth_ca + - name: clusterGroup.isHubCluster + value: "false" destination: name: in-cluster - namespace: application-ci - project: datacenter + namespace: openshift-gitops + syncPolicy: + automated: + selfHeal: true + ignoreDifferences: + - group: apps + kind: Deployment + jsonPointers: + - /spec/replicas + - group: route.openshift.io + kind: Route + jsonPointers: + - /status +--- +# Source: pattern-clustergroup/templates/plumbing/hosted-sites.yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: mypattern-argo-edge-sydney + namespace: openshift-gitops + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground +spec: + project: argo-edge source: repoURL: https://github.com/pattern-clone/mypattern - targetRevision: - path: charts/datacenter/pipelines + targetRevision: main + path: common/clustergroup helm: ignoreMissingValueFiles: true valueFiles: - "/values-global.yaml" - - "/values-example.yaml" - # Watch the progress of https://issues.redhat.com/browse/GITOPS-891 and update accordingly + - "/values-argo-edge.yaml" parameters: - - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL - - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION - - name: global.namespace - value: $ARGOCD_APP_NAMESPACE - - name: global.pattern - value: mypattern - - name: global.hubClusterDomain - value: hub.example.com - - name: global.localClusterDomain - value: region.example.com + - name: global.repoURL + value: $ARGOCD_APP_SOURCE_REPO_URL + - name: global.targetRevision + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + - name: global.namespace + value: $ARGOCD_APP_NAMESPACE + - name: global.pattern + value: mypattern + - name: global.hubClusterDomain + value: apps.hub.example.com + - name: global.localClusterDomain + value: apps.syd.beekhof.net + - name: global.clusterDomain + value: syd.beekhof.net + - name: enabled + value: core + - name: clusterGroup.name + value: argo-edge + - name: clusterGroup.targetCluster + value: sydney + - name: clusterGroup.hostedSite.bearerKeyPath + value: secret/data/hub/cluster_sydney + - name: clusterGroup.hostedSite.caKeyPath + value: secret/data/hub/cluster_sydney_ca + - name: clusterGroup.isHubCluster + value: "false" + destination: + name: sydney + namespace: mypattern-argo-edge syncPolicy: - automated: {} - # selfHeal: true + automated: + selfHeal: true + ignoreDifferences: + - group: apps + kind: Deployment + jsonPointers: + - /spec/replicas + - group: route.openshift.io + kind: Route + jsonPointers: + - /status +--- +# Source: pattern-clustergroup/templates/plumbing/hosted-sites.yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: mypattern-argo-edge-sydney-plumbing + namespace: openshift-gitops + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground +spec: + project: argo-edge + source: + repoURL: https://github.com/pattern-clone/mypattern + targetRevision: main + path: common/clustergroup + helm: + ignoreMissingValueFiles: true + valueFiles: + - "/values-global.yaml" + - "/values-argo-edge.yaml" + parameters: + - name: global.repoURL + value: $ARGOCD_APP_SOURCE_REPO_URL + - name: global.targetRevision + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + - name: global.namespace + value: $ARGOCD_APP_NAMESPACE + - name: global.pattern + value: mypattern + - name: global.hubClusterDomain + value: apps.hub.example.com + - name: global.localClusterDomain + value: apps.syd.beekhof.net + - name: global.clusterDomain + value: syd.beekhof.net + - name: enabled + value: plumbing + - name: clusterGroup.name + value: argo-edge + - name: clusterGroup.targetCluster + value: sydney + - name: clusterGroup.hostedSite.bearerKeyPath + value: secret/data/hub/cluster_sydney + - name: clusterGroup.hostedSite.caKeyPath + value: secret/data/hub/cluster_sydney_ca + - name: clusterGroup.isHubCluster + value: "false" + destination: + name: in-cluster + namespace: openshift-gitops + syncPolicy: + automated: + selfHeal: true + ignoreDifferences: + - group: apps + kind: Deployment + jsonPointers: + - /spec/replicas + - group: route.openshift.io + kind: Route + jsonPointers: + - /status --- -# Source: pattern-clustergroup/templates/argocd.yaml +# Source: pattern-clustergroup/templates/plumbing/argocd.yaml apiVersion: argoproj.io/v1alpha1 kind: ArgoCD metadata: @@ -620,8 +888,10 @@ spec: --set global.targetRevision=$ARGOCD_APP_SOURCE_TARGET_REVISION --set global.namespace=$ARGOCD_APP_NAMESPACE --set global.pattern=mypattern - --set global.hubClusterDomain=hub.example.com - --set global.localClusterDomain=region.example.com + --set global.clusterDomain=region.example.com + --set global.hubClusterDomain=apps.hub.example.com + --set global.localClusterDomain=apps.region.example.com + --set clusterGroup.name=example --post-renderer ./kustomize"] applicationSet: resources: @@ -692,7 +962,7 @@ spec: ca: {} status: --- -# Source: pattern-clustergroup/templates/argocd.yaml +# Source: pattern-clustergroup/templates/plumbing/argocd.yaml apiVersion: console.openshift.io/v1 kind: ConsoleLink metadata: @@ -702,58 +972,11 @@ spec: applicationMenu: section: OpenShift GitOps imageURL: data:image/png;base64,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 - href: 'https://example-gitops-server-mypattern-example.region.example.com' + href: 'https://example-gitops-server-mypattern-example.apps.region.example.com' location: ApplicationMenu text: 'Example ArgoCD' --- -# Source: pattern-clustergroup/templates/cluster-external-secrets.yaml -apiVersion: "external-secrets.io/v1beta1" -kind: ExternalSecret -metadata: - name: example-secret - namespace: mypattern-example - annotations: - argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true - argocd.argoproj.io/sync-wave: "100" -spec: - refreshInterval: 15s - secretStoreRef: - name: vault-backend - kind: ClusterSecretStore - target: - name: example-secret - template: - type: Opaque - metadata: - labels: - argocd.argoproj.io/secret-type: cluster - data: - name: example - server: |- - {{ .kubeServer | toString }} - config: | - { - "bearerToken": {{ .kubeBearer | toString | quote }}, - "tlsClientConfig": { - "insecure": false, - "caData": {{ .kubeCA | toString | quote }} - } - } - data: - - secretKey: kubeServer - remoteRef: - key: secret/data/hub/cluster_example - property: server - - secretKey: kubeBearer - remoteRef: - key: secret/data/hub/cluster_example - property: bearerToken - - secretKey: kubeCA - remoteRef: - key: secret/data/hub/cluster_example_ca - property: b64content ---- -# Source: pattern-clustergroup/templates/operatorgroup.yaml +# Source: pattern-clustergroup/templates/core/operatorgroup.yaml apiVersion: operators.coreos.com/v1 kind: OperatorGroup metadata: @@ -763,7 +986,7 @@ spec: targetNamespaces: - open-cluster-management --- -# Source: pattern-clustergroup/templates/operatorgroup.yaml +# Source: pattern-clustergroup/templates/core/operatorgroup.yaml apiVersion: operators.coreos.com/v1 kind: OperatorGroup metadata: @@ -773,7 +996,7 @@ spec: targetNamespaces: - application-ci --- -# Source: pattern-clustergroup/templates/subscriptions.yaml +# Source: pattern-clustergroup/templates/core/subscriptions.yaml apiVersion: operators.coreos.com/v1alpha1 kind: Subscription metadata: @@ -787,7 +1010,7 @@ spec: installPlanApproval: Automatic startingCSV: advanced-cluster-management.v2.4.1 --- -# Source: pattern-clustergroup/templates/subscriptions.yaml +# Source: pattern-clustergroup/templates/core/subscriptions.yaml apiVersion: operators.coreos.com/v1alpha1 kind: Subscription metadata: diff --git a/common/tests/clustergroup.expected.diff b/common/tests/clustergroup.expected.diff new file mode 100644 index 00000000..b1bb3239 --- /dev/null +++ b/common/tests/clustergroup.expected.diff @@ -0,0 +1,930 @@ +--- tests/clustergroup-naked.expected.yml ++++ tests/clustergroup-normal.expected.yml +@@ -1,17 +1,243 @@ + --- ++# Source: pattern-clustergroup/templates/core/namespaces.yaml ++apiVersion: v1 ++kind: Namespace ++metadata: ++ labels: ++ name: pattern ++ argocd.argoproj.io/managed-by: mypattern-example ++ name: open-cluster-management ++spec: ++--- ++# Source: pattern-clustergroup/templates/core/namespaces.yaml ++apiVersion: v1 ++kind: Namespace ++metadata: ++ labels: ++ name: pattern ++ argocd.argoproj.io/managed-by: mypattern-example ++ name: application-ci ++spec: ++--- ++# Source: pattern-clustergroup/templates/imperative/namespace.yaml ++apiVersion: v1 ++kind: Namespace ++metadata: ++ labels: ++ name: imperative ++ argocd.argoproj.io/managed-by: mypattern-example ++ name: imperative ++--- + # Source: pattern-clustergroup/templates/plumbing/gitops-namespace.yaml + apiVersion: v1 + kind: Namespace + metadata: + labels: +- name: common-example ++ name: mypattern-example + # The name here needs to be consistent with + # - acm/templates/policies/application-policies.yaml + # - clustergroup/templates/applications.yaml + # - any references to secrets and route URLs in documentation +- name: common-example ++ name: mypattern-example + spec: {} + --- ++# Source: pattern-clustergroup/templates/imperative/serviceaccount.yaml ++apiVersion: v1 ++kind: ServiceAccount ++metadata: ++ name: imperative-sa ++ namespace: imperative ++--- ++# Source: pattern-clustergroup/templates/imperative/configmap.yaml ++apiVersion: v1 ++kind: ConfigMap ++metadata: ++ name: helm-values-configmap-example ++ namespace: imperative ++data: ++ values.yaml: | ++ clusterGroup: ++ applications: ++ acm: ++ ignoreDifferences: ++ - group: internal.open-cluster-management.io ++ jsonPointers: ++ - /spec/loggingCA ++ kind: ManagedClusterInfo ++ name: acm ++ namespace: open-cluster-management ++ path: common/acm ++ project: datacenter ++ pipe: ++ name: pipelines ++ namespace: application-ci ++ path: charts/datacenter/pipelines ++ project: datacenter ++ imperative: ++ activeDeadlineSeconds: 3600 ++ clusterRoleName: imperative-cluster-role ++ clusterRoleYaml: "" ++ cronJobName: imperative-cronjob ++ image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest ++ imagePullPolicy: Always ++ insecureUnsealVaultInsideClusterSchedule: '*/5 * * * *' ++ jobName: imperative-job ++ jobs: ++ - name: test ++ playbook: ansible/test.yml ++ namespace: imperative ++ roleName: imperative-role ++ roleYaml: "" ++ schedule: '*/10 * * * *' ++ serviceAccountCreate: true ++ serviceAccountName: imperative-sa ++ valuesConfigMap: helm-values-configmap ++ verbosity: "" ++ insecureUnsealVaultInsideCluster: true ++ isHubCluster: true ++ managedClusterGroups: ++ - acmlabels: ++ - name: clusterGroup ++ value: acm-region ++ helmOverrides: ++ - name: clusterGroup.isHubCluster ++ value: "false" ++ name: acm-edge ++ targetRevision: main ++ - acmlabels: ++ - name: clusterGroup ++ value: region ++ clusterPools: ++ exampleAWSPool: ++ baseDomain: blueprints.rhecoeng.com ++ clusters: ++ - One ++ name: aws-ap ++ openshiftVersion: 4.10.18 ++ platform: ++ aws: ++ region: ap-southeast-2 ++ size: 3 ++ exampleAzurePool: ++ baseDomain: blueprints.rhecoeng.com ++ clusters: ++ - Two ++ - Three ++ name: azure-us ++ openshiftVersion: 4.10.18 ++ platform: ++ azure: ++ baseDomainResourceGroupName: dojo-dns-zones ++ region: eastus ++ helmOverrides: ++ - name: clusterGroup.isHubCluster ++ value: "false" ++ name: acm-provision-edge ++ targetRevision: main ++ - helmOverrides: ++ - name: clusterGroup.isHubCluster ++ value: "false" ++ hostedArgoSites: ++ - bearerKeyPath: secret/data/hub/cluster_perth ++ caKeyPath: secret/data/hub/cluster_perth_ca ++ domain: perth1.beekhof.net ++ name: perth ++ - domain: syd.beekhof.net ++ name: sydney ++ name: argo-edge ++ name: example ++ namespaces: ++ - open-cluster-management ++ - application-ci ++ projects: ++ - datacenter ++ subscriptions: ++ acm: ++ channel: release-2.4 ++ csv: advanced-cluster-management.v2.4.1 ++ name: advanced-cluster-management ++ namespace: open-cluster-management ++ odh: ++ csv: opendatahub-operator.v1.1.0 ++ disabled: true ++ name: opendatahub-operator ++ source: community-operators ++ pipelines: ++ csv: redhat-openshift-pipelines.v1.5.2 ++ name: openshift-pipelines-operator-rh ++ targetCluster: in-cluster ++ enabled: all ++ files: ++ cluster_example_ca: /path/to/ca.file ++ global: ++ clusterDomain: region.example.com ++ git: ++ account: hybrid-cloud-patterns ++ dev_revision: main ++ email: someone@somewhere.com ++ hostname: github.com ++ hubClusterDomain: apps.hub.example.com ++ localClusterDomain: apps.region.example.com ++ namespace: pattern-namespace ++ options: ++ installPlanApproval: Automatic ++ syncPolicy: Automatic ++ useCSV: false ++ pattern: mypattern ++ repoURL: https://github.com/pattern-clone/mypattern ++ targetRevision: main ++ main: ++ clusterGroupName: example ++ git: ++ repoURL: https://github.com/pattern-clone/mypattern ++ revision: main ++ secretStore: ++ kind: ClusterSecretStore ++ name: vault-backend ++ secrets: ++ aws: ++ s3Secret: test-secret ++ cluster_example: ++ bearerToken: ++ server: https://api.example.openshiftapps.com:6443 ++ git: ++ token: test-git-token ++ username: test-user ++ imageregistry: ++ account: test-account ++ token: test-quay-token ++ secretsBase: ++ key: secret/data/hub ++--- ++# Source: pattern-clustergroup/templates/imperative/clusterrole.yaml ++apiVersion: rbac.authorization.k8s.io/v1 ++kind: ClusterRole ++metadata: ++ name: imperative-cluster-role ++rules: ++ - apiGroups: ++ - '*' ++ resources: ++ - '*' ++ verbs: ++ - get ++ - list ++ - watch ++--- ++# Source: pattern-clustergroup/templates/imperative/rbac.yaml ++apiVersion: rbac.authorization.k8s.io/v1 ++kind: ClusterRoleBinding ++metadata: ++ name: imperative-cluster-admin-rolebinding ++roleRef: ++ apiGroup: rbac.authorization.k8s.io ++ kind: ClusterRole ++ name: imperative-cluster-role ++subjects: ++ - kind: ServiceAccount ++ name: imperative-sa ++ namespace: imperative ++--- + # Source: pattern-clustergroup/templates/plumbing/argocd-super-role.yaml + # WARNING: ONLY USE THIS FOR MANAGING CLUSTERS NOT FOR REGULAR USERS + apiVersion: rbac.authorization.k8s.io/v1 +@@ -36,7 +262,7 @@ + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: +- name: common-example-cluster-admin-rolebinding ++ name: mypattern-example-cluster-admin-rolebinding + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole +@@ -45,16 +271,583 @@ + - kind: ServiceAccount + # This is the {ArgoCD.name}-argocd-application-controller + name: example-gitops-argocd-application-controller +- namespace: common-example ++ namespace: mypattern-example + # NOTE: THIS MUST BE FIXED FOR MULTITENANT SETUP + - kind: ServiceAccount + # This is the {ArgoCD.name}-argocd-server + name: example-gitops-argocd-server +- namespace: common-example ++ namespace: mypattern-example + # NOTE: This is needed starting with gitops-1.5.0 (see issue common#76) + - kind: ServiceAccount + name: example-gitops-argocd-dex-server +- namespace: common-example ++ namespace: mypattern-example ++--- ++# Source: pattern-clustergroup/templates/imperative/role.yaml ++apiVersion: rbac.authorization.k8s.io/v1 ++kind: Role ++metadata: ++ name: imperative-role ++ namespace: imperative ++rules: ++ - apiGroups: ++ - '*' ++ resources: ++ - '*' ++ verbs: ++ - '*' ++--- ++# Source: pattern-clustergroup/templates/imperative/rbac.yaml ++apiVersion: rbac.authorization.k8s.io/v1 ++kind: RoleBinding ++metadata: ++ name: imperative-admin-rolebinding ++ namespace: imperative ++roleRef: ++ apiGroup: rbac.authorization.k8s.io ++ kind: Role ++ name: imperative-role ++subjects: ++ - kind: ServiceAccount ++ name: imperative-sa ++ namespace: imperative ++--- ++# Source: pattern-clustergroup/templates/imperative/job.yaml ++apiVersion: batch/v1 ++kind: CronJob ++metadata: ++ name: imperative-cronjob ++ namespace: imperative ++spec: ++ schedule: "*/10 * * * *" ++ # if previous Job is still running, skip execution of a new Job ++ concurrencyPolicy: Forbid ++ jobTemplate: ++ spec: ++ activeDeadlineSeconds: 3600 ++ template: ++ metadata: ++ name: imperative-job ++ spec: ++ serviceAccountName: imperative-sa ++ initContainers: ++ # git init happens in /git/repo so that we can set the folder to 0770 permissions ++ # reason for that is ansible refuses to create temporary folders in there ++ - name: git-init ++ image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest ++ imagePullPolicy: Always ++ env: ++ - name: HOME ++ value: /git/home ++ command: ++ - 'sh' ++ - '-c' ++ - "mkdir /git/{repo,home};git clone --single-branch --branch main --depth 1 -- https://github.com/pattern-clone/mypattern /git/repo;chmod 0770 /git/{repo,home}" ++ volumeMounts: ++ - name: git ++ mountPath: "/git" ++ - name: test ++ image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest ++ imagePullPolicy: Always ++ env: ++ - name: HOME ++ value: /git/home ++ workingDir: /git/repo ++ # We have a default timeout of 600s for each playbook. Can be overridden ++ # on a per-job basis ++ command: ++ - timeout ++ - "600" ++ - ansible-playbook ++ - -e ++ - "@/values/values.yaml" ++ - ansible/test.yml ++ volumeMounts: ++ - name: git ++ mountPath: "/git" ++ - name: values-volume ++ mountPath: /values/values.yaml ++ subPath: values.yaml ++ containers: ++ - name: "done" ++ image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest ++ imagePullPolicy: Always ++ command: ++ - 'sh' ++ - '-c' ++ - 'echo' ++ - 'done' ++ - '\n' ++ volumes: ++ - name: git ++ emptyDir: {} ++ - name: values-volume ++ configMap: ++ name: helm-values-configmap-example ++ restartPolicy: Never ++--- ++# Source: pattern-clustergroup/templates/imperative/unsealjob.yaml ++apiVersion: batch/v1 ++kind: CronJob ++metadata: ++ name: unsealvault-cronjob ++ namespace: imperative ++spec: ++ schedule: "*/5 * * * *" ++ # if previous Job is still running, skip execution of a new Job ++ concurrencyPolicy: Forbid ++ jobTemplate: ++ spec: ++ activeDeadlineSeconds: 3600 ++ template: ++ metadata: ++ name: unsealvault-job ++ spec: ++ serviceAccountName: imperative-sa ++ initContainers: ++ # git init happens in /git/repo so that we can set the folder to 0770 permissions ++ # reason for that is ansible refuses to create temporary folders in there ++ - name: git-init ++ image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest ++ imagePullPolicy: Always ++ env: ++ - name: HOME ++ value: /git/home ++ command: ++ - 'sh' ++ - '-c' ++ - "mkdir /git/{repo,home};git clone --single-branch --branch main --depth 1 -- https://github.com/pattern-clone/mypattern /git/repo;chmod 0770 /git/{repo,home}" ++ volumeMounts: ++ - name: git ++ mountPath: "/git" ++ - name: unseal-playbook ++ image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest ++ imagePullPolicy: Always ++ env: ++ - name: HOME ++ value: /git/home ++ workingDir: /git/repo ++ # We have a default timeout of 600s for each playbook. Can be overridden ++ # on a per-job basis ++ command: ++ - timeout ++ - "600" ++ - ansible-playbook ++ - -e ++ - "@/values/values.yaml" ++ - -e ++ - '{"file_unseal": false}' ++ - -t ++ - 'vault_init,vault_unseal,vault_secrets_init' ++ - "common/ansible/playbooks/vault/vault.yaml" ++ volumeMounts: ++ - name: git ++ mountPath: "/git" ++ - name: values-volume ++ mountPath: /values/values.yaml ++ subPath: values.yaml ++ containers: ++ - name: "done" ++ image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest ++ imagePullPolicy: Always ++ command: ++ - 'sh' ++ - '-c' ++ - 'echo' ++ - 'done' ++ - '\n' ++ volumes: ++ - name: git ++ emptyDir: {} ++ - name: values-volume ++ configMap: ++ name: helm-values-configmap-example ++ restartPolicy: Never ++--- ++# Source: pattern-clustergroup/templates/core/subscriptions.yaml ++--- ++--- ++# Source: pattern-clustergroup/templates/plumbing/hosted-sites.yaml ++apiVersion: argoproj.io/v1alpha1 ++kind: AppProject ++metadata: ++ name: argo-edge ++ namespace: openshift-gitops ++spec: ++ description: "Cluster Group argo-edge" ++ destinations: ++ - namespace: '*' ++ server: '*' ++ clusterResourceWhitelist: ++ - group: '*' ++ kind: '*' ++ namespaceResourceWhitelist: ++ - group: '*' ++ kind: '*' ++ sourceRepos: ++ - '*' ++status: {} ++--- ++# Source: pattern-clustergroup/templates/plumbing/projects.yaml ++apiVersion: argoproj.io/v1alpha1 ++kind: AppProject ++metadata: ++ name: datacenter ++ namespace: mypattern-example ++spec: ++ description: "Pattern datacenter" ++ destinations: ++ - namespace: '*' ++ server: '*' ++ clusterResourceWhitelist: ++ - group: '*' ++ kind: '*' ++ namespaceResourceWhitelist: ++ - group: '*' ++ kind: '*' ++ sourceRepos: ++ - '*' ++status: {} ++--- ++# Source: pattern-clustergroup/templates/plumbing/applications.yaml ++apiVersion: argoproj.io/v1alpha1 ++kind: Application ++metadata: ++ name: acm ++ namespace: mypattern-example ++ finalizers: ++ - resources-finalizer.argocd.argoproj.io/foreground ++spec: ++ destination: ++ name: in-cluster ++ namespace: open-cluster-management ++ project: datacenter ++ source: ++ repoURL: https://github.com/pattern-clone/mypattern ++ targetRevision: main ++ path: common/acm ++ helm: ++ ignoreMissingValueFiles: true ++ valueFiles: ++ - "/values-global.yaml" ++ - "/values-example.yaml" ++ # Watch the progress of https://issues.redhat.com/browse/GITOPS-891 and update accordingly ++ parameters: ++ - name: global.repoURL ++ value: $ARGOCD_APP_SOURCE_REPO_URL ++ - name: global.targetRevision ++ value: $ARGOCD_APP_SOURCE_TARGET_REVISION ++ - name: global.namespace ++ value: $ARGOCD_APP_NAMESPACE ++ - name: global.pattern ++ value: mypattern ++ - name: global.clusterDomain ++ value: region.example.com ++ - name: global.hubClusterDomain ++ value: apps.hub.example.com ++ - name: global.localClusterDomain ++ value: apps.region.example.com ++ ignoreDifferences: [ ++ { ++ "group": "internal.open-cluster-management.io", ++ "jsonPointers": [ ++ "/spec/loggingCA" ++ ], ++ "kind": "ManagedClusterInfo" ++ } ++] ++ syncPolicy: ++ automated: {} ++ # selfHeal: true ++--- ++# Source: pattern-clustergroup/templates/plumbing/applications.yaml ++apiVersion: argoproj.io/v1alpha1 ++kind: Application ++metadata: ++ name: pipelines ++ namespace: mypattern-example ++ finalizers: ++ - resources-finalizer.argocd.argoproj.io/foreground ++spec: ++ destination: ++ name: in-cluster ++ namespace: application-ci ++ project: datacenter ++ source: ++ repoURL: https://github.com/pattern-clone/mypattern ++ targetRevision: main ++ path: charts/datacenter/pipelines ++ helm: ++ ignoreMissingValueFiles: true ++ valueFiles: ++ - "/values-global.yaml" ++ - "/values-example.yaml" ++ # Watch the progress of https://issues.redhat.com/browse/GITOPS-891 and update accordingly ++ parameters: ++ - name: global.repoURL ++ value: $ARGOCD_APP_SOURCE_REPO_URL ++ - name: global.targetRevision ++ value: $ARGOCD_APP_SOURCE_TARGET_REVISION ++ - name: global.namespace ++ value: $ARGOCD_APP_NAMESPACE ++ - name: global.pattern ++ value: mypattern ++ - name: global.clusterDomain ++ value: region.example.com ++ - name: global.hubClusterDomain ++ value: apps.hub.example.com ++ - name: global.localClusterDomain ++ value: apps.region.example.com ++ syncPolicy: ++ automated: {} ++ # selfHeal: true ++--- ++# Source: pattern-clustergroup/templates/plumbing/hosted-sites.yaml ++apiVersion: argoproj.io/v1alpha1 ++kind: Application ++metadata: ++ name: mypattern-argo-edge-perth ++ namespace: openshift-gitops ++ finalizers: ++ - resources-finalizer.argocd.argoproj.io/foreground ++spec: ++ project: argo-edge ++ source: ++ repoURL: https://github.com/pattern-clone/mypattern ++ targetRevision: main ++ path: common/clustergroup ++ helm: ++ ignoreMissingValueFiles: true ++ valueFiles: ++ - "/values-global.yaml" ++ - "/values-argo-edge.yaml" ++ parameters: ++ - name: global.repoURL ++ value: $ARGOCD_APP_SOURCE_REPO_URL ++ - name: global.targetRevision ++ value: $ARGOCD_APP_SOURCE_TARGET_REVISION ++ - name: global.namespace ++ value: $ARGOCD_APP_NAMESPACE ++ - name: global.pattern ++ value: mypattern ++ - name: global.hubClusterDomain ++ value: apps.hub.example.com ++ - name: global.localClusterDomain ++ value: apps.perth1.beekhof.net ++ - name: global.clusterDomain ++ value: perth1.beekhof.net ++ - name: enabled ++ value: core ++ - name: clusterGroup.name ++ value: argo-edge ++ - name: clusterGroup.targetCluster ++ value: perth ++ - name: clusterGroup.hostedSite.bearerKeyPath ++ value: secret/data/hub/cluster_perth ++ - name: clusterGroup.hostedSite.caKeyPath ++ value: secret/data/hub/cluster_perth_ca ++ - name: clusterGroup.isHubCluster ++ value: "false" ++ destination: ++ name: perth ++ namespace: mypattern-argo-edge ++ syncPolicy: ++ automated: ++ selfHeal: true ++ ignoreDifferences: ++ - group: apps ++ kind: Deployment ++ jsonPointers: ++ - /spec/replicas ++ - group: route.openshift.io ++ kind: Route ++ jsonPointers: ++ - /status ++--- ++# Source: pattern-clustergroup/templates/plumbing/hosted-sites.yaml ++apiVersion: argoproj.io/v1alpha1 ++kind: Application ++metadata: ++ name: mypattern-argo-edge-perth-plumbing ++ namespace: openshift-gitops ++ finalizers: ++ - resources-finalizer.argocd.argoproj.io/foreground ++spec: ++ project: argo-edge ++ source: ++ repoURL: https://github.com/pattern-clone/mypattern ++ targetRevision: main ++ path: common/clustergroup ++ helm: ++ ignoreMissingValueFiles: true ++ valueFiles: ++ - "/values-global.yaml" ++ - "/values-argo-edge.yaml" ++ parameters: ++ - name: global.repoURL ++ value: $ARGOCD_APP_SOURCE_REPO_URL ++ - name: global.targetRevision ++ value: $ARGOCD_APP_SOURCE_TARGET_REVISION ++ - name: global.namespace ++ value: $ARGOCD_APP_NAMESPACE ++ - name: global.pattern ++ value: mypattern ++ - name: global.hubClusterDomain ++ value: apps.hub.example.com ++ - name: global.localClusterDomain ++ value: apps.perth1.beekhof.net ++ - name: global.clusterDomain ++ value: perth1.beekhof.net ++ - name: enabled ++ value: plumbing ++ - name: clusterGroup.name ++ value: argo-edge ++ - name: clusterGroup.targetCluster ++ value: perth ++ - name: clusterGroup.hostedSite.bearerKeyPath ++ value: secret/data/hub/cluster_perth ++ - name: clusterGroup.hostedSite.caKeyPath ++ value: secret/data/hub/cluster_perth_ca ++ - name: clusterGroup.isHubCluster ++ value: "false" ++ destination: ++ name: in-cluster ++ namespace: openshift-gitops ++ syncPolicy: ++ automated: ++ selfHeal: true ++ ignoreDifferences: ++ - group: apps ++ kind: Deployment ++ jsonPointers: ++ - /spec/replicas ++ - group: route.openshift.io ++ kind: Route ++ jsonPointers: ++ - /status ++--- ++# Source: pattern-clustergroup/templates/plumbing/hosted-sites.yaml ++apiVersion: argoproj.io/v1alpha1 ++kind: Application ++metadata: ++ name: mypattern-argo-edge-sydney ++ namespace: openshift-gitops ++ finalizers: ++ - resources-finalizer.argocd.argoproj.io/foreground ++spec: ++ project: argo-edge ++ source: ++ repoURL: https://github.com/pattern-clone/mypattern ++ targetRevision: main ++ path: common/clustergroup ++ helm: ++ ignoreMissingValueFiles: true ++ valueFiles: ++ - "/values-global.yaml" ++ - "/values-argo-edge.yaml" ++ parameters: ++ - name: global.repoURL ++ value: $ARGOCD_APP_SOURCE_REPO_URL ++ - name: global.targetRevision ++ value: $ARGOCD_APP_SOURCE_TARGET_REVISION ++ - name: global.namespace ++ value: $ARGOCD_APP_NAMESPACE ++ - name: global.pattern ++ value: mypattern ++ - name: global.hubClusterDomain ++ value: apps.hub.example.com ++ - name: global.localClusterDomain ++ value: apps.syd.beekhof.net ++ - name: global.clusterDomain ++ value: syd.beekhof.net ++ - name: enabled ++ value: core ++ - name: clusterGroup.name ++ value: argo-edge ++ - name: clusterGroup.targetCluster ++ value: sydney ++ - name: clusterGroup.hostedSite.bearerKeyPath ++ value: secret/data/hub/cluster_sydney ++ - name: clusterGroup.hostedSite.caKeyPath ++ value: secret/data/hub/cluster_sydney_ca ++ - name: clusterGroup.isHubCluster ++ value: "false" ++ destination: ++ name: sydney ++ namespace: mypattern-argo-edge ++ syncPolicy: ++ automated: ++ selfHeal: true ++ ignoreDifferences: ++ - group: apps ++ kind: Deployment ++ jsonPointers: ++ - /spec/replicas ++ - group: route.openshift.io ++ kind: Route ++ jsonPointers: ++ - /status ++--- ++# Source: pattern-clustergroup/templates/plumbing/hosted-sites.yaml ++apiVersion: argoproj.io/v1alpha1 ++kind: Application ++metadata: ++ name: mypattern-argo-edge-sydney-plumbing ++ namespace: openshift-gitops ++ finalizers: ++ - resources-finalizer.argocd.argoproj.io/foreground ++spec: ++ project: argo-edge ++ source: ++ repoURL: https://github.com/pattern-clone/mypattern ++ targetRevision: main ++ path: common/clustergroup ++ helm: ++ ignoreMissingValueFiles: true ++ valueFiles: ++ - "/values-global.yaml" ++ - "/values-argo-edge.yaml" ++ parameters: ++ - name: global.repoURL ++ value: $ARGOCD_APP_SOURCE_REPO_URL ++ - name: global.targetRevision ++ value: $ARGOCD_APP_SOURCE_TARGET_REVISION ++ - name: global.namespace ++ value: $ARGOCD_APP_NAMESPACE ++ - name: global.pattern ++ value: mypattern ++ - name: global.hubClusterDomain ++ value: apps.hub.example.com ++ - name: global.localClusterDomain ++ value: apps.syd.beekhof.net ++ - name: global.clusterDomain ++ value: syd.beekhof.net ++ - name: enabled ++ value: plumbing ++ - name: clusterGroup.name ++ value: argo-edge ++ - name: clusterGroup.targetCluster ++ value: sydney ++ - name: clusterGroup.hostedSite.bearerKeyPath ++ value: secret/data/hub/cluster_sydney ++ - name: clusterGroup.hostedSite.caKeyPath ++ value: secret/data/hub/cluster_sydney_ca ++ - name: clusterGroup.isHubCluster ++ value: "false" ++ destination: ++ name: in-cluster ++ namespace: openshift-gitops ++ syncPolicy: ++ automated: ++ selfHeal: true ++ ignoreDifferences: ++ - group: apps ++ kind: Deployment ++ jsonPointers: ++ - /spec/replicas ++ - group: route.openshift.io ++ kind: Route ++ jsonPointers: ++ - /status + --- + # Source: pattern-clustergroup/templates/plumbing/argocd.yaml + apiVersion: argoproj.io/v1alpha1 +@@ -65,7 +858,7 @@ + # Changing the name affects the ClusterRoleBinding, the generated secret, + # route URL, and argocd.argoproj.io/managed-by annotations + name: example-gitops +- namespace: common-example ++ namespace: mypattern-example + annotations: + argocd.argoproj.io/compare-options: IgnoreExtraneous + spec: +@@ -94,10 +887,10 @@ + --set global.repoURL=$ARGOCD_APP_SOURCE_REPO_URL + --set global.targetRevision=$ARGOCD_APP_SOURCE_TARGET_REVISION + --set global.namespace=$ARGOCD_APP_NAMESPACE +- --set global.pattern=common +- --set global.clusterDomain= +- --set global.hubClusterDomain= +- --set global.localClusterDomain= ++ --set global.pattern=mypattern ++ --set global.clusterDomain=region.example.com ++ --set global.hubClusterDomain=apps.hub.example.com ++ --set global.localClusterDomain=apps.region.example.com + --set clusterGroup.name=example + --post-renderer ./kustomize"] + applicationSet: +@@ -174,11 +967,59 @@ + kind: ConsoleLink + metadata: + name: example-gitops-link +- namespace: common-example ++ namespace: mypattern-example + spec: + applicationMenu: + section: OpenShift GitOps + imageURL: data:image/png;base64,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 +- href: 'https://example-gitops-server-common-example.' ++ href: 'https://example-gitops-server-mypattern-example.apps.region.example.com' + location: ApplicationMenu + text: 'Example ArgoCD' ++--- ++# Source: pattern-clustergroup/templates/core/operatorgroup.yaml ++apiVersion: operators.coreos.com/v1 ++kind: OperatorGroup ++metadata: ++ name: open-cluster-management-operator-group ++ namespace: open-cluster-management ++spec: ++ targetNamespaces: ++ - open-cluster-management ++--- ++# Source: pattern-clustergroup/templates/core/operatorgroup.yaml ++apiVersion: operators.coreos.com/v1 ++kind: OperatorGroup ++metadata: ++ name: application-ci-operator-group ++ namespace: application-ci ++spec: ++ targetNamespaces: ++ - application-ci ++--- ++# Source: pattern-clustergroup/templates/core/subscriptions.yaml ++apiVersion: operators.coreos.com/v1alpha1 ++kind: Subscription ++metadata: ++ name: advanced-cluster-management ++ namespace: open-cluster-management ++spec: ++ name: advanced-cluster-management ++ source: redhat-operators ++ sourceNamespace: openshift-marketplace ++ channel: release-2.4 ++ installPlanApproval: Automatic ++ startingCSV: advanced-cluster-management.v2.4.1 ++--- ++# Source: pattern-clustergroup/templates/core/subscriptions.yaml ++apiVersion: operators.coreos.com/v1alpha1 ++kind: Subscription ++metadata: ++ name: openshift-pipelines-operator-rh ++ namespace: openshift-operators ++spec: ++ name: openshift-pipelines-operator-rh ++ source: redhat-operators ++ sourceNamespace: openshift-marketplace ++ channel: stable ++ installPlanApproval: Automatic ++ startingCSV: redhat-openshift-pipelines.v1.5.2 diff --git a/common/tests/examples-blank-naked.expected.yaml b/common/tests/examples-blank-naked.expected.yml similarity index 100% rename from common/tests/examples-blank-naked.expected.yaml rename to common/tests/examples-blank-naked.expected.yml diff --git a/common/tests/examples-blank-normal.expected.yaml b/common/tests/examples-blank-normal.expected.yml similarity index 100% rename from common/tests/examples-blank-normal.expected.yaml rename to common/tests/examples-blank-normal.expected.yml diff --git a/common/tests/examples-blank.expected.diff b/common/tests/examples-blank.expected.diff new file mode 100644 index 00000000..e69de29b diff --git a/common/tests/examples-kustomize-renderer-naked.expected.yaml b/common/tests/examples-kustomize-renderer-naked.expected.yml similarity index 100% rename from common/tests/examples-kustomize-renderer-naked.expected.yaml rename to common/tests/examples-kustomize-renderer-naked.expected.yml diff --git a/common/tests/examples-kustomize-renderer-normal.expected.yaml b/common/tests/examples-kustomize-renderer-normal.expected.yml similarity index 100% rename from common/tests/examples-kustomize-renderer-normal.expected.yaml rename to common/tests/examples-kustomize-renderer-normal.expected.yml diff --git a/common/tests/examples-kustomize-renderer.expected.diff b/common/tests/examples-kustomize-renderer.expected.diff new file mode 100644 index 00000000..cee20d02 --- /dev/null +++ b/common/tests/examples-kustomize-renderer.expected.diff @@ -0,0 +1,19 @@ +--- tests/examples-kustomize-renderer-naked.expected.yml ++++ tests/examples-kustomize-renderer-normal.expected.yml +@@ -7,12 +7,12 @@ + data: + IMAGE_PROVIDER: + IMAGE_ACCOUNT: PLAINTEXT +- GIT_EMAIL: SOMEWHERE@EXAMPLE.COM +- GIT_DEV_REPO_URL: https:///PLAINTEXT/manuela-dev.git ++ GIT_EMAIL: someone@somewhere.com ++ GIT_DEV_REPO_URL: https://github.com/hybrid-cloud-patterns/manuela-dev.git + GIT_DEV_REPO_REVISION: main +- GIT_OPS_REPO_TEST_URL: ++ GIT_OPS_REPO_TEST_URL: https://github.com/pattern-clone/mypattern + GIT_OPS_REPO_TEST_REVISION: +- GIT_OPS_REPO_PROD_URL: ++ GIT_OPS_REPO_PROD_URL: https://github.com/pattern-clone/mypattern + GIT_OPS_REPO_PROD_REVISION: + IOT_CONSUMER_IMAGE: iot-consumer + IOT_CONSUMER_YAML_PATH: images.(name==messaging).newTag diff --git a/common/tests/golang-external-secrets-naked.expected.yaml b/common/tests/golang-external-secrets-naked.expected.yml similarity index 100% rename from common/tests/golang-external-secrets-naked.expected.yaml rename to common/tests/golang-external-secrets-naked.expected.yml diff --git a/common/tests/golang-external-secrets-normal.expected.yaml b/common/tests/golang-external-secrets-normal.expected.yml similarity index 99% rename from common/tests/golang-external-secrets-normal.expected.yaml rename to common/tests/golang-external-secrets-normal.expected.yml index 7d9fa628..872b07de 100644 --- a/common/tests/golang-external-secrets-normal.expected.yaml +++ b/common/tests/golang-external-secrets-normal.expected.yml @@ -5827,7 +5827,7 @@ metadata: spec: provider: vault: - server: https://vault-vault.hub.example.com + server: https://vault-vault.apps.hub.example.com path: secret # Version of KV backend version: v2 diff --git a/common/tests/golang-external-secrets.expected.diff b/common/tests/golang-external-secrets.expected.diff new file mode 100644 index 00000000..299cd616 --- /dev/null +++ b/common/tests/golang-external-secrets.expected.diff @@ -0,0 +1,11 @@ +--- tests/golang-external-secrets-naked.expected.yml ++++ tests/golang-external-secrets-normal.expected.yml +@@ -5827,7 +5827,7 @@ + spec: + provider: + vault: +- server: https://vault-vault.hub.example.com ++ server: https://vault-vault.apps.hub.example.com + path: secret + # Version of KV backend + version: v2 diff --git a/common/tests/hashicorp-vault-naked.expected.yaml b/common/tests/hashicorp-vault-naked.expected.yml similarity index 100% rename from common/tests/hashicorp-vault-naked.expected.yaml rename to common/tests/hashicorp-vault-naked.expected.yml diff --git a/common/tests/hashicorp-vault-normal.expected.yaml b/common/tests/hashicorp-vault-normal.expected.yml similarity index 99% rename from common/tests/hashicorp-vault-normal.expected.yaml rename to common/tests/hashicorp-vault-normal.expected.yml index d2af3d1b..9d707c16 100644 --- a/common/tests/hashicorp-vault-normal.expected.yaml +++ b/common/tests/hashicorp-vault-normal.expected.yml @@ -340,7 +340,7 @@ spec: applicationMenu: section: HashiCorp Vault imageURL: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAf0AAAHhCAQAAADO0a/jAAAcYElEQVR42u2dB5hU5fWHzy5NmoBd7LH3WIIFFVS6goJRFBVjwYqKIhgbCFgQO2LBBoKKBQWFYIt/E2NHo4SABERAaui9LOzm/41DCLA7M7ffr7zv++Qxj48c7j3n++3Mztz7XZGh8h9EdMyhIodKGY1AdMoylXvFAFqB6JQD5Ff2lhKageiMJSrzG7mHdiA64z2yiZ1kFQ1BdMJVKu+b0Y2WIDphN9mCbWURTUG03kUq61txJW1BtN4rpRzVZBaNQbTaWSrnFdCe1iBabXupkEoymeYgWutklfEcNKc9iNbaXPLwHQ1CtNLvJC9NaRGilTaVAoykSYjWOVIKchxtQrTO48QDL9EoRKt8STxxiJTSLERrLFWZ9kh/2oVojf3FM3vKOhqGaIXrVJ590IeWIVphH/HFjrKSpiEa70qVZZ90pW2IxttVfFNbFtI4RKNdqHIcgCtoHaLRXiGBqCYzaR6isc6seGMOL5xL+xCN9VwJTLFMooGIRjpJ5TcEzWghopE2k5CMpYmIxjlWQnM6bUQ0ztMlAkbQSESjHCGR8DtaiWiUv5OIGEwzEY1xsETGQWzegWiIpSqvEfIYLUU0wsckUvZg8w5EA1ynshoxvWgrovb2ksjZQVbQWEStXaFyGgM301pErb1ZYqGWLKC5iNq6QGU0Ji6nvYjaernERlWZQYMRtXSGymeMnEOLEbX0HImVYplIkxG1c2K4jTm80IQ2I2pnE0mAr2k0olZ+LYlwKq1G1MpTJSHeotmI2viWJMYxtBtRG4+RBHmRhiNq4YuSKAfIBpqOmLobVBYT5lHajpi6j0ri7C5raTxiqq5VOUyBnrQeMVV7SipsJ8tpPmJqLlcZTIkutB8xNbtIatSU+QwAMRXnq/ylyKWMADEVL5VUqSLTGQJi4k5X2UuZdowBMXHbSeoUywQGgZioE+LfmMMLZzEKxEQ9SzThI4aBmJgfiTY0YhyIidlINGI4A0FMxOGiFUcxEsREPEo043mGghi7z4t27M/mHYgxu0HlTEMeZjSIsfqwaEl9WcNwEGNzjcqYpvRgPIix2UO0pZ4sY0CIsbhM5UtjbmREiLF4o2hNDZnHkBAjd57KluZcwpgQI/cS0Z4q8jODQozUn9PfmMMLZzMqxEg9W4ygSMYzLMTIHK8yZQitGRdiZLYWg/iAgSFG4gdiFCczMsRIPFkM4w2GhhjaN8Q4jpQyBocYyjKVIwN5jtEhhvI5MZJ9ZT3DQwzsepUhQ3mQ8SEG9kExll1lNQNEDORqlR+DuZMRIgbyTjGaurKEISL6donKjuFczxgRfXu9GE91mcsgEX05V+XGAjoySkRfdhQrqCxTGSaiZ6eqzFhCG8aJ6Nk2Yg1FMo6BInpynDkbc3ihFSNF9GQrsYz3GSpiQd8X62jIWBEL2lAs5DUGi5jX18RKjmDzDsQ8lqmMWMpAxouY04FiLb9h8w7EHJaofFhMP0aMWKH9xGp2kVUMGbGcq1Q2LOcOxoxYzjvEeurIYgaNuIWLVS4c4DpGjbiF14kTVJc5DBtxk3Ps2JjDCxcx7kAXfCyUf8rH8lf5lyzTuGbWNTJNvpAP5QeZKxuYXl4vEmeoLJMZuA+XyMtygdTbood7yNUyStZpVTPrFLlfGmxx4+k20kqelJlMskIn27MxhxdaM3KPrpA+eT4C2lNeDPCaGkfNrAvkKinOUbeK+sEym4mWs7U4RZF8ydA9+L7sVLCXh8qPqdfM+sFW7yIq+pynP1Pdwi/t2pjDCy0Ye0EflkqeermtjE61ZtZX1eu6Fy4P/SuFTbYQBxnD4PPa00cvi2VkajWzjvLx6tWGezg3Okac5ARGn8fhPt8I1pZ/plIz63TZzlfl25nwr54gjjKM4edwmtT03c39C7yRjqPmfz3Jd+X3mLJa/85yGG/8chjsEQz9E6+Z9a0AdQ+XUuev0zhMHOZpYl6BE3J+QZafnWVlojWzrpcDA1V+xfEpPy1Os7eUEPVyBn/U4kuJ1sz6ZsC6Jzo94xK19h2nL1EvZ/DdWs5NtGbW5gHrFstCh2fcV5xnp4JvKF3zxxDdrJNjC7Q4amadEfAXiQwvOzvjlR4uq3KA24j7VpfGhGFyYjWzPhKibldnZ3wbsc9eN7aIwEcUJpFPE6uZtVmIuhc6OuFFas3Dr1xL4Dfz1lC9fCOxmhlXyzYh6p7u6ISvJfL/parMIvKbvCFUL/8UQ82X8nxlGAY3H8Y2S6132EQHIr/Je0N9JLcu8pr5HpW6MFTddk7OtwNx35xKbN6xyRdC9LFjDDVFfshzRVqVEHVd/EVvssc7Jx3iDEK/0Y9DdPGjGGoWy5I8R7tfiMouPpDlDKJenu+I/a+uDXCbTZZjY6gpclzeow2zl+w452b7HTGviGbEfqNnBezg2zHUFOmT91iD33G+h4OTbUbMK2Y0sQ9xAU6DvPdBBr2op7jAVl1rZEcu6PHoaCIe7K2lO5bKob57V0XGR14zQ+GN0x8NVLeW/Nu5uR5HxHPzCsH/1RG+O9czhpqZHyhTPXw2sUeAync6N9NXiHc+DnF+A4dg3/628LR9tv9vlB/2dKx/9r2T/FHOPXG5VK1tyMtTxH7j79DHeu7Z4bI88pr5rhIo7+O+6u4kM5yb51NEuxC7s1XzRmer10YvHOHjwRZea2Zoq97Kez/aOz3X3UXGOjfLdWpdQ0HuJ/YbXSXnefhKdHnkNTOPSOnpe9/E16SGp2sPXLxf435i7YUdZAWx3+TQPPvr1JIH826jEaRmhuPlL4GOdZK0y1u3nvRVv3S4N8MVak2DJ24l8ptZIs/IyeWu/K4jV4Z4gGXFNUW9bp8p74Q62rFykWxf4a8lvWWpoxO8lUh7pbbMIfJbuVhel/vkBvV2/Q9ytwyP5NXzfzUvlK7ST8ZE9JpcKp/Lo2rBXyLnyDXSSwY5/ZTdOWo9g2euJuxoiVcTZz9U42nsaIUz1VoGX1zAskELvIAo+6WSTGLhoOFOYmOOILRi6aDhtiLGwRjL4kGDHUuEg9KE5YMG24QIB2cUCwgNdRTxDcORLKGNrpe/ySDpK13kFnlIXs6zS266NbP+LK/L43KbXC995Dl537lbdDMeQXzDMZTYy7vSXuqW68zucqV8o1XNjNOkewV3pm8jLdSPAJceqD6U6IblYE+bUNjrxwW2dWorE7SomXGedM77ZJl9ZIgjW7FsUOsWQjPA2dhvkBs99KeKDEy5Ztb/q/C2na1pkXdXf1scQGyjYE8nb/T8j4qI90+Ir/X43iiOmlmf9LxJ1wHWP2lpTaDdCqEC7nXyFd/fV0NdU6qZ1d9W3/vIQqtndy+RjYodfO5EY4M3+u7SkFRqZvxWqvus2zjQFiNmuJyNOaKku3Mf7vmnRoFdDuKomX0vcWCAyvY+b687cY2SWrLAqegHe1jDNYnXzPh8oLrbWbpnzwK1ViFSrnLqe/xgVJHpidbMWBL4I62eVs7uSqIaNdUc2ru9feAu9Uu0ZtBfI7LsZ+HkZrAxRxy0d+aS3bqBe9QowZpZbw4x0X/xQxu8UFzggZK2+LcQPaqc47uQOGpmDXPV2mOWTW68WqMQCy2ciP6gUD36R2I1s1YNUbezZZNrQUTj42sHoh/uSS0fJVYz4+JQdX9v1dy+Jp5xcoID0e8SqkNDE6uZcWKouidbNbcTiGe8vGN99G8J1Z/hMdR8LeexTglV9zSLpvYO0YybY62P/kOh+vNtDDU/yXmsK0LV7WDR1I4hmvEzxPLovxyqOwtiqPljnqOtGaJuV2tmNoRYJsEBlm/e8UOI3uwbQ82asjbP0TYIUXmwNXdZHkAsk+EJy1/3dwvcmd4x1GyT91h7Ba5bLPMtmdcTRDIpds/7OuTudeBFMi2Ga8sHFrhh1/Vva9aq9QiJ0cfq6H8TsCsXx1CzjizOe6xlcrTjb/f7EMck2V6WWR3+toF6siDymiL3FDzW9wLVPdSSDTqXedqRECLkFqujP0Gq+O7I0Bhq1peVHo721ADzG81VGBCMWtZ8SFSxA332o0cMNavK556Odbbs6rNyN0umNJ+NOdKgk+Wf81/roxedY6gp8oLnY/3K133qZ1izG38nYpgGVQvsH2P+t8VdPfWhkvSVsohrZrr7gq+j/avs6LFyB1ltyYSmh7pvEUJwnvUX9Q6RGgV/G/9L5DUzVT8PEITCn/VXtmo7zvOIYFoUB3xAlEnOkWtyfjy3rfTx9DGcn5qZr/PuCVQ1855ikOyV56qDDvKTVR/FsjFHijRz4CbezCMs+0mjLZ5uUyynSP9QD7IoXzNzyW4bGVjge/xCrpPX5eKtdqIvkt9JL5lo2VSaEb90+cSJ8GdcLv+Qj2SovClfy6KIaw5TffwxwmskS9Xr+2cyXAbLGPk+sqPVyU+IXto0dib6qJONiV76jGAhYsKOIHY6cDRLERP2aGKnB4NZjJigg4mcLuxv+eYdqNelVvsTOX14nCWJCfk4cdOJnWWN1cttvXwi3eUcaSj7ykHSSNpLH/m7hjWzTpX+cpE0kcNkb2kgbaSzjAx4kZB+rlFrDbSit7Wx/0U6SZ0Kz7m+9Ai4b0EcNbM/TgbmeBRXNTlLvrNgGr2Jmm5sF/IqND1dKV0K3BO3vTzi+ead+GpmfVv2y1u3SM5VP3RMnscitc5AO2628ALeIzydeZu8D8SMv2b2+r3unuruJH8zeCI3EzMdqSmzrAr+t1tdCZ+PQ2ReajUzlsiZnutWlWGGTmRWqKcOQIxcbtUde/V9nXtDWZdKzaxX+6pbTb40ciaXEzFdqSJTLQl+iRzv++w7pVAz6zO+6+6ifgyZNpOpAfY2hMSw5bHNAwKd/ZeJ18y4ULYNUPdS42bye+KlM8Uy3oLgr1KvikE4NeGaWYPtSVsp75P89HM8G3PoTlOnrxf7LNGaGRdL9YB1Oxo1k6ZES38+Nz76jQOf+y2J1sw4LHDdegbdefE5sTKBUwwP/tKtts3yw0EJ1sx6YYhJfWrMTE4hVmbwttHRHx3q3OcmVjNr/RB1exkykbeJlCn8NtBlqLr4TKhzH5tYzewNrGE+/DLjISplaj2BMQwyOPp3hzrzUYnVzDg3VN3WRsxjEHEyib1kvbHR7xzqzAfHUHNQnq+8wnCCEbdL70WczOJRY6N/Z6jzHhNDzRF5bv4NQ0sDpvEoUTKNXY19stsToc57Qgw1c1/Rty5UXf2v6Fvt+xnCoAF3Gxr94SHOuSjHbjjDQ3VyWp6j3T5E3Tss/9wFUqKeLDEy+rNDnHOjGGrWz3u0rSP/5UQfl6g1BEZyk6Gv+0cFPuMXY6jZKaavImtG+KCveLyJCJlKDfVqZ2L0ewQ831p5dtbpEbiL7+Q91pnql4xgtNP+3VcNImQulxkZ/XkBd4N5OIaaBxe80v6CgLP5SvMpXEZ8TMbUzTtuC3CuRxcI6W2BOvhWwWOdEuj+AN1f89mYw3jaGRn9JbKHz/OsLeMir+nlbv2MXX3XrS2TNZ9AO6JjOkUFI6Gn3/m6D76afBx5zcw1kQs8XvF2mq+6xfKu5t0fF/gTDNCIZoZ+zv+6VPIc/JGR1xSpKz94PtaFcqCPiTykfe+bERs7+MjQ8P/Z0wMf9vH1VJs/e3yIxEHyL1/HuthjXKrLq9r3/SMiYwvHGXs9/09ycoFfZy70feFSoZrZqkt9H+sGuUO2KVD5SCMevnUckbGH4QbfxDtGjs5xVi0CPx4zd02RM+T7wMc6Uzrl/GT8ABlmxD4Kw4mLTRxh0D5wFfmj+v34dNlr46vqTnKS9JOfI61ZS/aTs+W5CC6CWipvSEc5eONFsFVkN2kovSN6hm/8bvD4YDIwhhcM37Hvf8FaE0PNeB6BvVYWGbdf0gtExTZ+IyWWhB/js0StE7COR1jaWMBHiImN7CKrWNyYx6BPKALt6cHyxhjumATtqSuLWeCY86KkukTEXm5kiWMObyQeNlPdwOe6YxLOCfzYUDCEP7DME/te3yT/QDRsp5JMIeyxXs1nolN83NEIxtKW2Oe5hr8o1DX8ptqWWLhAUZ7HR7pgXHfumetYNuZwhZYOBz+u+/VNtiWRcIcPHQ1+XLv0mOyHxMElTnQy+HHtzWe2JxIHt3jTueDHtyOvyb5JFFzjMCl1LPpx7cNvsqVqHYBzPOdU8ON7+o7JPkcMXGQvpzbviOuZeyZbotYAOMlDDkU/riftmuxDRMBVdnbm2vXZIbpU39KerFTzB2e5y5Hoh9tgepqVPbmL5e8ydWSRE9F/IlSXvrSwI4vU7MFpbnAi+neE6tEICztyA0vfdbaR6Q5Ev3OoHg22rh/TCz4iDBygowPRvztUh0Zb14+OLHsQqSyTrY/+M6E6ZNtNzpPVzAEUZ1kf/dGh+jPXsm6cxZKHLEVGPPo5jEtDvM4dZN39i2zMAZtobv3rfuPAvbnFsk40Z7nD5rxvefQfD9yZz6zqw/ssddiS4y2PftDnydl2x/7xLHXYmtctD/+AQF2x60q+11nmUJ6DLd+8oyTAK55dd+2VqhkDVMCzlr/uz5H6vvrRUNZZdf7PssShYna3bKmX91vZwXM3DpF5Vp37OjVfgBz0s/5LvmlyhKdOtJHllp15P5Y35GZ7WWF9+FdKF6lWoAuPSJllZ71CnRVAHu5w4ibeX6RTjvvV60sPWcZty+Ae28q/Hdm5Z718It2lnTSUfeVAaSTtpY/83dJz/beaK0ABOjsSfZfszLKGwmwjMwmLVc5kYw7wxsXExSovZkmDNyrJJAJjjZN8PF0YnKc1kbHG1ixn8MNYQmOFY1nK4I8mxMYKm7CUwS/vERzjfY9lDP5pQHSMtwHLGIIwjPAY7TCWMATjYNlAgIx1AxtzQHCeIULG+gzLF4Kzp6wlREa6Vs0OIAQPECMjfYClC+HYwbrdalxwuY+NyABycDtRMs7bWbYQntqygDAZ5QI1M4AIuJY4GeW1LFmIhmoyg0AZ44wCm44C+OBCImWMF7JcIToqyURCZYQT2ZgDouVMYmWEZ7JUIWq+IVja+w3LFKLnNKKlvaexTCEO/kS4tPZPLFGIh2OJl9YeyxKFuHiVgGnrqyxPiI8D2bxD2405DmR5Qpw8Rcy09CmWJsTLHmzeoeXGHLuzNCFu7idq2nk/yxLiZ3tZRti0cpmaCUAC/JG4aeUfWZKQDLVkPoHTxvlqHgAJcQ2R08ZrWI6QHFVlOqHTwulqFgAJcgGx08ILWIqQLMUygeCl7gQ1B4CEaUX0UrcVyxDS4CvCl6pfsQQhHRoTv1RtzBKEtBhFAFNzFMsP0uNoKSOEqVimeg+QIi8Tw1R8maUH6XKArCeIibte9R0gZZ4kion7JMsO0mc3WUMYE3WN6jmABtxHHBP1PpYc6MF2spRAJuZS1W8ATehOJBOzO8sN9KGmzCOUiThP9RpAI64ilol4FUsN9KKq/EwwY/dnNuYA/TifaMbu+Swz0I9iGU84Y3U8G3OAnrQknrHakiUGuvIFAY3NL1heoC+nENHYPIXlBTrzLiGNxXdZWqA3v2Xzjlg25vgtSwt0ZwhRjdwhLCvQn/3YvCPyjTn2Y1mBCTxBXCP1CZYUmEF9WU1gI3O16ieAIdxDZCPzHpYTmEM9WUJoI3GJ6iWAQXQjtpHYjaUEZlFD5hLc0M5VfQQwjE5EN7SdWEZgHlVkKuEN5VTVQwADOY/4hvI8lhCYSZGMI8CBHaf6B2AozYlwYJuzfMBkPiPEgfyMpQNmcxIxDuRJLB0wnZEE2bcjWTZgPkeyeYfvjTmOZNmADbxEnH35EksG7GBfKSHQni1R/QKwhP5E2rP9WS5gD7vKKkLtyVWyC8sFbKI3sfZkb5YK2EVdWUywC7pY9QnAMroS7YJ2ZZmAfVSXOYQ7r3NUjwAs5ArindcrWCJgJ5VlCgHP6RTVHwBLOZeI5/RclgfYS5F8T8gr9Hs25gC7aUrMK7QpSwNs51OCXs5PWRZgPycS9XKeyLIAF3ibsG/h2ywJcIPDpZTAb7JU9QPAEQYR+U0OYjmAO+zD5h2bNubYh+UALvEYsf/Vx1gK4BY7y0qCr3qwM0sBXKMX0Vc9AHCOOrLI8eAvUj0AcJCbHI/+TSwBcJPqMsvh4M9iYw5wl8scjv5ljB/cpbJMdjT4k9mYA9zmHEejfw6jB7cpkr87GPzv2JgDoImD0W/C2AFEPnEs+J8wcoAMxzsW/eMZOUCWtxwK/luMG+C/HOrM5h2l6lwBYBMvOhL9Fxk1wObsLescCP46dZ4AsAWPOBD9RxgzwNbsJCssD/4KdY4AUI6elke/JyMGqIhtZaHFwV+ozg8AKqSLxdHvwngBcrGNzLQ0+DPVuQFATi61NPqXMlqAfFSSSRYGf5I6LwDIS1sLo9+WsQIUoki+tSz437IxB4AXmloW/aaMFMAbH1oU/A8ZJ4BXGlgU/QaME8A7b1oS/DcZJYAfDpYNFgR/gzoPAPDF8xZE/3nGCOCXPWWt4cFfq84BAHzzsOHRf5gRAgRhR1lucPCXq+MHgEDcZXD072J8AEGpLQsMDf4CdewAEJgbDI3+DYwOIAzV5BcDg/+LOm4ACMUlBkb/EsYGEJZK8qNhwZ/IxhwAUXC2YdE/m5EBRMM3BgX/G8YFEBWnGxT90xkXQHR8YEjwP2BUAFFyrCHRP5ZRAUTLGwYE/w3GBBA1B2m/eccGdYwAEDnPah79ZxkRQBzsofXmHWvV8QFALDyocfQfZDwAcbGDLNM0+MvUsQFAbNypafTvZDQAcVJL5msY/PnquAAgVq7XMPrXMxaAuKkq0zUL/nR1TAAQOxdrFv2LGQlAEhTLBI2CP0EdDwAkQhuNot+GcQAkx1eaBP8rRgGQJKdqEv1TGQVAsrynQfDfYwwASXOMlKUc/DJ1DACQOK+lHP3XGAFAGhwg61MM/nr19wNAKgxMMfoDaT9AWuwma1IK/hr1dwNAajyQUvQfoPUAabKdLE0h+EvV3wsAqXJ7CtG/nbYDpE1NmZdw8OepvxMAUue6hKN/HS0H0IGqMi3B4E9jYw4AXbgowehfRLsBdKFYxicU/PFszAGgE2cmFP0zaTWAXnyRQPC/oM0AutEogeg3os0A+jEm5uCPocUAOnJUrJt3lKn6AKAlr8YY/VdpL4Cu7B/b5h3rVW0A0JanY4r+07QWQGfqy+oYgr9a1QUArekbQ/T70lYA3aknSyIO/hJVEwC057aIo38bLQUwgRoyN8Lgz1X1AMAIrokw+tfQTgBTqCJTIwr+VFULAIyhQ0TR70ArAUyiWMZFEPxxbMwBYBpnRBD9M2gjgHl8FjL4n9FCABM5OWT0T6aFAGYyOkTwR9M+AFM5MvDmHWXqzwKAsbwSMPqv0DoAk9lXSgIEv0T9OQAwmicDRP9J2gZgOrvKKp/BX6X+DAAYz30+o38fLQOwgbqy2EfwF6v/HgCs4FYf0b+VdgHYQg2Z4zH4c9iYA8AmrvYY/atpFYBNVJGfPAT/JzbmALCN8z1E/3zaBGAbRfJDgeD/oP4bALCOlgWi35IWAdjJp3mC/yntAbCVhnmi35D2ANjLuzmC/y6tAbCZw6W0guCXqn8PAFYztILoD6UtALazT7nNO0rUvwMA6xmwVfQH0BIAF9hFVm4W/JWyMy0BcIN7N4v+vbQDwBXqyKKNwV+k/j8AOEO3jdHvRisAXKK6zFbBn63+CQBOcaWK/pW0AcA1Ksto9T8AcA525HGY/wcAxiEwaH/ifAAAAABJRU5ErkJggg== - href: 'https://vault-vault.region.example.com' + href: 'https://vault-vault.apps.region.example.com' location: ApplicationMenu text: 'Vault' --- diff --git a/common/tests/hashicorp-vault.expected.diff b/common/tests/hashicorp-vault.expected.diff new file mode 100644 index 00000000..dbc3442f --- /dev/null +++ b/common/tests/hashicorp-vault.expected.diff @@ -0,0 +1,11 @@ +--- tests/hashicorp-vault-naked.expected.yml ++++ tests/hashicorp-vault-normal.expected.yml +@@ -340,7 +340,7 @@ + applicationMenu: + section: HashiCorp Vault + imageURL: data:image/png;base64,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 +- href: 'https://vault-vault.apps.foo.cluster.com' ++ href: 'https://vault-vault.apps.region.example.com' + location: ApplicationMenu + text: 'Vault' + --- diff --git a/common/tests/install-naked.expected.yaml b/common/tests/install-naked.expected.yml similarity index 100% rename from common/tests/install-naked.expected.yaml rename to common/tests/install-naked.expected.yml diff --git a/common/tests/install-normal.expected.yaml b/common/tests/install-normal.expected.yml similarity index 98% rename from common/tests/install-normal.expected.yaml rename to common/tests/install-normal.expected.yml index d115d8ae..faaef3cc 100644 --- a/common/tests/install-normal.expected.yaml +++ b/common/tests/install-normal.expected.yml @@ -40,7 +40,7 @@ spec: - name: global.pattern value: install - name: global.hubClusterDomain - value: hub.example.com + value: apps.hub.example.com syncPolicy: automated: {} --- diff --git a/common/tests/install.expected.diff b/common/tests/install.expected.diff new file mode 100644 index 00000000..563de641 --- /dev/null +++ b/common/tests/install.expected.diff @@ -0,0 +1,43 @@ +--- tests/install-naked.expected.yml ++++ tests/install-normal.expected.yml +@@ -11,14 +11,14 @@ + apiVersion: argoproj.io/v1alpha1 + kind: Application + metadata: +- name: install-default ++ name: install-example + namespace: openshift-gitops + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground + spec: + destination: + name: in-cluster +- namespace: install-default ++ namespace: install-example + project: default + source: + repoURL: https://github.com/pattern-clone/mypattern +@@ -28,7 +28,7 @@ + ignoreMissingValueFiles: true + valueFiles: + - "/values-global.yaml" +- - "/values-default.yaml" ++ - "/values-example.yaml" + # Track the progress of https://github.com/argoproj/argo-cd/pull/6280 + parameters: + - name: global.repoURL +@@ -40,7 +40,7 @@ + - name: global.pattern + value: install + - name: global.hubClusterDomain +- value: ++ value: apps.hub.example.com + syncPolicy: + automated: {} + --- +@@ -61,4 +61,4 @@ + config: + env: + - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES +- value: install-default,openshift-gitops ++ value: install-example,openshift-gitops diff --git a/common/tests/operator-install-naked.expected.yaml b/common/tests/operator-install-naked.expected.yml similarity index 100% rename from common/tests/operator-install-naked.expected.yaml rename to common/tests/operator-install-naked.expected.yml diff --git a/common/tests/operator-install-normal.expected.yaml b/common/tests/operator-install-normal.expected.yml similarity index 100% rename from common/tests/operator-install-normal.expected.yaml rename to common/tests/operator-install-normal.expected.yml diff --git a/common/tests/operator-install.expected.diff b/common/tests/operator-install.expected.diff new file mode 100644 index 00000000..9f5bdedc --- /dev/null +++ b/common/tests/operator-install.expected.diff @@ -0,0 +1,11 @@ +--- tests/operator-install-naked.expected.yml ++++ tests/operator-install-normal.expected.yml +@@ -6,7 +6,7 @@ + name: operator-install + namespace: openshift-operators + spec: +- clusterGroupName: default ++ clusterGroupName: example + gitSpec: + targetRepo: https://github.com/pattern-clone/mypattern + targetRevision: main diff --git a/tests/all-bookinfo-naked.expected.yaml b/tests/all-bookinfo-naked.expected.yml similarity index 100% rename from tests/all-bookinfo-naked.expected.yaml rename to tests/all-bookinfo-naked.expected.yml diff --git a/tests/all-bookinfo-normal.expected.yaml b/tests/all-bookinfo-normal.expected.yml similarity index 100% rename from tests/all-bookinfo-normal.expected.yaml rename to tests/all-bookinfo-normal.expected.yml diff --git a/tests/all-bookinfo.expected.diff b/tests/all-bookinfo.expected.diff new file mode 100644 index 00000000..69e547d1 --- /dev/null +++ b/tests/all-bookinfo.expected.diff @@ -0,0 +1,136 @@ +--- tests/all-bookinfo-naked.expected.yml ++++ tests/all-bookinfo-normal.expected.yml +@@ -3,14 +3,14 @@ + apiVersion: v1 + kind: Namespace + metadata: +- name: bookinfo ++ name: pattern-namespace + --- + # Source: bookinfo/charts/details/templates/serviceaccount.yaml + apiVersion: v1 + kind: ServiceAccount + metadata: + name: bookinfo-details +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + account: details + --- +@@ -19,7 +19,7 @@ + kind: ServiceAccount + metadata: + name: bookinfo-productpage +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + account: productpage + --- +@@ -28,7 +28,7 @@ + kind: ServiceAccount + metadata: + name: bookinfo-ratings +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + account: ratings + --- +@@ -37,7 +37,7 @@ + kind: ServiceAccount + metadata: + name: bookinfo-reviews +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + account: reviews + --- +@@ -75,7 +75,7 @@ + kind: Service + metadata: + name: details +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + app: details + service: details +@@ -91,7 +91,7 @@ + kind: Service + metadata: + name: productpage +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + app: productpage + service: productpage +@@ -110,7 +110,7 @@ + kind: Service + metadata: + name: ratings +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + app: ratings + service: ratings +@@ -126,7 +126,7 @@ + kind: Service + metadata: + name: reviews +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + app: reviews + service: reviews +@@ -142,7 +142,7 @@ + kind: Deployment + metadata: + name: details-v1 +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + helm.sh/chart: details-0.1.0 + app: details +@@ -176,7 +176,7 @@ + kind: Deployment + metadata: + name: productpage-v1 +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + helm.sh/chart: productpage-0.1.0 + app: productpage +@@ -216,7 +216,7 @@ + kind: Deployment + metadata: + name: ratings-v1 +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + helm.sh/chart: ratings-0.1.0 + app: ratings +@@ -250,7 +250,7 @@ + kind: Deployment + metadata: + name: reviews-v1 +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + helm.sh/chart: reviews-0.1.0 + app: reviews +@@ -297,7 +297,7 @@ + kind: Deployment + metadata: + name: reviews-v2 +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + helm.sh/chart: reviews-0.1.0 + app: reviews +@@ -344,7 +344,7 @@ + kind: Deployment + metadata: + name: reviews-v3 +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + helm.sh/chart: reviews-0.1.0 + app: reviews diff --git a/tests/all-clustering-naked.expected.yaml b/tests/all-clustering-naked.expected.yml similarity index 100% rename from tests/all-clustering-naked.expected.yaml rename to tests/all-clustering-naked.expected.yml diff --git a/tests/all-clustering-normal.expected.yaml b/tests/all-clustering-normal.expected.yml similarity index 100% rename from tests/all-clustering-normal.expected.yaml rename to tests/all-clustering-normal.expected.yml diff --git a/tests/all-clustering.expected.diff b/tests/all-clustering.expected.diff new file mode 100644 index 00000000..983ca8a2 --- /dev/null +++ b/tests/all-clustering.expected.diff @@ -0,0 +1,164 @@ +--- tests/all-clustering-naked.expected.yml ++++ tests/all-clustering-normal.expected.yml +@@ -3,22 +3,22 @@ + apiVersion: v1 + kind: ServiceAccount + metadata: +- name: kong-clustering-gitops +- namespace: test ++ name: kong-gitops ++ namespace: pattern-namespace + --- + # Source: kong-clustering/templates/post-deploy-cp.yaml + apiVersion: v1 + kind: ConfigMap + metadata: +- namespace: test +- name: kong-clustering-cp-post-deploy ++ namespace: pattern-namespace ++ name: kong-cp-post-deploy + data: + post-deploy.sh: | + #!/bin/bash + set -eu + argocd login --username admin \ +- $(oc get routes -n unmanaged- -gitops-server -otemplate='{{ .spec.host }}') \ +- --password $(oc get secret -n unmanaged- -gitops-cluster -ojsonpath='{.data.admin\.password}' | base64 -d) \ ++ $(oc get routes -n mypattern-unmanaged unmanaged-gitops-server -otemplate='{{ .spec.host }}') \ ++ --password $(oc get secret -n mypattern-unmanaged unmanaged-gitops-cluster -ojsonpath='{.data.admin\.password}' | base64 -d) \ + --insecure \ + --grpc-web + argocd app patch-resource kong-cp \ +@@ -31,22 +31,22 @@ + apiVersion: v1 + kind: ConfigMap + metadata: +- namespace: test +- name: kong-clustering-dp-post-deploy ++ namespace: pattern-namespace ++ name: kong-dp-post-deploy + data: + post-deploy.sh: | + #!/bin/bash + set -eu + argocd login --username admin \ +- $(oc get routes -n unmanaged- -gitops-server -otemplate='{{ .spec.host }}') \ +- --password $(oc get secret -n unmanaged- -gitops-cluster -ojsonpath='{.data.admin\.password}' | base64 -d) \ ++ $(oc get routes -n mypattern-unmanaged unmanaged-gitops-server -otemplate='{{ .spec.host }}') \ ++ --password $(oc get secret -n mypattern-unmanaged unmanaged-gitops-cluster -ojsonpath='{.data.admin\.password}' | base64 -d) \ + --insecure \ + --grpc-web + if ! oc get cm -n kong cluster-urls; then + echo "config map cluster-urls not found" + exit 1 + fi +- if ! oc get appprojects -n unmanaged- dataplane; then ++ if ! oc get appprojects -n mypattern-unmanaged dataplane; then + echo "dataplane project cannot be retrieved" + exit 1 + fi +@@ -64,7 +64,7 @@ + kind: ClusterRole + apiVersion: rbac.authorization.k8s.io/v1 + metadata: +- name: kong-clustering-jobs ++ name: kong-jobs + rules: + - verbs: + - get +@@ -92,22 +92,22 @@ + kind: ClusterRoleBinding + apiVersion: rbac.authorization.k8s.io/v1 + metadata: +- name: kong-clustering-jobs-cluster-binding ++ name: kong-jobs-cluster-binding + subjects: + - kind: ServiceAccount +- namespace: test +- name: kong-clustering-gitops ++ namespace: pattern-namespace ++ name: kong-gitops + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole +- name: kong-clustering-jobs ++ name: kong-jobs + --- + # Source: kong-clustering/templates/post-deploy-roles.yaml + kind: Role + apiVersion: rbac.authorization.k8s.io/v1 + metadata: +- name: kong-clustering-role +- namespace: test ++ name: kong-role ++ namespace: pattern-namespace + rules: + - apiGroups: + - security.openshift.io +@@ -122,33 +122,33 @@ + kind: RoleBinding + apiVersion: rbac.authorization.k8s.io/v1 + metadata: +- name: kong-clustering-jobs-binding +- namespace: test ++ name: kong-jobs-binding ++ namespace: pattern-namespace + subjects: + - kind: ServiceAccount +- name: kong-clustering-gitops +- namespace: test ++ name: kong-gitops ++ namespace: pattern-namespace + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role +- name: kong-clustering-role ++ name: kong-role + --- + # Source: kong-clustering/templates/post-deploy-cp.yaml + apiVersion: batch/v1 + kind: Job + metadata: +- namespace: test +- name: kong-clustering-cp-post-deploy ++ namespace: pattern-namespace ++ name: kong-cp-post-deploy + spec: + backoffLimit: 20 + template: + spec: + restartPolicy: OnFailure +- serviceAccountName: kong-clustering-gitops ++ serviceAccountName: kong-gitops + volumes: + - name: post-deploy + configMap: +- name: kong-clustering-cp-post-deploy ++ name: kong-cp-post-deploy + defaultMode: 0711 + containers: + - image: quay.io/ecosystem-appeng/argocd-helper:1.0 +@@ -165,19 +165,19 @@ + apiVersion: batch/v1 + kind: Job + metadata: +- namespace: test +- name: kong-clustering-dp-post-deploy ++ namespace: pattern-namespace ++ name: kong-dp-post-deploy + generateName: path-kong-clustering + spec: + backoffLimit: 20 + template: + spec: + restartPolicy: OnFailure +- serviceAccountName: kong-clustering-gitops ++ serviceAccountName: kong-gitops + volumes: + - name: post-deploy + configMap: +- name: kong-clustering-dp-post-deploy ++ name: kong-dp-post-deploy + defaultMode: 0711 + containers: + - image: quay.io/ecosystem-appeng/argocd-helper:1.0 diff --git a/tests/all-kong-naked.expected.yaml b/tests/all-kong-naked.expected.yml similarity index 100% rename from tests/all-kong-naked.expected.yaml rename to tests/all-kong-naked.expected.yml diff --git a/tests/all-kong-normal.expected.yaml b/tests/all-kong-normal.expected.yml similarity index 100% rename from tests/all-kong-normal.expected.yaml rename to tests/all-kong-normal.expected.yml diff --git a/tests/all-kong.expected.diff b/tests/all-kong.expected.diff new file mode 100644 index 00000000..f495f45b --- /dev/null +++ b/tests/all-kong.expected.diff @@ -0,0 +1,158 @@ +--- tests/all-kong-naked.expected.yml ++++ tests/all-kong-normal.expected.yml +@@ -3,14 +3,14 @@ + apiVersion: v1 + kind: Namespace + metadata: +- name: test ++ name: pattern-namespace + --- + # Source: kong/templates/service-account.yaml + apiVersion: v1 + kind: ServiceAccount + metadata: + name: kong +- namespace: test ++ namespace: pattern-namespace + --- + # Source: kong/charts/kong/templates/secret-sa-token.yaml + apiVersion: v1 +@@ -27,7 +27,7 @@ + kind: Secret + metadata: + name: postgresql +- namespace: test ++ namespace: pattern-namespace + stringData: + database-name: kong + database-password: kong123 +@@ -38,7 +38,7 @@ + kind: Secret + metadata: + name: kong-enterprise-license +- namespace: test ++ namespace: pattern-namespace + annotations: + avp.kubernetes.io/path: "secret/data/hub/kong" + type: Opaque +@@ -87,14 +87,14 @@ + kind: ConfigMap + metadata: + name: cm-generator +- namespace: test ++ namespace: pattern-namespace + --- + # Source: kong/charts/postgresql/templates/pvc.yaml + apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: postgresql +- namespace: test ++ namespace: pattern-namespace + spec: + accessModes: + - ReadWriteOnce +@@ -429,7 +429,7 @@ + apiVersion: rbac.authorization.k8s.io/v1 + metadata: + name: kong-role +- namespace: test ++ namespace: pattern-namespace + rules: + - apiGroups: + - security.openshift.io +@@ -481,11 +481,11 @@ + apiVersion: rbac.authorization.k8s.io/v1 + metadata: + name: kong-role-binding +- namespace: test ++ namespace: pattern-namespace + subjects: + - kind: ServiceAccount + name: kong +- namespace: test ++ namespace: pattern-namespace + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role +@@ -697,7 +697,7 @@ + kind: Service + metadata: + name: postgresql +- namespace: test ++ namespace: pattern-namespace + spec: + ports: + - name: postgresql +@@ -1357,7 +1357,7 @@ + kind: Job + metadata: + name: cert-secret +- namespace: test ++ namespace: pattern-namespace + spec: + backoffLimit: 1 + template: +@@ -1371,7 +1371,7 @@ + command: + - "/bin/bash" + - "-c" +- - "oc create secret tls kong-cluster-cert --cert=./cluster.crt --key=./cluster.key -n test && echo 'kong certificate secret created'" ++ - "oc create secret tls kong-cluster-cert --cert=./cluster.crt --key=./cluster.key -n pattern-namespace && echo 'kong certificate secret created'" + restartPolicy: Never + --- + # Source: kong/templates/cm-generator-job.yaml +@@ -1379,7 +1379,7 @@ + kind: Job + metadata: + name: cm-generator +- namespace: test ++ namespace: pattern-namespace + spec: + template: + spec: +@@ -1406,7 +1406,7 @@ + kind: DeploymentConfig + metadata: + name: postgresql +- namespace: test ++ namespace: pattern-namespace + spec: + replicas: 1 + selector: +@@ -1497,7 +1497,7 @@ + kind: Route + metadata: + name: kong-cp-kong-admin +- namespace: test ++ namespace: pattern-namespace + spec: + port: + targetPort: kong-admin +@@ -1510,7 +1510,7 @@ + kind: Route + metadata: + name: kong-cp-kong-manager +- namespace: test ++ namespace: pattern-namespace + spec: + port: + targetPort: kong-manager +@@ -1523,7 +1523,7 @@ + kind: Route + metadata: + name: kong-cp-kong-manager-tls +- namespace: test ++ namespace: pattern-namespace + spec: + port: + targetPort: kong-manager-tls +@@ -1538,7 +1538,7 @@ + kind: Route + metadata: + name: kong-cp-kong-admin-tls +- namespace: test ++ namespace: pattern-namespace + spec: + port: + targetPort: kong-admin-tls