From f2215f746338b1c38f5fdfc2db096059935e8a4b Mon Sep 17 00:00:00 2001 From: Tomer Figenblat Date: Tue, 16 Apr 2024 17:41:21 -0400 Subject: [PATCH 01/64] feat: add support for hive clusterdeployments creating spokes Co-authored-by: Alejandro Villegas Signed-off-by: Tomer Figenblat --- .../provision/clusterdeployment.yaml | 71 +++++++++++++++++++ acm/templates/provision/clusterpool.yaml | 15 +--- .../provision/managedclusterset.yaml | 16 +++++ acm/templates/provision/secrets-aws.yaml | 65 +++++++++++------ acm/templates/provision/secrets-azure.yaml | 65 +++++++++++------ acm/templates/provision/secrets-common.yaml | 59 ++++++++++----- acm/values.yaml | 21 +++++- clustergroup/values.schema.json | 32 +++++++++ 8 files changed, 267 insertions(+), 77 deletions(-) create mode 100644 acm/templates/provision/clusterdeployment.yaml create mode 100644 acm/templates/provision/managedclusterset.yaml diff --git a/acm/templates/provision/clusterdeployment.yaml b/acm/templates/provision/clusterdeployment.yaml new file mode 100644 index 00000000..cc37c161 --- /dev/null +++ b/acm/templates/provision/clusterdeployment.yaml @@ -0,0 +1,71 @@ +{{- range .Values.clusterGroup.managedClusterGroups }} +{{- $group := . }} + +{{- range $group.clusterDeployments}} +{{ $cluster := . }} +{{- $deploymentName := print $cluster.name "-" $group.name }} + +{{- $cloud := "None" }} +{{- $region := "None" }} + +{{- if $cluster.platform.aws }} +{{- $cloud = "aws" }} +{{- $region = $cluster.platform.aws.region }} +{{- else if $cluster.platform.azure }} +{{- $cloud = "azure" }} +{{- $region = $cluster.platform.azure.region }} +{{- end }} + +--- +apiVersion: v1 +kind: Namespace +metadata: + name: {{ $deploymentName }} + +--- +apiVersion: hive.openshift.io/v1 +kind: ClusterDeployment +metadata: + name: {{ $deploymentName }} + namespace: {{ $deploymentName }} + labels: + vendor: OpenShift +spec: + baseDomain: {{ $cluster.baseDomain }} + clusterName: {{ $deploymentName }} + installAttemptsLimit: 1 + platform: + {{ $cloud }}: + credentialsSecretRef: + name: {{ $deploymentName }}-creds + region: {{ $region }} + provisioning: + installConfigSecretRef: + name: {{ $deploymentName }}-install-config + sshPrivateKeySecretRef: + name: {{ $deploymentName }}-ssh-private-key + imageSetRef: + name: img{{ $cluster.openshiftVersion }}-multi-appsub + pullSecretRef: + name: {{ $deploymentName }}-pull-secret + +--- +apiVersion: cluster.open-cluster-management.io/v1 +kind: ManagedCluster +metadata: + labels: + cluster.open-cluster-management.io/clusterset: {{ $group.name }} + {{- 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 }} + name: {{ $deploymentName }} +spec: + hubAcceptsClient: true +{{- end }}{{- /* range $group.clusterDeployments */}} +{{- end }}{{- /* range .Values.clusterGroup.managedClusterGroups */}} diff --git a/acm/templates/provision/clusterpool.yaml b/acm/templates/provision/clusterpool.yaml index e2f9d3d1..d95905f7 100644 --- a/acm/templates/provision/clusterpool.yaml +++ b/acm/templates/provision/clusterpool.yaml @@ -1,17 +1,5 @@ {{- range .Values.clusterGroup.managedClusterGroups }} {{- $group := . }} -{{- if .clusterPools }}{{- /* We only create ManagedClusterSets if there are clusterPools defined */}} -apiVersion: cluster.open-cluster-management.io/v1beta1 -kind: ManagedClusterSet -metadata: - annotations: - cluster.open-cluster-management.io/submariner-broker-ns: {{ .name }}-broker - argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true - name: {{ .name }} -spec: - clusterSelector: - selectorType: LegacyClusterSetLabel ---- {{- range .clusterPools }} {{- $pool := . }} @@ -54,7 +42,7 @@ spec: runningCount: {{ $numClusters }} baseDomain: {{ .baseDomain }} installConfigSecretTemplateRef: - name: {{ $poolName }}-install-config + name: {{ $poolName }}-install-config imageSetRef: name: img{{ .openshiftVersion }}-multi-appsub pullSecretRef: @@ -91,5 +79,4 @@ spec: --- {{- end }}{{- /* range .range clusters */}} {{- end }}{{- /* range .clusterPools */}} -{{- end }}{{- /* if .clusterPools) */}} {{- end }}{{- /* range .Values.clusterGroup.managedClusterGroups */}} diff --git a/acm/templates/provision/managedclusterset.yaml b/acm/templates/provision/managedclusterset.yaml new file mode 100644 index 00000000..dce01f73 --- /dev/null +++ b/acm/templates/provision/managedclusterset.yaml @@ -0,0 +1,16 @@ +{{- range .Values.clusterGroup.managedClusterGroups }} +{{- if or .clusterPools .clusterDeployments }}{{- /* We only create ManagedClusterSets if there are clusterPools or clusterDeployments defined */}} +--- +apiVersion: cluster.open-cluster-management.io/v1beta2 +kind: ManagedClusterSet +metadata: + annotations: + cluster.open-cluster-management.io/submariner-broker-ns: {{ .name }}-broker + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + name: {{ .name }} +spec: + clusterSelector: + selectorType: LegacyClusterSetLabel + +{{- end }}{{- /* if .clusterPools) */}} +{{- end }}{{- /* range .Values.clusterGroup.managedClusterGroups */}} diff --git a/acm/templates/provision/secrets-aws.yaml b/acm/templates/provision/secrets-aws.yaml index 002c9247..a671638d 100644 --- a/acm/templates/provision/secrets-aws.yaml +++ b/acm/templates/provision/secrets-aws.yaml @@ -3,58 +3,82 @@ {{- range .clusterPools }} {{- $poolName := print .name "-" $group.name }} {{- if .platform.aws }} +--- +{{- template "externalsecret.aws.creds" (dict "name" $poolName "context" . "secretStore" $.Values.secretStore) }} +--- +{{- template "externalsecret.aws.infra-creds" (dict "name" $poolName "context" . "secretStore" $.Values.secretStore) }} + +{{- end }}{{- /* if .platform.aws */}} +{{- end }}{{- /* range .clusterPools */}} + +{{- range .clusterDeployments }} +{{- $deploymentName := print .name "-" $group.name }} +{{- if .platform.aws }} +--- +{{- template "externalsecret.aws.creds" (dict "name" $deploymentName "context" . "secretStore" $.Values.secretStore) }} +--- +{{- template "externalsecret.aws.infra-creds" (dict "name" $deploymentName "context" . "secretStore" $.Values.secretStore) }} + +{{- end }}{{- /* if .platform.aws */}} +{{- end }}{{- /* range .clusterDeployments */}} + +{{- end }}{{- /* range .Values.clusterGroup.managedClusterGroups */}} + +{{- define "externalsecret.aws.creds" }} apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: - name: {{ $poolName }}-creds + name: {{ .name }}-creds spec: dataFrom: - extract: # Expects entries called: aws_access_key_id and aws_secret_access_key - key: {{ default "secret/data/hub/aws" .awsKeyPath }} + key: {{ default "secret/data/hub/aws" .context.awsKeyPath }} refreshInterval: 24h0m0s secretStoreRef: - name: {{ $.Values.secretStore.name }} - kind: {{ $.Values.secretStore.kind }} + name: {{ .secretStore.name }} + kind: {{ .secretStore.kind }} target: - name: {{ $poolName }}-creds + name: {{ .name }}-creds creationPolicy: Owner template: type: Opaque ---- +{{- end}} + +{{- define "externalsecret.aws.infra-creds"}} # For use when manually creating clusters with ACM apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: - name: {{ $poolName }}-infra-creds -spec: + name: {{ .name }}-infra-creds +spec: data: - secretKey: openshiftPullSecret remoteRef: - key: {{ default "secret/data/hub/openshiftPullSecret" .pullSecretKeyPath }} + key: {{ default "secret/data/hub/openshiftPullSecret" .context.pullSecretKeyPath }} property: content - secretKey: awsKeyId remoteRef: - key: {{ default "secret/data/hub/aws" .awsKeyPath }} + key: {{ default "secret/data/hub/aws" .context.awsKeyPath }} property: aws_access_key_id - secretKey: awsAccessKey remoteRef: - key: {{ default "secret/data/hub/aws" .awsKeyPath }} + key: {{ default "secret/data/hub/aws" .context.awsKeyPath }} property: aws_secret_access_key - secretKey: sshPublicKey remoteRef: - key: {{ default "secret/data/hub/publickey" .sshPublicKeyPath }} + key: {{ default "secret/data/hub/publickey" .context.sshPublicKeyPath }} property: content - secretKey: sshPrivateKey remoteRef: - key: {{ default "secret/data/hub/privatekey" .sshPrivateKeyPath }} + key: {{ default "secret/data/hub/privatekey" .context.sshPrivateKeyPath }} property: content refreshInterval: 24h0m0s - secretStoreRef: - name: {{ $.Values.secretStore.name }} - kind: {{ $.Values.secretStore.kind }} + secretStoreRef: + name: {{ .secretStore.name }} + kind: {{ .secretStore.kind }} target: - name: {{ $poolName }}-infra-creds + name: {{ .name }}-infra-creds creationPolicy: Owner template: type: Opaque @@ -63,7 +87,7 @@ spec: cluster.open-cluster-management.io/credentials: "" cluster.open-cluster-management.io/type: aws data: - baseDomain: "{{ .baseDomain }}" + baseDomain: "{{ .context.baseDomain }}" pullSecret: |- {{ "{{ .openshiftPullSecret | toString }}" }} aws_access_key_id: |- @@ -78,7 +102,4 @@ spec: httpsProxy: "" noProxy: "" additionalTrustBundle: "" ---- -{{- end }} -{{- end }} -{{- end }} \ No newline at end of file +{{- end}} diff --git a/acm/templates/provision/secrets-azure.yaml b/acm/templates/provision/secrets-azure.yaml index 7fe6271b..21c9d482 100644 --- a/acm/templates/provision/secrets-azure.yaml +++ b/acm/templates/provision/secrets-azure.yaml @@ -3,58 +3,84 @@ {{- range .clusterPools }} {{- $poolName := print .name "-" $group.name }} {{- if .platform.azure }} +--- +{{- template "externalsecret.azure.creds" (dict "name" $poolName "context" . "secretStore" $.Values.secretStore) }} +--- +{{- template "externalsecret.azure.infra-creds" (dict "name" $poolName "context" . "secretStore" $.Values.secretStore) }} + +--- +{{- end }}{{- /* if .platform.azure */}} +{{- end }}{{- /* range .clusterPools */}} + +{{- range .clusterDeployments }} +{{- $deploymentName := print .name "-" $group.name }} +{{- if .platform.azure }} +--- +{{- template "externalsecret.azure.creds" (dict "name" $deploymentName "context" . "secretStore" $.Values.secretStore) }} +--- +{{- template "externalsecret.azure.infra-creds" (dict "name" $deploymentName "context" . "secretStore" $.Values.secretStore) }} + + +{{- end }}{{- /* if .platform.azure */}} +{{- end }}{{- /* range .clusterPools */}} + +{{- end }}{{- /* range .Values.clusterGroup.managedClusterGroups */}} + +{{- define "externalsecret.azure.creds" }} apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: - name: {{ $poolName }}-creds + name: {{ .name }}-creds spec: data: - secretKey: azureOsServicePrincipal remoteRef: - key: {{ default "secret/data/hub/azureOsServicePrincipal" .azureKeyPath }} + key: {{ default "secret/data/hub/azureOsServicePrincipal" .context.azureKeyPath }} property: content refreshInterval: 24h0m0s secretStoreRef: - name: {{ $.Values.secretStore.name }} - kind: {{ $.Values.secretStore.kind }} + name: {{ .secretStore.name }} + kind: {{ .secretStore.kind }} target: - name: {{ $poolName }}-creds + name: {{ .name }}-creds creationPolicy: Owner template: type: Opaque data: osServicePrincipal.json: |- {{ "{{ .azureOsServicePrincipal | toString }}" }} ---- +{{- end }} + +{{- define "externalsecret.azure.infra-creds"}} # For use when manually creating clusters with ACM apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: - name: {{ $poolName }}-infra-creds -spec: + name: {{ .name }}-infra-creds +spec: data: - secretKey: openshiftPullSecret remoteRef: - key: {{ default "secret/data/hub/openshiftPullSecret" .pullSecretKeyPath }} + key: {{ default "secret/data/hub/openshiftPullSecret" .context.pullSecretKeyPath }} property: content - secretKey: sshPublicKey remoteRef: - key: {{ default "secret/data/hub/publickey" .sshPublicKeyPath }} + key: {{ default "secret/data/hub/publickey" .context.sshPublicKeyPath }} property: content - secretKey: sshPrivateKey remoteRef: - key: {{ default "secret/data/hub/privatekey" .sshPrivateKeyPath }} + key: {{ default "secret/data/hub/privatekey" .context.sshPrivateKeyPath }} property: content - secretKey: azureOsServicePrincipal remoteRef: - key: {{ default "secret/data/hub/azureOsServicePrincipal" .azureKeyPath }} + key: {{ default "secret/data/hub/azureOsServicePrincipal" .context.azureKeyPath }} property: content refreshInterval: 24h0m0s - secretStoreRef: - name: {{ $.Values.secretStore.name }} - kind: {{ $.Values.secretStore.kind }} + secretStoreRef: + name: {{ .secretStore.name }} + kind: {{ .secretStore.kind }} target: - name: {{ $poolName }}-infra-creds + name: {{ .name }}-infra-creds creationPolicy: Owner template: type: Opaque @@ -66,8 +92,8 @@ spec: cloudName: AzurePublicCloud osServicePrincipal.json: |- {{ "{{ .azureOsServicePrincipal | toString }}" }} - baseDomain: "{{ .baseDomain }}" - baseDomainResourceGroupName: "{{ .platform.azure.baseDomainResourceGroupName | toString }}" + baseDomain: "{{ .context.baseDomain }}" + baseDomainResourceGroupName: "{{ .context.platform.azure.baseDomainResourceGroupName | toString }}" pullSecret: |- {{ "{{ .openshiftPullSecret | toString }}" }} ssh-privatekey: |- @@ -78,7 +104,4 @@ spec: httpsProxy: "" noProxy: "" additionalTrustBundle: "" ---- -{{- end }} -{{- end }} {{- end }} diff --git a/acm/templates/provision/secrets-common.yaml b/acm/templates/provision/secrets-common.yaml index 21a03b73..474347c6 100644 --- a/acm/templates/provision/secrets-common.yaml +++ b/acm/templates/provision/secrets-common.yaml @@ -1,61 +1,86 @@ {{- range .Values.clusterGroup.managedClusterGroups }} {{- $group := . }} + {{- range .clusterPools }} {{- $poolName := print .name "-" $group.name }} +--- +{{- template "secret.install-config" (dict "name" $poolName "context" .) }} +--- +{{- template "externalsecret.pull-secret" (dict "name" $poolName "context" . "secretStore" $.Values.secretStore) }} +--- +{{- template "externalsecret.ssh.private.key" (dict "name" $poolName "context" . "secretStore" $.Values.secretStore) }} +{{- end }}{{- /* range .clusterPools */}} + +{{- range .clusterDeployments }} +{{- $deploymentName := print .name "-" $group.name }} +--- +{{- template "secret.install-config" (dict "name" $deploymentName "context" .) }} +--- +{{- template "externalsecret.pull-secret" (dict "name" $deploymentName "context" . "secretStore" $.Values.secretStore) }} +--- +{{- template "externalsecret.ssh.private.key" (dict "name" $deploymentName "context" . "secretStore" $.Values.secretStore) }} +{{- end }}{{- /* range .clusterDeplyments */}} + +{{- end }}{{- /* range .Values.clusterGroup.managedClusterGroups */}} + +{{- define "secret.install-config"}} apiVersion: v1 kind: Secret metadata: - name: {{ $poolName }}-install-config + name: {{ .name }}-install-config data: # Base64 encoding of install-config yaml - install-config.yaml: {{ include "cluster.install-config" . | b64enc }} + install-config.yaml: {{ include "cluster.install-config" .context | b64enc }} type: Opaque ---- +{{- end }} + +{{- define "externalsecret.pull-secret" }} apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: - name: {{ $poolName }}-pull-secret -spec: + name: {{ .name }}-pull-secret +spec: data: - secretKey: openshiftPullSecret remoteRef: - key: {{ default "secret/data/hub/openshiftPullSecret" .pullSecretKeyPath }} + key: {{ default "secret/data/hub/openshiftPullSecret" .context.pullSecretKeyPath }} property: content refreshInterval: 24h0m0s secretStoreRef: - name: {{ $.Values.secretStore.name }} - kind: {{ $.Values.secretStore.kind }} + name: {{ .secretStore.name }} + kind: {{ .secretStore.kind }} target: - name: {{ $poolName }}-pull-secret + name: {{ .name }}-pull-secret creationPolicy: Owner template: type: kubernetes.io/dockerconfigjson data: .dockerconfigjson: |- {{ "{{ .openshiftPullSecret | toString }}" }} ---- +{{- end }} + + +{{- define "externalsecret.ssh.private.key" }} apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: - name: {{ $poolName }}-ssh-private-key + name: {{ .name }}-ssh-private-key spec: data: - secretKey: sshPrivateKey remoteRef: - key: {{ default "secret/data/hub/privatekey" .sshPrivateKeyPath }} + key: {{ default "secret/data/hub/privatekey" .context.sshPrivateKeyPath }} property: content refreshInterval: 24h0m0s secretStoreRef: - name: {{ $.Values.secretStore.name }} - kind: {{ $.Values.secretStore.kind }} + name: {{ .secretStore.name }} + kind: {{ .secretStore.kind }} target: - name: {{ $poolName }}-ssh-private-key + name: {{ .name }}-ssh-private-key creationPolicy: Owner template: type: Opaque data: ssh-privatekey: |- {{ "{{ .sshPrivateKey | toString }}" }} ---- -{{- end }} {{- end }} diff --git a/acm/values.yaml b/acm/values.yaml index fb7cb03a..54c84a2e 100644 --- a/acm/values.yaml +++ b/acm/values.yaml @@ -21,14 +21,29 @@ clusterGroup: # testPool: # name: spoke # openshiftVersion: 4.10.18 -# provider: -# region: ap-southeast-2 -# baseDomain: blueprints.rhecoeng.com +# baseDomain: blueprints.rhecoeng.com +# platform: +# aws: +# region: ap-southeast-2 # clusters: # - spoke1 # labels: # - name: clusterGroup # value: region-one +# testRegionTwo: +# name: region-two +# clusterDeployments: +# myFirstCluster: +# name: mcluster1 +# openshiftVersion: 4.10.18 +# baseDomain: blueprints.rhecoeng.com +# platform: +# azure: +# baseDomainResourceGroupName: dojo-dns-zones +# region: eastus +# labels: +# - name: clusterGroup +# value: region-two secretStore: name: vault-backend diff --git a/clustergroup/values.schema.json b/clustergroup/values.schema.json index cf14bf26..4b6190ae 100644 --- a/clustergroup/values.schema.json +++ b/clustergroup/values.schema.json @@ -741,6 +741,12 @@ "$ref": "#/definitions/ClusterPools" } }, + "clusterDeployments": { + "type": "object", + "items": { + "$ref": "#/definitions/ClusterDeployments" + } + }, "clusterSelector": { "type": "object", "additionalProperties": true @@ -788,6 +794,32 @@ ], "title": "ClusterPools" }, + "ClusterDeployments": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string" + }, + "openshiftVersion": { + "type": "string" + }, + "baseDomain": { + "type": "string" + }, + "platform": { + "type": "object", + "$ref": "#/definitions/ClusterPoolsPlatform" + } + }, + "required": [ + "name", + "openshiftVersion", + "baseDomain", + "platform" + ], + "title": "ClusterDeployments" + }, "ClusterPoolsPlatform": { "type": "object", "additionalProperties": false, From f9bf1f7842343181ee95c68d1126aa41087f6ee6 Mon Sep 17 00:00:00 2001 From: Tomer Figenblat Date: Tue, 16 Apr 2024 18:46:24 -0400 Subject: [PATCH 02/64] test: regenerated tests after clusterdeployment commit Co-authored-by: Alejandro Villegas Signed-off-by: Tomer Figenblat --- tests/acm-normal.expected.yaml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/acm-normal.expected.yaml b/tests/acm-normal.expected.yaml index 1a3f6e72..e83a83a6 100644 --- a/tests/acm-normal.expected.yaml +++ b/tests/acm-normal.expected.yaml @@ -6,7 +6,7 @@ metadata: name: aws-ap-acm-provision-edge-install-config data: # Base64 encoding of install-config yaml - install-config.yaml: CgphcGlWZXJzaW9uOiB2MQptZXRhZGF0YToKICBuYW1lOiAnYXdzLWFwJyAKYmFzZURvbWFpbjogYmx1ZXByaW50cy5yaGVjb2VuZy5jb20KY29udHJvbFBsYW5lOgogIGFyY2hpdGVjdHVyZTogYW1kNjQKICBoeXBlcnRocmVhZGluZzogRW5hYmxlZAogIG5hbWU6IGNvbnRyb2xQbGFuZQogIHJlcGxpY2FzOiAxCiAgcGxhdGZvcm06CiAgICBhd3M6CiAgICAgIHR5cGU6IG01LnhsYXJnZQpjb21wdXRlOgotIGh5cGVydGhyZWFkaW5nOiBFbmFibGVkCiAgYXJjaGl0ZWN0dXJlOiBhbWQ2NAogIG5hbWU6ICd3b3JrZXInCiAgcmVwbGljYXM6IDAKbmV0d29ya2luZzoKICBjbHVzdGVyTmV0d29yazoKICAtIGNpZHI6IDEwLjEyOC4wLjAvMTQKICAgIGhvc3RQcmVmaXg6IDIzCiAgbWFjaGluZU5ldHdvcms6CiAgLSBjaWRyOiAxMC4wLjAuMC8xNgogIG5ldHdvcmtUeXBlOiBPVk5LdWJlcm5ldGVzCiAgc2VydmljZU5ldHdvcms6CiAgLSAxNzIuMzAuMC4wLzE2CnBsYXRmb3JtOgogIGF3czoKICAgIHJlZ2lvbjogYXAtc291dGhlYXN0LTIKcHVsbFNlY3JldDogIiIgIyBza2lwLCBoaXZlIHdpbGwgaW5qZWN0IGJhc2VkIG9uIGl0J3Mgc2VjcmV0cwpzc2hLZXk6ICIiICAgICAjIHNraXAsIGhpdmUgd2lsbCBpbmplY3QgYmFzZWQgb24gaXQncyBzZWNyZXRz + install-config.yaml: CgphcGlWZXJzaW9uOiB2MQptZXRhZGF0YToKICBuYW1lOiAnYXdzLWFwJyAKYmFzZURvbWFpbjogYmx1ZXByaW50cy5yaGVjb2VuZy5jb20KY29udHJvbFBsYW5lOgogIGFyY2hpdGVjdHVyZTogYW1kNjQKICBoeXBlcnRocmVhZGluZzogRW5hYmxlZAogIG5hbWU6IGNvbnRyb2xQbGFuZQogIHJlcGxpY2FzOiAxCiAgcGxhdGZvcm06CiAgICBhd3M6CiAgICAgIHR5cGU6IG01LnhsYXJnZQpjb21wdXRlOgotIGh5cGVydGhyZWFkaW5nOiBFbmFibGVkCiAgYXJjaGl0ZWN0dXJlOiBhbWQ2NAogIG5hbWU6ICd3b3JrZXInCiAgcmVwbGljYXM6IDAKbmV0d29ya2luZzoKICBjbHVzdGVyTmV0d29yazoKICAtIGNpZHI6IDEwLjEyOC4wLjAvMTQKICAgIGhvc3RQcmVmaXg6IDIzCiAgbWFjaGluZU5ldHdvcms6CiAgLSBjaWRyOiAxMC4wLjAuMC8xNgogIG5ldHdvcmtUeXBlOiBPVk5LdWJlcm5ldGVzCiAgc2VydmljZU5ldHdvcms6CiAgLSAxNzIuMzAuMC4wLzE2CnBsYXRmb3JtOgogIGF3czoKICAgIHJlZ2lvbjogYXAtc291dGhlYXN0LTIKcHVsbFNlY3JldDogIiIgIyBza2lwLCBoaXZlIHdpbGwgaW5qZWN0IGJhc2VkIG9uIGl0J3Mgc2VjcmV0cwpzc2hLZXk6ICIiICAgICAjIHNraXAsIGhpdmUgd2lsbCBpbmplY3QgYmFzZWQgb24gaXQncyBzZWNyZXRz type: Opaque --- # Source: acm/templates/provision/secrets-common.yaml @@ -16,7 +16,7 @@ metadata: name: azure-us-acm-provision-edge-install-config data: # Base64 encoding of install-config yaml - install-config.yaml: CgphcGlWZXJzaW9uOiB2MQptZXRhZGF0YToKICBuYW1lOiAnYXp1cmUtdXMnIApiYXNlRG9tYWluOiBibHVlcHJpbnRzLnJoZWNvZW5nLmNvbQpjb250cm9sUGxhbmU6CiAgYXJjaGl0ZWN0dXJlOiBhbWQ2NAogIGh5cGVydGhyZWFkaW5nOiBFbmFibGVkCiAgbmFtZTogY29udHJvbFBsYW5lCiAgcmVwbGljYXM6IDMKICBwbGF0Zm9ybToKICAgIGF6dXJlOgogICAgICB0eXBlOiBTdGFuZGFyZF9EOHNfdjMKY29tcHV0ZToKLSBoeXBlcnRocmVhZGluZzogRW5hYmxlZAogIGFyY2hpdGVjdHVyZTogYW1kNjQKICBuYW1lOiAnd29ya2VyJwogIHJlcGxpY2FzOiAzCiAgcGxhdGZvcm06CiAgICBhenVyZToKICAgICAgdHlwZTogU3RhbmRhcmRfRDhzX3YzCm5ldHdvcmtpbmc6CiAgY2x1c3Rlck5ldHdvcms6CiAgLSBjaWRyOiAxMC4xMjguMC4wLzE0CiAgICBob3N0UHJlZml4OiAyMwogIG1hY2hpbmVOZXR3b3JrOgogIC0gY2lkcjogMTAuMC4wLjAvMTYKICBuZXR3b3JrVHlwZTogT1ZOS3ViZXJuZXRlcwogIHNlcnZpY2VOZXR3b3JrOgogIC0gMTcyLjMwLjAuMC8xNgpwbGF0Zm9ybToKICBhenVyZToKICAgIGJhc2VEb21haW5SZXNvdXJjZUdyb3VwTmFtZTogZG9qby1kbnMtem9uZXMKICAgIHJlZ2lvbjogZWFzdHVzCnB1bGxTZWNyZXQ6ICIiICMgc2tpcCwgaGl2ZSB3aWxsIGluamVjdCBiYXNlZCBvbiBpdCdzIHNlY3JldHMKc3NoS2V5OiAiIiAgICAgIyBza2lwLCBoaXZlIHdpbGwgaW5qZWN0IGJhc2VkIG9uIGl0J3Mgc2VjcmV0cw== + install-config.yaml: CgphcGlWZXJzaW9uOiB2MQptZXRhZGF0YToKICBuYW1lOiAnYXp1cmUtdXMnIApiYXNlRG9tYWluOiBibHVlcHJpbnRzLnJoZWNvZW5nLmNvbQpjb250cm9sUGxhbmU6CiAgYXJjaGl0ZWN0dXJlOiBhbWQ2NAogIGh5cGVydGhyZWFkaW5nOiBFbmFibGVkCiAgbmFtZTogY29udHJvbFBsYW5lCiAgcmVwbGljYXM6IDMKICBwbGF0Zm9ybToKICAgIGF6dXJlOgogICAgICB0eXBlOiBTdGFuZGFyZF9EOHNfdjMKY29tcHV0ZToKLSBoeXBlcnRocmVhZGluZzogRW5hYmxlZAogIGFyY2hpdGVjdHVyZTogYW1kNjQKICBuYW1lOiAnd29ya2VyJwogIHJlcGxpY2FzOiAzCiAgcGxhdGZvcm06CiAgICBhenVyZToKICAgICAgdHlwZTogU3RhbmRhcmRfRDhzX3YzCm5ldHdvcmtpbmc6CiAgY2x1c3Rlck5ldHdvcms6CiAgLSBjaWRyOiAxMC4xMjguMC4wLzE0CiAgICBob3N0UHJlZml4OiAyMwogIG1hY2hpbmVOZXR3b3JrOgogIC0gY2lkcjogMTAuMC4wLjAvMTYKICBuZXR3b3JrVHlwZTogT1ZOS3ViZXJuZXRlcwogIHNlcnZpY2VOZXR3b3JrOgogIC0gMTcyLjMwLjAuMC8xNgpwbGF0Zm9ybToKICBhenVyZToKICAgIGJhc2VEb21haW5SZXNvdXJjZUdyb3VwTmFtZTogZG9qby1kbnMtem9uZXMKICAgIHJlZ2lvbjogZWFzdHVzCnB1bGxTZWNyZXQ6ICIiICMgc2tpcCwgaGl2ZSB3aWxsIGluamVjdCBiYXNlZCBvbiBpdCdzIHNlY3JldHMKc3NoS2V5OiAiIiAgICAgIyBza2lwLCBoaXZlIHdpbGwgaW5qZWN0IGJhc2VkIG9uIGl0J3Mgc2VjcmV0cw== type: Opaque --- # Source: acm/templates/policies/acm-hub-ca-policy.yaml @@ -79,7 +79,7 @@ spec: runningCount: 0 baseDomain: blueprints.rhecoeng.com installConfigSecretTemplateRef: - name: aws-ap-acm-provision-edge-install-config + name: aws-ap-acm-provision-edge-install-config imageSetRef: name: img4.10.18-multi-appsub pullSecretRef: @@ -109,7 +109,7 @@ spec: runningCount: 2 baseDomain: blueprints.rhecoeng.com installConfigSecretTemplateRef: - name: azure-us-acm-provision-edge-install-config + name: azure-us-acm-provision-edge-install-config imageSetRef: name: img4.10.18-multi-appsub pullSecretRef: @@ -147,7 +147,7 @@ apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: aws-ap-acm-provision-edge-infra-creds -spec: +spec: data: - secretKey: openshiftPullSecret remoteRef: @@ -170,7 +170,7 @@ spec: key: secret/data/hub/privatekey property: content refreshInterval: 24h0m0s - secretStoreRef: + secretStoreRef: name: vault-backend kind: ClusterSecretStore target: @@ -229,7 +229,7 @@ apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: azure-us-acm-provision-edge-infra-creds -spec: +spec: data: - secretKey: openshiftPullSecret remoteRef: @@ -248,7 +248,7 @@ spec: key: secret/data/hub/azureOsServicePrincipal property: content refreshInterval: 24h0m0s - secretStoreRef: + secretStoreRef: name: vault-backend kind: ClusterSecretStore target: @@ -282,7 +282,7 @@ apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: aws-ap-acm-provision-edge-pull-secret -spec: +spec: data: - secretKey: openshiftPullSecret remoteRef: @@ -330,7 +330,7 @@ apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: azure-us-acm-provision-edge-pull-secret -spec: +spec: data: - secretKey: openshiftPullSecret remoteRef: @@ -373,8 +373,8 @@ spec: ssh-privatekey: |- {{ .sshPrivateKey | toString }} --- -# Source: acm/templates/provision/clusterpool.yaml -apiVersion: cluster.open-cluster-management.io/v1beta1 +# Source: acm/templates/provision/managedclusterset.yaml +apiVersion: cluster.open-cluster-management.io/v1beta2 kind: ManagedClusterSet metadata: annotations: From 5b4e9038b1e9dca267137cccf5648b25c10c2665 Mon Sep 17 00:00:00 2001 From: Tomer Figenblat Date: Tue, 16 Apr 2024 20:03:57 -0400 Subject: [PATCH 03/64] test: updated test-cased and regeneated expectations Co-authored-by: Alejandro Villegas Signed-off-by: Tomer Figenblat --- examples/values-example.yaml | 23 +- tests/acm-normal.expected.yaml | 499 ++++++++++++++++++++++++ tests/clustergroup-normal.expected.yaml | 17 + 3 files changed, 536 insertions(+), 3 deletions(-) diff --git a/examples/values-example.yaml b/examples/values-example.yaml index 84682e20..b8b1dde9 100644 --- a/examples/values-example.yaml +++ b/examples/values-example.yaml @@ -15,7 +15,7 @@ clusterGroup: - /values/{{ .Values.global.clusterPlatform }}.yaml - /values/{{ .Values.global.clusterVersion }}.yaml - # + # # You can define namespaces using hashes and not as a list like so: # namespaces: # open-cluster-management: @@ -25,7 +25,7 @@ clusterGroup: # annotations: # openshift.io/cluster-monitoring: "true" # owner: "namespace owner" - # application-ci: + # application-ci: # You cannot mix list and hashes to define namespaces namespaces: - open-cluster-management: @@ -70,7 +70,7 @@ clusterGroup: name: openshift-pipelines-operator-rh csv: redhat-openshift-pipelines.v1.5.2 - # + # # You can define projects using hashes like so: # projects: # hub: @@ -159,9 +159,26 @@ clusterGroup: clusters: - Two - three + clusterDeployments: + myFirstCluster: + name: aws-cd-one-w-pool + openshiftVersion: 4.10.18 + baseDomain: blueprints.rhecoeng.com + platform: + aws: + region: ap-southeast-1 acmlabels: - name: clusterGroup value: region + - name: acm-provision-on-deploy + clusterDeployments: + mySecondCluster: + name: aws-cd-two-wo-pool + openshiftVersion: 4.10.18 + baseDomain: blueprints.rhecoeng.com + platform: + aws: + region: ap-southeast-3 - name: argo-edge hostedArgoSites: - name: perth diff --git a/tests/acm-normal.expected.yaml b/tests/acm-normal.expected.yaml index e83a83a6..1e63d2e7 100644 --- a/tests/acm-normal.expected.yaml +++ b/tests/acm-normal.expected.yaml @@ -1,4 +1,16 @@ --- +# Source: acm/templates/provision/clusterdeployment.yaml +apiVersion: v1 +kind: Namespace +metadata: + name: aws-cd-one-w-pool-acm-provision-edge +--- +# Source: acm/templates/provision/clusterdeployment.yaml +apiVersion: v1 +kind: Namespace +metadata: + name: aws-cd-two-wo-pool-acm-provision-on-deploy +--- # Source: acm/templates/provision/secrets-common.yaml apiVersion: v1 kind: Secret @@ -19,6 +31,26 @@ data: install-config.yaml: CgphcGlWZXJzaW9uOiB2MQptZXRhZGF0YToKICBuYW1lOiAnYXp1cmUtdXMnIApiYXNlRG9tYWluOiBibHVlcHJpbnRzLnJoZWNvZW5nLmNvbQpjb250cm9sUGxhbmU6CiAgYXJjaGl0ZWN0dXJlOiBhbWQ2NAogIGh5cGVydGhyZWFkaW5nOiBFbmFibGVkCiAgbmFtZTogY29udHJvbFBsYW5lCiAgcmVwbGljYXM6IDMKICBwbGF0Zm9ybToKICAgIGF6dXJlOgogICAgICB0eXBlOiBTdGFuZGFyZF9EOHNfdjMKY29tcHV0ZToKLSBoeXBlcnRocmVhZGluZzogRW5hYmxlZAogIGFyY2hpdGVjdHVyZTogYW1kNjQKICBuYW1lOiAnd29ya2VyJwogIHJlcGxpY2FzOiAzCiAgcGxhdGZvcm06CiAgICBhenVyZToKICAgICAgdHlwZTogU3RhbmRhcmRfRDhzX3YzCm5ldHdvcmtpbmc6CiAgY2x1c3Rlck5ldHdvcms6CiAgLSBjaWRyOiAxMC4xMjguMC4wLzE0CiAgICBob3N0UHJlZml4OiAyMwogIG1hY2hpbmVOZXR3b3JrOgogIC0gY2lkcjogMTAuMC4wLjAvMTYKICBuZXR3b3JrVHlwZTogT1ZOS3ViZXJuZXRlcwogIHNlcnZpY2VOZXR3b3JrOgogIC0gMTcyLjMwLjAuMC8xNgpwbGF0Zm9ybToKICBhenVyZToKICAgIGJhc2VEb21haW5SZXNvdXJjZUdyb3VwTmFtZTogZG9qby1kbnMtem9uZXMKICAgIHJlZ2lvbjogZWFzdHVzCnB1bGxTZWNyZXQ6ICIiICMgc2tpcCwgaGl2ZSB3aWxsIGluamVjdCBiYXNlZCBvbiBpdCdzIHNlY3JldHMKc3NoS2V5OiAiIiAgICAgIyBza2lwLCBoaXZlIHdpbGwgaW5qZWN0IGJhc2VkIG9uIGl0J3Mgc2VjcmV0cw== type: Opaque --- +# Source: acm/templates/provision/secrets-common.yaml +apiVersion: v1 +kind: Secret +metadata: + name: aws-cd-one-w-pool-acm-provision-edge-install-config +data: + # Base64 encoding of install-config yaml + install-config.yaml: CgphcGlWZXJzaW9uOiB2MQptZXRhZGF0YToKICBuYW1lOiAnYXdzLWNkLW9uZS13LXBvb2wnIApiYXNlRG9tYWluOiBibHVlcHJpbnRzLnJoZWNvZW5nLmNvbQpjb250cm9sUGxhbmU6CiAgYXJjaGl0ZWN0dXJlOiBhbWQ2NAogIGh5cGVydGhyZWFkaW5nOiBFbmFibGVkCiAgbmFtZTogY29udHJvbFBsYW5lCiAgcmVwbGljYXM6IDMKICBwbGF0Zm9ybToKICAgIGF3czoKICAgICAgdHlwZTogbTUueGxhcmdlCmNvbXB1dGU6Ci0gaHlwZXJ0aHJlYWRpbmc6IEVuYWJsZWQKICBhcmNoaXRlY3R1cmU6IGFtZDY0CiAgbmFtZTogJ3dvcmtlcicKICByZXBsaWNhczogMwogIHBsYXRmb3JtOgogICAgYXdzOgogICAgICB0eXBlOiBtNS54bGFyZ2UKbmV0d29ya2luZzoKICBjbHVzdGVyTmV0d29yazoKICAtIGNpZHI6IDEwLjEyOC4wLjAvMTQKICAgIGhvc3RQcmVmaXg6IDIzCiAgbWFjaGluZU5ldHdvcms6CiAgLSBjaWRyOiAxMC4wLjAuMC8xNgogIG5ldHdvcmtUeXBlOiBPVk5LdWJlcm5ldGVzCiAgc2VydmljZU5ldHdvcms6CiAgLSAxNzIuMzAuMC4wLzE2CnBsYXRmb3JtOgogIGF3czoKICAgIHJlZ2lvbjogYXAtc291dGhlYXN0LTEKcHVsbFNlY3JldDogIiIgIyBza2lwLCBoaXZlIHdpbGwgaW5qZWN0IGJhc2VkIG9uIGl0J3Mgc2VjcmV0cwpzc2hLZXk6ICIiICAgICAjIHNraXAsIGhpdmUgd2lsbCBpbmplY3QgYmFzZWQgb24gaXQncyBzZWNyZXRz +type: Opaque +--- +# Source: acm/templates/provision/secrets-common.yaml +apiVersion: v1 +kind: Secret +metadata: + name: aws-cd-two-wo-pool-acm-provision-on-deploy-install-config +data: + # Base64 encoding of install-config yaml + install-config.yaml: CgphcGlWZXJzaW9uOiB2MQptZXRhZGF0YToKICBuYW1lOiAnYXdzLWNkLXR3by13by1wb29sJyAKYmFzZURvbWFpbjogYmx1ZXByaW50cy5yaGVjb2VuZy5jb20KY29udHJvbFBsYW5lOgogIGFyY2hpdGVjdHVyZTogYW1kNjQKICBoeXBlcnRocmVhZGluZzogRW5hYmxlZAogIG5hbWU6IGNvbnRyb2xQbGFuZQogIHJlcGxpY2FzOiAzCiAgcGxhdGZvcm06CiAgICBhd3M6CiAgICAgIHR5cGU6IG01LnhsYXJnZQpjb21wdXRlOgotIGh5cGVydGhyZWFkaW5nOiBFbmFibGVkCiAgYXJjaGl0ZWN0dXJlOiBhbWQ2NAogIG5hbWU6ICd3b3JrZXInCiAgcmVwbGljYXM6IDMKICBwbGF0Zm9ybToKICAgIGF3czoKICAgICAgdHlwZTogbTUueGxhcmdlCm5ldHdvcmtpbmc6CiAgY2x1c3Rlck5ldHdvcms6CiAgLSBjaWRyOiAxMC4xMjguMC4wLzE0CiAgICBob3N0UHJlZml4OiAyMwogIG1hY2hpbmVOZXR3b3JrOgogIC0gY2lkcjogMTAuMC4wLjAvMTYKICBuZXR3b3JrVHlwZTogT1ZOS3ViZXJuZXRlcwogIHNlcnZpY2VOZXR3b3JrOgogIC0gMTcyLjMwLjAuMC8xNgpwbGF0Zm9ybToKICBhd3M6CiAgICByZWdpb246IGFwLXNvdXRoZWFzdC0zCnB1bGxTZWNyZXQ6ICIiICMgc2tpcCwgaGl2ZSB3aWxsIGluamVjdCBiYXNlZCBvbiBpdCdzIHNlY3JldHMKc3NoS2V5OiAiIiAgICAgIyBza2lwLCBoaXZlIHdpbGwgaW5qZWN0IGJhc2VkIG9uIGl0J3Mgc2VjcmV0cw== +type: Opaque +--- # Source: acm/templates/policies/acm-hub-ca-policy.yaml # This pushes out the HUB's Certificate Authorities on to the imported clusters --- @@ -61,6 +93,60 @@ metadata: spec: clusterPoolName: azure-us-acm-provision-edge --- +# Source: acm/templates/provision/clusterdeployment.yaml +apiVersion: hive.openshift.io/v1 +kind: ClusterDeployment +metadata: + name: aws-cd-one-w-pool-acm-provision-edge + namespace: aws-cd-one-w-pool-acm-provision-edge + labels: + vendor: OpenShift +spec: + baseDomain: blueprints.rhecoeng.com + clusterName: aws-cd-one-w-pool-acm-provision-edge + installAttemptsLimit: 1 + platform: + aws: + credentialsSecretRef: + name: aws-cd-one-w-pool-acm-provision-edge-creds + region: ap-southeast-1 + provisioning: + installConfigSecretRef: + name: aws-cd-one-w-pool-acm-provision-edge-install-config + sshPrivateKeySecretRef: + name: aws-cd-one-w-pool-acm-provision-edge-ssh-private-key + imageSetRef: + name: img4.10.18-multi-appsub + pullSecretRef: + name: aws-cd-one-w-pool-acm-provision-edge-pull-secret +--- +# Source: acm/templates/provision/clusterdeployment.yaml +apiVersion: hive.openshift.io/v1 +kind: ClusterDeployment +metadata: + name: aws-cd-two-wo-pool-acm-provision-on-deploy + namespace: aws-cd-two-wo-pool-acm-provision-on-deploy + labels: + vendor: OpenShift +spec: + baseDomain: blueprints.rhecoeng.com + clusterName: aws-cd-two-wo-pool-acm-provision-on-deploy + installAttemptsLimit: 1 + platform: + aws: + credentialsSecretRef: + name: aws-cd-two-wo-pool-acm-provision-on-deploy-creds + region: ap-southeast-3 + provisioning: + installConfigSecretRef: + name: aws-cd-two-wo-pool-acm-provision-on-deploy-install-config + sshPrivateKeySecretRef: + name: aws-cd-two-wo-pool-acm-provision-on-deploy-ssh-private-key + imageSetRef: + name: img4.10.18-multi-appsub + pullSecretRef: + name: aws-cd-two-wo-pool-acm-provision-on-deploy-pull-secret +--- # Source: acm/templates/provision/clusterpool.yaml apiVersion: hive.openshift.io/v1 kind: ClusterPool @@ -199,6 +285,162 @@ spec: noProxy: "" additionalTrustBundle: "" --- +# Source: acm/templates/provision/secrets-aws.yaml +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: aws-cd-one-w-pool-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-cd-one-w-pool-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-cd-one-w-pool-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-cd-one-w-pool-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-aws.yaml +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: aws-cd-two-wo-pool-acm-provision-on-deploy-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-cd-two-wo-pool-acm-provision-on-deploy-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-cd-two-wo-pool-acm-provision-on-deploy-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-cd-two-wo-pool-acm-provision-on-deploy-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 @@ -373,6 +615,124 @@ spec: ssh-privatekey: |- {{ .sshPrivateKey | toString }} --- +# Source: acm/templates/provision/secrets-common.yaml +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: aws-cd-one-w-pool-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-cd-one-w-pool-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-cd-one-w-pool-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-cd-one-w-pool-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: aws-cd-two-wo-pool-acm-provision-on-deploy-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-cd-two-wo-pool-acm-provision-on-deploy-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-cd-two-wo-pool-acm-provision-on-deploy-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-cd-two-wo-pool-acm-provision-on-deploy-ssh-private-key + creationPolicy: Owner + template: + type: Opaque + data: + ssh-privatekey: |- + {{ .sshPrivateKey | toString }} +--- +# Source: acm/templates/provision/clusterdeployment.yaml +apiVersion: cluster.open-cluster-management.io/v1 +kind: ManagedCluster +metadata: + labels: + cluster.open-cluster-management.io/clusterset: acm-provision-edge + clusterGroup: region + name: aws-cd-one-w-pool-acm-provision-edge +spec: + hubAcceptsClient: true +--- +# Source: acm/templates/provision/clusterdeployment.yaml +apiVersion: cluster.open-cluster-management.io/v1 +kind: ManagedCluster +metadata: + labels: + cluster.open-cluster-management.io/clusterset: acm-provision-on-deploy + clusterGroup: acm-provision-on-deploy + name: aws-cd-two-wo-pool-acm-provision-on-deploy +spec: + hubAcceptsClient: true +--- # Source: acm/templates/provision/managedclusterset.yaml apiVersion: cluster.open-cluster-management.io/v1beta2 kind: ManagedClusterSet @@ -385,6 +745,18 @@ spec: clusterSelector: selectorType: LegacyClusterSetLabel --- +# Source: acm/templates/provision/managedclusterset.yaml +apiVersion: cluster.open-cluster-management.io/v1beta2 +kind: ManagedClusterSet +metadata: + annotations: + cluster.open-cluster-management.io/submariner-broker-ns: acm-provision-on-deploy-broker + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + name: acm-provision-on-deploy +spec: + clusterSelector: + selectorType: LegacyClusterSetLabel +--- # Source: acm/templates/multiclusterhub.yaml apiVersion: operator.open-cluster-management.io/v1 kind: MultiClusterHub @@ -444,6 +816,22 @@ subjects: 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-on-deploy-placement-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: acm-provision-on-deploy-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: acm-provision-on-deploy-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 @@ -508,6 +896,21 @@ spec: matchLabels: clusterGroup: region --- +# Source: acm/templates/policies/application-policies.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: acm-provision-on-deploy-placement + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchLabels: + clusterGroup: acm-provision-on-deploy +--- # Source: acm/templates/policies/ocp-gitops-policy.yaml apiVersion: apps.open-cluster-management.io/v1 kind: PlacementRule @@ -763,6 +1166,102 @@ spec: jsonPointers: - /status --- +# Source: acm/templates/policies/application-policies.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: acm-provision-on-deploy-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-on-deploy-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-on-deploy + 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-on-deploy.yaml" + - '/values-{{ (lookup "config.openshift.io/v1" "Infrastructure" "" "cluster").spec.platformSpec.type }}.yaml' + - '/values-{{ (lookup "config.openshift.io/v1" "Infrastructure" "" "cluster").spec.platformSpec.type }}-{{ printf "%d.%d" ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Major) ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Minor) }}.yaml' + - '/values-{{ (lookup "config.openshift.io/v1" "Infrastructure" "" "cluster").spec.platformSpec.type }}-acm-provision-on-deploy.yaml' + # We cannot use $.Values.global.clusterVersion because that gets resolved to the + # hub's cluster version, whereas we want to include the spoke cluster version + - '/values-{{ printf "%d.%d" ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Major) ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Minor) }}.yaml' + parameters: + - name: global.repoURL + value: https://github.com/pattern-clone/mypattern + - name: global.targetRevision + value: main + - 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." "" }}' + # Requires ACM 2.6 or higher (I could not come up with something less terrible to get maj.min) + - name: global.clusterVersion + value: '{{ printf "%d.%d" ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Major) ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Minor) }}' + - name: global.localClusterName + value: '{{ (split "." (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain)._1 }}' + - name: global.clusterPlatform + value: aws + - name: clusterGroup.name + value: acm-provision-on-deploy + - name: global.experimentalCapabilities + value: + destination: + server: https://kubernetes.default.svc + namespace: mypattern-acm-provision-on-deploy + syncPolicy: + automated: + prune: false + selfHeal: true + retry: + limit: 20 + 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/tests/clustergroup-normal.expected.yaml b/tests/clustergroup-normal.expected.yaml index 8d3d4d51..e449dd9c 100644 --- a/tests/clustergroup-normal.expected.yaml +++ b/tests/clustergroup-normal.expected.yaml @@ -160,6 +160,14 @@ data: - acmlabels: - name: clusterGroup value: region + clusterDeployments: + myFirstCluster: + baseDomain: blueprints.rhecoeng.com + name: aws-cd-one-w-pool + openshiftVersion: 4.10.18 + platform: + aws: + region: ap-southeast-1 clusterPools: exampleAWSPool: baseDomain: blueprints.rhecoeng.com @@ -192,6 +200,15 @@ data: value: "false" name: acm-provision-edge targetRevision: main + - clusterDeployments: + mySecondCluster: + baseDomain: blueprints.rhecoeng.com + name: aws-cd-two-wo-pool + openshiftVersion: 4.10.18 + platform: + aws: + region: ap-southeast-3 + name: acm-provision-on-deploy - helmOverrides: - name: clusterGroup.isHubCluster value: "false" From a073b8c4c8101c42cc7f8c52b81b3c2a5324a667 Mon Sep 17 00:00:00 2001 From: Tomer Figenblat Date: Tue, 23 Apr 2024 17:07:47 -0400 Subject: [PATCH 04/64] chore: added annotations controling gitops and fail for missing meta for clusterdeployments Signed-off-by: Tomer Figenblat --- acm/templates/provision/clusterdeployment.yaml | 12 ++++++++++++ tests/acm-normal.expected.yaml | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/acm/templates/provision/clusterdeployment.yaml b/acm/templates/provision/clusterdeployment.yaml index cc37c161..f7f71a52 100644 --- a/acm/templates/provision/clusterdeployment.yaml +++ b/acm/templates/provision/clusterdeployment.yaml @@ -3,6 +3,14 @@ {{- range $group.clusterDeployments}} {{ $cluster := . }} + +{{- if (eq $cluster.name nil) }} +{{- fail (printf "managedClusterGroup clusterDeployment cluster name is empty: %s" $cluster) }} +{{- end }} +{{- if (eq $group.name nil) }} +{{- fail (printf "managedClusterGroup clusterDeployment group name is empty: %s" $cluster) }} +{{- end }} + {{- $deploymentName := print $cluster.name "-" $group.name }} {{- $cloud := "None" }} @@ -30,6 +38,8 @@ metadata: namespace: {{ $deploymentName }} labels: vendor: OpenShift + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true spec: baseDomain: {{ $cluster.baseDomain }} clusterName: {{ $deploymentName }} @@ -65,6 +75,8 @@ metadata: {{- end }} {{- end }} name: {{ $deploymentName }} + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true spec: hubAcceptsClient: true {{- end }}{{- /* range $group.clusterDeployments */}} diff --git a/tests/acm-normal.expected.yaml b/tests/acm-normal.expected.yaml index 1e63d2e7..b3627634 100644 --- a/tests/acm-normal.expected.yaml +++ b/tests/acm-normal.expected.yaml @@ -101,6 +101,8 @@ metadata: namespace: aws-cd-one-w-pool-acm-provision-edge labels: vendor: OpenShift + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true spec: baseDomain: blueprints.rhecoeng.com clusterName: aws-cd-one-w-pool-acm-provision-edge @@ -128,6 +130,8 @@ metadata: namespace: aws-cd-two-wo-pool-acm-provision-on-deploy labels: vendor: OpenShift + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true spec: baseDomain: blueprints.rhecoeng.com clusterName: aws-cd-two-wo-pool-acm-provision-on-deploy @@ -719,6 +723,8 @@ metadata: cluster.open-cluster-management.io/clusterset: acm-provision-edge clusterGroup: region name: aws-cd-one-w-pool-acm-provision-edge + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true spec: hubAcceptsClient: true --- @@ -730,6 +736,8 @@ metadata: cluster.open-cluster-management.io/clusterset: acm-provision-on-deploy clusterGroup: acm-provision-on-deploy name: aws-cd-two-wo-pool-acm-provision-on-deploy + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true spec: hubAcceptsClient: true --- From c6ffd0ecdab72ff98f3cf89271ab4c5433c9f5bf Mon Sep 17 00:00:00 2001 From: Tomer Figenblat Date: Fri, 26 Apr 2024 11:05:33 -0400 Subject: [PATCH 05/64] chore: removed managedclusterset spec Signed-off-by: Tomer Figenblat --- acm/templates/provision/managedclusterset.yaml | 3 --- tests/acm-normal.expected.yaml | 6 ------ 2 files changed, 9 deletions(-) diff --git a/acm/templates/provision/managedclusterset.yaml b/acm/templates/provision/managedclusterset.yaml index dce01f73..2c8eaffa 100644 --- a/acm/templates/provision/managedclusterset.yaml +++ b/acm/templates/provision/managedclusterset.yaml @@ -8,9 +8,6 @@ metadata: cluster.open-cluster-management.io/submariner-broker-ns: {{ .name }}-broker argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true name: {{ .name }} -spec: - clusterSelector: - selectorType: LegacyClusterSetLabel {{- end }}{{- /* if .clusterPools) */}} {{- end }}{{- /* range .Values.clusterGroup.managedClusterGroups */}} diff --git a/tests/acm-normal.expected.yaml b/tests/acm-normal.expected.yaml index b3627634..3e6fbc74 100644 --- a/tests/acm-normal.expected.yaml +++ b/tests/acm-normal.expected.yaml @@ -749,9 +749,6 @@ metadata: cluster.open-cluster-management.io/submariner-broker-ns: acm-provision-edge-broker argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true name: acm-provision-edge -spec: - clusterSelector: - selectorType: LegacyClusterSetLabel --- # Source: acm/templates/provision/managedclusterset.yaml apiVersion: cluster.open-cluster-management.io/v1beta2 @@ -761,9 +758,6 @@ metadata: cluster.open-cluster-management.io/submariner-broker-ns: acm-provision-on-deploy-broker argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true name: acm-provision-on-deploy -spec: - clusterSelector: - selectorType: LegacyClusterSetLabel --- # Source: acm/templates/multiclusterhub.yaml apiVersion: operator.open-cluster-management.io/v1 From 3a4eaf900a3a2bae40730ab0a731972d590638fa Mon Sep 17 00:00:00 2001 From: "Sergio G." Date: Thu, 9 May 2024 22:12:08 +0200 Subject: [PATCH 06/64] Added support to label/annotate nodes --- clustergroup/templates/core/nodes.yaml | 25 ++++++ clustergroup/values.schema.json | 81 ++++++++++++++----- clustergroup/values.yaml | 7 +- examples/values-example.yaml | 11 +++ ...roup-industrial-edge-factory.expected.yaml | 1 + ...tergroup-industrial-edge-hub.expected.yaml | 1 + ...rgroup-medical-diagnosis-hub.expected.yaml | 1 + tests/clustergroup-naked.expected.yaml | 1 + tests/clustergroup-normal.expected.yaml | 37 +++++++++ 9 files changed, 142 insertions(+), 23 deletions(-) create mode 100644 clustergroup/templates/core/nodes.yaml diff --git a/clustergroup/templates/core/nodes.yaml b/clustergroup/templates/core/nodes.yaml new file mode 100644 index 00000000..5106447d --- /dev/null +++ b/clustergroup/templates/core/nodes.yaml @@ -0,0 +1,25 @@ +{{- if not (eq .Values.enabled "plumbing") }} +{{- range $node := .Values.clusterGroup.nodes }} +apiVersion: v1 +kind: Node +metadata: + {{- range $k, $v := $node }} + name: {{ $k }} + labels: + argocd.argoproj.io/managed-by: {{ $.Values.global.pattern }}-{{ $.Values.clusterGroup.name }} + {{- if $v.labels }} + {{- range $key, $value := $v.labels }} + {{ $key }}: {{ $value | default "" | quote }} + {{- end }} + {{- end }} + + {{- if $v.annotations }} + annotations: + {{- range $key, $value := $v.annotations }} + {{ $key }}: {{ $value | default "" | quote }} + {{- end }} + {{- end }}{{- /* if $v.annotations */}} + {{- end }}{{- /* range $k, $v := $node */}} +--- +{{- end -}} +{{- end -}} diff --git a/clustergroup/values.schema.json b/clustergroup/values.schema.json index 8d206957..76c997b4 100644 --- a/clustergroup/values.schema.json +++ b/clustergroup/values.schema.json @@ -271,6 +271,20 @@ "$ref": "#/definitions/Namespaces" } }, + "nodes": { + "anyOf": [ + { + "type": "array" + }, + { + "type": "object" + } + ], + "description": "Description of those nodes which ArgoCD will control the labels and/or annotations.", + "items": { + "$ref": "#/definitions/Nodes" + } + }, "indexImages": { "anyOf": [ { @@ -389,28 +403,51 @@ "type": "string" } ], - "description": "Description of the applications that will be created in the ArgoCD instances. The Application CRD is the Kubernetes resource object representing a deployed application instance in an environment. Two ways of defining applications: Using a list or using a dictionary.", - "additionalProperties": true, - "properties": { - "name": { - "type": "string", - "description": "Name of the namespace." - }, - "labels": { - "type": "array", - "items": { - "$ref": "#/definitions/NameValue" - } - }, - "annotations": { - "type": "array", - "items": { - "$ref": "#/definitions/NameValue" - } - } + "description": "Description of the applications that will be created in the ArgoCD instances. The Application CRD is the Kubernetes resource object representing a deployed application instance in an environment. Two ways of defining applications: Using a list or using a dictionary.", + "additionalProperties": true, + "properties": { + "name": { + "type": "string", + "description": "Name of the namespace." + }, + "labels": { + "type": "array", + "items": { + "$ref": "#/definitions/NameValue" + } + }, + "annotations": { + "type": "array", + "items": { + "$ref": "#/definitions/NameValue" } + } + } }, - "NameValue": { + "Nodes": { + "type": "object", + "description": "Description of those nodes which ArgoCD will control the labels and/or annotations.", + "additionalProperties": true, + "properties": { + "name": { + "type": "string", + "description": "Name of the node." + }, + "labels": { + "type": "array", + "items": { + "$ref": "#/definitions/NameValue" + } + }, + "annotations": { + "type": "array", + "items": { + "$ref": "#/definitions/NameValue" + } + } + } + }, + "NameValue": { "type": "object", "description": "Description of the applications that will be created in the ArgoCD instances. The Application CRD is the Kubernetes resource object representing a deployed application instance in an environment. Two ways of defining applications: Using a list or using a dictionary.", "additionalProperties": true, @@ -423,8 +460,8 @@ "type": "string", "description": "Name of the namespace." } - } - }, + } + }, "Applications": { "type": "object", "description": "Description of the applications that will be created in the ArgoCD instances. The Application CRD is the Kubernetes resource object representing a deployed application instance in an environment. Two ways of defining applications: Using a list or using a dictionary.", diff --git a/clustergroup/values.yaml b/clustergroup/values.yaml index c3611241..9b9f943e 100644 --- a/clustergroup/values.yaml +++ b/clustergroup/values.yaml @@ -10,7 +10,6 @@ global: installPlanApproval: Automatic applicationRetryLimit: 20 - enabled: "all" # Note that sometimes changing helm values might require a hard refresh (https://github.com/helm/helm/issues/3486) @@ -73,6 +72,12 @@ clusterGroup: # - OpenShift # # - open-cluster-management +# + nodes: [] +# nodes: +# - m-m00.mycluster.domain.tld: +# labels: +# cluster.ocs.openshift.io/openshift-storage: "" # subscriptions: {} # - name: advanced-cluster-management diff --git a/examples/values-example.yaml b/examples/values-example.yaml index 84682e20..542ec7c9 100644 --- a/examples/values-example.yaml +++ b/examples/values-example.yaml @@ -50,6 +50,17 @@ clusterGroup: - include-default-og: operatorGroup: true + nodes: + - m-m00.cluster.example.tld: + labels: + cluster.ocs.openshift.io/openshift-storage: "" + - m-m01.cluster.example.tld: + labels: + cluster.ocs.openshift.io/openshift-storage: "" + - m-m02.cluster.example.tld: + labels: + cluster.ocs.openshift.io/openshift-storage: "" + operatorgroupExcludes: - exclude-og diff --git a/tests/clustergroup-industrial-edge-factory.expected.yaml b/tests/clustergroup-industrial-edge-factory.expected.yaml index c3eabd83..c9911469 100644 --- a/tests/clustergroup-industrial-edge-factory.expected.yaml +++ b/tests/clustergroup-industrial-edge-factory.expected.yaml @@ -152,6 +152,7 @@ data: - manuela-stormshift-machine-sensor - manuela-stormshift-messaging - manuela-factory-ml-workspace + nodes: [] operatorgroupExcludes: - manuela-factory-ml-workspace projects: diff --git a/tests/clustergroup-industrial-edge-hub.expected.yaml b/tests/clustergroup-industrial-edge-hub.expected.yaml index 393e530c..7b2b387c 100644 --- a/tests/clustergroup-industrial-edge-hub.expected.yaml +++ b/tests/clustergroup-industrial-edge-hub.expected.yaml @@ -291,6 +291,7 @@ data: - manuela-data-lake - staging - vault + nodes: [] operatorgroupExcludes: - manuela-ml-workspace projects: diff --git a/tests/clustergroup-medical-diagnosis-hub.expected.yaml b/tests/clustergroup-medical-diagnosis-hub.expected.yaml index f4933c53..b20cde33 100644 --- a/tests/clustergroup-medical-diagnosis-hub.expected.yaml +++ b/tests/clustergroup-medical-diagnosis-hub.expected.yaml @@ -270,6 +270,7 @@ data: - staging - vault - golang-external-secrets + nodes: [] projects: - hub - medical-diagnosis diff --git a/tests/clustergroup-naked.expected.yaml b/tests/clustergroup-naked.expected.yaml index 6f1c6b2e..d21a4f42 100644 --- a/tests/clustergroup-naked.expected.yaml +++ b/tests/clustergroup-naked.expected.yaml @@ -73,6 +73,7 @@ data: managedClusterGroups: {} name: example namespaces: [] + nodes: [] projects: [] sharedValueFiles: [] subscriptions: {} diff --git a/tests/clustergroup-normal.expected.yaml b/tests/clustergroup-normal.expected.yaml index baad3fd0..c7491805 100644 --- a/tests/clustergroup-normal.expected.yaml +++ b/tests/clustergroup-normal.expected.yaml @@ -234,6 +234,16 @@ data: operatorGroup: false - include-default-og: operatorGroup: true + nodes: + - m-m00.cluster.example.tld: + labels: + cluster.ocs.openshift.io/openshift-storage: "" + - m-m01.cluster.example.tld: + labels: + cluster.ocs.openshift.io/openshift-storage: "" + - m-m02.cluster.example.tld: + labels: + cluster.ocs.openshift.io/openshift-storage: "" operatorgroupExcludes: - exclude-og projects: @@ -1174,6 +1184,33 @@ spec: location: ApplicationMenu text: 'Example ArgoCD' --- +# Source: clustergroup/templates/core/nodes.yaml +apiVersion: v1 +kind: Node +metadata: + name: m-m00.cluster.example.tld + labels: + argocd.argoproj.io/managed-by: mypattern-example + cluster.ocs.openshift.io/openshift-storage: "" +--- +# Source: clustergroup/templates/core/nodes.yaml +apiVersion: v1 +kind: Node +metadata: + name: m-m01.cluster.example.tld + labels: + argocd.argoproj.io/managed-by: mypattern-example + cluster.ocs.openshift.io/openshift-storage: "" +--- +# Source: clustergroup/templates/core/nodes.yaml +apiVersion: v1 +kind: Node +metadata: + name: m-m02.cluster.example.tld + labels: + argocd.argoproj.io/managed-by: mypattern-example + cluster.ocs.openshift.io/openshift-storage: "" +--- # Source: clustergroup/templates/core/operatorgroup.yaml --- apiVersion: operators.coreos.com/v1 From 308d708f922e86383f8b4b8e1708a87d8625ff42 Mon Sep 17 00:00:00 2001 From: "Sergio G." Date: Thu, 9 May 2024 22:17:44 +0200 Subject: [PATCH 07/64] Added support to enable user workloads in control plane nodes --- clustergroup/templates/core/scheduler.yaml | 8 ++++++++ clustergroup/values.schema.json | 4 ++++ clustergroup/values.yaml | 2 ++ examples/values-example.yaml | 2 ++ tests/clustergroup-industrial-edge-factory.expected.yaml | 9 +++++++++ tests/clustergroup-industrial-edge-hub.expected.yaml | 9 +++++++++ tests/clustergroup-medical-diagnosis-hub.expected.yaml | 9 +++++++++ tests/clustergroup-naked.expected.yaml | 9 +++++++++ tests/clustergroup-normal.expected.yaml | 9 +++++++++ 9 files changed, 61 insertions(+) create mode 100644 clustergroup/templates/core/scheduler.yaml diff --git a/clustergroup/templates/core/scheduler.yaml b/clustergroup/templates/core/scheduler.yaml new file mode 100644 index 00000000..fd2cdb67 --- /dev/null +++ b/clustergroup/templates/core/scheduler.yaml @@ -0,0 +1,8 @@ +{{- if not (eq .Values.enabled "plumbing") }} +apiVersion: config.openshift.io/v1 +kind: Scheduler +metadata: + name: cluster +spec: + mastersSchedulable: {{ $.Values.clusterGroup.mastersSchedulable }} +{{- end -}} diff --git a/clustergroup/values.schema.json b/clustergroup/values.schema.json index 8d206957..8b6bfea6 100644 --- a/clustergroup/values.schema.json +++ b/clustergroup/values.schema.json @@ -257,6 +257,10 @@ "type": "array", "description": "Templated value file paths." }, + "mastersSchedulable": { + "type": "boolean", + "description": "if set to true, the control plane nodes will be marked as schedulable for user workloads also." + }, "namespaces": { "anyOf": [ { diff --git a/clustergroup/values.yaml b/clustergroup/values.yaml index c3611241..2b1018da 100644 --- a/clustergroup/values.yaml +++ b/clustergroup/values.yaml @@ -20,6 +20,8 @@ clusterGroup: targetCluster: in-cluster sharedValueFiles: [] + mastersSchedulable: false + argoCD: initContainers: [] configManagementPlugins: [] diff --git a/examples/values-example.yaml b/examples/values-example.yaml index 84682e20..d5b45f71 100644 --- a/examples/values-example.yaml +++ b/examples/values-example.yaml @@ -15,6 +15,8 @@ clusterGroup: - /values/{{ .Values.global.clusterPlatform }}.yaml - /values/{{ .Values.global.clusterVersion }}.yaml + mastersSchedulable: true + # # You can define namespaces using hashes and not as a list like so: # namespaces: diff --git a/tests/clustergroup-industrial-edge-factory.expected.yaml b/tests/clustergroup-industrial-edge-factory.expected.yaml index c3eabd83..727a2b4f 100644 --- a/tests/clustergroup-industrial-edge-factory.expected.yaml +++ b/tests/clustergroup-industrial-edge-factory.expected.yaml @@ -146,6 +146,7 @@ data: verbosity: "" isHubCluster: false managedClusterGroups: {} + mastersSchedulable: false name: factory namespaces: - manuela-stormshift-line-dashboard @@ -774,6 +775,14 @@ spec: targetNamespaces: - manuela-stormshift-messaging --- +# Source: clustergroup/templates/core/scheduler.yaml +apiVersion: config.openshift.io/v1 +kind: Scheduler +metadata: + name: cluster +spec: + mastersSchedulable: false +--- # Source: clustergroup/templates/core/subscriptions.yaml apiVersion: operators.coreos.com/v1alpha1 kind: Subscription diff --git a/tests/clustergroup-industrial-edge-hub.expected.yaml b/tests/clustergroup-industrial-edge-hub.expected.yaml index 393e530c..cf2e69ea 100644 --- a/tests/clustergroup-industrial-edge-hub.expected.yaml +++ b/tests/clustergroup-industrial-edge-hub.expected.yaml @@ -280,6 +280,7 @@ data: - name: clusterGroup.isHubCluster value: "false" name: factory + mastersSchedulable: false name: datacenter namespaces: - golang-external-secrets @@ -1547,6 +1548,14 @@ spec: targetNamespaces: - vault --- +# Source: clustergroup/templates/core/scheduler.yaml +apiVersion: config.openshift.io/v1 +kind: Scheduler +metadata: + name: cluster +spec: + mastersSchedulable: false +--- # Source: clustergroup/templates/core/subscriptions.yaml apiVersion: operators.coreos.com/v1alpha1 kind: Subscription diff --git a/tests/clustergroup-medical-diagnosis-hub.expected.yaml b/tests/clustergroup-medical-diagnosis-hub.expected.yaml index f4933c53..3226ebd7 100644 --- a/tests/clustergroup-medical-diagnosis-hub.expected.yaml +++ b/tests/clustergroup-medical-diagnosis-hub.expected.yaml @@ -259,6 +259,7 @@ data: - name: clusterGroup.isHubCluster value: false name: region-one + mastersSchedulable: false name: hub namespaces: - open-cluster-management @@ -1705,6 +1706,14 @@ spec: targetNamespaces: - golang-external-secrets --- +# Source: clustergroup/templates/core/scheduler.yaml +apiVersion: config.openshift.io/v1 +kind: Scheduler +metadata: + name: cluster +spec: + mastersSchedulable: false +--- # Source: clustergroup/templates/core/subscriptions.yaml apiVersion: operators.coreos.com/v1alpha1 kind: Subscription diff --git a/tests/clustergroup-naked.expected.yaml b/tests/clustergroup-naked.expected.yaml index 6f1c6b2e..5ab214b9 100644 --- a/tests/clustergroup-naked.expected.yaml +++ b/tests/clustergroup-naked.expected.yaml @@ -71,6 +71,7 @@ data: verbosity: "" isHubCluster: true managedClusterGroups: {} + mastersSchedulable: false name: example namespaces: [] projects: [] @@ -463,3 +464,11 @@ spec: href: 'https://example-gitops-server-common-example.' location: ApplicationMenu text: 'Example ArgoCD' +--- +# Source: clustergroup/templates/core/scheduler.yaml +apiVersion: config.openshift.io/v1 +kind: Scheduler +metadata: + name: cluster +spec: + mastersSchedulable: false diff --git a/tests/clustergroup-normal.expected.yaml b/tests/clustergroup-normal.expected.yaml index baad3fd0..18f43d52 100644 --- a/tests/clustergroup-normal.expected.yaml +++ b/tests/clustergroup-normal.expected.yaml @@ -211,6 +211,7 @@ data: - domain: syd.beekhof.net name: sydney name: argo-edge + mastersSchedulable: true name: example namespaces: - open-cluster-management: @@ -1217,6 +1218,14 @@ spec: targetNamespaces: - include-default-og --- +# Source: clustergroup/templates/core/scheduler.yaml +apiVersion: config.openshift.io/v1 +kind: Scheduler +metadata: + name: cluster +spec: + mastersSchedulable: true +--- # Source: clustergroup/templates/core/subscriptions.yaml apiVersion: operators.coreos.com/v1alpha1 kind: Subscription From 0123fc78e1de0ba539ef968b71a58d696038f0a6 Mon Sep 17 00:00:00 2001 From: "Sergio G." Date: Fri, 10 May 2024 00:04:09 +0200 Subject: [PATCH 08/64] Added full support for the scheduler --- clustergroup/templates/core/scheduler.yaml | 5 ++++- clustergroup/values.schema.json | 6 +++--- clustergroup/values.yaml | 5 ++++- examples/values-example.yaml | 3 ++- tests/clustergroup-industrial-edge-factory.expected.yaml | 9 --------- tests/clustergroup-industrial-edge-hub.expected.yaml | 9 --------- tests/clustergroup-medical-diagnosis-hub.expected.yaml | 9 --------- tests/clustergroup-naked.expected.yaml | 9 --------- tests/clustergroup-normal.expected.yaml | 3 ++- 9 files changed, 15 insertions(+), 43 deletions(-) diff --git a/clustergroup/templates/core/scheduler.yaml b/clustergroup/templates/core/scheduler.yaml index fd2cdb67..5061065e 100644 --- a/clustergroup/templates/core/scheduler.yaml +++ b/clustergroup/templates/core/scheduler.yaml @@ -1,8 +1,11 @@ {{- if not (eq .Values.enabled "plumbing") }} +{{- if hasKey .Values.clusterGroup "scheduler" }} apiVersion: config.openshift.io/v1 kind: Scheduler metadata: name: cluster spec: - mastersSchedulable: {{ $.Values.clusterGroup.mastersSchedulable }} +{{- toYaml .Values.clusterGroup.scheduler | nindent 2 }} {{- end -}} +{{- end -}} + diff --git a/clustergroup/values.schema.json b/clustergroup/values.schema.json index 8b6bfea6..c4f97634 100644 --- a/clustergroup/values.schema.json +++ b/clustergroup/values.schema.json @@ -257,9 +257,9 @@ "type": "array", "description": "Templated value file paths." }, - "mastersSchedulable": { - "type": "boolean", - "description": "if set to true, the control plane nodes will be marked as schedulable for user workloads also." + "scheduler": { + "type": "object", + "description": "If set, it will become the spec of the scheduler/cluster in the managed cluster." }, "namespaces": { "anyOf": [ diff --git a/clustergroup/values.yaml b/clustergroup/values.yaml index 2b1018da..bb149567 100644 --- a/clustergroup/values.yaml +++ b/clustergroup/values.yaml @@ -20,7 +20,10 @@ clusterGroup: targetCluster: in-cluster sharedValueFiles: [] - mastersSchedulable: false +# scheduler: +# mastersSchedulable: true +# defaultNodeSelector: type=user-node,region=east +# profile: HighNodeUtilization argoCD: initContainers: [] diff --git a/examples/values-example.yaml b/examples/values-example.yaml index d5b45f71..0226efe7 100644 --- a/examples/values-example.yaml +++ b/examples/values-example.yaml @@ -15,7 +15,8 @@ clusterGroup: - /values/{{ .Values.global.clusterPlatform }}.yaml - /values/{{ .Values.global.clusterVersion }}.yaml - mastersSchedulable: true + scheduler: + mastersSchedulable: true # # You can define namespaces using hashes and not as a list like so: diff --git a/tests/clustergroup-industrial-edge-factory.expected.yaml b/tests/clustergroup-industrial-edge-factory.expected.yaml index 727a2b4f..c3eabd83 100644 --- a/tests/clustergroup-industrial-edge-factory.expected.yaml +++ b/tests/clustergroup-industrial-edge-factory.expected.yaml @@ -146,7 +146,6 @@ data: verbosity: "" isHubCluster: false managedClusterGroups: {} - mastersSchedulable: false name: factory namespaces: - manuela-stormshift-line-dashboard @@ -775,14 +774,6 @@ spec: targetNamespaces: - manuela-stormshift-messaging --- -# Source: clustergroup/templates/core/scheduler.yaml -apiVersion: config.openshift.io/v1 -kind: Scheduler -metadata: - name: cluster -spec: - mastersSchedulable: false ---- # Source: clustergroup/templates/core/subscriptions.yaml apiVersion: operators.coreos.com/v1alpha1 kind: Subscription diff --git a/tests/clustergroup-industrial-edge-hub.expected.yaml b/tests/clustergroup-industrial-edge-hub.expected.yaml index cf2e69ea..393e530c 100644 --- a/tests/clustergroup-industrial-edge-hub.expected.yaml +++ b/tests/clustergroup-industrial-edge-hub.expected.yaml @@ -280,7 +280,6 @@ data: - name: clusterGroup.isHubCluster value: "false" name: factory - mastersSchedulable: false name: datacenter namespaces: - golang-external-secrets @@ -1548,14 +1547,6 @@ spec: targetNamespaces: - vault --- -# Source: clustergroup/templates/core/scheduler.yaml -apiVersion: config.openshift.io/v1 -kind: Scheduler -metadata: - name: cluster -spec: - mastersSchedulable: false ---- # Source: clustergroup/templates/core/subscriptions.yaml apiVersion: operators.coreos.com/v1alpha1 kind: Subscription diff --git a/tests/clustergroup-medical-diagnosis-hub.expected.yaml b/tests/clustergroup-medical-diagnosis-hub.expected.yaml index 3226ebd7..f4933c53 100644 --- a/tests/clustergroup-medical-diagnosis-hub.expected.yaml +++ b/tests/clustergroup-medical-diagnosis-hub.expected.yaml @@ -259,7 +259,6 @@ data: - name: clusterGroup.isHubCluster value: false name: region-one - mastersSchedulable: false name: hub namespaces: - open-cluster-management @@ -1706,14 +1705,6 @@ spec: targetNamespaces: - golang-external-secrets --- -# Source: clustergroup/templates/core/scheduler.yaml -apiVersion: config.openshift.io/v1 -kind: Scheduler -metadata: - name: cluster -spec: - mastersSchedulable: false ---- # Source: clustergroup/templates/core/subscriptions.yaml apiVersion: operators.coreos.com/v1alpha1 kind: Subscription diff --git a/tests/clustergroup-naked.expected.yaml b/tests/clustergroup-naked.expected.yaml index 5ab214b9..6f1c6b2e 100644 --- a/tests/clustergroup-naked.expected.yaml +++ b/tests/clustergroup-naked.expected.yaml @@ -71,7 +71,6 @@ data: verbosity: "" isHubCluster: true managedClusterGroups: {} - mastersSchedulable: false name: example namespaces: [] projects: [] @@ -464,11 +463,3 @@ spec: href: 'https://example-gitops-server-common-example.' location: ApplicationMenu text: 'Example ArgoCD' ---- -# Source: clustergroup/templates/core/scheduler.yaml -apiVersion: config.openshift.io/v1 -kind: Scheduler -metadata: - name: cluster -spec: - mastersSchedulable: false diff --git a/tests/clustergroup-normal.expected.yaml b/tests/clustergroup-normal.expected.yaml index 18f43d52..3e2e2849 100644 --- a/tests/clustergroup-normal.expected.yaml +++ b/tests/clustergroup-normal.expected.yaml @@ -211,7 +211,6 @@ data: - domain: syd.beekhof.net name: sydney name: argo-edge - mastersSchedulable: true name: example namespaces: - open-cluster-management: @@ -239,6 +238,8 @@ data: - exclude-og projects: - datacenter + scheduler: + mastersSchedulable: true sharedValueFiles: - /values/aws.yaml - /values/4.12.yaml From 48b584e59c7129d104fa4b53b27cec11729cf09b Mon Sep 17 00:00:00 2001 From: "Sergio G." Date: Fri, 10 May 2024 00:21:37 +0200 Subject: [PATCH 09/64] Simplified PR for auto approve install plans --- .../auto-approve-installplans.yaml | 40 ++++++++++++++ .../imperative/auto-approve-installplans.yaml | 52 +++++++++++++++++++ clustergroup/values.schema.json | 4 ++ 3 files changed, 96 insertions(+) create mode 100644 ansible/playbooks/auto-approve-installplans/auto-approve-installplans.yaml create mode 100644 clustergroup/templates/imperative/auto-approve-installplans.yaml diff --git a/ansible/playbooks/auto-approve-installplans/auto-approve-installplans.yaml b/ansible/playbooks/auto-approve-installplans/auto-approve-installplans.yaml new file mode 100644 index 00000000..6b6802d4 --- /dev/null +++ b/ansible/playbooks/auto-approve-installplans/auto-approve-installplans.yaml @@ -0,0 +1,40 @@ +# This playbook will watch for pending install plans of managed operators +# if they are in Manual and there's a startingCSV that must be installed +--- +- name: InstallPlan Auto-Approver + hosts: localhost + connection: local + gather_facts: false + become: false + + tasks: + - name: Get all installPlans from OpenShift + kubernetes.core.k8s_info: + api_version: operators.coreos.com/v1alpha1 + kind: InstallPlan + register: installplans + + - name: Get required CSVs from clusterGroup data + ansible.builtin.set_fact: + expected_csv: "{{ expected_csv | default([]) + [item.csv] }}" + when: item.csv | default(false) and + ((item.installPlanApproval | default("") == "Manual") or + (item.installPlanApproval | default("") == "" and global.options.installPlanApproval | default("") == "Manual")) + with_items: "{{ clusterGroup.subscriptions.values() }}" + + # TODO: loop over clusterGroup.subscriptions instead of installplans + # to allow certain control on the order of approvals + # IDEA: allow adding a per-installplan delay after the approval before + # moving forward to the next one + - name: Approve the missing installPlans + kubernetes.core.k8s_json_patch: + api_version: operators.coreos.com/v1alpha1 + kind: InstallPlan + name: "{{ item.metadata.name }}" + namespace: "{{ item.metadata.namespace }}" + patch: + - op: replace + path: /spec/approved + value: true + when: (item.spec.clusterServiceVersionNames | intersect(expected_csv | default([]))) | length > 0 + loop: "{{ installplans.resources }}" diff --git a/clustergroup/templates/imperative/auto-approve-installplans.yaml b/clustergroup/templates/imperative/auto-approve-installplans.yaml new file mode 100644 index 00000000..e6ebf26c --- /dev/null +++ b/clustergroup/templates/imperative/auto-approve-installplans.yaml @@ -0,0 +1,52 @@ +{{- if $.Values.global.options.autoApproveManualInstallPlans }} +--- +apiVersion: batch/v1 +kind: CronJob +metadata: + name: auto-approve-installplans-cronjob + namespace: {{ $.Values.clusterGroup.imperative.namespace}} +spec: + schedule: "*/5 * * * *" + # if previous Job is still running, skip execution of a new Job + concurrencyPolicy: Forbid + jobTemplate: + spec: + activeDeadlineSeconds: {{ $.Values.clusterGroup.imperative.activeDeadlineSeconds }} + template: + metadata: + name: auto-approve-installplans-job + spec: + serviceAccountName: {{ $.Values.clusterGroup.imperative.serviceAccountName }} + 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 + {{- include "imperative.initcontainers.gitinit" . | indent 12 }} + - name: auto-approve-installplans + image: {{ $.Values.clusterGroup.imperative.image }} + imagePullPolicy: {{ $.Values.clusterGroup.imperative.imagePullPolicy }} + env: + - name: HOME + value: /git/home + workingDir: /git/repo + command: + - timeout + - {{ .timeout | default "600" | quote }} + - ansible-playbook + {{- if $.Values.clusterGroup.imperative.verbosity }} + - {{ $.Values.clusterGroup.imperative.verbosity }} + {{- end }} + - -e + - "@/values/values.yaml" + - common/ansible/playbooks/auto-approve-installplans/auto-approve-installplans.yaml + volumeMounts: + {{- include "imperative.volumemounts" . | indent 16 }} + containers: + {{- include "imperative.containers.done" . | indent 12 }} + volumes: + - name: git + emptyDir: {} + - name: values-volume + configMap: + name: {{ $.Values.clusterGroup.imperative.valuesConfigMap }}-{{ $.Values.clusterGroup.name }} + restartPolicy: Never +{{- end }} diff --git a/clustergroup/values.schema.json b/clustergroup/values.schema.json index 8d206957..9c3a3651 100644 --- a/clustergroup/values.schema.json +++ b/clustergroup/values.schema.json @@ -226,6 +226,10 @@ "deprecated": true, "description": "This is used to approval strategy for the subscriptions of OpenShift Operators being installed. You can choose Automatic or Manual updates. NOTE: This setting is now available in the subcriptions description in the values file." }, + "autoApproveManualInstallPlans": { + "type": "boolean", + "description": "This is used to approve automatically those subscriptions of OpenShift Operators that are in Manual with a startingCSV version. You can choose True or False. Defaults: False." + }, "applicationRetryLimit": { "type": "integer", "description": "Number of failed sync attempt retries; unlimited number of attempts if less than 0" From 6cd4e85d5bf7955b172b935dd05cd360fd0c4443 Mon Sep 17 00:00:00 2001 From: Tomer Figenblat Date: Tue, 28 May 2024 13:36:43 -0400 Subject: [PATCH 10/64] fix: when using clusterdeployments, secrets should exist in the cluster-namespace Co-authored-by: Michele Baldessari Co-authored-by: Alejandro Villegas Signed-off-by: Tomer Figenblat --- acm/templates/provision/secrets-aws.yaml | 10 ++++++++-- acm/templates/provision/secrets-azure.yaml | 10 ++++++++-- acm/templates/provision/secrets-common.yaml | 15 ++++++++++++--- tests/acm-normal.expected.yaml | 10 ++++++++++ 4 files changed, 38 insertions(+), 7 deletions(-) diff --git a/acm/templates/provision/secrets-aws.yaml b/acm/templates/provision/secrets-aws.yaml index a671638d..911aff4a 100644 --- a/acm/templates/provision/secrets-aws.yaml +++ b/acm/templates/provision/secrets-aws.yaml @@ -15,9 +15,9 @@ {{- $deploymentName := print .name "-" $group.name }} {{- if .platform.aws }} --- -{{- template "externalsecret.aws.creds" (dict "name" $deploymentName "context" . "secretStore" $.Values.secretStore) }} +{{- template "externalsecret.aws.creds" (dict "name" $deploymentName "context" . "secretStore" $.Values.secretStore "namespaced" true) }} --- -{{- template "externalsecret.aws.infra-creds" (dict "name" $deploymentName "context" . "secretStore" $.Values.secretStore) }} +{{- template "externalsecret.aws.infra-creds" (dict "name" $deploymentName "context" . "secretStore" $.Values.secretStore "namespaced" true) }} {{- end }}{{- /* if .platform.aws */}} {{- end }}{{- /* range .clusterDeployments */}} @@ -29,6 +29,9 @@ apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: {{ .name }}-creds + {{- if .namespaced }} + namespace: {{ .name }} + {{- end }} spec: dataFrom: - extract: @@ -51,6 +54,9 @@ apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: {{ .name }}-infra-creds + {{- if .namespaced }} + namespace: {{ .name }} + {{- end }} spec: data: - secretKey: openshiftPullSecret diff --git a/acm/templates/provision/secrets-azure.yaml b/acm/templates/provision/secrets-azure.yaml index 21c9d482..1ef5842c 100644 --- a/acm/templates/provision/secrets-azure.yaml +++ b/acm/templates/provision/secrets-azure.yaml @@ -16,9 +16,9 @@ {{- $deploymentName := print .name "-" $group.name }} {{- if .platform.azure }} --- -{{- template "externalsecret.azure.creds" (dict "name" $deploymentName "context" . "secretStore" $.Values.secretStore) }} +{{- template "externalsecret.azure.creds" (dict "name" $deploymentName "context" . "secretStore" $.Values.secretStore "namespaced" true) }} --- -{{- template "externalsecret.azure.infra-creds" (dict "name" $deploymentName "context" . "secretStore" $.Values.secretStore) }} +{{- template "externalsecret.azure.infra-creds" (dict "name" $deploymentName "context" . "secretStore" $.Values.secretStore "namespaced" true) }} {{- end }}{{- /* if .platform.azure */}} @@ -31,6 +31,9 @@ apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: {{ .name }}-creds + {{- if .namespaced }} + namespace: {{ .name }} + {{- end }} spec: data: - secretKey: azureOsServicePrincipal @@ -57,6 +60,9 @@ apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: {{ .name }}-infra-creds + {{- if .namespaced }} + namespace: {{ .name }} + {{- end }} spec: data: - secretKey: openshiftPullSecret diff --git a/acm/templates/provision/secrets-common.yaml b/acm/templates/provision/secrets-common.yaml index 474347c6..6901c79c 100644 --- a/acm/templates/provision/secrets-common.yaml +++ b/acm/templates/provision/secrets-common.yaml @@ -14,11 +14,11 @@ {{- range .clusterDeployments }} {{- $deploymentName := print .name "-" $group.name }} --- -{{- template "secret.install-config" (dict "name" $deploymentName "context" .) }} +{{- template "secret.install-config" (dict "name" $deploymentName "context" . "namespaced" true) }} --- -{{- template "externalsecret.pull-secret" (dict "name" $deploymentName "context" . "secretStore" $.Values.secretStore) }} +{{- template "externalsecret.pull-secret" (dict "name" $deploymentName "context" . "secretStore" $.Values.secretStore "namespaced" true) }} --- -{{- template "externalsecret.ssh.private.key" (dict "name" $deploymentName "context" . "secretStore" $.Values.secretStore) }} +{{- template "externalsecret.ssh.private.key" (dict "name" $deploymentName "context" . "secretStore" $.Values.secretStore "namespaced" true) }} {{- end }}{{- /* range .clusterDeplyments */}} {{- end }}{{- /* range .Values.clusterGroup.managedClusterGroups */}} @@ -28,6 +28,9 @@ apiVersion: v1 kind: Secret metadata: name: {{ .name }}-install-config + {{- if .namespaced }} + namespace: {{ .name }} + {{- end }} data: # Base64 encoding of install-config yaml install-config.yaml: {{ include "cluster.install-config" .context | b64enc }} @@ -39,6 +42,9 @@ apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: {{ .name }}-pull-secret + {{- if .namespaced }} + namespace: {{ .name }} + {{- end }} spec: data: - secretKey: openshiftPullSecret @@ -65,6 +71,9 @@ apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: {{ .name }}-ssh-private-key + {{- if .namespaced }} + namespace: {{ .name }} + {{- end }} spec: data: - secretKey: sshPrivateKey diff --git a/tests/acm-normal.expected.yaml b/tests/acm-normal.expected.yaml index 3e6fbc74..7969434f 100644 --- a/tests/acm-normal.expected.yaml +++ b/tests/acm-normal.expected.yaml @@ -36,6 +36,7 @@ apiVersion: v1 kind: Secret metadata: name: aws-cd-one-w-pool-acm-provision-edge-install-config + namespace: aws-cd-one-w-pool-acm-provision-edge data: # Base64 encoding of install-config yaml install-config.yaml: CgphcGlWZXJzaW9uOiB2MQptZXRhZGF0YToKICBuYW1lOiAnYXdzLWNkLW9uZS13LXBvb2wnIApiYXNlRG9tYWluOiBibHVlcHJpbnRzLnJoZWNvZW5nLmNvbQpjb250cm9sUGxhbmU6CiAgYXJjaGl0ZWN0dXJlOiBhbWQ2NAogIGh5cGVydGhyZWFkaW5nOiBFbmFibGVkCiAgbmFtZTogY29udHJvbFBsYW5lCiAgcmVwbGljYXM6IDMKICBwbGF0Zm9ybToKICAgIGF3czoKICAgICAgdHlwZTogbTUueGxhcmdlCmNvbXB1dGU6Ci0gaHlwZXJ0aHJlYWRpbmc6IEVuYWJsZWQKICBhcmNoaXRlY3R1cmU6IGFtZDY0CiAgbmFtZTogJ3dvcmtlcicKICByZXBsaWNhczogMwogIHBsYXRmb3JtOgogICAgYXdzOgogICAgICB0eXBlOiBtNS54bGFyZ2UKbmV0d29ya2luZzoKICBjbHVzdGVyTmV0d29yazoKICAtIGNpZHI6IDEwLjEyOC4wLjAvMTQKICAgIGhvc3RQcmVmaXg6IDIzCiAgbWFjaGluZU5ldHdvcms6CiAgLSBjaWRyOiAxMC4wLjAuMC8xNgogIG5ldHdvcmtUeXBlOiBPVk5LdWJlcm5ldGVzCiAgc2VydmljZU5ldHdvcms6CiAgLSAxNzIuMzAuMC4wLzE2CnBsYXRmb3JtOgogIGF3czoKICAgIHJlZ2lvbjogYXAtc291dGhlYXN0LTEKcHVsbFNlY3JldDogIiIgIyBza2lwLCBoaXZlIHdpbGwgaW5qZWN0IGJhc2VkIG9uIGl0J3Mgc2VjcmV0cwpzc2hLZXk6ICIiICAgICAjIHNraXAsIGhpdmUgd2lsbCBpbmplY3QgYmFzZWQgb24gaXQncyBzZWNyZXRz @@ -46,6 +47,7 @@ apiVersion: v1 kind: Secret metadata: name: aws-cd-two-wo-pool-acm-provision-on-deploy-install-config + namespace: aws-cd-two-wo-pool-acm-provision-on-deploy data: # Base64 encoding of install-config yaml install-config.yaml: CgphcGlWZXJzaW9uOiB2MQptZXRhZGF0YToKICBuYW1lOiAnYXdzLWNkLXR3by13by1wb29sJyAKYmFzZURvbWFpbjogYmx1ZXByaW50cy5yaGVjb2VuZy5jb20KY29udHJvbFBsYW5lOgogIGFyY2hpdGVjdHVyZTogYW1kNjQKICBoeXBlcnRocmVhZGluZzogRW5hYmxlZAogIG5hbWU6IGNvbnRyb2xQbGFuZQogIHJlcGxpY2FzOiAzCiAgcGxhdGZvcm06CiAgICBhd3M6CiAgICAgIHR5cGU6IG01LnhsYXJnZQpjb21wdXRlOgotIGh5cGVydGhyZWFkaW5nOiBFbmFibGVkCiAgYXJjaGl0ZWN0dXJlOiBhbWQ2NAogIG5hbWU6ICd3b3JrZXInCiAgcmVwbGljYXM6IDMKICBwbGF0Zm9ybToKICAgIGF3czoKICAgICAgdHlwZTogbTUueGxhcmdlCm5ldHdvcmtpbmc6CiAgY2x1c3Rlck5ldHdvcms6CiAgLSBjaWRyOiAxMC4xMjguMC4wLzE0CiAgICBob3N0UHJlZml4OiAyMwogIG1hY2hpbmVOZXR3b3JrOgogIC0gY2lkcjogMTAuMC4wLjAvMTYKICBuZXR3b3JrVHlwZTogT1ZOS3ViZXJuZXRlcwogIHNlcnZpY2VOZXR3b3JrOgogIC0gMTcyLjMwLjAuMC8xNgpwbGF0Zm9ybToKICBhd3M6CiAgICByZWdpb246IGFwLXNvdXRoZWFzdC0zCnB1bGxTZWNyZXQ6ICIiICMgc2tpcCwgaGl2ZSB3aWxsIGluamVjdCBiYXNlZCBvbiBpdCdzIHNlY3JldHMKc3NoS2V5OiAiIiAgICAgIyBza2lwLCBoaXZlIHdpbGwgaW5qZWN0IGJhc2VkIG9uIGl0J3Mgc2VjcmV0cw== @@ -294,6 +296,7 @@ apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: aws-cd-one-w-pool-acm-provision-edge-creds + namespace: aws-cd-one-w-pool-acm-provision-edge spec: dataFrom: - extract: @@ -315,6 +318,7 @@ apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: aws-cd-one-w-pool-acm-provision-edge-infra-creds + namespace: aws-cd-one-w-pool-acm-provision-edge spec: data: - secretKey: openshiftPullSecret @@ -372,6 +376,7 @@ apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: aws-cd-two-wo-pool-acm-provision-on-deploy-creds + namespace: aws-cd-two-wo-pool-acm-provision-on-deploy spec: dataFrom: - extract: @@ -393,6 +398,7 @@ apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: aws-cd-two-wo-pool-acm-provision-on-deploy-infra-creds + namespace: aws-cd-two-wo-pool-acm-provision-on-deploy spec: data: - secretKey: openshiftPullSecret @@ -624,6 +630,7 @@ apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: aws-cd-one-w-pool-acm-provision-edge-pull-secret + namespace: aws-cd-one-w-pool-acm-provision-edge spec: data: - secretKey: openshiftPullSecret @@ -648,6 +655,7 @@ apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: aws-cd-one-w-pool-acm-provision-edge-ssh-private-key + namespace: aws-cd-one-w-pool-acm-provision-edge spec: data: - secretKey: sshPrivateKey @@ -672,6 +680,7 @@ apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: aws-cd-two-wo-pool-acm-provision-on-deploy-pull-secret + namespace: aws-cd-two-wo-pool-acm-provision-on-deploy spec: data: - secretKey: openshiftPullSecret @@ -696,6 +705,7 @@ apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: aws-cd-two-wo-pool-acm-provision-on-deploy-ssh-private-key + namespace: aws-cd-two-wo-pool-acm-provision-on-deploy spec: data: - secretKey: sshPrivateKey From 113a9076b64ac070866050c31e692c2da62b3cdd Mon Sep 17 00:00:00 2001 From: Lester Claudio Date: Wed, 29 May 2024 14:06:55 -0600 Subject: [PATCH 11/64] bug: Invalid OperatorGroup generated when ommitting targetNamespaces Problem Statement: When setting a namespace like this: - openshift-distributed-tracing: operatorGroup: true targetNamespaces: [] The chart generates the following yaml: ```yaml apiVersion: operators.coreos.com/v1 kind: OperatorGroup metadata: name: openshift-distributed-tracing-operator-group namespace: openshift-distributed-tracing spec: targetNamespaces: ``` Which k8s rejects the targetNamespaces key as invalid when it attempts to apply it and removes it since it doesn't have a value, which just so happens to have the desired result of not setting the targetNamespaces (or a selector) to enable it for All Namespaces. --- clustergroup/templates/_helpers.tpl | 12 +++++++++--- clustergroup/templates/core/operatorgroup.yaml | 10 +++++++--- clustergroup/templates/plumbing/applications.yaml | 2 +- tests/clustergroup-normal.expected.yaml | 2 -- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/clustergroup/templates/_helpers.tpl b/clustergroup/templates/_helpers.tpl index 5001a06e..c6d14d08 100644 --- a/clustergroup/templates/_helpers.tpl +++ b/clustergroup/templates/_helpers.tpl @@ -202,13 +202,19 @@ kind: OperatorGroup metadata: name: {{ $k }}-operator-group namespace: {{ $k }} + {{- if (hasKey $v "targetNamespaces") }} + {{- if $v.targetNamespaces }} + {{- if (len $v.targetNamespaces) }} spec: targetNamespaces: - {{- if (hasKey $v "targetNamespaces") }} - {{- range $v.targetNamespaces }}{{- /* We loop through the list of tergetnamespaces */}} + {{- range $v.targetNamespaces }}{{- /* We loop through the list of tergetnamespaces */}} - {{ . }} - {{- end }}{{- /* End range targetNamespaces */}} + {{- end }}{{- /* End range targetNamespaces */}} + {{- end }}{{- /* End if (len $v.targetNamespaces) */}} + {{- end }}{{- /* End $v.targetNamespaces */}} {{- else }} +spec: + targetNamespaces: - {{ $k }} {{- end }}{{- /* End of if hasKey $v "targetNamespaces" */}} {{- end }}{{- /* End if $v.operatorGroup */}} diff --git a/clustergroup/templates/core/operatorgroup.yaml b/clustergroup/templates/core/operatorgroup.yaml index 4d8c3014..6adfef47 100644 --- a/clustergroup/templates/core/operatorgroup.yaml +++ b/clustergroup/templates/core/operatorgroup.yaml @@ -21,15 +21,19 @@ kind: OperatorGroup metadata: name: {{ $k }}-operator-group namespace: {{ $k }} + {{- if (hasKey $v "targetNamespaces") }} + {{- if $v.targetNamespaces }} spec: targetNamespaces: - {{- if (hasKey $v "targetNamespaces") }} {{- range $v.targetNamespaces }}{{- /* We loop through the list of tergetnamespaces */}} - {{ . }} {{- end }}{{- /* End range targetNamespaces */}} - {{- else }} + {{- end }}{{- /* End if $v.targetNamespaces */}} + {{- else }} +spec: + targetNamespaces: - {{ $k }} - {{- end }}{{- /* End of if operatorGroup */}} + {{- end }}{{- /* End of if (hasKey $v "targetNamespaces") */}} {{- end }}{{- /* range $k, $v := $ns */}} {{- end }}{{- /* End of if operatorGroup */}} {{- else if kindIs "string" $ns }} diff --git a/clustergroup/templates/plumbing/applications.yaml b/clustergroup/templates/plumbing/applications.yaml index 870babe3..0b9f4eda 100644 --- a/clustergroup/templates/plumbing/applications.yaml +++ b/clustergroup/templates/plumbing/applications.yaml @@ -78,7 +78,7 @@ spec: - name: global.namespace value: {{ $.Values.global.namespace }} - name: clusterGroup.name - value: {{ .Values.clusterGroup.name }} + value: {{ $.Values.clusterGroup.name }} {{- range .extraHubClusterDomainFields }} - name: {{ . }} value: {{ $.Values.global.hubClusterDomain }} diff --git a/tests/clustergroup-normal.expected.yaml b/tests/clustergroup-normal.expected.yaml index 41eb68b8..c594b65e 100644 --- a/tests/clustergroup-normal.expected.yaml +++ b/tests/clustergroup-normal.expected.yaml @@ -1197,8 +1197,6 @@ kind: OperatorGroup metadata: name: exclude-targetns-operator-group namespace: exclude-targetns -spec: - targetNamespaces: --- # Source: clustergroup/templates/core/operatorgroup.yaml --- From ad87c84b9643b66e3994215dcd6cb830fcefad52 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Thu, 30 May 2024 17:26:23 +0200 Subject: [PATCH 12/64] Fix CI issue --- tests/acm-normal.expected.yaml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/acm-normal.expected.yaml b/tests/acm-normal.expected.yaml index 8abd52ef..8e78a98f 100644 --- a/tests/acm-normal.expected.yaml +++ b/tests/acm-normal.expected.yaml @@ -1219,15 +1219,17 @@ spec: path: common/clustergroup helm: ignoreMissingValueFiles: true + values: | + extraParametersNested: valueFiles: - - "/values-global.yaml" - - "/values-acm-provision-on-deploy.yaml" - - '/values-{{ (lookup "config.openshift.io/v1" "Infrastructure" "" "cluster").spec.platformSpec.type }}.yaml' - - '/values-{{ (lookup "config.openshift.io/v1" "Infrastructure" "" "cluster").spec.platformSpec.type }}-{{ printf "%d.%d" ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Major) ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Minor) }}.yaml' - - '/values-{{ (lookup "config.openshift.io/v1" "Infrastructure" "" "cluster").spec.platformSpec.type }}-acm-provision-on-deploy.yaml' - # We cannot use $.Values.global.clusterVersion because that gets resolved to the - # hub's cluster version, whereas we want to include the spoke cluster version - - '/values-{{ printf "%d.%d" ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Major) ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Minor) }}.yaml' + - "/values-global.yaml" + - "/values-acm-provision-on-deploy.yaml" + - '/values-{{ (lookup "config.openshift.io/v1" "Infrastructure" "" "cluster").spec.platformSpec.type }}.yaml' + - '/values-{{ (lookup "config.openshift.io/v1" "Infrastructure" "" "cluster").spec.platformSpec.type }}-{{ printf "%d.%d" ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Major) ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Minor) }}.yaml' + - '/values-{{ (lookup "config.openshift.io/v1" "Infrastructure" "" "cluster").spec.platformSpec.type }}-acm-provision-on-deploy.yaml' + # We cannot use $.Values.global.clusterVersion because that gets resolved to the + # hub's cluster version, whereas we want to include the spoke cluster version + - '/values-{{ printf "%d.%d" ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Major) ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Minor) }}.yaml' parameters: - name: global.repoURL value: https://github.com/pattern-clone/mypattern @@ -1241,10 +1243,8 @@ spec: 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." "" }}' - # Requires ACM 2.6 or higher (I could not come up with something less terrible to get maj.min) - name: global.clusterVersion value: '{{ printf "%d.%d" ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Major) ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Minor) }}' - name: global.localClusterName From beb71a1ba529dc6f50454ff947e2f8e547ae1cae Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Mon, 3 Jun 2024 19:09:52 +0200 Subject: [PATCH 13/64] Actually use adminServiceAccountName for the auto approve job --- .../templates/imperative/auto-approve-installplans.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clustergroup/templates/imperative/auto-approve-installplans.yaml b/clustergroup/templates/imperative/auto-approve-installplans.yaml index e6ebf26c..23e6b133 100644 --- a/clustergroup/templates/imperative/auto-approve-installplans.yaml +++ b/clustergroup/templates/imperative/auto-approve-installplans.yaml @@ -16,7 +16,7 @@ spec: metadata: name: auto-approve-installplans-job spec: - serviceAccountName: {{ $.Values.clusterGroup.imperative.serviceAccountName }} + serviceAccountName: {{ $.Values.clusterGroup.imperative.adminServiceAccountName }} 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 From 39addf213792aa75d323f83c618fe49fa77c9819 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Tue, 4 Jun 2024 10:39:39 +0200 Subject: [PATCH 14/64] Make sure that the if condition on chart split is not always true This should fix the fact that jobs are triggered on unrelated changes --- .github/workflows/chart-branches.yml | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/.github/workflows/chart-branches.yml b/.github/workflows/chart-branches.yml index 1a4fb455..4fb784f0 100644 --- a/.github/workflows/chart-branches.yml +++ b/.github/workflows/chart-branches.yml @@ -49,9 +49,7 @@ jobs: acm: needs: changes - if: | - ${{ needs.changes.outputs.acm == 'true' }} && - github.repository == 'validatedpatterns/common' + if: ${{ (needs.changes.outputs.acm == 'true') && (github.repository == 'validatedpatterns/common') }} uses: validatedpatterns/common/.github/workflows/chart-split.yml@main permissions: actions: write @@ -63,9 +61,7 @@ jobs: golang-external-secrets: needs: changes - if: | - ${{ needs.changes.outputs.golang-external-secrets == 'true' }} && - github.repository == 'validatedpatterns/common' + if: ${{ (needs.changes.outputs.golang-external-secrets == 'true') && (github.repository == 'validatedpatterns/common') }} uses: validatedpatterns/common/.github/workflows/chart-split.yml@main permissions: actions: write @@ -77,9 +73,7 @@ jobs: hashicorp-vault: needs: changes - if: | - ${{ needs.changes.outputs.hashicorp-vault == 'true' }} && - github.repository == 'validatedpatterns/common' + if: ${{ (needs.changes.outputs.hashicorp-vault == 'true') && (github.repository == 'validatedpatterns/common') }} uses: validatedpatterns/common/.github/workflows/chart-split.yml@main permissions: actions: write @@ -91,9 +85,7 @@ jobs: letsencrypt: needs: changes - if: | - ${{ needs.changes.outputs.letsencrypt == 'true' }} && - github.repository == 'validatedpatterns/common' + if: ${{ (needs.changes.outputs.letsencrypt == 'true') && (github.repository == 'validatedpatterns/common') }} uses: validatedpatterns/common/.github/workflows/chart-split.yml@main permissions: actions: write @@ -105,9 +97,7 @@ jobs: clustergroup: needs: changes - if: | - ${{ needs.changes.outputs.clustergroup == 'true' }} && - github.repository == 'validatedpatterns/common' + if: ${{ (needs.changes.outputs.clustergroup == 'true') && (github.repository == 'validatedpatterns/common') }} uses: validatedpatterns/common/.github/workflows/chart-split.yml@main permissions: actions: write From 10b06654858958f9af5ddb7adbf7fafd65cd9b99 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Tue, 4 Jun 2024 10:49:05 +0200 Subject: [PATCH 15/64] Bump super-linter from 5 to 6 --- .github/workflows/superlinter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/superlinter.yml b/.github/workflows/superlinter.yml index 7430db09..ca6daab0 100644 --- a/.github/workflows/superlinter.yml +++ b/.github/workflows/superlinter.yml @@ -21,7 +21,7 @@ jobs: # Run Linter against code base # ################################ - name: Lint Code Base - uses: github/super-linter/slim@v5 + uses: github/super-linter/slim@v6 env: VALIDATE_ALL_CODEBASE: true DEFAULT_BRANCH: main From c85ada60e6d5be2478a5ab2941a9ceddfbe6eb3a Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Tue, 4 Jun 2024 10:53:41 +0200 Subject: [PATCH 16/64] Drop some validations for now --- .github/workflows/superlinter.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/superlinter.yml b/.github/workflows/superlinter.yml index ca6daab0..55acbdb0 100644 --- a/.github/workflows/superlinter.yml +++ b/.github/workflows/superlinter.yml @@ -29,8 +29,11 @@ jobs: # These are the validation we disable atm VALIDATE_ANSIBLE: false VALIDATE_BASH: false + VALIDATE_CHECKOV: false VALIDATE_JSCPD: false VALIDATE_KUBERNETES_KUBECONFORM: false + VALIDATE_PYTHON_PYLINT: false + VALIDATE_SHELL_SHFMT: false VALIDATE_YAML: false # VALIDATE_DOCKERFILE_HADOLINT: false # VALIDATE_MARKDOWN: false From a232db50c15ca3e3d450e8d5cdb7b4a5ed83c48a Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Tue, 4 Jun 2024 11:05:24 +0200 Subject: [PATCH 17/64] Add some debugging to the chart split action --- .github/workflows/chart-split.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/chart-split.yml b/.github/workflows/chart-split.yml index 2792d6ad..ad356e61 100644 --- a/.github/workflows/chart-split.yml +++ b/.github/workflows/chart-split.yml @@ -31,8 +31,10 @@ jobs: set -e N="${{ inputs.chart_name }}" B="${N}-main-single-chart" + echo "Running subtree split for ${B}" git push origin -d "${B}" || /bin/true git subtree split -P "${N}" -b "${B}" + git remote -v git push -f -u origin "${B}" #git clone https://validatedpatterns:${GITHUB_TOKEN}@github.com/validatedpatterns/common.git -b "acm-main-single-chart" --single-branch git push --force https://validatedpatterns:"${GITHUB_TOKEN}"@github.com/${{ inputs.target_repository }}.git "${B}:main" From 821727ad13f3b779d47efd1444bb5fcda7dc4738 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Tue, 4 Jun 2024 16:01:46 +0200 Subject: [PATCH 18/64] Use a specific git version when running git subtree split Otherwise we will get errors during the command as git subtree has regressed since v2.44.0 --- .github/workflows/chart-split.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/chart-split.yml b/.github/workflows/chart-split.yml index ad356e61..39ee9c01 100644 --- a/.github/workflows/chart-split.yml +++ b/.github/workflows/chart-split.yml @@ -31,10 +31,12 @@ jobs: set -e N="${{ inputs.chart_name }}" B="${N}-main-single-chart" + GITIMG="quay.io/hybridcloudpatterns/gitsubtree-container:2.40.1" + sudo apt-get update -y && apt-get install -y podman echo "Running subtree split for ${B}" + podman pull "${GITIMG}" git push origin -d "${B}" || /bin/true - git subtree split -P "${N}" -b "${B}" - git remote -v - git push -f -u origin "${B}" + # Git subtree got broken on recent versions of git hence this container + podman run --net=host --rm -t -v .:/git "${GITIMG}" subtree split -P "${N}" -b "${B}" #git clone https://validatedpatterns:${GITHUB_TOKEN}@github.com/validatedpatterns/common.git -b "acm-main-single-chart" --single-branch git push --force https://validatedpatterns:"${GITHUB_TOKEN}"@github.com/${{ inputs.target_repository }}.git "${B}:main" From 3061644432685ff5b77276d194739e1af71c4d3b Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Tue, 4 Jun 2024 16:17:00 +0200 Subject: [PATCH 19/64] Release clustergroup v0.8.6 --- clustergroup/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clustergroup/Chart.yaml b/clustergroup/Chart.yaml index e2d4f98b..2ddd15ba 100644 --- a/clustergroup/Chart.yaml +++ b/clustergroup/Chart.yaml @@ -3,4 +3,4 @@ description: A Helm chart to create per-clustergroup ArgoCD applications and any keywords: - pattern name: clustergroup -version: 0.8.5 +version: 0.8.6 From ae14cd2bfab2a3fc7fe8cb83941b52c87c97547a Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Tue, 4 Jun 2024 16:22:57 +0200 Subject: [PATCH 20/64] Add a sudo to apt-get command --- .github/workflows/chart-split.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/chart-split.yml b/.github/workflows/chart-split.yml index 39ee9c01..150e419b 100644 --- a/.github/workflows/chart-split.yml +++ b/.github/workflows/chart-split.yml @@ -32,7 +32,7 @@ jobs: N="${{ inputs.chart_name }}" B="${N}-main-single-chart" GITIMG="quay.io/hybridcloudpatterns/gitsubtree-container:2.40.1" - sudo apt-get update -y && apt-get install -y podman + sudo apt-get update -y && sudo apt-get install -y podman echo "Running subtree split for ${B}" podman pull "${GITIMG}" git push origin -d "${B}" || /bin/true From 17325d65776a7508c89f84ebbec9eebf37f04ad7 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Thu, 6 Jun 2024 08:52:27 +0200 Subject: [PATCH 21/64] Add some READMEs in the individual charts --- acm/README.md | 5 +++++ clustergroup/README.md | 5 +++++ golang-external-secrets/README.md | 4 ++++ hashicorp-vault/README.md | 4 ++++ letsencrypt/README.md | 4 ++++ 5 files changed, 22 insertions(+) create mode 100644 acm/README.md create mode 100644 clustergroup/README.md diff --git a/acm/README.md b/acm/README.md new file mode 100644 index 00000000..c8c67635 --- /dev/null +++ b/acm/README.md @@ -0,0 +1,5 @@ +# Validated Patterns ACM chart + +This chart is used to set up ACM in Validated Patterns https://validatedpatterns.io + +Please send PRs to https://github.com/validatedpatterns/common diff --git a/clustergroup/README.md b/clustergroup/README.md new file mode 100644 index 00000000..8983ddf9 --- /dev/null +++ b/clustergroup/README.md @@ -0,0 +1,5 @@ +# Validated Patterns ClusterGroup chart + +This chart is used to set up the basic building blocks in Validated Patterns https://validatedpatterns.io + +Please send PRs to https://github.com/validatedpatterns/common diff --git a/golang-external-secrets/README.md b/golang-external-secrets/README.md index e12d58f1..6d9e0f41 100644 --- a/golang-external-secrets/README.md +++ b/golang-external-secrets/README.md @@ -12,3 +12,7 @@ we just override the tag with the version + "-ubi" 4. Tweak `values.yaml` with the new image versions 5. Run `make test` 6. Commit to git + +## PRs + +Please send PRs to https://github.com/validatedpatterns/common diff --git a/hashicorp-vault/README.md b/hashicorp-vault/README.md index 26252b7e..6d5fefd6 100644 --- a/hashicorp-vault/README.md +++ b/hashicorp-vault/README.md @@ -1,5 +1,9 @@ # VP hashicorp-vault +## PRs + +Please send PRs to https://github.com/validatedpatterns/common + ## Updating the chart 1. Edit Chart.yaml with the new version diff --git a/letsencrypt/README.md b/letsencrypt/README.md index d277abaa..549e44e8 100644 --- a/letsencrypt/README.md +++ b/letsencrypt/README.md @@ -22,6 +22,10 @@ In order to enable this chart in your patterns, please add and edit the followin Once the above is enabled in a pattern, a certain amount of time (~15/20 minutes or so) is needed for all the cluster operators to settle, all the HTTPS routes will have a wildcard certificate signed by letsencrypt. By default also the API endpoint will use a certificate signed by letsencrypt. +## PRs + +Please send PRs to https://github.com/validatedpatterns/common + ## Limitations Please be aware of the following gotchas when using this chart: From 55230973793444aa5d0e43088ef9b637d17f8e33 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Thu, 6 Jun 2024 09:01:37 +0200 Subject: [PATCH 22/64] Fix super-linter issues and upgrade local super-linter target --- Makefile | 11 +++++++---- acm/README.md | 4 ++-- clustergroup/README.md | 4 ++-- golang-external-secrets/README.md | 2 +- hashicorp-vault/README.md | 2 +- letsencrypt/README.md | 2 +- 6 files changed, 14 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 86cb5177..f9b00e57 100644 --- a/Makefile +++ b/Makefile @@ -230,17 +230,20 @@ kubeconform: ## run helm kubeconform super-linter: ## Runs super linter locally rm -rf .mypy_cache podman run -e RUN_LOCAL=true -e USE_FIND_ALGORITHM=true \ + -e VALIDATE_ANSIBLE=false \ -e VALIDATE_BASH=false \ + -e VALIDATE_CHECKOV=false \ + -e VALIDATE_DOCKERFILE_HADOLINT=false \ -e VALIDATE_JSCPD=false \ -e VALIDATE_KUBERNETES_KUBECONFORM=false \ - -e VALIDATE_YAML=false \ - -e VALIDATE_ANSIBLE=false \ - -e VALIDATE_DOCKERFILE_HADOLINT=false \ + -e VALIDATE_PYTHON_PYLINT=false \ + -e VALIDATE_SHELL_SHFMT=false \ -e VALIDATE_TEKTON=false \ + -e VALIDATE_YAML=false \ $(DISABLE_LINTERS) \ -v $(PWD):/tmp/lint:rw,z \ -w /tmp/lint \ - docker.io/github/super-linter:slim-v5 + ghcr.io/super-linter/super-linter:slim-v6 .PHONY: ansible-lint ansible-lint: ## run ansible lint on ansible/ folder diff --git a/acm/README.md b/acm/README.md index c8c67635..56b39ae3 100644 --- a/acm/README.md +++ b/acm/README.md @@ -1,5 +1,5 @@ # Validated Patterns ACM chart -This chart is used to set up ACM in Validated Patterns https://validatedpatterns.io +This chart is used to set up ACM in [Validated Patterns](https://validatedpatterns.io) -Please send PRs to https://github.com/validatedpatterns/common +Please send PRs [here](https://github.com/validatedpatterns/common) diff --git a/clustergroup/README.md b/clustergroup/README.md index 8983ddf9..bb522d12 100644 --- a/clustergroup/README.md +++ b/clustergroup/README.md @@ -1,5 +1,5 @@ # Validated Patterns ClusterGroup chart -This chart is used to set up the basic building blocks in Validated Patterns https://validatedpatterns.io +This chart is used to set up the basic building blocks in [Validated Patterns](https://validatedpatterns.io) -Please send PRs to https://github.com/validatedpatterns/common +Please send PRs [here](https://github.com/validatedpatterns/common) diff --git a/golang-external-secrets/README.md b/golang-external-secrets/README.md index 6d9e0f41..4316d3a1 100644 --- a/golang-external-secrets/README.md +++ b/golang-external-secrets/README.md @@ -15,4 +15,4 @@ we just override the tag with the version + "-ubi" ## PRs -Please send PRs to https://github.com/validatedpatterns/common +Please send PRs [here](https://github.com/validatedpatterns/common) diff --git a/hashicorp-vault/README.md b/hashicorp-vault/README.md index 6d5fefd6..28362080 100644 --- a/hashicorp-vault/README.md +++ b/hashicorp-vault/README.md @@ -2,7 +2,7 @@ ## PRs -Please send PRs to https://github.com/validatedpatterns/common +Please send PRs [here](https://github.com/validatedpatterns/common) ## Updating the chart diff --git a/letsencrypt/README.md b/letsencrypt/README.md index 549e44e8..ded97205 100644 --- a/letsencrypt/README.md +++ b/letsencrypt/README.md @@ -24,7 +24,7 @@ Once the above is enabled in a pattern, a certain amount of time (~15/20 minutes ## PRs -Please send PRs to https://github.com/validatedpatterns/common +Please send PRs [here](https://github.com/validatedpatterns/common) ## Limitations From e3babbbaeea77385cc9f6423b4433fce15a15781 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Thu, 6 Jun 2024 10:41:00 +0200 Subject: [PATCH 23/64] Skip unreachable spokes when setting up vault MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When setting up vault we loop through all the managed clusters and set up the token so ESO can fetch certain paths in vault. This happens in the unseal vault ansible job and will fail if one of the managed clusters is unreachable. This is undesirable because a cluster might have been shut down on purpose or might be temporarily not reachable and this is no reason to stop the configuration of vault. Tested as follows: 1. Deployed mcg on sno1 and sno2. All green. 2. Shut off sno2 so it is unreachable. observed unseal-cronjob fail (took a while but eventually failed with: ``` TASK [vault_utils : Fetch remote ansible to remote cluster] ******************** ok: [localhost] => (item=local-cluster) An exception occurred during task execution. To see the full traceback, use -vvv. The error was: urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='api.sno2.ocplab.ocp', port=6443): Max retries exceeded with url: /version (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 110] Connection timed out')) failed: [localhost] (item=sno2) => {"ansible_loop_var": "item", "changed": false, "item": {"key": "sno2", "value": {"bearerToken": "eyJhbGciOiJSUzI1... ``` 3. Imported sno3 into the hub on sno1. observed unseal-cronjob still fail: ``` TASK [vault_utils : Fetch remote ansible to remote cluster] ******************** ok: [localhost] => (item=local-cluster) An exception occurred during task execution. To see the full traceback, use -vvv. The error was: urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='api.sno2.ocplab.ocp', port=6443): Max retries exceeded with url: /version (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 110] Connection timed out')) failed: [localhost] (item=sno2) => {"ansible_loop_var": "item", "changed": false, "item": {"key": "sno2", "value": {"bearerToken": "ey... ok: [localhost] => (item=sno3) PLAY RECAP ********************************************************************* localhost : ok=37 changed=11 unreachable=0 failed=1 skipped=13 rescued=0 ignored=0 ``` 4. After the ignore_errors patch: ``` TASK [vault_utils : Fetch remote ansible to remote cluster] ******************** ok: [localhost] => (item=local-cluster) An exception occurred during task execution. To see the full traceback, use -vvv. The error was: urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='api.sno2.ocplab.ocp', port=6443): Max retries exceeded with url: /version (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 110] Connection timed out')) failed: [localhost] (item=sno2) => {"ansible_loop_var": "item", "changed": false, "item": {"key": "sno2", "value": {"bearerToken": "eyJhb.... ok: [localhost] => (item=sno3) ...ignoring # sno2 correctly gets skipped in the subsequent tasks ``` sno3 did manage to login to the vault and everything just worked Reported-by: François Charette --- ansible/roles/vault_utils/tasks/vault_spokes_init.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ansible/roles/vault_utils/tasks/vault_spokes_init.yaml b/ansible/roles/vault_utils/tasks/vault_spokes_init.yaml index e930252a..92000b90 100644 --- a/ansible/roles/vault_utils/tasks/vault_spokes_init.yaml +++ b/ansible/roles/vault_utils/tasks/vault_spokes_init.yaml @@ -72,6 +72,11 @@ api_version: v1 validate_certs: "{{ validate_certs_api_endpoint }}" register: remote_external_secrets_sa + # We are allowed to ignore errors here because a spoke might be down or unreachable + # if a spoke is not reachable then its ['token'] field will not be set which + # will leave the ['esoToken'] field empty in the dict which will make it so that + # the spoke gets skipped + ignore_errors: true when: - clusters_info[item.key]['bearerToken'] is defined - clusters_info[item.key]['server_api'] is defined From 3ec1839635f24172ab6d1ebda88cf6983b3724a5 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Fri, 7 Jun 2024 09:28:55 +0200 Subject: [PATCH 24/64] Add no_log to spokes initialization task --- ansible/roles/vault_utils/tasks/vault_spokes_init.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ansible/roles/vault_utils/tasks/vault_spokes_init.yaml b/ansible/roles/vault_utils/tasks/vault_spokes_init.yaml index 92000b90..060378bc 100644 --- a/ansible/roles/vault_utils/tasks/vault_spokes_init.yaml +++ b/ansible/roles/vault_utils/tasks/vault_spokes_init.yaml @@ -77,6 +77,11 @@ # will leave the ['esoToken'] field empty in the dict which will make it so that # the spoke gets skipped ignore_errors: true + # We add no_log: true here because in case of a remote failure secret bits might + # end up in the log. Unfortunately ansible is currently not easily able to control + # output in a loop (see + # https://serverfault.com/questions/1059530/how-to-not-print-items-in-an-ansible-loop-error-without-no-log) + no_log: true when: - clusters_info[item.key]['bearerToken'] is defined - clusters_info[item.key]['server_api'] is defined From 9809c86af214c3d383afc2ce2bbe03f396a688e4 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Thu, 6 Jun 2024 17:48:15 +0200 Subject: [PATCH 25/64] Drop initContainers variable and make it the default This will allow us to work with external CAs out of the box and also it will allow the framework to be able use internal gitea instances out of the box. Tested as follows: 1. Deployed stock MCG with no changes 2. Changed the MCG repo to one with this patch 3. Observed initContainers to show up on: A. namespaced argo on hub B. clusterwide argo on spoke C. namespaced argo on spoke 4. All applications still worked 5. Deployed mcg from scratch using a branch with this patch (with multisource set to false so we're sure we're testing the right common bits in the branch) --- acm/templates/policies/application-policies.yaml | 1 - acm/templates/policies/ocp-gitops-policy.yaml | 3 --- .../imperative/auto-approve-installplans.yaml | 11 ++++------- clustergroup/templates/imperative/job.yaml | 14 -------------- clustergroup/templates/imperative/unsealjob.yaml | 15 --------------- clustergroup/templates/plumbing/argocd.yaml | 7 ------- 6 files changed, 4 insertions(+), 47 deletions(-) diff --git a/acm/templates/policies/application-policies.yaml b/acm/templates/policies/application-policies.yaml index 2a815913..01073bd4 100644 --- a/acm/templates/policies/application-policies.yaml +++ b/acm/templates/policies/application-policies.yaml @@ -1,5 +1,4 @@ # TODO: Also create a GitOpsCluster.apps.open-cluster-management.io -{{- $hasInitContainerCapability := and (.Values.global.experimentalCapabilities) (has "initcontainers" (splitList "," .Values.global.experimentalCapabilities)) }} {{- range .Values.clusterGroup.managedClusterGroups }} {{- $group := . }} {{- if not .hostedArgoSites }} diff --git a/acm/templates/policies/ocp-gitops-policy.yaml b/acm/templates/policies/ocp-gitops-policy.yaml index e72434ae..29204254 100644 --- a/acm/templates/policies/ocp-gitops-policy.yaml +++ b/acm/templates/policies/ocp-gitops-policy.yaml @@ -1,4 +1,3 @@ -{{- $hasInitContainerCapability := and (.Values.global.experimentalCapabilities) (has "initcontainers" (splitList "," .Values.global.experimentalCapabilities)) }} apiVersion: policy.open-cluster-management.io/v1 kind: Policy metadata: @@ -54,7 +53,6 @@ spec: env: - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES value: "*" -{{- if $hasInitContainerCapability }} - complianceType: mustonlyhave objectDefinition: apiVersion: argoproj.io/v1beta1 @@ -215,7 +213,6 @@ spec: provider: dex tls: ca: {} -{{- end }}{{/* if hasInitContainerCapability */}} --- apiVersion: policy.open-cluster-management.io/v1 kind: PlacementBinding diff --git a/clustergroup/templates/imperative/auto-approve-installplans.yaml b/clustergroup/templates/imperative/auto-approve-installplans.yaml index 23e6b133..7b935e77 100644 --- a/clustergroup/templates/imperative/auto-approve-installplans.yaml +++ b/clustergroup/templates/imperative/auto-approve-installplans.yaml @@ -20,7 +20,8 @@ spec: 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 - {{- include "imperative.initcontainers.gitinit" . | indent 12 }} + {{- include "imperative.initcontainers.fetch-ca" . | indent 12 }} + {{- include "imperative.initcontainers.gitinit-ca" . | indent 12 }} - name: auto-approve-installplans image: {{ $.Values.clusterGroup.imperative.image }} imagePullPolicy: {{ $.Values.clusterGroup.imperative.imagePullPolicy }} @@ -39,14 +40,10 @@ spec: - "@/values/values.yaml" - common/ansible/playbooks/auto-approve-installplans/auto-approve-installplans.yaml volumeMounts: - {{- include "imperative.volumemounts" . | indent 16 }} + {{- include "imperative.volumemounts_ca" . | indent 16 }} containers: {{- include "imperative.containers.done" . | indent 12 }} volumes: - - name: git - emptyDir: {} - - name: values-volume - configMap: - name: {{ $.Values.clusterGroup.imperative.valuesConfigMap }}-{{ $.Values.clusterGroup.name }} + {{- include "imperative.volumes_ca" . | indent 12 }} restartPolicy: Never {{- end }} diff --git a/clustergroup/templates/imperative/job.yaml b/clustergroup/templates/imperative/job.yaml index 0b82d47c..55400e8c 100644 --- a/clustergroup/templates/imperative/job.yaml +++ b/clustergroup/templates/imperative/job.yaml @@ -1,5 +1,3 @@ -{{- $hasInitContainerCapability := and (.Values.global.experimentalCapabilities) (has "initcontainers" (splitList "," .Values.global.experimentalCapabilities)) }} - {{- if not (eq .Values.enabled "plumbing") }} {{/* Define this if needed (jobs defined */}} {{- if (and $.Values.clusterGroup.imperative (gt (len $.Values.clusterGroup.imperative.jobs) 0)) -}} @@ -24,12 +22,8 @@ spec: 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 -{{- if $hasInitContainerCapability }} {{- include "imperative.initcontainers.fetch-ca" . | indent 12 }} {{- include "imperative.initcontainers.gitinit-ca" . | indent 12 }} -{{- else }} - {{- include "imperative.initcontainers.gitinit" . | indent 12 }} -{{- end }} {{- range $.Values.clusterGroup.imperative.jobs }} {{- if ne (.disabled | default "false" | toString | lower ) "true" }} - name: {{ .name }} @@ -60,21 +54,13 @@ spec: {{- end }} - {{ .playbook }} volumeMounts: -{{- if $hasInitContainerCapability }} {{- include "imperative.volumemounts_ca" . | indent 16 }} -{{- else }} - {{- include "imperative.volumemounts" . | indent 16 }} -{{- end }} {{- end }} {{- end }} containers: {{- include "imperative.containers.done" . | indent 12 }} volumes: -{{- if $hasInitContainerCapability }} {{- include "imperative.volumes_ca" . | indent 12 }} -{{- else }} - {{- include "imperative.volumes" . | indent 12 }} -{{- end }} restartPolicy: Never {{- end }} {{- end }} diff --git a/clustergroup/templates/imperative/unsealjob.yaml b/clustergroup/templates/imperative/unsealjob.yaml index e0ff2c78..a7553da8 100644 --- a/clustergroup/templates/imperative/unsealjob.yaml +++ b/clustergroup/templates/imperative/unsealjob.yaml @@ -1,5 +1,3 @@ -{{- $hasInitContainerCapability := and (.Values.global.experimentalCapabilities) (has "initcontainers" (splitList "," .Values.global.experimentalCapabilities)) }} - {{/* If the backend is not set at all we default to "vault". See https://www.github.com/helm/helm/issues/3308 why we avoid using the default function */}} {{- if or (eq .Values.global.secretStore.backend "vault") (not (hasKey .Values.global.secretStore "backend")) }} @@ -26,13 +24,8 @@ spec: 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 -{{- if $hasInitContainerCapability }} - {{- include "imperative.initcontainers.fetch-ca" . | indent 12 }} {{- include "imperative.initcontainers.gitinit-ca" . | indent 12 }} -{{- else }} - {{- include "imperative.initcontainers.gitinit" . | indent 12 }} -{{- end }} - name: unseal-playbook image: {{ $.Values.clusterGroup.imperative.image }} imagePullPolicy: {{ $.Values.clusterGroup.imperative.imagePullPolicy }} @@ -55,19 +48,11 @@ spec: - 'vault_init,vault_unseal,vault_secrets_init,vault_spokes_init' - "common/ansible/playbooks/vault/vault.yaml" volumeMounts: -{{- if $hasInitContainerCapability }} {{- include "imperative.volumemounts_ca" . | indent 16 }} -{{- else }} - {{- include "imperative.volumemounts" . | indent 16 }} -{{- end }} containers: {{- include "imperative.containers.done" . | indent 12 }} volumes: -{{- if $hasInitContainerCapability }} {{- include "imperative.volumes_ca" . | indent 12 }} -{{- else }} - {{- include "imperative.volumes" . | indent 12 }} -{{- end }} restartPolicy: Never {{- end }} {{- end }} diff --git a/clustergroup/templates/plumbing/argocd.yaml b/clustergroup/templates/plumbing/argocd.yaml index dcce1b4b..7d42ec36 100644 --- a/clustergroup/templates/plumbing/argocd.yaml +++ b/clustergroup/templates/plumbing/argocd.yaml @@ -1,4 +1,3 @@ -{{- $hasInitContainerCapability := and (.Values.global.experimentalCapabilities) (has "initcontainers" (splitList "," .Values.global.experimentalCapabilities)) }} {{- if (eq .Values.enabled "all") }} {{- $namespace := print $.Values.global.pattern "-" $.Values.clusterGroup.name }} @@ -70,7 +69,6 @@ spec: rbac: defaultPolicy: role:admin repo: -{{- if $hasInitContainerCapability }} initContainers: - command: - bash @@ -109,11 +107,6 @@ spec: {{- if len $.Values.clusterGroup.argoCD.initContainers }} {{ $.Values.clusterGroup.argoCD.initContainers | toPrettyJson }} {{- end }} -{{- else }} -{{- if len $.Values.clusterGroup.argoCD.initContainers }} - initContainers: {{ $.Values.clusterGroup.argoCD.initContainers | toPrettyJson }} -{{- end }} -{{- end }}{{/* if $hasInitContainerCapability */}} {{- if len $.Values.clusterGroup.argoCD.configManagementPlugins }} sidecarContainers: {{- range $cmp := $.Values.clusterGroup.argoCD.configManagementPlugins }} From 75f8385c1ea3c7743b52d4c13378504f8ce668a8 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Fri, 7 Jun 2024 10:19:23 +0200 Subject: [PATCH 26/64] Update tests after dropping initContainers --- .../acm-industrial-edge-factory.expected.yaml | 155 ++++++++++++++++++ tests/acm-industrial-edge-hub.expected.yaml | 155 ++++++++++++++++++ tests/acm-medical-diagnosis-hub.expected.yaml | 155 ++++++++++++++++++ tests/acm-naked.expected.yaml | 155 ++++++++++++++++++ tests/acm-normal.expected.yaml | 155 ++++++++++++++++++ ...roup-industrial-edge-factory.expected.yaml | 71 ++++++++ ...tergroup-industrial-edge-hub.expected.yaml | 107 ++++++++++++ ...rgroup-medical-diagnosis-hub.expected.yaml | 107 ++++++++++++ tests/clustergroup-naked.expected.yaml | 71 ++++++++ tests/clustergroup-normal.expected.yaml | 107 ++++++++++++ 10 files changed, 1238 insertions(+) diff --git a/tests/acm-industrial-edge-factory.expected.yaml b/tests/acm-industrial-edge-factory.expected.yaml index 561fbd7b..fa867edd 100644 --- a/tests/acm-industrial-edge-factory.expected.yaml +++ b/tests/acm-industrial-edge-factory.expected.yaml @@ -119,3 +119,158 @@ spec: env: - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES value: "*" + - complianceType: mustonlyhave + objectDefinition: + apiVersion: argoproj.io/v1beta1 + kind: ArgoCD + metadata: + name: openshift-gitops + namespace: openshift-gitops + spec: + applicationSet: + resources: + limits: + cpu: "2" + memory: 1Gi + requests: + cpu: 250m + memory: 512Mi + webhookServer: + ingress: + enabled: false + route: + enabled: false + controller: + processors: {} + resources: + limits: + cpu: "2" + memory: 2Gi + requests: + cpu: 250m + memory: 1Gi + sharding: {} + grafana: + enabled: false + ingress: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + route: + enabled: false + ha: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + initialSSHKnownHosts: {} + monitoring: + enabled: false + notifications: + enabled: false + prometheus: + enabled: false + ingress: + enabled: false + route: + enabled: false + rbac: + defaultPolicy: "" + policy: |- + g, system:cluster-admins, role:admin + g, cluster-admins, role:admin + scopes: '[groups]' + redis: + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + repo: + initContainers: + - command: + - bash + - -c + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt + || true + image: registry.redhat.io/ubi9/ubi-minimal:latest + name: fetch-ca + resources: {} + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 250m + memory: 256Mi + volumeMounts: + - mountPath: /etc/pki/tls/certs + name: ca-bundles + volumes: + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - emptyDir: {} + name: ca-bundles + resourceExclusions: |- + - apiGroups: + - tekton.dev + clusters: + - '*' + kinds: + - TaskRun + - PipelineRun + server: + autoscale: + enabled: false + grpc: + ingress: + enabled: false + ingress: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 125m + memory: 128Mi + route: + enabled: true + service: + type: "" + sso: + dex: + openShiftOAuth: true + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + provider: dex + tls: + ca: {} diff --git a/tests/acm-industrial-edge-hub.expected.yaml b/tests/acm-industrial-edge-hub.expected.yaml index 4199ba03..d715989d 100644 --- a/tests/acm-industrial-edge-hub.expected.yaml +++ b/tests/acm-industrial-edge-hub.expected.yaml @@ -327,3 +327,158 @@ spec: env: - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES value: "*" + - complianceType: mustonlyhave + objectDefinition: + apiVersion: argoproj.io/v1beta1 + kind: ArgoCD + metadata: + name: openshift-gitops + namespace: openshift-gitops + spec: + applicationSet: + resources: + limits: + cpu: "2" + memory: 1Gi + requests: + cpu: 250m + memory: 512Mi + webhookServer: + ingress: + enabled: false + route: + enabled: false + controller: + processors: {} + resources: + limits: + cpu: "2" + memory: 2Gi + requests: + cpu: 250m + memory: 1Gi + sharding: {} + grafana: + enabled: false + ingress: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + route: + enabled: false + ha: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + initialSSHKnownHosts: {} + monitoring: + enabled: false + notifications: + enabled: false + prometheus: + enabled: false + ingress: + enabled: false + route: + enabled: false + rbac: + defaultPolicy: "" + policy: |- + g, system:cluster-admins, role:admin + g, cluster-admins, role:admin + scopes: '[groups]' + redis: + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + repo: + initContainers: + - command: + - bash + - -c + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt + || true + image: registry.redhat.io/ubi9/ubi-minimal:latest + name: fetch-ca + resources: {} + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 250m + memory: 256Mi + volumeMounts: + - mountPath: /etc/pki/tls/certs + name: ca-bundles + volumes: + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - emptyDir: {} + name: ca-bundles + resourceExclusions: |- + - apiGroups: + - tekton.dev + clusters: + - '*' + kinds: + - TaskRun + - PipelineRun + server: + autoscale: + enabled: false + grpc: + ingress: + enabled: false + ingress: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 125m + memory: 128Mi + route: + enabled: true + service: + type: "" + sso: + dex: + openShiftOAuth: true + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + provider: dex + tls: + ca: {} diff --git a/tests/acm-medical-diagnosis-hub.expected.yaml b/tests/acm-medical-diagnosis-hub.expected.yaml index f2a8fdd6..2fd25e75 100644 --- a/tests/acm-medical-diagnosis-hub.expected.yaml +++ b/tests/acm-medical-diagnosis-hub.expected.yaml @@ -318,3 +318,158 @@ spec: env: - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES value: "*" + - complianceType: mustonlyhave + objectDefinition: + apiVersion: argoproj.io/v1beta1 + kind: ArgoCD + metadata: + name: openshift-gitops + namespace: openshift-gitops + spec: + applicationSet: + resources: + limits: + cpu: "2" + memory: 1Gi + requests: + cpu: 250m + memory: 512Mi + webhookServer: + ingress: + enabled: false + route: + enabled: false + controller: + processors: {} + resources: + limits: + cpu: "2" + memory: 2Gi + requests: + cpu: 250m + memory: 1Gi + sharding: {} + grafana: + enabled: false + ingress: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + route: + enabled: false + ha: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + initialSSHKnownHosts: {} + monitoring: + enabled: false + notifications: + enabled: false + prometheus: + enabled: false + ingress: + enabled: false + route: + enabled: false + rbac: + defaultPolicy: "" + policy: |- + g, system:cluster-admins, role:admin + g, cluster-admins, role:admin + scopes: '[groups]' + redis: + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + repo: + initContainers: + - command: + - bash + - -c + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt + || true + image: registry.redhat.io/ubi9/ubi-minimal:latest + name: fetch-ca + resources: {} + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 250m + memory: 256Mi + volumeMounts: + - mountPath: /etc/pki/tls/certs + name: ca-bundles + volumes: + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - emptyDir: {} + name: ca-bundles + resourceExclusions: |- + - apiGroups: + - tekton.dev + clusters: + - '*' + kinds: + - TaskRun + - PipelineRun + server: + autoscale: + enabled: false + grpc: + ingress: + enabled: false + ingress: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 125m + memory: 128Mi + route: + enabled: true + service: + type: "" + sso: + dex: + openShiftOAuth: true + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + provider: dex + tls: + ca: {} diff --git a/tests/acm-naked.expected.yaml b/tests/acm-naked.expected.yaml index 561fbd7b..fa867edd 100644 --- a/tests/acm-naked.expected.yaml +++ b/tests/acm-naked.expected.yaml @@ -119,3 +119,158 @@ spec: env: - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES value: "*" + - complianceType: mustonlyhave + objectDefinition: + apiVersion: argoproj.io/v1beta1 + kind: ArgoCD + metadata: + name: openshift-gitops + namespace: openshift-gitops + spec: + applicationSet: + resources: + limits: + cpu: "2" + memory: 1Gi + requests: + cpu: 250m + memory: 512Mi + webhookServer: + ingress: + enabled: false + route: + enabled: false + controller: + processors: {} + resources: + limits: + cpu: "2" + memory: 2Gi + requests: + cpu: 250m + memory: 1Gi + sharding: {} + grafana: + enabled: false + ingress: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + route: + enabled: false + ha: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + initialSSHKnownHosts: {} + monitoring: + enabled: false + notifications: + enabled: false + prometheus: + enabled: false + ingress: + enabled: false + route: + enabled: false + rbac: + defaultPolicy: "" + policy: |- + g, system:cluster-admins, role:admin + g, cluster-admins, role:admin + scopes: '[groups]' + redis: + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + repo: + initContainers: + - command: + - bash + - -c + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt + || true + image: registry.redhat.io/ubi9/ubi-minimal:latest + name: fetch-ca + resources: {} + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 250m + memory: 256Mi + volumeMounts: + - mountPath: /etc/pki/tls/certs + name: ca-bundles + volumes: + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - emptyDir: {} + name: ca-bundles + resourceExclusions: |- + - apiGroups: + - tekton.dev + clusters: + - '*' + kinds: + - TaskRun + - PipelineRun + server: + autoscale: + enabled: false + grpc: + ingress: + enabled: false + ingress: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 125m + memory: 128Mi + route: + enabled: true + service: + type: "" + sso: + dex: + openShiftOAuth: true + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + provider: dex + tls: + ca: {} diff --git a/tests/acm-normal.expected.yaml b/tests/acm-normal.expected.yaml index 8e78a98f..356d0658 100644 --- a/tests/acm-normal.expected.yaml +++ b/tests/acm-normal.expected.yaml @@ -1330,3 +1330,158 @@ spec: env: - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES value: "*" + - complianceType: mustonlyhave + objectDefinition: + apiVersion: argoproj.io/v1beta1 + kind: ArgoCD + metadata: + name: openshift-gitops + namespace: openshift-gitops + spec: + applicationSet: + resources: + limits: + cpu: "2" + memory: 1Gi + requests: + cpu: 250m + memory: 512Mi + webhookServer: + ingress: + enabled: false + route: + enabled: false + controller: + processors: {} + resources: + limits: + cpu: "2" + memory: 2Gi + requests: + cpu: 250m + memory: 1Gi + sharding: {} + grafana: + enabled: false + ingress: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + route: + enabled: false + ha: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + initialSSHKnownHosts: {} + monitoring: + enabled: false + notifications: + enabled: false + prometheus: + enabled: false + ingress: + enabled: false + route: + enabled: false + rbac: + defaultPolicy: "" + policy: |- + g, system:cluster-admins, role:admin + g, cluster-admins, role:admin + scopes: '[groups]' + redis: + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + repo: + initContainers: + - command: + - bash + - -c + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt + || true + image: registry.redhat.io/ubi9/ubi-minimal:latest + name: fetch-ca + resources: {} + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 250m + memory: 256Mi + volumeMounts: + - mountPath: /etc/pki/tls/certs + name: ca-bundles + volumes: + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - emptyDir: {} + name: ca-bundles + resourceExclusions: |- + - apiGroups: + - tekton.dev + clusters: + - '*' + kinds: + - TaskRun + - PipelineRun + server: + autoscale: + enabled: false + grpc: + ingress: + enabled: false + ingress: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 125m + memory: 128Mi + route: + enabled: true + service: + type: "" + sso: + dex: + openShiftOAuth: true + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + provider: dex + tls: + ca: {} diff --git a/tests/clustergroup-industrial-edge-factory.expected.yaml b/tests/clustergroup-industrial-edge-factory.expected.yaml index 4e18f8cb..2242f75d 100644 --- a/tests/clustergroup-industrial-edge-factory.expected.yaml +++ b/tests/clustergroup-industrial-edge-factory.expected.yaml @@ -417,6 +417,25 @@ spec: 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: fetch-ca + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + imagePullPolicy: Always + env: + - name: HOME + value: /git/home + command: + - 'sh' + - '-c' + - >- + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true; + ls -l /tmp/ca-bundles/ + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles - name: git-init image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest imagePullPolicy: Always @@ -426,6 +445,8 @@ spec: volumeMounts: - name: git mountPath: "/git" + - name: ca-bundles + mountPath: /etc/pki/tls/certs command: - 'sh' - '-c' @@ -477,6 +498,12 @@ spec: - name: values-volume mountPath: /values/values.yaml subPath: values.yaml + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles containers: - name: "done" image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -493,6 +520,15 @@ spec: - name: values-volume configMap: name: helm-values-configmap-factory + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - name: ca-bundles + emptyDir: {} restartPolicy: Never --- # Source: clustergroup/templates/core/subscriptions.yaml @@ -673,6 +709,41 @@ spec: rbac: defaultPolicy: role:admin repo: + initContainers: + - command: + - bash + - -c + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + name: fetch-ca + resources: {} + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 250m + memory: 256Mi + volumeMounts: + - mountPath: /etc/pki/tls/certs + name: ca-bundles + volumes: + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - emptyDir: {} + name: ca-bundles sidecarContainers: - name: helm-with-kustomize command: [/var/run/argocd/argocd-cmp-server] diff --git a/tests/clustergroup-industrial-edge-hub.expected.yaml b/tests/clustergroup-industrial-edge-hub.expected.yaml index 1af3211d..5e64dc60 100644 --- a/tests/clustergroup-industrial-edge-hub.expected.yaml +++ b/tests/clustergroup-industrial-edge-hub.expected.yaml @@ -578,6 +578,25 @@ spec: 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: fetch-ca + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + imagePullPolicy: Always + env: + - name: HOME + value: /git/home + command: + - 'sh' + - '-c' + - >- + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true; + ls -l /tmp/ca-bundles/ + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles - name: git-init image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest imagePullPolicy: Always @@ -587,6 +606,8 @@ spec: volumeMounts: - name: git mountPath: "/git" + - name: ca-bundles + mountPath: /etc/pki/tls/certs command: - 'sh' - '-c' @@ -638,6 +659,12 @@ spec: - name: values-volume mountPath: /values/values.yaml subPath: values.yaml + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles containers: - name: "done" image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -654,6 +681,15 @@ spec: - name: values-volume configMap: name: helm-values-configmap-datacenter + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - name: ca-bundles + emptyDir: {} restartPolicy: Never --- # Source: clustergroup/templates/imperative/unsealjob.yaml @@ -677,6 +713,25 @@ spec: 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: fetch-ca + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + imagePullPolicy: Always + env: + - name: HOME + value: /git/home + command: + - 'sh' + - '-c' + - >- + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true; + ls -l /tmp/ca-bundles/ + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles - name: git-init image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest imagePullPolicy: Always @@ -686,6 +741,8 @@ spec: volumeMounts: - name: git mountPath: "/git" + - name: ca-bundles + mountPath: /etc/pki/tls/certs command: - 'sh' - '-c' @@ -739,6 +796,12 @@ spec: - name: values-volume mountPath: /values/values.yaml subPath: values.yaml + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles containers: - name: "done" image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -755,6 +818,15 @@ spec: - name: values-volume configMap: name: helm-values-configmap-datacenter + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - name: ca-bundles + emptyDir: {} restartPolicy: Never --- # Source: clustergroup/templates/core/subscriptions.yaml @@ -1403,6 +1475,41 @@ spec: rbac: defaultPolicy: role:admin repo: + initContainers: + - command: + - bash + - -c + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + name: fetch-ca + resources: {} + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 250m + memory: 256Mi + volumeMounts: + - mountPath: /etc/pki/tls/certs + name: ca-bundles + volumes: + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - emptyDir: {} + name: ca-bundles sidecarContainers: - name: helm-with-kustomize command: [/var/run/argocd/argocd-cmp-server] diff --git a/tests/clustergroup-medical-diagnosis-hub.expected.yaml b/tests/clustergroup-medical-diagnosis-hub.expected.yaml index 2d9a4d36..1ea53dc6 100644 --- a/tests/clustergroup-medical-diagnosis-hub.expected.yaml +++ b/tests/clustergroup-medical-diagnosis-hub.expected.yaml @@ -505,6 +505,25 @@ spec: 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: fetch-ca + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + imagePullPolicy: Always + env: + - name: HOME + value: /git/home + command: + - 'sh' + - '-c' + - >- + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true; + ls -l /tmp/ca-bundles/ + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles - name: git-init image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest imagePullPolicy: Always @@ -514,6 +533,8 @@ spec: volumeMounts: - name: git mountPath: "/git" + - name: ca-bundles + mountPath: /etc/pki/tls/certs command: - 'sh' - '-c' @@ -565,6 +586,12 @@ spec: - name: values-volume mountPath: /values/values.yaml subPath: values.yaml + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles containers: - name: "done" image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -581,6 +608,15 @@ spec: - name: values-volume configMap: name: helm-values-configmap-hub + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - name: ca-bundles + emptyDir: {} restartPolicy: Never --- # Source: clustergroup/templates/imperative/unsealjob.yaml @@ -604,6 +640,25 @@ spec: 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: fetch-ca + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + imagePullPolicy: Always + env: + - name: HOME + value: /git/home + command: + - 'sh' + - '-c' + - >- + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true; + ls -l /tmp/ca-bundles/ + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles - name: git-init image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest imagePullPolicy: Always @@ -613,6 +668,8 @@ spec: volumeMounts: - name: git mountPath: "/git" + - name: ca-bundles + mountPath: /etc/pki/tls/certs command: - 'sh' - '-c' @@ -666,6 +723,12 @@ spec: - name: values-volume mountPath: /values/values.yaml subPath: values.yaml + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles containers: - name: "done" image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -682,6 +745,15 @@ spec: - name: values-volume configMap: name: helm-values-configmap-hub + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - name: ca-bundles + emptyDir: {} restartPolicy: Never --- # Source: clustergroup/templates/core/subscriptions.yaml @@ -1588,6 +1660,41 @@ spec: rbac: defaultPolicy: role:admin repo: + initContainers: + - command: + - bash + - -c + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + name: fetch-ca + resources: {} + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 250m + memory: 256Mi + volumeMounts: + - mountPath: /etc/pki/tls/certs + name: ca-bundles + volumes: + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - emptyDir: {} + name: ca-bundles resources: limits: cpu: "1" diff --git a/tests/clustergroup-naked.expected.yaml b/tests/clustergroup-naked.expected.yaml index a7fee415..bd89773a 100644 --- a/tests/clustergroup-naked.expected.yaml +++ b/tests/clustergroup-naked.expected.yaml @@ -270,6 +270,25 @@ spec: 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: fetch-ca + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + imagePullPolicy: Always + env: + - name: HOME + value: /git/home + command: + - 'sh' + - '-c' + - >- + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true; + ls -l /tmp/ca-bundles/ + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles - name: git-init image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest imagePullPolicy: Always @@ -279,6 +298,8 @@ spec: volumeMounts: - name: git mountPath: "/git" + - name: ca-bundles + mountPath: /etc/pki/tls/certs command: - 'sh' - '-c' @@ -332,6 +353,12 @@ spec: - name: values-volume mountPath: /values/values.yaml subPath: values.yaml + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles containers: - name: "done" image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -348,6 +375,15 @@ spec: - name: values-volume configMap: name: helm-values-configmap-example + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - name: ca-bundles + emptyDir: {} restartPolicy: Never --- # Source: clustergroup/templates/plumbing/argocd.yaml @@ -419,6 +455,41 @@ spec: rbac: defaultPolicy: role:admin repo: + initContainers: + - command: + - bash + - -c + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + name: fetch-ca + resources: {} + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 250m + memory: 256Mi + volumeMounts: + - mountPath: /etc/pki/tls/certs + name: ca-bundles + volumes: + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - emptyDir: {} + name: ca-bundles resources: limits: cpu: "1" diff --git a/tests/clustergroup-normal.expected.yaml b/tests/clustergroup-normal.expected.yaml index bc04b88e..13daced6 100644 --- a/tests/clustergroup-normal.expected.yaml +++ b/tests/clustergroup-normal.expected.yaml @@ -486,6 +486,25 @@ spec: 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: fetch-ca + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + imagePullPolicy: Always + env: + - name: HOME + value: /git/home + command: + - 'sh' + - '-c' + - >- + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true; + ls -l /tmp/ca-bundles/ + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles - name: git-init image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest imagePullPolicy: Always @@ -495,6 +514,8 @@ spec: volumeMounts: - name: git mountPath: "/git" + - name: ca-bundles + mountPath: /etc/pki/tls/certs command: - 'sh' - '-c' @@ -546,6 +567,12 @@ spec: - name: values-volume mountPath: /values/values.yaml subPath: values.yaml + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles containers: - name: "done" image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -562,6 +589,15 @@ spec: - name: values-volume configMap: name: helm-values-configmap-example + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - name: ca-bundles + emptyDir: {} restartPolicy: Never --- # Source: clustergroup/templates/imperative/unsealjob.yaml @@ -585,6 +621,25 @@ spec: 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: fetch-ca + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + imagePullPolicy: Always + env: + - name: HOME + value: /git/home + command: + - 'sh' + - '-c' + - >- + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true; + ls -l /tmp/ca-bundles/ + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles - name: git-init image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest imagePullPolicy: Always @@ -594,6 +649,8 @@ spec: volumeMounts: - name: git mountPath: "/git" + - name: ca-bundles + mountPath: /etc/pki/tls/certs command: - 'sh' - '-c' @@ -647,6 +704,12 @@ spec: - name: values-volume mountPath: /values/values.yaml subPath: values.yaml + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles containers: - name: "done" image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -663,6 +726,15 @@ spec: - name: values-volume configMap: name: helm-values-configmap-example + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - name: ca-bundles + emptyDir: {} restartPolicy: Never --- # Source: clustergroup/templates/core/operatorgroup.yaml @@ -1152,6 +1224,41 @@ spec: rbac: defaultPolicy: role:admin repo: + initContainers: + - command: + - bash + - -c + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + name: fetch-ca + resources: {} + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 250m + memory: 256Mi + volumeMounts: + - mountPath: /etc/pki/tls/certs + name: ca-bundles + volumes: + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - emptyDir: {} + name: ca-bundles resources: limits: cpu: "1" From b489135f33510dc1c489e246c8c9248151a57d52 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Fri, 7 Jun 2024 11:14:41 +0200 Subject: [PATCH 27/64] Release clustergroup v0.8.7 --- clustergroup/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clustergroup/Chart.yaml b/clustergroup/Chart.yaml index 2ddd15ba..222a2482 100644 --- a/clustergroup/Chart.yaml +++ b/clustergroup/Chart.yaml @@ -3,4 +3,4 @@ description: A Helm chart to create per-clustergroup ArgoCD applications and any keywords: - pattern name: clustergroup -version: 0.8.6 +version: 0.8.7 From d846593fe8bd2a4be8537c93d5784afc818a27b5 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Fri, 7 Jun 2024 14:48:36 +0200 Subject: [PATCH 28/64] Upgrade ESO to v0.9.19 --- golang-external-secrets/Chart.yaml | 2 +- .../charts/external-secrets-0.9.18.tgz | Bin 76336 -> 0 bytes .../charts/external-secrets-0.9.19.tgz | Bin 0 -> 76457 bytes golang-external-secrets/values.yaml | 6 +- ...rets-industrial-edge-factory.expected.yaml | 100 ++++++++++-------- ...-secrets-industrial-edge-hub.expected.yaml | 100 ++++++++++-------- ...ecrets-medical-diagnosis-hub.expected.yaml | 100 ++++++++++-------- ...olang-external-secrets-naked.expected.yaml | 100 ++++++++++-------- ...lang-external-secrets-normal.expected.yaml | 100 ++++++++++-------- 9 files changed, 279 insertions(+), 229 deletions(-) delete mode 100644 golang-external-secrets/charts/external-secrets-0.9.18.tgz create mode 100644 golang-external-secrets/charts/external-secrets-0.9.19.tgz diff --git a/golang-external-secrets/Chart.yaml b/golang-external-secrets/Chart.yaml index 4aef19aa..afffe393 100644 --- a/golang-external-secrets/Chart.yaml +++ b/golang-external-secrets/Chart.yaml @@ -6,6 +6,6 @@ name: golang-external-secrets version: 0.0.3 dependencies: - name: external-secrets - version: "0.9.18" + version: "0.9.19" repository: "https://charts.external-secrets.io" #"https://external-secrets.github.io/kubernetes-external-secrets" diff --git a/golang-external-secrets/charts/external-secrets-0.9.18.tgz b/golang-external-secrets/charts/external-secrets-0.9.18.tgz deleted file mode 100644 index 7aa6d4505f93b7754cdc2f6c712ff8724153f85c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 76336 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
q0j)i=a#pu1jU+b_58*02a$>ktMv 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 diff --git a/golang-external-secrets/charts/external-secrets-0.9.19.tgz b/golang-external-secrets/charts/external-secrets-0.9.19.tgz new file mode 100644 index 0000000000000000000000000000000000000000..66fffaa0b08d686867fc9e4307204eaae1e22964 GIT binary patch literal 76457 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

-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 Date: Fri, 7 Jun 2024 19:49:02 +0200 Subject: [PATCH 29/64] Update helm version in CI to 3.14.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's the version gitops 1.12 is using these days: ❯ oc exec -it -n openshift-gitops openshift-gitops-repo-server-66bf746964-926qk -c argocd-repo-server -- bash -c "helm version" version.BuildInfo{Version:"v3.14.0", GitCommit:"2a2fb3b98829f1e0be6fb18af2f6599e0f4e8243", GitTreeState:"", GoVersion:"go1.21.9 (Red Hat 1.21.9-1.module+el8.10.0+21671+b35c3b78)"} --- .github/workflows/linter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 39843f26..f82194ee 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -36,7 +36,7 @@ jobs: - name: Setup helm uses: azure/setup-helm@v4 with: - version: 'v3.13.2' + version: 'v3.14.0' ################################ From 429f55cea86954bbe92c4f36094751847d8930ee Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Mon, 10 Jun 2024 10:37:05 +0200 Subject: [PATCH 30/64] Drop imperative.initcontainers.gitinit Now that we switched to imperative.initcontainers.gitinit-ca, the older define is not used anywhere, so we can drop this. --- .../templates/imperative/_helpers.tpl | 42 ------------------- 1 file changed, 42 deletions(-) diff --git a/clustergroup/templates/imperative/_helpers.tpl b/clustergroup/templates/imperative/_helpers.tpl index d55220e4..18735dec 100644 --- a/clustergroup/templates/imperative/_helpers.tpl +++ b/clustergroup/templates/imperative/_helpers.tpl @@ -27,48 +27,6 @@ name: ca-bundles {{- end }} -{{/* git-init InitContainer */}} -{{- define "imperative.initcontainers.gitinit" }} -- name: git-init - image: {{ $.Values.clusterGroup.imperative.image }} - imagePullPolicy: {{ $.Values.clusterGroup.imperative.imagePullPolicy }} - env: - - name: HOME - value: /git/home - volumeMounts: - - name: git - mountPath: "/git" - command: - - 'sh' - - '-c' - - >- - if ! oc get secrets -n openshift-gitops vp-private-repo-credentials &> /dev/null; then - URL="{{ $.Values.global.repoURL }}"; - else - if ! oc get secrets -n openshift-gitops vp-private-repo-credentials -o go-template='{{ `{{index .data.sshPrivateKey | base64decode}}` }}' &>/dev/null; then - U="$(oc get secret -n openshift-gitops vp-private-repo-credentials -o go-template='{{ `{{index .data.username | base64decode }}` }}')"; - P="$(oc get secret -n openshift-gitops vp-private-repo-credentials -o go-template='{{ `{{index .data.password | base64decode }}` }}')"; - URL=$(echo {{ $.Values.global.repoURL }} | sed -E "s/(https?:\/\/)/\1${U}:${P}@/"); - else - S="$(oc get secret -n openshift-gitops vp-private-repo-credentials -o go-template='{{ `{{index .data.sshPrivateKey | base64decode }}` }}')"; - mkdir -p --mode 0700 "${HOME}/.ssh"; - echo "${S}" > "${HOME}/.ssh/id_rsa"; - chmod 0600 "${HOME}/.ssh/id_rsa"; - URL=$(echo {{ $.Values.global.repoURL }} | sed -E "s/(https?:\/\/)/\1git@/"); - git config --global core.sshCommand "ssh -i "${HOME}/.ssh/id_rsa" -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"; - fi; - fi; - OUT="$(oc get proxy.config.openshift.io/cluster -o jsonpath='{.spec.httpProxy}' 2>/dev/null)"; - if [ -n "${OUT}" ]; then export HTTP_PROXY="${OUT}"; fi; - OUT="$(oc get proxy.config.openshift.io/cluster -o jsonpath='{.spec.httpsProxy}' 2>/dev/null)"; - if [ -n "${OUT}" ]; then export HTTPS_PROXY="${OUT}"; fi; - OUT="$(oc get proxy.config.openshift.io/cluster -o jsonpath='{.spec.noProxy}' 2>/dev/null)"; - if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; - mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch --branch {{ $.Values.global.targetRevision }} --depth 1 -- "${URL}" /git/repo; - chmod 0770 /git/{repo,home}; -{{- end }} - {{/* git-init-ca InitContainer */}} {{- define "imperative.initcontainers.gitinit-ca" }} - name: git-init From e967b159b31dc839d894088c1b67893c1408ed57 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Mon, 10 Jun 2024 10:41:26 +0200 Subject: [PATCH 31/64] Have unseal work whenever we specifiy HEAD Otherwise if HEAD is specified we get the following: mkdir: cannot create directory '/git/home': File exists Cloning into '/git/repo'... warning: Could not find remote branch HEAD to clone. fatal: Remote branch HEAD not found in upstream origin --- clustergroup/templates/imperative/_helpers.tpl | 3 ++- tests/clustergroup-industrial-edge-factory.expected.yaml | 3 ++- tests/clustergroup-industrial-edge-hub.expected.yaml | 6 ++++-- tests/clustergroup-medical-diagnosis-hub.expected.yaml | 6 ++++-- tests/clustergroup-naked.expected.yaml | 3 ++- tests/clustergroup-normal.expected.yaml | 6 ++++-- 6 files changed, 18 insertions(+), 9 deletions(-) diff --git a/clustergroup/templates/imperative/_helpers.tpl b/clustergroup/templates/imperative/_helpers.tpl index 18735dec..c7f986e4 100644 --- a/clustergroup/templates/imperative/_helpers.tpl +++ b/clustergroup/templates/imperative/_helpers.tpl @@ -66,8 +66,9 @@ if [ -n "${OUT}" ]; then export HTTPS_PROXY="${OUT}"; fi; OUT="$(oc get proxy.config.openshift.io/cluster -o jsonpath='{.spec.noProxy}' 2>/dev/null)"; if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; + if [ "{{ $.Values.global.targetRevision }}" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch {{ $.Values.global.targetRevision }}"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch --branch {{ $.Values.global.targetRevision }} --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch "${BRANCH}" --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; {{- end }} {{/* Final done container */}} diff --git a/tests/clustergroup-industrial-edge-factory.expected.yaml b/tests/clustergroup-industrial-edge-factory.expected.yaml index 2242f75d..ccd2a52c 100644 --- a/tests/clustergroup-industrial-edge-factory.expected.yaml +++ b/tests/clustergroup-industrial-edge-factory.expected.yaml @@ -473,8 +473,9 @@ spec: if [ -n "${OUT}" ]; then export HTTPS_PROXY="${OUT}"; fi; OUT="$(oc get proxy.config.openshift.io/cluster -o jsonpath='{.spec.noProxy}' 2>/dev/null)"; if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; + if [ "main" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch main"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch --branch main --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch "${BRANCH}" --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; - name: test image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest diff --git a/tests/clustergroup-industrial-edge-hub.expected.yaml b/tests/clustergroup-industrial-edge-hub.expected.yaml index 5e64dc60..2486927b 100644 --- a/tests/clustergroup-industrial-edge-hub.expected.yaml +++ b/tests/clustergroup-industrial-edge-hub.expected.yaml @@ -634,8 +634,9 @@ spec: if [ -n "${OUT}" ]; then export HTTPS_PROXY="${OUT}"; fi; OUT="$(oc get proxy.config.openshift.io/cluster -o jsonpath='{.spec.noProxy}' 2>/dev/null)"; if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; + if [ "main" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch main"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch --branch main --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch "${BRANCH}" --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; - name: test image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -769,8 +770,9 @@ spec: if [ -n "${OUT}" ]; then export HTTPS_PROXY="${OUT}"; fi; OUT="$(oc get proxy.config.openshift.io/cluster -o jsonpath='{.spec.noProxy}' 2>/dev/null)"; if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; + if [ "main" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch main"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch --branch main --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch "${BRANCH}" --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; - name: unseal-playbook image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest diff --git a/tests/clustergroup-medical-diagnosis-hub.expected.yaml b/tests/clustergroup-medical-diagnosis-hub.expected.yaml index 1ea53dc6..908f526f 100644 --- a/tests/clustergroup-medical-diagnosis-hub.expected.yaml +++ b/tests/clustergroup-medical-diagnosis-hub.expected.yaml @@ -561,8 +561,9 @@ spec: if [ -n "${OUT}" ]; then export HTTPS_PROXY="${OUT}"; fi; OUT="$(oc get proxy.config.openshift.io/cluster -o jsonpath='{.spec.noProxy}' 2>/dev/null)"; if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; + if [ "main" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch main"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch --branch main --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch "${BRANCH}" --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; - name: test image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -696,8 +697,9 @@ spec: if [ -n "${OUT}" ]; then export HTTPS_PROXY="${OUT}"; fi; OUT="$(oc get proxy.config.openshift.io/cluster -o jsonpath='{.spec.noProxy}' 2>/dev/null)"; if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; + if [ "main" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch main"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch --branch main --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch "${BRANCH}" --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; - name: unseal-playbook image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest diff --git a/tests/clustergroup-naked.expected.yaml b/tests/clustergroup-naked.expected.yaml index bd89773a..4a417d5d 100644 --- a/tests/clustergroup-naked.expected.yaml +++ b/tests/clustergroup-naked.expected.yaml @@ -326,8 +326,9 @@ spec: if [ -n "${OUT}" ]; then export HTTPS_PROXY="${OUT}"; fi; OUT="$(oc get proxy.config.openshift.io/cluster -o jsonpath='{.spec.noProxy}' 2>/dev/null)"; if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; + if [ "main" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch main"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch --branch main --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch "${BRANCH}" --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; - name: unseal-playbook image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest diff --git a/tests/clustergroup-normal.expected.yaml b/tests/clustergroup-normal.expected.yaml index 13daced6..efb98493 100644 --- a/tests/clustergroup-normal.expected.yaml +++ b/tests/clustergroup-normal.expected.yaml @@ -542,8 +542,9 @@ spec: if [ -n "${OUT}" ]; then export HTTPS_PROXY="${OUT}"; fi; OUT="$(oc get proxy.config.openshift.io/cluster -o jsonpath='{.spec.noProxy}' 2>/dev/null)"; if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; + if [ "main" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch main"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch --branch main --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch "${BRANCH}" --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; - name: test image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -677,8 +678,9 @@ spec: if [ -n "${OUT}" ]; then export HTTPS_PROXY="${OUT}"; fi; OUT="$(oc get proxy.config.openshift.io/cluster -o jsonpath='{.spec.noProxy}' 2>/dev/null)"; if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; + if [ "main" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch main"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch --branch main --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch "${BRANCH}" --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; - name: unseal-playbook image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest From 85c3a9bec46378570b2e1df8aaa0c073151980af Mon Sep 17 00:00:00 2001 From: Trevor Royer Date: Wed, 5 Jun 2024 15:09:06 -0600 Subject: [PATCH 32/64] make resourceExclusion configurable --- clustergroup/templates/plumbing/argocd.yaml | 9 +++------ clustergroup/values.schema.json | 4 ++++ clustergroup/values.yaml | 6 ++++++ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/clustergroup/templates/plumbing/argocd.yaml b/clustergroup/templates/plumbing/argocd.yaml index 7d42ec36..68b692ff 100644 --- a/clustergroup/templates/plumbing/argocd.yaml +++ b/clustergroup/templates/plumbing/argocd.yaml @@ -150,12 +150,9 @@ spec: requests: cpu: 250m memory: 256Mi - resourceExclusions: | - - apiGroups: - - tekton.dev - kinds: - - TaskRun - - PipelineRun +{{- if $.Values.clusterGroup.argoCD.resourceExclusions }} + resourceExclusions: {{- $.Values.clusterGroup.argoCD.resourceExclusions | toYaml | indent 2 }} +{{- end }} {{- if .Values.global.excludeESO }} - apiGroups: - external-secrets.io diff --git a/clustergroup/values.schema.json b/clustergroup/values.schema.json index 2955bf1a..e0331497 100644 --- a/clustergroup/values.schema.json +++ b/clustergroup/values.schema.json @@ -548,6 +548,10 @@ "initContainers": { "type": "array", "description": "A list of initContainers to add to the repo-server if needed" + }, + "resourceExclusions": { + "type": "string", + "description": "ResourceExclusions is used to completely ignore entire classes of resource group/kinds." } } }, diff --git a/clustergroup/values.yaml b/clustergroup/values.yaml index bb149567..94a01af9 100644 --- a/clustergroup/values.yaml +++ b/clustergroup/values.yaml @@ -28,6 +28,12 @@ clusterGroup: argoCD: initContainers: [] configManagementPlugins: [] + resourceExclusions: | + - apiGroups: + - tekton.dev + kinds: + - TaskRun + - PipelineRun imperative: jobs: [] From 05a876bf60fa5787cec1480394ce875dff3a5207 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Mon, 10 Jun 2024 16:57:23 +0200 Subject: [PATCH 33/64] Update tests after upgrading resourceExclusions tweak --- tests/clustergroup-industrial-edge-factory.expected.yaml | 8 +++++++- tests/clustergroup-industrial-edge-hub.expected.yaml | 8 +++++++- tests/clustergroup-medical-diagnosis-hub.expected.yaml | 8 +++++++- tests/clustergroup-naked.expected.yaml | 8 +++++++- tests/clustergroup-normal.expected.yaml | 8 +++++++- 5 files changed, 35 insertions(+), 5 deletions(-) diff --git a/tests/clustergroup-industrial-edge-factory.expected.yaml b/tests/clustergroup-industrial-edge-factory.expected.yaml index ccd2a52c..d651d450 100644 --- a/tests/clustergroup-industrial-edge-factory.expected.yaml +++ b/tests/clustergroup-industrial-edge-factory.expected.yaml @@ -121,6 +121,12 @@ data: --set clusterGroup.name=factory --post-renderer ./kustomize"] initContainers: [] + resourceExclusions: | + - apiGroups: + - tekton.dev + kinds: + - TaskRun + - PipelineRun imperative: activeDeadlineSeconds: 3600 adminClusterRoleName: imperative-admin-cluster-role @@ -778,7 +784,7 @@ spec: requests: cpu: 250m memory: 256Mi - resourceExclusions: | + resourceExclusions: | - apiGroups: - tekton.dev kinds: diff --git a/tests/clustergroup-industrial-edge-hub.expected.yaml b/tests/clustergroup-industrial-edge-hub.expected.yaml index 2486927b..eec93391 100644 --- a/tests/clustergroup-industrial-edge-hub.expected.yaml +++ b/tests/clustergroup-industrial-edge-hub.expected.yaml @@ -242,6 +242,12 @@ data: --set clusterGroup.name=datacenter --post-renderer ./kustomize"] initContainers: [] + resourceExclusions: | + - apiGroups: + - tekton.dev + kinds: + - TaskRun + - PipelineRun imperative: activeDeadlineSeconds: 3600 adminClusterRoleName: imperative-admin-cluster-role @@ -1545,7 +1551,7 @@ spec: requests: cpu: 250m memory: 256Mi - resourceExclusions: | + resourceExclusions: | - apiGroups: - tekton.dev kinds: diff --git a/tests/clustergroup-medical-diagnosis-hub.expected.yaml b/tests/clustergroup-medical-diagnosis-hub.expected.yaml index 908f526f..17e26914 100644 --- a/tests/clustergroup-medical-diagnosis-hub.expected.yaml +++ b/tests/clustergroup-medical-diagnosis-hub.expected.yaml @@ -225,6 +225,12 @@ data: argoCD: configManagementPlugins: [] initContainers: [] + resourceExclusions: | + - apiGroups: + - tekton.dev + kinds: + - TaskRun + - PipelineRun imperative: activeDeadlineSeconds: 3600 adminClusterRoleName: imperative-admin-cluster-role @@ -1704,7 +1710,7 @@ spec: requests: cpu: 250m memory: 256Mi - resourceExclusions: | + resourceExclusions: | - apiGroups: - tekton.dev kinds: diff --git a/tests/clustergroup-naked.expected.yaml b/tests/clustergroup-naked.expected.yaml index 4a417d5d..3c8294d1 100644 --- a/tests/clustergroup-naked.expected.yaml +++ b/tests/clustergroup-naked.expected.yaml @@ -48,6 +48,12 @@ data: argoCD: configManagementPlugins: [] initContainers: [] + resourceExclusions: | + - apiGroups: + - tekton.dev + kinds: + - TaskRun + - PipelineRun imperative: activeDeadlineSeconds: 3600 adminClusterRoleName: imperative-admin-cluster-role @@ -498,7 +504,7 @@ spec: requests: cpu: 250m memory: 256Mi - resourceExclusions: | + resourceExclusions: | - apiGroups: - tekton.dev kinds: diff --git a/tests/clustergroup-normal.expected.yaml b/tests/clustergroup-normal.expected.yaml index efb98493..4cb54949 100644 --- a/tests/clustergroup-normal.expected.yaml +++ b/tests/clustergroup-normal.expected.yaml @@ -133,6 +133,12 @@ data: argoCD: configManagementPlugins: [] initContainers: [] + resourceExclusions: | + - apiGroups: + - tekton.dev + kinds: + - TaskRun + - PipelineRun imperative: activeDeadlineSeconds: 3600 adminClusterRoleName: imperative-admin-cluster-role @@ -1268,7 +1274,7 @@ spec: requests: cpu: 250m memory: 256Mi - resourceExclusions: | + resourceExclusions: | - apiGroups: - tekton.dev kinds: From e97b2e7313c4161e382ecbae8ef4bc1e093de000 Mon Sep 17 00:00:00 2001 From: Trevor Royer Date: Wed, 5 Jun 2024 14:42:50 -0600 Subject: [PATCH 34/64] Make resourcehealthchecks configurable --- clustergroup/values.schema.json | 22 ++++++++++++++++++++++ clustergroup/values.yaml | 20 ++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/clustergroup/values.schema.json b/clustergroup/values.schema.json index e0331497..b05dcb03 100644 --- a/clustergroup/values.schema.json +++ b/clustergroup/values.schema.json @@ -552,6 +552,13 @@ "resourceExclusions": { "type": "string", "description": "ResourceExclusions is used to completely ignore entire classes of resource group/kinds." + }, + "resourceHealthChecks": { + "type": "array", + "items": { + "$ref": "#/definitions/ArgoCDResourceHealthChecks" + }, + "description": "ResourceHealthChecks customizes resource health check behavior." } } }, @@ -585,6 +592,21 @@ "image" ] }, + "ArgoCDResourceHealthChecks": { + "type": "object", + "additionalProperties": false, + "properties": { + "check": { + "type": "string" + }, + "group": { + "type": "string" + }, + "kind": { + "type": "string" + } + } + }, "IndexImages": { "type": "object", "description": "Details for overriding default catalog sources", diff --git a/clustergroup/values.yaml b/clustergroup/values.yaml index 94a01af9..cdbf823e 100644 --- a/clustergroup/values.yaml +++ b/clustergroup/values.yaml @@ -28,6 +28,26 @@ clusterGroup: argoCD: initContainers: [] configManagementPlugins: [] + resourceHealthChecks: + - kind: PersistentVolumeClaim + check: | + hs = {} + if obj.status ~= nil then + if obj.status.phase ~= nil then + if obj.status.phase == "Pending" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + elseif obj.status.phase == "Bound" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + end + end + end + hs.status = "Progressing" + hs.message = "Waiting for PVC" + return hs resourceExclusions: | - apiGroups: - tekton.dev From 8d1aaab0a77c9a2c4226b46f8160409ad34fa033 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Mon, 10 Jun 2024 17:23:39 +0200 Subject: [PATCH 35/64] Update tests after upgrading resourceHealthChecks change --- ...roup-industrial-edge-factory.expected.yaml | 20 +++++++++++++++++++ ...tergroup-industrial-edge-hub.expected.yaml | 20 +++++++++++++++++++ ...rgroup-medical-diagnosis-hub.expected.yaml | 20 +++++++++++++++++++ tests/clustergroup-naked.expected.yaml | 20 +++++++++++++++++++ tests/clustergroup-normal.expected.yaml | 20 +++++++++++++++++++ 5 files changed, 100 insertions(+) diff --git a/tests/clustergroup-industrial-edge-factory.expected.yaml b/tests/clustergroup-industrial-edge-factory.expected.yaml index d651d450..96cf061c 100644 --- a/tests/clustergroup-industrial-edge-factory.expected.yaml +++ b/tests/clustergroup-industrial-edge-factory.expected.yaml @@ -127,6 +127,26 @@ data: kinds: - TaskRun - PipelineRun + resourceHealthChecks: + - check: | + hs = {} + if obj.status ~= nil then + if obj.status.phase ~= nil then + if obj.status.phase == "Pending" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + elseif obj.status.phase == "Bound" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + end + end + end + hs.status = "Progressing" + hs.message = "Waiting for PVC" + return hs + kind: PersistentVolumeClaim imperative: activeDeadlineSeconds: 3600 adminClusterRoleName: imperative-admin-cluster-role diff --git a/tests/clustergroup-industrial-edge-hub.expected.yaml b/tests/clustergroup-industrial-edge-hub.expected.yaml index eec93391..eaf5b736 100644 --- a/tests/clustergroup-industrial-edge-hub.expected.yaml +++ b/tests/clustergroup-industrial-edge-hub.expected.yaml @@ -248,6 +248,26 @@ data: kinds: - TaskRun - PipelineRun + resourceHealthChecks: + - check: | + hs = {} + if obj.status ~= nil then + if obj.status.phase ~= nil then + if obj.status.phase == "Pending" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + elseif obj.status.phase == "Bound" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + end + end + end + hs.status = "Progressing" + hs.message = "Waiting for PVC" + return hs + kind: PersistentVolumeClaim imperative: activeDeadlineSeconds: 3600 adminClusterRoleName: imperative-admin-cluster-role diff --git a/tests/clustergroup-medical-diagnosis-hub.expected.yaml b/tests/clustergroup-medical-diagnosis-hub.expected.yaml index 17e26914..e834bd9e 100644 --- a/tests/clustergroup-medical-diagnosis-hub.expected.yaml +++ b/tests/clustergroup-medical-diagnosis-hub.expected.yaml @@ -231,6 +231,26 @@ data: kinds: - TaskRun - PipelineRun + resourceHealthChecks: + - check: | + hs = {} + if obj.status ~= nil then + if obj.status.phase ~= nil then + if obj.status.phase == "Pending" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + elseif obj.status.phase == "Bound" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + end + end + end + hs.status = "Progressing" + hs.message = "Waiting for PVC" + return hs + kind: PersistentVolumeClaim imperative: activeDeadlineSeconds: 3600 adminClusterRoleName: imperative-admin-cluster-role diff --git a/tests/clustergroup-naked.expected.yaml b/tests/clustergroup-naked.expected.yaml index 3c8294d1..04724078 100644 --- a/tests/clustergroup-naked.expected.yaml +++ b/tests/clustergroup-naked.expected.yaml @@ -54,6 +54,26 @@ data: kinds: - TaskRun - PipelineRun + resourceHealthChecks: + - check: | + hs = {} + if obj.status ~= nil then + if obj.status.phase ~= nil then + if obj.status.phase == "Pending" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + elseif obj.status.phase == "Bound" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + end + end + end + hs.status = "Progressing" + hs.message = "Waiting for PVC" + return hs + kind: PersistentVolumeClaim imperative: activeDeadlineSeconds: 3600 adminClusterRoleName: imperative-admin-cluster-role diff --git a/tests/clustergroup-normal.expected.yaml b/tests/clustergroup-normal.expected.yaml index 4cb54949..c28834d5 100644 --- a/tests/clustergroup-normal.expected.yaml +++ b/tests/clustergroup-normal.expected.yaml @@ -139,6 +139,26 @@ data: kinds: - TaskRun - PipelineRun + resourceHealthChecks: + - check: | + hs = {} + if obj.status ~= nil then + if obj.status.phase ~= nil then + if obj.status.phase == "Pending" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + elseif obj.status.phase == "Bound" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + end + end + end + hs.status = "Progressing" + hs.message = "Waiting for PVC" + return hs + kind: PersistentVolumeClaim imperative: activeDeadlineSeconds: 3600 adminClusterRoleName: imperative-admin-cluster-role From 32194d1ad4c3cce0f4d7c8ce3c8877a30b83914a Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Mon, 10 Jun 2024 18:10:27 +0200 Subject: [PATCH 36/64] Do not quote $BRANCH variable Otherwise we might error out with: error: unknown option `branch qe_test-16831' usage: git clone [] [--] [

] --- clustergroup/templates/imperative/_helpers.tpl | 2 +- tests/clustergroup-industrial-edge-factory.expected.yaml | 2 +- tests/clustergroup-industrial-edge-hub.expected.yaml | 4 ++-- tests/clustergroup-medical-diagnosis-hub.expected.yaml | 4 ++-- tests/clustergroup-naked.expected.yaml | 2 +- tests/clustergroup-normal.expected.yaml | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/clustergroup/templates/imperative/_helpers.tpl b/clustergroup/templates/imperative/_helpers.tpl index c7f986e4..93299f91 100644 --- a/clustergroup/templates/imperative/_helpers.tpl +++ b/clustergroup/templates/imperative/_helpers.tpl @@ -68,7 +68,7 @@ if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; if [ "{{ $.Values.global.targetRevision }}" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch {{ $.Values.global.targetRevision }}"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch "${BRANCH}" --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch ${BRANCH} --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; {{- end }} {{/* Final done container */}} diff --git a/tests/clustergroup-industrial-edge-factory.expected.yaml b/tests/clustergroup-industrial-edge-factory.expected.yaml index 96cf061c..e795d287 100644 --- a/tests/clustergroup-industrial-edge-factory.expected.yaml +++ b/tests/clustergroup-industrial-edge-factory.expected.yaml @@ -501,7 +501,7 @@ spec: if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; if [ "main" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch main"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch "${BRANCH}" --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch ${BRANCH} --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; - name: test image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest diff --git a/tests/clustergroup-industrial-edge-hub.expected.yaml b/tests/clustergroup-industrial-edge-hub.expected.yaml index eaf5b736..8c05e007 100644 --- a/tests/clustergroup-industrial-edge-hub.expected.yaml +++ b/tests/clustergroup-industrial-edge-hub.expected.yaml @@ -662,7 +662,7 @@ spec: if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; if [ "main" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch main"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch "${BRANCH}" --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch ${BRANCH} --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; - name: test image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -798,7 +798,7 @@ spec: if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; if [ "main" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch main"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch "${BRANCH}" --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch ${BRANCH} --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; - name: unseal-playbook image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest diff --git a/tests/clustergroup-medical-diagnosis-hub.expected.yaml b/tests/clustergroup-medical-diagnosis-hub.expected.yaml index e834bd9e..a299e7dc 100644 --- a/tests/clustergroup-medical-diagnosis-hub.expected.yaml +++ b/tests/clustergroup-medical-diagnosis-hub.expected.yaml @@ -589,7 +589,7 @@ spec: if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; if [ "main" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch main"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch "${BRANCH}" --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch ${BRANCH} --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; - name: test image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -725,7 +725,7 @@ spec: if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; if [ "main" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch main"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch "${BRANCH}" --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch ${BRANCH} --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; - name: unseal-playbook image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest diff --git a/tests/clustergroup-naked.expected.yaml b/tests/clustergroup-naked.expected.yaml index 04724078..ef518557 100644 --- a/tests/clustergroup-naked.expected.yaml +++ b/tests/clustergroup-naked.expected.yaml @@ -354,7 +354,7 @@ spec: if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; if [ "main" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch main"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch "${BRANCH}" --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch ${BRANCH} --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; - name: unseal-playbook image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest diff --git a/tests/clustergroup-normal.expected.yaml b/tests/clustergroup-normal.expected.yaml index c28834d5..c046404b 100644 --- a/tests/clustergroup-normal.expected.yaml +++ b/tests/clustergroup-normal.expected.yaml @@ -570,7 +570,7 @@ spec: if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; if [ "main" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch main"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch "${BRANCH}" --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch ${BRANCH} --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; - name: test image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -706,7 +706,7 @@ spec: if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; if [ "main" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch main"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch "${BRANCH}" --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch ${BRANCH} --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; - name: unseal-playbook image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest From 97b2afa01bffe16bf70142165b1a8e2b3ac0e1d6 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Mon, 10 Jun 2024 18:40:38 +0200 Subject: [PATCH 37/64] Fix initcontainer race on spokes initContainers on the clusterwide argo instances on spokes rely on a configmap called "trusted-ca-bundle" that gets created by ACM in the openshift-gitops namespace. Since we have no explicit guarantees about ordering, it might happen that the argocd object gets created by acm before the configmap. This is problematic because the init container will start but just ignore the missing configmap. Solve this by splitting the ocp-gitops-policy in two and making sure that both the openshift-gitops subscription and the trusted-ca-bundle configmap are green before applying the next dependency. --- acm/templates/policies/ocp-gitops-policy.yaml | 99 ++++++++++++++++--- .../acm-industrial-edge-factory.expected.yaml | 94 ++++++++++++++++-- tests/acm-industrial-edge-hub.expected.yaml | 94 ++++++++++++++++-- tests/acm-medical-diagnosis-hub.expected.yaml | 94 ++++++++++++++++-- tests/acm-naked.expected.yaml | 94 ++++++++++++++++-- tests/acm-normal.expected.yaml | 94 ++++++++++++++++-- 6 files changed, 511 insertions(+), 58 deletions(-) diff --git a/acm/templates/policies/ocp-gitops-policy.yaml b/acm/templates/policies/ocp-gitops-policy.yaml index 29204254..9210b47f 100644 --- a/acm/templates/policies/ocp-gitops-policy.yaml +++ b/acm/templates/policies/ocp-gitops-policy.yaml @@ -24,15 +24,6 @@ spec: include: - default object-templates: - - complianceType: mustonlyhave - objectDefinition: - kind: ConfigMap - apiVersion: v1 - metadata: - name: trusted-ca-bundle - namespace: openshift-gitops - labels: - config.openshift.io/inject-trusted-cabundle: 'true' - complianceType: mustonlyhave objectDefinition: # This is an auto-generated file. DO NOT EDIT @@ -53,6 +44,88 @@ spec: env: - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES value: "*" + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-ca-bundle + namespace: openshift-gitops + labels: + config.openshift.io/inject-trusted-cabundle: 'true' +--- +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 +--- +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: openshift-gitops-placement + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: vendor + operator: In + values: + - OpenShift + - key: local-cluster + operator: NotIn + values: + - 'true' +--- +# This policy depends on openshift-gitops-policy and the reason is that we need to be +# certain that the trusted-ca-bundle exists before spawning the clusterwide argocd instance +# because the initcontainer references the trusted-ca-bundle and if it starts without the +# configmap being there we risk running an argo instances that won't trust public CAs +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: openshift-gitops-policy-argocd + 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 + dependencies: + - apiVersion: policy.open-cluster-management.io/v1 + compliance: Compliant + kind: Policy + name: openshift-gitops-policy + namespace: open-cluster-management + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: openshift-gitops-config-argocd + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: - complianceType: mustonlyhave objectDefinition: apiVersion: argoproj.io/v1beta1 @@ -217,22 +290,22 @@ spec: apiVersion: policy.open-cluster-management.io/v1 kind: PlacementBinding metadata: - name: openshift-gitops-placement-binding + name: openshift-gitops-placement-binding-argocd annotations: argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true placementRef: - name: openshift-gitops-placement + name: openshift-gitops-placement-argocd kind: PlacementRule apiGroup: apps.open-cluster-management.io subjects: - - name: openshift-gitops-policy + - name: openshift-gitops-policy-argocd kind: Policy apiGroup: policy.open-cluster-management.io --- apiVersion: apps.open-cluster-management.io/v1 kind: PlacementRule metadata: - name: openshift-gitops-placement + name: openshift-gitops-placement-argocd annotations: argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true spec: diff --git a/tests/acm-industrial-edge-factory.expected.yaml b/tests/acm-industrial-edge-factory.expected.yaml index fa867edd..980d0220 100644 --- a/tests/acm-industrial-edge-factory.expected.yaml +++ b/tests/acm-industrial-edge-factory.expected.yaml @@ -42,6 +42,22 @@ subjects: 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-argocd + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: openshift-gitops-placement-argocd + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: openshift-gitops-policy-argocd + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml apiVersion: apps.open-cluster-management.io/v1 kind: PlacementRule metadata: @@ -64,6 +80,28 @@ spec: - 'true' --- # Source: acm/templates/policies/ocp-gitops-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: openshift-gitops-placement-argocd + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: vendor + operator: In + values: + - OpenShift + - key: local-cluster + operator: NotIn + values: + - 'true' +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml apiVersion: policy.open-cluster-management.io/v1 kind: Policy metadata: @@ -90,15 +128,6 @@ spec: include: - default object-templates: - - complianceType: mustonlyhave - objectDefinition: - kind: ConfigMap - apiVersion: v1 - metadata: - name: trusted-ca-bundle - namespace: openshift-gitops - labels: - config.openshift.io/inject-trusted-cabundle: 'true' - complianceType: mustonlyhave objectDefinition: # This is an auto-generated file. DO NOT EDIT @@ -119,6 +148,53 @@ spec: env: - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES value: "*" + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-ca-bundle + namespace: openshift-gitops + labels: + config.openshift.io/inject-trusted-cabundle: 'true' +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +# This policy depends on openshift-gitops-policy and the reason is that we need to be +# certain that the trusted-ca-bundle exists before spawning the clusterwide argocd instance +# because the initcontainer references the trusted-ca-bundle and if it starts without the +# configmap being there we risk running an argo instances that won't trust public CAs +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: openshift-gitops-policy-argocd + 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 + dependencies: + - apiVersion: policy.open-cluster-management.io/v1 + compliance: Compliant + kind: Policy + name: openshift-gitops-policy + namespace: open-cluster-management + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: openshift-gitops-config-argocd + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: - complianceType: mustonlyhave objectDefinition: apiVersion: argoproj.io/v1beta1 diff --git a/tests/acm-industrial-edge-hub.expected.yaml b/tests/acm-industrial-edge-hub.expected.yaml index d715989d..7e3bd0f3 100644 --- a/tests/acm-industrial-edge-hub.expected.yaml +++ b/tests/acm-industrial-edge-hub.expected.yaml @@ -70,6 +70,22 @@ subjects: 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-argocd + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: openshift-gitops-placement-argocd + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: openshift-gitops-policy-argocd + kind: Policy + apiGroup: policy.open-cluster-management.io +--- # Source: acm/templates/policies/acm-hub-ca-policy.yaml apiVersion: apps.open-cluster-management.io/v1 kind: PlacementRule @@ -136,6 +152,28 @@ spec: values: - 'true' --- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: openshift-gitops-placement-argocd + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: vendor + operator: In + values: + - OpenShift + - key: local-cluster + operator: NotIn + values: + - 'true' +--- # Source: acm/templates/policies/acm-hub-ca-policy.yaml apiVersion: policy.open-cluster-management.io/v1 kind: Policy @@ -298,15 +336,6 @@ spec: include: - default object-templates: - - complianceType: mustonlyhave - objectDefinition: - kind: ConfigMap - apiVersion: v1 - metadata: - name: trusted-ca-bundle - namespace: openshift-gitops - labels: - config.openshift.io/inject-trusted-cabundle: 'true' - complianceType: mustonlyhave objectDefinition: # This is an auto-generated file. DO NOT EDIT @@ -327,6 +356,53 @@ spec: env: - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES value: "*" + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-ca-bundle + namespace: openshift-gitops + labels: + config.openshift.io/inject-trusted-cabundle: 'true' +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +# This policy depends on openshift-gitops-policy and the reason is that we need to be +# certain that the trusted-ca-bundle exists before spawning the clusterwide argocd instance +# because the initcontainer references the trusted-ca-bundle and if it starts without the +# configmap being there we risk running an argo instances that won't trust public CAs +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: openshift-gitops-policy-argocd + 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 + dependencies: + - apiVersion: policy.open-cluster-management.io/v1 + compliance: Compliant + kind: Policy + name: openshift-gitops-policy + namespace: open-cluster-management + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: openshift-gitops-config-argocd + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: - complianceType: mustonlyhave objectDefinition: apiVersion: argoproj.io/v1beta1 diff --git a/tests/acm-medical-diagnosis-hub.expected.yaml b/tests/acm-medical-diagnosis-hub.expected.yaml index 2fd25e75..e63e0654 100644 --- a/tests/acm-medical-diagnosis-hub.expected.yaml +++ b/tests/acm-medical-diagnosis-hub.expected.yaml @@ -70,6 +70,22 @@ subjects: 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-argocd + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: openshift-gitops-placement-argocd + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: openshift-gitops-policy-argocd + kind: Policy + apiGroup: policy.open-cluster-management.io +--- # Source: acm/templates/policies/acm-hub-ca-policy.yaml apiVersion: apps.open-cluster-management.io/v1 kind: PlacementRule @@ -127,6 +143,28 @@ spec: values: - 'true' --- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: openshift-gitops-placement-argocd + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: vendor + operator: In + values: + - OpenShift + - key: local-cluster + operator: NotIn + values: + - 'true' +--- # Source: acm/templates/policies/acm-hub-ca-policy.yaml apiVersion: policy.open-cluster-management.io/v1 kind: Policy @@ -289,15 +327,6 @@ spec: include: - default object-templates: - - complianceType: mustonlyhave - objectDefinition: - kind: ConfigMap - apiVersion: v1 - metadata: - name: trusted-ca-bundle - namespace: openshift-gitops - labels: - config.openshift.io/inject-trusted-cabundle: 'true' - complianceType: mustonlyhave objectDefinition: # This is an auto-generated file. DO NOT EDIT @@ -318,6 +347,53 @@ spec: env: - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES value: "*" + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-ca-bundle + namespace: openshift-gitops + labels: + config.openshift.io/inject-trusted-cabundle: 'true' +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +# This policy depends on openshift-gitops-policy and the reason is that we need to be +# certain that the trusted-ca-bundle exists before spawning the clusterwide argocd instance +# because the initcontainer references the trusted-ca-bundle and if it starts without the +# configmap being there we risk running an argo instances that won't trust public CAs +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: openshift-gitops-policy-argocd + 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 + dependencies: + - apiVersion: policy.open-cluster-management.io/v1 + compliance: Compliant + kind: Policy + name: openshift-gitops-policy + namespace: open-cluster-management + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: openshift-gitops-config-argocd + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: - complianceType: mustonlyhave objectDefinition: apiVersion: argoproj.io/v1beta1 diff --git a/tests/acm-naked.expected.yaml b/tests/acm-naked.expected.yaml index fa867edd..980d0220 100644 --- a/tests/acm-naked.expected.yaml +++ b/tests/acm-naked.expected.yaml @@ -42,6 +42,22 @@ subjects: 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-argocd + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: openshift-gitops-placement-argocd + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: openshift-gitops-policy-argocd + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml apiVersion: apps.open-cluster-management.io/v1 kind: PlacementRule metadata: @@ -64,6 +80,28 @@ spec: - 'true' --- # Source: acm/templates/policies/ocp-gitops-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: openshift-gitops-placement-argocd + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: vendor + operator: In + values: + - OpenShift + - key: local-cluster + operator: NotIn + values: + - 'true' +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml apiVersion: policy.open-cluster-management.io/v1 kind: Policy metadata: @@ -90,15 +128,6 @@ spec: include: - default object-templates: - - complianceType: mustonlyhave - objectDefinition: - kind: ConfigMap - apiVersion: v1 - metadata: - name: trusted-ca-bundle - namespace: openshift-gitops - labels: - config.openshift.io/inject-trusted-cabundle: 'true' - complianceType: mustonlyhave objectDefinition: # This is an auto-generated file. DO NOT EDIT @@ -119,6 +148,53 @@ spec: env: - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES value: "*" + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-ca-bundle + namespace: openshift-gitops + labels: + config.openshift.io/inject-trusted-cabundle: 'true' +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +# This policy depends on openshift-gitops-policy and the reason is that we need to be +# certain that the trusted-ca-bundle exists before spawning the clusterwide argocd instance +# because the initcontainer references the trusted-ca-bundle and if it starts without the +# configmap being there we risk running an argo instances that won't trust public CAs +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: openshift-gitops-policy-argocd + 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 + dependencies: + - apiVersion: policy.open-cluster-management.io/v1 + compliance: Compliant + kind: Policy + name: openshift-gitops-policy + namespace: open-cluster-management + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: openshift-gitops-config-argocd + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: - complianceType: mustonlyhave objectDefinition: apiVersion: argoproj.io/v1beta1 diff --git a/tests/acm-normal.expected.yaml b/tests/acm-normal.expected.yaml index 356d0658..f3ca998a 100644 --- a/tests/acm-normal.expected.yaml +++ b/tests/acm-normal.expected.yaml @@ -860,6 +860,22 @@ subjects: 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-argocd + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: openshift-gitops-placement-argocd + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: openshift-gitops-policy-argocd + kind: Policy + apiGroup: policy.open-cluster-management.io +--- # Source: acm/templates/policies/acm-hub-ca-policy.yaml apiVersion: apps.open-cluster-management.io/v1 kind: PlacementRule @@ -945,6 +961,28 @@ spec: values: - 'true' --- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: openshift-gitops-placement-argocd + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: vendor + operator: In + values: + - OpenShift + - key: local-cluster + operator: NotIn + values: + - 'true' +--- # Source: acm/templates/policies/acm-hub-ca-policy.yaml apiVersion: policy.open-cluster-management.io/v1 kind: Policy @@ -1301,15 +1339,6 @@ spec: include: - default object-templates: - - complianceType: mustonlyhave - objectDefinition: - kind: ConfigMap - apiVersion: v1 - metadata: - name: trusted-ca-bundle - namespace: openshift-gitops - labels: - config.openshift.io/inject-trusted-cabundle: 'true' - complianceType: mustonlyhave objectDefinition: # This is an auto-generated file. DO NOT EDIT @@ -1330,6 +1359,53 @@ spec: env: - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES value: "*" + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-ca-bundle + namespace: openshift-gitops + labels: + config.openshift.io/inject-trusted-cabundle: 'true' +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +# This policy depends on openshift-gitops-policy and the reason is that we need to be +# certain that the trusted-ca-bundle exists before spawning the clusterwide argocd instance +# because the initcontainer references the trusted-ca-bundle and if it starts without the +# configmap being there we risk running an argo instances that won't trust public CAs +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: openshift-gitops-policy-argocd + 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 + dependencies: + - apiVersion: policy.open-cluster-management.io/v1 + compliance: Compliant + kind: Policy + name: openshift-gitops-policy + namespace: open-cluster-management + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: openshift-gitops-config-argocd + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: - complianceType: mustonlyhave objectDefinition: apiVersion: argoproj.io/v1beta1 From ffa35ef5be91d5542e1a468b24f40de6325267b0 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Mon, 10 Jun 2024 20:50:30 +0200 Subject: [PATCH 38/64] Release clustergroup v0.8.8 --- clustergroup/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clustergroup/Chart.yaml b/clustergroup/Chart.yaml index 222a2482..5b774788 100644 --- a/clustergroup/Chart.yaml +++ b/clustergroup/Chart.yaml @@ -3,4 +3,4 @@ description: A Helm chart to create per-clustergroup ArgoCD applications and any keywords: - pattern name: clustergroup -version: 0.8.7 +version: 0.8.8 From e47dd3f883dac404f56721cd703784f0c61b4b46 Mon Sep 17 00:00:00 2001 From: Trevor Royer Date: Tue, 11 Jun 2024 09:57:54 +0200 Subject: [PATCH 39/64] configure annotation based resource tracking --- clustergroup/templates/plumbing/argocd.yaml | 1 + clustergroup/values.schema.json | 9 +++++++++ clustergroup/values.yaml | 2 ++ tests/clustergroup-industrial-edge-factory.expected.yaml | 2 ++ tests/clustergroup-industrial-edge-hub.expected.yaml | 2 ++ tests/clustergroup-medical-diagnosis-hub.expected.yaml | 2 ++ tests/clustergroup-naked.expected.yaml | 2 ++ tests/clustergroup-normal.expected.yaml | 2 ++ 8 files changed, 22 insertions(+) diff --git a/clustergroup/templates/plumbing/argocd.yaml b/clustergroup/templates/plumbing/argocd.yaml index 68b692ff..ee1b7c2d 100644 --- a/clustergroup/templates/plumbing/argocd.yaml +++ b/clustergroup/templates/plumbing/argocd.yaml @@ -36,6 +36,7 @@ spec: hs.message = "Waiting for PVC" return hs + resourceTrackingMethod: {{ $.Values.clusterGroup.argoCD.resourceTrackingMethod}} applicationInstanceLabelKey: argocd.argoproj.io/instance applicationSet: resources: diff --git a/clustergroup/values.schema.json b/clustergroup/values.schema.json index b05dcb03..a1449ff3 100644 --- a/clustergroup/values.schema.json +++ b/clustergroup/values.schema.json @@ -549,6 +549,15 @@ "type": "array", "description": "A list of initContainers to add to the repo-server if needed" }, + "resourceTrackingMethod": { + "type": "string", + "description": "ResourceTrackingMethod defines how Argo CD should track resources that it manages", + "enum": [ + "annotation", + "label", + "annotation+label" + ] + }, "resourceExclusions": { "type": "string", "description": "ResourceExclusions is used to completely ignore entire classes of resource group/kinds." diff --git a/clustergroup/values.yaml b/clustergroup/values.yaml index cdbf823e..f02175f9 100644 --- a/clustergroup/values.yaml +++ b/clustergroup/values.yaml @@ -28,6 +28,8 @@ clusterGroup: argoCD: initContainers: [] configManagementPlugins: [] + # resource tracking can be set to annotation, label, or annotation+label + resourceTrackingMethod: label resourceHealthChecks: - kind: PersistentVolumeClaim check: | diff --git a/tests/clustergroup-industrial-edge-factory.expected.yaml b/tests/clustergroup-industrial-edge-factory.expected.yaml index e795d287..ad6cfa3c 100644 --- a/tests/clustergroup-industrial-edge-factory.expected.yaml +++ b/tests/clustergroup-industrial-edge-factory.expected.yaml @@ -147,6 +147,7 @@ data: hs.message = "Waiting for PVC" return hs kind: PersistentVolumeClaim + resourceTrackingMethod: label imperative: activeDeadlineSeconds: 3600 adminClusterRoleName: imperative-admin-cluster-role @@ -703,6 +704,7 @@ spec: hs.message = "Waiting for PVC" return hs + resourceTrackingMethod: label applicationInstanceLabelKey: argocd.argoproj.io/instance applicationSet: resources: diff --git a/tests/clustergroup-industrial-edge-hub.expected.yaml b/tests/clustergroup-industrial-edge-hub.expected.yaml index 8c05e007..cc30a7ac 100644 --- a/tests/clustergroup-industrial-edge-hub.expected.yaml +++ b/tests/clustergroup-industrial-edge-hub.expected.yaml @@ -268,6 +268,7 @@ data: hs.message = "Waiting for PVC" return hs kind: PersistentVolumeClaim + resourceTrackingMethod: label imperative: activeDeadlineSeconds: 3600 adminClusterRoleName: imperative-admin-cluster-role @@ -1470,6 +1471,7 @@ spec: hs.message = "Waiting for PVC" return hs + resourceTrackingMethod: label applicationInstanceLabelKey: argocd.argoproj.io/instance applicationSet: resources: diff --git a/tests/clustergroup-medical-diagnosis-hub.expected.yaml b/tests/clustergroup-medical-diagnosis-hub.expected.yaml index a299e7dc..1888528f 100644 --- a/tests/clustergroup-medical-diagnosis-hub.expected.yaml +++ b/tests/clustergroup-medical-diagnosis-hub.expected.yaml @@ -251,6 +251,7 @@ data: hs.message = "Waiting for PVC" return hs kind: PersistentVolumeClaim + resourceTrackingMethod: label imperative: activeDeadlineSeconds: 3600 adminClusterRoleName: imperative-admin-cluster-role @@ -1655,6 +1656,7 @@ spec: hs.message = "Waiting for PVC" return hs + resourceTrackingMethod: label applicationInstanceLabelKey: argocd.argoproj.io/instance applicationSet: resources: diff --git a/tests/clustergroup-naked.expected.yaml b/tests/clustergroup-naked.expected.yaml index ef518557..56452cca 100644 --- a/tests/clustergroup-naked.expected.yaml +++ b/tests/clustergroup-naked.expected.yaml @@ -74,6 +74,7 @@ data: hs.message = "Waiting for PVC" return hs kind: PersistentVolumeClaim + resourceTrackingMethod: label imperative: activeDeadlineSeconds: 3600 adminClusterRoleName: imperative-admin-cluster-role @@ -449,6 +450,7 @@ spec: hs.message = "Waiting for PVC" return hs + resourceTrackingMethod: label applicationInstanceLabelKey: argocd.argoproj.io/instance applicationSet: resources: diff --git a/tests/clustergroup-normal.expected.yaml b/tests/clustergroup-normal.expected.yaml index c046404b..ba0e704d 100644 --- a/tests/clustergroup-normal.expected.yaml +++ b/tests/clustergroup-normal.expected.yaml @@ -159,6 +159,7 @@ data: hs.message = "Waiting for PVC" return hs kind: PersistentVolumeClaim + resourceTrackingMethod: label imperative: activeDeadlineSeconds: 3600 adminClusterRoleName: imperative-admin-cluster-role @@ -1219,6 +1220,7 @@ spec: hs.message = "Waiting for PVC" return hs + resourceTrackingMethod: label applicationInstanceLabelKey: argocd.argoproj.io/instance applicationSet: resources: From 5b52f0daaf9cf4a7ef392b1d32394febce6df1ea Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Sat, 15 Jun 2024 14:24:48 +0200 Subject: [PATCH 40/64] Drop imperative.volumes and imperative.volumemounts With the switch to initcontainers they are not used anywhere anymore --- clustergroup/templates/imperative/_helpers.tpl | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/clustergroup/templates/imperative/_helpers.tpl b/clustergroup/templates/imperative/_helpers.tpl index 93299f91..f1d99416 100644 --- a/clustergroup/templates/imperative/_helpers.tpl +++ b/clustergroup/templates/imperative/_helpers.tpl @@ -98,22 +98,6 @@ - mountPath: /tmp/ca-bundles name: ca-bundles {{- end }} -{{- define "imperative.volumemounts" }} -- name: git - mountPath: "/git" -- name: values-volume - mountPath: /values/values.yaml - subPath: values.yaml -{{- end }} - -{{/* volumes for all containers */}} -{{- define "imperative.volumes" }} -- name: git - emptyDir: {} -- name: values-volume - configMap: - name: {{ $.Values.clusterGroup.imperative.valuesConfigMap }}-{{ $.Values.clusterGroup.name }} -{{- end }} {{- define "imperative.volumes_ca" }} - name: git From 28b2d3965ee10a31bc1ca03539ffd0d04f1a8cc9 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Tue, 18 Jun 2024 10:00:46 +0200 Subject: [PATCH 41/64] Properly quote vault kv command When using a password with a dollar, the oc exec commands run inside the vault are not properly escaped, casing the dollar signed to be interpreted by the shell inside the vault pod. So a password like 'Y$yxn54&qXAxpUd2*yGH' will become 'Y&qXAxpUd2*yGH' in the vault. This is because the command that is being run ends up being: oc exec -n vault vault-0 -i -- sh -c "vault kv patch -mount=secret global/mysecret dollar=Y$yxn54&qXAxpUd2*yGH" The `$yxn54` will be interpreted by the shell inside vault. Let's fix this by running a properly escaped command: oc exec -n vault vault-0 -i -- sh -c "vault kv patch -mount=secret global/mysecret dollar='"'Y$yxn54&qXAxpUd2*yGH'"'" Reported-By: Chris Butler --- ansible/plugins/modules/vault_load_parsed_secrets.py | 2 +- ansible/tests/unit/test_vault_load_parsed_secrets.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ansible/plugins/modules/vault_load_parsed_secrets.py b/ansible/plugins/modules/vault_load_parsed_secrets.py index cfcf9732..0a6aa146 100644 --- a/ansible/plugins/modules/vault_load_parsed_secrets.py +++ b/ansible/plugins/modules/vault_load_parsed_secrets.py @@ -215,7 +215,7 @@ def inject_field( for prefix in prefixes: cmd = ( f"oc exec -n {self.namespace} {self.pod} -i -- sh -c " - f"\"vault kv {verb} -mount={mount} {prefix}/{secret_name} {fieldname}='{fieldvalue}'\"" + f"\"vault kv {verb} -mount={mount} {prefix}/{secret_name} {fieldname}='\"'{fieldvalue}'\"'\"" ) self._run_command(cmd, attempts=3) return diff --git a/ansible/tests/unit/test_vault_load_parsed_secrets.py b/ansible/tests/unit/test_vault_load_parsed_secrets.py index ca37de94..1a449739 100644 --- a/ansible/tests/unit/test_vault_load_parsed_secrets.py +++ b/ansible/tests/unit/test_vault_load_parsed_secrets.py @@ -120,7 +120,7 @@ def test_ensure_value_injection_works(self): attempts=3, ), call( - "oc exec -n vault vault-0 -i -- sh -c \"vault kv put -mount=secret hub/config-demo secret='value123'\"", + "oc exec -n vault vault-0 -i -- sh -c \"vault kv put -mount=secret hub/config-demo secret='\"'value123'\"'\"", # noqa: E501 attempts=3, ), ] @@ -159,7 +159,7 @@ def test_ensure_b64_value_injection_works(self): attempts=3, ), call( - "oc exec -n vault vault-0 -i -- sh -c \"vault kv put -mount=secret hub/config-demo secret='dmFsdWUxMjMK'\"", # noqa: E501 + "oc exec -n vault vault-0 -i -- sh -c \"vault kv put -mount=secret hub/config-demo secret='\"'dmFsdWUxMjMK'\"'\"", # noqa: E501 attempts=3, ), ] @@ -198,11 +198,11 @@ def test_ensure_file_injection_works(self): attempts=3, ), call( - "oc exec -n vault vault-0 -i -- sh -c \"vault kv put -mount=secret secret/region-one/config-demo secret='value123'\"", # noqa: E501 + "oc exec -n vault vault-0 -i -- sh -c \"vault kv put -mount=secret secret/region-one/config-demo secret='\"'value123'\"'\"", # noqa: E501 attempts=3, ), call( - "oc exec -n vault vault-0 -i -- sh -c \"vault kv put -mount=secret secret/snowflake.blueprints.rhecoeng.com/config-demo secret='value123'\"", # noqa: E501 + "oc exec -n vault vault-0 -i -- sh -c \"vault kv put -mount=secret secret/snowflake.blueprints.rhecoeng.com/config-demo secret='\"'value123'\"'\"", # noqa: E501 attempts=3, ), call( @@ -249,11 +249,11 @@ def test_ensure_file_b64_injection_works(self): attempts=3, ), call( - "oc exec -n vault vault-0 -i -- sh -c \"vault kv put -mount=secret secret/region-one/config-demo secret='value123'\"", # noqa: E501 + "oc exec -n vault vault-0 -i -- sh -c \"vault kv put -mount=secret secret/region-one/config-demo secret='\"'value123'\"'\"", # noqa: E501 attempts=3, ), call( - "oc exec -n vault vault-0 -i -- sh -c \"vault kv put -mount=secret secret/snowflake.blueprints.rhecoeng.com/config-demo secret='value123'\"", # noqa: E501 + "oc exec -n vault vault-0 -i -- sh -c \"vault kv put -mount=secret secret/snowflake.blueprints.rhecoeng.com/config-demo secret='\"'value123'\"'\"", # noqa: E501 attempts=3, ), call( From 6a312d732d1cf551f552eefd5444beddac1243c3 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Tue, 11 Jun 2024 15:35:49 +0200 Subject: [PATCH 42/64] Make HUB work when spokes point to in hub cluster gitea With this change we push the hub CA to the spokes in both the openshift-gitops, the namespaced argo namespace and in the imperative namespace. We do this so that the two argo instances are allowed to clone from an eventual gitea repository on the hub. Same goes for the imperative framework which might need to clone the code from the in-cluster gitea service running on the hub. --- acm/templates/policies/acm-hub-ca-policy.yaml | 158 +++++++++++++++++- acm/templates/policies/ocp-gitops-policy.yaml | 13 +- .../templates/imperative/_helpers.tpl | 10 +- clustergroup/templates/plumbing/argocd.yaml | 8 +- 4 files changed, 184 insertions(+), 5 deletions(-) diff --git a/acm/templates/policies/acm-hub-ca-policy.yaml b/acm/templates/policies/acm-hub-ca-policy.yaml index ef15b136..5759247c 100644 --- a/acm/templates/policies/acm-hub-ca-policy.yaml +++ b/acm/templates/policies/acm-hub-ca-policy.yaml @@ -36,6 +36,18 @@ spec: data: hub-kube-root-ca.crt: '{{ `{{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | base64enc hub}}` }}' hub-openshift-service-ca.crt: '{{ `{{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | base64enc hub}}` }}' + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-hub-bundle + namespace: imperative + data: + hub-kube-root-ca.crt: | + {{ `{{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}}` }} + hub-openshift-service-ca.crt: | + {{ `{{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}}` }} --- apiVersion: policy.open-cluster-management.io/v1 kind: PlacementBinding @@ -68,5 +80,147 @@ spec: operator: NotIn values: - 'true' -{{- end }} -{{- end }} +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: hub-argo-ca-openshift-gitops-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: hub-argo-ca-openshift-gitops-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-hub-bundle + namespace: openshift-gitops + data: + hub-kube-root-ca.crt: | + {{ `{{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}}` }} + hub-openshift-service-ca.crt: | + {{ `{{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}}` }} +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: hub-argo-ca-openshift-gitops-policy-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: hub-argo-ca-openshift-gitops-policy-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: hub-argo-ca-openshift-gitops-policy + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: hub-argo-ca-openshift-gitops-policy-placement + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: local-cluster + operator: NotIn + values: + - 'true' + +{{- end }}{{/* if (eq (((.Values.global).secretStore).backend) "vault") */}} +{{- range .Values.clusterGroup.managedClusterGroups }} +{{- $group := . }} +{{- if not .hostedArgoSites }} +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: hub-argo-ca-{{ .name }}-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: hub-argo-ca-{{ .name }}-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-hub-bundle + namespace: {{ $.Values.global.pattern }}-{{ .name }} + data: + hub-kube-root-ca.crt: | + {{ `{{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}}` }} + hub-openshift-service-ca.crt: | + {{ `{{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}}` }} +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: hub-argo-ca-{{ .name }}-placement-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: hub-argo-ca-{{ .name }}-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: hub-argo-ca-{{ .name }}-policy + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: hub-argo-ca-{{ .name }}-placement + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: local-cluster + operator: NotIn + values: + - 'true' +{{- end }}{{/* if not .hostedArgoSites */}} +{{- end }}{{/* range .Values.clusterGroup.managedClusterGroups */}} +{{- end }}{{/* isHubCluster */}} diff --git a/acm/templates/policies/ocp-gitops-policy.yaml b/acm/templates/policies/ocp-gitops-policy.yaml index 9210b47f..cdc0a7e1 100644 --- a/acm/templates/policies/ocp-gitops-policy.yaml +++ b/acm/templates/policies/ocp-gitops-policy.yaml @@ -113,6 +113,11 @@ spec: kind: Policy name: openshift-gitops-policy namespace: open-cluster-management + - apiVersion: policy.open-cluster-management.io/v1 + compliance: Compliant + kind: Policy + name: hub-argo-ca-openshift-gitops-policy + namespace: open-cluster-management policy-templates: - objectDefinition: apiVersion: policy.open-cluster-management.io/v1 @@ -209,7 +214,7 @@ spec: - command: - bash - -c - - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true image: registry.redhat.io/ubi9/ubi-minimal:latest name: fetch-ca @@ -219,6 +224,8 @@ spec: name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles resources: @@ -239,6 +246,10 @@ spec: name: trusted-ca-bundle optional: true name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle - emptyDir: {} name: ca-bundles resourceExclusions: |- diff --git a/clustergroup/templates/imperative/_helpers.tpl b/clustergroup/templates/imperative/_helpers.tpl index f1d99416..88538f88 100644 --- a/clustergroup/templates/imperative/_helpers.tpl +++ b/clustergroup/templates/imperative/_helpers.tpl @@ -16,13 +16,15 @@ - 'sh' - '-c' - >- - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true; + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true; ls -l /tmp/ca-bundles/ volumeMounts: - mountPath: /var/run/kube-root-ca name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles {{- end }} @@ -95,6 +97,8 @@ name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle +- mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles {{- end }} @@ -112,6 +116,10 @@ name: trusted-ca-bundle optional: true name: trusted-ca-bundle +- configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle - name: ca-bundles emptyDir: {} {{- end }} diff --git a/clustergroup/templates/plumbing/argocd.yaml b/clustergroup/templates/plumbing/argocd.yaml index ee1b7c2d..d7a8f7e3 100644 --- a/clustergroup/templates/plumbing/argocd.yaml +++ b/clustergroup/templates/plumbing/argocd.yaml @@ -74,7 +74,7 @@ spec: - command: - bash - -c - - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true image: {{ $.Values.clusterGroup.imperative.image }} name: fetch-ca resources: {} @@ -83,6 +83,8 @@ spec: name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles resources: @@ -103,6 +105,10 @@ spec: name: trusted-ca-bundle optional: true name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle - emptyDir: {} name: ca-bundles {{- if len $.Values.clusterGroup.argoCD.initContainers }} From 591a339f7d8f8077185252d66a32194bf2e2221f Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Tue, 18 Jun 2024 17:59:54 +0200 Subject: [PATCH 43/64] update tests --- .../acm-industrial-edge-factory.expected.yaml | 13 +- tests/acm-industrial-edge-hub.expected.yaml | 167 +++++++++- tests/acm-medical-diagnosis-hub.expected.yaml | 167 +++++++++- tests/acm-naked.expected.yaml | 13 +- tests/acm-normal.expected.yaml | 309 +++++++++++++++++- ...roup-industrial-edge-factory.expected.yaml | 18 +- ...tergroup-industrial-edge-hub.expected.yaml | 28 +- ...rgroup-medical-diagnosis-hub.expected.yaml | 28 +- tests/clustergroup-naked.expected.yaml | 18 +- tests/clustergroup-normal.expected.yaml | 28 +- 10 files changed, 771 insertions(+), 18 deletions(-) diff --git a/tests/acm-industrial-edge-factory.expected.yaml b/tests/acm-industrial-edge-factory.expected.yaml index 980d0220..39238f91 100644 --- a/tests/acm-industrial-edge-factory.expected.yaml +++ b/tests/acm-industrial-edge-factory.expected.yaml @@ -182,6 +182,11 @@ spec: kind: Policy name: openshift-gitops-policy namespace: open-cluster-management + - apiVersion: policy.open-cluster-management.io/v1 + compliance: Compliant + kind: Policy + name: hub-argo-ca-openshift-gitops-policy + namespace: open-cluster-management policy-templates: - objectDefinition: apiVersion: policy.open-cluster-management.io/v1 @@ -278,7 +283,7 @@ spec: - command: - bash - -c - - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true image: registry.redhat.io/ubi9/ubi-minimal:latest name: fetch-ca @@ -288,6 +293,8 @@ spec: name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles resources: @@ -308,6 +315,10 @@ spec: name: trusted-ca-bundle optional: true name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle - emptyDir: {} name: ca-bundles resourceExclusions: |- diff --git a/tests/acm-industrial-edge-hub.expected.yaml b/tests/acm-industrial-edge-hub.expected.yaml index 7e3bd0f3..83a81f06 100644 --- a/tests/acm-industrial-edge-hub.expected.yaml +++ b/tests/acm-industrial-edge-hub.expected.yaml @@ -38,6 +38,38 @@ subjects: kind: Policy apiGroup: policy.open-cluster-management.io --- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: hub-argo-ca-openshift-gitops-policy-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: hub-argo-ca-openshift-gitops-policy-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: hub-argo-ca-openshift-gitops-policy + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: hub-argo-ca-factory-placement-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: hub-argo-ca-factory-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: hub-argo-ca-factory-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 @@ -104,6 +136,42 @@ spec: values: - 'true' --- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: hub-argo-ca-openshift-gitops-policy-placement + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: local-cluster + operator: NotIn + values: + - 'true' +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: hub-argo-ca-factory-placement + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: local-cluster + operator: NotIn + values: + - 'true' +--- # Source: acm/templates/policies/application-policies.yaml apiVersion: apps.open-cluster-management.io/v1 kind: PlacementRule @@ -209,6 +277,92 @@ spec: data: hub-kube-root-ca.crt: '{{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | base64enc hub}}' hub-openshift-service-ca.crt: '{{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | base64enc hub}}' + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-hub-bundle + namespace: imperative + data: + hub-kube-root-ca.crt: | + {{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}} + hub-openshift-service-ca.crt: | + {{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}} +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: hub-argo-ca-openshift-gitops-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: hub-argo-ca-openshift-gitops-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-hub-bundle + namespace: openshift-gitops + data: + hub-kube-root-ca.crt: | + {{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}} + hub-openshift-service-ca.crt: | + {{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}} +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: hub-argo-ca-factory-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: hub-argo-ca-factory-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-hub-bundle + namespace: mypattern-factory + data: + hub-kube-root-ca.crt: | + {{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}} + hub-openshift-service-ca.crt: | + {{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}} --- # Source: acm/templates/policies/application-policies.yaml # TODO: Also create a GitOpsCluster.apps.open-cluster-management.io @@ -390,6 +544,11 @@ spec: kind: Policy name: openshift-gitops-policy namespace: open-cluster-management + - apiVersion: policy.open-cluster-management.io/v1 + compliance: Compliant + kind: Policy + name: hub-argo-ca-openshift-gitops-policy + namespace: open-cluster-management policy-templates: - objectDefinition: apiVersion: policy.open-cluster-management.io/v1 @@ -486,7 +645,7 @@ spec: - command: - bash - -c - - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true image: registry.redhat.io/ubi9/ubi-minimal:latest name: fetch-ca @@ -496,6 +655,8 @@ spec: name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles resources: @@ -516,6 +677,10 @@ spec: name: trusted-ca-bundle optional: true name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle - emptyDir: {} name: ca-bundles resourceExclusions: |- diff --git a/tests/acm-medical-diagnosis-hub.expected.yaml b/tests/acm-medical-diagnosis-hub.expected.yaml index e63e0654..edb33909 100644 --- a/tests/acm-medical-diagnosis-hub.expected.yaml +++ b/tests/acm-medical-diagnosis-hub.expected.yaml @@ -38,6 +38,38 @@ subjects: kind: Policy apiGroup: policy.open-cluster-management.io --- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: hub-argo-ca-openshift-gitops-policy-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: hub-argo-ca-openshift-gitops-policy-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: hub-argo-ca-openshift-gitops-policy + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: hub-argo-ca-region-one-placement-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: hub-argo-ca-region-one-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: hub-argo-ca-region-one-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 @@ -104,6 +136,42 @@ spec: values: - 'true' --- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: hub-argo-ca-openshift-gitops-policy-placement + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: local-cluster + operator: NotIn + values: + - 'true' +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: hub-argo-ca-region-one-placement + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: local-cluster + operator: NotIn + values: + - 'true' +--- # Source: acm/templates/policies/application-policies.yaml apiVersion: apps.open-cluster-management.io/v1 kind: PlacementRule @@ -200,6 +268,92 @@ spec: data: hub-kube-root-ca.crt: '{{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | base64enc hub}}' hub-openshift-service-ca.crt: '{{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | base64enc hub}}' + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-hub-bundle + namespace: imperative + data: + hub-kube-root-ca.crt: | + {{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}} + hub-openshift-service-ca.crt: | + {{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}} +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: hub-argo-ca-openshift-gitops-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: hub-argo-ca-openshift-gitops-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-hub-bundle + namespace: openshift-gitops + data: + hub-kube-root-ca.crt: | + {{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}} + hub-openshift-service-ca.crt: | + {{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}} +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: hub-argo-ca-region-one-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: hub-argo-ca-region-one-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-hub-bundle + namespace: mypattern-region-one + data: + hub-kube-root-ca.crt: | + {{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}} + hub-openshift-service-ca.crt: | + {{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}} --- # Source: acm/templates/policies/application-policies.yaml # TODO: Also create a GitOpsCluster.apps.open-cluster-management.io @@ -381,6 +535,11 @@ spec: kind: Policy name: openshift-gitops-policy namespace: open-cluster-management + - apiVersion: policy.open-cluster-management.io/v1 + compliance: Compliant + kind: Policy + name: hub-argo-ca-openshift-gitops-policy + namespace: open-cluster-management policy-templates: - objectDefinition: apiVersion: policy.open-cluster-management.io/v1 @@ -477,7 +636,7 @@ spec: - command: - bash - -c - - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true image: registry.redhat.io/ubi9/ubi-minimal:latest name: fetch-ca @@ -487,6 +646,8 @@ spec: name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles resources: @@ -507,6 +668,10 @@ spec: name: trusted-ca-bundle optional: true name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle - emptyDir: {} name: ca-bundles resourceExclusions: |- diff --git a/tests/acm-naked.expected.yaml b/tests/acm-naked.expected.yaml index 980d0220..39238f91 100644 --- a/tests/acm-naked.expected.yaml +++ b/tests/acm-naked.expected.yaml @@ -182,6 +182,11 @@ spec: kind: Policy name: openshift-gitops-policy namespace: open-cluster-management + - apiVersion: policy.open-cluster-management.io/v1 + compliance: Compliant + kind: Policy + name: hub-argo-ca-openshift-gitops-policy + namespace: open-cluster-management policy-templates: - objectDefinition: apiVersion: policy.open-cluster-management.io/v1 @@ -278,7 +283,7 @@ spec: - command: - bash - -c - - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true image: registry.redhat.io/ubi9/ubi-minimal:latest name: fetch-ca @@ -288,6 +293,8 @@ spec: name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles resources: @@ -308,6 +315,10 @@ spec: name: trusted-ca-bundle optional: true name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle - emptyDir: {} name: ca-bundles resourceExclusions: |- diff --git a/tests/acm-normal.expected.yaml b/tests/acm-normal.expected.yaml index f3ca998a..6660ae87 100644 --- a/tests/acm-normal.expected.yaml +++ b/tests/acm-normal.expected.yaml @@ -796,6 +796,70 @@ subjects: kind: Policy apiGroup: policy.open-cluster-management.io --- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: hub-argo-ca-openshift-gitops-policy-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: hub-argo-ca-openshift-gitops-policy-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: hub-argo-ca-openshift-gitops-policy + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: hub-argo-ca-acm-edge-placement-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: hub-argo-ca-acm-edge-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: hub-argo-ca-acm-edge-policy + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: hub-argo-ca-acm-provision-edge-placement-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: hub-argo-ca-acm-provision-edge-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: hub-argo-ca-acm-provision-edge-policy + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: hub-argo-ca-acm-provision-on-deploy-placement-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: hub-argo-ca-acm-provision-on-deploy-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: hub-argo-ca-acm-provision-on-deploy-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 @@ -894,6 +958,78 @@ spec: values: - 'true' --- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: hub-argo-ca-openshift-gitops-policy-placement + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: local-cluster + operator: NotIn + values: + - 'true' +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: hub-argo-ca-acm-edge-placement + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: local-cluster + operator: NotIn + values: + - 'true' +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: hub-argo-ca-acm-provision-edge-placement + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: local-cluster + operator: NotIn + values: + - 'true' +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: hub-argo-ca-acm-provision-on-deploy-placement + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: local-cluster + operator: NotIn + values: + - 'true' +--- # Source: acm/templates/policies/application-policies.yaml apiVersion: apps.open-cluster-management.io/v1 kind: PlacementRule @@ -1018,6 +1154,166 @@ spec: data: hub-kube-root-ca.crt: '{{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | base64enc hub}}' hub-openshift-service-ca.crt: '{{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | base64enc hub}}' + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-hub-bundle + namespace: imperative + data: + hub-kube-root-ca.crt: | + {{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}} + hub-openshift-service-ca.crt: | + {{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}} +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: hub-argo-ca-openshift-gitops-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: hub-argo-ca-openshift-gitops-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-hub-bundle + namespace: openshift-gitops + data: + hub-kube-root-ca.crt: | + {{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}} + hub-openshift-service-ca.crt: | + {{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}} +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: hub-argo-ca-acm-edge-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: hub-argo-ca-acm-edge-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-hub-bundle + namespace: mypattern-acm-edge + data: + hub-kube-root-ca.crt: | + {{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}} + hub-openshift-service-ca.crt: | + {{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}} +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: hub-argo-ca-acm-provision-edge-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: hub-argo-ca-acm-provision-edge-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-hub-bundle + namespace: mypattern-acm-provision-edge + data: + hub-kube-root-ca.crt: | + {{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}} + hub-openshift-service-ca.crt: | + {{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}} +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: hub-argo-ca-acm-provision-on-deploy-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: hub-argo-ca-acm-provision-on-deploy-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-hub-bundle + namespace: mypattern-acm-provision-on-deploy + data: + hub-kube-root-ca.crt: | + {{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}} + hub-openshift-service-ca.crt: | + {{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}} --- # Source: acm/templates/policies/application-policies.yaml # TODO: Also create a GitOpsCluster.apps.open-cluster-management.io @@ -1393,6 +1689,11 @@ spec: kind: Policy name: openshift-gitops-policy namespace: open-cluster-management + - apiVersion: policy.open-cluster-management.io/v1 + compliance: Compliant + kind: Policy + name: hub-argo-ca-openshift-gitops-policy + namespace: open-cluster-management policy-templates: - objectDefinition: apiVersion: policy.open-cluster-management.io/v1 @@ -1489,7 +1790,7 @@ spec: - command: - bash - -c - - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true image: registry.redhat.io/ubi9/ubi-minimal:latest name: fetch-ca @@ -1499,6 +1800,8 @@ spec: name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles resources: @@ -1519,6 +1822,10 @@ spec: name: trusted-ca-bundle optional: true name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle - emptyDir: {} name: ca-bundles resourceExclusions: |- diff --git a/tests/clustergroup-industrial-edge-factory.expected.yaml b/tests/clustergroup-industrial-edge-factory.expected.yaml index ad6cfa3c..49c2c1d6 100644 --- a/tests/clustergroup-industrial-edge-factory.expected.yaml +++ b/tests/clustergroup-industrial-edge-factory.expected.yaml @@ -454,13 +454,15 @@ spec: - 'sh' - '-c' - >- - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true; + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true; ls -l /tmp/ca-bundles/ volumeMounts: - mountPath: /var/run/kube-root-ca name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles - name: git-init @@ -530,6 +532,8 @@ spec: name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles containers: @@ -555,6 +559,10 @@ spec: name: trusted-ca-bundle optional: true name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle - name: ca-bundles emptyDir: {} restartPolicy: Never @@ -742,7 +750,7 @@ spec: - command: - bash - -c - - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest name: fetch-ca resources: {} @@ -751,6 +759,8 @@ spec: name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles resources: @@ -771,6 +781,10 @@ spec: name: trusted-ca-bundle optional: true name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle - emptyDir: {} name: ca-bundles sidecarContainers: diff --git a/tests/clustergroup-industrial-edge-hub.expected.yaml b/tests/clustergroup-industrial-edge-hub.expected.yaml index cc30a7ac..4730754c 100644 --- a/tests/clustergroup-industrial-edge-hub.expected.yaml +++ b/tests/clustergroup-industrial-edge-hub.expected.yaml @@ -615,13 +615,15 @@ spec: - 'sh' - '-c' - >- - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true; + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true; ls -l /tmp/ca-bundles/ volumeMounts: - mountPath: /var/run/kube-root-ca name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles - name: git-init @@ -691,6 +693,8 @@ spec: name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles containers: @@ -716,6 +720,10 @@ spec: name: trusted-ca-bundle optional: true name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle - name: ca-bundles emptyDir: {} restartPolicy: Never @@ -751,13 +759,15 @@ spec: - 'sh' - '-c' - >- - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true; + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true; ls -l /tmp/ca-bundles/ volumeMounts: - mountPath: /var/run/kube-root-ca name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles - name: git-init @@ -829,6 +839,8 @@ spec: name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles containers: @@ -854,6 +866,10 @@ spec: name: trusted-ca-bundle optional: true name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle - name: ca-bundles emptyDir: {} restartPolicy: Never @@ -1509,7 +1525,7 @@ spec: - command: - bash - -c - - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest name: fetch-ca resources: {} @@ -1518,6 +1534,8 @@ spec: name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles resources: @@ -1538,6 +1556,10 @@ spec: name: trusted-ca-bundle optional: true name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle - emptyDir: {} name: ca-bundles sidecarContainers: diff --git a/tests/clustergroup-medical-diagnosis-hub.expected.yaml b/tests/clustergroup-medical-diagnosis-hub.expected.yaml index 1888528f..76083c4e 100644 --- a/tests/clustergroup-medical-diagnosis-hub.expected.yaml +++ b/tests/clustergroup-medical-diagnosis-hub.expected.yaml @@ -542,13 +542,15 @@ spec: - 'sh' - '-c' - >- - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true; + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true; ls -l /tmp/ca-bundles/ volumeMounts: - mountPath: /var/run/kube-root-ca name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles - name: git-init @@ -618,6 +620,8 @@ spec: name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles containers: @@ -643,6 +647,10 @@ spec: name: trusted-ca-bundle optional: true name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle - name: ca-bundles emptyDir: {} restartPolicy: Never @@ -678,13 +686,15 @@ spec: - 'sh' - '-c' - >- - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true; + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true; ls -l /tmp/ca-bundles/ volumeMounts: - mountPath: /var/run/kube-root-ca name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles - name: git-init @@ -756,6 +766,8 @@ spec: name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles containers: @@ -781,6 +793,10 @@ spec: name: trusted-ca-bundle optional: true name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle - name: ca-bundles emptyDir: {} restartPolicy: Never @@ -1694,7 +1710,7 @@ spec: - command: - bash - -c - - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest name: fetch-ca resources: {} @@ -1703,6 +1719,8 @@ spec: name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles resources: @@ -1723,6 +1741,10 @@ spec: name: trusted-ca-bundle optional: true name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle - emptyDir: {} name: ca-bundles resources: diff --git a/tests/clustergroup-naked.expected.yaml b/tests/clustergroup-naked.expected.yaml index 56452cca..16c6d81d 100644 --- a/tests/clustergroup-naked.expected.yaml +++ b/tests/clustergroup-naked.expected.yaml @@ -307,13 +307,15 @@ spec: - 'sh' - '-c' - >- - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true; + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true; ls -l /tmp/ca-bundles/ volumeMounts: - mountPath: /var/run/kube-root-ca name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles - name: git-init @@ -385,6 +387,8 @@ spec: name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles containers: @@ -410,6 +414,10 @@ spec: name: trusted-ca-bundle optional: true name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle - name: ca-bundles emptyDir: {} restartPolicy: Never @@ -488,7 +496,7 @@ spec: - command: - bash - -c - - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest name: fetch-ca resources: {} @@ -497,6 +505,8 @@ spec: name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles resources: @@ -517,6 +527,10 @@ spec: name: trusted-ca-bundle optional: true name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle - emptyDir: {} name: ca-bundles resources: diff --git a/tests/clustergroup-normal.expected.yaml b/tests/clustergroup-normal.expected.yaml index ba0e704d..0ff865e3 100644 --- a/tests/clustergroup-normal.expected.yaml +++ b/tests/clustergroup-normal.expected.yaml @@ -523,13 +523,15 @@ spec: - 'sh' - '-c' - >- - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true; + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true; ls -l /tmp/ca-bundles/ volumeMounts: - mountPath: /var/run/kube-root-ca name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles - name: git-init @@ -599,6 +601,8 @@ spec: name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles containers: @@ -624,6 +628,10 @@ spec: name: trusted-ca-bundle optional: true name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle - name: ca-bundles emptyDir: {} restartPolicy: Never @@ -659,13 +667,15 @@ spec: - 'sh' - '-c' - >- - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true; + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true; ls -l /tmp/ca-bundles/ volumeMounts: - mountPath: /var/run/kube-root-ca name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles - name: git-init @@ -737,6 +747,8 @@ spec: name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles containers: @@ -762,6 +774,10 @@ spec: name: trusted-ca-bundle optional: true name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle - name: ca-bundles emptyDir: {} restartPolicy: Never @@ -1258,7 +1274,7 @@ spec: - command: - bash - -c - - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt > /tmp/ca-bundles/ca-bundle.crt || true + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest name: fetch-ca resources: {} @@ -1267,6 +1283,8 @@ spec: name: kube-root-ca - mountPath: /var/run/trusted-ca name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle - mountPath: /tmp/ca-bundles name: ca-bundles resources: @@ -1287,6 +1305,10 @@ spec: name: trusted-ca-bundle optional: true name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle - emptyDir: {} name: ca-bundles resources: From de5647f19c931452cda24291b344e0ae516c5ce0 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Mon, 24 Jun 2024 10:42:09 +0200 Subject: [PATCH 44/64] ACM chart version 0.0.2 --- acm/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acm/Chart.yaml b/acm/Chart.yaml index 3bae9da5..5ab78a75 100644 --- a/acm/Chart.yaml +++ b/acm/Chart.yaml @@ -3,4 +3,4 @@ description: A Helm chart to configure Advanced Cluster Manager for OpenShift. keywords: - pattern name: acm -version: 0.0.1 +version: 0.0.2 From 1fa57464d8bba92c7e7dc171634833df99f946e4 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Mon, 24 Jun 2024 10:42:36 +0200 Subject: [PATCH 45/64] golang-external-secrets chart version 0.0.4 --- golang-external-secrets/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/golang-external-secrets/Chart.yaml b/golang-external-secrets/Chart.yaml index afffe393..2c214633 100644 --- a/golang-external-secrets/Chart.yaml +++ b/golang-external-secrets/Chart.yaml @@ -3,7 +3,7 @@ description: A Helm chart to configure the golang-based external-secrets. keywords: - pattern name: golang-external-secrets -version: 0.0.3 +version: 0.0.4 dependencies: - name: external-secrets version: "0.9.19" From 89b499b3cb114c41b5d2181537430094897dcd0f Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Mon, 24 Jun 2024 10:42:56 +0200 Subject: [PATCH 46/64] hashicorp-vault chart version 0.0.2 --- hashicorp-vault/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hashicorp-vault/Chart.yaml b/hashicorp-vault/Chart.yaml index e1577595..0fcbcb48 100644 --- a/hashicorp-vault/Chart.yaml +++ b/hashicorp-vault/Chart.yaml @@ -3,7 +3,7 @@ description: A Helm chart to configure Hashicorp's vault. keywords: - pattern name: hashicorp-vault -version: 0.0.1 +version: 0.0.2 dependencies: - name: vault version: "0.28.0" From 89a4cadd511133803ebff74869bb4cbec4a98705 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Mon, 24 Jun 2024 11:00:40 +0200 Subject: [PATCH 47/64] Implement multi-source --- acm/templates/_helpers.tpl | 44 +++++++++++++ .../policies/application-policies.yaml | 64 ++++++++++++------- clustergroup/templates/_helpers.tpl | 10 ++- 3 files changed, 94 insertions(+), 24 deletions(-) diff --git a/acm/templates/_helpers.tpl b/acm/templates/_helpers.tpl index 910b3970..8302457a 100644 --- a/acm/templates/_helpers.tpl +++ b/acm/templates/_helpers.tpl @@ -11,3 +11,47 @@ Default always defined valueFiles to be included when pushing the cluster wide a # hub's cluster version, whereas we want to include the spoke cluster version - '/values-{{ `{{ printf "%d.%d" ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Major) ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Minor) }}` }}.yaml' {{- end }} {{- /*acm.app.policies.valuefiles */}} + +{{- define "acm.app.policies.multisourcevaluefiles" -}} +- "$patternref/values-global.yaml" +- "$patternref/values-{{ .name }}.yaml" +- '$patternref/values-{{ `{{ (lookup "config.openshift.io/v1" "Infrastructure" "" "cluster").spec.platformSpec.type }}` }}.yaml' +- '$patternref/values-{{ `{{ (lookup "config.openshift.io/v1" "Infrastructure" "" "cluster").spec.platformSpec.type }}` }}-{{ `{{ printf "%d.%d" ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Major) ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Minor) }}` }}.yaml' +- '$patternref/values-{{ `{{ (lookup "config.openshift.io/v1" "Infrastructure" "" "cluster").spec.platformSpec.type }}` }}-{{ .name }}.yaml' +# We cannot use $.Values.global.clusterVersion because that gets resolved to the +# hub's cluster version, whereas we want to include the spoke cluster version +- '$patternref/values-{{ `{{ printf "%d.%d" ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Major) ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Minor) }}` }}.yaml' +{{- end }} {{- /*acm.app.policies.multisourcevaluefiles */}} + +{{- define "acm.app.policies.helmparameters" -}} +- name: global.repoURL + value: {{ $.Values.global.repoURL }} +- name: global.targetRevision + value: {{ $.Values.global.targetRevision }} +- 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: '{{ `{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain }}` }}' +- name: global.clusterDomain + value: '{{ `{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain | replace "apps." "" }}` }}' +- name: global.clusterVersion + value: '{{ `{{ printf "%d.%d" ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Major) ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Minor) }}` }}' +- name: global.localClusterName + value: '{{ `{{ (split "." (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain)._1 }}` }}' +- name: global.clusterPlatform + value: {{ $.Values.global.clusterPlatform }} +- name: global.multiSourceSupport + value: {{ $.Values.global.multiSourceSupport | quote }} +- name: global.multiSourceRepoUrl + value: {{ $.Values.global.multiSourceRepoUrl }} +- name: global.multiSourceTargetRevision + value: {{ $.Values.global.multiSourceTargetRevision }} +- name: global.privateRepo + value: {{ $.Values.global.privateRepo | quote }} +- name: global.experimentalCapabilities + value: {{ $.Values.global.experimentalCapabilities }} +{{- end }} {{- /*acm.app.policies.helmparameters */}} diff --git a/acm/templates/policies/application-policies.yaml b/acm/templates/policies/application-policies.yaml index 01073bd4..5f0d132f 100644 --- a/acm/templates/policies/application-policies.yaml +++ b/acm/templates/policies/application-policies.yaml @@ -36,6 +36,46 @@ spec: - resources-finalizer.argocd.argoproj.io/foreground spec: project: default + {{- if $.Values.global.multiSourceSupport }} + sources: + - repoURL: {{ coalesce .repoURL $.Values.global.repoURL }} + targetRevision: {{ coalesce .targetRevision $.Values.global.targetRevision }} + ref: patternref + - repoURL: {{ $.Values.global.multiSourceRepoUrl }} + targetRevision: {{ $.Values.global.multiSourceTargetRevision }} + helm: + ignoreMissingValueFiles: true + values: | + extraParametersNested: + {{- range $k, $v := $.Values.extraParametersNested }} + {{ $k }}: {{ printf "%s" $v | quote }} + {{- end }} + valueFiles: + {{- include "acm.app.policies.multisourcevaluefiles" . | nindent 26 }} + {{- range $valueFile := .extraValueFiles }} + - {{ $valueFile | quote }} + {{- end }} + parameters: + {{- include "acm.app.policies.helmparameters" $ | nindent 26 }} + - name: clusterGroup.name + value: {{ $group.name }} + {{- range $k, $v := $.Values.extraParametersNested }} + - name: {{ $k }} + value: {{ printf "%s" $v | quote }} + {{- end }} + {{- range .helmOverrides }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end }} + {{- if .fileParameters }} + fileParameters: + {{- range .fileParameters }} + - name: {{ .name }} + path: {{ .path }} + {{- end }} + {{- end }} + + {{- else }} source: repoURL: {{ coalesce .repoURL $.Values.global.repoURL }} targetRevision: {{ coalesce .targetRevision $.Values.global.targetRevision }} @@ -53,30 +93,9 @@ spec: - {{ $valueFile | quote }} {{- end }} parameters: - - name: global.repoURL - value: {{ $.Values.global.repoURL }} - - name: global.targetRevision - value: {{ $.Values.global.targetRevision }} - - 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: '{{ `{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain }}` }}' - - name: global.clusterDomain - value: '{{ `{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain | replace "apps." "" }}` }}' - - name: global.clusterVersion - value: '{{ `{{ printf "%d.%d" ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Major) ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Minor) }}` }}' - - name: global.localClusterName - value: '{{ `{{ (split "." (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain)._1 }}` }}' - - name: global.clusterPlatform - value: {{ $.Values.global.clusterPlatform }} + {{- include "acm.app.policies.helmparameters" $ | nindent 22 }} - name: clusterGroup.name value: {{ $group.name }} - - name: global.experimentalCapabilities - value: {{ $.Values.global.experimentalCapabilities }} {{- range $k, $v := $.Values.extraParametersNested }} - name: {{ $k }} value: {{ printf "%s" $v | quote }} @@ -92,6 +111,7 @@ spec: path: {{ .path }} {{- end }} {{- end }} + {{- end }}{{/* if $.Values.global.multiSourceSupport */}} destination: server: https://kubernetes.default.svc namespace: {{ $.Values.global.pattern }}-{{ .name }} diff --git a/clustergroup/templates/_helpers.tpl b/clustergroup/templates/_helpers.tpl index c6d14d08..0237e94a 100644 --- a/clustergroup/templates/_helpers.tpl +++ b/clustergroup/templates/_helpers.tpl @@ -3,9 +3,9 @@ Default always defined top-level variables for helm charts */}} {{- define "clustergroup.app.globalvalues.helmparameters" -}} - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: {{ $.Values.global.repoURL }} - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: {{ $.Values.global.targetRevision }} - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -18,6 +18,12 @@ Default always defined top-level variables for helm charts value: "{{ $.Values.global.clusterPlatform }}" - name: global.hubClusterDomain value: {{ $.Values.global.hubClusterDomain }} +- name: global.multiSourceSupport + value: {{ $.Values.global.multiSourceSupport | quote }} +- name: global.multiSourceRepoUrl + value: {{ $.Values.global.multiSourceRepoUrl }} +- name: global.multiSourceTargetRevision + value: {{ $.Values.global.multiSourceTargetRevision }} - name: global.localClusterDomain value: {{ coalesce $.Values.global.localClusterDomain $.Values.global.hubClusterDomain }} - name: global.privateRepo From 2e7866966f29dae91c7f3a88e92c18c32ec6d8e6 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Sat, 29 Jun 2024 17:36:52 +0200 Subject: [PATCH 48/64] Add tests for proper multisource support on spokes --- tests/acm-industrial-edge-hub.expected.yaml | 12 +- tests/acm-medical-diagnosis-hub.expected.yaml | 12 +- tests/acm-normal.expected.yaml | 36 ++++- ...roup-industrial-edge-factory.expected.yaml | 10 +- ...tergroup-industrial-edge-hub.expected.yaml | 70 ++++++++-- ...rgroup-medical-diagnosis-hub.expected.yaml | 130 ++++++++++++++---- tests/clustergroup-normal.expected.yaml | 20 ++- 7 files changed, 234 insertions(+), 56 deletions(-) diff --git a/tests/acm-industrial-edge-hub.expected.yaml b/tests/acm-industrial-edge-hub.expected.yaml index 83a81f06..8b18a4da 100644 --- a/tests/acm-industrial-edge-hub.expected.yaml +++ b/tests/acm-industrial-edge-hub.expected.yaml @@ -438,10 +438,18 @@ spec: value: '{{ (split "." (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain)._1 }}' - name: global.clusterPlatform value: aws - - name: clusterGroup.name - value: factory + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: + - name: global.privateRepo + value: - name: global.experimentalCapabilities value: + - name: clusterGroup.name + value: factory - name: clusterGroup.isHubCluster value: "false" destination: diff --git a/tests/acm-medical-diagnosis-hub.expected.yaml b/tests/acm-medical-diagnosis-hub.expected.yaml index edb33909..dffb9eb6 100644 --- a/tests/acm-medical-diagnosis-hub.expected.yaml +++ b/tests/acm-medical-diagnosis-hub.expected.yaml @@ -429,10 +429,18 @@ spec: value: '{{ (split "." (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain)._1 }}' - name: global.clusterPlatform value: aws - - name: clusterGroup.name - value: region-one + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: + - name: global.privateRepo + value: - name: global.experimentalCapabilities value: + - name: clusterGroup.name + value: region-one - name: clusterGroup.isHubCluster value: "false" destination: diff --git a/tests/acm-normal.expected.yaml b/tests/acm-normal.expected.yaml index 6660ae87..1e2b1573 100644 --- a/tests/acm-normal.expected.yaml +++ b/tests/acm-normal.expected.yaml @@ -1389,10 +1389,18 @@ spec: value: '{{ (split "." (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain)._1 }}' - name: global.clusterPlatform value: aws - - name: clusterGroup.name - value: acm-edge + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: + - name: global.privateRepo + value: - name: global.experimentalCapabilities value: + - name: clusterGroup.name + value: acm-edge - name: clusterGroup.isHubCluster value: "false" destination: @@ -1487,10 +1495,18 @@ spec: value: '{{ (split "." (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain)._1 }}' - name: global.clusterPlatform value: aws - - name: clusterGroup.name - value: acm-provision-edge + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: + - name: global.privateRepo + value: - name: global.experimentalCapabilities value: + - name: clusterGroup.name + value: acm-provision-edge - name: clusterGroup.isHubCluster value: "false" destination: @@ -1585,10 +1601,18 @@ spec: value: '{{ (split "." (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain)._1 }}' - name: global.clusterPlatform value: aws - - name: clusterGroup.name - value: acm-provision-on-deploy + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: + - name: global.privateRepo + value: - name: global.experimentalCapabilities value: + - name: clusterGroup.name + value: acm-provision-on-deploy destination: server: https://kubernetes.default.svc namespace: mypattern-acm-provision-on-deploy diff --git a/tests/clustergroup-industrial-edge-factory.expected.yaml b/tests/clustergroup-industrial-edge-factory.expected.yaml index 49c2c1d6..0d479fe4 100644 --- a/tests/clustergroup-industrial-edge-factory.expected.yaml +++ b/tests/clustergroup-industrial-edge-factory.expected.yaml @@ -650,9 +650,9 @@ spec: - "/values-4.12-factory.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -665,6 +665,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo diff --git a/tests/clustergroup-industrial-edge-hub.expected.yaml b/tests/clustergroup-industrial-edge-hub.expected.yaml index 4730754c..626b823a 100644 --- a/tests/clustergroup-industrial-edge-hub.expected.yaml +++ b/tests/clustergroup-industrial-edge-hub.expected.yaml @@ -993,9 +993,9 @@ spec: - "/values-4.12-datacenter.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1008,6 +1008,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1060,9 +1066,9 @@ spec: - "/values-4.12-datacenter.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1075,6 +1081,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1118,9 +1130,9 @@ spec: - "/values-4.12-datacenter.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1133,6 +1145,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1176,9 +1194,9 @@ spec: - "/values-4.12-datacenter.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1191,6 +1209,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1264,9 +1288,9 @@ spec: - "/values-4.12-datacenter.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1279,6 +1303,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1322,9 +1352,9 @@ spec: - "/values-4.12-datacenter.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1337,6 +1367,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1407,9 +1443,9 @@ spec: - "/values-4.12-datacenter.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1422,6 +1458,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo diff --git a/tests/clustergroup-medical-diagnosis-hub.expected.yaml b/tests/clustergroup-medical-diagnosis-hub.expected.yaml index 76083c4e..0b15ec3a 100644 --- a/tests/clustergroup-medical-diagnosis-hub.expected.yaml +++ b/tests/clustergroup-medical-diagnosis-hub.expected.yaml @@ -878,9 +878,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -893,6 +893,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -936,9 +942,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -951,6 +957,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -994,9 +1006,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1009,6 +1021,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1052,9 +1070,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1067,6 +1085,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1110,9 +1134,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1125,6 +1149,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1168,9 +1198,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1183,6 +1213,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1226,9 +1262,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1241,6 +1277,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1284,9 +1326,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1299,6 +1341,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1360,9 +1408,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1375,6 +1423,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1418,9 +1472,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1433,6 +1487,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1476,9 +1536,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1491,6 +1551,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1543,9 +1609,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1558,6 +1624,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1610,9 +1682,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1625,6 +1697,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo diff --git a/tests/clustergroup-normal.expected.yaml b/tests/clustergroup-normal.expected.yaml index 0ff865e3..9b035135 100644 --- a/tests/clustergroup-normal.expected.yaml +++ b/tests/clustergroup-normal.expected.yaml @@ -864,9 +864,9 @@ spec: - "/values/4.12.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -879,6 +879,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -934,9 +940,9 @@ spec: - "/values/4.12/aws.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -949,6 +955,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo From 9a3aa2b289bbb4bf6c77184254e734f58035617e Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Sat, 29 Jun 2024 19:13:30 +0200 Subject: [PATCH 49/64] Release clustergroup v0.8.9 --- clustergroup/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clustergroup/Chart.yaml b/clustergroup/Chart.yaml index 5b774788..ab8abbf5 100644 --- a/clustergroup/Chart.yaml +++ b/clustergroup/Chart.yaml @@ -3,4 +3,4 @@ description: A Helm chart to create per-clustergroup ArgoCD applications and any keywords: - pattern name: clustergroup -version: 0.8.8 +version: 0.8.9 From 13f3b23d0cd7d7131b5105e472da362c1f54c282 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Sat, 29 Jun 2024 20:11:21 +0200 Subject: [PATCH 50/64] Fix multisource indent error --- acm/templates/policies/application-policies.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acm/templates/policies/application-policies.yaml b/acm/templates/policies/application-policies.yaml index 5f0d132f..d157e473 100644 --- a/acm/templates/policies/application-policies.yaml +++ b/acm/templates/policies/application-policies.yaml @@ -51,12 +51,12 @@ spec: {{ $k }}: {{ printf "%s" $v | quote }} {{- end }} valueFiles: - {{- include "acm.app.policies.multisourcevaluefiles" . | nindent 26 }} + {{- include "acm.app.policies.multisourcevaluefiles" . | nindent 24 }} {{- range $valueFile := .extraValueFiles }} - {{ $valueFile | quote }} {{- end }} parameters: - {{- include "acm.app.policies.helmparameters" $ | nindent 26 }} + {{- include "acm.app.policies.helmparameters" $ | nindent 24 }} - name: clusterGroup.name value: {{ $group.name }} {{- range $k, $v := $.Values.extraParametersNested }} From ac6640c6d83e931ac4b6c95d742cc92eecc3ebdb Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Sat, 29 Jun 2024 20:13:02 +0200 Subject: [PATCH 51/64] Release clustergroup v0.8.10 --- clustergroup/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clustergroup/Chart.yaml b/clustergroup/Chart.yaml index ab8abbf5..b2d703a2 100644 --- a/clustergroup/Chart.yaml +++ b/clustergroup/Chart.yaml @@ -3,4 +3,4 @@ description: A Helm chart to create per-clustergroup ArgoCD applications and any keywords: - pattern name: clustergroup -version: 0.8.9 +version: 0.8.10 From 5f678b534a5e21c47b830194c3e4db2479e190ca Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Sat, 29 Jun 2024 20:18:15 +0200 Subject: [PATCH 52/64] Release acm v0.0.3 --- acm/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acm/Chart.yaml b/acm/Chart.yaml index 5ab78a75..b756d549 100644 --- a/acm/Chart.yaml +++ b/acm/Chart.yaml @@ -3,4 +3,4 @@ description: A Helm chart to configure Advanced Cluster Manager for OpenShift. keywords: - pattern name: acm -version: 0.0.2 +version: 0.0.3 From ca9e3a2831df18ff3137fe338cd48c7f4eaf0aac Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Sat, 29 Jun 2024 20:46:23 +0200 Subject: [PATCH 53/64] Fix missing chart field --- acm/templates/policies/application-policies.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/acm/templates/policies/application-policies.yaml b/acm/templates/policies/application-policies.yaml index d157e473..fd7c2a3f 100644 --- a/acm/templates/policies/application-policies.yaml +++ b/acm/templates/policies/application-policies.yaml @@ -43,6 +43,7 @@ spec: ref: patternref - repoURL: {{ $.Values.global.multiSourceRepoUrl }} targetRevision: {{ $.Values.global.multiSourceTargetRevision }} + chart: clustergroup helm: ignoreMissingValueFiles: true values: | From 5bdeff5e33c49fba525e8fc21439b29bb8b26de8 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Tue, 9 Jul 2024 17:16:31 +0200 Subject: [PATCH 54/64] Release acm v0.0.4 --- acm/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acm/Chart.yaml b/acm/Chart.yaml index b756d549..327e0ba5 100644 --- a/acm/Chart.yaml +++ b/acm/Chart.yaml @@ -3,4 +3,4 @@ description: A Helm chart to configure Advanced Cluster Manager for OpenShift. keywords: - pattern name: acm -version: 0.0.3 +version: 0.0.4 From bf0c8aac8a2d3b1e0437cd76eb57b940b49447d6 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Tue, 9 Jul 2024 18:04:18 +0200 Subject: [PATCH 55/64] Update chart versions --- acm/Chart.yaml | 2 +- golang-external-secrets/Chart.yaml | 2 +- hashicorp-vault/Chart.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/acm/Chart.yaml b/acm/Chart.yaml index 327e0ba5..31fa54ea 100644 --- a/acm/Chart.yaml +++ b/acm/Chart.yaml @@ -3,4 +3,4 @@ description: A Helm chart to configure Advanced Cluster Manager for OpenShift. keywords: - pattern name: acm -version: 0.0.4 +version: 0.1.0 diff --git a/golang-external-secrets/Chart.yaml b/golang-external-secrets/Chart.yaml index 2c214633..b304d092 100644 --- a/golang-external-secrets/Chart.yaml +++ b/golang-external-secrets/Chart.yaml @@ -3,7 +3,7 @@ description: A Helm chart to configure the golang-based external-secrets. keywords: - pattern name: golang-external-secrets -version: 0.0.4 +version: 0.1.0 dependencies: - name: external-secrets version: "0.9.19" diff --git a/hashicorp-vault/Chart.yaml b/hashicorp-vault/Chart.yaml index 0fcbcb48..ef3c22d2 100644 --- a/hashicorp-vault/Chart.yaml +++ b/hashicorp-vault/Chart.yaml @@ -3,7 +3,7 @@ description: A Helm chart to configure Hashicorp's vault. keywords: - pattern name: hashicorp-vault -version: 0.0.2 +version: 0.1.0 dependencies: - name: vault version: "0.28.0" From fc675e51643b2c9ad12e86654c305ced7939f881 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Mon, 15 Jul 2024 10:17:31 -0600 Subject: [PATCH 56/64] Update vault-helm to v0.28.1 and vault to 1.17.2 --- hashicorp-vault/Chart.yaml | 2 +- hashicorp-vault/charts/vault-0.28.0.tgz | Bin 49079 -> 0 bytes hashicorp-vault/charts/vault-0.28.1.tgz | Bin 0 -> 49807 bytes hashicorp-vault/values.yaml | 2 +- ...ault-industrial-edge-factory.expected.yaml | 20 +++++++++--------- ...rp-vault-industrial-edge-hub.expected.yaml | 20 +++++++++--------- ...-vault-medical-diagnosis-hub.expected.yaml | 20 +++++++++--------- tests/hashicorp-vault-naked.expected.yaml | 20 +++++++++--------- tests/hashicorp-vault-normal.expected.yaml | 20 +++++++++--------- 9 files changed, 52 insertions(+), 52 deletions(-) delete mode 100644 hashicorp-vault/charts/vault-0.28.0.tgz create mode 100644 hashicorp-vault/charts/vault-0.28.1.tgz diff --git a/hashicorp-vault/Chart.yaml b/hashicorp-vault/Chart.yaml index ef3c22d2..ede5950f 100644 --- a/hashicorp-vault/Chart.yaml +++ b/hashicorp-vault/Chart.yaml @@ -6,5 +6,5 @@ name: hashicorp-vault version: 0.1.0 dependencies: - name: vault - version: "0.28.0" + version: "0.28.1" repository: "https://helm.releases.hashicorp.com" diff --git a/hashicorp-vault/charts/vault-0.28.0.tgz b/hashicorp-vault/charts/vault-0.28.0.tgz deleted file mode 100644 index 0e02f376d504c1c78df62986fa658fc8a73e796c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49079 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

-kq@x{yw0bR#K#QLpH+^Lc;W8;O?A{*W7X3AfrZD#f!Vtk7EP$2^ARh?agbE9Q z5LdS{?f9pryE$tt`oMpM5L+VdWV4G0) z9Jrn*z>6B@)6^TJz>`GRus9mVqb9sjwhZO3BQl46&OFhB0+QbLiD>*!!Kr**`K$tg zp$39%l|(37`!qW^VDFcHbTJREGA~HEdK>^VMRggj9F^yfeog`UFZqdSBn3gLdO{kB zV;Y=C{UiNU9B*+5~)%C`?~rrFxlV*e{k zJU9z_!(TpjJ;IOP_3f0COFoK(_U_wd1>dE0H1P&%*&jd z7;Bh9rCIu?7r_eAN8owRRuxr8MZo6w=_mr=GL9|jQ1x5BX}@3#DABiL5e0_~{8NUt!`&H(Uj3w(1?Xm=Uk_)**KC`t0Fo8nSB zwyn%X<~yUI?k73+eR7?7Pj3ACl)xAIAmko?t;4F&o#BDB7D|fZhuJn(ewfE;_Ri1l z;^d|c%v!VjTOp5=FRonTP>`7_=`g)UWpSr+nXLDtbx(G;FNe>nYboqSThnUx6P*}OnE~#n##C=Jdy;g?AwSoS56fbC z{%gXbYv21fK!XR~zj0+GYLDtc1A`>&2(DidAPT|$TR|b3&lwSm&a$NcOsmGccZ;49<<{8Fv8|1 zzeI5OO4_;pj$XG+B{7X0n=H z`-X;qj`+XBZ=XLa>Hl9m`}SL>|KG)9tp9J;P@Skl@dG~;Lie%0$zVzHcy2T}s}9ny z^=$AT_NWxV~ls7D04$%YqQ0%crOR(u(nodMl8lHKxZt{~WQ>1Pi}ePqC)Q z!X$TXj`(6|q6Pj>CTzM^Vvr8}|IIgt-<0tGH_+bU|6M$r;(t06)+XX%3E@*OY?aM{ z-TaMM{n5=|d3=MU0Yc?<4#Gh1mg6lT?_?EnadqgyLdktb3^4Qt@C)`FasM>F(gD3J zsR*F$6qX$?x_bYH{l)le{tD!h!rZYLe6+cZl)SU#lfR&sTpg<;&W+&K5z6 z6HWZ<0A&|#cbevW%fetrq4wew$e?((%b7RL4)F3aMhUEL9)+>>N!_hA)UDqz4!<&+ zEkqp39f5Ni$H^>+O!l7w7dq!v0zv&;hQr|onBoWc0Z!o;fiPgY=l&J;DPiBTT4+^8 zi+!vuT}^%k)<&SN?*8m-=^HTEa=}F#{FlRM?dfB||B0QoX92t9|L>kXE%Sdb4xRkJ zlV?-@Pui{I;n-OAS7=;Z^qvL%+(5PqVc*IkT3sP&A7@qJM6S>mbXDSZ&nSk8Rinq zxOG=IzLw3gMFm8E+J@&FY8&kFzlh?qAOl_a|Jh*~|9^YvvvDT zd+zeT?&9g%e>P1RrT@&(+kL&f;O+GP**D*OSC0RB_T6{iIr_hgr^Jv`3X(89K0isT zaa>iUwWf3w!K_Ax&g=r=!b@Z&@iC=V{jU$mSNy(`OOiF7T zHk+MBzY=?16F)>`e<7Muh8Ju)oU-9n5-+NGUSvAH@w#5sB|vE0`!(ENOgA%G1>ua( z=2pw}e)#R^sbZ~)mp&cAx9EWtC-ok{Qo6k6O3RMcg5%-`026dx$4QX8_6%AKH8H;qxCR$DiF z5EYsZTj13q3xW`2Yt>RwA+}1bEGZ?EdTG(3hB# zRm_?8VCK!@yNIW2#T3vg5lHCY`k}~sGQxv8qV~n^P9x|n6eg$|6$iy_v?6L^R-i`gpZ{PD~^00@92Y#!`^NQaF`)r-kQFsgKpA{%B)fqS(I zXCBA48T2uYucP2M)q5)UiTDgSH<73*K`#3Th_@?!FW5bFgyVXvNb8a3V5!bUW%4d; zgd|&-#BGHxuVccH!DNN#YCOZkGERf*Axoz70F#=~hAo33EhZx54tw;KvU!yT<_b2R zx~1@nFqq|LA!5VR$V7*HvH70hPYA~IR~MIg+H=}BzD0S{8VJeVLdXK3D5nX0iG+!I zm1a_&)in%|-lnU`BFOMq{0~4q!;P$Vd`$G4&$ezTv9ID=R2%qrrEZ&08a_DD>aXqJ;3Kl1oC;b|->3xt zx5aM|0;!;y;+3b~m0?IUjM`R#W;SDdBxyUX;DyFXpI-6&(#x=BmWU`)IRBAMTkdH8y-lIAag zwyP9V%_?Hx^@U*pC9TF6?M@1(Xk&^FuxL^|) zOhG}z5IJZ+x%d5m$sxf_DEB-sOVQ>hL!%w6ihjBcIaU90kpqV_q&6_pM`Neg)X3S<2#>`Hr`B?f$=bGiaZHqNU zYjKYp^F_I160&*Wrdw=+Vc(|Q9%B1F9;-MsP@4?v(*fUQY95Y^|8I} zN1|f|9IoK|1OtA8>&k)!5xM%b+;y6S@^f0B)0<8j^X~jG9Nt8zi_NV#G$LsvPR}on zFj4DI$7j_8**P?B4JSwne5$S%TcYMT7kxu%0BC-K%wHH#ZEGCEl7zJ{#)M3DkSP5w zY(T1v7iUbOY!B?dk)}<_k|9L9i3mR2dbAn2>S)sX+K+C7B#tmg8Vqp$V6;Y+x;|-B3LA4z>j9NsGd_l?}vg- zEAO3jYP3u-kE5d#HGciUz?*v&hhcn&gXD9?B7-Vm^}u6cibYO+4>;vEt?P9>#596% zM>0+Os(xbBNP|u~x{kkkbNKDE+R15KcHsSd@e}H7=`-=u@jQr_`1enKvS3lu_WIFk zQGb+&9R~wjREBP7m(Qo6LHi_IuclOo*Prq3!%KPaW897crbc_A?7H?lqKj8?Jb@Fz zYt@cu7pF-vxt7r)xIKE!6^H_dMBT{{Dj5ac(r~~hjCSEM8j0mglAJZeYyE8y8O>B~ z{IY!&u`C&jX)MmBVL@Ut7}pqX<-<+UsOgpkgO{)m(0iLz_yB)Rd`>`c9i^x*{rB2VEM z(JG>h`IsO&wmoE-AF(FoZ;@-^4Nvl#$T}wHZ+UTNK*zdC(K{E^kyci*1>oFiigkyf zW$Mi|cSwEK{M>ML8;EAj&&Vgkh*Vud{sj9@)xW;nQc|JuSz7Jb(Vo<^SKw zQ%G7|bpri5|FxQa^p!XiTwz+1_}@8<{z)80Yq5lpv*=nLqNQ=@_d+;)@nq8b+*7o+ zO~qlfeo363*7%J|SFqe!w6=ps%4bx};!)LM6ix`;1QsI818t5mjb)J%|C+|p8BsXy z)aVx$b3uNNd2--$|7uiHB=CKsw-pAa#5`3;6I}XbP}8M!_mruv?RqDM2d^CmLHb|+ z@#H^8_}%y456&@_?BMJF7OiSVhWG8mNnhLv;FwKaachr}tcb?HRT5PFVM1?AorQJo zp6YS#p3dF#U&-CG7FiTrJb4|(l%!rnaHK)1{j3bZHk(tCF1&46S7o}WwUj_mJ_VvH zPhv0bIKVl=I(1u@Ev&Y*PN|7T3cC$!eRwOD>-0SAeA<=sg}r^(U{h+fBen0TGMeZ{ z5&3B|r)2?zD%)bT1iWsFwiaiw`LS%eAeEV%;N{S-uQV{k7?+aW`9Al*d98|kOV<)A z2ZO=}zCPp1(1ZqV7`MYzS(sK49ve;4dqV6UPHgml!{7hs>-t$Y+r-T5;fcS9Grz-E zz}B>QE;}t5aQI;2#M62NcslyyUi0F!CxV3!ecfdYx2wFM%HUN7BT#`}4AAlu$@!X>6&*yK9S{nh#Vy}#xCkp_7?cYmr3~?Db z`3RRtiM-^)I&l7yH3ZPk>ULPQX*?X<_`cR zrfGnwl4DV%7wyqMVh0B_iIKdTgf@+)Wqvq~y2FMvp*}Z8Vr$EjB(JUrp<&W9VX8Wm zT#+J+Ty}ecN<}zh%dZbmznHF;m`$oRhUxAm%lwU;E(eeH_2wG1`g~$i+4(A^P3nrATJVvLB^B|QCLVv^qpMyfb#J%O=JqEz( z+z+l==$Rk8kezxA-C*1yKqvV35V=ZjYQp(ZDW;&XzEBh<9dxPYavLps<6 z==6XdI-HD>RPbN_ZRDkmhgLdjCRDqA#;rKFhuz=XL|C-xO6wm*dfT&Bj7#|&x;oWE z840o8b59yIJBeQNjgvcOG=f!lLA^TCa_Xd=EV*b3XP`5drgw2NJ1FO)0P<~eKCG8x z8s^cm99@;Mi#;$UaQF;qzl<7oxQFT!H3+uizA4>^AD>dVu5N2m)Q{t6y-KB&kZUwI z9hwCB*r9_p558eojaRr8`Z|?*{)zr8oUm%;&aVxJ(i!qk+V`LK=!U(kgi#g2@zD3G z-|J%3&}4$cTm#nHN-?b+DrWj&LJAlC;T95_lJM zSt9>OBevv6?A7rkjwh-A!to>z!;_fl3knd&o1E4l2%((oTN4Bb2XM_AI*sZ)``2Pv zXy_=e$qv#-UJ_%}CBv|}7`+PTElO@yT z_oW%aGkKQ;S;xg$kNS$PrN7c^(tliKz`b1inRF#y>)~X(y&H}Jy+RsMM=(>Sk>sCLIe|XG$W)3Aamb^^VFx*E-wA zHZiaE8p!o3xECO7$nweO(}-&oK5+=AnqgP#PwKej*n4utz>rb*Ilpxnhx<4Uu+0L}%e=5a1a&IQT2Aa%8ME=cNeE=UjLg4BakkjVHTlR7l}1_@Gj*kr6U zJ>%!a0j2qxEhynB?r*Tb6ropirKJ}*x85QP=&@@|#i#UJ`cYVRDY-tdFqrWXF!Y@F zI*8K2fj3yC1MdmkqQU?7|E7bl;fDqNO#idM|CtXO`+dvPpQk=)x_d~dIH_IL)x-3Qek)nykr%k;2p`TW&&4c z1)ZBg2$X(LAJe=ax3urJ=?*&=Pi+#A+}e|?552eOo7&N)!*FYaQA#J@WP@8T2XAS< z!zYFD8+Vwdx#2Tf4o?E8L(a&|vAsBZi}oq@UwRpHqn) z>W2oKY4J;Wc!lm=0*`qUV3x7=QI@AD6FFZ>lkKC}MO#J{`K;#%u#JjSesm2$GSuKH z1bJJZVO?)&C)~f%r%_6UuZ$^tuF_Gl8(cMIPmq*yi|W|_>`zx5<92r?r;vwG$e>W3 zMpHJx5RmRLQ8V8uEdz0DqprO$J~k9BV&=Q7kxDY|_OxKL-pt64)xw)Ih3QXA<{^o7 zWYRH(eNg1X5W;;!OH-6gW}$J`E(_iq6)TUZVGbu?~mr0>Va z5}YASBWc#e*Y#}-mDH%*Dt{dIbJ(xtLx=sUA35w-eJsIgx#yGBod& zLVt2W#Q2*x#P|1)=&hOe?t_~(R0&*Tj$1BmsHzHGP~2yn)J@w&X>&=L?J2}Kk0PDi zs}M*OZB?m`v}C#{Coc{f{C@QWUFfy=t~~pc%69v#*7dK8A}&}qoxjRM5sXa4<&Svk zdMvYn`cHz0fChOr5uV{C35BC{{tMaHkKUa$J1*KJKyFp89kt9%B;S{BNL!}7Ou2u- z0W<(Qalk7`M#5cNG;SF-@u~QM3c<(En`#-z$Bd8ZyP18mQd=`msmkQFM7cD=5flQjc0NmEQOD;pXDB{U5X{{{vik8r}H$zbO0It z=hf!`Ya!qkp2U6%ztS(gK#EVWPdEv`7(Ch$N8ktuy}|@sNKw>T!4z7bM(72>m)wQW zb@v+_V6jT6AVd^LLtu2X``Qr%9N`ZgjB5`j1|o9~f5Qu!p!#&?%~rHvCX3+((~faS z^^0LUUFp1y!{6*6B^-V|2xtXI?;ddbWI~5QdmYR^b7AqFpJhr%TP-k0{0p|_IZ^}xc)v* z;EAJ_srP|*H;+?JoRl$i0Dlb*TJ1slg&v$ng9B9|pm0eQ870@10lgcn!w77`@|BJh zK&kyiRanH@gHj5$E-*knv4p(nh2r!ONbk?y3{q{dAKe?xby*Wu$ zrIAKj{F^#q;=I?Dc;Zimi_A{|$VwckmuE!Z;L*bPN!n_}D=ZJ>enZ=0O71&d(DP1}1MY>}hh4o__XGZVhr9%4J- zt#`~_?~cE=;INHt0M_n6CYsnaIc-zjYPa6mfZw(X1ZiLNTFW)yyX~D441HNmuj~%_ z@11hsyXV18Jo&pC*m2_RM_2Lb-Te9SJVqGjUm#mfxd%#qpvYhIIB*u-XFQoC689R# ztB?7iR!eV+eM3V_w!Gt*w=G<&!`r!X+-8bsYAi*<{Q|MrYBUW(3`3HIMLA)HH*Fl73U=F=X<>%sS9AO=F)ON?#sIvL0@`;obn!UqQ z<$x^`!SqsJ^NPVmp1m{2k3Z4}`W0s)zEb;%5Fzh6Pv-)}t#huX%8A;wt5x6}SBYN~ zQ?5!AhYpuvd{4v{kyntB6vNV{%sSndO!aLj%thy8?V)drNwRY{SpHs@y8=QwJz@}l__AokNyPMtQ-3Ej{jSZmVb2a-v<7jh@H@8qs0&K z3g^e<>8ni_)*2KqI62^WzyA(=(==Sod~Z<6&2qI0Lu@wiMlk*1oi@e14~{voqtQ9A zj#vpjM-cz?{%3_nX=(BDp-i9Nm@g|M_yMblZM1*>Wy7bun6dOsOUJlF<0(I{;w>dG zx@U{fYK*7wymx|K7IP#w=cf?=EYwQpTBta-HR9BeD@T7fA-CH-#z_{ z_jJ?6nLH~@hw6EM0kLBa`_kC1>-`t{h+Byy@`=2f=t;uD@c8^B{W|}ZUsz&NYGUK@ zENY35FwGDit%#?#y!orhVDyM$`n_Yyz;rI~#R>A=#2G)*<4!6u8#q@I$qG}_n#ucv z4YT+ka8BVy{?m(KOymQeYp=!ik$(yhbRj4CUR?3f6fWjliZM)#+OXN|H2Rg~#-r-A zvE^_fngX~2YC4>m_ogTre-8liwbSq0&Y&qg9-@Am2F@Y~VT zM-n$yQABP2sz<3P?|z-ctL00tu8BaEe7n)z={im{jx3iAbz&)wROL+4OVnV!ZfNiZ z-ch3^@RKa8T?r>Y^El!BXFii@D&7I*#Z;wrUqgd*8Y4v&gFjM53PexCf>tcRY$wNY zxLOpc)~~>koe?$215IU=J_`SET^Gv=%{uz&RfV$8^t^+Gjya_sNmHeI-A5-FM!#C2&i5e6b6R99ArGlkj;f)5ulxq6;2UL-ZWB8wYwcU39q0vWv| zm5Lz2caTEpItqSMy{o8aViPitPAx)H)WxVX_Ab~xbcEx2t4Qmy$$az{w=RgT;+Nh$ z%a-ZO@%TE(BpsQ?iv=d;xgQhC3MMO5#EobEtsjol;CjfC=^VJ`X$HGJ25=8)F%i#l zzL7MT7H_x4d__ zN9hnZ#CZ3bqFI|2iGox$ZnuVEP(fL^jnELK*j#hilKrzoUnt1&x~|Ek(l%V-npP_RHpAr@1vN{2V) zv(e4-*eznTDfzR|6_M-g#g#=_)^H|$J3VL_tXkHAYV0K-4@u-MxMt;OI>iKjor7eQ zyp_(VDpiO0!YV%rK2}KrC~xfPiAm^B0ctoqweS*rhCqDg@l13+3`~-$T1D{yT}3rk zlVzfH;`v;MOh2@oU6eW0<f!9L#^g|1nxAT_yRwevSjlKOthB`lfeh+BDuJ)FC( z6!Nm^N7eiL$4knTVl>iK@pfb1#p{i(I!r(|)sm-RE6gg+o#Twg`b3xHle8{~FgF?j zNtVnBUaW_UZzixVBzs1ql&r)uMHE708zl-Xf^gTZPH-vw2ZbFDiwECJ98ok z__sU~<}uS{J6t|JKJJzvZxy(k7EtSMFg}fliF09#qHl z2emCynF|!z9;7%rp6!qF)DN9I`pY5`Sdqqz2;~eo<_Xqk-4>8qer%}(Tg?L0#TjQ$ zSog9YiGfN9*gnAoKEaJ;!9u04D#Mlb(s-bT%>h870_n~V!{JR7-$j~Lghr<72dC#3 zN9gJM)A5=2F-~s6n9aOXw0Q)z!gKwTks|`R_e$`p4Q0!vAI-S1OsYSrI`4ig^LMO~ z^uac(LXXt0z$rSa_otzHwl$v&^I%vIQ}Y=Nm0)YoRFfttM$-mawfACw3@OJPt)RJq|_MuEU|oyq||o@NU#>%6?cyGm8Q@ z9XovX>g^bPi(WhjgfNX!lX-mPO=t{N2jdoVRG{FWJDqTYH+g0w4#pzl+$pG2FE8rr z9F-hjJpBJaI@@jT^IXg@RYs9KgPG(gcP)r0O6WSp3~?HomCgq zThi*bcK~bQ?>O6Xw?}U%X$=p zzRKtrR8iv%)zJNb%QPiQr@Fi))?1%YE0r;+W?A-IY-_6f3O2OsoE0Fn37a&Q-6^^m z^0s!Ko#LD0Fka1iaqR5yFsz%g^pE5kdZyWr5!u7P$#Ti+lS$?>r_ ztiAT{Pfv{8wrdxK1o|lN$XVE&f}}WCryy|(l2UUk9WtO55fau9juMB?;VFlw3UhUM z%HgR}^DViS6*(@O&q|1Jhbrd8zlI~#?u1nN>A|d zqRT2E75o5WFP+_R7i%8DuSrEb$n_o&77)JMAc-SPW!E9X`FX_sES{z#7-Ga0?6)`? zP2eT|MfeprK4WgWp*Fc5)H1)`byjaP z(8|DZ;s>kN`My`ta`VuYieoD`;v<%&elv3c#MG2>T-^DVTd!BehOBt3OWZ;glY0FTqir zy;gciykF9)u8X6}nAhPcho=g2b$H6*sZ#Tud)aa|p}7JSSki4PKe;Q3@s!Tv(C4uW z^sl4ycUodNevitEMlPbWG+nhy7)Eog$rs-`T_OJ}1tXuU)M1FktCQS+my+4(N$y$( z>h}GUet)R|Nk?M}bMY~quF9rd|MaBO=BKfxfq>K6O6}iPiGOozrr5@|uRqu+xA7Yf ziG6=*6L*(?5GOx^>n$UIpqV(Wn3sAQELlk3b$a-kGAleM?P;e*pep_moaN^dL(5CF z@cA!`!DUcAWSn_QUKnB!s zOMI=sd+o60^}bd8*^W~=#E7Tj5(nNBvHY(wPrE2CT|~LSl0M1&h#?<%pg6*V0>ZD) zT(1qxg`t_W{to15;&){hMv*bNj&hUkGM;%)Qs4I&n+@TQVIW$z4QVE&8SgeWFD;;> zwKR7dG&i~#a?$OKeBo4{UU>`HS0b4eD5Ef61@r;B!cZv|t(F1iGR`SaPqMt3gNMy6 zyC`?8rG2h(VQB4(lAD$E1XMt>F7;=5tNW1Jj2%g=jicLk9C<*8k)9nz3>`$Q30t>A z$i~sby*YqvIfmHa!0sDAv?(vN+YnwO9!b)6^UMMKgOj4(P6~1SEiZ^e_001sNPQ^2 zi~vY1)Xzz1ydnNYzJfx`+*!4x^uG0(EF zWI@t&Q%opaU6CmLF~Gd$!n~0vZ-K-K1pW8;mMsl@d$cNsHnwUj5!b>>c3WRxZ-WV# zI$BlAq%EI`l;zg0qli=w<)V zu>l)8{{s|y;INI|5AD3yoo|cbS9_-jf!L9ikz66Y2Uh~@*oS@#7ry?vNvpECztb2 zKCmQUlh98eMg}iAFY+l47eXyiPPNRRR+tl!9lFMi7Bs!P7SS`6GpCn1JH#X|6EbMuh|Gi|LERim3GV)HuLBj(i zle%!yPq|!nVB>4aG1R$#!NkmPaQcIt*#O%=Q10Tj_!8V+oU>eoXxayNvQ0a|GH^zM zj>oYpmB+Cwj$Kjxd@1Zo+84Vbv>7(OJwg#EO2QzRUq!QJ9KiPCZ{+Nm*N&gc%@I+Y z%1kb`zY>k?H*0XSn)pfNXU(|00HfEcxfP?p3Lo-I@rCdVg{hn9GZyT#=5^y8wlxhR z)27C8oY2V1w{p%>o~?+x=^w-Ql&pyViM#@nNs)*PL4WVKJy_Y+!Y9YwR;-LG;wK)* zT{S(9yRuz}e`m7kDm#(*hpAQMoQBX#wAUm$ zr9k%03|U-!@e^ZnP01}sv%>I>yrbC+UiMO!ddhxSMYHxyx0MMVAMuYk(U`E*fAM?> z1S>|i`}l}VF-Wn10C#lD!&+Z@ll#u5#^-j*WQ}C2MLjOmt@1y^U5!{c6z5Z2Z`q<0Fnk1lh{LLBc}9Qa07t& z9e8mR-ixF@XbBu}v_I%7b}ygZ=egt9L^{%WEUPYVk22j|7VtRE^sKNA0oq%8pKsQY z<*jk5G$#Ob4$hb}-YdYBELF$j00sNOF=4N_Y&kGlL3bW9`ACmW!^UbF{esaZZpBEF z8k$@xVG{50&w0_Q!7Ui@ky^K zyZg!xbY3bJ&BlPP zpxcC!lSo-CT`iYkpw$yVOb5tMhI*?+gXAkhpQ}-K>P}no;F7hxu!0s#@xUeV>Kc>! z1HI3J+d>kNJ~IJd0pR@vVPLPA|1tkodY)(89i9URTHI76>b$>c<+x-Pehy~aoBlMgWmG-V!u{X{aH+eMIv^d z&$1j8A>1K$oaNRedW3Wh9Kao|5H_1C@Tc)&$&zg0w~GZfDCIcsQXUvy2|yc*Hl-c- zg%rDIt90I}S2EfxKbj`@w2%&;RhuQh(mR!lrgNuAv1~vDS{R2FXdVO-N*?a6D`5_a zq9Rg>`CJoO!)T#GA@r{@ZxXWThHDE*j{%ckVH9={wih&*Vad5g5cxuttZNoVFdf*8 zSZE_82P3Ll=V|qUhLLusb)br7p>5Ml>NX4p9SsnbnO1c;73`X6d+F4*=^?VL2`TD9 ziW|Z|78Hcz2s0AmDm1tX4X#2%XH!?9!BuG3s|pQ-Y|av~!)Kyz?*u#Vj33^cm}kp* zo6a4dtz=4pE{V9X&`4ca5ornMj`L-^d~Qy6S)8lWUG5X{me2m{F84J-3f^$^Su`dk zC*lLCZNRh;bObgPBtC05Y32B8xIG(R zoWHSj9(*BLTJRivQ1wvzN$CcX=6P)C6Ko>5^KR=_!B@bcPnx>r(o=1{g+HCMC`cFG zF)j)w34I;SB->8=J@Y7XMsrpxQLsK8W0tIa^W~!)@&N2OYg;bPkeHppbc7^RfpE^` zc@s9h!K!p{MHVP|x8{+~AAl?E;Q?wvUU~zumUc}ff2=4FcG_NuPd@9w2mzv3?VCwP zu?t$HSxfyaGv!}a%ZmS+4*bZ(WsX0Vbu-q@rDzJlV(i)t_l!`%YNV9}@Mc)4st8$e zPdiHJ=1*OupE=aHT);!$nzZ+bJwUdK2}@DELoPgMMivW~WW_g135#(6z)j)EiUYt& zSx(AwQkIjlw&5Xy9Em|QPGb!knt2^qEXO*BpTQC1dHt#^=jEFVdM5(aQg3ok3Q;_6 zJol6y$9AB5AoDbV%p%UMIt?WE3qPC3U4Y)NjDp8`u0#s{(?C$6$T>St?LQcVnDA#E zFyZ6qqS;a$UF=~AjxO#sUEG1JQwX}L$~tPRguJ5>7M+%4u`N#Y>vbk;Qy6?4>NH!5 zL!CV=!J*E*MxDk@f4%FSTmSoAEwj#XoyMUn_3qz4UW(LD3KMn@^6_%~{`BN{>-=~g zVqJ7++G+wR86)e}j9K!TD@ASV-fn3B=SnX)u!z`v!!&wKYzK89weg>5^mE?LCk&qY zqH`@O5a(Wcg7BbzQ#$OCmM@1MLdIV#V{@)Bg7_>7xI686<=efK0~GYm93*;#5^eD)x{Ej~Sag6oeZ#--WV zW8M5SbIgm6jf{iOZqwf8tFi=!wcJx#o8_h1SNR8@zGNWk%YHZPQsUxcoEA5qk)f8# zK0&W-xpM0%Sv#(P9JnP}rsTAO!rpfLRbUBQ@m1NTrwX^gAWTRaZZ^Ltd3XCJnEmob z(L`aTszpAU@Jwp1w#}6cy=iOPbr8-A#HnnZ%64B^mi<@R_Ur{>JaTstP5IcK2~9m= zq7SYz`<)|jgr55a%PpQ&uA10?Q#WgTY>+eYEoZh&R}T8!@Lu&BQqO{w*ej#q2Kj=% zC{FCCR5hWjtl_8TTykh>x?1=n_=+}s+j%p%V)%}f?KEVc_O5m6uo#}lJtH+el9}Dt)a-?{?5Luq;qlluhU^O2gu5ijd>Oo#7Tn9) z^|a6hQXy`z!;_T;izQ$a*yZG2+7U_D6~^&Wkgq9=;1f6rn8FtDAfbG;l?CmQ1B3>6 zX(8yvkJu#iX9DvgmTNzy^DJAYFURA%ySouZh{7enT^a@Pcot97u}rc^;@mj#m!S~t zzG7h*-~A%s2CMqzHekQZY3-dyVG_pxrDmO)5w5X00q-=V$*TpZAx1gBnQ{SHcxZ&Z zQ;@7%z-?Kz%eHO1b{V^D+qP}nwr$(CZQHiG&VO&;?udTqr+m!(A~GU#tvSY=T5r?^ z$Tj*MuWD{6MvC1q5V#y=Na*Vr0N;6dTcBdtdT&%5lBO8Z3D7mXk^5aiEPb+y-WUCTyY4!T1>Gd8G_1tAPcCVrSy9CvSp}b66!Lm7QnxX)6 z@a08q$Ye+1AUAB#pyuC%R#cfA0W@z;f;L9A`<8<-E9%1>g+}-DetEXgcY0S`qO7_8 zd<4$9d)1H)`vm4k0W68EUOq&Ic@{FT2UhBK584s}R3l)Cv&jQwNivddX7}<~e58>u z?${Ed1+$*pl+pS0N&T1k^pN%DbBrt6CK7SM=g_K3eu3#`J?0bmBI@0?5+W;%0V|jp z!JF)EveWPgZr0U7sV~4Z8n`g?`gEp@(|palgnJ&hgxh|dsDv94PKB#++e=p*h*m!f zV;@pL7I}Jb=T(qJ3yw7t%Rp_cu=A?E1#8@+Oe$~K!JHOcO2i6Af%(e+G0XiQK?f~7`?GxPQi|2v zy4nSGSFvQoP>71Jr0xdwq|xc?OD^!JFR&GdpLM2?=xlB<8m*qmE>M>}rqd_Pji$DaO z@Xf8`IVBnF;-MI9UpMw_LVB7^1RT6az^iJ;ithbY9IJ)cf(GsyX1yrKg1M|pktT)y ze0U7`*Dg121}&prKCs^uLqMu~1=ys2lC@u8%=*jBeSw{-FUaDQ2#q?;xQ{a3Ag-L@JI+~$F`rX&L28UGS~Kd; zPka|y5_*t|EdgMUCoum_I7qit-2D9aohD3$)ghCc*~Ks%<$C6nwHhv zzVyqJ&%Qi(-#+=oyxvtnJIQTVuM^2~;%d~3!GpT$QElO_^f2FadNCvk42u-~;^ue3 zEg?v&FlSyV(kI{kM;oA~Z19-Qo%A303W?yzk? zA(OsAWHJwOJn&0Hff4!2ilK2U$n4`jgj4v-ko%E#1Q}*X?}ih*0$l;dXuKixquh8X zP4GNPqO{;V;c6-oCl!N@j&ZGiO3C3Jkww}ZF)Ca&TQsPblAmUtIC16?FV*{eqlKvm zQ>3QxdyfEFtyEq_4LPre4h`XrxMvCJ$hG4OuSNIZ-LUn)N~eM&aQ1M-5G7>&2ZIq3 z3@O!WkR#WF&6jN^=!!tH($Q*i=eZU?Vd zgu5*Jb+W?tL}4`v!zVedk;9%$z=8dwN>Mdqn^UX92!R`gb=UMr=8DeJtvnv#YHiGFwXxnv?pXSM)gk*f2i5WPJ^FSJx3^zF*)LGedc_@5-m8*X7cqWA z-nT4^vNpI>MEb3Jw=5e>BG2p?A!5b6D^;bIlc{q3QZA5GNBz{(S zP4Yg&iS``d@F%>Bo!G$tF4WLBifjBfb zt3&;Zm)QX){^Dh$Sg;hq1-%g8!Axre0&Tj@;%vpjn3-=YeT$}zK{=WQJp{Q*2~4_i zpe|K|TE%BJyl@Y|D*}Q)0(V}hbQ~(y38RqK#e7t4FJGnJQ+{5z4!tBp&jV(DwB&Alk>FsX z@N;J99g{J+o6*q7^EB3#{;;68E57qZF3_a~v3+LDyN_M|@W@R6pdWmB@p8r zMqA4jDOe#|sM@(tb(yc($sw8M8VZM$ocmaOkX2s_<7fk4a?s2wcE;ap`8H1lt+fL@ zznWC*k{M_a;TI}kN5BmmR{jn+Cz3-g1N-5dJCMPPN$&f#Ehe)b4i&xMMR@{w$p}=) zA<{guMU-r10LL$UuMuWV4-}zH$^PEsmvJDQ-)4`v2x-@nMipwB(D5ZfZs9t;@+lX0 z+r_ar>2Q`at&~`f7nhc>bJr!y*gBiQ57x&?BzUFKL=JIoG`ML)_abzf%rQ=r z5WTkWA%?8$E0Ts|csl2swklFT$DR6@$ZL=_E;!G>vYkzenf$)dTp4%DG@E)m^Jqu# z3bJ03x>Yr+)1L#&L-gIU-&N;Z*XztRb9)ExCP-oM8`z zsQZi)kMK@D+KiNZ_K7sv=580?{6j(ffrQ7qLrS4%mmy;n)-vN|^FrbY$cf(jdS*C^ zX!sz+az(trOZx4GJBW_5vpo>D5Bm*)AA1myJ=sPWUH+wU>p~o}#}cSbTj#0Id*`We znwt1yepT6Z=IU&^5Zh9YP zSw!+l8=QI^u^AED1({lkl6-%Zz}@HPeyI$QAogT2;u8)@l~CHD0U90Hm%`a2UcfA? z7`6>JKVrx?i*fdSER2GUctp1qv~$rH!)HE#U4RWRG>p2rtea{@u5%vB`NOdtn?l=B z(sSSnrvlr=W&DAG&6vm4PEIzu31%fVB*dfKb{x|gdz7SIwKUNIGh@-QvbaT(NIMxe z32fGY0;~+m@%e4yfI`u+#=Q}hy(UXe68s*l(|VW>j7a&`MTPPG!*S=`VmQkaM>QLgy>8u2X!)_W%d@yvd3P9F(2|;gz$@I8eD_ zs(zL2xwj5QC_5!{&ifH*1{KUP#=WkQdB>)I$PPkHCwFv7Lon{{XW+h_rT!?SDv0U^}zuzvARQ)`G%cloyM^$c5 zV1dY0|1VS#RcjCE0vJ7pfeTkpk5Px&JwI&inq7d%qqUGPbpDAsE{#APJ2*d&k| zG`qE)j%9PYS9H_*UC8?hRV;$J3bt-HPr0G5{JxPLp{C#Twp?hsU#N*K+3QB_IV8s1 z?KKziH@#gqG8Ca150uuAB%f34O8pjwJN4C3GG;YX7w+RlV9}74kG)zDtx_<(h*3ah z7n)m_uvIjvK@mc{NnxJ5*e_)~{+|fEUlS+W-nD#j6I~{51h~zxGNzDv{6fnV$l7;^ zD_g9!KS0~5zUtHkn*WYbTK2_w0Oeqz42_f9o%48!dziPx`yQ!mz<-Ty{a?@SZBOrd zNO>wK#VGc@^XLYFO-LsmezZ`sQ+?gLSEp;P~fh0+&3S*ADlS|a4h0^+B zL}klzl6(1L$u$KyRNU2`GN1hr?_-}s4Dy*TGtUb$=Q~(gw5qH@CXv(Yt;=Ar~_khlu&$NWVdc5de zV;8&emWy=XiMmAVJ012k5^06daTHf7p?TkJp6<3NVJvSr-D366oAaf&8Y#~cOY;_W zDJN=W9s(96YH7{1Z!^leSgy`y=IR|V{fcbmJ!2!WsSbW=ODW~aGC>gSt(~#btfN(< z-ks1K=4T_lx|Xzom|;1n*o-JpXLTY90{LPjSp+#+7F1NpU0a3OVe@k>JeiRz-kfG< zT-a_lK@R>$Fhb=p`p>Ao%mE~gGRk>5#{`>$uNe0$9gZiAcj$-rLJ~lJMwsf39njy+ z;-48BOf7ttAHRv?1-|z|o^eGFC3*)HnP0++G{(5upA`d~^It)IFJAsz;m|po4g*Wv z1nbOVK}3<5?!`Sbq*o(^{^5&__J!yPEZ&&r?Vi6!4B~xu37W>S-J|gPLhi|=sEtAC z%}Qs>gxkvC?+(X^0p5~_SLri#u4U!?LF-9l0+!i7_WK88NhAX;@QxIR81|cIYK-d3bd&uQ+dQn$ZSU*!gy$!vyI~=>*}YJ?8eREu)z(gC3Kj7A;_n&JEsB*1|5W^f@Jh4bdE=y%0Zn z#ni3Af1`_Y%(4`wU5&W5)VY}f;#5s=OiEP=se9Jk+3{#d_3MhK-MDj%)r2>Y57~%2 zff%nZ97FwN(;VRMlf=(eLN#`186v3Z-_Z*nm-V^QVzHQEt_gkyM*NdIvxl&8k)wbQ}g)eP#c)}!TNR5(9Dq!o3sIH^d zI;KaF>2YDuslrDs$ruWuTg-}!tlX*C!1j18bBI}4z;))(dGiA?c+q-uWP>3f{d|W} ze`$^M9uBACkXx#y$%}k=cH_WIp&B?A5#ySfC_=3qJW{eIDZ!(;`zzV40Jbsfc57*$ z#%4$p>KGiev=D0uW^HJ`MA(n0_wA;)o;&9Oa4U<0dew6;Z(Uod`bHLPR1vYX;7on{ z%3X4c)L;o$X*`5)$(>`7e^_+q_fs#}oC#J?d&jm0i`}+QpgCGFn}cw2n4* zMN2k}C8!1Lzsr53*V~o#)eiGqdFv0X+vbx|((Iw02ZHz{UtjXi4aux0*?vYQTqGuf z@~eX?)BY0Z*(Y$?;)*SQmLZl5Y>!d-h%2b~Y6j`)ZRl|=$Cvs96KFT(RXK)*4?q?K zz0y%WBl`mF6oW^e)!L&M^UOUo)ste>$S80{Z&djAvtD`nFB1pAmQw{IhsKZ|wvdbaCODlE3Z`ZR#+klPAj`(`s)r zR)F?Vijp^0O${xA`+99sLc&0}wDCQkC{Wr}B2g?t{3#G)U@s?wuArPLgAph;?cTdT z(P*{fO>JgNa2}rPhp9tPQ#C3`ykVZuBXk}x1ae5t&#D}Vse6ik{$)UEX!}S8mI$e?+6KKbEJXWc|5Dv*KyK6LvgEP-=+b&E?Vt z!E7EnL=4LsPi7AcaP4>!pV>KV0cUHex1ui%$76vDA@;VK*yKFmTm{pu@b|=Lp@&}N zLXI0X)v-4T+8hsA2g=OR#GmUCkjyivf8|K%u1z=t$3t?iH72Pgs=)Kdu`K(kNR)C_ zN!R~$X2&@8TW-rNNoe4j8F%P$#gnRi6HF*TpZ6rez+68;&p%<>jkj=~17ai-O=o3c zw%}Ub?bnA%+4hTp^_H$d8nI%Mmfo+&n0NyhrX#uJ)UOX9Za}|1KD^V)9V-s!w_fE4 z{K`|oLB{)(0)604yj!sc-mcso(ktT8TMG5w6#r|{U9i2({f1=aXYE09(dxx=fd6)RXhwF3XK zi_8-;^Ob&D08wWNOj$(?W=!Fl_CO;mq>nEZCCov6%4X>tQJ)qTJJ{U5p8GlfyyF-CD2w^1EVCjgYeSo!SO%kx z3o{bt@K!>jo>$sTzaLlH_~2e-s4ayX=_c4f%Z4ReLjOQWD5)ABW|=}x$(&sp$3+uk z@J*eUz*J#mNwjCvE(nK})yC&U&(LnG%T@e`=M5qnr5^oI8)Agp+=q|7-@xgssPZ~c z{?pT$g6v!%A{@jjqU%x&m33Oy=dlfUE-`fpf9A$7f4%I<-)cS6qJVMFDV6tqi?SU$ z)uO|H_c3uTSU&rRq}rL(hoy0dvBYH38N*$M&%XFGFNKR1OKY$!KF=Zn!L*1)i^cBY8Z4+7OAUj%#$gHY`hX zn)eMKy5UUw_4)39V|rU7{|nPIU;D-MChNfTAKbsaMBZAk-Y?n9HY_Qm&#!;Mg@sp@ z*mkL}S;_NYbeJ+F6|IRj(T{Jmb#7qplI-ofv)5O_HoT(kgoas@)Rer-vB`}DqK2E8 z6283Si&rXDO87hiEc=t_JZ)YTQs^k|ZSfr0_Bx0< zh)`J{Lvz*Yf369dfJ-(9JIA#45V$(S5gl%MK0+kd@w@KXVThf!a-=Ve3J`bVkc(C) zTmOz5AX&^)uKdAo-D1DMBXXb80`40>i%3s^6ha;U97x^4gV!D#DH#K14r%Zrz~U{m z@pd5?YWB8lR5FDbuvJe%zmZN_bt5WIoZerdRa)ca2@X350;!cv>W7^TkP0=VDetIh zAK(lESnXS&N=`~zm+-D)Y}RtOG<#uSb6e9*t5x$eTWxfKd{n+UxP@3r1&lV9QB+WO z3Vj}y0htnZWLR5xW3 zy>vHTc9)2hD`Ro{=*8RIt4is-a_D*6DH0XEYP6a!EsbxG(}q_n7PegBvO z*?HyJ)xn3YC>-k4@m;WZKjin+zv9q(?<6B_3rJnlJibcYIR(0T z+thMji-Oo0AWPX|?Qf>wyI{(iR>J-RYq0|K6neFh*e&okt;x*4JX%i}?p`00rO_9K z=g?#qN-hn#*jgXlOE(CDxt<^NxA{8(oj?G>F?!FVTA+xR0z;ItS8(1CoQ%R6uDrUqq3xEwpJkemF>{9894;oL)Bj(+9L{^#*(^S zq7ucWa^<-U7$rBJ{)JC_7=7w<<0G$D;%3*s)am*#3x$i6Go9Bmg_Xw1MJ zG5!584C`*Za8ssOe+MQl(tf557eI)0#(h%H-)79fyIAxuwcgeotCgzvcvdqoY`Nrg zdshME?i*-ONJo&*8!$RANdi*DnwH0bV`5%KGEH-54kJ#=A632Y0_*sxp35|jV~LA_C4-G`S3Bk~HAVpr zi$l*l9vhphuo9mQ8Qg`QAu|#1JT}z$M_QEx`qbz~C52OX$DpD>$+Xgf1_f-j!*du> z)(T%fiL8YSV#RjxN!oFNzJ4mtvxm%XYG|>J(s5h@&~4Xx;Sn3MAh$=Fn-Vs-8EuOU z)MZ~TbA_tH&Y_;_FYuLdB7DE+y0t%H*emkR3PB5!Ahf!YMZEvh&zJM53GZsh?{gQ~ zUYHTb=f27h$BQD4d8Nulk9R7++@9D(z5{ShnA&fC=nDqd0DIMHfu>-dRN$n@8#=u2WLqqbjfR8 z+L>}kMH>Ai>7Wv*xVGh9XrZXHjB{(foub^?GMP_2i=zT+NqJp**@G1q?2l+gwq-U@ z*q%Aq)SCLMh=J)|g;z0eE%M|m?FomlOG&o_G?3`5TSuRkXudHAayT*V&xqJD?JHd6 zWN{-L!r@HcWyYMsi~wlJaq~j9QYa#4R)<+#?o?dJaGKpNAsvrx9GgeBDrIgr_f5m> z7>(0*`n-f}%#TE^E6x-Hv~R44E#b7CFC!&n{a|UW*PXf&Htf~4Iu&K#)TI4{XY&FL z)F<~$kGPDPCOP3S_j`u`*QP0e^^3e~pM}7nt8hHN$yPi;*!;C(x zQD(WkUtn4#<4GlWsE0~XJV*b(dDq^r=e9F>zhgf9JmS*{SQ%?9QDmIXA%OXTj^H_d zgq(34Nq*EVY+F9WzfkmVD92-P{k2ZLX>f%`2!h?$B7Et8w;3gf~g| zTn(5%`Q(9z$hf7UG?Vnt*{@8=aoYmUnKNUZFw&Nr81nLT5m|w(cRItT2R%O=NaDXW zhpSna2hA)@aPe@_UE zbu|P)t^*tP_p(@DjhUfvg>gtw$Fm5li{3^;t;!n)z|HkJQhiR#YAy_Rnm+pbFpvgCRqqn>7jPD$SdI}E<&`YI657hG>0LM z-4Ya09P<0wv*l36=z+1HsKB!oi1ly^^v+rOt?W6qwXiRCFGpc*F$zv4g{A23ZyxF3 zIydk^JSk*mwzjgI-G>3j9icxMmcg(RdOQC`_tSSyoVpH<{f+S7DQ)PU9`UG>;lMYg zhj(i%u|uyHi)?%4a?O}l>t}_sF%+i{VPfj41Fr6lWOQ7!FB4EfEy>(=4RE%Me)+eE%j@EMsLchdi+aKyc^pKj$#C|EJLpLAf*DInrSyvE^<8*nN6N2;f+SJ0&h!+}zxc25y zvxk9wXNJ1{pb6QVdRIMm4qwBlB$9EEtCh^js#k)QrY|{AndefCkL5kIqXNN{F!AuLY)o#I86w36`G`_28I0b9jRerDoM8+n=z&B@Q662=F za4xGTZZF*$?NCbFX9pYYVCwUn;6U$`9mlp*ss^E8U9Jmm8bCXL%SNYTYS`7GuV?X< z)j!8kg&`D2$A*Q5W&`+!=!kRq&aYwb@ zEx?@5*4^L8MAzn)R(IrPsn)(62z0QuT;*Sb?{ei|oNazV^Ldsj#Mgd$JcKNX_>MW1 zm-#vG9WkG&ZZ?2ucb&kkQU5%Z62o5t;GFrCZ2F8LDN>=V;ai*h=-pq;>Mdw}3^hqM z8}9Z1wkz)8>f46%KluCeC*^0IzE$ml^%zi&lWrgYJNFn}-aNGnU&MV7cu@VEXa$K% z5DNe=quA60p2cmI0!tsVw-AH`g(4kuQ28ynWP~k9DbW}6(Iey^>uA17&+<6FlRxST zEWgK2COkGpp|>{RLXxO@a;=I~1B~{*zz%Zi>{&%!;sIBSO_c0v0-BU~)re zI9zU3qk5-g+QpkBO&z?Tnto>E394Qzfk-{E+n6-MiClic_qdKOQWs8mJ;B@U zN}5q6_+LuC@i=xY2Na<=(h%p|u~cDtDNj0tLt^Sfa&ylO@IutjrpKeiQf{R3;jsrZ zg!Z#S^%TdeGdJR-1cOAd_woD{;@jK(QCTK-(TX2=$1+3ah1Vq2je?82u2_m~NM+xF z*&;WAY}l^&%p6c+WUU~6^pHzED_7^{(kL8iK6Wdi!;B$_^9tU`^yPQ1B8u6qnRvXM zDe%@^{VX>;Hu42hnRzR7iudZyjDsXdmQ4r%S%``Vvqa{J@IP; zm8hqktLK-_IB1K|4}o1_*F3S!8gR<;x&mI26Xy|EY{vK%YR5E9fowuyxTohOLO5`t zg*dC3Qco@Aga=c{h#$}<*!mcaSSYpM3cHg>K@{Gj{@r8Nfqc+JlmCpJ&289)VxC$? zy50MzgE0AEPkPURet?wRLiOsB!`XABn?yX1SH2yD`VoOfqqFJH-i|pxsujYqw@b*Z z`L8sn4S+tq{$RvUo4Y>V>4Ur4k9uI*TLDCHv1EYc6TWPkF!AmM>f6(0q83I;oeuzP zL%r^**D$a{RSyauyo1{je=`PZOfzQtFM33@XQ$=V;Y)HWHZK`AVNNlu+hdYR^q)6+ zX7{6z(SsK5bTmf|(}&qs0wfE7@#5&MhiFuz8)_~LX-Iqe*HX*TPAtb_+>UGL7dggN ztaM24FCl(I9lBwJ^dV2NrLJ5?$7KZ%An*oHi75^#A(Wqsto)1o0Evo%D*vOeGi(k7 zR7}J1@u5{^au!lwrw$VF{dGXX8hd2TxfS5qiQU7?&A#0(_bwb%g&M_{cryM;4yuA?12PWi$Pdl7GKk4HO(KrpCS1$j*|ZE^m>eSfZwIW+gYSKXQnPrZmwb53 z@ht_t!5rkS-aGe<%MT*xj5b#bN5pNA&zAZ>E}!?ilQ!}MSpJ|Q4rX~~157z;Ir5X6 zgHNw?+}{^ubRTn&Vehw()hT0D5@xRp-AaWQ-^+HAw~E8kz(42CjL*G@&GA(x8Ex*a zp+x=VX#EfrtJjs>u58iv_?u;i$N*pw575=It*O`^Co`jkYV!~jdoRUO?adczJnESr!dl?Ya=EmcW z`y$|^Y*%?X$ceMjIgX!&|7jm)3E74)4#UBx-YLZ~pnrR!&*028M(<4rxe43m?kr^t zOT0JXpJ8~C7WJDngV`hu)^o{S=6EP3dvzL-`lhJ`J#=x_A+q0|wMIU+* z5YH?(>zf{}#TyG#{DEG_Tok9zHu~+f?S5jl$(13Rf^l~tTpf8G_#LhLH9%~o+*)A4 zqGvM_3L2_B@YFX3;fp)uCKs!E$STlj^IeQ4c}TkzOl0gKz!eMnM%mTg-JCMK%vmN( z(Nid9#O|cSU8tjqkmmlwy5sC`tFPFp-%(ec9?iJ_1?`f9N;8MyLbZipt#PKSyFUkZ(!mRZ{pN^a&BzL8bAM@ zRbUtpxo&L0S}OSqBrr0f{_E>&VPF?Ies|tz2 zWY`a3+dDhRkox{U)s6*bdKL*AQ+jPP_kp2loS&*(bala%n<&SIzxzF zlxsROhQTVZ{Vk4BMqqoHud?e{h){rR0Lc3%d>vRyigS-MZv4=oltH_^b`8$(UPA+v zQ(YTXerc@AA|wm~?lv156cfkBl1u6^n}D<&bUg4v28p}4`rbngxQl*8P~nUn#zKk$ z{oY(fJBAGZCzb0ITwx<@$wV>`Ogb0XltD?Kleh)p#yieSN5QQsv z>B5yUYoRL z2;b3bRYpz_dDJ4n%-GVu0|`@a-*xLvDQ|k@uUMP^N56TS{!hP2iy)>EY-)@~y~j4| zmw}g2#-vWRCDBbu@Hp!hRUwExC^E(ZCuDD%)X3J%Z#-qcm<*#x~r%f_pIAeY=n&t0Te!_s5VK$_LB z#<1G*u9w;v3s{qijFn8WpAMf9I!X@(CrHA0qGe4QczpsZQVsag8Rj!Yl>fU6S<@Ff z+IPitDXhBdy3G}HEng|0D%I78-h>at6XfXRgyLz9^QW!xzv}M0_lZJJ6|qiuq!6be z$~qP13bs<`y5mt4r~p_a75O<|G|;A}K^5ZMyP4S#0X zu$c1P{Y9`ya75$vq}(tCd*CN((GrGBTt~7+i0t42-L1lQ(9pM3PPtw804y{?P0(KH z*Q*B`z-KDqd&m-o1&^ZYD(%s!+InZTracznj!bj(n;QcH=x~X&3F%Y@t{xDh} z(WNF$VjA1u^~irjUX$l<_cb%wJUEf-h;Eo!>(rN5rP}vLM~U<@Ni^oYgk?bw12VKJ z#Ap#p#IWmtCw>#TrZ@_wWrL~p=xF~y z9ZlzhK#i5B3GkUuY@@~OeMc9IJ+HQru(bf6B;T6YOSIONJ{x3_3tV_4h~H!ZHR&C2 z4>iw53^c=Ta9Dnj^*0Mo1%4N3Wg>nnwamC9w)21&MZnV~1(zuQRd}p@2I}Q3ncut3ZbouQg-QhFw{E~a2x^h1gMZXu$Mz@#&!LM4I8gYbeYr$xRZ8tiP zxnblmIMN27Xwn(ywS%$W<>Mv5)w0*T{nbghnnqAf4=l7N`57f+xbS4FRmYH=Bsso8 z3nwhFpcbxKceZ=7s0p85iKAR>`o6*(Eje$5N_y||DvF`Hr(78ydT{9--8nZ5AzVwB ze8zv9bb95t4!4L3o?M^h0I->OT(nqdhDwCU3<7uazwDt(U5YqP>2vx^lBG+ymA)!G zCoQu8Vu9m#bS5o6!2GriVEZ%v8be4HPwGRZh|&ak2=u(J)_IrZ;?PPh(O|oO!|vaY z9>uHY?7w}KzwLL>255Zf7Lwb900vzL^)cbq-TZWwyH=K(^ihQLe!xf?lu@7($b zowuml(Q@zL-e1{%UTJ<-#bJgy?;5qa)}oM8SY$)$jBdqWCopUnbLLKe=Q)@v%geZ~ zJINBe?id_7()TwIz;?**8&YO+d>&peq-F>ynWIkJ0>242QL?Dwop!25M=&2%Q5vwJ zNubbJfx5w#u|*;ic3FL%-L(?P=G!~5^l=hx;+3!~m@b#-`Y@g|^=iJ}{9!ye=lIdc zhnyAXG@Lp($1MiJIR@upJ{jC45BIQ(K9;l0-hUz*%mbxd$CFpW6q21P?N0%jzeMy!?g_v`2n$p_{L32W zDqM1o``lH)+o7XoYC-WX8ZC03D63vsSAO;pny-gUiV>`wsD5*+ixA6y0u0>$vzM4! zp*ZPQPaL+T7L3K|)K$k>rM7RbB9x%4H<~&#h6gt7>CRU09YA{?Q>cV?McbW)*WJ4=647;bkz9~Pz#u09VZkd(;Z`hxPkq@9@BQ1AbM(F8tl;v zk0Wcop5%VJ`Iy0u=czQ>TI(5y_pfoS0q@6fcGMsukD8cb1unhS;|LJ%R{47w{LcSFX!zh4D@ zPINeO?j1+Q3+y62=!12ND8u0~>0)eWQ1x7P?%g0~eutp%dO~)*J`{iGxMpDCa=Kst z8jE?$W$64Fbg}TvJ;^%Y0YfuYV zELk|Cyo=u3MV8DACh~4$`E5ZK9odWoBroP2cYaLRM_8>hA9hQ39EG zu)+kpej8f`Y(!-6#5|Qf&K3}Y@EBFiILap}Lh)RPrY? zJ3?5ACVQntOp>c?qLRm?5(@%8NKA{i^{!3fqO4cv^w-fbBX}9y$VZ+se*Nw?jTP)O&e?O^WKe+N z6GNp^Y8SH0wfYYqd&kfN;<&m3PZy;$R<(F`v=gd~&A(gdgA3o1!rql7MCHQaj$nbr zO*FE1qTgTC@i1oq&48P%i07ltT^Yl3x=AAzeV5xGsAsHPGITFb!Jj}JEF|vf;ne&O zcaZyK)km-wBjy>@Jr#SN9^D@ui7o7#UXLJZZ~7rs8p(Y?D#eAq%j0dC3VHiU(mcKb zP%A{usC94|b6l0`LlV1tyPi{Isx0082xM<;N!4a$4XqoTYdMZV7=~@`ESGX`*%BQDVpX4Y zMF6SfXJe=juI>st0*BxG8yK9m8kZ+ zPHNeqvScX<7@@R!Lgapknt5y25kJ9$b4kZGR2D#JehH3$p69roTcrK^#_ zAo|#?0b5t3A(uE(rrFR#4|{iSyFiY^U)ZNJ#?BsT*z!0_K2c*iE1L2Ef*fH$>{h9M zl2V?)ZRmIepD|9jsfo04qxa83yGdta0_C|Xc_3j4hNdxb-=oCBBV{e)V(;@$?zOh-oe z^+#k(&o9Vka8Fp;?aeT96PuD%O$Wv(zs?C^L)jT=029k&Uw$@$v+tU*((;mjx7G=S zu%mAo^|yQPNE?ndks)IM4wjeg^OnvZZ(h;Nx+*S!&;19=%C`x7hT=mjD5d?}u!o)w zCmrtqnEP4kA-S+ShsyH&vGkWxDFQ`#$|}6Z25Zo11oZCH^YLqfO$v@eu7G8C=7ME! zmR=$l$s!z?>cp$Tx_?iekJoF6SC90G@ZF8p@fP^gx12<3=OwL}aBvsnDr8KXTujAw z5y=s7U>ihv1=5i>cm+Mtc{f#l1q@2K;)q-pq&;nqU{&ppEo>Zad1CTNcVcpw{pHE= z)idbvy*_^@!BzFG6B4q6jhp<{)9rTt+2j1c_Ct5_qxAGcsp(E+Q}d+R8GbN()88i1 zIfsZ~q5b=KN-ovu+7@4}gB6=*6}NjtOg1#!fb?#O*du%9a)mFHH}a3g9>NQn!qQE%=GAfucdOhQNL?7|7Ve@HuUK0caaI#uH-Wv zBq?*%VmKr30GtGt&eo~ReGo+^rn0P$S6=w)-cA^f^n~z8vvBZ0v+%n}vrzpO=xz8M zOU`b7T@FPQ!F~9fh-TXW_eOX>SiEO>E4C?qYZSK*GiV6mSlGUfaxJk1(IsL`~F{)-D7hlYS*yqIO*87ZQJPBw$-t1Cmq|it&VM@)V#(R=W%9!^-JW-4%WaTEPVHUP^vDyXtN5H6pRo{D*<{f zU8T9gc?)l}KLig8DV5BcgJ#t~sYT03xF? zs&-@A2;n9Vx{<9#;jYZK-c^UPR8yefyrZP#Rn!~M=crQ($Tif=WL%sjJ92GmoEQ5w zTI>ugNud$CNgfKggj1~iDA)AobP;`M%hfq*)n_}*(eG9opBk0opsFV#873_fxSbQ@ zmKhc27-ReeUR`8_W72OR_xoTsKr*OrlSir_eoP2qwK)RJ#-A-lsWKeKLnC!#2&_2= z12P^mm2R{hCjgr^N%5yM3~4?JvWz$Tz5`l&TKQ46g{<&P0LXKh8|s&PTo5H5u6vLw z_jQgze8bn(mn@|HAq328`loro7Yo7S<4Xz;qC)n->f4mOQH+v*5|AF9(8wC->%J7E&JBlyaiYLdfwMDtdFH%?%kLxHy~F_nJ!g zf-mSdx5;eKCjHC>?^CZEskc4l0gP<7mZ`JC{O`&i4a=E=JmVJ5HFiT7SfDk9?2lt6 zFi{jI39r0gLD{ zO>+7DPi~6FTiOeWzB-snz*L$c$9Je>{_Fwr!8~vc@pCTfSfU?U0wwMIKP)z;UtzT| zBCocIf11}E8V;v=klK7^!%^iB2yreJv zukI(){Y+V?*9GFWiKsg@=R*3Q=c)Sl6e z3}!vzQ}+Yg>{3B_yMT2-x>f65$S6W)JDVIecj^fqH_*)*=Q6|DCR61N&Fhi2XevKi zYyCZAEej^Ub+kDb6y`R&A%u?oi5Fu%k40!^c1EmQ5rf6~Je6X!QBH}o>0Zyx7rUz` z{nPg+&FW@0=?ag6rRF`Jbz+prj@}Fi9dIR2!}R^O3nRHe3y7#o6^M^t8vvoXjPIxq zq##Za(W$%L9vcOVKa$GQeJ>eeNgM;h5@R$3k+n?yR4ej)*g;gxa-hKFTiW(o#}g4oYbVmmL-`hJOa3zg&C3^ z*(80Dma){`l*ul!9E&5S8Sv@WWddi#lrMeC`{%)j^pyqszK|Q`v~IO9kySLSz#!;6 z27!B}!6QLT_tLY=Z%R1g4p&1RGEW!T57U&`eQjQ~&)?7Va*Qn&;nMiGoj+s8PTbzn zK1z*0DePCf1fYOOJccr;G$*@XhrO3K!E)_$}_1f&=;PED;uVxbdug z;(}Op`zCu{&c1x-z*Zj?iuUh3%HVnpCh~tpX?8)CBtO!ZyZNA`E_(4ubthvrobaX* znpeYE8jubURQQ@H1<`kxCUd71Z^A;Xv`mMj9rCHSK-?r>D^^?DI+_%!VkW3*yOGv{ zRE*)fBb5ChAJEjg_Y-S0_^tkH>{Z%d1w=(6fwe2wC>s5@?gZ@Hx2&#y4agT`^#jt+ zlYTr;I5!RJF6gbFG$DZO!Wd&@L~c7JG=|u20i_OVh&$jDRbX*2d{IEDRh`ieNvq2j zLis|Na6_V(5L8&qaA`xv??KG?uF)Y73t;h*pOT|yD0vZ(bA?Wx@*~K=w0X5nCfKjX z6yLzMkO&W^#RU}jKnBbNa(ho~*1m=N#dBgwMXu`(9;mEvll7y)wyOvu44T)SIZwjP zXNf61*n?kr=Bc}(6#w>*{tCy#odt`OE6Y}9=CR5CZ9tMCO7P1~=sUe+1in*(FA)!o zJ!3d6ki0#1HX4kVQt~YOc#Zdhgia#?>MN-nRNBTBPZx{qVlb)V{osbq=yY2>;lt%V zS}|Aopq zV{lFWJdWaE=8UM_!dQO!rcI=@2l?Di84nEFl>A;GO{qIA>nFv5umkav`N%42bV4$k znG3_W*2BYRvt)?}MU&d@!R59j#=>e5-3Y1htDKS8GEJ%bR6B(*H>*#Lw4n`Q9N3ad z3AVDxi!PHvEa`<#&U8F?iIF4TKa}$J&_#`%m`y{-lbhh!sd=5Cb|}jwmyjasiPPfQ zdXS;9V3yKga-Zk)=oEgFwYS(|t7Y@AYR0a&BkZ0Oel1?o%h4B_#-4|6g}KJtYolVp ze&tBJzcoOi-1zhL$X zg9j5?W=V$Ti1x}~u)gfII6oY;+CoPxcX>-goU}MgL*7=F`*oWmzdfoDyd|y#j}y%> zc465iNg$Jwae;3E(H$oBH6@;Zh4XP|Tv_-kOH16HFl~nYNN)vF?DDak3PJx~(9?wG zj|oJfF}}Cd{y^b_V-;COAHc;L*F_3J8mf;JFs6|()&{@32u>%q%zH+lnI5wJ{AU(Ctu=Z@U29epRH6c&>ipWmD}7w?=lQc zYc4IS{3%58!*SRt1=@+env!*a^U<@8y@$1nwhBgI+ zT-!#-AuHlnqG)-@ya&SKBfMk6^Kb+cl>LXS!Yz%d9=;l(kq-QKE(Uh(V0Vn8hOIX$ z>{W29mAOSyu%r<42BUo~KhXB#yiPzX#ZmCb;zRpAyYxe7iID?j+u*Edo~mfDVm?=vGP%bo@(zamaGzN$BbP_GV?+g0h!W7so~&2(BwesqUR1Y25=_Fn8$MwU0kR z%bR?tHY}wvHbuj8sA$7g0vzJekXVSfj7uxIF)rT&oJR1#Kw#B%WCFwWb%^7Y9Nlp%X>N7vC6*Wh|i>sZEPItM~5h}?z)e(+P=dL-`;{+-z!=#xn5@b3_7wE^FPfi5J zSS7%kgOVFqTTLi(Uh->Od7l)Mv{0JcikAIqik7cXerjYmE&t#+b2&M1wbk11JFK2` zy(nTd+pn2hWM5$NN?v6X_qQB1Ou+btyl zf84xrr9>iYQnX=j_`BP=&^OhtyX7S3fWhr$c|(1-p#UT2!aQW!?P}CW5BuCI~0U3A} zEdR;HTE@6mi^#quf(2!M*0We)5J&ONvJafSfH#pgKm{CGhbyRKt-}$bCM$r(d}kcX zW0vWz>uRfE8tUGoh@kFkD#F3eh@r=4t4a1G7fNkiv;3z_z~cOaJ%iHUJhII z!2g=)fxA6h>-N6=FKHVQ1*D&^5ZFL|eZN0aq`p`((T?Yn>kj?3?FV_v4)^!@N~J3x z;791H%}$KL>i~~!qzA!Cf~`R66PSPi zF_7igdz4pCU8%SCu+kmyJJM#v4O-`o#FGuu55{3-cRgOe*e|~K%Z<`kzmp|pcem&F zp~fq{uIIzf((AXz(rrGU8;mPUyGk1mHB9Jp0KSuA2G5aSueQ-dDgJGMeTxPfK{02#7QDtLy^)CF8w5+4*Pz@|f^x2t(wQceofipNik9vWG{tDf3A5U9}14L{u3{5w#kB^kpG~Mn=sQ@S9xn zG-$q2b$AB|=6Dc^Ul$!+Ga6>?wE`xvJ`zL&z{w0uJk3_Q z%Hi|qIQTlV?57Oo9zZ;OUJ8Y=e(#MM8T*p^tR4LtlJ2#Z6?AZx zrMOlm$`+C0QSjEBLrF?mEMqFe;$6X0(c^DI&u_E%<`JC|vGY59#Qf}!bv(ieq^L>} zY_|c;4t#*&FyC$~a)%o>Xekq7+ydsiv?c7iiLWSl_WUOjE49u>$P6()Aa#Juiw2UO zwRFGw=e_TngmeZb3WCwrw~?gUkGH5Aej4d+6+_XA#K3VieLL&T%<|sGfVf6mwRCAk zKEc)Vdi=@tIl&vZ}i<+-4$&g4kJmS(22UA2Kr;w0Oa5% zxd0UPONT4ddD)c3WuDdHu=?ChTjg@_C^pK!1erLeTP`{3hR@D#S}&!+Y>9T5r#sf@ zor7_1URUujBJ&m(PsGS)hZprLMcaDE5T|nWXuhdqlVs?rJ7md~U8waJqgkUeb1mzN zDP#L4h>o36EH(T6lj=wJ8Rss$Pc|7-;NHE-K72?8j6Jy-WP?zfgcycCIiH`Hx;WQM zv@w@@BM{^%>_c6*qeQ{JQqw&J<~0gXCO8aQAvIwLEKhaqc>M}rsd_U3Xn{EW#ec<> z9a$2kjIM>dC=!{DAjf_Qhkibf!Oq&NO^k5|aQm_Ve#Jdlp24`ocIAfG*J_&Tv zFO#AO#JfMLxeFYWnsGK^Pl;S~?;5p28jZPlmU9nIn!Xfh$IZy|;NNBzju?8VHvD>g zUaK3w&i5Q13CzFB*Zsy*eUHfVZo!;s5WB6Jz>>GsZH1Emuw@2WQ50wfTWwu!QmSay zn?ZHtl=ecg%$iD-I3MCZa5}}Z9KF+II;Bi_&Q+-jvU7mk1Zw~Rn98&Qh7$Vj;`xsR z5^7UE4T`l(=5If+QtG!i@l6Wj&J}W07L&*4?r&oJzS5TEmv+C01_v$c$=9bv{jlW% zOpDxdpR1EW=sCLY^PybCDa@T4(rT3{TR1i}P|9W(J+V7$qHm#-*R9@yf3`tLX_CR2 zQr)iyAK5tv25u-9;H(yDMCX$`g_^pAs<{v)$UCtWfW#@2aI@|82t|-1qi^4P|9Jl@m0G zF*c9&8H9@^I*igcC$Dc=hwk|$)>=&_#BSh z&e9|I8chouYG_s%gHG!QEAjfZdzUc*MlCvW{(vMm`Ulel>_tdx8gaaC5M$04EO~0K zg~0>!?a$8dYvP0Np%2QEp3mw`sIkn%iIGUAFJ%zxdJ(FW;@ zkNz}J?FLLyb@?kl$GV9ZcLyd#s#afzQ4ykEoNE$v-}^E}3>YuM1K;cP^5uGKQISBw_C2rmPXEQFDAEgnm9)8>T9=Z& z-dRPUS}`iYSC=AYs(xYTk#By)an75i00*YM=D}h z{E)UmZ01H!BCo=6RIXZkBJiJ~DH(@(#XmgOFocWDcH7|TmH2ZgAQz1!zaevc`ZSWr zsDqa*7o2thhs#+YJ##^q+}JdpV$)_WpT<5b`wwc{zyP(u?@*7*j!k0M9GJ(c+>Vfa8YW%v%?)`&d3WZ%QQ{cP8gMxfUk$XL~3bcFGKF19fQf^9n$E71f4kl z>H~uqcz1Np^IvXuTM1-$<5B_72dzeDonU5PQV@9xXfHx7AB#L@!0!%Ow)4FX4!Qz{ z!lX>|Ac9gad()=-v5 zh?tiJQN}@c3T>kESkEwwAUFJzcZ=sg!%mUETsSb$W30xV9UoOj$_i8Ku@;*p zXYtf83~!l?<)LP}UZW|iiuA6se!M8t^A`j{a#V6kN8F&363oNR`Sra9Z_RZk(x>_s zE|M&l>uViSiyFOzmKr5Rthe*;0AT|W$X9^PYtV{iL)mO{x$h+!1x~X==o?VTdWP;9 zE61+Y!8!pua`4(=uVfQ?UqgZbl}>?>+O)%tNv>e+`NydO>wS|tE61?`%t`Ajs33rg zz4fnEW`c^LQ1+5}CfUOT1os2eu|soj7mk6#6+*u}9=HU%A%46_otIwIe9ZIUz9hAR zi*51fCWYVOnG`QINuEfW2`B+lfTc(UR`Ae;0g@i0ko$lX-~LD><|Jth7S_vZJ?3bUKGcGW!WQtY3e%IQt*yzstasYZg{S2@wM8)I9#B8 zywa?y3g{`&XKQ-}hrw!oZfLA5aZtH!8Ym$qP$o4w{MpXFSJ>FOa#kx7b;LA*3&Wq; zT~_G=7_>a6pp4D61-&%mh-?EcnpM7P{PIqJhM(MJd@XS!g8T zDrv6Xuumn>9VpNq$6rV)F4%ocALFwkGOxYg{mvieI5L=}HBJ`Qtg1_QGcLD3#0>RO z|FxD|Ifq_J%a9O`{_c zL9^3QmZqK)@P)o{R4Zrd1IB#KDSZ}w`Rcy9;+9_VZc3|0c}csg#%~jcpe3|zuuk>O zdh85MmV^)R1(>DPt?Amv2w%`l@+G2-^zt8V*`IXUEeyYP5KJf;u_uz*u_?V_n-!il zpsQYLaIvPv21GZJ4WCt06?>jxFSth#^xmFM6j>Wzr;)V|nK^P3A~tP_6pmtKSz*b` zHCv2WN~~wsDoAGPm^6ej>C0Q`lHX2sOgn@72*TKoLBrT^m!AXc#fSaJF4|5`2MacI zt)&wI(f&&a9Lt=$Y+JZ{KXDw>$xSu_LeJiu*;#IGH#s)@PKy-l$Q%p-YrL8xS0Zuj zTs^5oNiEl2MA>sb#`U7c{L+|JD2cN!d9snPb@XP4JF`|T{Bt#{tpg3|7~o5mcrm0t z0fbqbTIACk_#41<&E{?uSh_WKnTudTPdahNeB%;zlh5umn0AUD1-&=`w$ehJjS!nb zV|ainRI@H(57YF8b?ACn_I1Yr3&%y#FRQA||4`&VPG(qJ*f?{Ei?!2sJT`ksAV)wQluN=E3A z6T3tShebUH#+CDLb;0)!G8taO1)O97h(SE2&?X#h@_7d?-A`C9U7MVmcZNOl4)`;2 zf6J+_TL7J_$IC~1s79MAhC2$|3|Wxw>RpsBw0i`5Dey0Cm!yY?aqPeUM?yvz(;6VySztO5kA$Kv`rVg z(4DY=h$-$y6zxus{@ZgWne=Gln=HI z6Jl~gS}j{kQ^7ap&Kf+yim-MeMNFjxu&Q%6oL<#+e@B(R?nA$DmANdINc*%N^(B?+wxUS=&~Q19=zNb_cWd=P z=B6^e(Oa8E=o$lRCmzm#2OSH~mTO!rd zM`sOKmnk|(bBjXsF@Jh2Uyr7W!7m{~;zIUieyf5R%K@a+-h`2Dzk`#|SYSKXi4m;3 z$bs;CsqnGte`in?{bPKgYjYS(ebg~^T7W~>SGI0(!A%=G)1yj|JX4}7sVZ=0VgR@& zl7lI8;lRul7rm8U?FxKlxd3B{aiNX}W;u>1!v7=WBIBp9L7Z&3F#1S11UN77ODgrX zKoX+=HXM0-FgbY_OZlps#_R$^#cs$8H^(Z9A>J! z0!n>ddOrZ09TEr-N8=HI4Kt}+slsDz5aeKBjMh-V(me{!OO#e;A`g;@O6*ue8zO zk~#1#nt~S7*X@K4!)~el{UR2M?CNeXiPA?M?tP1s1~yj;zvZ?3!p&%UCDrepv&J%J zQkWPum^8U6ESd*^<;DJH0l?4E*4#Eg;6^zXH0yHQP$CQu&s7JKC&%!?DUA3Az)Jui zF|ogp81WOfScVx0lO?;UKoz6Bs6La9dF@v0TcBV=dP zcc)U6AJ^n@)`NZ5rS{OLixZIQ;H^L>&wIOHkn?l@uJ4D7HUif7iwY>vx)_vJwg=)h z-KCp{i#16a!iVuZPS zFVA|}Y^^hNiYkBNKhP+8o3id!f~Uwo(C9Zyx;MHOwk02MoOPFJXvFnk*~x}>{G0!8 zX0%@~izt!QHU_L#PKg7!&N|DuWM??v-PhM)v6PPx-b^{7Fg79OoDVSa%Yk_96?M9g z6FOGTliwyGbvU*&KBTJsX>hvPR?G_be^qTsvj45xGLgr~6_-&aVeta;ubO75xCCAU z>(*bN_k*Lhovw(8#5PRBWyDM4(zoM1~(bln%$Zf19d|>S3k0 zIn-?13D%nN`wcHu!BB2xMsn}goJtpR8qK$lTs~#Hn8k(XKTGe*ZFQKTZ@ea~+gqBK z5ZyxOiU}Cb7ZGOl^6=wNO^&$3;bDb4zVT(?fUYUx$N@X>=V%SX7&dD0^^HW)SNf}5 zgGP5dyAJ49d4Tnjqumg$cnN98jeD;p(wM;w{qPsiOm0)%!sfNX+@U64T zzVbq&<3P|Y*LcL)9MSz1Jhl%)en6}9E7(}z39w4^>>m*prw-(3nolLRJRW{57q$<+9H&RgCstj-Jm zva~IJw5uHKZD&)qG2U1qI8WMmhC@?4VX)o1yhYeMkg)GI1w&*-DMdq3k`E$-Iq8%` z&{sAKIV$42ScFm;5(sR3*IA-PO|=*^$9a`~SIZ@?CMpE1b#1ahR7xC)4ZKE?-}26;62H!v*>Dh`DRRo{sJ@3yEaO4DRSx?>>uG(2h)DLAqbnsg5w z$f!T|kBC|{_gcIb0!CK(B)4Bb2kFO56!iWR6g{*&()5(3#L$?hNGD)A07XERa90p~ zen>xS4rpg&O5#svyB7tC*24l4(_VYei-|o5LcXj>p>E!^&dH0{(kmKiyKlz zvAuu59SSt_p_K?C8AyPTVIG{2u>q%O$ZndCgQDs*sr5DVkCDGw^+x+|{enYZe=z3< zl7WPwr36wrmKf)l8jb}Pos^_0wAD1sL8Ptdq;Vksq5H`hkoWbsx)xv;r`9t&tY%BL zr=>CWBeRmUmJ3)JvW4ib?U-|4=t>!7Jpqs+h#6#Qt&<~r1$nUe|G=U;s7Xf_h9@4+l$4pP zpMN`L{e(=(hcl@tiN33#g=W$y$eNrFk!9m{bJq!ye7N{3@hDC#7uu~V_$EY|X%T;f z9z$i%4;(+oAXC6>kY7&*Mt8`L#Q2AHh0DOLHZjt(+LBsd>s+v;#~u~!lW?YU+{Sxt zkvep@Tq#_5%HQOtE$pYJq@`iO%lXx@;269?j_Y=z>j!Q`Ii*x0%D(N$ zwOCSUKuk-{-f+4W-*UPR)zehuGKA<#y&0(ovkwfnN>GA`NnwKBRa&$}gRbhm$7J!{ zt=}lOa}h@>r;imssu#q6n8E!}0~9&mtFTfr4DPkqT8&UOc13)tdJuE+8C_6(h5^0& zt{+_kEhR!G>x-PRDA<}WYSWtIjc5)WAI8r)31~M0@#+T5RLBlQ$5(i*kTe@w&j)QA zk;x8X?}Phol_et%>MdvXo2pwg=nI5Ytmi*T_~E%S=!S?!0EhoS_w`65qEHJuOgAEV z$Zr_X!t2j*R8T(5tL3!?PMYr?D!l%IMIC$eatdjRk9K{!qchFOwj#~TB2c8+H3CTpzMzdF48O06WxZUmZkkUD_J;6g6HIX4zzEr^%w{mj z7v={LVlOB|Y`<6hA|zb^XzU}T?$G6*#y4I!+)POc?l{w>p$o;5&Iu6wk@Ot279v3} z>#Msd?uITlx#UAI|LHy~r(rMfwuItScicP!0Z#JshZH(Ua+>355psf)Im=ZI*+PBB z^}%XPDJ79aX;YbC9$vv4#RFzHe@qu;xlhv>QEGiHigP%^I@_>#PQwK=VNIZEFDt7* zl*IfeY^HAd>HEu1TubUpzQ}U5yngkQmk5qu`@Ee6_UpJFSE;<6(oh$5UrHVA?@`mz zLj`M?vuMtl3XaHBQN@*im|>edLBdafUd9yck}ZCEiyb?$oyz^Tl*ZR-NWoB>HKM|A zBh}M2R`Sbx(zMr>B%U`X-=P8O$|Zz7N4pa^-2OhpQq3c^88f`1lB0P~4o=4tlR-0e%e8s9lAS$9x za&Y=iGbM;Pm}fAyaWg|S?q^K^Xj>s#znL=lC#xQ29 zk|xmJpGHqM$}`Qhm<(=dqWj_d9|Iv+Xt`RUi1o`7T&DV= zNV?*dN zaayaXmCm(OZZtn1s4Z@7QhzvRmd4W;Q1?li(j<0$mbt&kHaN<@8Sp~6v*EH^Xy0#4 zmZ6#@L&8AEE{CBZrrX_g=&?zinL445a&qaI@FCv1UGw|>r-xj!4=0vCYPje?)SIvw zE)6{}_E$;Z0k7OtdP+vHEnHJ1a;t4FhviLiJeoeD6`id8$Js4?HLgBftNDJ^9U!a{ z#6T(ylM{qcfo~;1^;>YBH;&FHP!`N>%l0?*Gc@PDlya+%XGL}Eb*U3N_(=iJuvi~y zer;j8$%bXGIlkDm#k3U}^m3{3WJ0rDk9U#?zCWJ1?ZglkawAJx>`xPF#OZWiJ3w1S zBN@JC6ol+*nRosL)V`RHSCDR0+KzB}z9!-z4h_6tZUg3K%p4DsNbtVGhh>b?RVa$p zx;)pk z%j~?OKS`J@hApdvL|AG;qyA_dU9)f+@z&}m|LO8}61o!2(>j&Clp=~8i8;!d-(Q7y zMli`C|EW3Hu38#!;QKe90yF!Tta!~ilPuZihYdxI%4L33{s9?;i1PVQHANS|g%(Bu zsws0r-6c^xKV6`OI8-$yY?FVwvGx}%B+#}DMfi44o7h4J#ffACsxD=XfPd(V?JH#q zZ6~#E-A-qIy_KfRTr~@v&c$0FZzIz2uTqBnmqPq{u>d9m*Djl2Mx-k0Qbt>rkj&Vm zJA+A@->JCF_V)(d#h12 zwEG^$H-GzQR%G-!$~22H&scR72SLx?%*NS8MQYH@-Iia~TTLK+535!IB+|ouLK2C- zi%}q+>=GqGNHq1kkJb9uCzp(jEhUoKO|n7f;KRY^_<}QiKe_36Te$I zHHQZtTtN_WjUK|$N~#&(^~kZH3(kj}Dp^4FpH~3O@Gp&OQjXrI-|G)7(q<#cg-oz1 zMp!|V`yWf{>c#4xH44|psp&2u_<5vlqh|1nT8B!_f;@* z*KF4}yj4?v)unh*TQ_#GzEOYeETqDU`m9}r>VDVpj$YV1WMN)ZTBA5_rc?jHM`k^O z_7k*~bRsEBO<{E-wilY#kfw)v<6dPK9W(fw)WFms2HDk*ZLmiDEy@haDwXC@36vbE zsil_ognSNL+fMj?j{wf(YUQ;{n2Clj>W!Rk!Dxv~`T{C~4VL_J3Yq&pRkL0vu-I9r zUW4|b#&K1YH@j1_m^e5`@}57FDJSDXy*OKyz9OfZb;w?(teb@Tvlv4Wc*zyyNy%*Q zi&@g}bh7F&eqj1@42eK4UXvDiE3zHX@amIxn3d9<$oW+ni-D9%+m+awlF!JBRdKlb7~cZoomEm0Zr5q|vU zv3m;!Mh|pE*@VZQ)zVOmD}jwbMBV$cSa)L5jXcCvi)*kL7E$g@#!qy@`7OT~q^G zno19O#Wr6nStwQq3921QxM5Nbi2I?6_$E)o??O>!h1Zrmb`a{Y z+wl$Aq2~)*&2o6?19xraMI{oxxf6IEKnzvEnT{X+B z^G{F{ckhpam1cIF=r;%j0D}W(-=M^|yfj-|T+#?vpoJjQ)EN}gx9J&X=n>ORZ&=~Q zGQP;94V;+uK1mQuLBK+mg;I#Z(HC=1;lX2}cBm#$exk1&6fX3o`y|Kr z-YpTKKXep&y;)BRqHFH4Hw2lfM4jHb{f!1;?Qmhs>*6`>9KmX`c#~&Jgr8ALymonSfSJKP!DDU z(wVg>%|m?B(a)&|eamKwPns0h(vZjJ=syd@KnK?SjFcJtDPy2F=y*}; zoMSq1|Hs|i&5fe~O0f;BO}dZ}e`e2;J4FgzDhmhDsYWgMtxgNO-}&G2K`K{u_kYR< zRmv>=Z0r;}*`cf+%|L8}lt&!O^n@@7)ik-LNqed`7y>l41<~WJM13L@E+8U2puYs} z3pWTONND}U!oJZBI3(;ogem@${fHdbC&^!nnIC{>y+gm-Z}{fPE%w5E%_v*9gZxSs z58dHZ=+j)|ur*iGC7#N^6?q}*(_ueFY|HiEu!3^fKVgNv4bGj8%l{Krct&`hV_Qxs z=tPz97>ek_44DVc74GQhfaY(750F_%&XqlK|1ibguO!twP^DK%r=CnzXhC&z7#}Ty zb^!_@q2b`n+8HiRLZtcxC9R7CJixTGWWw<=+(YNdowR^k;v#b>3k{VcU^2m!SgMP% zlpa8xY6A7+|II2C3CIr^*8Nbb1RC^)7}WclRVY?00&Nao1^Jd*xG_ z7L`+!*&zBS9t=JrZRh65;NukJ_WdGwAKn0mNT}LA$Q5A8c3t)LUt+&E5&9;@_53Yr z&P3>SlR(+Parn_)wO|;=lt7pan|tTo)GCqJ*0Qr9^XtEMJTLXV4rk{YkMfGoQrlN{ z=)ECU(z-%=cRWW-3GjGdZ&8~9TkA#A%V#nbZGtVO5NRlq9{q_X6R~P1H6x|Be3iw` zl7p9NQN4pC49ENJ-?ZqbEt^^W*QzQHI?M%I1%jO2SRw>)$~!)V^t*QTHK@9tQ*+*% z;tHZCc9I!)G3|(QhyF8_#*hGG|8{yI&Qk65l2S@+zDxhBN6dW5MaGmf5Fz}()u?d%dA3PN1^&r zfmScrQNgK>%0@23x|j>3=N}N4)mTTYPHhCg4AjFZC(kI{t9hJVCWDHRc6G&*9+y&l z&X}$y|1x;dDOtxbDsnkTA_#atp7)FE)<+wQ=_}0q2ex(nWYH>w!M}N55HxgevW>WfQ+d-S|MYuBke{fOM^~EA~;F1e-i) z!eoVYjqQ$gnk)PZ#o;^y0{?(F(@Too1ee`McUq#=Bl#%zAlYUHKX8q{D|ZUfai9GN zL~mg2l+j31`YP+N==pYwN+`iBS}oZ)Ui3!IprFtNxV)E??we<)paNXpbF5cHxh`0n zL+WB$P#&&6cg%rV24|f*>%$Q&zfU5(NHa($ zcvE$xqcBN1;)Yd*_@0NgyG-HGy+;#0u?Vj?dHCipg#4f&XYc2EJyA6!W9hE=k#Edj zujqUAc_xtaegxI~`uPU@>br%|^Ld3N;G3LJKfa;r1!gs3EY1F{ABe%Gcw_%H^)S1Y zp~P|Yx$M5jhjZ)t(H^9esQYUEWK+M+djkkg?7!#T;uXi|F6~28x zOvWcfLe5E!AJKFu*sefLHaxx))nn9;IGGUr+a9h1QH&+Z)<3GKxfupYSk#OzK3Y2B zbdn?m6l0|HKdPuVKo#{=)r)+K{8tst|4pZM`mZV~2T(;pgho@+km>=d=+He-cPl^@ zO$Df;HvdsYH*3d-o{Js9|D%fD1N~POEk^oZRMFWI%Hc>`2YtiP(L*~Y)Bs1iD5jxEi*7K-*is^}!o zVM1Cg?3^=^D!E7W1k|Vq~<%A5>wb*v-p3aw|FLWeN;x5<~hNItnE zhpbo6S%h~eAhG>`r|)_0Cw$1PmcOO=^dV`=@5(T^J3WlpYGL9L8`C>!1kc)e!d!e&Hwa zU6SJv;gTsTL_`$W>?4~|!1A{7dF*lrX>I+iRMtp#9$56G( zY#-1kwnEN*EU*hIGiMA$R*yPjpb!!r&&P}S!VjaBougI1 ziVQKYTtou@%1cTB=l!L$xDrpCvz%0w?w(W|$SBg?R|#X+Z$DlyIZux{!9CjYW4d9; zE`Q*$2vR%ZmpCnXVHS3Hvj!8u`7nq;!;smwwXVt@G36JRUgUR>bQe~ z59uk_o zu1LIwL{(lGZtL#3W)x=mATH_boGe2rf1?l{a&&x=qlUip(OLrh@HI(x4fTPwlw$ez z+q4{A7g#P40yauELeLgX-_|?Z5M{sH8E5jrKO=kSQuT2;obqBgzd)ZJmc79zn#z}f zR59h14OMY#KOH%jRAnE4l$CYrm81MyReZz4v{x?h*~3 zzM2Co)oO+YyQ5_TLt{w2ySW$pOjJBa;1jLZaJvcE7yIazf_BKb=)d#k)W{)zWZi3A ztFuApbvbMTifpbEn+q~d?&hO;ED7mUh;J*`n&x3G7<3Wxxk!o6oacXK1w4SPFc7N` z>&iPY*aR=Ox35qHK(8YIqE}*NAyXJXi^fQ&~?0Q6pHREz&m$`)u*Tn^Tu}&F5STn?swY>pFU$(|G_+5EfAOQG=4jhywV> zc^t|4O5>@fmn==P#7h=8zgt!#OFjh`4(2<#kMEZMAKTJfy2nN=cH*!RnRqi_j_0O! zSF+j5XK8%n=srKxI7z8VBxky`=n{57Q$TOEoFK1Tkk3wYu;!x(126cy zpFKQrl80t};hx*(F?Tl0JmI*r*z-6Kw_mCiQO$Q-iO*H4!|x=Tj?Q`S(A`@qK$CGF;ukavpzp}mZ2w( zh&7LDww0leG+gmbd|oTkArPp59E=NhMxU37`OHd1BavlPU@UAO1LIv+j-QjuPEbBm z^qWmcK{xndm%BjQemF!Dmr`nZeTzLkZ!VDB`$!=7)WuaD?t+)+;#Ezn{Oh|WXW;Bp z-KG(yMnA+SiRpI3*#3g6OB-SNrtUslDc6Gb5i3NgH~j5%%cjl9oBP2C(8L(&>KJ)G zT9o%CcF|yb6T>;i!2QI~cvC=IAOuer*@E}rIk@=w1Ugth+91cS)*FXWp%M<+meTMc z(Lc>{2ZWHYuZJ@jV=y4=s~FAy!Nk8Pdd^f%uckAxtTVfOzBckAn{qJ(pM((>db?Mtf778Il;_ zPDTac=qR0C3BZ*Px8YMcX%!W61QpD{4_0T-kQ4zs^og5ypj4M%bnuB@5!io9s6dAI@y1l@P4kj6_X`^r^qv)Vg?ioHe}SpUfU$y^?qs<-k9gR;-GBPjxLiyA~TsYHsLf$icyTZ@KOF z?1c9f(a@rkL}{J;o-ue*+O!hc5S7TAm();srn#aGaT*JUlYzo&<4rE_tNg(6f{E-z z&)E2i{r?d5PEnQxYL{i$wr$(CZDrWDZQEvsZ9BuZ?F?HLdH*}As=FWh;he`a_S+eI zeRHk3bXU$Gh@OT%e+Jf$x)zrvC{Fu{fe}3wqCkAR5GY(~NXYwSZYjZ1Ud(*hXk}wE z+|Zh}$gIfxwj7ppyKYBLn-fNSU2QK{*Hs|VEI7Fh6mMD={4_@Ou)q_Xg~2cU<(c+Z zhYT-Br^noapiV|O$~LWkM=iq7$?BLb+~${GofGbm9nYfmqdKUO+YyQV-8!W(r|hmL zjQ}rfDuIsDxL@Sv^gXGO@R>ESkIh?n|I6?6y=jlagOOqdVOlf&w$0e*zf3*l<`S;A`oPVWIj>>vl+0So&BaSLECF@M^G zLsg703)~!sNTV9F2%;|L5h#tG8jDIP7E_YF;<&#$Lw8!CFlam=>t|K7F3D13QanCg)8}?|z1m(T1Jo&4t16s+8YIIRYikq@ku(k7h`HJ?wOHzO zzdtrT0*!Zyr@OOv!``v6a*I6cwJ7uHl^ie!+&DCO+*qQkKl6)hke|SDA(Uur&%84A znc88s29A}Gm?0LC2NxL98$hXYjkhGx&RowA9My=6N%%MFney(KX3K#8=Uld!E^P zN2Lu=`$F<{RDZb$(!eHLC!ld17bFj@CO3~$jiY`$WnK6x{?(wy&_Pz;qC?3al^V;J zZyD{_=!S)kcW~}>89Ht$TEl0E>^?bl8T{>HrB}}_<#PbC*ezPZ?~QftgUrZ=O7EH# zwI*@NpcsG>hyA@>~yB*NTd zo>hNVb*o9g2PCw{lM@JLL?2xnWUg)DC0N%3s$hd6FxiV@Fep;s|0wbx%P*?oDDo13 zS5?W_tc%7+$228c`oqkjXSA#&Sg?68St;o7TmDjJqhrNbUM<^_x7NUxdk`rh-4x2H z+nt%u(WU5kk?cf@&2w($D-Y-x!$3n9dM8ezVFay^_GCVq+(b4H??pKEUzjvV>8m zeyH)gJf)1`+6R4DHrj=DqR$_`ZW21gu@%y$ZorR0SwK;HGG_POB68HhOE&J{$$Dk4 zt-C9amMlTA;Y6Xx9mn$Lpd%dfbI>Um=@yGg1tsQ+DJm>E6op-fTHK72ut~P?!Ebx? z$i{j}*>9ZAQ2NxK+X%aF4FFJUXQGhZGH?b*Uy6gO6AklykP9B^Yw?eNANXEMB5dq}i?V%)ml?ycGP`JZiI2^S#X+LoVrU=FD3N0@t* zD1mjHc`+O(A<~NGdE8TIE=}zU;GIfVdrjoL<3| zs?I^*n}i4?SgeYIcR+P{xs6p2@y%p{s`YMv*Ms^7tsP#E<1qX6j0AG22_K%ltv)}y z9eU*y+Z3G+YH0hKE}5`_1rrJ1wSzM%$xQ0( zOa$O09T`zSoUi@}=cCAd2^lEny$WZF_9A=yLrY$>6P<~QS5_-5HAWkvPNjL`Xz-UH zp>SO=&@{n*6NQ(1V+978E^Vld0D6-5tgxWz-EeuvG>%~k6MviERw?p+B}&i=cNf0t zz|5G_4Bx7-%jjvs`o901qAO{;bv=V`S8;=H@S%?$05v8rHh49NWxgWYWX@J2dRWHZ z`0TMsQ$kK_MF*$9dI-yn2N1HN{y?F2Q+Q)>tb?o2FSBUxUAAEXF7yxLUu^^$P$FJl z1#rE!tpUexXt_X}&XG#GpV6lph;!LeH=n*@uN`qsBr=`%mJt(rB<@Ob8jF4B#@fN} zE%laV(QS!95|A!Uli^lm6tqEGRl@8aFC%W^(#~NZU{m|DO$ci)0SU7 zzT)NN{7t-W+#4EdN$~N_qFIYzlamHCVjkQCJyxdr9pQdmOg3(HR%ddfI_4%FOYu3h ztKueReG--bR)D#=I!1L5jbWgsv5i^}5&88WujsMP@KeCTh}pO9ur6Zz(Qn)9tKrLLMxv*4vzoc$C+&Vmnq?*0!~t6Ds{B>GBV9 zQD+}No2VGLngP;AZ10XHy$f-Z7o5tx=0LRxdrZ@z*1qX9k^CX^M+%2;-erR3BuJ?dM?bfIsiCpvlUj-I=?0Dkbp4%ON9_#4^4 zcog7O_SCG+qGeBYRkuebe={bOyfsh2#xTqtRAE0 z_ov_`)PJq_g zWK}4JUc?%V?h8yDq0X@Ulf?yYK3x1fiszz5FGsXDn0uyV z-V6^fN8_i@TNa8%Z(Ki6X;2~-W8t4d+2X~?cyK}esP-AM6uYbcKe@);Louo!dIsQa zK)mENya*pBAmVwP4D19dgk2(a{+rFm#-=D;|G|X213Udg?e8I7B%K*%#Xxkr@k2dR zDndQUfR3v!>_6UW{bE-Qx(I-L@D2C|h)sM>3c0Dhi-+F&PziGSU6go0fXiJ~<23$_ z?ib_(dq!N(W$b~`&@Zl8E@TccqsI0UTx;>wPOIO6nf81lu38+&vX&8N0 zi_O^<&bcS7x`HtBWxb~YBQnOW9>BSSuv<=+Tj+y|Mz4lBCse~rZ8}?j>MVYA*LBqv z2pMdwCMhAU;dwYN0A)Y~>sYUk@uQ$h3NV2C52w{`83f2ogI19>V?JDYAlA21DAL!u z+FgeW&8bd@+i9s=&kqtymPIG@GIz3gm1oeu$S3JzE24R7oG|(I6MIS!SED(HZLmtm zRwgw|Ht@*t)qg(RuNsf{vv>6lisSm{8)_v(@{aP1lC=@Ur8nsWQ&9|%{^N(X^J!8h zF{tW(z3sc$JK!JCLk1~L>Ce#ip0as5;qq0wWzu=iLnLkp%vlp%IStxADI4o*V(NpJ zgwm!hHr;p80t7K3Vf_zsVZeWEGYeCr<_S zWClag>IT9-V7v*bk_HxKVG7`@7y`u9{^(CD*&z`dQv^&ide6B0ejq0WmIO_g$b{J= z8NL#1Zm9`y+_V8TZd=dXcTjR%I4CyWaN(fjyf%w^Y(l|u{ey@fhBKAAA8!ONZU4ui zHlZjaM$|2$c|Z1Xoi8OHNCoMb58`4?w5kiohKP2#5VSMA&VBbZl2$}bLqxU81$(lP z(i3X*nlW-9RTR=I3F=xUWwNFl~xV(>-YKcQULy{12sH;gxy6IbjP{#GZlUZqJ3VTsu?Ff zl0E0h#>`Y}Zmo_N;+63|(EFr*&e*FHqm3JS{v5}5_;7jgabpwk;(9A=?EefLW#h)) zRn+Q^0kq~+$RG{cpqmVvJ!|%RQp|QN54BSH>r8u5u13zNMYil4ot#@KbfM&K@g&h3MFnISt5ZgB(zvU;Re>!CC5`DyEwZ> z5=ZHD1D=_pGMJY;dFBL5sYk4ddQfP%htT`vE~JGJTA-`05fAlY%P*h4{0tDq^&EYo zob0Vx*(?lT#f#fiq$Ib#tTf~AX?cK<%<{2m6C@mHjoVh(XO{PYMwdU7-MXNB94F;L z1JTQ!(&s9sIWsd!z-yoGl?h1};YNWU1M7}!r8Tse{FP(h_UivbDy^IxZZnr3dN3`5 zjx;ewSN|6+YuX7o`A^i9ee@tB+~|jeeYAxV!f>oh(*nbC>ACj71EG|Q*G1SZ(neN8 zr)LXd0RGVwz_h#^!F*eNwr)}c+nd@07V4#@-x!f1NVzWbq)AU*`)t6N>X9#bo4()j zAXChcF5PoAIYN|{wxgT2R)k3{y~exy@%4VO10(6Y3<>6jHuQ4X`2@HONWHJ8i_h7p z1InI3CxMSN{N28%iAWRW-u_($(LG1@m`3nsdTye1o*i%(sUHEFYei($01AiwA5s0r z^f#mGvQ&Rhx^O(U%h<*}ZtR}My=!3jh?%dAn`))S<${i_h8CY?-Qi|u>Pi=8_b=Ii z2DSyMg5X#V_zuce59zR4n~taErjt+RjAss+=I1U#i@; zJl%I6!%UqsQOp%x&eCln3;JUNz;eykKyyG^WL((k=;fpL5slknSRNFWOik>QN$xJZ zVPAzPbdNRxLDxw^A<{6~feMXrO`nY4YEVa7Zi$-(9Z0@yqJRgbo!NO;KsOFN6$gqd zdVvRu&za(nBzGF45)LE$OV*kKl423J;#Ib4Nd)@8gU(e|41)Cg;`%gV~z z&BPyn!Z%28?4m>YB_i`*ibpL1DwSk-%Wz?biQN=(LXjKjh!;B8$XHNh_D%b)vef4? z((U|eMCS7*Rv$+)HEd{k#q-KJvn$;`k+LgWogQudo)(t0GkC129yu0|6|#hFVisI~ z+t4dym8&T3U3RRiBOaFujctx_*X^Te7`nbcfL`{4+HPOIo07QhE>C`#Y(nHWTogZm z8NvG66jlV@5%Tm;b5m1a%CbUCcw|lE=2b5OEq?4)IS^IkLFUEXo3Mk^{KqT0r$hD> zK-l;5hCuejY7AiKt}TaWS(KNGd>g>xXxNX#1(da3TlJEdDYgAW=u&y|a~KizchPQ} zpw^%TATBtH$yO8d51aXL93^E*nLX_heJA=6qaIQPz=ji%>$C)%v@g$8Rpmvjj7bi)eiy;c^{qIVBe<6t+`1{_I@x-zR_nS0_ESW z*`tM4PcNsCmV}CM$I))8c!TY-yz=T^ z`zQ$x0t-eI_rwAx%of3jo(FEXz$yJ=x)&n@d2DZ5%AVS{l%^O;r%mT_I=-L0fNggJ z$G2p*kx9@(U&D6Nsil=s!a0}LO_!H7;B$AKuE}`~J?Czuw>0APB;i{y|2mZLr{=1F zy>2MeKe)3H%xyTqa!eG%!PXcL*@-NS_v}Kng8|_MB8t;>@t<7u^S-VKulGq!;u!c= zk%-&xFDp+FG2hgHSFSW52J<$nChop!>AATRPSb?r3E8DHv2wIUI_twUsxk4k$R+Pr z{{3!Zx{LiD8|Q|cHfq?g6e1D)##uzRuYk@CZ?^B+R=^)Sz}`7BJx~vi5K8s(L&K1l zg1V~uQ*)TkXx}XhZPExEj$MAf6`#KrHcG7_lezX8ljwwZYk*30HG^>@{^LpUK*z}h|zI!h)qh^bA{kNF0GvG()ZNNG$p(9 z!`x?eIGiwLci1#td&sQuUEJXvs=wmqj4VWtowp481eO*67usoqRxw7^5eChB=U*f9 z9{j$d8*brZD5L7>uE(V8^vo?k47~J8roDdGMu+MR>S2xU?4q(wcL;w@BZUO|R#$qU zq|mP-&g7(D>voEn%G5R*MAJSEX41<&uRlRFN?&Z_HqsPd(3$y?B{afv;JnD`vrV#mUM&UX5UTT*k@L2Wlw{C_~OeN)=G?LM#w#09=amO0)F@`=%JfGvryB zPIUyV#>Il&jgEoCDk%8V{F{mu(MqgPooIyF)9ukihLJO&qDj!vI}BP-&^zV^k#tT+ z^ula4G#R`SsEvd;eAI&f_Ll#^Z6N?4cbwfg@HA8 z%>d`X7tTOG)nOi4^>o8C2bl0t<)O#?j-DFJKuh=6a_=1>*4bE@5sk(pF<{g$cFD{+1#Ifoxm{Dhx{-BO^{_T zQr@wqu+Dcw9MdeiwEAZpUMff#+2WPR4;MMzG7f@R4PK7yw59fCxP>rRzC&aM31l;= zBATk;<~qW|wY7x!9cRtWx}ba`m><~c1_A81Yo4ZlpB{ZQ-)~8eS+~FZU>d*CO^u}0 zA7?r$fllLKl>=sMD?nA$O(0>c#EKf&CZro{VZix(7;zWVK5f%4@QxNVWAeF(h3jWq zj7#dXWC`c%4q<^swA-)<$pg4)PxY1>kLYllKvz)F4bIc%FoiTaVWzd3!IZ1G34y_bEp^QIy&!DdAyTy+ zKMZkz6}p0k-^SfdYaxZ&CJ;9$@T;KdM=U=p!1kvtR#E}wHIG@xZ3@dL-$6(Gd{xZZQ*C?G78>Y@%TtRBrm+D27&?9cq?;S=w;^*Y`H{7Kg#&Tl?w7JP?Yz zol$Dvc(Pfo=Hq?y3(sr9#_{RF0LsI8$P3rN>L-kvHVUX5=Du4WlV>Z){0&(MY^s;^ z!RYe>#MilCB{S2}BIieizX{Wfte9w#)Tpl*wl3Arz#3`mNcVH~3 zk&`;3+_n!g;{V{a(lUoZh8T<5=XknXMlADgKYpBE$*t9A0ijPY>crGI!)n=F4`CYeEh*;KW8{oZM z0Ct@QB)=G~*}!LM&}^bj=$OxQ0~FhA55}+%8Tr!&F}A)Y$NJ26yDz7nYW1!{ZD^>j^3}WjAv)py)fMqE2?LzM~-<>so(TtB5(6NmlTMypP;Bx zTW#b=)Orp6Ai9I23LY)}Hu+JYL~6j4GOf%d05Q)q68MGs{Jik298*tL4}P7P#3Qr- zezC-wc5+v|{?S9D5lN)X47@F8#cKks)yUR5*kj|_dOag%lma5UMZdMdQ}AsbSBt2Z zm%3fX;R7|L(E{X=={=@ZNDdT-e3Pf7JP5Q4~)Mh@Z%3yjGVe5MSVJ`o8h4E9+23iv@rcIoLoh$b$ z;&L$#d!VPkEK#c}bppZ6LIxYA81})UxLxpC4&)ufuPrJG^QQn(LwUWt z*N5ooI2N+<kc}Gqs_ESn(6LX*3d>QnWsXIXZ@#uM$FXbpm5dc;LxFt`*P_h95h8q| zlQUqj13||px2K@SfpLL_LgxGiW|NrXWw~fQ?h9biveiFtS~;WF4VugwGZ*dSeJK0e zsky(E2FA3ly@S0*@5Jh`J8t0J)-IZ$752xroY%W|hI~8padmfh2?VK)CV!xC%9Tn3 z*f#J{D_M>8%aJJ@Nr?0E;OlpAuTS_l1FO`gouDy>=*z zi3$ux^7v)K#-CT?^bS4un*0aK2Ew{!BdXS~RNBtjRz^d{{@!Yq++XhW(Ui$MMj!SS zxC0RnTx-=7EcDRDNa*&Z^nEJm9xz$x#6ojS07~6nd)%NZr|AnWJtgQE^0U~^zYDI^ z=Ir-@kTeUJ?nB^{zlo3l2v|29p!g#t z&dHPVdbwQQe1`VzC9RRn8W~4d?H~J_D1Yp#^Rx~B&w=|v7rYQj9N^?kQY&H_GbbRe zN!Ft34fz%eZV!ge2*kuQrD@IE_TM_lh=j#VMcYTEju^dP`6yO5-xD0+GC~z#I(w`b zh@5Rcp<58pI5Sx%bGnhLP>tp67)5BteP!`AH8p`V)xrd6u197IoO*s4$=6g7=!W}s zH5#N(k*28NOLWUP?S=-k1(#A(Z(!uBu7S}lhza}r0>$6q81*T*O>49FLbU+r$+p_@ zBZRk#s4CfS{)mDDGMz{)4pOoCxu9n(p<6+JgSq+_>@ljcR8{~O@tw$_bnNU80>dW& zRv~+RzG(Y=hb8p(SWG=@7n_%$+cDLa=_=VaN6gcdVGlliXo3YDD4o_InL`KEN~JjF zj^N8XQlpANV?SnK%!}hRd4GL9t}T=WDQXkR7b$0jbmJ~b_jF|=9hWzV!fKE-+xxzZ z9VH$b)<+Hra_{okW1>_WK|R4BTQ0OyQE9N$ZwawnYZynZZj)xVK6z*If>A*Y*~W%P zQfI^;Q3{~={=p@NVBIeS1Cj2o>rAz9oyD8%cak8I>@^V#k4^wznUOcH0@fG1d_^WY ztPxF@8eHA;EcF7$ywbSt(yGU`)x{f+C#8{!=!aPA4j7Jt`|WCOk{n}0(mI;LLb5+` z;a9M!*`!aX$?8NQVYBwW&$ziW$1;Y;{m(19yNUEAV++ZSw&YudY+~+Xr*zisl+R|} zRkn)e>9D$NpdDuOEwZ}&J7du_xwpyUT6ipz!`DBWd3Hc!ZZ?Z+1HdVE1WFzj!3mA|vTccA|Cb?X$qmYjr6fRtv0it9l4OacJ?bLly0c2hZ)x7;lta z_5hvjgV?STgdd7qoGV2!V`WwPx~Nc*jBbQh8Rv$ z%c#>j_Jsr8|2&$#;hI~x>$%o0{Df_Dxie24gqwK?H8h_hJEHeC!ny;mhMH}pAyLv} z^!IuC~Xb z8fu$(<3Bq1My1pg0xWJ>0(82kDKh<`aUornh%QQ0fW%Gc>TlEQC<)EbV+?SAG-mRA zXHc|x!wfav=Ci^KE{PzFV#c&V^sC%-o)qVn)K5cDyMBcArHUY8Yt^Bg>rDE7FewgK zlsk2ST3t+Llyn~NvX~jFNLq~wH?Vjil+YWI=Fi1P``K#J!0A&RQZ-&+&hL$6eBa+2 z@5{$6G1mRw$F+SWWmHe8l2Q%EC+Bj1Q;8@e$b5g3kgt`iECWe~4`6_B08olb>NNWq zeQ$py@}4{ZZ^eiK?@l!LZ?T$xBw^v7#QdrsiCNUILY6-p zM&5#OumE*Q=ZBVW@71}IHDx}>7auc>R%I<2&3R65VE2X0c@lqVndw`J3wquA`f8-l ztMWusEYS4I6+fjP(3#61(tO;C1g;W{Q)Qger%-Hb!@052pK=%?f%StQ;is{>6VXa@ z6Rrw+khMe^UB`O5ls1R;sy3MU^d1Q9t~M`Vm8!>7eGuFF8+*52*9BK^5B!b9OLk`u zchI9+mdO{@EhDTV-%Wjb7y0^h7Q&=88ja@H`qDYPGu~Ku+grMdOj`6jc-RWoFfF}o zhzTgpViSUO!m~oWXs_QID6_PHB=l$jSzz^-me3kBV}AjPshVJ6|N7r=Y&==3#XIzX zt@cfCWgCdF5_oRFO#YLVmRJv#U~T`%N|%3RrQkP992Z_?G>XpWS13Ss?uSjkg~mFX zZBVp9UF{lq6>JkG{Jle~+#3xMF=AwM^l2G5N>_X_G+To7uL50^TQUZs&{FTJ zCf~QZHQM!8YL2#&@k~eiDfkn*nbw+q0(qu73je|VA)&E&x-%=;HtEnI>uAj$Alz~- zWQuk+i^G`@1B?(8Z4I_sqmmr9PR&FULNN7%bdr3N#E|?{loZC6efJZvy(2<);R_zz z9>pabkwdflR*WR^&!UJfoX7C{NE&_k>g$qU%Y8Y@$&=)Hgh=H8wpC9Xh7@f;pvyQ<+xYlg zejjtf#v9*||65gxxIogt>GLvMu#q2P0BF4@AosVV6ZF$E_~0;xE^vdP?Z829+&US9 z6zy<4J1ga^!P5WyKc>=KaI&gMw1d72ti2M=Z%;(g7tNK6!3VG5|1p)mp$i6Q)FxX( z`+0urk@#Pk-|iO#3vK(;TFKoE8uR1x{r>*gKj0&y0h`x#^v9k=%8kAT1lSArneTlr zQ!HY1-Sz0{jr-p6ai}Z$LjP)ReYdvzj@tS>@uL6dCp853-3j`}@!q?#HlJDthN;T) z+(xhK!CqaSzpmK!D~xj}mwbvUJcvqyfiL5SekJ7*fn~)@O|LQj{#3^#dkMIB;fn@r z#{tGkIs+9aAeV56&~hp5-xPO1t~J(UPua1+$pJE9DK7LTqeJoKkpF@thp#!!(}OW8 z)M%*fI)0Y?__363s;I6?b)C57I#$`IWoYfZ9NcPt&{J)DsbsVLfJ=YXA!_3Ju3|p$ zj-x4mHdXjwQbpCl2psjg*&+A&QdRNj2Fxc-i5Z&QIu~|$Pp_Rp8ff(1s^kM=_-L3f z(8*B9a8;&vbLHlZ8Mz;*dX6ztaDf)ZWRX%JuQg2tYF9OjcGr=glpurpJ=^$`y>FBj z$8$uZP&Di}kT456Bhfo9y#zLx z_?wsd$_?aay_|krmYJoEL^*CNwztxWZ5Q(P1>D^jj}G7Hvw~N; zjb?vRG|bY_F$)vWYrNW#M9+>=WDFTg7<5m3q=;cW(>EmpI%@IJ8^YY_v0Vwki6h{FA zxW%C%FI-*AkH(Quo0x3SRFUCcg=U46<(LH&!+AV}ZXzcTe(pcq+0@(>_#80$-zh@} z5B-nN6AH=HqlMbShNK!`hNcBWZqTEYjEMH9f(DV>6w92fOyk+th|!Y?Hpgf%S|d z`@0y8q|}`rG?j-&ET2P?n?aJd9;PjrpUc8pc_Xu$%SF_1Ztbn%<-R^~53d zSx>Zmh4I|!224YX!p_AUs3^DU;WSvllLpw0vO*feH{173WzxTabn#$C?ZAdL56RjO zDp9j@tCv-_bR-|WMNQGi-Wr&3>i>>Y8y}Uh?JCRrLjRZn4n_^ws{dG1EaxdrxYNLa zpA~xKKH?ubuwKz$FsLk-cak~{0JvMB=-XL_GLG9=#OqWqrfQl-&Gc5xtJ!Qoy1J@i z1}viBwY@YZeGrYEL#oCXSQ~39pxRI74oAPy05gSct}{Ur{ASaK>Yat%Glk=jx|+K0 zHQ|B*97vH=HV-Kw9j%zMmw3te%-)DV$7FQ#&@=10C#WS4R;QSuWL9uO_O-?TjU&xe zpS%LvX$l?6JToi3s&%Oymz=*7bXYqQ2ElXIX+}O~9 zOwU}bE&!7^f(l?fGyL#+tEm0AnHcj;lvM*ytVX3^N>SnoOL;y!Qaf-TSZecaO+rEgYO~E{|oA8 z1S}*;W7X&Oxv@ySISDuNntk{gs<*f?Nz56z%w;^Q&@<=U&hTy0nla?(9Z(Td$z{Yc zFWPU5^{4MQ{v#`Cgp3LO`<9-qpc_1gf?s!TF{>c2%MI&M?!Sb?}p}na(N$ zI4y&d@5>NpzmJvw7uzRcwgq4O;tV6~I;zYrRD24)oQZW=yVw1pj{>SpF2C8zvYdZp zA%QEph+>=$AWE7HR>mFJEM@?I4>#YluiX5z;{ITNskGH&PaVILng{|ZKj5}diNe_l z>E?Y!9+swQvnGplPzJlh39Cxpn+HENWar}$eHNf|#4!6LP{)U;dpHPw-s2&V4a{qY z1>c%7^_m%96c&+6ko-lv((e#;*%@$xd?`(tW(4>Cq&>Qe4ywvyx!mC~;!&fY1oB0T~q3!ZQ+@b^HVhGtSU{R+Ea`qGu91vS@DYmE<(!T2Smld#}tJ zoeKrFf&+p5K$>^LHh%8%oWy(vtD!&Q9^&)!OB~hG3u_0;-0IJF=Fb5Ud)AazldIh% zW7^1%deYl}Q!V|NR5}4YP|a0{(w6KOOSUzm%CvY&W}1hUX>*zQYGcZnq8~h?&O?t9 zRDc`%N|<(`G$xIz8tnZI`>mQPsf5Eq-H<&Dt9he6<&-9cR*TV~`7{v@6(tUglOF{w z&)${4pGp44C7$hGo-X+h*Tecw20nC(a=?M@z2q>>a^rmAR&|pPj=Ztomsi3CxN9Bi z+ELQp=?x-j9e(B~xLwIh^4mM7<-97R9j?uS-5q_OC*+p8J=~kX-)P4@&Kn^$;!~48 zy9e-vu7*8t*3n*aN&VhJ!ID{Qsy(>Lw4)d{YM8fegs`pR&wDR=*326Yhz)AT7t08P zA_GM>Y9cQj`HIQg3N9kaL1Zf}LC(e71p)J~S}8Rs?5QMbgz7U!=r{F&@#;2#V#u@b zTumGF&&P5^?TRiE;T>-VkID`e5pFD_`Qj@oOll;75;r$&lSkXmk!J$|Q*qKb79s*H_alO#5L zxU8S0eJV(!7Cl|3@Ktto3s8(gZ_)-+Ix;RX`|j2E%IR22rJS$w-B~A-B6l`@pN>;~ z2>TbI78t3858pXY^-Ng0=*9gU)Dyg3-S-P0{-fC}HBykv84*^=F#x9BR72EWc3|M< z8?$3y(@JKH5pp|+MmSo{ueS8$Av4J}7biw7>?c_ZviWfgghLlda^uGXLC4`ftpR~e z&mgwDju=o2BSF4Ajd)g3y%j9lw5jD1W7VNgu8w7*#>>kb!Y!V`^wl1Rz44pw>ZEMg zybg(E_mF$CNm;o4sh^?3z70*>ppka@a3d38+@%fdf`c! z^VgK14~5bh1{e;WI70T7Dq767;|$`2!@1!6YYi?(k>>gRbUlLE+C)t7W?Vkv5RFRZ z($0SQ#Nq6Ev!#;08VGqENO&t>^zvsCI1tK&E&h_)n<)e|=9Z27td|w;LlsBl~9@-VpNX?CrDS2AGyNf{%mJ(VmvU|H<=Q1ShVo8k`S0}jJ( zs2*)rQ&d>*jV@<2dP2XNn@~@6!}M`?;oT&;LfH+*S=w#8L2)9|$i+{v?_sQr?F3hC z)G!USFR*CnIBuIM3GkExDLryQT*Ls>;6$c#2l&g@C-v8o#|hW1RjNfc8sPm1L<{70On}Fa}q6)edW64 zR7Qa27cOf{sQX|movslrt z@jyUq8lW3cfwG1~|8XxtW~*O6C9Gk;bka&Z^W0g&>ezJr-qM{%PahYo2kS#px%k=t zC6V=(q*+qV2&=)BuXs+y>K0$N^}FB}xAG2$l~60nnGli(e65Vl_a%W{Lr`a@r75Oy zwW^8MUr1V~cQFR~g{Jtg3-o5o;5yV+_3YNaFB^{*V&|3AR?;U+lfNT*(I0jK1JrKz zm7O6cWwih$u|Jywc=#T|=PI_F)%YPA7TWiYDi`$+-Rus|*DYOP?OO;~-|n}GCAfpi zH=i4=CutJq$72)`ZQ1nD_(>o$b~FgH^MIy^YKS8}#_AHmM*g@odDd^njqn%y`J9*J!TfW8og z40-e9`HAW~p5SM1jPdjh1gmp-T5Vv=_H ztDA}Bw1`YwbfSNf+|lQf$QWA2CecHet&^_2vg1yM6V*Ym%N|WuAXA}8!H}MRpfaE& zGg%emuNTXBgEM6ORL+mw-oJQA6M`Er%~ZYIORSgH^=vALV&5CsmIxme?K;lui}lW? z>M!pMWxU1qTM4l!%?ZNu#6VJF$O0yg)oS;HUR&gxLu{gP>1oLzhU;or5r{;>4R41; z$Wec6Fpc?{C7xBNFEdBx5qXVL4mFh#avDqDqIkBErwG)A8;)9Crdw;lckGd-qwO<; zBmk3Zc>@ym(w0e>WPYzA?`Ns=1HLH#uLuI2$dYv)VydvV6Yg^F-|F=qFuD96B&fnS zy_!fPss#kPrEO4bV3e2k)dkoY|2wu*?r#z$vcW)^67J-?%=io4gJKYl2=+ z!D{OzbX;=Cl=%!aiw_V;OjZd`BcrBs1HJTfip4-r zLDI#e4~`-?kVm53M&MRup=<$1pz~h5#Gu8Vm2xz?bS8`xkLD?bX=BJRO>3LOemM$8 z{HoLG>AQ5VGs!SMRn67?tu#DfuK2mjj(@7|k9i5#yS}k@_B4^WteQLG(R7FCJ&~HE zT*hNVUF#QC3_lIVogmYZDTmI;FCvdAZ$a1X%rgyT;Hb{U+yNwrsEZx`J9d~;WQ7W` zxoM^GHBDg4A7P6i(I67pn3IKK0KQ!@TLFu%RQg64dWtFox$`LYf+h_saZQ^)I-c=% zmkYG~<{m6Mv|Eo5$wjs&HaHxYm3?oSqATm-92(Vl5AEph#{FU(GtonW-!B8vg26Hz z2}I6W5~xL^aR?-rVb-4Hzfe-ULBE-n4@hR4TKpiN>-nWlezlODRg^c8S)8b7Cq1Of z&R<)pIhdoM)IPLJEoq(*&`rJq)Du6<8;+uJ*RU<2aoeJDtN9MN02~!UJV&%|X)9{H zMo?q7VURUrsig$}Ex-zPkLvn+WxL{(Uft2^wbg@TR%Lu&%uaf>`F5P^)_LKn36>Ix z>r9>EMWUJ9MU^s_tqqF~sLNHL@JO*uZ;p;f~9R9CULf#)|oOl$#Q6J;SFC=Jdl1oT@K7oS|w`EiS zU{_a1ztc|~7`wzn-cQfbFIuq)Y+aC61N+hXWF~CT1qQanwc6yf1`Y$%E|K?c{x1P1 z$tH|JOcspxD!=YcW5WsX`x1{^Jo?1~c{)YOGxgoST@7o%aRvwf|Q*_1)h4?tSwA%%(QB{93+4 zS{tWBQhEC7(o*O&FUUHE1vUCjr0kSgbGhz_DKe_4rhd78R2+e*niTg8}WbX z)cGo)TNk`hU+^fvsIg~%{T3vWVFkcK2AC6mIp}^I&lIq@00)<38WxxeA95=`e>VAd zurS2Sp*(!Co(#y|6?N_F5xU<%;p~TUh}N)|!?fby%Xl1MQdx5kpynIR7y1zjCzTv_ z@1^W(8Nh!7syiZ+^y|T}{)Vx3;2XvY{oafI8teVV%-K+k6Y zI;OvI#su3M?n3!_x>|JEGdFvi3>5bvPfgniMM_8nAd9FadAap>V&}aEY#p+CzmTPG zA9R!muCp^4oGfa#`H?{*1v2RkYZ^NUzN1ja#AkU+q03M{vdD})ORadOr3w0f90Jka zdz7MI!o)Faqql;e)Rt_3$C7YZSO471;{w}Z=xU{Y_t{LCa3+$66PxxHxPjZ0FU}VO zvSYprF$j=T?W09`Gd9YYxO1V?;3MBL{wD_8yKZnhI~||`SDFIrl0Q9dg@CvV=}}xr z0y}JL2~WYZ!+fIhrk8E>SgMlbKu^!91UPvH79t`HC$O*A)U6golk@cD>VP}}gar7X z1PuA>;$H%GVs+F&Tg9XM`jdb`1au}Ugjv_W=0emT{RCjuiFe4)G4C&9^0Wv@ogwj{ z0tr_%la8E9?jj7p^z1%#p$qo8<#^J=v2hVY2|)ItwpnP+o0>4cWP?suTgQ^Ix4A3Y z{+od1(6iP31_!yN*s_gnmdy7$K8csBR*nt!f9R%VCDIT5+X_dI#gPBs=Nw8NT=}W%(BF77n#&i5l0TX8$N!UN|6i=6DZ}gL-bZ=!n5W*DIYt@U<=Iq z-|SRB>ARd(=z>Mca{8@gs`#)^r0{f9@&@48u3)>h*C_d^w`r+&YS#XSq<5*NbE$Ma z@6T|nd9*!(dGHvs%7ZQb2tj-7V9*|sLFJkVim=QW>s2qdhGsTN+5(3j$c2yjyGOI22ZtJoJq1@pd zeG9mkK@~XgsbTG`5rb|NyyG_QYjtPpl$5XM#8BzNP!Ws8a_yoBgRZr1b8t;#aJ3)6 zCcOaa#}~Pb(N(cF&PbbHeo7ozyL5C{-d8NQnJlU?9M;c?ji#=$H~?onU6lJ&3B{N z3Rn((QQpj$8m(vooMpMm??j#t&B)gn0d-7-BaWb@rTkDfjr?H{DdxoTQQ4PW-GInC zDcB+NvtO|4S&f)B+hpD~$9+QM$>XUqhF$rH{KsR8!=sidPz8kh_aV}+`U^rZs|ga0s;to9?+iFtTa=EL`tc<2{)R;=y}vQ- z`r+4J0WFrCZQi0VIhYZ42`_MRwy(J7Y3l!!M2l(g3i)+o0=LQ=lWL0@l=jqUX0~}9OTO1^ZXI0t zT;a;g1vbwc$C-uelD`(@5#iYobiIs9?95WfCQ{pLJ7X2gRI%yvkRA|OfAIC`I(Ek%M!03hW8XZ}eHv+iz|M182=Z5}& zZ};GNtN-7|lk=h)4R}KqRl3Z*Ua#X+dobmU)O!%qSR=|h(IPO1SuW^{A3-SaQ zF2<8!Nkd@8{ombt_RP5d&vu`+_kSx-k+hx2J^zO7x#H=d8Uts<{O0Ds^J3H0?1H`7 zc-Z;awn1U8sR5^H7$3=0Yc#(4i_U!1YOe7ibtd5d_G9cDQ_y~^o`j_fZ5o@lEVe{q zyN?6^r$c|VqUQ&DD*QhVp6?j(-@7kf9PG9De;bd1R%p+8LXw_=@aY{U8v(iLcb0lH zj{;xXgu#f%1s3{NHIqE5oT=dRw+u6^Mpkm2b&gh-F})aGawV-bS2+!pu7NtGi-_rS zdKmEf9fo1cIAx1{GGWEJ41Hlwq--XWOV$-Xa{Gt%o#>mtG~1NDMze+X+ij2z^JxGD zlAodmSN?H_bf&xdI?Lu|{61iAprx;`L--^79bnUSLQwtD>{EMZ>Cgpz%R94s+b89t zG~3RSv1&l6u>bmRX2@wQ7mU$$ws|{$3{tslSk7%V zI@sk$yM&W)^8=NPm5!rK#H3-ZmRvT4*g!Tcbd6wNuQz(uGrc;W%#Fyya9N))l+O7fQB83$atq zMwJlVM4PjmZon-7kCFs4UaN$uB` zJ_J(wC`ip_wc#TT*>Mn|yuyR0;lWag!fFT0n3i!o^tUW`p}-OvJN}UkBsDZqRa(H0 z?&@cK9QI$nH>;a~tNecsc1{1kor9e=|MylN1CxmO39y9;9$X>- z6Cj1$8VQXHK~>-XX%dH+QhQVPe;4lkZXy0-Z>PQg+jtbs;$yFW?9com&~VH{ z+0P3hWc}|k#Vn9bgL$i7Kct(8kB`ZYPVI^29sLX z4U#)P*p|tjIc!S?mn4JYtZbDWirsslWKmAv(lMx;a$;ek zV`=o;4gsaQoJwA^Efdm`;ah^bBtbQfkTVI`y2+}smk*V^n$!I2klDI-`O_e`O;AHi zc3ZMrkL;FP037=NTUJRBMqjZAe1-k*V1IYt)c+ssxA|YT@-$LoV6a1m|4f5PNHuP3 zzGFYhbHj_@9ILgbEu5PYvC!j(E-;9j#Z?Qd+|H61PXD22mO$5Q$|qAGu_iWXW~nor zuQyRGzF^<0Q9QmrI$yG)yaEUj*l^ep-rQZWS$$;(%OX0go_MgzU#xC;zY+xUvj?C4 z(!Jds!r9s7FO!)}hKRi!Uz{GjJ?%dAx<8(u@PD10zC4A0{mPN4aO$H`wJ@1qIccKm z@9gPH*ZMI|zgU0CsJ*n3gZk=an|Sdhu_I>E>Z}(gJr2K~vUEIm;!+z`s0iQ)MHTE= z%Jua6ntWru*KqqfvP#({rlB6g&j%gL2`L6AeJTgV7FK0DFI+17s~wi&@;7s4OtEM~ zv_^O2ZOP3iNpAE_{8SK$=|lc`5gmQ?o53NTckPGKA`L7mE^$A!FFtke&D9@={3kU3 zYUTJ%6r1w=hmWyB(p8B+C{-Dr<|YdsDU3vT2O~ zmeNkfoJnTw#9xeNI>O)U50D0NaQ97cEvr2#KU5CGV7L6q`^?FD?WYF)U%3u&h5z^N zi`^ZQ{y#rBXzBkpo@V;rjnw~rfb_W($!)(buo!uX`oMY9&D065y^8rD!m^P0n2^U~VGW*Og}1Jn=ZaP3De??fpr|c?+I6!vZlxQ)tTWhlXp^DMAP&qFD-tFz1#$T zG{5EIUt=VSpxtG@!z+wh@hwizAk>ml6D*4>K8;uU3BI1Y1Q%rFYI< zepU1ye41rg8`ey%eSE0zC2FVE8-CgGiWo&dl{z49=JVNifk6++Ite2GUK%R)cC>G1K^hVxk()8ZQ%W_1k5GL!2g$ao(3aJe%^3|uo0+j2 z#J!!a3XE!>K+iX7m87(B@P7WUJ9iTDELe+8Q0ya_g=A)X@K~TnDl$|J(k) zng3(|;Kj36|GSN+x&8M+m57vQbZey|*J|D^sV?aPb%QFC&AM^Lc{zJ(R&}yzSB6z^ zJNoL+$9h-;|8p<94d#C<)c@Um@w~PFZRM%P|BvHjZk3`8C!i-L_E%zd$>r~_W+YsP z6Ax>+Mq6T2%vJ0Dub2n8%KvY7zmWfNcfa-j+sf0({=bS@sC5fI_b`}@xbo@(yk3gvWBC2cCAmpL0t<_RiJrYsAxshxK))~j>TpMGNG&*Z63 z|Ci4LU8VoodA?`R|7QogE&boh(_H_v%@omfoPHh-@8IC_H=8=T%$4cmi52bhi97}T ze{p(r^6Iod9j|W;H~!y$w*SJY|FV0qf6&%{*~;_CJLM;Ut7)=M=kK%s{(Cr`cv(97 zx{D4I+2LT2`geU+By$01hFsnd`zO;u;RqFenEGKn@Ux6wW=StfCh&jAr}k&@qzlMw zJiqz6ySuaVTNkiYH2=DQfxG|x_rdJHJDpz!gI^E5N8V$3PCZ^t6d38@y*EkbKmhvQ z$s6zWo44NS$=TcflTPP9etAnGk3S~OW z7+)vp)MtsT{%1D7kAknSfz=Jn`l?fk%#towteX8h@l|FdBz{VqrEv3y9Qv zS7y&whx#g4pW`F%7|=p8^)7@@OXr(=VS9e6%@D>Z9q;(!B*U-6%p3W!Hw-+P*lWxd zcg5S{mscM7iS-FcKgMARm=>`Ls3I`DJVe2OOWxAD?zgzAWI9DwFb$^3ElAa3nEYsY zQW*kovn&~fbo1m^F}PqKtdMP{ZXjD5V_G_$KfNCU^oYQl2LCzXrhWWZHcCS>40(Tc z{_Nqy{$Kn@`xpHMy(vx>36<}Ie_Z|X;R^nP-FQZpz=of5KKD;=m?WrWxI!->{P=Pf zjKXWwLEPO0u-Me|Jtbs1-}6-28afQrVD&h9q+Cy&gr^__b))?2ys zHT%;;*FgOEmtUP98@^4ATGeYHG>LC+gES4txG&ipQz&AyZnvzN5{RJepuRm6xzzv9TA6*2T`5D>R_&TfiALCsc5s)|#DNzfR`oX^_EAR&;@=J;OY5Mi-Nt z5rtJ(;=YRh=l-P0lGK=!I{Rt!J;f}M)amoBziue;xYf#<4(Ail| z&ndk^Y5G1{c)%q=-w7dvJi{m4&IC~^kc0CynIgVe(9LDp4(XinA?wV>4yRYV1F=N< zDj&nr?-EzZaJZ|3NQ_{vy4dVI8JF~CIuPhxcKKd)4{3{@c2%E;?%^&CiJj-(O&)V^ z@_NKjO)+wL9L%8!0yB_Y(tAk`@oJ5eQHEtpN5Ks46=H`d@yFQ!CYTNKzOzBeDr8dB znlLm%Q!GbPkS1#f1<$hLej`xCcisp;B-YDHsi>H21LBC4eThH7fAG4mx$m%--6V@> zTtyyBf)t7?IpS|{J7ptOnh&k_z~=3(UawuE652=Xc47Z`Dx$zja<$-1+2L;49;Ly* z7r`QsF%8}zs&o`$z!6ikBCY~)8Q<$(oz z*XeJhmd6^W$?TV%U-iv7dik<+cg)_J-CMJ@a96)blKHo=zU&?-=XBZ57V%N`I*GBf zRl4{QNRE1dc1r2C*&O~x$pWs_H7uq-XEK2TS>Vku;S-k<96&Brf!3urc+Mqv!278) zlnfj#0`N$@%WS>Fpznhiphogm9#@Ii3_qXQ37}mOUr#_WXHXCAI`r5@;GW`JkH20S zy0M*7q0maNIH-z{MMkXeon3qA#*_t2Hs!Da!5o3~6aYeG{xL}>I z?onUO^19sIZLQU`f=A=>sLecZiEj4FmiQ_Z_tXK5PJGZj+;Pco08g*N(p}k6dxEGLmaySPN$7~TNp4awu1$; zL&*;*>V}BF;2oF>+kVMF>@9&}nNd_w7KS)qWH-$hfUS&4;|Fgjts+SgHBeV<9tED3 zF>$I_)~Zh##~I7XXz3uI@fCdbhH?H^*vYuiiB06^;QuyEGe+d}4p|dhe+ZQrZafqI zB%UbnIed3YE)+_wX@IzfI`eX#O%s%T;-Q83%A`_`clu&BZXFYSaGaAmE6#Ikp6Klx z>fF`7S{YTXeX6T&GK0BF7SBIJh6eyj9OZo|h`a`k%6xDI zSE08+oQHbIfR6Iie^2U#sV9a7IgBtQ+`sse1_r?|%jg9|jfa#?1Ek@j*(|z8)S2hj z%}~(+;sVf25RqYxNNjEZz02;1yu!SgLz0J-6D=Hl#05a2q1Winzt6}fV|Lz0p`4eF z^$#Uot%S z37~x+^%vpwbwJdbx)lup>_Qdt6jt*dKg@7qC?6w>v>1kP9+=$)rMU0H`S*)qZi-0| zCm>d5-NGc;pRl5gkCMVR=5`ZWt1<{{2WJH4%lC2_ZRpz7pDukTLSC*{GMD(PSR_C5 z+zcYqZz$`lRE;V&Av<*ie(0&RI?-OuCaFK>ly-iTCX309!t$}fVc*8UenjkEl+lH! zMKcx=2EZhEd3i4$-852|!MP1cc!BA}BZg}Lku6d@BTR)x>dqt%yR$#9aZ^Z4NSYDruP$7?N;h?n=5az1u%e2mbQWMo^davBS7zN zK~xOxaAmD8FcWaOv${e|D6k36MKb6NldzsVURc0nMEl+;?kKVr%(^~_84d}iwwaX4 zHw`Ahs!`M&)+zba7<7g*P|cNYN3~9)aOA-oWeu&}43IQD+~P@iD-|)KLsGt@Rt8~E zHjxS?d8KyylUHX`Er7AC0bseKW!ezr^pY6Z=v3%n#;8vu?O~eShA7J^mG0zN7vCHm z+sN4~*iqad2MCS=FGl+B^e)D zf+iS+Tv_42qK3brN`EyS{xVAYrds;7spYL9Iy$pUSB&(l;tP@=bL@~UX2{F{Jn&Mp39b2$(Y}BCf@GThCby};<43>TzVp4Ih@ZPYs_(r8$N$`ndA0ZJPVWlTk zcv8hBM-5QROkM_aRfmb2NxEf*ao)kZ;5z(GTx+=EG<5l*L#wg=*$&ezNK<|;m^r3i ztVL?#PA2q;0-+r9uv1CeG#ti=yk1=s;H?}LImM0@St#{ zh*N!awY z*#T8q%&@amjQ3@RJ@7f8?v5mZ;k~{9xPiGqWG+o-WMGA%m`@pO3uSDq1c+-qe4TwE zCwax~S`d%Ed$dxn;#d%+k)=}-iAcUe-+rcJtpvp)gFgpKcLVp-WPuj#oPPD<`Ob~T zijucjh6G=>cpUa&;Zb-U;MI5{cnbwSHRcNh5Df>TVBpWf9{u#FSgonAbc)x~djp5% zKJZgKEL%!C_h}bHOX0;CHH5z@sl;J-df#Jxb?K~p%ghnl zvEb|6*M|9np7Y1Bkn)6sassHc) z{9km!n1!i+V+A8jqe-N(@iXxni~Nvur!F&R$|tldDbtNRk~;%KI|@{^$dDPs`?R0e zKFNpv_||8i`g3!ck|>lP%PK`b?u`ysCaSXO2yF(AJ6wcl6^ezk0%GwDum?)73FpwY zo*r}N21d_ zfeyDOa+#Q+!&SpwYGp~6jbcXc3O>Z`df>|BTkrFVFSRO_IzIRoUUlv8y_MB)bGD%% z`7(8$Q798T^-v?ibkN#VYWhA{ihZ~xK;YBFaUkmjn<$#j)GlCBu)q4zSc8GQ*j+QT zv)*=%=4ZX*jhLZJtHU^tWDy%%v|~D7UTi{=yn>49#FAK`j8xy^TPJ_gQkLJUls#Lr z06Q}PEn^9m>9QMK=sE`9l6p-|4Zn`$px!5704`Q}ss>j>gRqv6O3~r(9qb6qz_#7w zk=SKIU~Ap1Y8RG80k&eRtSC~_JpRX3=3%M8pS(l2F|$}qq2j1~^2W{bl$Uj}gs{8o zovmg7EbFMDA+W5Qnzwm1!(eGIH4KE#whlvKS-YhThBa~+t!%<78)M_9EO+j#wVJeQ zs>h5+(!ECkDa||^`{`2@SvFGvwasIcmAhm2RkpQ{_nG$=Q}$G z`1|hjXV2RD4_kSduRCSqQ>);3e^Aj@rPPb}%dZ_*6&3bg7Oi0&Xb}!9<(v$25Gnf~ zdA;76;}~SmW;}y@v5B|_*?FD#2KjM~I0sP>$PyO9A~ZT3mEAn_b~_z{>O<};*KvqQB^076HJY2fwMIv7rPC?MH5=n;`id03^a;a0D6E!NTOS&5^p z*{vGqD0|Bthh;BnI!=KvMPMmIRa|@!AS)DYMx?8%a%h`Og)RM9aPL=kbeY)Ujv9|l zv+w9YS$h}>^uKfq(a>IrsG$}GIT8A6HN!J8N<*i zgiL4yts}O(qeqaJ^uONx1$fptR>`{}o{P)1lBhjcUtvoThn%T-Aa2=4^#>qy9bMay zgLx@si6qQAQD0f#gLGZ=VRT(vS!Lx7sE-DUnvUlwN*}e8n)(>}e9bx;ne`nh1KJE6 zyV%%7U~VbZwa~(l7*|z#YE}`oE=<#gy`}Lc^t;+R0^0_EGHju3IBJ!7zSckL3vC84-bwJ?7A&el1A>N}nGpvX}twLk_PX3}*wN1_JMwcki%Z&AXiI zeg~-g9jeL+8ovs_F;7jDK>kaI`Ts_s|IG?8=mh(4?ufac9e%YA5z5S^gJE)3JPbX7 z6t+iUch>Bkq-&?-rP8idnIn>AzC}D`am=FcOuo2NFk5s?t3}6cwCHFy3r5__TwXes z>g`g;u}ycQj>SVtV<80f*Na25V`Wxn7UqI_DT+FZcc$EWZasC%WNzQz5_zm~q!0FE z#t^|K9Zb6=UDkI}#4Bfh%q8c7{iOhh2WElstl1Kn4TeGRB!v5vM@5zI?7F;;(b`aa zUmUlQ-!Ret!g=*PX=hsA(&V%?t;5=++MAkKoOG*=S4ca>$z8!l;1%-RnZ~XP*TRm# z>*SA!XKeivegRDswL+`vg$hHgQ8#4M4lSb}vT2Bx(h=FTM2+=Co6!_0x+05v0!LFk zWXEK6R*KN!eXTD}hj+MIv<~lN$(S7*$EKg`m19+Te`|*>nsjM0oS#Mg6<0E;uG8$BX&+{fs31+mGuUVl{5e+JT z=Ex%t3RPjSdhqO8plTs9g0LN{p1I|$Th6*J zXZ^7mYijtg`07uEv2HozmNQgs9(k&uL#A{jp9(MfJNc) zi`|z2l=IV5{QvO$bddeOE-!}Tv+?QZ^mK4OdNCM|ho@&R$mtW{QYvv6(SVQ_OKvTg z!)n`Ys{fM~R^W z{-5)o`ut}Wgxqr{WHsth-%o!I%x}!mpl36mxi)hx&caF0AeQIaJQ7W&JbIu3)ES|D z4RX2jlfcaj?BQID_h-dN1@$r0N1t#~7OEPJpOoq^BmBDRj zjsdmM3b-$kd9At;*^MlzOXqCK+=$G)fP5cMp_)Z3>@7URYY|0$h{N(|5l>CaTb4&I zKIm}^htgdG`e4fLG0Y39A{eb5q~j&!?lBERQ5kxMVha4vfK9Jsc~7f1wuPG5GCF$USo$?k+95^45Q!<1<7( z;hU_u@5x`Kfupq#k3nD@Zc*ewFX4_7oX;)W`?9&z=zqtv?sqoE2K_%c0b^g%|AW2$ ze~waA?oY3>`J9E(goFz^Iz5}r&Ia}=8(U}89-oY6);XKm(}7LxlaurFF`ZHR@+BLL zruNGbn|@=Tjz;5?^U=%E%h@^nn6loSfmWjtvnQlK8jQxq;LI2e-VXg>{Z95gB5N-u58QEx%K!mr4PG*d zeL{(BatAhu^}wmWa)5s<$UFrj6?$<1*d3tP&puE-3RM!M*eoOfadi-9FNE6 z`Sm{cSr#nj<54vGRcqhbPP?;lLU7VRS(0Vji+&7!bXCm}AlG$J6U4KN%V7Bj3} zhc9^~RZq0wAvpl`fh2kL?hf0c5(#}~fzG&|fyQwd4HfM$2mm|nP*P7mFoE->n8f6wJ!exK6LLr(=B=ca?5pw2 zJ?w~_A8t=5&#KQ+b~Bql(>Q^SeoHNZgYht=dR_% zcEc1+i9|!g5Ex^DL-AG(WM?O+fIFpOqbt5S9(#A-(@H= za%vmXwFIOk=8gp`p32Ju_%Vs>S%R7pbv4t-`!Bk5(rHx6S3SXv2R2=J-u;skJ{f4w zfJ(X;O9soy%CCUO6SQKw68?nrRmc9bOwVFLWT1fxJjY?d)5}?Lz`eXR(x?gy0 zliciL4uvtcn@j4I6*q06TC&u#ych!(9=d0(WKDFul>Oe-Z8q}FOiN->*!msRQzYHV zn1^*h-RzVzuB!&$SAXkdl9rccE7D@O ztGZsTDO@xKEx~sucn5g3TT{S&i8MrV^Cj4FMdTx;n=oJj6q4aqN@fmSd2!HYgC?Nm z$t)h33Whey>CSDUH*d0CnlvN_>QO}J;F=`S1mQoWUdv%|gc3FLgKaa?2EyKAZZyDX z4VZo3VJO@I1FEtWbID5Z4`@!KG|r*pr)_8(2=J1)gedZ2g!wuo{SbT-cMg*i!w}I# zHi~>lKQ+aflMfM55E3F~+a9RKzbjAWu+*(Y0V6|#C=OiQS~Gzi2-uH4bMF>>77-rG z@Hi00!f+YR9E0b*pF*JiL`qDpDd1rO32h{f*+L$(ow8DSMSVKu4v#pjsmq&d#pBTY zjv_Ug6$d<8n;!HIvA6J^hbas(L!&^0DtfpggCX>qgn6ZiIi(l}Q7HpI@K)T$^hv&z zW^^r8q)^=Dd-chI&8;Y%NAf(ifO%y4mTvLoVN251jI8PKCAFy!T-GB@E=XzAEJG9m z8o{~aO{q9xi7oQ_ShENIQ^Wi}er50S3Bu29?H< zhd|q|2sP&6VKP;m?D5y+mMy(ib{(qyn~q=$R_pd<#$6C^$)nQa{w#bGc(LCn{UCNP z!=FObP4aJ5VdUTf(OoYp2?6|m%iZ|HkK$ZjnCa9FojjQ0;CfY-f7h*F{JVN2bz-rf zXvk9E&z+`uveJrjx-VX(;^9%gBk1J_a@J8w$z+mCi^ zEIn9wVf2ng4_R!u84TXqKk z@*b+KLB$!|5-zwr1mi9=KQ%kc%EGJdtD1;2w;MXvDzHqRK;+vT=j!%VSjJc?aKi`9 z#9;NWl(Q35&h@QE?>J+S-hJ0F!6RD>WxTncwB zzI9zP*w-}KdM@>A$Oq*q_Bjp>Lw#OGb}UsjDf$LD)mh@t9lhPYbcp}^o^A6mh($hT z8ryT$G7+%p{*Tk~s1W}@8;#HR@&D&2t>gdo5vo^-P<$(eLd8BFpEB^pemqSY+>{5| zZT7(M?dcybgPuw-1j;*z9l3oo2uxHQpHTxCqz_LJvMbN0$(i;= zWns$Tp}UYOka~zZ6fO6Z1OkKrj0q?ntWe$c>#v>fupCtys-Ca>;Br z5haw*L{7`|0-L*S_%B{u*oaqw1l710hOvdF_!b_36#gj`2B3S(W(ZT$zG1e|s;m}w zF}E%D)X#??aK@kT#Q7(K^kzti!+A}Q(aPX)?5JC)72zA5kC_1N71PrBsJ zI(srA|17sfZ|c?*EGYEjIt7ycZW@M*REHu!I{i__xJk0o*qH4rvLT!9D<>o)ys$Nr z+0JY-vY4LC2OxGAZ5VGEZRoE5)mwZW%)lo7KN=SG|LJhQ|9_sct^Timx$^OmfTH@> zeqJ{#(8VkLV+DORsOD3MIhu>qZ~k;|vtg*v$sLBHomq%_Xqi?|(fX zqW{0Y|Mlt1CjL_^pyK+^2v55|?z<4p_J4FTJ}bWeH99}vzyI|trTIu?{yna8&^i-z z6JhFG6$*TngsF3eyV6qRO%EO`Em@d)lTu~RawqZg=T$vd-ItW?Q(HJGjcurHU%S5w z_q^i$Az}8Hs;Ri)1)CZcHD-agEZ_5@uj4y@?5XMkAu`_k99A!0H#3d7V@qsuSF@j* zgMvp>alrN%UwHOhApL~o0;19-%PWh}RClv`LG@`}y(^u|VCRO`%2SiL;l-YFFW~7B zIioOoCS-Vdb$cl)-X|3p6aT)V@+~}*SD`z8+Pg0m~NggP~^u3l~J9D71vQGF4JC2k}6D#Q+CXw=Zy14?J2Q z=7)ZdceyH@1rKaudk?O>=9Oi>Z$RXkdU;=piGpg1_IYsEE&vM^D7*|qUaer)%t(@4 zPRQ)_a-i-Q161%1vWm~r2(F+hKAt+>RDL-I8y{a@zA}EijH89Qv@_uR0PqPSUOai5 zQRlhm&B7uCCb>^T%~4+bp=1_sxe)RvZ~Os5040HWzyo!SHY#J{iPVBw0)8jHFA?Ip ziXEFsEgb<2%bUCWV*)+Yd=mZ%$c?K$_#=+KAECZ4!Cule0K#!e>}DX!yIab*BsYNP z7@^G_Uj7#2(a~d}{rEISb#-i`upEbcZqUG5aJ&pfFwEzMn2alo0`TaIBv)1#SO(_g zl`pv}p}{&b3l$qmBUJ$9WK*8tBP8SP>$~^qb?Jg{l0|9L3JPg%A!UJ3;w}{Ei3UwT z)#+7v8?3|8PKWVy$s-ht-+<~7GO`T#O4xm&PDCouE;oS%cLi$Exk7{a+`JQ4zZ=Mq z*4!(;g`DpoiJhy;zFpgv-Fanx2N04qs_vxM-$)TGk@~Yjp<`j@+|<1=?}*cvmuQ1X zJuJWnCP8WvQ16%75VGozYqip1UwA7FH?W5S*gBPl1raSjZSI3b-I{W(Y(;gW0{wr; z_dyDT%4(`AlGGJxC~TN$TP9jNjIn6bc3sj7wMbvjUI?q0lD(3c!_GLC45BDme#FkV~yvD~v-O;J0A4NTPqXNvFS zsp$d!f%xJI{*X*a%=K3x`2{V@FY?Z(%(67e9e&(EUnUwRKACKYW_!w7p`-kBW*>JYu0s7y{*Y- znRnkyHM#E(A%6RNaLGO=BC3Qt6fYa_PF- zFBRZ~I5NQZ3k>)RELX~x!pK!$=Uo*^D3Jef9TYJ-W& zu7xd3RqM&MHc?##_K#+owlzyFDZ1H+V3FCQ?abANCXLn1UGczk@ovla*sh|#BJ70R z#8Zb`SB@7~MU>iz#q0cN1r?@42LL~dR}!ZVRUi|!O(l5Cb6uFExH;doD^QV-7hR7Cbwd0&DkI=2H$`3No`Kg7 z!WxM((bwb=6^$~~3C+3p#oOWOs1msh%Z|uTcW*FeE4ryiR}1b^_4gYVEU8<^UgpNj zYEd>e2nMz&4PDbN#iyo0Gm?!uIwl5;>`1=AQAE# zx2E8t_#S)LNyvQkBWIvKj3}(TNQ7!fA)9G9k_cm7_!yJKx>D?%Gl|#g)u1jPOYYP! z=2ub6ie#}EOS)A>DC___JI!oy(uevgiiw|4G7|4TQsoKRas2! zCLEJ&s&O6CQ6|f^k@pMMK*kueoHy4$z`qlC^V?!Y)X;bD(fg_R>}n+?gGUsVQ4_T z-sTztX2s*0rCVb(D;}et3?q`vjdK{67k6!DpT*OPTedLZALFYN*34(D%e+~xiM!@=nMy!igdcs$y_|Mx5< zcWH6?5a?n0w0z^|Yb6vi@L6&3|Ng+}{=jJCfze9s((172qfUqx#u3kRuhHivTGXc} zMJwBs4vbb$N!rtjbEEnwSbA8r5FB;Q1B$$=?2Pvy~+m;RntfYir5^_AG&pbLiwm#ZW} z_}~9=@OKmYU0n2U@k-YI;s2;s6(d7^^Kkks?i6&>wnuR*#YlfiP4-Q8P}RbOr!liG z?EbiCQufC^_s2c|FCF)+R2I1-p7Q&Pq1g4Jf)f#>%5FspHszf1cHxJbd6m$`sHG-C za;89mB3gUNg9Fl&tO~bn%7s;alBdulV+uDX)^>4PvG{$T&x=oUa6ZS|cQrYs#ynCp zPm`ocHYuXJ)_YnVh){N0T1^3$TVh-D7;G<=bql0~$tzqO+2yMf3?9Ch5mXKEfJrQ!A%NQ-^gHSAO@}(cSEW&hgO~*TOmmfgu91`ng0&I|8`i7b$w2(T|PWu zOD|#@&I)u*E#7LNg#?ZqOi8?$k0Q?oc=FWz|FZY5%WWK4qA=RO{S*~&Oh}F(0LfOn z`zX$wy=hW*vnAOKl9G1E#DtjuiexnlRoGPkDZ0mx^}WFNWM{3Fm&z*CWhGD`p>}4( zOv^-8URGwV`$c{BT(MANwZVt+X!H%va1}16H|;h;zROr4ww`MhUdI=fJ?>ckgYkg{ z)ep)MS=E*m))E4}hRzY2jX~u$WUrBoL`gJFXWjm14)*$4D66Dw0NtN~eclqZdiGra z_7J!vR>vQJCHwxBL)Q;y?^wNA0CG4hmh)r@;BUhREsh~BBPSo_5~;D*0mhEZFjke} zeZpU>W}Q@qrCr`Cm7xiVA)y`;62x^rmW+(#?-v?bD>8ooC^63?OtGA*;=X8){t*W_ zphb-I(<^5V~cMN zP%oLU7MO*qHRQ&5Pj~gIfsMDM(S7ZXcC`(jI}F|lc*?DPn0}t}CA{rIDsC*txgNB{ zaUt>nyd(Js#eyjXs*KU;;yg%YgU}zzz~`tmE^%)~cn)s)Tv`6!f6FKs!5ttciAWS(iGA8K-9D7Rx&9HFLtCIu{eAKJk#LZ=7x(2-=6q=NtYZ21$iF|Ooq=o-`xWhBJNI*S4o;sK zYX+zAf_inNtC?=Sc0h5fu1MpXvKQ@^Wzp9`xaXMw{)1J>HhFs&Ub zXNEs`bC3c)!ynN}fujR$c__zf9ONH#e7k)60y#DFj3ql~2_PJWXi&<9fZ>if5(=>< zDCocr=93!N46Pd3b)g3+B8Y%|h4pUZo!VC(MxyMV(~cNcHzcHGI5l(u57_Nka>WY~ zWeUQW^davS5wtVy8#U-G4JH4lq`pEp7#VI95nIil@jtvK)N4WmuL<>NZ+P&2iR~CGPh7(hT99yw9R#$HUo-`l_L| zztUUMe_Snrd$|sm+Ld@-xc{ntn#bvw<-OK4oT+JwOQh2>>lk0OS%S<#@$QR79O;aN zv3LkGt#}EZUqx9?!Jx6om+dN1R^AR5{eU2J+L8*Il#KTaxUzMg)l_QponEcynWGm+#V#2^7i zT7^pq;oLIpTH|RQm!5l1o|s-vzwgG8H|a`JwPP0`+jk|`wozk;?-)j!m8Y_}g=WoF zXc(M^m^J4#FE_ZS(m4e#$~2u%R8?$AqO}187DhZH`WER)QhLZ8qg$FJ%NE+TrcapU zEUyJr;iphtTU1hqbSKulsCYf-vLQ0VG^*(kPsz=;4z+)NRGYX+bxq)1kZPKDLGmt0 z-UX?vuXjN*&AT8ykqc4}PC+W;gHGzu>>H#=*~=zlCHIb>l_%8ZYcZ#Ur+B{698-i| z(UaC*;L>`FEMOq6F%_TDZ`oI2(WT`2DB@@)XTZ>NIqD$E2M57ml@EgF@QMci@Bfnz zzJWi?>Cg24=J@|^294vsm+8;*kThMtg;{DjMZqgpRhJ{!U^1;(o?kXb6?R_MawZU# zU)RpDDF=skVNMr(xpOSJ32tPenJzro7xrT;hLicc1;2ITp?1xiMlOw$)AIo^C})%4 zm;0pUk!5M*W9aCegPL!_h$zKt;bn+#jDG9L8&U0Zaqy%e^MwH!z^ge z5uqFB*;T;Udi4~#Z-=yFWu(&d26)*jM!`GLRm~KxT$Xfhj1VaMoj#*=KWpjVZPOig zZl3yNAi1?CS04uN(KofDPlw@_g;6RupL4*ik3;t4pYU;M{>BrgWo~=Ia^c$^F|D}k zXgJ5$2}jleM)UbGliK)Re2=cBz!@AwmO}Kw!FQbwQ-xyQm zTD7BMH@Irbo**fe7S(b1Ih?K}#_b+TFQEvb&_SUx{ig1KAt2phqCDRzD+6(Br>?VL zUmJ=R;rT9Gq>_xgJ#Cmb8jt)qZM->CnB7`34{5BUla3keV-kxI(#;J9Qkch}ranur zF>;NSx^L)~wcJVHsJoCcbWLHdJy}xmDRb_Vd`U z$3u zu*MyiHZ)a*&MEFQ&FYrTQQBNkW_t=TE}}>$4<-Z>MO#ziBd?e)s>zF^2ESiBK^J;0 z{#;#sPG!48QS18GMG@y>IlXyPgd(s^#MO^v>Uu1*f%;E^h=K-rH4&bXB?*{@3h*wbV{$!_is1mQ`S)G)0fylz9@Pi&*oV! zp^bO)CR!*T<8WDcw00?$r2B`SK;F)i1k(X5@qgZYj<6O29^r8s=I~egOD~X;3+xk4 z$}a}5b|Mit0>Z8^0S{6Ybv7`C-X{rqLC7t4A#~gQ1}B)Waw-Usq{$E%-Q`2=3<{3$ zA2t{_o=iY`V-Pw4aB!#*<)( zNO!2dT&DAuz45Y9wR6HlbBc|fdhj^gXp2OX-aT#!2kvvU)+Py!^0NOI(i6JTzsqz@ zBOp>(Mk)?Vzo}prYnYa)7B~f-HGCY(Dx2{9Lz%!6XRT82gW&!q%_VU%#?S%$*WjSl z9%Mi0!AUYWFcktykJOM+a$OnFZ-Y%3fo)j6%9R2rwcn^U7P0oCR6?yw3{X!jp)7h~ zI6VZ?FK6{IYQaXli@L@jNw$vu_J3Dl_CN`H3zBL|BaN*1H*>?(eXlF=B-^Nou~Y{ji$@<8sbV$vZPhlnYDoL>%;HJTzY$ z$k6`nl9P5|5qR9RyT`!}IqKc;)DAG?@YU`Rdj#J4k-6)~&<-i}G2j_V5cXe>%#M`f~;nTbM z^P`&-VO)HHY&qo~sQ7^*e=Xy{Me?we$t01u*C<{?%n!9%1XCOvIy$oD9oM{V<5nHs z&Yj~iQ$$l^DH7=yh{aZuX%u4^k}fPN2{Zh16Hae!;Gyf56m;q~-LkW0+&HW$3RvmX zT!xbh16Rjn6yl`sO1{PEB*%iOeb(YEsv6fFR?7`xh#`PO#C411g@H@!f#)OQM-4u3tZzW3(I24Rb}BY;37^Rh}a_Xik2kBh`cGY zPWK}-V>5+(vtax5R!w}Mej8}>)=M143m$twx|s#P|NfPoT2~I0 z>lCoTr*Hyn)-C<@UjAFpR(y08-bLZPik+}lW5o~13g<`U>1!<)_8OHRI62@1|N0m3 zP1ATa3xmO0ZkDT69AmdZFoNX|@2w>kV@S+_1C7prb;L^O1%mjW;Qy|$C@pPXH_G%G zjODhL1V3Okv5)o7KdDw-)L46%vUZ@>G?ci;Ufc;Ph5hHZsuO@rW1AU@mx zd>i|9{r-hE^}3MMJ=aeRJwikrADtcN-xPn95099QnizMyQ&s{aOc#V#E0HNGZ~v+? z5q(9m`N0uoQaV%b{uudZ;&8vR<44wFFL13ST9uY$b<^(vJ1*0Iz&(YR^*=!Zb0R%| zW&Nz4f&Nbgf-WSZe^*a+G=&HDo?-wC-!@kWW*jsA}@BOpyXL(y*izi!j^C zQ5vu2Wvca0;K)vi8We%1I!Ygfe|YBe#Tv~z{OQdaWuMu32TKD>NvCJ(8^C+EnLNxvYjSnOQDu7T+KTsN^=w0Y}fR;4^?>a(H_3@w@ZN z5A}jWIrD`jCBWIB$#}EnGB-6wL|Zy0n=H0~HZ!D=XBULTv@XM~awIJuf$}lA2zT#f`YTbt&i^ z8NDpmiXg>zkV5D>iGDMqo2X}EFO~t_T7;&mi&1Cnor?z;2=9rl0VNB>KnygR}H=c!eVLZ;G>!HY|H^4PdmvGu+0QZnK zlgKRR^V!#iQ?2ESYuM?!R5V?O^;TtO6eWvLaV9DWcX0OR{K5)c$8(cMWZm87(?ZAs zpu$XkX%Zd*J)rD|Qq4!)F7oJe)as$273Rx&tK<<8Vu}x5AiAhg1D_<&YaYf&qAthg zj?WIyC?Dd1uurcknzdPxs7O`gaa$M$6_lmd2pv(1Ei{KM**`nY7|BZ6g)F zS%&|9bN-91{C$op?%UUJY}aUy7^(j~ibb9y;j7PmggWKQK#_Dr7I0pq&5|ngA``0B zm6Tz~tzAVi(oGo3E&~B0>6${WYA>DOs}pV?Oawg2fh#4W>(58QFFMhVsT(ynDZFaN zW@JO1M@d(gE=`oU4Ig4S9F~{%q3T?0F_*B-b^5OSA(@(j2rFb~ijO{G;6zuxG>(Ub zUh_|%4j0jfvv+J~6tk3{J|XoBK4fvV{1EMl}N`Loay(fjPhmBm=ra3y^^Jy;p6TK0iz>;)hXP2|p{X60}?#RPtx zlPoEDE8S63st)mmQ+^U`PDuhNZ|uo2C-kQTHC&z9cm+N~AU-$gObtGaI7wBVqIiI= zq8h8oGSRy5Vy#1AUs}m7>Ky8NYr~)5obOqoYfd}JIWMes{mdk(zbvGLrSlv~E3dML zOShF$UN-xx27mu_L77rmGhLNmH;!F?-sq|$6l8NNc?$Nztm4u+jy2aMJ(5dpT~J|e zGy{?>ofEuV4;O!#z`l^|v1X}QiFJx7gvc&R6gULoZd#q-LirCWI~*1de$Y6kf?b~F z!6h<|O1e`dhV~wur}R3I*FhD(7P(|c$tJLuq|Ocx2^NyVN-&^nsksep7};6L6PGB{ zHLrrUG+dJqp8(0u8L?VB-9m?Tu4Nw%*Qe0fRZ@}HY&JN#P9zDt(h7v7ewa#KG$aiX z+^6z?>np*JnXcO5isi|9cLaH-z}>urS|11F(~L-d37fB>e%mZBEY_()26)g@ewfus zZA^bq+auSxK#}c1ieuy1{wPoV)PR7yyif~Vi6`YDJ+xfPpi(mn`8ct z4U#^%W>x5s+Lbs(PxbyVRL`~M6EhEn12N^VU}yweMpsLk?C8y2D_gvCy_;v+BqJkI zbUy7;(2R;li-khiV9XS43^A^q-Lq)JtdFt$69Ihb?$I zwdc~AL`xTp6h7ECIibVCjIN>xwO!~L#u*aErRu-jC6@==)cI5T+?=GLH^}3C&^ZVBBGj3KaYcrxR)LCXa5!!B|9GIt6v=zBjtJjO;lC{102i7v}u9CxO z8f0Sdk&?i6^rJPqLlCMB9mu$RIy%xk4J5W5G>5eojs2=Qq@a}qDA!c-oJL>h<@$zt z%i6+5`n4<8p_XBAS^{^}oMv@{HF7fEt_R}dIsl*r*yNqgS6B%&H%EVfR-M6-u17KG ztBek#ikj?brtSw^+>|Jt>hhLYZ+k(lREAT{vg)_k*46eEZ0OgyDnMuxF=;HjQ+6|y zece1e)i+0Rx|;Rk*xBJ>Shr&BA1O8T!m=MDvWI_@(86n-d#{<6odT`o|~^Dc+~=8L~7Ecd_zZCdc7A zH#&^%Vn3^#5A%x>#2Mcx7&3ZVPI-gCtm>6(QBf%~WU?58vv`jjo4aA{ zZTN6<%yQeV-4qh&!(t$BVe<--@>;!u#4AWD-JNvEfL2sUSU)&QT{@4aJf148)#E9T zrz+id^tXg^dj6Sq*jL}hc$kWBrI?{D9^b)HUkz#1} zwy_%Go*7;G>D*2I0R0u}QK?iOT?f&X-5hljb~HBzvZFSf0^&lvwIX|1a}_jtf=}mN zRspTx2N(zW>{hy1%Lsl;Dw0924}h?M@ZCjOnqVrs4iPRaBJOADG#|kfBQY1hrO9ZT z&c`s@5H>Ts#tc3(;vRuJyk5ZpjP*IfISrxb=w>;Ozm~>l%uP467T1GX=AZYS)!P_a z8MsdJV%0j|_bOU$AG)$;*>7+k_W=`}<^v}5Dty3%XFvCz{e1d>iKmZO0CMG^DMi+b zMRH}Eq!_GVsVyJrnB!fel71B)EA07ns{MXS0gj;dl_kEcAIDy`MyDUYWr-5=e{R;mg43Q%B4cdh)Ct|aUwouzRoV;AUO zhi5-qiQ(isswx_#h%WMc)hc1I)>@MEM3h5s%kv$K=jwM^9Q z`=|Z>as`r(&J^YnVme)uO}W1Hq|=tSv8988)5c2e-&R?8d&g63W8b$Q-IUw-O@PF{ zzqE;umwyl!KZ572BY>crx~-U(dKxW6Oy6~S_;Q&QnUnUUQzNi0{t=w@=Nd!nN3@Wu zjl(8>t51=Z$!KjtCHIWM>XEr}qK#apYWED4^Rn5D)F#(s9~r1Vm?!5Fo(!f*q6&El zHpDhZ)({@!c#IQxjN>uRR^1Rqbfwx*uz0=3iE%kWjd$uE${|KPmA5zuo~!MDgL&Fjap^M31(x*rGE4;Wfd_^oJSZXj`pos# z#8McVY3uJm&!+xv%)%%#M%PJU(p{vp;CUW~fe^DH{Kqg-J=><_NonlU#_p93boAEd zZbo<3%g~!{XXHz_^5iO*!?_a4T!S(S^Xq^^V5=Q((|yt4D^ zz*gGl8W)Dvu_(D&MNdElB=y5}MSv-=a?flFE@`K~D-cAc~@>f|9hw7OZRgn5ne6avX zEYycAW^YOA5+Aed2}f6}x3Q@%_Db9~KFCTz>f6vhO`%kKuKy;v}Od#oykF1BhX5!b;=c2{3tZ;J(R9oU9= zuI)UWixk;LlQ|C+Z}g^*^m@9;8-tajE?on`*8_u0~D!y$Ix_#buFLisV`wz}( z^e=UD4S$?mK07DTh1?}-$u;>TX@b4AQE%m7&%^xh73*Y$bYYiKaI7vGULc*+MUsBX z%ob?`$BTa>XV0Q`{8S%~isCe8a;^Q< zXk@=xgWJ_4%#v`~jLS>E4y0w^t`)@mGMRVRP)?bQ}f)F z>pnbpRgAO4G)M*wd*q1CBS+p=JaX(|3m!S{HF9)FA!=K;ow#EX|8j*GtG+=s(SOeR zw9S)Vdta}*=6$`qub21r3Orq@w5Rv=Vs~9~yirQmf{NA3=sWs&EhYw;_#O$-BotYg zZRR!O#gf2_C0;DqVhf&p{5yyx%#^V6bQ%84IdqeqNd1Fr6*;3R>=NxYiB2hyeLF*z z6ko!OZLX=f_+sY6t`?MYj9s zkW4X1v48+~3@gK0Uk8(i&aUixI~BS{veTxXmFiZ7pW&@0A|9%HFpARg-HXwy(aSN? zEkuDI+_08>3rn`$09>@MyGnI_@3UH;!&Gk4y!G3T=*z3Jm3^+UJ&O@e~_UL4GHp}Q2j4p92EJ#>VAl>KX(p!4gt7#jU#P2-qlo&X*Oc9TWsck2 z=hWU+`%O5x3c~qf`EXG99~apbmDA=Z_+=rpyTs5B$FHQDE57J_R3e#;0bRkc86_vt zvRJ-aEaJ$jCxDm^ke?3qHi-twSA;${vp%XjZN-C2*Yd&&S|Y~_m!+#~OzIExei_}B zl8E$~3HS;CA7%&xcg6gV#kbn?%oT#FHU6t;=r%A9lCr0lA zC-!E&!?dQ;PF%E}D0OOZs~RHs<>=&C#Yqx}T_iQ=EgvtA>$KDlY9S&~vGa13)u0IF z4)MrYZaL8-q-&4>?&yWE*;au+P3H@dE$3moSm1(Ej*21mg^`s2thwk=+JRq6v3t78 zZ#wl#tiuYEY4$)H>F`-~+438EP`zoocZL+}4n&}paoB+7Ng!e5;qJN;d`OfPkw(my zn#dYP3l$1+c(n{Bu}E&Ewt(~)u=o{5VMlR$L4z5VoSR2Us8q?eW?=-&fx}3ZHbQeS zs;YI7Rv%~>X?I#DTGK4F9U7-@!(h6w5*SP()Q`fea$gw7*st2iFi2PVl z5Q!srB*a%}@D&<-g@(?qzCweq(6Cn(8VJX;(eOu25e%R7EH80YhN+jdqanfCBji5m ztVMg*Vz=vr92yFM`48HYRoJFeQ5i(?YAQ&^6YWY!>DFnPg5OmDF& z9XydaO5Uw`q>Bb{r87K0Ey(L&p!U+PiImNW0^y+Th4^&a1V#uDyK3J|Gm2f%BF$PJ zE|*;XWwluIU$cRqa9rkObF7=OX)Z-B1k15&x6(7h1gnu&62QB}N>ydZs(0E^Lbqsj zk$!xrNx49VzBOs@5qp4al@gYsdWTYYu#7AYF3E;()Do7E0DzYwk(C61m$JN+<)thy zW$nU41UV8$H%Vg|9eG{{4%>0g;m5dQGOyn{%X#tcoPJY*YI!huAcZJiH<^3Nj$=Ep zJ&5n>|SCSbzm=^}3{ zo-X#V1y2|Enl3(qtWyfQS(kOpQ7L)HA}ls7S*ETyF|5~_Y)oOWdDO| zy+)nvuK&F6om>C=eJ!&tah=7X8};trKV7KQPX-fqPx9$v{L9Jl(a!ntBE-7v&a~46 zQaVO9sF}0kGgpb)w!PiZ{x6kYaA6U#h0HX1LLCPUptbRrH2awx<`RRazUW+w2E>Jz zo+3P`-_#C!q~$B1hmZ;9i!>8J$JQawp1kDD*y!qLl8DXl*<7yqtX^{QOi(HTB?5e9 zqzG4Dn3rUUyF@aG=+dZ9x#RC&(#7!eBFYFO0GUja+2dWOV&-5O5!-@XEG~h4v)Gfi zynTn8#h$LW8~E}CR*zU=+6w0PI>}I!EWdx{bZ6j;@VYe?rf3_LB*#`)ilsoqgjOsG zVrg-5!XhvgY|n*_D~iSDjAqw%>F_qNJz8p8Y$Gq5F zWE^adoA$QYl_M~m<({>@IX;?wm4C4HB?Hk|?x*3F5*HggEpD+Qrk2V*L9c7Ma_1#E zJFb8nxFcDn;dJH#pnn|RtNuXhS+ELw#hPwVZ0L*P#11P}6ROG@ zd27xzhnDB7c{qZv=r5B9b$fy}(c30nj}BeTLrR&bQi!H;G>v#lvOQ(mlt=IyR7DFY zkW*v35LaUybvgv;MU0vtAxUsi{8**LPFG9GI`XP+ToSIi)FH>}4bu#15^Az#rjXf6 z@Rtc}YQ|+c@goEi-1a!kO3Gr-PkMgR^OK&Rbn%|rz?`uqx_?a5M}wN*#`FiZJrq@v z+#`}38_)JccIxMq1;`DxP>HH}6iAM!l^`WMA|l36?1V)4;)lNYVf7PV{Lpznp5ztd zd}+lGT{JUB5y0rnh!ke8GM(enLzq5}Vy15YJz2$Y6TK^A_R%lj+&#@DAW&J8QGR0WkJWAVsW~jxG~SWlOYvTc z_biR06t9Wvu28MXAV;nUgxm-r(%)*aVg(iMl}Ex3VyX23^u?-?w0h2^pk>ri`m~)l zgC~Z+k+Pkp?9<-0NgWpEecUrr(<7OA{F<7*kd{ZPsL8w@`$$UqAS2ERock%#%qbr1 za!go2$toi}kwu0z8Mza2G(!?%+u`j51f$>=UAMM%nyAnU!2p<7FEW|mE-p^b5t%L1 zX&S3E{|k}9;VfnOk4W7L5ENP`S;Qb((0FDz6gU!qr!G%GTHH{Us?8tZ0?k3HPfKZ3 zol|gTQM+!_9lK-Owr$(CZFg+jwr$&XzK-p5?40z!_daKzi&eF1Ue2mjHQ)J+@hq~9 z+PE>xyud;OTWG6>6oE9*G!3*UHFpo#lCRk zs;8@7Bwed>aFY{1jcM+tG(4=>fBz(3~os zbNtNSs3h+9U+4N6qxQ9TDcJ2eb&;b}5r0pPt-3y}ft}LFC*&xr-H&V*cGToD)Y9&qO!cBT&s>Ss{#`e$+zQ)>Z0V z6aGDiz3jfDlwLs2TdGnr+Qm%8x@in%HfaW88ZO&mbE3efg0HTWr=}RL{wk z^4u$eNrJsS;=kkqFDeXo)iZ36^u?d1ZDd2?DP^IkoP{2xK#ns;a!^@WdE#`AJjSdO zJb4Ps>zh6DOeu9Nk_@d>0(D2COf#&L#mHDLiNn7;HUbNW*5*P%A{_Ar1bKmEIHYpEZD@VZ;`lKVNINd)yh&c>s?q6=HxM924-ax0X_= z4+R4#P^7>V%fI0wue**x2$nek{hN~la|A8l`vGcQe4L@-@N_RV*_t)s>_*qg*(7l8 zaJw?uxipubxZMR$#%AF;DJlIW@#rEcLlRfVUot8lKF1vuyYkUYl z=i#N&pJ*O~T-0@S5?jt?$??0Ery*k%*W)sN6}Oxe1-{x2FKt0QLcLU4yB|d4RQ6ql z))??1KFEPJX-RtMliHn4aeYV|j5%A@Nyv=T%+hB5n(L8aA3!4o{levK-1PH?QdNV{ z!Ie)f$HhJZ;Udz6Q_Y*Cf?R>jPt|c)vBe3_FY|V;u2?hI57#+(yB!m9y`WO1K)5w) zESuQnWFIn0NzfgZw=IT$;?i>g2F;}h@8_(jZh(3Ixe%>RGVoylY-V8gO21S?0>8Az zW$i^`bA_-g-0_jX*yHy|`(ZVU&FT4w?d<%q=LO3fGP?s7>2`zm=c41HFi=b{CqVYb zlq<=>XG^^v;ZFj-tStHE51}+NCY`?;5zyx#!O12e(?5U%-e1{y-dR!?iY(TsCj(4pv^6ExP=iG+2 zH*ew~vp|1^-HlG-m#`ZT@Wu^f#}|-}RYt`=Y7>9c3wfxFpw7PeiFUIluvj$aJvQj1 z)0s{}!~&$kX}a?wr4i9<$t&Ro9OSuE+)L@BpQiK5CI}7c%Pk?2gzSFdS-}g*iIyMs z_^)QdY0AW_Qf@JUza1v5DJg;nHnNIQ1ZVIY7GbW7R>wd(=;mcBYtK%FkO{$AXU=-C zcq{K3y0@$Sj7%Yv%FR3dKY1gZ?nak|l_;Rspq~GQ{*t!CtWJca<1q{FEUn)FNL>wR zp+_6?*hkddgZ8!_y0a}HJUki#&eyZCB{5w`rIoo(d#%jf?dzd8=j$5b_e1U%2mkhL z=zmh(RXdxCyEBJnUH^@jAwlT^_5tut)(eG?*!O+_TchjvLDjw2n{&hd<|JfR$YalB zDci0#@+g=&IR`h-%k!qkVJMU$PXc#XFxmXE3MaVKldB^;JRcpy2}jB&9w#vB7Wbss z3%?4Q5^aR40)c?8(gC@zM20{W3NgmMBI_dQJq7Cgs3-U|?Qb{(d3Rn+%Y1Ljc82Tyj>m#!uN1E%{B*k{I5!;iUykw2iu(G~F$*yRyFX&u zo9#MrYa z-1VjesMmzu`cL4=3TTY60xbn!{o(LHMRenbKuC^f7e}h6Yt^w*pa5vrprZ%HIyZvU`zm z{Pmti`yUuBuDy?lPj(RdQ_}YoC&qESGoS!F8&{I>Fa9u-R+YA`A^}#IkezGh{Y4!qEUzp{RGWjr%X)4Oph{g z$C1%!oF2Tu#G(9A?Re!Ul(QYpnCNi#_8S)!qboG*GxY4ug!B4OyHp9SdwP`a>&4r= z&7FTe1A16Yj}S88FmU%G`^x^-R&HCfkvQI|zR&E7t|;i<@ONrXzdF7MN=A#Xk}0cI z+6*LGQWuadG>pJHhN3V#e@K|@;2)LWASg&<`~;f`E9~g{Kwm6*-ZwZ%8|23J2{6Py zdO{E(82I7({JpTOX7=i>3CrcqI6pkI0P6IM0Q%kPtKir{XS=Ed*s2by>;>aNs(HZ@ z<9OviPAR*++gV?RXs#YHE6-X@N801_u zsj4+>?5Xrb?2%B4Ze@WZ`Af;FFnWF`_yR2t_NX+U7&xq~TxHUr_J;G=`(63gJ03R3 zi`w2THwN-(>D;jiHMBYxO+Z5kgS&NI#PBL+WZ)8a@fB}Nfq_Mse@o>;BToj`xq6=R zbtmL<$0TlrP^F^N6)FE98xSp^1R$#AeSte~aHfJ_258VSp5rE>cG)ewG193gk||v` zrj{uL+QM^T^Q@-yxS;Sj>BcIH*UGIcODiC_I9^ca?wn1HP~Bim?69*u)1P(kU0&)r zMWwuZARVXw7bkG|M@qvTsj+!i&VJ^JTGqR_p_R|)h3&4(2ej?+$Z7QL&tELN{^OYK zyFY(>e*P&`^P^J8c`f%rXd5|-?0X@!?}5fx7vF{=F`t*@+!962gxqRY1V&bUe+ zwK)^bPXprB;Q*v$O`T=();^*khIec6tthcLUTXoPF?ukr+`}MUxFUvk5s8c4_MGux*E9_sc&gZX8+V;=)EAj1lNLO6DHd+op&vOD z80CjrR+Opg6i8%iwd21xtwf!UalAE7S25T>_ew%xE|KjhvaQMTp@_0}CCD}|RIsv- zkb1v%k$M{yXO&MxwA26`_4#_o6+nTqL&h{Ss;v!rg%{^Xk`+Di;Zv_S#4Zy$6lSY% z=?ld8)PXFDXjJhocuj*&!YWt^NRr!i<+R-;5PDl z_K71*iQL=fa>fE||DDc~T>mGXl`U>-p&*_M9p>LEI%Z)!Z1#+fS{+mF;G(FO`8F}^ zlRBJniUL3^okT-3f~(KU-$0+_s(+~!wh;MVU?=v+QzP+#5YDPO2{WicfWFctmcWTxYG4jB0LoXiJAqpg zw@QG|Z8Z`=Xhl*_MYRlebiuyU+yNcZ%SK`ejPQ3Laon`vPI4(E>H0Z>#}JVO9_m=$ z018n<+TT)0Rb;#&>mhaNyDpqPUKEKJyTRDHwL3qf9yUYo&;@7bryX&9X?Q?zZ|u4X ztS>r3o~jS6>lm0dZa@x=s-ojgRIs;sd(5Xl3i?O4#hUFiVlC$@Zxm>9Ot!sJK28fY zb9l=@#*zbFG1e7AIm;4}i6p62=t_F)fjM_-NgFd+X$p68DKe{xDaIZ(idLwaE{{+| zbQPNZqH-^q!*{)==goXz$rZqx8nqo(7Ngg*M5tOjW6 z)bW`hYyak{Wm{9d;snZfi8C#Ax7!b|aXuK5g}<+w^7tEitD6z;zoV6(n$#W1#ZvbqC65Y!$LKX zRx!eclzVMhu-V%AhjeMho;~yfHaOyug9ieIqCVy$K-E=v+uabRFw4JDAYf)1CkMz^ znNla`rIXc#McX-ezfX25TTt!p7G~7jJ^7mkWl%}5zSdpx)Ky#(yCjjWqAZmhz1hN0 z)kjF|w0Uw&T?EGGAJAKx>>QGe$~2+bBt1@G?m6~9`ET~XUtpS+b#dW!9mMRYh*AimqR+_S=z5RRUWiq-e+_5`Qc` zYO1I?DuN^_y1Ht$J$VjZa7 zv-cx{Sz?45&>unPQ~zD`7b-C%;E5SyA$FuZg*iOa^x~+$xFmfju88(Q8<=*-YDr9) znN)~U?I2U{RVd!TH?@NkXVT>VvPKE@Kp2pT!b|M^E$v1dGn$t~r^!i9y*O70Fu7?} zLEYN=`vc?$?lcmRcjAX^+k8abm1F4)z4bIeu*t!SY#l5?dsrYCuen?w(Ku@!t|)39oX ztzIs<-#Nc!k4()dZ^hHA{3Qo}di6qL+i_7MmIXh@>z%1|qM;7?f&PynC^OHC{rcEZ zUfehH3nIFHRq5Cn_=6XmSO@Nrzv!jyMrmO*&p03LTQO!f+y#HbMu;+^I|w39Cdg~` z|9Z*@4KK$z42Vzw>yF>+hQq1wgDu&Mz48w0HxE7%ndVWS*}HwC0Y~dpb`HO|)c{{$ zlL(WBNhn*gL;X(CN$^qZp7MLt=g`brNK#0V^QW-))@RqGb#Tk8^Dc@Y!!!#TH{9@p z{9)_AK8?yw`2k7XfN$=m-pd3Sr@NAK%BEUG)tl~(Gq;A+fw_3fjc4_)BH#wfZ90+H#h6K zxv!$QQOyFo?6pIK;iWk;f*WDPFfknbPlRLjHEtOCVM_y?o{-^cQe)&2l9*a0Y8z;E zPQ4g12TqJxk)){U+_4Dymb~QHn#J00IQg!%I zxc3~>UKi$C&|tQi#O0oD1u!4qim{To;9iuiK*JN8SUI5F64Ew@WR2s76DI|H1V|2s zD?TNLq%pPil4=lIYM*rCtA(>hfvE|vv_*rOGb%QmBLf(1o^J(%hT&{pVb`~xn?I68 z8D4XEW@9v8O;NdumD^?eb+ne<#Z98JdRUV55k?bd1BtOw#_$C{5^1 zC>%$ZGpuMU5qF0{**VWr z5_XX6*OvBwXp%Iciq_^Leo6gP$VB&~3A-Gch5_Pfrg~ zh_lU6UjFLmouLy+{2Hwc0!NVFo5UNqoietH{1@}FEfB0mVwDX-t!6&Y-Ir z4w`RSuc}r9wx#j#F>Xng7udI@(33clx&v6=CK*HGclj*=f)J_> z*;w*iE@D-2+0Q?4tS+Dqo2aa_%U(6V_i5Z~KDR?EYXuzi$ld5510rWs5qVSuQ<#NN z4f^@c*>z0%Q`s&hPf7hX#>X)$ru-CsvRR={fE?Wvin>%%lXmtVtU14^zgH@5!;S>n zcu1(5uLNsJYK<1jJ@-*#kyb-}MrkM}xz=W;8`RW+Kh9&@N#VhUM7IwxzZ^%DZt@n? z$WB;uyc#Ln7-PkwAq2wPOS?x#n8DfD5BSz8@+)vjzqX{5>!$aX_A>#^GkI1jN45xh zbT)G6bN!I$9vZ<0Nu|Fio@!0R$V9tk&H>#0$vJ-HZXKPC2{)cC6kX=FJg^xq9Kmhb zQP|fl6djdx&(_VYC_NIv@IkS>5-T!Ij@tmY{UDvj_~Eq1>VY(JcW%c%%|Idj^?6!Q z!K_lAN+L)k@f)=ulI+PR5T?p$kldh_5mLHSeBWF$Lx%|B5l?GGwcH2*l^6V)jqQIz zaGY?oEot+B8NXV?5*GH0cfr9ty@8Z=ok$$30G|fb6y)QzAM9Ta=&9Rx_cI6Wrpr$W z!QW;Qqho)uBn+wC?ssQKkOpD_l^F~6&+rUKLfPg}X82M{WNF}&Ah*;59(U5vb{IH0 zIqzW+**g@p2g>gkIk?9hY;K=n5h0U}%?@X+&d~|cAZ)vU1>Bvq@DW}Gx8IgzVV9zu ztZ&z1M(4m6qG|dP#^?&TA4kD!cw5#&WF~Oj36D2P!K?)xuF6>z+6wrAJZHSQpy~H5a0iz806{1}?UVgFd5} zaL-R!-Gj7x5H-$kYL<=u$!@Os?8+N#%^A#HRE)`mZ|95x6Qy$}3V;}-(up>=?_O2K z8rzu_%<#vx|5n(-BX-mg{dv1n54F9VNT9wV8ZVhrs4Q3>?3a7Q&GoJfI^BqUuUX|O zBi`&lr*k}fa_MB;PubB$l@M*+L1b*hJ_$yx$I*B^Y%8@IVwt6ax}nhVJ9Ty_KAk4R ze3Rz)3>w%bY(ZDBN zV~n9z9-$`w$Utz5^xkqr0GH;F!xksIGwP*5Y;?KTT}*LY7@t)w9);A?p<*x!;S#t) z%`2nY-bFFm4^nN1ZzC3TP!W+G0POVew+D()1-R2 zQ}z<;INat-r}U9!4-JFw_t5!zrzPtI%Z6We4zB`~t(6fiz7DmaX~2ll`f4_~{Pra< zwBPwlaj|1*_txNIqEGS1+1i+tU1~(SkyQ>22FO$?j%t*MqcbBaO7Xxj;cLfUf3?}t z)}DPO*If&8X5SEnA!Mw5gJuXxyT0ni7D~Pq5vW(qs1r}l`Csi>+JI5(p}Sy4rG&bM zaEEjch@4D*onY5yNd=C5Fp!KEOtz}Pr0|Bd$oKdT;F%#pvV`Nz;wMN>LnW|Os=-Z& zreSRn2XyXKskIjDS-!gz%gcsIY8}#D$FUO(Qa2nP+@Y?@J@~j2fX!Xo_mCGKPF(68 z=glTjxgu*%)&L;~LObjI1N+Bk;@qtwd=^#dAXdCKRwV8&)afL9WDT-s0-NFFpeBvq z8GI@IZ?s<=K704L2u6gqTsqk`AwbYuET=udj#~hGLQ+6Z!$j>#6s$AmgqQ%hR)l7@ z`d=uxI1=%XuyhrgeqnNi2;w;GLBW!-f#~9S6M}-Oa9PJ^xr3VxxDbT(elsTxm>OVM z)AXi4V%~J9QRc_%)Cv9?rLxvNNRbL1=(90{BB%*uwGGqxi!AoaOm}XQu%e%JQb-d* z-1pqw(9x5(%a)LAk%+<*;$$1mM|bhn@Wa;kQIKk=Z%*LSJhlbBjeCsBLR~J^K3Rs~ z8-#J}b{+$TkyScEli>f#VyhkO}eVeyTx^rV$xvHg-8$D7WY$4GBZuptl z?H)dOIDcO9(_WPYUurz;WbKly710I^RerAVFvpKNrnR!C{=dBJTj0mB`+lI`6_zWt+CZht3r1Cw|XKjyP#1j#gs&s8F@=pFNJUGX*NlF)IzdJj7er|

U@r}nz0LDB{;n` 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 z zh@Z!H%$c@Yr5viNBP2BDQRT77qmRtwRlb09>ehz`TDY!pPVw?VP7yg@iB84kkjSQ@ z4LwwpOGW8Ua?F?b<3l!Nfpq=QF@`*Q5!a6RkznEZVB)RU`#f35?l-D=l2dR1Y|*|6 z9ifu!S=w|RE0O4S>qO^w3O0_azW8SGyF_1hOO2BW5=b)C0y8E<_BFXVO#>Qtm{ zRrT+X^ugVbH&RMh^Z6=Km*_z9l+~>_&Zk%*Ozui|rmR4)L{|q9wPkZHqHC9k+BoXT z@)=M!AVfEaWTfH*S&kAE;SYsToKPBWW3(Z=Y69>(X>oS)blG!^E#mJZh@SMU- z`*{OK!%;60iMB1CBO&5I?j~GD;oU-4zg9sOUQyw`z05?C6QPgALx&ZGE}wNFb>x6c z6lfro5hUvBXMAql6|BGqU1e;jNMP04{tVvZXqqjbd6RV4QoKpJb*bJY{m3TiTV@pp zr=WOi%x$X9wocN9Irk7d!YCd)dhEE}QayHjRP5NBi&+r{GqZe4cz!$Ea~u zhRDh!s8S|p+sUf_711~U|MtGMxs4lHG@s{JU}>L11azsr`a=0_36vgqa^Eb}lJHO<1Hy#6EFfWp#rG&Fv4mATbfCkXr=x%f)sH~0< z3sQZcM1cz3UQfoP@g^c6NeI{6q6P)tkGPsyQaJj8xP@i57!<|1EneU4qUpv@hwc?v zvaXBQbb+0}t?WkDr-GI2cukuDLjWfW$(b?KP%sM3cZ)NX&?W00s?Zi`pMCo5efrc! ze&GKUj29uE1BdWWJeAZ)+7mv1hRWG{4hoO~GdsHOvwwzX7jgWN-d^$FvbC(zX?Pih zSAt4uz0oKQ7bCg-O6xAaC#<8Fct88}3C$(r#Sqq@CCH`z`C>fAVlC!F_uE%m7c&@~ zDI*~NG^ACi`JMmH{=JA{U(n#?Luzl<;lr8}{!lgj`Lq7>t3TmmPe2D_Z&TW#4z8+> zm;nDen2eWgqYKZ$-X8w9_jtdn{}+Gm?ZEHe-of6^Zf~di_~5JV4!k?~ignjH(4q$< zrXXSLs|k>PSWAWFs=nXR$D$;3m>7?bPM@W?BZ65Zc7C71Z(J->q67ZNCn@U6fd+hx zra;k-0FUwHR8XyF$WSShi#G}90aAUW16jBRK}fK5IwcyEOe-dLF&3Q1|AIvbbm4af zr&kQwX7K1eHQ)Yo8plCq1Qq`nfAQr`i^!;?I=K}l!&tfI7_`Mgu8!X3qlc4%)i9RYkb z>YNQDbo@hq`$C57n2i@nFwVNo+2ci=%wJ^^T?CSKra)9CLB=Bi%oL=;pLX9^AIgPVF*0dV5P@dr7ZKe^NI()qQB!z# z!MBTm`+;3#Ief$<*xuu&r9s&@QfcQjMYw;(3pxa)B8#((;)3=mQW~K&`G_{Amg?y& z9$sspO^|QG5ar1QTIRDzF9-~`0UwvJ2WOv^+XuEJC2Rw5k@82Qc$Sn`b*R8;%g%Ci zo*;>szeDd1no^~uNkU;V4&=cAov27!%*(~xGL_=$T<~~ID8~SdK|Gp9zbWX-(S>IY zq?`@7pU}~75fbKeuu;>Kgygukm}(F&In~RRSEku4Yt|^5OO7B^fb;7P5r_zmAh5A{ zUad|VjoLvnxQON<9RNCj?lui(N_5ko4DTt)*C}N?M0wis4JQi;f^a1vfPApooXBI# z>G7MlTF6hFH{s)_iaIbPXA3b4h$7orlxF8h=@G#Vyu$RkIGaTCRQFiQ13n_wND9Ci zx@|hta?htwY7&l*0@s=HhUbnluC;MOYR{f7ALJ`I)B}=v6i&AwhL}lSGAX_l&%%q~ zGKy9DGRbVTb3HqpUfc9YZaTm^-sj0w;F6wR02>=|O}AEyw6OLJlbpg5DrvuNpqoqT7$S&oNB^og$?FZnXz%iLScLKyg#f-?chb-_3F*kM3$u zpc1$18+W;`Qh!&tT35SSuc!$xbgeFQt1i`pbMIW|-pT~%lZri9F(hNoe&7u@?I-st zs-#Bpobs~h?pA46xemFq5uw@V1a|Hoa~0Y8C5@+LLD-E3|4&LsBklsrtp=QiEw{u< z5iO2u%d+w};(PP0Rzbc!|QAOQi{_4#5dd=*n7=bV(|rTA3y zA{#{@G!|`@l2Dn|7W;DRvVoz@;T(MngqJ}TI`FAs?W}PJ-AZ^TY})7g%+yIKU(bo5 z(uJYoE*6iqi$@rAtt~eP*E9xK`vKgf7eM{{MPMCLnH{!0wRe zGzG{0vJ$q;bRw^+H*CIw+J7{Qi+M~JLCxF%6l&2}u_hc})ie8QW1jBdM)PZsV&>2_ zv#_x9KahgeL-t@aXAj`~k`g|~;q)QvJ=6zpK&!iE61)YPSY2tc2g7JEr@O1>d!Mxi z^7s9RHRmPw;v!Dxufq9NoP0F!sJ+h$3lBa+UDVFVv43@l7`7`w~KOC4Z;N}lx1s><%7>WGD>@D{iSHimXWtPNn+DT;y4-DQ>`1M#|h0`gm z7|aMv6S|XYF9C;1aF~ozYpn$Es-GW(V*qBoHfy)}nr!njZDM7B?5Elpu5{|PW-N^4 zn^NM)Q=Q0_)hcUN_gAuknD0-&Jv=HLxVi;^^VCLz{&WzH!{q6CFgC*OI_g+!x~w*h z1YTL>K@J9OY9;Gu_1+iYvPK8YC0f~&1~_R#QHr~HvPdr~`Zj|ib?2yJk!OBfM`H}e zmTOXTA{$@{eXW;PuG2cX6b{4T%MfVZz$Ig8qn3r+6Dr;2a-80uYH&4CB1n}J8{(UV z2WO4K){7dWv9@!aJxNs)Gl!;`tAdaV(CirlAnU|s*XMx&c zkI|-5bDHHG+Rt?~ZPJ7!_$eMQCgDpw9atT>)V|m-hj<63d; z3{ZSLWNbK19WtJJn>+nzCAgZ`0A*`_ooLFc)<37X=SxEhpC&`&P&_+ngO-g&I*o_n z8=0K(cXj_tejbhEvtVqNQo!`LE1jovy$a6B|NXkSN2)}2h!$_w+mm@b7H++1acA^G z3Y7M8-Cdf+K!&g1%rNE9Zt?>7?~q%<=12xC-T~Ex4lxe7gx?Hy%!xiayqyz$+?|R$^Hj^GK|t>K^`4v zi{U6-(hyv+|9d;Tw*7avx4Yf{8+r1=#xphN-|{)vJXUmL@QjWlnK}3*Uv)LRaCc)f)2sXD4*PV>ldM@9+_nt8O(wUrC0`2rm-Cy1Ek4?Hiaw*+%6NAfCTCeUfCH(b zs8d&eTp^!ntv=48ep&B3+?}`Z^LYe+M85%UTBR7&U)nH@Zw`QE*mr!h!MlnSx6*7n z3)-rIrQH0R?`**OCmUMv%Hda|GazMar#$pT(J~4KNiaZ5E!~UI)(O1V>7(`eJouGD>#oHQQ11X9IHezL1i}mfaV)8+5T>*FN%6gEcE4cYS@IV!l zV78I*u0X$#Nz#3X<=T{}&r7agA74=zv zM6m|1g4}t5hUUI-LW0o`-@g+p|sZeA}K!UxulM54VI;4zxqYjx<>=E(T) zmZaP`k~d9*zJ*_SdAF1l8HKhg98-k@_z{5u4Mvn zIXSEWs`SFq3Kk(bQ1hZvvt6TMakW*zO z%~?)2P<{X$!O*B3!iGj!X%QY%n?N)_W7=2jlQNxPinLlUJg zLeyLq9MRGlUk>tGxAf*|xUh7lu-d}1x@9d7^DB=>DXD}Zj(=feNexX@l@{>!IAWIA zf5m*PZUV0I|Jm=^{(s%Q$J_Yt8+k11A#b$Exi9ejQM5r2!WHR4b^+$r1%j{Fki%3w}=OP7NWNA`DFGZEe85D3VI zzvF0EyKU8`Kb)7VBz*IBmFrd&Y-Aw3{Fat^r^>!(WqL6!@3ORa3n=(%Pc{7)7Nix} zK$ZXZ;JQn$G!JufQ|xBAe;P4Ik+JgD3OQ1G#_wA#V}AqZt~^@<8sRH zAi8Dn*T`tf2vqg{pTyG$L!;l+{_pKPhRtr@|LE;(_x~myO`G_D`A5MlI0GJz@kISB zp+)NdfT5bjO2EU}AWp&<4yrf<-Px(!Bd zvYQWbr@HVa-;|-?Zc1uo0vMr=n&plxl(**+lT#JrQYi;^1yWFzNl19rpCnlIW zQii_GFi^_Ns>QY2Fe5E!e#=moWT@5>DhlFJIiHu(hwmpGxR;_!QGOR z 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 Date: Mon, 15 Jul 2024 15:02:36 -0600 Subject: [PATCH 58/64] Release new hashicorp-vault and golang-external-secrets charts --- golang-external-secrets/Chart.yaml | 2 +- hashicorp-vault/Chart.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/golang-external-secrets/Chart.yaml b/golang-external-secrets/Chart.yaml index 802979b4..0bcc381d 100644 --- a/golang-external-secrets/Chart.yaml +++ b/golang-external-secrets/Chart.yaml @@ -3,7 +3,7 @@ description: A Helm chart to configure the golang-based external-secrets. keywords: - pattern name: golang-external-secrets -version: 0.1.0 +version: 0.1.1 dependencies: - name: external-secrets version: "0.9.20" diff --git a/hashicorp-vault/Chart.yaml b/hashicorp-vault/Chart.yaml index ede5950f..87d3470d 100644 --- a/hashicorp-vault/Chart.yaml +++ b/hashicorp-vault/Chart.yaml @@ -3,7 +3,7 @@ description: A Helm chart to configure Hashicorp's vault. keywords: - pattern name: hashicorp-vault -version: 0.1.0 +version: 0.1.1 dependencies: - name: vault version: "0.28.1" From 0983d0d872d29ddf35eeae5bc6e61d1896746a95 Mon Sep 17 00:00:00 2001 From: Martin Jackson Date: Fri, 19 Jul 2024 10:54:41 -0500 Subject: [PATCH 59/64] Add Ansible playbook --- scripts/write-token-kubeconfig.yml | 90 ++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100755 scripts/write-token-kubeconfig.yml diff --git a/scripts/write-token-kubeconfig.yml b/scripts/write-token-kubeconfig.yml new file mode 100755 index 00000000..a2edd83e --- /dev/null +++ b/scripts/write-token-kubeconfig.yml @@ -0,0 +1,90 @@ +#!env ansible-playbook +--- +- name: Test k8s authentication methods + hosts: localhost + connection: local + gather_facts: false + become: false + vars: + kubeconfig_file: '~/.kube/config' + k8s_host: '{{ lookup("env", "K8S_AUTH_HOST") }}' + k8s_validate_certs: '{{ lookup("env", "K8S_AUTH_VERIFY_SSL") | default(false) | bool }}' + k8s_username: '{{ lookup("env", "K8S_AUTH_USERNAME") | default("kubeconfig") }}' + k8s_password: '{{ lookup("env", "K8S_AUTH_PASSWORD") | default(omit) }}' + k8s_api_key: '{{ lookup("env", "K8S_AUTH_TOKEN") | default(omit) }}' + k8s_ca_cert_file: '{{ lookup("env", "K8S_AUTH_SSL_CA_CERT") | default(omit) }}' + tasks: + - name: Check for pre-existing kubeconfig + ansible.builtin.stat: + path: '{{ kubeconfig_file }}' + register: kubeconfig_stat + + - name: Exit if kubeconfig found + ansible.builtin.fail: + msg: '{{ kubeconfig_file }} already exists! Exiting' + when: kubeconfig_stat.stat.exists + + - name: Get namespaces to test parameters + kubernetes.core.k8s_info: + host: '{{ k8s_host }}' + validate_certs: '{{ k8s_validate_certs }}' + username: '{{ k8s_username }}' + api_key: '{{ k8s_api_key }}' + ca_cert: '{{ k8s_ca_cert_file | default(omit) }}' + kind: namespace + when: k8s_api_key + + - name: Login explicitly + when: not k8s_api_key + block: + - name: Login explicitly to get token + kubernetes.core.k8s_auth: + host: '{{ k8s_host }}' + validate_certs: '{{ k8s_validate_certs }}' + username: '{{ k8s_username }}' + password: '{{ k8s_password }}' + ca_cert: '{{ k8s_ca_cert_file | default(omit) }}' + register: auth + + - name: Set api_key + ansible.builtin.set_fact: + k8s_api_key: '{{ auth.openshift_auth.api_key }}' + + - name: Update username if needed + ansible.builtin.set_fact: + config_k8s_username: 'kube:admin' + when: k8s_username == 'kubeadmin' + + - name: Determine clustername + ansible.builtin.set_fact: + config_k8s_clustername: "{{ k8s_host | regex_replace('https://', '') | regex_replace('\\.', '-') }}" + + - name: Write config file + ansible.builtin.copy: + content: |- + apiVersion: v1 + clusters: + - cluster: + {% if k8s_validate_certs is false %} + insecure-skip-tls-verify: true + {% endif %} + {% if k8s_ca_cert_file -%} + certificate-authority-data: {{ lookup("file", k8s_ca_cert_file) | b64encode }} + {% endif %} + server: {{ k8s_host }} + name: {{ config_k8s_clustername }} + contexts: + - context: + cluster: {{ config_k8s_clustername }} + namespace: default + user: {{ config_k8s_username | default(k8s_username) }}/{{ config_k8s_clustername }} + name: default/{{ config_k8s_clustername }}/{{ config_k8s_username | default(k8s_username) }} + current-context: default/{{ config_k8s_clustername }}/{{ config_k8s_username | default(k8s_username) }} + kind: Config + preferences: {} + users: + - name: {{ config_k8s_username | default(k8s_username) }}/{{ config_k8s_clustername }} + user: + token: {{ k8s_api_key }} + dest: '{{ kubeconfig_file }}' + mode: '0640' From 4ce4d806702d1853e1e4d117ef00fab4cd69a270 Mon Sep 17 00:00:00 2001 From: Martin Jackson Date: Fri, 19 Jul 2024 11:22:08 -0500 Subject: [PATCH 60/64] Put the playbook in a more normal location for us --- Makefile | 3 +++ .../write-token-kubeconfig.yml | 1 - scripts/pattern-util.sh | 6 ++++++ scripts/write-token-kubeconfig.sh | 19 +++++++++++++++++++ 4 files changed, 28 insertions(+), 1 deletion(-) rename {scripts => ansible/playbooks/write-token-kubeconfig}/write-token-kubeconfig.yml (99%) mode change 100755 => 100644 create mode 100755 scripts/write-token-kubeconfig.sh diff --git a/Makefile b/Makefile index f9b00e57..e0f0c11b 100644 --- a/Makefile +++ b/Makefile @@ -119,6 +119,9 @@ load-iib: ## CI target to install Index Image Bundles exit 1; \ fi +.PHONY: token-kubeconfig +token-kubeconfig: ## Create a local ~/.kube/config with password (not usually needed) + common/scripts/write-token-kubeconfig.sh ##@ Validation Tasks diff --git a/scripts/write-token-kubeconfig.yml b/ansible/playbooks/write-token-kubeconfig/write-token-kubeconfig.yml old mode 100755 new mode 100644 similarity index 99% rename from scripts/write-token-kubeconfig.yml rename to ansible/playbooks/write-token-kubeconfig/write-token-kubeconfig.yml index a2edd83e..e1ab10e8 --- a/scripts/write-token-kubeconfig.yml +++ b/ansible/playbooks/write-token-kubeconfig/write-token-kubeconfig.yml @@ -1,4 +1,3 @@ -#!env ansible-playbook --- - name: Test k8s authentication methods hosts: localhost diff --git a/scripts/pattern-util.sh b/scripts/pattern-util.sh index f7be58c2..8ff0c365 100755 --- a/scripts/pattern-util.sh +++ b/scripts/pattern-util.sh @@ -67,6 +67,12 @@ podman run -it --rm --pull=newer \ -e EXTRA_HELM_OPTS \ -e EXTRA_PLAYBOOK_OPTS \ -e KUBECONFIG \ + -e K8S_AUTH_HOST \ + -e K8S_AUTH_VERIFY_SSL \ + -e K8S_AUTH_SSL_CA_CERT \ + -e K8S_AUTH_USERNAME \ + -e K8S_AUTH_PASSWORD \ + -e K8S_AUTH_TOKEN \ -v "${PKI_HOST_MOUNT}":/etc/pki:ro \ -v "${HOME}":"${HOME}" \ -v "${HOME}":/pattern-home \ diff --git a/scripts/write-token-kubeconfig.sh b/scripts/write-token-kubeconfig.sh new file mode 100755 index 00000000..f9b0c8a0 --- /dev/null +++ b/scripts/write-token-kubeconfig.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -eu + +get_abs_filename() { + # $1 : relative filename + echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")" +} + +SCRIPT=$(get_abs_filename "$0") +SCRIPTPATH=$(dirname "${SCRIPT}") +COMMONPATH=$(dirname "${SCRIPTPATH}") +PATTERNPATH=$(dirname "${COMMONPATH}") +ANSIBLEPATH="$(dirname ${SCRIPTPATH})/ansible" +PLAYBOOKPATH="${ANSIBLEPATH}/playbooks" +export ANSIBLE_CONFIG="${ANSIBLEPATH}/ansible.cfg" + +PATTERN_NAME=${1:-$(basename "`pwd`")} + +ansible-playbook -e pattern_name="${PATTERN_NAME}" -e pattern_dir="${PATTERNPATH}" "${PLAYBOOKPATH}/write-token-kubeconfig/write-token-kubeconfig.yml" From 41bc42df584b2ff0c6c3f6f1b6f6599e06e8c23a Mon Sep 17 00:00:00 2001 From: Martin Jackson Date: Fri, 19 Jul 2024 12:58:43 -0500 Subject: [PATCH 61/64] Exclude new playbook --- .ansible-lint | 1 + 1 file changed, 1 insertion(+) diff --git a/.ansible-lint b/.ansible-lint index aaffc6b5..0522976e 100644 --- a/.ansible-lint +++ b/.ansible-lint @@ -16,5 +16,6 @@ exclude_paths: - ./ansible/playbooks/iib-ci/iib-ci.yaml - ./ansible/playbooks/k8s_secrets/k8s_secrets.yml - ./ansible/playbooks/process_secrets/process_secrets.yml + - ./ansible/playbooks/write-token-kubeconfig/write-token-kubeconfig.yml - ./ansible/playbooks/process_secrets/display_secrets_info.yml - ./ansible/roles/vault_utils/tests/test.yml From 7bcfbd33e6617ca545baf89fd63ab256dac1bdd1 Mon Sep 17 00:00:00 2001 From: Martin Jackson Date: Fri, 26 Jul 2024 12:40:02 -0500 Subject: [PATCH 62/64] Allow for choice in where file is written --- .../write-token-kubeconfig/write-token-kubeconfig.yml | 4 ++++ scripts/write-token-kubeconfig.sh | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ansible/playbooks/write-token-kubeconfig/write-token-kubeconfig.yml b/ansible/playbooks/write-token-kubeconfig/write-token-kubeconfig.yml index e1ab10e8..dcb23111 100644 --- a/ansible/playbooks/write-token-kubeconfig/write-token-kubeconfig.yml +++ b/ansible/playbooks/write-token-kubeconfig/write-token-kubeconfig.yml @@ -87,3 +87,7 @@ token: {{ k8s_api_key }} dest: '{{ kubeconfig_file }}' mode: '0640' + + - name: Notify user + ansible.builtin.debug: + msg: "Wrote {{ kubeconfig_file }}" diff --git a/scripts/write-token-kubeconfig.sh b/scripts/write-token-kubeconfig.sh index f9b0c8a0..12a2bb80 100755 --- a/scripts/write-token-kubeconfig.sh +++ b/scripts/write-token-kubeconfig.sh @@ -1,6 +1,8 @@ #!/usr/bin/env bash set -eu +OUTPUTFILE=${1:-"~/.kube/config"} + get_abs_filename() { # $1 : relative filename echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")" @@ -14,6 +16,4 @@ ANSIBLEPATH="$(dirname ${SCRIPTPATH})/ansible" PLAYBOOKPATH="${ANSIBLEPATH}/playbooks" export ANSIBLE_CONFIG="${ANSIBLEPATH}/ansible.cfg" -PATTERN_NAME=${1:-$(basename "`pwd`")} - -ansible-playbook -e pattern_name="${PATTERN_NAME}" -e pattern_dir="${PATTERNPATH}" "${PLAYBOOKPATH}/write-token-kubeconfig/write-token-kubeconfig.yml" +ansible-playbook -e pattern_dir="${PATTERNPATH}" -e kubeconfig_file="${OUTPUTFILE}" "${PLAYBOOKPATH}/write-token-kubeconfig/write-token-kubeconfig.yml" From 98d43123834d24fafb670e4127244cddc07763d5 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Tue, 6 Aug 2024 10:03:38 +0200 Subject: [PATCH 63/64] Fix pki bind mount when using podman machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we test for the existance of local TLS folder and bind mount them in containers. This does not work correctly when using podman machine, because a the test is running on the host and so we might bind mount the wrong folder. For example: On Mac OSX /etc/pki does not exist on the folder and so we bind mount /etc/ssl even though /etc/pki does exist in the podman machine VM Co-Authored-By: Ákos Erős --- scripts/pattern-util.sh | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/scripts/pattern-util.sh b/scripts/pattern-util.sh index 8ff0c365..508e1531 100755 --- a/scripts/pattern-util.sh +++ b/scripts/pattern-util.sh @@ -49,13 +49,20 @@ if [ -n "$KUBECONFIG" ]; then fi fi -# Use /etc/pki by default and try a couple of fallbacks if it does not exist -if [ -d /etc/pki ]; then - PKI_HOST_MOUNT="/etc/pki" -elif [ -d /etc/ssl ]; then - PKI_HOST_MOUNT="/etc/ssl" +# Detect if we use podman machine. If we do not then we bind mount local host ssl folders +# if we are using podman machine then we do not bind mount anything (for now!) +REMOTE_PODMAN=$(podman system connection list -q | wc -l) +if [ $REMOTE_PODMAN -eq 0 ]; then # If we are not using podman machine we check the hosts folders + # Use /etc/pki by default and try a couple of fallbacks if it does not exist + if [ -d /etc/pki ]; then + PKI_HOST_MOUNT_ARGS="-v /etc/pki:/etc/pki:ro" + elif [ -d /etc/ssl ]; then + PKI_HOST_MOUNT_ARGS="-v /etc/ssl:/etc/ssl:ro" + else + PKI_HOST_MOUNT_ARGS="-v /usr/share/ca-certificates:/usr/share/ca-certificates:ro" + fi else - PKI_HOST_MOUNT="/usr/share/ca-certificates" + PKI_HOST_MOUNT_ARGS="" fi # Copy Kubeconfig from current environment. The utilities will pick up ~/.kube/config if set so it's not mandatory @@ -67,13 +74,7 @@ podman run -it --rm --pull=newer \ -e EXTRA_HELM_OPTS \ -e EXTRA_PLAYBOOK_OPTS \ -e KUBECONFIG \ - -e K8S_AUTH_HOST \ - -e K8S_AUTH_VERIFY_SSL \ - -e K8S_AUTH_SSL_CA_CERT \ - -e K8S_AUTH_USERNAME \ - -e K8S_AUTH_PASSWORD \ - -e K8S_AUTH_TOKEN \ - -v "${PKI_HOST_MOUNT}":/etc/pki:ro \ + ${PKI_HOST_MOUNT_ARGS} \ -v "${HOME}":"${HOME}" \ -v "${HOME}":/pattern-home \ ${PODMAN_ARGS} \ From 915aa59e8822e4c8225869ea51f4f2e234b71385 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Tue, 6 Aug 2024 10:31:02 +0200 Subject: [PATCH 64/64] Update tests after common rebase --- ...-acm-industrial-edge-factory.expected.yaml | 260 +++- ...mmon-acm-industrial-edge-hub.expected.yaml | 426 +++++- ...on-acm-medical-diagnosis-hub.expected.yaml | 426 +++++- tests/common-acm-naked.expected.yaml | 260 +++- tests/common-acm-normal.expected.yaml | 1257 +++++++++++++++-- ...roup-industrial-edge-factory.expected.yaml | 129 +- ...tergroup-industrial-edge-hub.expected.yaml | 236 +++- ...rgroup-medical-diagnosis-hub.expected.yaml | 296 +++- tests/common-clustergroup-naked.expected.yaml | 119 +- .../common-clustergroup-normal.expected.yaml | 251 +++- ...rets-industrial-edge-factory.expected.yaml | 519 ++++++- ...-secrets-industrial-edge-hub.expected.yaml | 519 ++++++- ...ecrets-medical-diagnosis-hub.expected.yaml | 519 ++++++- ...olang-external-secrets-naked.expected.yaml | 519 ++++++- ...lang-external-secrets-normal.expected.yaml | 519 ++++++- ...ault-industrial-edge-factory.expected.yaml | 20 +- ...rp-vault-industrial-edge-hub.expected.yaml | 20 +- ...-vault-medical-diagnosis-hub.expected.yaml | 20 +- ...common-hashicorp-vault-naked.expected.yaml | 20 +- ...ommon-hashicorp-vault-normal.expected.yaml | 20 +- 20 files changed, 5852 insertions(+), 503 deletions(-) diff --git a/tests/common-acm-industrial-edge-factory.expected.yaml b/tests/common-acm-industrial-edge-factory.expected.yaml index 561fbd7b..39238f91 100644 --- a/tests/common-acm-industrial-edge-factory.expected.yaml +++ b/tests/common-acm-industrial-edge-factory.expected.yaml @@ -42,6 +42,22 @@ subjects: 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-argocd + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: openshift-gitops-placement-argocd + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: openshift-gitops-policy-argocd + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml apiVersion: apps.open-cluster-management.io/v1 kind: PlacementRule metadata: @@ -64,6 +80,28 @@ spec: - 'true' --- # Source: acm/templates/policies/ocp-gitops-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: openshift-gitops-placement-argocd + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: vendor + operator: In + values: + - OpenShift + - key: local-cluster + operator: NotIn + values: + - 'true' +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml apiVersion: policy.open-cluster-management.io/v1 kind: Policy metadata: @@ -90,15 +128,6 @@ spec: include: - default object-templates: - - complianceType: mustonlyhave - objectDefinition: - kind: ConfigMap - apiVersion: v1 - metadata: - name: trusted-ca-bundle - namespace: openshift-gitops - labels: - config.openshift.io/inject-trusted-cabundle: 'true' - complianceType: mustonlyhave objectDefinition: # This is an auto-generated file. DO NOT EDIT @@ -119,3 +148,216 @@ spec: env: - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES value: "*" + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-ca-bundle + namespace: openshift-gitops + labels: + config.openshift.io/inject-trusted-cabundle: 'true' +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +# This policy depends on openshift-gitops-policy and the reason is that we need to be +# certain that the trusted-ca-bundle exists before spawning the clusterwide argocd instance +# because the initcontainer references the trusted-ca-bundle and if it starts without the +# configmap being there we risk running an argo instances that won't trust public CAs +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: openshift-gitops-policy-argocd + 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 + dependencies: + - apiVersion: policy.open-cluster-management.io/v1 + compliance: Compliant + kind: Policy + name: openshift-gitops-policy + namespace: open-cluster-management + - apiVersion: policy.open-cluster-management.io/v1 + compliance: Compliant + kind: Policy + name: hub-argo-ca-openshift-gitops-policy + namespace: open-cluster-management + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: openshift-gitops-config-argocd + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + apiVersion: argoproj.io/v1beta1 + kind: ArgoCD + metadata: + name: openshift-gitops + namespace: openshift-gitops + spec: + applicationSet: + resources: + limits: + cpu: "2" + memory: 1Gi + requests: + cpu: 250m + memory: 512Mi + webhookServer: + ingress: + enabled: false + route: + enabled: false + controller: + processors: {} + resources: + limits: + cpu: "2" + memory: 2Gi + requests: + cpu: 250m + memory: 1Gi + sharding: {} + grafana: + enabled: false + ingress: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + route: + enabled: false + ha: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + initialSSHKnownHosts: {} + monitoring: + enabled: false + notifications: + enabled: false + prometheus: + enabled: false + ingress: + enabled: false + route: + enabled: false + rbac: + defaultPolicy: "" + policy: |- + g, system:cluster-admins, role:admin + g, cluster-admins, role:admin + scopes: '[groups]' + redis: + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + repo: + initContainers: + - command: + - bash + - -c + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt + || true + image: registry.redhat.io/ubi9/ubi-minimal:latest + name: fetch-ca + resources: {} + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 250m + memory: 256Mi + volumeMounts: + - mountPath: /etc/pki/tls/certs + name: ca-bundles + volumes: + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle + - emptyDir: {} + name: ca-bundles + resourceExclusions: |- + - apiGroups: + - tekton.dev + clusters: + - '*' + kinds: + - TaskRun + - PipelineRun + server: + autoscale: + enabled: false + grpc: + ingress: + enabled: false + ingress: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 125m + memory: 128Mi + route: + enabled: true + service: + type: "" + sso: + dex: + openShiftOAuth: true + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + provider: dex + tls: + ca: {} diff --git a/tests/common-acm-industrial-edge-hub.expected.yaml b/tests/common-acm-industrial-edge-hub.expected.yaml index 4199ba03..8b18a4da 100644 --- a/tests/common-acm-industrial-edge-hub.expected.yaml +++ b/tests/common-acm-industrial-edge-hub.expected.yaml @@ -38,6 +38,38 @@ subjects: kind: Policy apiGroup: policy.open-cluster-management.io --- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: hub-argo-ca-openshift-gitops-policy-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: hub-argo-ca-openshift-gitops-policy-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: hub-argo-ca-openshift-gitops-policy + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: hub-argo-ca-factory-placement-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: hub-argo-ca-factory-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: hub-argo-ca-factory-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 @@ -70,6 +102,22 @@ subjects: 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-argocd + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: openshift-gitops-placement-argocd + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: openshift-gitops-policy-argocd + kind: Policy + apiGroup: policy.open-cluster-management.io +--- # Source: acm/templates/policies/acm-hub-ca-policy.yaml apiVersion: apps.open-cluster-management.io/v1 kind: PlacementRule @@ -88,6 +136,42 @@ spec: values: - 'true' --- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: hub-argo-ca-openshift-gitops-policy-placement + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: local-cluster + operator: NotIn + values: + - 'true' +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: hub-argo-ca-factory-placement + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: local-cluster + operator: NotIn + values: + - 'true' +--- # Source: acm/templates/policies/application-policies.yaml apiVersion: apps.open-cluster-management.io/v1 kind: PlacementRule @@ -136,6 +220,28 @@ spec: values: - 'true' --- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: openshift-gitops-placement-argocd + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: vendor + operator: In + values: + - OpenShift + - key: local-cluster + operator: NotIn + values: + - 'true' +--- # Source: acm/templates/policies/acm-hub-ca-policy.yaml apiVersion: policy.open-cluster-management.io/v1 kind: Policy @@ -171,6 +277,92 @@ spec: data: hub-kube-root-ca.crt: '{{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | base64enc hub}}' hub-openshift-service-ca.crt: '{{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | base64enc hub}}' + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-hub-bundle + namespace: imperative + data: + hub-kube-root-ca.crt: | + {{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}} + hub-openshift-service-ca.crt: | + {{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}} +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: hub-argo-ca-openshift-gitops-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: hub-argo-ca-openshift-gitops-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-hub-bundle + namespace: openshift-gitops + data: + hub-kube-root-ca.crt: | + {{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}} + hub-openshift-service-ca.crt: | + {{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}} +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: hub-argo-ca-factory-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: hub-argo-ca-factory-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-hub-bundle + namespace: mypattern-factory + data: + hub-kube-root-ca.crt: | + {{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}} + hub-openshift-service-ca.crt: | + {{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}} --- # Source: acm/templates/policies/application-policies.yaml # TODO: Also create a GitOpsCluster.apps.open-cluster-management.io @@ -246,10 +438,18 @@ spec: value: '{{ (split "." (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain)._1 }}' - name: global.clusterPlatform value: aws - - name: clusterGroup.name - value: factory + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: + - name: global.privateRepo + value: - name: global.experimentalCapabilities value: + - name: clusterGroup.name + value: factory - name: clusterGroup.isHubCluster value: "false" destination: @@ -298,15 +498,6 @@ spec: include: - default object-templates: - - complianceType: mustonlyhave - objectDefinition: - kind: ConfigMap - apiVersion: v1 - metadata: - name: trusted-ca-bundle - namespace: openshift-gitops - labels: - config.openshift.io/inject-trusted-cabundle: 'true' - complianceType: mustonlyhave objectDefinition: # This is an auto-generated file. DO NOT EDIT @@ -327,3 +518,216 @@ spec: env: - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES value: "*" + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-ca-bundle + namespace: openshift-gitops + labels: + config.openshift.io/inject-trusted-cabundle: 'true' +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +# This policy depends on openshift-gitops-policy and the reason is that we need to be +# certain that the trusted-ca-bundle exists before spawning the clusterwide argocd instance +# because the initcontainer references the trusted-ca-bundle and if it starts without the +# configmap being there we risk running an argo instances that won't trust public CAs +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: openshift-gitops-policy-argocd + 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 + dependencies: + - apiVersion: policy.open-cluster-management.io/v1 + compliance: Compliant + kind: Policy + name: openshift-gitops-policy + namespace: open-cluster-management + - apiVersion: policy.open-cluster-management.io/v1 + compliance: Compliant + kind: Policy + name: hub-argo-ca-openshift-gitops-policy + namespace: open-cluster-management + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: openshift-gitops-config-argocd + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + apiVersion: argoproj.io/v1beta1 + kind: ArgoCD + metadata: + name: openshift-gitops + namespace: openshift-gitops + spec: + applicationSet: + resources: + limits: + cpu: "2" + memory: 1Gi + requests: + cpu: 250m + memory: 512Mi + webhookServer: + ingress: + enabled: false + route: + enabled: false + controller: + processors: {} + resources: + limits: + cpu: "2" + memory: 2Gi + requests: + cpu: 250m + memory: 1Gi + sharding: {} + grafana: + enabled: false + ingress: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + route: + enabled: false + ha: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + initialSSHKnownHosts: {} + monitoring: + enabled: false + notifications: + enabled: false + prometheus: + enabled: false + ingress: + enabled: false + route: + enabled: false + rbac: + defaultPolicy: "" + policy: |- + g, system:cluster-admins, role:admin + g, cluster-admins, role:admin + scopes: '[groups]' + redis: + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + repo: + initContainers: + - command: + - bash + - -c + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt + || true + image: registry.redhat.io/ubi9/ubi-minimal:latest + name: fetch-ca + resources: {} + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 250m + memory: 256Mi + volumeMounts: + - mountPath: /etc/pki/tls/certs + name: ca-bundles + volumes: + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle + - emptyDir: {} + name: ca-bundles + resourceExclusions: |- + - apiGroups: + - tekton.dev + clusters: + - '*' + kinds: + - TaskRun + - PipelineRun + server: + autoscale: + enabled: false + grpc: + ingress: + enabled: false + ingress: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 125m + memory: 128Mi + route: + enabled: true + service: + type: "" + sso: + dex: + openShiftOAuth: true + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + provider: dex + tls: + ca: {} diff --git a/tests/common-acm-medical-diagnosis-hub.expected.yaml b/tests/common-acm-medical-diagnosis-hub.expected.yaml index f2a8fdd6..dffb9eb6 100644 --- a/tests/common-acm-medical-diagnosis-hub.expected.yaml +++ b/tests/common-acm-medical-diagnosis-hub.expected.yaml @@ -38,6 +38,38 @@ subjects: kind: Policy apiGroup: policy.open-cluster-management.io --- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: hub-argo-ca-openshift-gitops-policy-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: hub-argo-ca-openshift-gitops-policy-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: hub-argo-ca-openshift-gitops-policy + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: hub-argo-ca-region-one-placement-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: hub-argo-ca-region-one-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: hub-argo-ca-region-one-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 @@ -70,6 +102,22 @@ subjects: 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-argocd + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: openshift-gitops-placement-argocd + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: openshift-gitops-policy-argocd + kind: Policy + apiGroup: policy.open-cluster-management.io +--- # Source: acm/templates/policies/acm-hub-ca-policy.yaml apiVersion: apps.open-cluster-management.io/v1 kind: PlacementRule @@ -88,6 +136,42 @@ spec: values: - 'true' --- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: hub-argo-ca-openshift-gitops-policy-placement + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: local-cluster + operator: NotIn + values: + - 'true' +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: hub-argo-ca-region-one-placement + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: local-cluster + operator: NotIn + values: + - 'true' +--- # Source: acm/templates/policies/application-policies.yaml apiVersion: apps.open-cluster-management.io/v1 kind: PlacementRule @@ -127,6 +211,28 @@ spec: values: - 'true' --- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: openshift-gitops-placement-argocd + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: vendor + operator: In + values: + - OpenShift + - key: local-cluster + operator: NotIn + values: + - 'true' +--- # Source: acm/templates/policies/acm-hub-ca-policy.yaml apiVersion: policy.open-cluster-management.io/v1 kind: Policy @@ -162,6 +268,92 @@ spec: data: hub-kube-root-ca.crt: '{{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | base64enc hub}}' hub-openshift-service-ca.crt: '{{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | base64enc hub}}' + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-hub-bundle + namespace: imperative + data: + hub-kube-root-ca.crt: | + {{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}} + hub-openshift-service-ca.crt: | + {{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}} +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: hub-argo-ca-openshift-gitops-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: hub-argo-ca-openshift-gitops-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-hub-bundle + namespace: openshift-gitops + data: + hub-kube-root-ca.crt: | + {{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}} + hub-openshift-service-ca.crt: | + {{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}} +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: hub-argo-ca-region-one-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: hub-argo-ca-region-one-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-hub-bundle + namespace: mypattern-region-one + data: + hub-kube-root-ca.crt: | + {{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}} + hub-openshift-service-ca.crt: | + {{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}} --- # Source: acm/templates/policies/application-policies.yaml # TODO: Also create a GitOpsCluster.apps.open-cluster-management.io @@ -237,10 +429,18 @@ spec: value: '{{ (split "." (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain)._1 }}' - name: global.clusterPlatform value: aws - - name: clusterGroup.name - value: region-one + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: + - name: global.privateRepo + value: - name: global.experimentalCapabilities value: + - name: clusterGroup.name + value: region-one - name: clusterGroup.isHubCluster value: "false" destination: @@ -289,15 +489,6 @@ spec: include: - default object-templates: - - complianceType: mustonlyhave - objectDefinition: - kind: ConfigMap - apiVersion: v1 - metadata: - name: trusted-ca-bundle - namespace: openshift-gitops - labels: - config.openshift.io/inject-trusted-cabundle: 'true' - complianceType: mustonlyhave objectDefinition: # This is an auto-generated file. DO NOT EDIT @@ -318,3 +509,216 @@ spec: env: - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES value: "*" + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-ca-bundle + namespace: openshift-gitops + labels: + config.openshift.io/inject-trusted-cabundle: 'true' +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +# This policy depends on openshift-gitops-policy and the reason is that we need to be +# certain that the trusted-ca-bundle exists before spawning the clusterwide argocd instance +# because the initcontainer references the trusted-ca-bundle and if it starts without the +# configmap being there we risk running an argo instances that won't trust public CAs +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: openshift-gitops-policy-argocd + 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 + dependencies: + - apiVersion: policy.open-cluster-management.io/v1 + compliance: Compliant + kind: Policy + name: openshift-gitops-policy + namespace: open-cluster-management + - apiVersion: policy.open-cluster-management.io/v1 + compliance: Compliant + kind: Policy + name: hub-argo-ca-openshift-gitops-policy + namespace: open-cluster-management + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: openshift-gitops-config-argocd + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + apiVersion: argoproj.io/v1beta1 + kind: ArgoCD + metadata: + name: openshift-gitops + namespace: openshift-gitops + spec: + applicationSet: + resources: + limits: + cpu: "2" + memory: 1Gi + requests: + cpu: 250m + memory: 512Mi + webhookServer: + ingress: + enabled: false + route: + enabled: false + controller: + processors: {} + resources: + limits: + cpu: "2" + memory: 2Gi + requests: + cpu: 250m + memory: 1Gi + sharding: {} + grafana: + enabled: false + ingress: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + route: + enabled: false + ha: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + initialSSHKnownHosts: {} + monitoring: + enabled: false + notifications: + enabled: false + prometheus: + enabled: false + ingress: + enabled: false + route: + enabled: false + rbac: + defaultPolicy: "" + policy: |- + g, system:cluster-admins, role:admin + g, cluster-admins, role:admin + scopes: '[groups]' + redis: + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + repo: + initContainers: + - command: + - bash + - -c + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt + || true + image: registry.redhat.io/ubi9/ubi-minimal:latest + name: fetch-ca + resources: {} + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 250m + memory: 256Mi + volumeMounts: + - mountPath: /etc/pki/tls/certs + name: ca-bundles + volumes: + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle + - emptyDir: {} + name: ca-bundles + resourceExclusions: |- + - apiGroups: + - tekton.dev + clusters: + - '*' + kinds: + - TaskRun + - PipelineRun + server: + autoscale: + enabled: false + grpc: + ingress: + enabled: false + ingress: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 125m + memory: 128Mi + route: + enabled: true + service: + type: "" + sso: + dex: + openShiftOAuth: true + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + provider: dex + tls: + ca: {} diff --git a/tests/common-acm-naked.expected.yaml b/tests/common-acm-naked.expected.yaml index 561fbd7b..39238f91 100644 --- a/tests/common-acm-naked.expected.yaml +++ b/tests/common-acm-naked.expected.yaml @@ -42,6 +42,22 @@ subjects: 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-argocd + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: openshift-gitops-placement-argocd + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: openshift-gitops-policy-argocd + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml apiVersion: apps.open-cluster-management.io/v1 kind: PlacementRule metadata: @@ -64,6 +80,28 @@ spec: - 'true' --- # Source: acm/templates/policies/ocp-gitops-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: openshift-gitops-placement-argocd + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: vendor + operator: In + values: + - OpenShift + - key: local-cluster + operator: NotIn + values: + - 'true' +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml apiVersion: policy.open-cluster-management.io/v1 kind: Policy metadata: @@ -90,15 +128,6 @@ spec: include: - default object-templates: - - complianceType: mustonlyhave - objectDefinition: - kind: ConfigMap - apiVersion: v1 - metadata: - name: trusted-ca-bundle - namespace: openshift-gitops - labels: - config.openshift.io/inject-trusted-cabundle: 'true' - complianceType: mustonlyhave objectDefinition: # This is an auto-generated file. DO NOT EDIT @@ -119,3 +148,216 @@ spec: env: - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES value: "*" + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-ca-bundle + namespace: openshift-gitops + labels: + config.openshift.io/inject-trusted-cabundle: 'true' +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +# This policy depends on openshift-gitops-policy and the reason is that we need to be +# certain that the trusted-ca-bundle exists before spawning the clusterwide argocd instance +# because the initcontainer references the trusted-ca-bundle and if it starts without the +# configmap being there we risk running an argo instances that won't trust public CAs +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: openshift-gitops-policy-argocd + 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 + dependencies: + - apiVersion: policy.open-cluster-management.io/v1 + compliance: Compliant + kind: Policy + name: openshift-gitops-policy + namespace: open-cluster-management + - apiVersion: policy.open-cluster-management.io/v1 + compliance: Compliant + kind: Policy + name: hub-argo-ca-openshift-gitops-policy + namespace: open-cluster-management + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: openshift-gitops-config-argocd + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + apiVersion: argoproj.io/v1beta1 + kind: ArgoCD + metadata: + name: openshift-gitops + namespace: openshift-gitops + spec: + applicationSet: + resources: + limits: + cpu: "2" + memory: 1Gi + requests: + cpu: 250m + memory: 512Mi + webhookServer: + ingress: + enabled: false + route: + enabled: false + controller: + processors: {} + resources: + limits: + cpu: "2" + memory: 2Gi + requests: + cpu: 250m + memory: 1Gi + sharding: {} + grafana: + enabled: false + ingress: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + route: + enabled: false + ha: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + initialSSHKnownHosts: {} + monitoring: + enabled: false + notifications: + enabled: false + prometheus: + enabled: false + ingress: + enabled: false + route: + enabled: false + rbac: + defaultPolicy: "" + policy: |- + g, system:cluster-admins, role:admin + g, cluster-admins, role:admin + scopes: '[groups]' + redis: + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + repo: + initContainers: + - command: + - bash + - -c + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt + || true + image: registry.redhat.io/ubi9/ubi-minimal:latest + name: fetch-ca + resources: {} + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 250m + memory: 256Mi + volumeMounts: + - mountPath: /etc/pki/tls/certs + name: ca-bundles + volumes: + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle + - emptyDir: {} + name: ca-bundles + resourceExclusions: |- + - apiGroups: + - tekton.dev + clusters: + - '*' + kinds: + - TaskRun + - PipelineRun + server: + autoscale: + enabled: false + grpc: + ingress: + enabled: false + ingress: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 125m + memory: 128Mi + route: + enabled: true + service: + type: "" + sso: + dex: + openShiftOAuth: true + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + provider: dex + tls: + ca: {} diff --git a/tests/common-acm-normal.expected.yaml b/tests/common-acm-normal.expected.yaml index 143de18b..1e2b1573 100644 --- a/tests/common-acm-normal.expected.yaml +++ b/tests/common-acm-normal.expected.yaml @@ -1,4 +1,16 @@ --- +# Source: acm/templates/provision/clusterdeployment.yaml +apiVersion: v1 +kind: Namespace +metadata: + name: aws-cd-one-w-pool-acm-provision-edge +--- +# Source: acm/templates/provision/clusterdeployment.yaml +apiVersion: v1 +kind: Namespace +metadata: + name: aws-cd-two-wo-pool-acm-provision-on-deploy +--- # Source: acm/templates/provision/secrets-common.yaml apiVersion: v1 kind: Secret @@ -6,7 +18,7 @@ metadata: name: aws-ap-acm-provision-edge-install-config data: # Base64 encoding of install-config yaml - install-config.yaml: CgphcGlWZXJzaW9uOiB2MQptZXRhZGF0YToKICBuYW1lOiAnYXdzLWFwJyAKYmFzZURvbWFpbjogYmx1ZXByaW50cy5yaGVjb2VuZy5jb20KY29udHJvbFBsYW5lOgogIGFyY2hpdGVjdHVyZTogYW1kNjQKICBoeXBlcnRocmVhZGluZzogRW5hYmxlZAogIG5hbWU6IGNvbnRyb2xQbGFuZQogIHJlcGxpY2FzOiAxCiAgcGxhdGZvcm06CiAgICBhd3M6CiAgICAgIHR5cGU6IG01LnhsYXJnZQpjb21wdXRlOgotIGh5cGVydGhyZWFkaW5nOiBFbmFibGVkCiAgYXJjaGl0ZWN0dXJlOiBhbWQ2NAogIG5hbWU6ICd3b3JrZXInCiAgcmVwbGljYXM6IDAKbmV0d29ya2luZzoKICBjbHVzdGVyTmV0d29yazoKICAtIGNpZHI6IDEwLjEyOC4wLjAvMTQKICAgIGhvc3RQcmVmaXg6IDIzCiAgbWFjaGluZU5ldHdvcms6CiAgLSBjaWRyOiAxMC4wLjAuMC8xNgogIG5ldHdvcmtUeXBlOiBPVk5LdWJlcm5ldGVzCiAgc2VydmljZU5ldHdvcms6CiAgLSAxNzIuMzAuMC4wLzE2CnBsYXRmb3JtOgogIGF3czoKICAgIHJlZ2lvbjogYXAtc291dGhlYXN0LTIKcHVsbFNlY3JldDogIiIgIyBza2lwLCBoaXZlIHdpbGwgaW5qZWN0IGJhc2VkIG9uIGl0J3Mgc2VjcmV0cwpzc2hLZXk6ICIiICAgICAjIHNraXAsIGhpdmUgd2lsbCBpbmplY3QgYmFzZWQgb24gaXQncyBzZWNyZXRz + install-config.yaml: CgphcGlWZXJzaW9uOiB2MQptZXRhZGF0YToKICBuYW1lOiAnYXdzLWFwJyAKYmFzZURvbWFpbjogYmx1ZXByaW50cy5yaGVjb2VuZy5jb20KY29udHJvbFBsYW5lOgogIGFyY2hpdGVjdHVyZTogYW1kNjQKICBoeXBlcnRocmVhZGluZzogRW5hYmxlZAogIG5hbWU6IGNvbnRyb2xQbGFuZQogIHJlcGxpY2FzOiAxCiAgcGxhdGZvcm06CiAgICBhd3M6CiAgICAgIHR5cGU6IG01LnhsYXJnZQpjb21wdXRlOgotIGh5cGVydGhyZWFkaW5nOiBFbmFibGVkCiAgYXJjaGl0ZWN0dXJlOiBhbWQ2NAogIG5hbWU6ICd3b3JrZXInCiAgcmVwbGljYXM6IDAKbmV0d29ya2luZzoKICBjbHVzdGVyTmV0d29yazoKICAtIGNpZHI6IDEwLjEyOC4wLjAvMTQKICAgIGhvc3RQcmVmaXg6IDIzCiAgbWFjaGluZU5ldHdvcms6CiAgLSBjaWRyOiAxMC4wLjAuMC8xNgogIG5ldHdvcmtUeXBlOiBPVk5LdWJlcm5ldGVzCiAgc2VydmljZU5ldHdvcms6CiAgLSAxNzIuMzAuMC4wLzE2CnBsYXRmb3JtOgogIGF3czoKICAgIHJlZ2lvbjogYXAtc291dGhlYXN0LTIKcHVsbFNlY3JldDogIiIgIyBza2lwLCBoaXZlIHdpbGwgaW5qZWN0IGJhc2VkIG9uIGl0J3Mgc2VjcmV0cwpzc2hLZXk6ICIiICAgICAjIHNraXAsIGhpdmUgd2lsbCBpbmplY3QgYmFzZWQgb24gaXQncyBzZWNyZXRz type: Opaque --- # Source: acm/templates/provision/secrets-common.yaml @@ -16,7 +28,29 @@ metadata: name: azure-us-acm-provision-edge-install-config data: # Base64 encoding of install-config yaml - install-config.yaml: CgphcGlWZXJzaW9uOiB2MQptZXRhZGF0YToKICBuYW1lOiAnYXp1cmUtdXMnIApiYXNlRG9tYWluOiBibHVlcHJpbnRzLnJoZWNvZW5nLmNvbQpjb250cm9sUGxhbmU6CiAgYXJjaGl0ZWN0dXJlOiBhbWQ2NAogIGh5cGVydGhyZWFkaW5nOiBFbmFibGVkCiAgbmFtZTogY29udHJvbFBsYW5lCiAgcmVwbGljYXM6IDMKICBwbGF0Zm9ybToKICAgIGF6dXJlOgogICAgICB0eXBlOiBTdGFuZGFyZF9EOHNfdjMKY29tcHV0ZToKLSBoeXBlcnRocmVhZGluZzogRW5hYmxlZAogIGFyY2hpdGVjdHVyZTogYW1kNjQKICBuYW1lOiAnd29ya2VyJwogIHJlcGxpY2FzOiAzCiAgcGxhdGZvcm06CiAgICBhenVyZToKICAgICAgdHlwZTogU3RhbmRhcmRfRDhzX3YzCm5ldHdvcmtpbmc6CiAgY2x1c3Rlck5ldHdvcms6CiAgLSBjaWRyOiAxMC4xMjguMC4wLzE0CiAgICBob3N0UHJlZml4OiAyMwogIG1hY2hpbmVOZXR3b3JrOgogIC0gY2lkcjogMTAuMC4wLjAvMTYKICBuZXR3b3JrVHlwZTogT1ZOS3ViZXJuZXRlcwogIHNlcnZpY2VOZXR3b3JrOgogIC0gMTcyLjMwLjAuMC8xNgpwbGF0Zm9ybToKICBhenVyZToKICAgIGJhc2VEb21haW5SZXNvdXJjZUdyb3VwTmFtZTogZG9qby1kbnMtem9uZXMKICAgIHJlZ2lvbjogZWFzdHVzCnB1bGxTZWNyZXQ6ICIiICMgc2tpcCwgaGl2ZSB3aWxsIGluamVjdCBiYXNlZCBvbiBpdCdzIHNlY3JldHMKc3NoS2V5OiAiIiAgICAgIyBza2lwLCBoaXZlIHdpbGwgaW5qZWN0IGJhc2VkIG9uIGl0J3Mgc2VjcmV0cw== + install-config.yaml: CgphcGlWZXJzaW9uOiB2MQptZXRhZGF0YToKICBuYW1lOiAnYXp1cmUtdXMnIApiYXNlRG9tYWluOiBibHVlcHJpbnRzLnJoZWNvZW5nLmNvbQpjb250cm9sUGxhbmU6CiAgYXJjaGl0ZWN0dXJlOiBhbWQ2NAogIGh5cGVydGhyZWFkaW5nOiBFbmFibGVkCiAgbmFtZTogY29udHJvbFBsYW5lCiAgcmVwbGljYXM6IDMKICBwbGF0Zm9ybToKICAgIGF6dXJlOgogICAgICB0eXBlOiBTdGFuZGFyZF9EOHNfdjMKY29tcHV0ZToKLSBoeXBlcnRocmVhZGluZzogRW5hYmxlZAogIGFyY2hpdGVjdHVyZTogYW1kNjQKICBuYW1lOiAnd29ya2VyJwogIHJlcGxpY2FzOiAzCiAgcGxhdGZvcm06CiAgICBhenVyZToKICAgICAgdHlwZTogU3RhbmRhcmRfRDhzX3YzCm5ldHdvcmtpbmc6CiAgY2x1c3Rlck5ldHdvcms6CiAgLSBjaWRyOiAxMC4xMjguMC4wLzE0CiAgICBob3N0UHJlZml4OiAyMwogIG1hY2hpbmVOZXR3b3JrOgogIC0gY2lkcjogMTAuMC4wLjAvMTYKICBuZXR3b3JrVHlwZTogT1ZOS3ViZXJuZXRlcwogIHNlcnZpY2VOZXR3b3JrOgogIC0gMTcyLjMwLjAuMC8xNgpwbGF0Zm9ybToKICBhenVyZToKICAgIGJhc2VEb21haW5SZXNvdXJjZUdyb3VwTmFtZTogZG9qby1kbnMtem9uZXMKICAgIHJlZ2lvbjogZWFzdHVzCnB1bGxTZWNyZXQ6ICIiICMgc2tpcCwgaGl2ZSB3aWxsIGluamVjdCBiYXNlZCBvbiBpdCdzIHNlY3JldHMKc3NoS2V5OiAiIiAgICAgIyBza2lwLCBoaXZlIHdpbGwgaW5qZWN0IGJhc2VkIG9uIGl0J3Mgc2VjcmV0cw== +type: Opaque +--- +# Source: acm/templates/provision/secrets-common.yaml +apiVersion: v1 +kind: Secret +metadata: + name: aws-cd-one-w-pool-acm-provision-edge-install-config + namespace: aws-cd-one-w-pool-acm-provision-edge +data: + # Base64 encoding of install-config yaml + install-config.yaml: CgphcGlWZXJzaW9uOiB2MQptZXRhZGF0YToKICBuYW1lOiAnYXdzLWNkLW9uZS13LXBvb2wnIApiYXNlRG9tYWluOiBibHVlcHJpbnRzLnJoZWNvZW5nLmNvbQpjb250cm9sUGxhbmU6CiAgYXJjaGl0ZWN0dXJlOiBhbWQ2NAogIGh5cGVydGhyZWFkaW5nOiBFbmFibGVkCiAgbmFtZTogY29udHJvbFBsYW5lCiAgcmVwbGljYXM6IDMKICBwbGF0Zm9ybToKICAgIGF3czoKICAgICAgdHlwZTogbTUueGxhcmdlCmNvbXB1dGU6Ci0gaHlwZXJ0aHJlYWRpbmc6IEVuYWJsZWQKICBhcmNoaXRlY3R1cmU6IGFtZDY0CiAgbmFtZTogJ3dvcmtlcicKICByZXBsaWNhczogMwogIHBsYXRmb3JtOgogICAgYXdzOgogICAgICB0eXBlOiBtNS54bGFyZ2UKbmV0d29ya2luZzoKICBjbHVzdGVyTmV0d29yazoKICAtIGNpZHI6IDEwLjEyOC4wLjAvMTQKICAgIGhvc3RQcmVmaXg6IDIzCiAgbWFjaGluZU5ldHdvcms6CiAgLSBjaWRyOiAxMC4wLjAuMC8xNgogIG5ldHdvcmtUeXBlOiBPVk5LdWJlcm5ldGVzCiAgc2VydmljZU5ldHdvcms6CiAgLSAxNzIuMzAuMC4wLzE2CnBsYXRmb3JtOgogIGF3czoKICAgIHJlZ2lvbjogYXAtc291dGhlYXN0LTEKcHVsbFNlY3JldDogIiIgIyBza2lwLCBoaXZlIHdpbGwgaW5qZWN0IGJhc2VkIG9uIGl0J3Mgc2VjcmV0cwpzc2hLZXk6ICIiICAgICAjIHNraXAsIGhpdmUgd2lsbCBpbmplY3QgYmFzZWQgb24gaXQncyBzZWNyZXRz +type: Opaque +--- +# Source: acm/templates/provision/secrets-common.yaml +apiVersion: v1 +kind: Secret +metadata: + name: aws-cd-two-wo-pool-acm-provision-on-deploy-install-config + namespace: aws-cd-two-wo-pool-acm-provision-on-deploy +data: + # Base64 encoding of install-config yaml + install-config.yaml: CgphcGlWZXJzaW9uOiB2MQptZXRhZGF0YToKICBuYW1lOiAnYXdzLWNkLXR3by13by1wb29sJyAKYmFzZURvbWFpbjogYmx1ZXByaW50cy5yaGVjb2VuZy5jb20KY29udHJvbFBsYW5lOgogIGFyY2hpdGVjdHVyZTogYW1kNjQKICBoeXBlcnRocmVhZGluZzogRW5hYmxlZAogIG5hbWU6IGNvbnRyb2xQbGFuZQogIHJlcGxpY2FzOiAzCiAgcGxhdGZvcm06CiAgICBhd3M6CiAgICAgIHR5cGU6IG01LnhsYXJnZQpjb21wdXRlOgotIGh5cGVydGhyZWFkaW5nOiBFbmFibGVkCiAgYXJjaGl0ZWN0dXJlOiBhbWQ2NAogIG5hbWU6ICd3b3JrZXInCiAgcmVwbGljYXM6IDMKICBwbGF0Zm9ybToKICAgIGF3czoKICAgICAgdHlwZTogbTUueGxhcmdlCm5ldHdvcmtpbmc6CiAgY2x1c3Rlck5ldHdvcms6CiAgLSBjaWRyOiAxMC4xMjguMC4wLzE0CiAgICBob3N0UHJlZml4OiAyMwogIG1hY2hpbmVOZXR3b3JrOgogIC0gY2lkcjogMTAuMC4wLjAvMTYKICBuZXR3b3JrVHlwZTogT1ZOS3ViZXJuZXRlcwogIHNlcnZpY2VOZXR3b3JrOgogIC0gMTcyLjMwLjAuMC8xNgpwbGF0Zm9ybToKICBhd3M6CiAgICByZWdpb246IGFwLXNvdXRoZWFzdC0zCnB1bGxTZWNyZXQ6ICIiICMgc2tpcCwgaGl2ZSB3aWxsIGluamVjdCBiYXNlZCBvbiBpdCdzIHNlY3JldHMKc3NoS2V5OiAiIiAgICAgIyBza2lwLCBoaXZlIHdpbGwgaW5qZWN0IGJhc2VkIG9uIGl0J3Mgc2VjcmV0cw== type: Opaque --- # Source: acm/templates/policies/acm-hub-ca-policy.yaml @@ -61,6 +95,64 @@ metadata: spec: clusterPoolName: azure-us-acm-provision-edge --- +# Source: acm/templates/provision/clusterdeployment.yaml +apiVersion: hive.openshift.io/v1 +kind: ClusterDeployment +metadata: + name: aws-cd-one-w-pool-acm-provision-edge + namespace: aws-cd-one-w-pool-acm-provision-edge + labels: + vendor: OpenShift + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + baseDomain: blueprints.rhecoeng.com + clusterName: aws-cd-one-w-pool-acm-provision-edge + installAttemptsLimit: 1 + platform: + aws: + credentialsSecretRef: + name: aws-cd-one-w-pool-acm-provision-edge-creds + region: ap-southeast-1 + provisioning: + installConfigSecretRef: + name: aws-cd-one-w-pool-acm-provision-edge-install-config + sshPrivateKeySecretRef: + name: aws-cd-one-w-pool-acm-provision-edge-ssh-private-key + imageSetRef: + name: img4.10.18-multi-appsub + pullSecretRef: + name: aws-cd-one-w-pool-acm-provision-edge-pull-secret +--- +# Source: acm/templates/provision/clusterdeployment.yaml +apiVersion: hive.openshift.io/v1 +kind: ClusterDeployment +metadata: + name: aws-cd-two-wo-pool-acm-provision-on-deploy + namespace: aws-cd-two-wo-pool-acm-provision-on-deploy + labels: + vendor: OpenShift + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + baseDomain: blueprints.rhecoeng.com + clusterName: aws-cd-two-wo-pool-acm-provision-on-deploy + installAttemptsLimit: 1 + platform: + aws: + credentialsSecretRef: + name: aws-cd-two-wo-pool-acm-provision-on-deploy-creds + region: ap-southeast-3 + provisioning: + installConfigSecretRef: + name: aws-cd-two-wo-pool-acm-provision-on-deploy-install-config + sshPrivateKeySecretRef: + name: aws-cd-two-wo-pool-acm-provision-on-deploy-ssh-private-key + imageSetRef: + name: img4.10.18-multi-appsub + pullSecretRef: + name: aws-cd-two-wo-pool-acm-provision-on-deploy-pull-secret +--- # Source: acm/templates/provision/clusterpool.yaml apiVersion: hive.openshift.io/v1 kind: ClusterPool @@ -79,7 +171,7 @@ spec: runningCount: 0 baseDomain: blueprints.rhecoeng.com installConfigSecretTemplateRef: - name: aws-ap-acm-provision-edge-install-config + name: aws-ap-acm-provision-edge-install-config imageSetRef: name: img4.10.18-multi-appsub pullSecretRef: @@ -109,7 +201,7 @@ spec: runningCount: 2 baseDomain: blueprints.rhecoeng.com installConfigSecretTemplateRef: - name: azure-us-acm-provision-edge-install-config + name: azure-us-acm-provision-edge-install-config imageSetRef: name: img4.10.18-multi-appsub pullSecretRef: @@ -147,7 +239,7 @@ apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: aws-ap-acm-provision-edge-infra-creds -spec: +spec: data: - secretKey: openshiftPullSecret remoteRef: @@ -170,7 +262,7 @@ spec: key: secret/data/hub/privatekey property: content refreshInterval: 24h0m0s - secretStoreRef: + secretStoreRef: name: vault-backend kind: ClusterSecretStore target: @@ -199,6 +291,166 @@ spec: noProxy: "" additionalTrustBundle: "" --- +# Source: acm/templates/provision/secrets-aws.yaml +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: aws-cd-one-w-pool-acm-provision-edge-creds + namespace: aws-cd-one-w-pool-acm-provision-edge +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-cd-one-w-pool-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-cd-one-w-pool-acm-provision-edge-infra-creds + namespace: aws-cd-one-w-pool-acm-provision-edge +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-cd-one-w-pool-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-aws.yaml +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: aws-cd-two-wo-pool-acm-provision-on-deploy-creds + namespace: aws-cd-two-wo-pool-acm-provision-on-deploy +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-cd-two-wo-pool-acm-provision-on-deploy-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-cd-two-wo-pool-acm-provision-on-deploy-infra-creds + namespace: aws-cd-two-wo-pool-acm-provision-on-deploy +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-cd-two-wo-pool-acm-provision-on-deploy-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 @@ -229,7 +481,7 @@ apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: azure-us-acm-provision-edge-infra-creds -spec: +spec: data: - secretKey: openshiftPullSecret remoteRef: @@ -248,7 +500,7 @@ spec: key: secret/data/hub/azureOsServicePrincipal property: content refreshInterval: 24h0m0s - secretStoreRef: + secretStoreRef: name: vault-backend kind: ClusterSecretStore target: @@ -282,7 +534,7 @@ apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: aws-ap-acm-provision-edge-pull-secret -spec: +spec: data: - secretKey: openshiftPullSecret remoteRef: @@ -330,7 +582,7 @@ apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: azure-us-acm-provision-edge-pull-secret -spec: +spec: data: - secretKey: openshiftPullSecret remoteRef: @@ -373,44 +625,240 @@ spec: ssh-privatekey: |- {{ .sshPrivateKey | toString }} --- -# Source: acm/templates/provision/clusterpool.yaml -apiVersion: cluster.open-cluster-management.io/v1beta1 -kind: ManagedClusterSet +# Source: acm/templates/provision/secrets-common.yaml +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret metadata: - annotations: - cluster.open-cluster-management.io/submariner-broker-ns: acm-provision-edge-broker - argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true - name: acm-provision-edge + name: aws-cd-one-w-pool-acm-provision-edge-pull-secret + namespace: aws-cd-one-w-pool-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" - installer.open-cluster-management.io/mce-subscription-spec: '{"source": "redhat-operators" }' -spec: {} + data: + - secretKey: openshiftPullSecret + remoteRef: + key: secret/data/hub/openshiftPullSecret + property: content + refreshInterval: 24h0m0s + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: aws-cd-one-w-pool-acm-provision-edge-pull-secret + creationPolicy: Owner + template: + type: kubernetes.io/dockerconfigjson + data: + .dockerconfigjson: |- + {{ .openshiftPullSecret | toString }} --- -# Source: acm/templates/policies/acm-hub-ca-policy.yaml -apiVersion: policy.open-cluster-management.io/v1 -kind: PlacementBinding +# Source: acm/templates/provision/secrets-common.yaml +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret metadata: - name: acm-hub-ca-policy-placement-binding - annotations: - argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true -placementRef: - name: acm-hub-ca-policy-placement - kind: PlacementRule - apiGroup: apps.open-cluster-management.io -subjects: - - name: acm-hub-ca-policy - kind: Policy - apiGroup: policy.open-cluster-management.io + name: aws-cd-one-w-pool-acm-provision-edge-ssh-private-key + namespace: aws-cd-one-w-pool-acm-provision-edge +spec: + data: + - secretKey: sshPrivateKey + remoteRef: + key: secret/data/hub/privatekey + property: content + refreshInterval: 24h0m0s + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: aws-cd-one-w-pool-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: aws-cd-two-wo-pool-acm-provision-on-deploy-pull-secret + namespace: aws-cd-two-wo-pool-acm-provision-on-deploy +spec: + data: + - secretKey: openshiftPullSecret + remoteRef: + key: secret/data/hub/openshiftPullSecret + property: content + refreshInterval: 24h0m0s + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: aws-cd-two-wo-pool-acm-provision-on-deploy-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-cd-two-wo-pool-acm-provision-on-deploy-ssh-private-key + namespace: aws-cd-two-wo-pool-acm-provision-on-deploy +spec: + data: + - secretKey: sshPrivateKey + remoteRef: + key: secret/data/hub/privatekey + property: content + refreshInterval: 24h0m0s + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: aws-cd-two-wo-pool-acm-provision-on-deploy-ssh-private-key + creationPolicy: Owner + template: + type: Opaque + data: + ssh-privatekey: |- + {{ .sshPrivateKey | toString }} +--- +# Source: acm/templates/provision/clusterdeployment.yaml +apiVersion: cluster.open-cluster-management.io/v1 +kind: ManagedCluster +metadata: + labels: + cluster.open-cluster-management.io/clusterset: acm-provision-edge + clusterGroup: region + name: aws-cd-one-w-pool-acm-provision-edge + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + hubAcceptsClient: true +--- +# Source: acm/templates/provision/clusterdeployment.yaml +apiVersion: cluster.open-cluster-management.io/v1 +kind: ManagedCluster +metadata: + labels: + cluster.open-cluster-management.io/clusterset: acm-provision-on-deploy + clusterGroup: acm-provision-on-deploy + name: aws-cd-two-wo-pool-acm-provision-on-deploy + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + hubAcceptsClient: true +--- +# Source: acm/templates/provision/managedclusterset.yaml +apiVersion: cluster.open-cluster-management.io/v1beta2 +kind: ManagedClusterSet +metadata: + annotations: + cluster.open-cluster-management.io/submariner-broker-ns: acm-provision-edge-broker + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + name: acm-provision-edge +--- +# Source: acm/templates/provision/managedclusterset.yaml +apiVersion: cluster.open-cluster-management.io/v1beta2 +kind: ManagedClusterSet +metadata: + annotations: + cluster.open-cluster-management.io/submariner-broker-ns: acm-provision-on-deploy-broker + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + name: acm-provision-on-deploy +--- +# 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" + installer.open-cluster-management.io/mce-subscription-spec: '{"source": "redhat-operators" }' +spec: {} +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: acm-hub-ca-policy-placement-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: acm-hub-ca-policy-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: acm-hub-ca-policy + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: hub-argo-ca-openshift-gitops-policy-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: hub-argo-ca-openshift-gitops-policy-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: hub-argo-ca-openshift-gitops-policy + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: hub-argo-ca-acm-edge-placement-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: hub-argo-ca-acm-edge-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: hub-argo-ca-acm-edge-policy + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: hub-argo-ca-acm-provision-edge-placement-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: hub-argo-ca-acm-provision-edge-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: hub-argo-ca-acm-provision-edge-policy + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: hub-argo-ca-acm-provision-on-deploy-placement-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: hub-argo-ca-acm-provision-on-deploy-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: hub-argo-ca-acm-provision-on-deploy-policy + kind: Policy + apiGroup: policy.open-cluster-management.io --- # Source: acm/templates/policies/application-policies.yaml apiVersion: policy.open-cluster-management.io/v1 @@ -444,6 +892,22 @@ subjects: 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-on-deploy-placement-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: acm-provision-on-deploy-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: acm-provision-on-deploy-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 @@ -460,6 +924,22 @@ subjects: 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-argocd + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: openshift-gitops-placement-argocd + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: openshift-gitops-policy-argocd + kind: Policy + apiGroup: policy.open-cluster-management.io +--- # Source: acm/templates/policies/acm-hub-ca-policy.yaml apiVersion: apps.open-cluster-management.io/v1 kind: PlacementRule @@ -478,6 +958,78 @@ spec: values: - 'true' --- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: hub-argo-ca-openshift-gitops-policy-placement + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: local-cluster + operator: NotIn + values: + - 'true' +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: hub-argo-ca-acm-edge-placement + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: local-cluster + operator: NotIn + values: + - 'true' +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: hub-argo-ca-acm-provision-edge-placement + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: local-cluster + operator: NotIn + values: + - 'true' +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: hub-argo-ca-acm-provision-on-deploy-placement + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: local-cluster + operator: NotIn + values: + - 'true' +--- # Source: acm/templates/policies/application-policies.yaml apiVersion: apps.open-cluster-management.io/v1 kind: PlacementRule @@ -493,48 +1045,244 @@ spec: matchLabels: clusterGroup: acm-region --- -# Source: acm/templates/policies/application-policies.yaml -apiVersion: apps.open-cluster-management.io/v1 -kind: PlacementRule +# Source: acm/templates/policies/application-policies.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: acm-provision-edge-placement + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchLabels: + clusterGroup: region +--- +# Source: acm/templates/policies/application-policies.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: acm-provision-on-deploy-placement + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchLabels: + clusterGroup: acm-provision-on-deploy +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: openshift-gitops-placement + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: vendor + operator: In + values: + - OpenShift + - key: local-cluster + operator: NotIn + values: + - 'true' +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: openshift-gitops-placement-argocd + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: vendor + operator: In + values: + - OpenShift + - key: local-cluster + operator: NotIn + values: + - 'true' +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: acm-hub-ca-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-hub-ca-config-policy + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + kind: Secret + apiVersion: v1 + type: Opaque + metadata: + name: hub-ca + namespace: golang-external-secrets + data: + hub-kube-root-ca.crt: '{{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | base64enc hub}}' + hub-openshift-service-ca.crt: '{{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | base64enc hub}}' + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-hub-bundle + namespace: imperative + data: + hub-kube-root-ca.crt: | + {{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}} + hub-openshift-service-ca.crt: | + {{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}} +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: hub-argo-ca-openshift-gitops-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: hub-argo-ca-openshift-gitops-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-hub-bundle + namespace: openshift-gitops + data: + hub-kube-root-ca.crt: | + {{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}} + hub-openshift-service-ca.crt: | + {{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}} +--- +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy metadata: - name: acm-provision-edge-placement + name: hub-argo-ca-acm-edge-policy annotations: argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + argocd.argoproj.io/compare-options: IgnoreExtraneous spec: - clusterConditions: - - status: 'True' - type: ManagedClusterConditionAvailable - clusterSelector: - matchLabels: - clusterGroup: region + remediationAction: enforce + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: hub-argo-ca-acm-edge-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-hub-bundle + namespace: mypattern-acm-edge + data: + hub-kube-root-ca.crt: | + {{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}} + hub-openshift-service-ca.crt: | + {{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}} --- -# Source: acm/templates/policies/ocp-gitops-policy.yaml -apiVersion: apps.open-cluster-management.io/v1 -kind: PlacementRule +# Source: acm/templates/policies/acm-hub-ca-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy metadata: - name: openshift-gitops-placement + name: hub-argo-ca-acm-provision-edge-policy annotations: argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + argocd.argoproj.io/compare-options: IgnoreExtraneous spec: - clusterConditions: - - status: 'True' - type: ManagedClusterConditionAvailable - clusterSelector: - matchExpressions: - - key: vendor - operator: In - values: - - OpenShift - - key: local-cluster - operator: NotIn - values: - - 'true' + remediationAction: enforce + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: hub-argo-ca-acm-provision-edge-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-hub-bundle + namespace: mypattern-acm-provision-edge + data: + hub-kube-root-ca.crt: | + {{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}} + hub-openshift-service-ca.crt: | + {{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}} --- # Source: acm/templates/policies/acm-hub-ca-policy.yaml apiVersion: policy.open-cluster-management.io/v1 kind: Policy metadata: - name: acm-hub-ca-policy + name: hub-argo-ca-acm-provision-on-deploy-policy annotations: argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true argocd.argoproj.io/compare-options: IgnoreExtraneous @@ -546,7 +1294,7 @@ spec: apiVersion: policy.open-cluster-management.io/v1 kind: ConfigurationPolicy metadata: - name: acm-hub-ca-config-policy + name: hub-argo-ca-acm-provision-on-deploy-config spec: remediationAction: enforce severity: medium @@ -556,15 +1304,16 @@ spec: object-templates: - complianceType: mustonlyhave objectDefinition: - kind: Secret + kind: ConfigMap apiVersion: v1 - type: Opaque metadata: - name: hub-ca - namespace: golang-external-secrets + name: trusted-hub-bundle + namespace: mypattern-acm-provision-on-deploy data: - hub-kube-root-ca.crt: '{{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | base64enc hub}}' - hub-openshift-service-ca.crt: '{{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | base64enc hub}}' + hub-kube-root-ca.crt: | + {{hub fromConfigMap "" "kube-root-ca.crt" "ca.crt" | autoindent hub}} + hub-openshift-service-ca.crt: | + {{hub fromConfigMap "" "openshift-service-ca.crt" "service-ca.crt" | autoindent hub}} --- # Source: acm/templates/policies/application-policies.yaml # TODO: Also create a GitOpsCluster.apps.open-cluster-management.io @@ -640,10 +1389,18 @@ spec: value: '{{ (split "." (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain)._1 }}' - name: global.clusterPlatform value: aws - - name: clusterGroup.name - value: acm-edge + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: + - name: global.privateRepo + value: - name: global.experimentalCapabilities value: + - name: clusterGroup.name + value: acm-edge - name: clusterGroup.isHubCluster value: "false" destination: @@ -738,10 +1495,18 @@ spec: value: '{{ (split "." (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain)._1 }}' - name: global.clusterPlatform value: aws - - name: clusterGroup.name - value: acm-provision-edge + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: + - name: global.privateRepo + value: - name: global.experimentalCapabilities value: + - name: clusterGroup.name + value: acm-provision-edge - name: clusterGroup.isHubCluster value: "false" destination: @@ -763,6 +1528,110 @@ spec: jsonPointers: - /status --- +# Source: acm/templates/policies/application-policies.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: acm-provision-on-deploy-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-on-deploy-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-on-deploy + 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 + values: | + extraParametersNested: + valueFiles: + - "/values-global.yaml" + - "/values-acm-provision-on-deploy.yaml" + - '/values-{{ (lookup "config.openshift.io/v1" "Infrastructure" "" "cluster").spec.platformSpec.type }}.yaml' + - '/values-{{ (lookup "config.openshift.io/v1" "Infrastructure" "" "cluster").spec.platformSpec.type }}-{{ printf "%d.%d" ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Major) ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Minor) }}.yaml' + - '/values-{{ (lookup "config.openshift.io/v1" "Infrastructure" "" "cluster").spec.platformSpec.type }}-acm-provision-on-deploy.yaml' + # We cannot use $.Values.global.clusterVersion because that gets resolved to the + # hub's cluster version, whereas we want to include the spoke cluster version + - '/values-{{ printf "%d.%d" ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Major) ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Minor) }}.yaml' + parameters: + - name: global.repoURL + value: https://github.com/pattern-clone/mypattern + - name: global.targetRevision + value: main + - 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 }}' + - name: global.clusterDomain + value: '{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain | replace "apps." "" }}' + - name: global.clusterVersion + value: '{{ printf "%d.%d" ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Major) ((semver (index (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").status.history 0).version).Minor) }}' + - name: global.localClusterName + value: '{{ (split "." (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain)._1 }}' + - name: global.clusterPlatform + value: aws + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: + - name: global.privateRepo + value: + - name: global.experimentalCapabilities + value: + - name: clusterGroup.name + value: acm-provision-on-deploy + destination: + server: https://kubernetes.default.svc + namespace: mypattern-acm-provision-on-deploy + syncPolicy: + automated: + prune: false + selfHeal: true + retry: + limit: 20 + 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 @@ -790,15 +1659,6 @@ spec: include: - default object-templates: - - complianceType: mustonlyhave - objectDefinition: - kind: ConfigMap - apiVersion: v1 - metadata: - name: trusted-ca-bundle - namespace: openshift-gitops - labels: - config.openshift.io/inject-trusted-cabundle: 'true' - complianceType: mustonlyhave objectDefinition: # This is an auto-generated file. DO NOT EDIT @@ -819,3 +1679,216 @@ spec: env: - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES value: "*" + - complianceType: mustonlyhave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: trusted-ca-bundle + namespace: openshift-gitops + labels: + config.openshift.io/inject-trusted-cabundle: 'true' +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +# This policy depends on openshift-gitops-policy and the reason is that we need to be +# certain that the trusted-ca-bundle exists before spawning the clusterwide argocd instance +# because the initcontainer references the trusted-ca-bundle and if it starts without the +# configmap being there we risk running an argo instances that won't trust public CAs +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: openshift-gitops-policy-argocd + 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 + dependencies: + - apiVersion: policy.open-cluster-management.io/v1 + compliance: Compliant + kind: Policy + name: openshift-gitops-policy + namespace: open-cluster-management + - apiVersion: policy.open-cluster-management.io/v1 + compliance: Compliant + kind: Policy + name: hub-argo-ca-openshift-gitops-policy + namespace: open-cluster-management + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: openshift-gitops-config-argocd + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + apiVersion: argoproj.io/v1beta1 + kind: ArgoCD + metadata: + name: openshift-gitops + namespace: openshift-gitops + spec: + applicationSet: + resources: + limits: + cpu: "2" + memory: 1Gi + requests: + cpu: 250m + memory: 512Mi + webhookServer: + ingress: + enabled: false + route: + enabled: false + controller: + processors: {} + resources: + limits: + cpu: "2" + memory: 2Gi + requests: + cpu: 250m + memory: 1Gi + sharding: {} + grafana: + enabled: false + ingress: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + route: + enabled: false + ha: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + initialSSHKnownHosts: {} + monitoring: + enabled: false + notifications: + enabled: false + prometheus: + enabled: false + ingress: + enabled: false + route: + enabled: false + rbac: + defaultPolicy: "" + policy: |- + g, system:cluster-admins, role:admin + g, cluster-admins, role:admin + scopes: '[groups]' + redis: + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + repo: + initContainers: + - command: + - bash + - -c + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt + || true + image: registry.redhat.io/ubi9/ubi-minimal:latest + name: fetch-ca + resources: {} + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 250m + memory: 256Mi + volumeMounts: + - mountPath: /etc/pki/tls/certs + name: ca-bundles + volumes: + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle + - emptyDir: {} + name: ca-bundles + resourceExclusions: |- + - apiGroups: + - tekton.dev + clusters: + - '*' + kinds: + - TaskRun + - PipelineRun + server: + autoscale: + enabled: false + grpc: + ingress: + enabled: false + ingress: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 125m + memory: 128Mi + route: + enabled: true + service: + type: "" + sso: + dex: + openShiftOAuth: true + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + provider: dex + tls: + ca: {} diff --git a/tests/common-clustergroup-industrial-edge-factory.expected.yaml b/tests/common-clustergroup-industrial-edge-factory.expected.yaml index 1826e750..57dd0de6 100644 --- a/tests/common-clustergroup-industrial-edge-factory.expected.yaml +++ b/tests/common-clustergroup-industrial-edge-factory.expected.yaml @@ -121,6 +121,33 @@ data: --set clusterGroup.name=factory --post-renderer ./kustomize"] initContainers: [] + resourceExclusions: | + - apiGroups: + - tekton.dev + kinds: + - TaskRun + - PipelineRun + resourceHealthChecks: + - check: | + hs = {} + if obj.status ~= nil then + if obj.status.phase ~= nil then + if obj.status.phase == "Pending" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + elseif obj.status.phase == "Bound" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + end + end + end + hs.status = "Progressing" + hs.message = "Waiting for PVC" + return hs + kind: PersistentVolumeClaim + resourceTrackingMethod: label imperative: activeDeadlineSeconds: 3600 adminClusterRoleName: imperative-admin-cluster-role @@ -152,6 +179,7 @@ data: - manuela-stormshift-machine-sensor - manuela-stormshift-messaging - manuela-factory-ml-workspace + nodes: [] operatorgroupExcludes: - manuela-factory-ml-workspace projects: @@ -432,6 +460,27 @@ spec: 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: fetch-ca + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + imagePullPolicy: Always + env: + - name: HOME + value: /git/home + command: + - 'sh' + - '-c' + - >- + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true; + ls -l /tmp/ca-bundles/ + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles - name: git-init image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest imagePullPolicy: Always @@ -441,6 +490,8 @@ spec: volumeMounts: - name: git mountPath: "/git" + - name: ca-bundles + mountPath: /etc/pki/tls/certs command: - 'sh' - '-c' @@ -467,8 +518,9 @@ spec: if [ -n "${OUT}" ]; then export HTTPS_PROXY="${OUT}"; fi; OUT="$(oc get proxy.config.openshift.io/cluster -o jsonpath='{.spec.noProxy}' 2>/dev/null)"; if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; + if [ "main" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch main"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch --branch main --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch ${BRANCH} --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; - name: test image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -492,6 +544,14 @@ spec: - name: values-volume mountPath: /values/values.yaml subPath: values.yaml + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles containers: - name: "done" image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -508,6 +568,19 @@ spec: - name: values-volume configMap: name: helm-values-configmap-factory + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle + - name: ca-bundles + emptyDir: {} restartPolicy: Never --- # Source: clustergroup/templates/core/subscriptions.yaml @@ -593,9 +666,9 @@ spec: - "/values-4.12-factory.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -608,6 +681,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -655,6 +734,7 @@ spec: hs.message = "Waiting for PVC" return hs + resourceTrackingMethod: label applicationInstanceLabelKey: argocd.argoproj.io/instance applicationSet: resources: @@ -688,6 +768,47 @@ spec: rbac: defaultPolicy: role:admin repo: + initContainers: + - command: + - bash + - -c + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + name: fetch-ca + resources: {} + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 250m + memory: 256Mi + volumeMounts: + - mountPath: /etc/pki/tls/certs + name: ca-bundles + volumes: + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle + - emptyDir: {} + name: ca-bundles sidecarContainers: - name: helm-with-kustomize command: [/var/run/argocd/argocd-cmp-server] @@ -721,7 +842,7 @@ spec: requests: cpu: 250m memory: 256Mi - resourceExclusions: | + resourceExclusions: | - apiGroups: - tekton.dev kinds: diff --git a/tests/common-clustergroup-industrial-edge-hub.expected.yaml b/tests/common-clustergroup-industrial-edge-hub.expected.yaml index b81b7cef..8857a222 100644 --- a/tests/common-clustergroup-industrial-edge-hub.expected.yaml +++ b/tests/common-clustergroup-industrial-edge-hub.expected.yaml @@ -242,6 +242,33 @@ data: --set clusterGroup.name=datacenter --post-renderer ./kustomize"] initContainers: [] + resourceExclusions: | + - apiGroups: + - tekton.dev + kinds: + - TaskRun + - PipelineRun + resourceHealthChecks: + - check: | + hs = {} + if obj.status ~= nil then + if obj.status.phase ~= nil then + if obj.status.phase == "Pending" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + elseif obj.status.phase == "Bound" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + end + end + end + hs.status = "Progressing" + hs.message = "Waiting for PVC" + return hs + kind: PersistentVolumeClaim + resourceTrackingMethod: label imperative: activeDeadlineSeconds: 3600 adminClusterRoleName: imperative-admin-cluster-role @@ -291,6 +318,7 @@ data: - manuela-data-lake - staging - vault + nodes: [] operatorgroupExcludes: - manuela-ml-workspace projects: @@ -593,6 +621,27 @@ spec: 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: fetch-ca + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + imagePullPolicy: Always + env: + - name: HOME + value: /git/home + command: + - 'sh' + - '-c' + - >- + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true; + ls -l /tmp/ca-bundles/ + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles - name: git-init image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest imagePullPolicy: Always @@ -602,6 +651,8 @@ spec: volumeMounts: - name: git mountPath: "/git" + - name: ca-bundles + mountPath: /etc/pki/tls/certs command: - 'sh' - '-c' @@ -628,8 +679,9 @@ spec: if [ -n "${OUT}" ]; then export HTTPS_PROXY="${OUT}"; fi; OUT="$(oc get proxy.config.openshift.io/cluster -o jsonpath='{.spec.noProxy}' 2>/dev/null)"; if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; + if [ "main" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch main"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch --branch main --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch ${BRANCH} --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; - name: test image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -653,6 +705,14 @@ spec: - name: values-volume mountPath: /values/values.yaml subPath: values.yaml + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles containers: - name: "done" image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -669,6 +729,19 @@ spec: - name: values-volume configMap: name: helm-values-configmap-datacenter + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle + - name: ca-bundles + emptyDir: {} restartPolicy: Never --- # Source: clustergroup/templates/imperative/unsealjob.yaml @@ -692,6 +765,27 @@ spec: 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: fetch-ca + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + imagePullPolicy: Always + env: + - name: HOME + value: /git/home + command: + - 'sh' + - '-c' + - >- + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true; + ls -l /tmp/ca-bundles/ + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles - name: git-init image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest imagePullPolicy: Always @@ -701,6 +795,8 @@ spec: volumeMounts: - name: git mountPath: "/git" + - name: ca-bundles + mountPath: /etc/pki/tls/certs command: - 'sh' - '-c' @@ -727,8 +823,9 @@ spec: if [ -n "${OUT}" ]; then export HTTPS_PROXY="${OUT}"; fi; OUT="$(oc get proxy.config.openshift.io/cluster -o jsonpath='{.spec.noProxy}' 2>/dev/null)"; if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; + if [ "main" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch main"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch --branch main --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch ${BRANCH} --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; - name: unseal-playbook image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -754,6 +851,14 @@ spec: - name: values-volume mountPath: /values/values.yaml subPath: values.yaml + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles containers: - name: "done" image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -770,6 +875,19 @@ spec: - name: values-volume configMap: name: helm-values-configmap-datacenter + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle + - name: ca-bundles + emptyDir: {} restartPolicy: Never --- # Source: clustergroup/templates/core/subscriptions.yaml @@ -891,9 +1009,9 @@ spec: - "/values-4.12-datacenter.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -906,6 +1024,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -958,9 +1082,9 @@ spec: - "/values-4.12-datacenter.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -973,6 +1097,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1016,9 +1146,9 @@ spec: - "/values-4.12-datacenter.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1031,6 +1161,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1074,9 +1210,9 @@ spec: - "/values-4.12-datacenter.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1089,6 +1225,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1162,9 +1304,9 @@ spec: - "/values-4.12-datacenter.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1177,6 +1319,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1220,9 +1368,9 @@ spec: - "/values-4.12-datacenter.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1235,6 +1383,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1305,9 +1459,9 @@ spec: - "/values-4.12-datacenter.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1320,6 +1474,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1385,6 +1545,7 @@ spec: hs.message = "Waiting for PVC" return hs + resourceTrackingMethod: label applicationInstanceLabelKey: argocd.argoproj.io/instance applicationSet: resources: @@ -1418,6 +1579,47 @@ spec: rbac: defaultPolicy: role:admin repo: + initContainers: + - command: + - bash + - -c + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + name: fetch-ca + resources: {} + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 250m + memory: 256Mi + volumeMounts: + - mountPath: /etc/pki/tls/certs + name: ca-bundles + volumes: + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle + - emptyDir: {} + name: ca-bundles sidecarContainers: - name: helm-with-kustomize command: [/var/run/argocd/argocd-cmp-server] @@ -1451,7 +1653,7 @@ spec: requests: cpu: 250m memory: 256Mi - resourceExclusions: | + resourceExclusions: | - apiGroups: - tekton.dev kinds: diff --git a/tests/common-clustergroup-medical-diagnosis-hub.expected.yaml b/tests/common-clustergroup-medical-diagnosis-hub.expected.yaml index d6496a85..0af485db 100644 --- a/tests/common-clustergroup-medical-diagnosis-hub.expected.yaml +++ b/tests/common-clustergroup-medical-diagnosis-hub.expected.yaml @@ -225,6 +225,33 @@ data: argoCD: configManagementPlugins: [] initContainers: [] + resourceExclusions: | + - apiGroups: + - tekton.dev + kinds: + - TaskRun + - PipelineRun + resourceHealthChecks: + - check: | + hs = {} + if obj.status ~= nil then + if obj.status.phase ~= nil then + if obj.status.phase == "Pending" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + elseif obj.status.phase == "Bound" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + end + end + end + hs.status = "Progressing" + hs.message = "Waiting for PVC" + return hs + kind: PersistentVolumeClaim + resourceTrackingMethod: label imperative: activeDeadlineSeconds: 3600 adminClusterRoleName: imperative-admin-cluster-role @@ -270,6 +297,7 @@ data: - staging - vault - golang-external-secrets + nodes: [] projects: - hub - medical-diagnosis @@ -520,6 +548,27 @@ spec: 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: fetch-ca + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + imagePullPolicy: Always + env: + - name: HOME + value: /git/home + command: + - 'sh' + - '-c' + - >- + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true; + ls -l /tmp/ca-bundles/ + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles - name: git-init image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest imagePullPolicy: Always @@ -529,6 +578,8 @@ spec: volumeMounts: - name: git mountPath: "/git" + - name: ca-bundles + mountPath: /etc/pki/tls/certs command: - 'sh' - '-c' @@ -555,8 +606,9 @@ spec: if [ -n "${OUT}" ]; then export HTTPS_PROXY="${OUT}"; fi; OUT="$(oc get proxy.config.openshift.io/cluster -o jsonpath='{.spec.noProxy}' 2>/dev/null)"; if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; + if [ "main" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch main"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch --branch main --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch ${BRANCH} --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; - name: test image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -580,6 +632,14 @@ spec: - name: values-volume mountPath: /values/values.yaml subPath: values.yaml + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles containers: - name: "done" image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -596,6 +656,19 @@ spec: - name: values-volume configMap: name: helm-values-configmap-hub + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle + - name: ca-bundles + emptyDir: {} restartPolicy: Never --- # Source: clustergroup/templates/imperative/unsealjob.yaml @@ -619,6 +692,27 @@ spec: 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: fetch-ca + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + imagePullPolicy: Always + env: + - name: HOME + value: /git/home + command: + - 'sh' + - '-c' + - >- + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true; + ls -l /tmp/ca-bundles/ + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles - name: git-init image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest imagePullPolicy: Always @@ -628,6 +722,8 @@ spec: volumeMounts: - name: git mountPath: "/git" + - name: ca-bundles + mountPath: /etc/pki/tls/certs command: - 'sh' - '-c' @@ -654,8 +750,9 @@ spec: if [ -n "${OUT}" ]; then export HTTPS_PROXY="${OUT}"; fi; OUT="$(oc get proxy.config.openshift.io/cluster -o jsonpath='{.spec.noProxy}' 2>/dev/null)"; if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; + if [ "main" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch main"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch --branch main --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch ${BRANCH} --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; - name: unseal-playbook image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -681,6 +778,14 @@ spec: - name: values-volume mountPath: /values/values.yaml subPath: values.yaml + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles containers: - name: "done" image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -697,6 +802,19 @@ spec: - name: values-volume configMap: name: helm-values-configmap-hub + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle + - name: ca-bundles + emptyDir: {} restartPolicy: Never --- # Source: clustergroup/templates/core/subscriptions.yaml @@ -776,9 +894,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -791,6 +909,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -834,9 +958,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -849,6 +973,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -892,9 +1022,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -907,6 +1037,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -950,9 +1086,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -965,6 +1101,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1008,9 +1150,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1023,6 +1165,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1066,9 +1214,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1081,6 +1229,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1124,9 +1278,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1139,6 +1293,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1182,9 +1342,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1197,6 +1357,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1258,9 +1424,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1273,6 +1439,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1316,9 +1488,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1331,6 +1503,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1374,9 +1552,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1389,6 +1567,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1441,9 +1625,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1456,6 +1640,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1508,9 +1698,9 @@ spec: - "/values-4.12-hub.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -1523,6 +1713,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1570,6 +1766,7 @@ spec: hs.message = "Waiting for PVC" return hs + resourceTrackingMethod: label applicationInstanceLabelKey: argocd.argoproj.io/instance applicationSet: resources: @@ -1603,6 +1800,47 @@ spec: rbac: defaultPolicy: role:admin repo: + initContainers: + - command: + - bash + - -c + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + name: fetch-ca + resources: {} + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 250m + memory: 256Mi + volumeMounts: + - mountPath: /etc/pki/tls/certs + name: ca-bundles + volumes: + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle + - emptyDir: {} + name: ca-bundles resources: limits: cpu: "1" @@ -1610,7 +1848,7 @@ spec: requests: cpu: 250m memory: 256Mi - resourceExclusions: | + resourceExclusions: | - apiGroups: - tekton.dev kinds: diff --git a/tests/common-clustergroup-naked.expected.yaml b/tests/common-clustergroup-naked.expected.yaml index a7fee415..7a9f94b2 100644 --- a/tests/common-clustergroup-naked.expected.yaml +++ b/tests/common-clustergroup-naked.expected.yaml @@ -48,6 +48,33 @@ data: argoCD: configManagementPlugins: [] initContainers: [] + resourceExclusions: | + - apiGroups: + - tekton.dev + kinds: + - TaskRun + - PipelineRun + resourceHealthChecks: + - check: | + hs = {} + if obj.status ~= nil then + if obj.status.phase ~= nil then + if obj.status.phase == "Pending" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + elseif obj.status.phase == "Bound" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + end + end + end + hs.status = "Progressing" + hs.message = "Waiting for PVC" + return hs + kind: PersistentVolumeClaim + resourceTrackingMethod: label imperative: activeDeadlineSeconds: 3600 adminClusterRoleName: imperative-admin-cluster-role @@ -73,6 +100,7 @@ data: managedClusterGroups: {} name: example namespaces: [] + nodes: [] projects: [] sharedValueFiles: [] subscriptions: {} @@ -270,6 +298,27 @@ spec: 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: fetch-ca + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + imagePullPolicy: Always + env: + - name: HOME + value: /git/home + command: + - 'sh' + - '-c' + - >- + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true; + ls -l /tmp/ca-bundles/ + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles - name: git-init image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest imagePullPolicy: Always @@ -279,6 +328,8 @@ spec: volumeMounts: - name: git mountPath: "/git" + - name: ca-bundles + mountPath: /etc/pki/tls/certs command: - 'sh' - '-c' @@ -305,8 +356,9 @@ spec: if [ -n "${OUT}" ]; then export HTTPS_PROXY="${OUT}"; fi; OUT="$(oc get proxy.config.openshift.io/cluster -o jsonpath='{.spec.noProxy}' 2>/dev/null)"; if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; + if [ "main" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch main"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch --branch main --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch ${BRANCH} --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; - name: unseal-playbook image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -332,6 +384,14 @@ spec: - name: values-volume mountPath: /values/values.yaml subPath: values.yaml + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles containers: - name: "done" image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -348,6 +408,19 @@ spec: - name: values-volume configMap: name: helm-values-configmap-example + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle + - name: ca-bundles + emptyDir: {} restartPolicy: Never --- # Source: clustergroup/templates/plumbing/argocd.yaml @@ -386,6 +459,7 @@ spec: hs.message = "Waiting for PVC" return hs + resourceTrackingMethod: label applicationInstanceLabelKey: argocd.argoproj.io/instance applicationSet: resources: @@ -419,6 +493,47 @@ spec: rbac: defaultPolicy: role:admin repo: + initContainers: + - command: + - bash + - -c + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + name: fetch-ca + resources: {} + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 250m + memory: 256Mi + volumeMounts: + - mountPath: /etc/pki/tls/certs + name: ca-bundles + volumes: + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle + - emptyDir: {} + name: ca-bundles resources: limits: cpu: "1" @@ -426,7 +541,7 @@ spec: requests: cpu: 250m memory: 256Mi - resourceExclusions: | + resourceExclusions: | - apiGroups: - tekton.dev kinds: diff --git a/tests/common-clustergroup-normal.expected.yaml b/tests/common-clustergroup-normal.expected.yaml index 2fca5174..70b29c07 100644 --- a/tests/common-clustergroup-normal.expected.yaml +++ b/tests/common-clustergroup-normal.expected.yaml @@ -133,6 +133,33 @@ data: argoCD: configManagementPlugins: [] initContainers: [] + resourceExclusions: | + - apiGroups: + - tekton.dev + kinds: + - TaskRun + - PipelineRun + resourceHealthChecks: + - check: | + hs = {} + if obj.status ~= nil then + if obj.status.phase ~= nil then + if obj.status.phase == "Pending" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + elseif obj.status.phase == "Bound" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + end + end + end + hs.status = "Progressing" + hs.message = "Waiting for PVC" + return hs + kind: PersistentVolumeClaim + resourceTrackingMethod: label imperative: activeDeadlineSeconds: 3600 adminClusterRoleName: imperative-admin-cluster-role @@ -170,6 +197,14 @@ data: - acmlabels: - name: clusterGroup value: region + clusterDeployments: + myFirstCluster: + baseDomain: blueprints.rhecoeng.com + name: aws-cd-one-w-pool + openshiftVersion: 4.10.18 + platform: + aws: + region: ap-southeast-1 clusterPools: exampleAWSPool: baseDomain: blueprints.rhecoeng.com @@ -202,6 +237,15 @@ data: value: "false" name: acm-provision-edge targetRevision: main + - clusterDeployments: + mySecondCluster: + baseDomain: blueprints.rhecoeng.com + name: aws-cd-two-wo-pool + openshiftVersion: 4.10.18 + platform: + aws: + region: ap-southeast-3 + name: acm-provision-on-deploy - helmOverrides: - name: clusterGroup.isHubCluster value: "false" @@ -234,10 +278,22 @@ data: operatorGroup: false - include-default-og: operatorGroup: true + nodes: + - m-m00.cluster.example.tld: + labels: + cluster.ocs.openshift.io/openshift-storage: "" + - m-m01.cluster.example.tld: + labels: + cluster.ocs.openshift.io/openshift-storage: "" + - m-m02.cluster.example.tld: + labels: + cluster.ocs.openshift.io/openshift-storage: "" operatorgroupExcludes: - exclude-og projects: - datacenter + scheduler: + mastersSchedulable: true sharedValueFiles: - /values/aws.yaml - /values/4.12.yaml @@ -482,6 +538,27 @@ spec: 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: fetch-ca + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + imagePullPolicy: Always + env: + - name: HOME + value: /git/home + command: + - 'sh' + - '-c' + - >- + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true; + ls -l /tmp/ca-bundles/ + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles - name: git-init image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest imagePullPolicy: Always @@ -491,6 +568,8 @@ spec: volumeMounts: - name: git mountPath: "/git" + - name: ca-bundles + mountPath: /etc/pki/tls/certs command: - 'sh' - '-c' @@ -517,8 +596,9 @@ spec: if [ -n "${OUT}" ]; then export HTTPS_PROXY="${OUT}"; fi; OUT="$(oc get proxy.config.openshift.io/cluster -o jsonpath='{.spec.noProxy}' 2>/dev/null)"; if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; + if [ "main" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch main"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch --branch main --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch ${BRANCH} --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; - name: test image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -542,6 +622,14 @@ spec: - name: values-volume mountPath: /values/values.yaml subPath: values.yaml + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles containers: - name: "done" image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -558,6 +646,19 @@ spec: - name: values-volume configMap: name: helm-values-configmap-example + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle + - name: ca-bundles + emptyDir: {} restartPolicy: Never --- # Source: clustergroup/templates/imperative/unsealjob.yaml @@ -581,6 +682,27 @@ spec: 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: fetch-ca + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + imagePullPolicy: Always + env: + - name: HOME + value: /git/home + command: + - 'sh' + - '-c' + - >- + cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true; + ls -l /tmp/ca-bundles/ + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles - name: git-init image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest imagePullPolicy: Always @@ -590,6 +712,8 @@ spec: volumeMounts: - name: git mountPath: "/git" + - name: ca-bundles + mountPath: /etc/pki/tls/certs command: - 'sh' - '-c' @@ -616,8 +740,9 @@ spec: if [ -n "${OUT}" ]; then export HTTPS_PROXY="${OUT}"; fi; OUT="$(oc get proxy.config.openshift.io/cluster -o jsonpath='{.spec.noProxy}' 2>/dev/null)"; if [ -n "${OUT}" ]; then export NO_PROXY="${OUT}"; fi; + if [ "main" = "HEAD" ]; then BRANCH=""; else BRANCH="--branch main"; fi; mkdir /git/{repo,home}; - git clone --recurse-submodules --single-branch --branch main --depth 1 -- "${URL}" /git/repo; + git clone --recurse-submodules --single-branch ${BRANCH} --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; - name: unseal-playbook image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -643,6 +768,14 @@ spec: - name: values-volume mountPath: /values/values.yaml subPath: values.yaml + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles containers: - name: "done" image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest @@ -659,6 +792,19 @@ spec: - name: values-volume configMap: name: helm-values-configmap-example + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle + - name: ca-bundles + emptyDir: {} restartPolicy: Never --- # Source: clustergroup/templates/core/operatorgroup.yaml @@ -743,9 +889,9 @@ spec: - "/values/4.12.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -758,6 +904,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -813,9 +965,9 @@ spec: - "/values/4.12/aws.yaml" parameters: - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL + value: https://github.com/pattern-clone/mypattern - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION + value: main - name: global.namespace value: $ARGOCD_APP_NAMESPACE - name: global.pattern @@ -828,6 +980,12 @@ spec: value: "aws" - name: global.hubClusterDomain value: apps.hub.example.com + - name: global.multiSourceSupport + value: + - name: global.multiSourceRepoUrl + value: + - name: global.multiSourceTargetRevision + value: - name: global.localClusterDomain value: apps.region.example.com - name: global.privateRepo @@ -1115,6 +1273,7 @@ spec: hs.message = "Waiting for PVC" return hs + resourceTrackingMethod: label applicationInstanceLabelKey: argocd.argoproj.io/instance applicationSet: resources: @@ -1148,6 +1307,47 @@ spec: rbac: defaultPolicy: role:admin repo: + initContainers: + - command: + - bash + - -c + - cat /var/run/kube-root-ca/ca.crt /var/run/trusted-ca/ca-bundle.crt /var/run/trusted-hub/hub-kube-root-ca.crt > /tmp/ca-bundles/ca-bundle.crt || true + image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest + name: fetch-ca + resources: {} + volumeMounts: + - mountPath: /var/run/kube-root-ca + name: kube-root-ca + - mountPath: /var/run/trusted-ca + name: trusted-ca-bundle + - mountPath: /var/run/trusted-hub + name: trusted-hub-bundle + - mountPath: /tmp/ca-bundles + name: ca-bundles + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 250m + memory: 256Mi + volumeMounts: + - mountPath: /etc/pki/tls/certs + name: ca-bundles + volumes: + - configMap: + name: kube-root-ca.crt + name: kube-root-ca + - configMap: + name: trusted-ca-bundle + optional: true + name: trusted-ca-bundle + - configMap: + name: trusted-hub-bundle + optional: true + name: trusted-hub-bundle + - emptyDir: {} + name: ca-bundles resources: limits: cpu: "1" @@ -1155,7 +1355,7 @@ spec: requests: cpu: 250m memory: 256Mi - resourceExclusions: | + resourceExclusions: | - apiGroups: - tekton.dev kinds: @@ -1201,6 +1401,33 @@ spec: location: ApplicationMenu text: 'Example ArgoCD' --- +# Source: clustergroup/templates/core/nodes.yaml +apiVersion: v1 +kind: Node +metadata: + name: m-m00.cluster.example.tld + labels: + argocd.argoproj.io/managed-by: mypattern-example + cluster.ocs.openshift.io/openshift-storage: "" +--- +# Source: clustergroup/templates/core/nodes.yaml +apiVersion: v1 +kind: Node +metadata: + name: m-m01.cluster.example.tld + labels: + argocd.argoproj.io/managed-by: mypattern-example + cluster.ocs.openshift.io/openshift-storage: "" +--- +# Source: clustergroup/templates/core/nodes.yaml +apiVersion: v1 +kind: Node +metadata: + name: m-m02.cluster.example.tld + labels: + argocd.argoproj.io/managed-by: mypattern-example + cluster.ocs.openshift.io/openshift-storage: "" +--- # Source: clustergroup/templates/core/operatorgroup.yaml --- apiVersion: operators.coreos.com/v1 @@ -1220,8 +1447,6 @@ kind: OperatorGroup metadata: name: exclude-targetns-operator-group namespace: exclude-targetns -spec: - targetNamespaces: --- # Source: clustergroup/templates/core/operatorgroup.yaml --- @@ -1244,6 +1469,14 @@ spec: targetNamespaces: - include-default-og --- +# Source: clustergroup/templates/core/scheduler.yaml +apiVersion: config.openshift.io/v1 +kind: Scheduler +metadata: + name: cluster +spec: + mastersSchedulable: true +--- # Source: clustergroup/templates/core/subscriptions.yaml apiVersion: operators.coreos.com/v1alpha1 kind: Subscription diff --git a/tests/common-golang-external-secrets-industrial-edge-factory.expected.yaml b/tests/common-golang-external-secrets-industrial-edge-factory.expected.yaml index 2a9621a7..66b23292 100644 --- a/tests/common-golang-external-secrets-industrial-edge-factory.expected.yaml +++ b/tests/common-golang-external-secrets-industrial-edge-factory.expected.yaml @@ -6,10 +6,10 @@ metadata: name: external-secrets-cert-controller namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm --- # Source: golang-external-secrets/charts/external-secrets/templates/serviceaccount.yaml @@ -19,10 +19,10 @@ metadata: name: common-golang-external-secrets namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm --- # Source: golang-external-secrets/charts/external-secrets/templates/webhook-serviceaccount.yaml @@ -32,10 +32,10 @@ metadata: name: external-secrets-webhook namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm --- # Source: golang-external-secrets/charts/external-secrets/templates/webhook-secret.yaml @@ -45,10 +45,10 @@ metadata: name: common-golang-external-secrets-webhook namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm external-secrets.io/component: webhook --- @@ -68,6 +68,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: acraccesstokens.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -264,6 +266,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: clusterexternalsecrets.external-secrets.io spec: group: external-secrets.io @@ -921,6 +925,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: clustersecretstores.external-secrets.io spec: group: external-secrets.io @@ -2461,6 +2467,11 @@ spec: ClusterSecretStoreCondition describes a condition by which to choose namespaces to process ExternalSecrets in for a ClusterSecretStore instance. properties: + namespaceRegexes: + description: Choose namespaces by using regex matching + items: + type: string + type: array namespaceSelector: description: Choose namespace using a labelSelector properties: @@ -3057,6 +3068,63 @@ spec: required: - vaultUrl type: object + bitwardensecretsmanager: + description: BitwardenSecretsManager configures this store to sync secrets using BitwardenSecretsManager provider + properties: + apiURL: + type: string + auth: + description: |- + Auth configures how secret-manager authenticates with a bitwarden machine account instance. + Make sure that the token being used has permissions on the given secret. + properties: + secretRef: + description: BitwardenSecretsManagerSecretRef contains the credential ref to the bitwarden instance. + properties: + credentials: + description: AccessToken used for the bitwarden instance. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + required: + - credentials + type: object + required: + - secretRef + type: object + bitwardenServerSDKURL: + type: string + caBundle: + description: |- + Base64 encoded certificate for the bitwarden server sdk. The sdk MUST run with HTTPS to make sure no MITM attack + can be performed. + type: string + identityURL: + type: string + organizationID: + description: OrganizationID determines which organization this secret store manages. + type: string + projectID: + description: ProjectID determines which project this secret store manages. + type: string + required: + - auth + - caBundle + - organizationID + - projectID + type: object chef: description: Chef configures this store to sync secrets with chef server properties: @@ -3318,6 +3386,42 @@ spec: - clientSecret - tenant type: object + device42: + description: Device42 configures this store to sync secrets using the Device42 provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a Device42 instance. + properties: + secretRef: + properties: + credentials: + description: Username / Password is used for authentication. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + type: object + required: + - secretRef + type: object + host: + description: URL configures the Device42 instance URL. + type: string + required: + - auth + - host + type: object doppler: description: Doppler configures this store to sync secrets using the Doppler provider properties: @@ -3494,6 +3598,9 @@ spec: - serviceAccountRef type: object type: object + location: + description: Location optionally defines a location for a secret + type: string projectID: description: ProjectID project where secret is located type: string @@ -3596,6 +3703,77 @@ spec: required: - auth type: object + infisical: + description: Infisical configures this store to sync secrets using the Infisical provider + properties: + auth: + description: Auth configures how the Operator authenticates with the Infisical API + properties: + universalAuthCredentials: + properties: + clientId: + description: |- + A reference to a specific 'key' within a Secret resource, + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + clientSecret: + description: |- + A reference to a specific 'key' within a Secret resource, + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + required: + - clientId + - clientSecret + type: object + type: object + hostAPI: + default: https://app.infisical.com/api + type: string + secretsScope: + properties: + environmentSlug: + type: string + projectSlug: + type: string + secretsPath: + default: / + type: string + required: + - environmentSlug + - projectSlug + type: object + required: + - auth + - secretsScope + type: object keepersecurity: description: KeeperSecurity configures this store to sync secrets using the KeeperSecurity provider properties: @@ -3720,6 +3898,23 @@ spec: type: object type: object type: object + authRef: + description: A reference to a secret that contains the auth information. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object remoteNamespace: default: default description: Remote namespace to fetch the secrets from @@ -3760,8 +3955,6 @@ spec: description: configures the Kubernetes server Address. type: string type: object - required: - - auth type: object onboardbase: description: Onboardbase configures this store to sync secrets using the Onboardbase provider @@ -5103,6 +5296,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: ecrauthorizationtokens.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -5270,6 +5465,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: externalsecrets.external-secrets.io spec: group: external-secrets.io @@ -5510,10 +5707,15 @@ spec: description: Binding represents a servicebinding.io Provisioned Service reference to the secret properties: name: + default: "" description: |- Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. TODO: Add other useful fields. apiVersion, kind, uid? + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -6016,10 +6218,15 @@ spec: description: Binding represents a servicebinding.io Provisioned Service reference to the secret properties: name: + default: "" description: |- Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. TODO: Add other useful fields. apiVersion, kind, uid? + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -6075,6 +6282,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: fakes.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -6151,6 +6360,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: gcraccesstokens.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -6279,6 +6490,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: githubaccesstokens.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -6322,7 +6535,7 @@ spec: auth: description: Auth configures how ESO authenticates with a Github instance. properties: - privatKey: + privateKey: properties: secretRef: description: |- @@ -6347,7 +6560,7 @@ spec: - secretRef type: object required: - - privatKey + - privateKey type: object installID: type: string @@ -6381,6 +6594,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: passwords.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -6857,6 +7072,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: secretstores.external-secrets.io spec: group: external-secrets.io @@ -8397,6 +8614,11 @@ spec: ClusterSecretStoreCondition describes a condition by which to choose namespaces to process ExternalSecrets in for a ClusterSecretStore instance. properties: + namespaceRegexes: + description: Choose namespaces by using regex matching + items: + type: string + type: array namespaceSelector: description: Choose namespace using a labelSelector properties: @@ -8993,6 +9215,63 @@ spec: required: - vaultUrl type: object + bitwardensecretsmanager: + description: BitwardenSecretsManager configures this store to sync secrets using BitwardenSecretsManager provider + properties: + apiURL: + type: string + auth: + description: |- + Auth configures how secret-manager authenticates with a bitwarden machine account instance. + Make sure that the token being used has permissions on the given secret. + properties: + secretRef: + description: BitwardenSecretsManagerSecretRef contains the credential ref to the bitwarden instance. + properties: + credentials: + description: AccessToken used for the bitwarden instance. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + required: + - credentials + type: object + required: + - secretRef + type: object + bitwardenServerSDKURL: + type: string + caBundle: + description: |- + Base64 encoded certificate for the bitwarden server sdk. The sdk MUST run with HTTPS to make sure no MITM attack + can be performed. + type: string + identityURL: + type: string + organizationID: + description: OrganizationID determines which organization this secret store manages. + type: string + projectID: + description: ProjectID determines which project this secret store manages. + type: string + required: + - auth + - caBundle + - organizationID + - projectID + type: object chef: description: Chef configures this store to sync secrets with chef server properties: @@ -9254,6 +9533,42 @@ spec: - clientSecret - tenant type: object + device42: + description: Device42 configures this store to sync secrets using the Device42 provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a Device42 instance. + properties: + secretRef: + properties: + credentials: + description: Username / Password is used for authentication. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + type: object + required: + - secretRef + type: object + host: + description: URL configures the Device42 instance URL. + type: string + required: + - auth + - host + type: object doppler: description: Doppler configures this store to sync secrets using the Doppler provider properties: @@ -9430,6 +9745,9 @@ spec: - serviceAccountRef type: object type: object + location: + description: Location optionally defines a location for a secret + type: string projectID: description: ProjectID project where secret is located type: string @@ -9532,6 +9850,77 @@ spec: required: - auth type: object + infisical: + description: Infisical configures this store to sync secrets using the Infisical provider + properties: + auth: + description: Auth configures how the Operator authenticates with the Infisical API + properties: + universalAuthCredentials: + properties: + clientId: + description: |- + A reference to a specific 'key' within a Secret resource, + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + clientSecret: + description: |- + A reference to a specific 'key' within a Secret resource, + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + required: + - clientId + - clientSecret + type: object + type: object + hostAPI: + default: https://app.infisical.com/api + type: string + secretsScope: + properties: + environmentSlug: + type: string + projectSlug: + type: string + secretsPath: + default: / + type: string + required: + - environmentSlug + - projectSlug + type: object + required: + - auth + - secretsScope + type: object keepersecurity: description: KeeperSecurity configures this store to sync secrets using the KeeperSecurity provider properties: @@ -9656,6 +10045,23 @@ spec: type: object type: object type: object + authRef: + description: A reference to a secret that contains the auth information. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object remoteNamespace: default: default description: Remote namespace to fetch the secrets from @@ -9696,8 +10102,6 @@ spec: description: configures the Kubernetes server Address. type: string type: object - required: - - auth type: object onboardbase: description: Onboardbase configures this store to sync secrets using the Onboardbase provider @@ -11039,6 +11443,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: vaultdynamicsecrets.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -11731,6 +12137,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: webhooks.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -11878,10 +12286,10 @@ kind: ClusterRole metadata: name: common-golang-external-secrets-cert-controller labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rules: - apiGroups: @@ -11945,10 +12353,10 @@ kind: ClusterRole metadata: name: common-golang-external-secrets-controller labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rules: - apiGroups: @@ -11982,6 +12390,7 @@ rules: - "pushsecrets/status" - "pushsecrets/finalizers" verbs: + - "get" - "update" - "patch" - apiGroups: @@ -12056,10 +12465,10 @@ kind: ClusterRole metadata: name: common-golang-external-secrets-view labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rbac.authorization.k8s.io/aggregate-to-view: "true" rbac.authorization.k8s.io/aggregate-to-edit: "true" @@ -12098,10 +12507,10 @@ kind: ClusterRole metadata: name: common-golang-external-secrets-edit labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rbac.authorization.k8s.io/aggregate-to-edit: "true" rbac.authorization.k8s.io/aggregate-to-admin: "true" @@ -12144,10 +12553,10 @@ metadata: name: common-golang-external-secrets-servicebindings labels: servicebinding.io/controller: "true" - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rules: - apiGroups: @@ -12165,10 +12574,10 @@ kind: ClusterRoleBinding metadata: name: common-golang-external-secrets-cert-controller labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io @@ -12185,10 +12594,10 @@ kind: ClusterRoleBinding metadata: name: common-golang-external-secrets-controller labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io @@ -12221,10 +12630,10 @@ metadata: name: common-golang-external-secrets-leaderelection namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rules: - apiGroups: @@ -12260,10 +12669,10 @@ metadata: name: common-golang-external-secrets-leaderelection namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io @@ -12281,10 +12690,10 @@ metadata: name: common-golang-external-secrets-webhook namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm external-secrets.io/component: webhook spec: @@ -12305,10 +12714,10 @@ metadata: name: common-golang-external-secrets-cert-controller namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: replicas: 1 @@ -12320,10 +12729,10 @@ spec: template: metadata: labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: serviceAccountName: external-secrets-cert-controller @@ -12338,7 +12747,7 @@ spec: - ALL readOnlyRootFilesystem: true runAsNonRoot: true - image: ghcr.io/external-secrets/external-secrets:v0.9.18-ubi + image: ghcr.io/external-secrets/external-secrets:v0.9.20-ubi imagePullPolicy: IfNotPresent args: - certcontroller @@ -12349,7 +12758,9 @@ spec: - --secret-namespace=default - --metrics-addr=:8080 - --healthz-addr=:8081 - + - --loglevel=info + - --zap-time-encoding=epoch + - --enable-partial-cache=true ports: - containerPort: 8080 protocol: TCP @@ -12368,10 +12779,10 @@ metadata: name: common-golang-external-secrets namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: replicas: 1 @@ -12383,10 +12794,10 @@ spec: template: metadata: labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: serviceAccountName: common-golang-external-secrets @@ -12401,11 +12812,13 @@ spec: - ALL readOnlyRootFilesystem: true runAsNonRoot: true - image: ghcr.io/external-secrets/external-secrets:v0.9.18-ubi + image: ghcr.io/external-secrets/external-secrets:v0.9.20-ubi imagePullPolicy: IfNotPresent args: - --concurrent=1 - --metrics-addr=:8080 + - --loglevel=info + - --zap-time-encoding=epoch ports: - containerPort: 8080 protocol: TCP @@ -12419,10 +12832,10 @@ metadata: name: common-golang-external-secrets-webhook namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: replicas: 1 @@ -12434,10 +12847,10 @@ spec: template: metadata: labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: hostNetwork: false @@ -12452,7 +12865,7 @@ spec: - ALL readOnlyRootFilesystem: true runAsNonRoot: true - image: ghcr.io/external-secrets/external-secrets:v0.9.18-ubi + image: ghcr.io/external-secrets/external-secrets:v0.9.20-ubi imagePullPolicy: IfNotPresent args: - webhook @@ -12462,6 +12875,8 @@ spec: - --check-interval=5m - --metrics-addr=:8080 - --healthz-addr=:8081 + - --loglevel=info + - --zap-time-encoding=epoch ports: - containerPort: 8080 protocol: TCP diff --git a/tests/common-golang-external-secrets-industrial-edge-hub.expected.yaml b/tests/common-golang-external-secrets-industrial-edge-hub.expected.yaml index 2f0b9ac3..b7c2ad96 100644 --- a/tests/common-golang-external-secrets-industrial-edge-hub.expected.yaml +++ b/tests/common-golang-external-secrets-industrial-edge-hub.expected.yaml @@ -6,10 +6,10 @@ metadata: name: external-secrets-cert-controller namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm --- # Source: golang-external-secrets/charts/external-secrets/templates/serviceaccount.yaml @@ -19,10 +19,10 @@ metadata: name: common-golang-external-secrets namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm --- # Source: golang-external-secrets/charts/external-secrets/templates/webhook-serviceaccount.yaml @@ -32,10 +32,10 @@ metadata: name: external-secrets-webhook namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm --- # Source: golang-external-secrets/charts/external-secrets/templates/webhook-secret.yaml @@ -45,10 +45,10 @@ metadata: name: common-golang-external-secrets-webhook namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm external-secrets.io/component: webhook --- @@ -68,6 +68,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: acraccesstokens.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -264,6 +266,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: clusterexternalsecrets.external-secrets.io spec: group: external-secrets.io @@ -921,6 +925,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: clustersecretstores.external-secrets.io spec: group: external-secrets.io @@ -2461,6 +2467,11 @@ spec: ClusterSecretStoreCondition describes a condition by which to choose namespaces to process ExternalSecrets in for a ClusterSecretStore instance. properties: + namespaceRegexes: + description: Choose namespaces by using regex matching + items: + type: string + type: array namespaceSelector: description: Choose namespace using a labelSelector properties: @@ -3057,6 +3068,63 @@ spec: required: - vaultUrl type: object + bitwardensecretsmanager: + description: BitwardenSecretsManager configures this store to sync secrets using BitwardenSecretsManager provider + properties: + apiURL: + type: string + auth: + description: |- + Auth configures how secret-manager authenticates with a bitwarden machine account instance. + Make sure that the token being used has permissions on the given secret. + properties: + secretRef: + description: BitwardenSecretsManagerSecretRef contains the credential ref to the bitwarden instance. + properties: + credentials: + description: AccessToken used for the bitwarden instance. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + required: + - credentials + type: object + required: + - secretRef + type: object + bitwardenServerSDKURL: + type: string + caBundle: + description: |- + Base64 encoded certificate for the bitwarden server sdk. The sdk MUST run with HTTPS to make sure no MITM attack + can be performed. + type: string + identityURL: + type: string + organizationID: + description: OrganizationID determines which organization this secret store manages. + type: string + projectID: + description: ProjectID determines which project this secret store manages. + type: string + required: + - auth + - caBundle + - organizationID + - projectID + type: object chef: description: Chef configures this store to sync secrets with chef server properties: @@ -3318,6 +3386,42 @@ spec: - clientSecret - tenant type: object + device42: + description: Device42 configures this store to sync secrets using the Device42 provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a Device42 instance. + properties: + secretRef: + properties: + credentials: + description: Username / Password is used for authentication. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + type: object + required: + - secretRef + type: object + host: + description: URL configures the Device42 instance URL. + type: string + required: + - auth + - host + type: object doppler: description: Doppler configures this store to sync secrets using the Doppler provider properties: @@ -3494,6 +3598,9 @@ spec: - serviceAccountRef type: object type: object + location: + description: Location optionally defines a location for a secret + type: string projectID: description: ProjectID project where secret is located type: string @@ -3596,6 +3703,77 @@ spec: required: - auth type: object + infisical: + description: Infisical configures this store to sync secrets using the Infisical provider + properties: + auth: + description: Auth configures how the Operator authenticates with the Infisical API + properties: + universalAuthCredentials: + properties: + clientId: + description: |- + A reference to a specific 'key' within a Secret resource, + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + clientSecret: + description: |- + A reference to a specific 'key' within a Secret resource, + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + required: + - clientId + - clientSecret + type: object + type: object + hostAPI: + default: https://app.infisical.com/api + type: string + secretsScope: + properties: + environmentSlug: + type: string + projectSlug: + type: string + secretsPath: + default: / + type: string + required: + - environmentSlug + - projectSlug + type: object + required: + - auth + - secretsScope + type: object keepersecurity: description: KeeperSecurity configures this store to sync secrets using the KeeperSecurity provider properties: @@ -3720,6 +3898,23 @@ spec: type: object type: object type: object + authRef: + description: A reference to a secret that contains the auth information. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object remoteNamespace: default: default description: Remote namespace to fetch the secrets from @@ -3760,8 +3955,6 @@ spec: description: configures the Kubernetes server Address. type: string type: object - required: - - auth type: object onboardbase: description: Onboardbase configures this store to sync secrets using the Onboardbase provider @@ -5103,6 +5296,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: ecrauthorizationtokens.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -5270,6 +5465,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: externalsecrets.external-secrets.io spec: group: external-secrets.io @@ -5510,10 +5707,15 @@ spec: description: Binding represents a servicebinding.io Provisioned Service reference to the secret properties: name: + default: "" description: |- Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. TODO: Add other useful fields. apiVersion, kind, uid? + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -6016,10 +6218,15 @@ spec: description: Binding represents a servicebinding.io Provisioned Service reference to the secret properties: name: + default: "" description: |- Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. TODO: Add other useful fields. apiVersion, kind, uid? + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -6075,6 +6282,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: fakes.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -6151,6 +6360,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: gcraccesstokens.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -6279,6 +6490,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: githubaccesstokens.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -6322,7 +6535,7 @@ spec: auth: description: Auth configures how ESO authenticates with a Github instance. properties: - privatKey: + privateKey: properties: secretRef: description: |- @@ -6347,7 +6560,7 @@ spec: - secretRef type: object required: - - privatKey + - privateKey type: object installID: type: string @@ -6381,6 +6594,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: passwords.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -6857,6 +7072,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: secretstores.external-secrets.io spec: group: external-secrets.io @@ -8397,6 +8614,11 @@ spec: ClusterSecretStoreCondition describes a condition by which to choose namespaces to process ExternalSecrets in for a ClusterSecretStore instance. properties: + namespaceRegexes: + description: Choose namespaces by using regex matching + items: + type: string + type: array namespaceSelector: description: Choose namespace using a labelSelector properties: @@ -8993,6 +9215,63 @@ spec: required: - vaultUrl type: object + bitwardensecretsmanager: + description: BitwardenSecretsManager configures this store to sync secrets using BitwardenSecretsManager provider + properties: + apiURL: + type: string + auth: + description: |- + Auth configures how secret-manager authenticates with a bitwarden machine account instance. + Make sure that the token being used has permissions on the given secret. + properties: + secretRef: + description: BitwardenSecretsManagerSecretRef contains the credential ref to the bitwarden instance. + properties: + credentials: + description: AccessToken used for the bitwarden instance. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + required: + - credentials + type: object + required: + - secretRef + type: object + bitwardenServerSDKURL: + type: string + caBundle: + description: |- + Base64 encoded certificate for the bitwarden server sdk. The sdk MUST run with HTTPS to make sure no MITM attack + can be performed. + type: string + identityURL: + type: string + organizationID: + description: OrganizationID determines which organization this secret store manages. + type: string + projectID: + description: ProjectID determines which project this secret store manages. + type: string + required: + - auth + - caBundle + - organizationID + - projectID + type: object chef: description: Chef configures this store to sync secrets with chef server properties: @@ -9254,6 +9533,42 @@ spec: - clientSecret - tenant type: object + device42: + description: Device42 configures this store to sync secrets using the Device42 provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a Device42 instance. + properties: + secretRef: + properties: + credentials: + description: Username / Password is used for authentication. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + type: object + required: + - secretRef + type: object + host: + description: URL configures the Device42 instance URL. + type: string + required: + - auth + - host + type: object doppler: description: Doppler configures this store to sync secrets using the Doppler provider properties: @@ -9430,6 +9745,9 @@ spec: - serviceAccountRef type: object type: object + location: + description: Location optionally defines a location for a secret + type: string projectID: description: ProjectID project where secret is located type: string @@ -9532,6 +9850,77 @@ spec: required: - auth type: object + infisical: + description: Infisical configures this store to sync secrets using the Infisical provider + properties: + auth: + description: Auth configures how the Operator authenticates with the Infisical API + properties: + universalAuthCredentials: + properties: + clientId: + description: |- + A reference to a specific 'key' within a Secret resource, + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + clientSecret: + description: |- + A reference to a specific 'key' within a Secret resource, + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + required: + - clientId + - clientSecret + type: object + type: object + hostAPI: + default: https://app.infisical.com/api + type: string + secretsScope: + properties: + environmentSlug: + type: string + projectSlug: + type: string + secretsPath: + default: / + type: string + required: + - environmentSlug + - projectSlug + type: object + required: + - auth + - secretsScope + type: object keepersecurity: description: KeeperSecurity configures this store to sync secrets using the KeeperSecurity provider properties: @@ -9656,6 +10045,23 @@ spec: type: object type: object type: object + authRef: + description: A reference to a secret that contains the auth information. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object remoteNamespace: default: default description: Remote namespace to fetch the secrets from @@ -9696,8 +10102,6 @@ spec: description: configures the Kubernetes server Address. type: string type: object - required: - - auth type: object onboardbase: description: Onboardbase configures this store to sync secrets using the Onboardbase provider @@ -11039,6 +11443,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: vaultdynamicsecrets.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -11731,6 +12137,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: webhooks.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -11878,10 +12286,10 @@ kind: ClusterRole metadata: name: common-golang-external-secrets-cert-controller labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rules: - apiGroups: @@ -11945,10 +12353,10 @@ kind: ClusterRole metadata: name: common-golang-external-secrets-controller labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rules: - apiGroups: @@ -11982,6 +12390,7 @@ rules: - "pushsecrets/status" - "pushsecrets/finalizers" verbs: + - "get" - "update" - "patch" - apiGroups: @@ -12056,10 +12465,10 @@ kind: ClusterRole metadata: name: common-golang-external-secrets-view labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rbac.authorization.k8s.io/aggregate-to-view: "true" rbac.authorization.k8s.io/aggregate-to-edit: "true" @@ -12098,10 +12507,10 @@ kind: ClusterRole metadata: name: common-golang-external-secrets-edit labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rbac.authorization.k8s.io/aggregate-to-edit: "true" rbac.authorization.k8s.io/aggregate-to-admin: "true" @@ -12144,10 +12553,10 @@ metadata: name: common-golang-external-secrets-servicebindings labels: servicebinding.io/controller: "true" - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rules: - apiGroups: @@ -12165,10 +12574,10 @@ kind: ClusterRoleBinding metadata: name: common-golang-external-secrets-cert-controller labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io @@ -12185,10 +12594,10 @@ kind: ClusterRoleBinding metadata: name: common-golang-external-secrets-controller labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io @@ -12221,10 +12630,10 @@ metadata: name: common-golang-external-secrets-leaderelection namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rules: - apiGroups: @@ -12260,10 +12669,10 @@ metadata: name: common-golang-external-secrets-leaderelection namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io @@ -12281,10 +12690,10 @@ metadata: name: common-golang-external-secrets-webhook namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm external-secrets.io/component: webhook spec: @@ -12305,10 +12714,10 @@ metadata: name: common-golang-external-secrets-cert-controller namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: replicas: 1 @@ -12320,10 +12729,10 @@ spec: template: metadata: labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: serviceAccountName: external-secrets-cert-controller @@ -12338,7 +12747,7 @@ spec: - ALL readOnlyRootFilesystem: true runAsNonRoot: true - image: ghcr.io/external-secrets/external-secrets:v0.9.18-ubi + image: ghcr.io/external-secrets/external-secrets:v0.9.20-ubi imagePullPolicy: IfNotPresent args: - certcontroller @@ -12349,7 +12758,9 @@ spec: - --secret-namespace=default - --metrics-addr=:8080 - --healthz-addr=:8081 - + - --loglevel=info + - --zap-time-encoding=epoch + - --enable-partial-cache=true ports: - containerPort: 8080 protocol: TCP @@ -12368,10 +12779,10 @@ metadata: name: common-golang-external-secrets namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: replicas: 1 @@ -12383,10 +12794,10 @@ spec: template: metadata: labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: serviceAccountName: common-golang-external-secrets @@ -12401,11 +12812,13 @@ spec: - ALL readOnlyRootFilesystem: true runAsNonRoot: true - image: ghcr.io/external-secrets/external-secrets:v0.9.18-ubi + image: ghcr.io/external-secrets/external-secrets:v0.9.20-ubi imagePullPolicy: IfNotPresent args: - --concurrent=1 - --metrics-addr=:8080 + - --loglevel=info + - --zap-time-encoding=epoch ports: - containerPort: 8080 protocol: TCP @@ -12419,10 +12832,10 @@ metadata: name: common-golang-external-secrets-webhook namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: replicas: 1 @@ -12434,10 +12847,10 @@ spec: template: metadata: labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: hostNetwork: false @@ -12452,7 +12865,7 @@ spec: - ALL readOnlyRootFilesystem: true runAsNonRoot: true - image: ghcr.io/external-secrets/external-secrets:v0.9.18-ubi + image: ghcr.io/external-secrets/external-secrets:v0.9.20-ubi imagePullPolicy: IfNotPresent args: - webhook @@ -12462,6 +12875,8 @@ spec: - --check-interval=5m - --metrics-addr=:8080 - --healthz-addr=:8081 + - --loglevel=info + - --zap-time-encoding=epoch ports: - containerPort: 8080 protocol: TCP diff --git a/tests/common-golang-external-secrets-medical-diagnosis-hub.expected.yaml b/tests/common-golang-external-secrets-medical-diagnosis-hub.expected.yaml index 2f0b9ac3..b7c2ad96 100644 --- a/tests/common-golang-external-secrets-medical-diagnosis-hub.expected.yaml +++ b/tests/common-golang-external-secrets-medical-diagnosis-hub.expected.yaml @@ -6,10 +6,10 @@ metadata: name: external-secrets-cert-controller namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm --- # Source: golang-external-secrets/charts/external-secrets/templates/serviceaccount.yaml @@ -19,10 +19,10 @@ metadata: name: common-golang-external-secrets namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm --- # Source: golang-external-secrets/charts/external-secrets/templates/webhook-serviceaccount.yaml @@ -32,10 +32,10 @@ metadata: name: external-secrets-webhook namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm --- # Source: golang-external-secrets/charts/external-secrets/templates/webhook-secret.yaml @@ -45,10 +45,10 @@ metadata: name: common-golang-external-secrets-webhook namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm external-secrets.io/component: webhook --- @@ -68,6 +68,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: acraccesstokens.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -264,6 +266,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: clusterexternalsecrets.external-secrets.io spec: group: external-secrets.io @@ -921,6 +925,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: clustersecretstores.external-secrets.io spec: group: external-secrets.io @@ -2461,6 +2467,11 @@ spec: ClusterSecretStoreCondition describes a condition by which to choose namespaces to process ExternalSecrets in for a ClusterSecretStore instance. properties: + namespaceRegexes: + description: Choose namespaces by using regex matching + items: + type: string + type: array namespaceSelector: description: Choose namespace using a labelSelector properties: @@ -3057,6 +3068,63 @@ spec: required: - vaultUrl type: object + bitwardensecretsmanager: + description: BitwardenSecretsManager configures this store to sync secrets using BitwardenSecretsManager provider + properties: + apiURL: + type: string + auth: + description: |- + Auth configures how secret-manager authenticates with a bitwarden machine account instance. + Make sure that the token being used has permissions on the given secret. + properties: + secretRef: + description: BitwardenSecretsManagerSecretRef contains the credential ref to the bitwarden instance. + properties: + credentials: + description: AccessToken used for the bitwarden instance. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + required: + - credentials + type: object + required: + - secretRef + type: object + bitwardenServerSDKURL: + type: string + caBundle: + description: |- + Base64 encoded certificate for the bitwarden server sdk. The sdk MUST run with HTTPS to make sure no MITM attack + can be performed. + type: string + identityURL: + type: string + organizationID: + description: OrganizationID determines which organization this secret store manages. + type: string + projectID: + description: ProjectID determines which project this secret store manages. + type: string + required: + - auth + - caBundle + - organizationID + - projectID + type: object chef: description: Chef configures this store to sync secrets with chef server properties: @@ -3318,6 +3386,42 @@ spec: - clientSecret - tenant type: object + device42: + description: Device42 configures this store to sync secrets using the Device42 provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a Device42 instance. + properties: + secretRef: + properties: + credentials: + description: Username / Password is used for authentication. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + type: object + required: + - secretRef + type: object + host: + description: URL configures the Device42 instance URL. + type: string + required: + - auth + - host + type: object doppler: description: Doppler configures this store to sync secrets using the Doppler provider properties: @@ -3494,6 +3598,9 @@ spec: - serviceAccountRef type: object type: object + location: + description: Location optionally defines a location for a secret + type: string projectID: description: ProjectID project where secret is located type: string @@ -3596,6 +3703,77 @@ spec: required: - auth type: object + infisical: + description: Infisical configures this store to sync secrets using the Infisical provider + properties: + auth: + description: Auth configures how the Operator authenticates with the Infisical API + properties: + universalAuthCredentials: + properties: + clientId: + description: |- + A reference to a specific 'key' within a Secret resource, + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + clientSecret: + description: |- + A reference to a specific 'key' within a Secret resource, + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + required: + - clientId + - clientSecret + type: object + type: object + hostAPI: + default: https://app.infisical.com/api + type: string + secretsScope: + properties: + environmentSlug: + type: string + projectSlug: + type: string + secretsPath: + default: / + type: string + required: + - environmentSlug + - projectSlug + type: object + required: + - auth + - secretsScope + type: object keepersecurity: description: KeeperSecurity configures this store to sync secrets using the KeeperSecurity provider properties: @@ -3720,6 +3898,23 @@ spec: type: object type: object type: object + authRef: + description: A reference to a secret that contains the auth information. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object remoteNamespace: default: default description: Remote namespace to fetch the secrets from @@ -3760,8 +3955,6 @@ spec: description: configures the Kubernetes server Address. type: string type: object - required: - - auth type: object onboardbase: description: Onboardbase configures this store to sync secrets using the Onboardbase provider @@ -5103,6 +5296,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: ecrauthorizationtokens.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -5270,6 +5465,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: externalsecrets.external-secrets.io spec: group: external-secrets.io @@ -5510,10 +5707,15 @@ spec: description: Binding represents a servicebinding.io Provisioned Service reference to the secret properties: name: + default: "" description: |- Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. TODO: Add other useful fields. apiVersion, kind, uid? + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -6016,10 +6218,15 @@ spec: description: Binding represents a servicebinding.io Provisioned Service reference to the secret properties: name: + default: "" description: |- Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. TODO: Add other useful fields. apiVersion, kind, uid? + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -6075,6 +6282,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: fakes.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -6151,6 +6360,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: gcraccesstokens.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -6279,6 +6490,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: githubaccesstokens.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -6322,7 +6535,7 @@ spec: auth: description: Auth configures how ESO authenticates with a Github instance. properties: - privatKey: + privateKey: properties: secretRef: description: |- @@ -6347,7 +6560,7 @@ spec: - secretRef type: object required: - - privatKey + - privateKey type: object installID: type: string @@ -6381,6 +6594,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: passwords.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -6857,6 +7072,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: secretstores.external-secrets.io spec: group: external-secrets.io @@ -8397,6 +8614,11 @@ spec: ClusterSecretStoreCondition describes a condition by which to choose namespaces to process ExternalSecrets in for a ClusterSecretStore instance. properties: + namespaceRegexes: + description: Choose namespaces by using regex matching + items: + type: string + type: array namespaceSelector: description: Choose namespace using a labelSelector properties: @@ -8993,6 +9215,63 @@ spec: required: - vaultUrl type: object + bitwardensecretsmanager: + description: BitwardenSecretsManager configures this store to sync secrets using BitwardenSecretsManager provider + properties: + apiURL: + type: string + auth: + description: |- + Auth configures how secret-manager authenticates with a bitwarden machine account instance. + Make sure that the token being used has permissions on the given secret. + properties: + secretRef: + description: BitwardenSecretsManagerSecretRef contains the credential ref to the bitwarden instance. + properties: + credentials: + description: AccessToken used for the bitwarden instance. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + required: + - credentials + type: object + required: + - secretRef + type: object + bitwardenServerSDKURL: + type: string + caBundle: + description: |- + Base64 encoded certificate for the bitwarden server sdk. The sdk MUST run with HTTPS to make sure no MITM attack + can be performed. + type: string + identityURL: + type: string + organizationID: + description: OrganizationID determines which organization this secret store manages. + type: string + projectID: + description: ProjectID determines which project this secret store manages. + type: string + required: + - auth + - caBundle + - organizationID + - projectID + type: object chef: description: Chef configures this store to sync secrets with chef server properties: @@ -9254,6 +9533,42 @@ spec: - clientSecret - tenant type: object + device42: + description: Device42 configures this store to sync secrets using the Device42 provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a Device42 instance. + properties: + secretRef: + properties: + credentials: + description: Username / Password is used for authentication. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + type: object + required: + - secretRef + type: object + host: + description: URL configures the Device42 instance URL. + type: string + required: + - auth + - host + type: object doppler: description: Doppler configures this store to sync secrets using the Doppler provider properties: @@ -9430,6 +9745,9 @@ spec: - serviceAccountRef type: object type: object + location: + description: Location optionally defines a location for a secret + type: string projectID: description: ProjectID project where secret is located type: string @@ -9532,6 +9850,77 @@ spec: required: - auth type: object + infisical: + description: Infisical configures this store to sync secrets using the Infisical provider + properties: + auth: + description: Auth configures how the Operator authenticates with the Infisical API + properties: + universalAuthCredentials: + properties: + clientId: + description: |- + A reference to a specific 'key' within a Secret resource, + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + clientSecret: + description: |- + A reference to a specific 'key' within a Secret resource, + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + required: + - clientId + - clientSecret + type: object + type: object + hostAPI: + default: https://app.infisical.com/api + type: string + secretsScope: + properties: + environmentSlug: + type: string + projectSlug: + type: string + secretsPath: + default: / + type: string + required: + - environmentSlug + - projectSlug + type: object + required: + - auth + - secretsScope + type: object keepersecurity: description: KeeperSecurity configures this store to sync secrets using the KeeperSecurity provider properties: @@ -9656,6 +10045,23 @@ spec: type: object type: object type: object + authRef: + description: A reference to a secret that contains the auth information. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object remoteNamespace: default: default description: Remote namespace to fetch the secrets from @@ -9696,8 +10102,6 @@ spec: description: configures the Kubernetes server Address. type: string type: object - required: - - auth type: object onboardbase: description: Onboardbase configures this store to sync secrets using the Onboardbase provider @@ -11039,6 +11443,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: vaultdynamicsecrets.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -11731,6 +12137,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: webhooks.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -11878,10 +12286,10 @@ kind: ClusterRole metadata: name: common-golang-external-secrets-cert-controller labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rules: - apiGroups: @@ -11945,10 +12353,10 @@ kind: ClusterRole metadata: name: common-golang-external-secrets-controller labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rules: - apiGroups: @@ -11982,6 +12390,7 @@ rules: - "pushsecrets/status" - "pushsecrets/finalizers" verbs: + - "get" - "update" - "patch" - apiGroups: @@ -12056,10 +12465,10 @@ kind: ClusterRole metadata: name: common-golang-external-secrets-view labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rbac.authorization.k8s.io/aggregate-to-view: "true" rbac.authorization.k8s.io/aggregate-to-edit: "true" @@ -12098,10 +12507,10 @@ kind: ClusterRole metadata: name: common-golang-external-secrets-edit labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rbac.authorization.k8s.io/aggregate-to-edit: "true" rbac.authorization.k8s.io/aggregate-to-admin: "true" @@ -12144,10 +12553,10 @@ metadata: name: common-golang-external-secrets-servicebindings labels: servicebinding.io/controller: "true" - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rules: - apiGroups: @@ -12165,10 +12574,10 @@ kind: ClusterRoleBinding metadata: name: common-golang-external-secrets-cert-controller labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io @@ -12185,10 +12594,10 @@ kind: ClusterRoleBinding metadata: name: common-golang-external-secrets-controller labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io @@ -12221,10 +12630,10 @@ metadata: name: common-golang-external-secrets-leaderelection namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rules: - apiGroups: @@ -12260,10 +12669,10 @@ metadata: name: common-golang-external-secrets-leaderelection namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io @@ -12281,10 +12690,10 @@ metadata: name: common-golang-external-secrets-webhook namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm external-secrets.io/component: webhook spec: @@ -12305,10 +12714,10 @@ metadata: name: common-golang-external-secrets-cert-controller namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: replicas: 1 @@ -12320,10 +12729,10 @@ spec: template: metadata: labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: serviceAccountName: external-secrets-cert-controller @@ -12338,7 +12747,7 @@ spec: - ALL readOnlyRootFilesystem: true runAsNonRoot: true - image: ghcr.io/external-secrets/external-secrets:v0.9.18-ubi + image: ghcr.io/external-secrets/external-secrets:v0.9.20-ubi imagePullPolicy: IfNotPresent args: - certcontroller @@ -12349,7 +12758,9 @@ spec: - --secret-namespace=default - --metrics-addr=:8080 - --healthz-addr=:8081 - + - --loglevel=info + - --zap-time-encoding=epoch + - --enable-partial-cache=true ports: - containerPort: 8080 protocol: TCP @@ -12368,10 +12779,10 @@ metadata: name: common-golang-external-secrets namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: replicas: 1 @@ -12383,10 +12794,10 @@ spec: template: metadata: labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: serviceAccountName: common-golang-external-secrets @@ -12401,11 +12812,13 @@ spec: - ALL readOnlyRootFilesystem: true runAsNonRoot: true - image: ghcr.io/external-secrets/external-secrets:v0.9.18-ubi + image: ghcr.io/external-secrets/external-secrets:v0.9.20-ubi imagePullPolicy: IfNotPresent args: - --concurrent=1 - --metrics-addr=:8080 + - --loglevel=info + - --zap-time-encoding=epoch ports: - containerPort: 8080 protocol: TCP @@ -12419,10 +12832,10 @@ metadata: name: common-golang-external-secrets-webhook namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: replicas: 1 @@ -12434,10 +12847,10 @@ spec: template: metadata: labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: hostNetwork: false @@ -12452,7 +12865,7 @@ spec: - ALL readOnlyRootFilesystem: true runAsNonRoot: true - image: ghcr.io/external-secrets/external-secrets:v0.9.18-ubi + image: ghcr.io/external-secrets/external-secrets:v0.9.20-ubi imagePullPolicy: IfNotPresent args: - webhook @@ -12462,6 +12875,8 @@ spec: - --check-interval=5m - --metrics-addr=:8080 - --healthz-addr=:8081 + - --loglevel=info + - --zap-time-encoding=epoch ports: - containerPort: 8080 protocol: TCP diff --git a/tests/common-golang-external-secrets-naked.expected.yaml b/tests/common-golang-external-secrets-naked.expected.yaml index dc6b146d..b6a836e9 100644 --- a/tests/common-golang-external-secrets-naked.expected.yaml +++ b/tests/common-golang-external-secrets-naked.expected.yaml @@ -6,10 +6,10 @@ metadata: name: external-secrets-cert-controller namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm --- # Source: golang-external-secrets/charts/external-secrets/templates/serviceaccount.yaml @@ -19,10 +19,10 @@ metadata: name: common-golang-external-secrets namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm --- # Source: golang-external-secrets/charts/external-secrets/templates/webhook-serviceaccount.yaml @@ -32,10 +32,10 @@ metadata: name: external-secrets-webhook namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm --- # Source: golang-external-secrets/charts/external-secrets/templates/webhook-secret.yaml @@ -45,10 +45,10 @@ metadata: name: common-golang-external-secrets-webhook namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm external-secrets.io/component: webhook --- @@ -68,6 +68,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: acraccesstokens.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -264,6 +266,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: clusterexternalsecrets.external-secrets.io spec: group: external-secrets.io @@ -921,6 +925,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: clustersecretstores.external-secrets.io spec: group: external-secrets.io @@ -2461,6 +2467,11 @@ spec: ClusterSecretStoreCondition describes a condition by which to choose namespaces to process ExternalSecrets in for a ClusterSecretStore instance. properties: + namespaceRegexes: + description: Choose namespaces by using regex matching + items: + type: string + type: array namespaceSelector: description: Choose namespace using a labelSelector properties: @@ -3057,6 +3068,63 @@ spec: required: - vaultUrl type: object + bitwardensecretsmanager: + description: BitwardenSecretsManager configures this store to sync secrets using BitwardenSecretsManager provider + properties: + apiURL: + type: string + auth: + description: |- + Auth configures how secret-manager authenticates with a bitwarden machine account instance. + Make sure that the token being used has permissions on the given secret. + properties: + secretRef: + description: BitwardenSecretsManagerSecretRef contains the credential ref to the bitwarden instance. + properties: + credentials: + description: AccessToken used for the bitwarden instance. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + required: + - credentials + type: object + required: + - secretRef + type: object + bitwardenServerSDKURL: + type: string + caBundle: + description: |- + Base64 encoded certificate for the bitwarden server sdk. The sdk MUST run with HTTPS to make sure no MITM attack + can be performed. + type: string + identityURL: + type: string + organizationID: + description: OrganizationID determines which organization this secret store manages. + type: string + projectID: + description: ProjectID determines which project this secret store manages. + type: string + required: + - auth + - caBundle + - organizationID + - projectID + type: object chef: description: Chef configures this store to sync secrets with chef server properties: @@ -3318,6 +3386,42 @@ spec: - clientSecret - tenant type: object + device42: + description: Device42 configures this store to sync secrets using the Device42 provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a Device42 instance. + properties: + secretRef: + properties: + credentials: + description: Username / Password is used for authentication. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + type: object + required: + - secretRef + type: object + host: + description: URL configures the Device42 instance URL. + type: string + required: + - auth + - host + type: object doppler: description: Doppler configures this store to sync secrets using the Doppler provider properties: @@ -3494,6 +3598,9 @@ spec: - serviceAccountRef type: object type: object + location: + description: Location optionally defines a location for a secret + type: string projectID: description: ProjectID project where secret is located type: string @@ -3596,6 +3703,77 @@ spec: required: - auth type: object + infisical: + description: Infisical configures this store to sync secrets using the Infisical provider + properties: + auth: + description: Auth configures how the Operator authenticates with the Infisical API + properties: + universalAuthCredentials: + properties: + clientId: + description: |- + A reference to a specific 'key' within a Secret resource, + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + clientSecret: + description: |- + A reference to a specific 'key' within a Secret resource, + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + required: + - clientId + - clientSecret + type: object + type: object + hostAPI: + default: https://app.infisical.com/api + type: string + secretsScope: + properties: + environmentSlug: + type: string + projectSlug: + type: string + secretsPath: + default: / + type: string + required: + - environmentSlug + - projectSlug + type: object + required: + - auth + - secretsScope + type: object keepersecurity: description: KeeperSecurity configures this store to sync secrets using the KeeperSecurity provider properties: @@ -3720,6 +3898,23 @@ spec: type: object type: object type: object + authRef: + description: A reference to a secret that contains the auth information. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object remoteNamespace: default: default description: Remote namespace to fetch the secrets from @@ -3760,8 +3955,6 @@ spec: description: configures the Kubernetes server Address. type: string type: object - required: - - auth type: object onboardbase: description: Onboardbase configures this store to sync secrets using the Onboardbase provider @@ -5103,6 +5296,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: ecrauthorizationtokens.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -5270,6 +5465,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: externalsecrets.external-secrets.io spec: group: external-secrets.io @@ -5510,10 +5707,15 @@ spec: description: Binding represents a servicebinding.io Provisioned Service reference to the secret properties: name: + default: "" description: |- Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. TODO: Add other useful fields. apiVersion, kind, uid? + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -6016,10 +6218,15 @@ spec: description: Binding represents a servicebinding.io Provisioned Service reference to the secret properties: name: + default: "" description: |- Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. TODO: Add other useful fields. apiVersion, kind, uid? + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -6075,6 +6282,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: fakes.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -6151,6 +6360,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: gcraccesstokens.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -6279,6 +6490,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: githubaccesstokens.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -6322,7 +6535,7 @@ spec: auth: description: Auth configures how ESO authenticates with a Github instance. properties: - privatKey: + privateKey: properties: secretRef: description: |- @@ -6347,7 +6560,7 @@ spec: - secretRef type: object required: - - privatKey + - privateKey type: object installID: type: string @@ -6381,6 +6594,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: passwords.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -6857,6 +7072,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: secretstores.external-secrets.io spec: group: external-secrets.io @@ -8397,6 +8614,11 @@ spec: ClusterSecretStoreCondition describes a condition by which to choose namespaces to process ExternalSecrets in for a ClusterSecretStore instance. properties: + namespaceRegexes: + description: Choose namespaces by using regex matching + items: + type: string + type: array namespaceSelector: description: Choose namespace using a labelSelector properties: @@ -8993,6 +9215,63 @@ spec: required: - vaultUrl type: object + bitwardensecretsmanager: + description: BitwardenSecretsManager configures this store to sync secrets using BitwardenSecretsManager provider + properties: + apiURL: + type: string + auth: + description: |- + Auth configures how secret-manager authenticates with a bitwarden machine account instance. + Make sure that the token being used has permissions on the given secret. + properties: + secretRef: + description: BitwardenSecretsManagerSecretRef contains the credential ref to the bitwarden instance. + properties: + credentials: + description: AccessToken used for the bitwarden instance. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + required: + - credentials + type: object + required: + - secretRef + type: object + bitwardenServerSDKURL: + type: string + caBundle: + description: |- + Base64 encoded certificate for the bitwarden server sdk. The sdk MUST run with HTTPS to make sure no MITM attack + can be performed. + type: string + identityURL: + type: string + organizationID: + description: OrganizationID determines which organization this secret store manages. + type: string + projectID: + description: ProjectID determines which project this secret store manages. + type: string + required: + - auth + - caBundle + - organizationID + - projectID + type: object chef: description: Chef configures this store to sync secrets with chef server properties: @@ -9254,6 +9533,42 @@ spec: - clientSecret - tenant type: object + device42: + description: Device42 configures this store to sync secrets using the Device42 provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a Device42 instance. + properties: + secretRef: + properties: + credentials: + description: Username / Password is used for authentication. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + type: object + required: + - secretRef + type: object + host: + description: URL configures the Device42 instance URL. + type: string + required: + - auth + - host + type: object doppler: description: Doppler configures this store to sync secrets using the Doppler provider properties: @@ -9430,6 +9745,9 @@ spec: - serviceAccountRef type: object type: object + location: + description: Location optionally defines a location for a secret + type: string projectID: description: ProjectID project where secret is located type: string @@ -9532,6 +9850,77 @@ spec: required: - auth type: object + infisical: + description: Infisical configures this store to sync secrets using the Infisical provider + properties: + auth: + description: Auth configures how the Operator authenticates with the Infisical API + properties: + universalAuthCredentials: + properties: + clientId: + description: |- + A reference to a specific 'key' within a Secret resource, + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + clientSecret: + description: |- + A reference to a specific 'key' within a Secret resource, + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + required: + - clientId + - clientSecret + type: object + type: object + hostAPI: + default: https://app.infisical.com/api + type: string + secretsScope: + properties: + environmentSlug: + type: string + projectSlug: + type: string + secretsPath: + default: / + type: string + required: + - environmentSlug + - projectSlug + type: object + required: + - auth + - secretsScope + type: object keepersecurity: description: KeeperSecurity configures this store to sync secrets using the KeeperSecurity provider properties: @@ -9656,6 +10045,23 @@ spec: type: object type: object type: object + authRef: + description: A reference to a secret that contains the auth information. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object remoteNamespace: default: default description: Remote namespace to fetch the secrets from @@ -9696,8 +10102,6 @@ spec: description: configures the Kubernetes server Address. type: string type: object - required: - - auth type: object onboardbase: description: Onboardbase configures this store to sync secrets using the Onboardbase provider @@ -11039,6 +11443,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: vaultdynamicsecrets.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -11731,6 +12137,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: webhooks.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -11878,10 +12286,10 @@ kind: ClusterRole metadata: name: common-golang-external-secrets-cert-controller labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rules: - apiGroups: @@ -11945,10 +12353,10 @@ kind: ClusterRole metadata: name: common-golang-external-secrets-controller labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rules: - apiGroups: @@ -11982,6 +12390,7 @@ rules: - "pushsecrets/status" - "pushsecrets/finalizers" verbs: + - "get" - "update" - "patch" - apiGroups: @@ -12056,10 +12465,10 @@ kind: ClusterRole metadata: name: common-golang-external-secrets-view labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rbac.authorization.k8s.io/aggregate-to-view: "true" rbac.authorization.k8s.io/aggregate-to-edit: "true" @@ -12098,10 +12507,10 @@ kind: ClusterRole metadata: name: common-golang-external-secrets-edit labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rbac.authorization.k8s.io/aggregate-to-edit: "true" rbac.authorization.k8s.io/aggregate-to-admin: "true" @@ -12144,10 +12553,10 @@ metadata: name: common-golang-external-secrets-servicebindings labels: servicebinding.io/controller: "true" - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rules: - apiGroups: @@ -12165,10 +12574,10 @@ kind: ClusterRoleBinding metadata: name: common-golang-external-secrets-cert-controller labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io @@ -12185,10 +12594,10 @@ kind: ClusterRoleBinding metadata: name: common-golang-external-secrets-controller labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io @@ -12221,10 +12630,10 @@ metadata: name: common-golang-external-secrets-leaderelection namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rules: - apiGroups: @@ -12260,10 +12669,10 @@ metadata: name: common-golang-external-secrets-leaderelection namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io @@ -12281,10 +12690,10 @@ metadata: name: common-golang-external-secrets-webhook namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm external-secrets.io/component: webhook spec: @@ -12305,10 +12714,10 @@ metadata: name: common-golang-external-secrets-cert-controller namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: replicas: 1 @@ -12320,10 +12729,10 @@ spec: template: metadata: labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: serviceAccountName: external-secrets-cert-controller @@ -12338,7 +12747,7 @@ spec: - ALL readOnlyRootFilesystem: true runAsNonRoot: true - image: ghcr.io/external-secrets/external-secrets:v0.9.18-ubi + image: ghcr.io/external-secrets/external-secrets:v0.9.20-ubi imagePullPolicy: IfNotPresent args: - certcontroller @@ -12349,7 +12758,9 @@ spec: - --secret-namespace=default - --metrics-addr=:8080 - --healthz-addr=:8081 - + - --loglevel=info + - --zap-time-encoding=epoch + - --enable-partial-cache=true ports: - containerPort: 8080 protocol: TCP @@ -12368,10 +12779,10 @@ metadata: name: common-golang-external-secrets namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: replicas: 1 @@ -12383,10 +12794,10 @@ spec: template: metadata: labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: serviceAccountName: common-golang-external-secrets @@ -12401,11 +12812,13 @@ spec: - ALL readOnlyRootFilesystem: true runAsNonRoot: true - image: ghcr.io/external-secrets/external-secrets:v0.9.18-ubi + image: ghcr.io/external-secrets/external-secrets:v0.9.20-ubi imagePullPolicy: IfNotPresent args: - --concurrent=1 - --metrics-addr=:8080 + - --loglevel=info + - --zap-time-encoding=epoch ports: - containerPort: 8080 protocol: TCP @@ -12419,10 +12832,10 @@ metadata: name: common-golang-external-secrets-webhook namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: replicas: 1 @@ -12434,10 +12847,10 @@ spec: template: metadata: labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: hostNetwork: false @@ -12452,7 +12865,7 @@ spec: - ALL readOnlyRootFilesystem: true runAsNonRoot: true - image: ghcr.io/external-secrets/external-secrets:v0.9.18-ubi + image: ghcr.io/external-secrets/external-secrets:v0.9.20-ubi imagePullPolicy: IfNotPresent args: - webhook @@ -12462,6 +12875,8 @@ spec: - --check-interval=5m - --metrics-addr=:8080 - --healthz-addr=:8081 + - --loglevel=info + - --zap-time-encoding=epoch ports: - containerPort: 8080 protocol: TCP diff --git a/tests/common-golang-external-secrets-normal.expected.yaml b/tests/common-golang-external-secrets-normal.expected.yaml index 2f0b9ac3..b7c2ad96 100644 --- a/tests/common-golang-external-secrets-normal.expected.yaml +++ b/tests/common-golang-external-secrets-normal.expected.yaml @@ -6,10 +6,10 @@ metadata: name: external-secrets-cert-controller namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm --- # Source: golang-external-secrets/charts/external-secrets/templates/serviceaccount.yaml @@ -19,10 +19,10 @@ metadata: name: common-golang-external-secrets namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm --- # Source: golang-external-secrets/charts/external-secrets/templates/webhook-serviceaccount.yaml @@ -32,10 +32,10 @@ metadata: name: external-secrets-webhook namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm --- # Source: golang-external-secrets/charts/external-secrets/templates/webhook-secret.yaml @@ -45,10 +45,10 @@ metadata: name: common-golang-external-secrets-webhook namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm external-secrets.io/component: webhook --- @@ -68,6 +68,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: acraccesstokens.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -264,6 +266,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: clusterexternalsecrets.external-secrets.io spec: group: external-secrets.io @@ -921,6 +925,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: clustersecretstores.external-secrets.io spec: group: external-secrets.io @@ -2461,6 +2467,11 @@ spec: ClusterSecretStoreCondition describes a condition by which to choose namespaces to process ExternalSecrets in for a ClusterSecretStore instance. properties: + namespaceRegexes: + description: Choose namespaces by using regex matching + items: + type: string + type: array namespaceSelector: description: Choose namespace using a labelSelector properties: @@ -3057,6 +3068,63 @@ spec: required: - vaultUrl type: object + bitwardensecretsmanager: + description: BitwardenSecretsManager configures this store to sync secrets using BitwardenSecretsManager provider + properties: + apiURL: + type: string + auth: + description: |- + Auth configures how secret-manager authenticates with a bitwarden machine account instance. + Make sure that the token being used has permissions on the given secret. + properties: + secretRef: + description: BitwardenSecretsManagerSecretRef contains the credential ref to the bitwarden instance. + properties: + credentials: + description: AccessToken used for the bitwarden instance. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + required: + - credentials + type: object + required: + - secretRef + type: object + bitwardenServerSDKURL: + type: string + caBundle: + description: |- + Base64 encoded certificate for the bitwarden server sdk. The sdk MUST run with HTTPS to make sure no MITM attack + can be performed. + type: string + identityURL: + type: string + organizationID: + description: OrganizationID determines which organization this secret store manages. + type: string + projectID: + description: ProjectID determines which project this secret store manages. + type: string + required: + - auth + - caBundle + - organizationID + - projectID + type: object chef: description: Chef configures this store to sync secrets with chef server properties: @@ -3318,6 +3386,42 @@ spec: - clientSecret - tenant type: object + device42: + description: Device42 configures this store to sync secrets using the Device42 provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a Device42 instance. + properties: + secretRef: + properties: + credentials: + description: Username / Password is used for authentication. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + type: object + required: + - secretRef + type: object + host: + description: URL configures the Device42 instance URL. + type: string + required: + - auth + - host + type: object doppler: description: Doppler configures this store to sync secrets using the Doppler provider properties: @@ -3494,6 +3598,9 @@ spec: - serviceAccountRef type: object type: object + location: + description: Location optionally defines a location for a secret + type: string projectID: description: ProjectID project where secret is located type: string @@ -3596,6 +3703,77 @@ spec: required: - auth type: object + infisical: + description: Infisical configures this store to sync secrets using the Infisical provider + properties: + auth: + description: Auth configures how the Operator authenticates with the Infisical API + properties: + universalAuthCredentials: + properties: + clientId: + description: |- + A reference to a specific 'key' within a Secret resource, + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + clientSecret: + description: |- + A reference to a specific 'key' within a Secret resource, + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + required: + - clientId + - clientSecret + type: object + type: object + hostAPI: + default: https://app.infisical.com/api + type: string + secretsScope: + properties: + environmentSlug: + type: string + projectSlug: + type: string + secretsPath: + default: / + type: string + required: + - environmentSlug + - projectSlug + type: object + required: + - auth + - secretsScope + type: object keepersecurity: description: KeeperSecurity configures this store to sync secrets using the KeeperSecurity provider properties: @@ -3720,6 +3898,23 @@ spec: type: object type: object type: object + authRef: + description: A reference to a secret that contains the auth information. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object remoteNamespace: default: default description: Remote namespace to fetch the secrets from @@ -3760,8 +3955,6 @@ spec: description: configures the Kubernetes server Address. type: string type: object - required: - - auth type: object onboardbase: description: Onboardbase configures this store to sync secrets using the Onboardbase provider @@ -5103,6 +5296,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: ecrauthorizationtokens.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -5270,6 +5465,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: externalsecrets.external-secrets.io spec: group: external-secrets.io @@ -5510,10 +5707,15 @@ spec: description: Binding represents a servicebinding.io Provisioned Service reference to the secret properties: name: + default: "" description: |- Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. TODO: Add other useful fields. apiVersion, kind, uid? + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -6016,10 +6218,15 @@ spec: description: Binding represents a servicebinding.io Provisioned Service reference to the secret properties: name: + default: "" description: |- Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. TODO: Add other useful fields. apiVersion, kind, uid? + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -6075,6 +6282,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: fakes.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -6151,6 +6360,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: gcraccesstokens.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -6279,6 +6490,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: githubaccesstokens.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -6322,7 +6535,7 @@ spec: auth: description: Auth configures how ESO authenticates with a Github instance. properties: - privatKey: + privateKey: properties: secretRef: description: |- @@ -6347,7 +6560,7 @@ spec: - secretRef type: object required: - - privatKey + - privateKey type: object installID: type: string @@ -6381,6 +6594,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: passwords.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -6857,6 +7072,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: secretstores.external-secrets.io spec: group: external-secrets.io @@ -8397,6 +8614,11 @@ spec: ClusterSecretStoreCondition describes a condition by which to choose namespaces to process ExternalSecrets in for a ClusterSecretStore instance. properties: + namespaceRegexes: + description: Choose namespaces by using regex matching + items: + type: string + type: array namespaceSelector: description: Choose namespace using a labelSelector properties: @@ -8993,6 +9215,63 @@ spec: required: - vaultUrl type: object + bitwardensecretsmanager: + description: BitwardenSecretsManager configures this store to sync secrets using BitwardenSecretsManager provider + properties: + apiURL: + type: string + auth: + description: |- + Auth configures how secret-manager authenticates with a bitwarden machine account instance. + Make sure that the token being used has permissions on the given secret. + properties: + secretRef: + description: BitwardenSecretsManagerSecretRef contains the credential ref to the bitwarden instance. + properties: + credentials: + description: AccessToken used for the bitwarden instance. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + required: + - credentials + type: object + required: + - secretRef + type: object + bitwardenServerSDKURL: + type: string + caBundle: + description: |- + Base64 encoded certificate for the bitwarden server sdk. The sdk MUST run with HTTPS to make sure no MITM attack + can be performed. + type: string + identityURL: + type: string + organizationID: + description: OrganizationID determines which organization this secret store manages. + type: string + projectID: + description: ProjectID determines which project this secret store manages. + type: string + required: + - auth + - caBundle + - organizationID + - projectID + type: object chef: description: Chef configures this store to sync secrets with chef server properties: @@ -9254,6 +9533,42 @@ spec: - clientSecret - tenant type: object + device42: + description: Device42 configures this store to sync secrets using the Device42 provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a Device42 instance. + properties: + secretRef: + properties: + credentials: + description: Username / Password is used for authentication. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + type: object + required: + - secretRef + type: object + host: + description: URL configures the Device42 instance URL. + type: string + required: + - auth + - host + type: object doppler: description: Doppler configures this store to sync secrets using the Doppler provider properties: @@ -9430,6 +9745,9 @@ spec: - serviceAccountRef type: object type: object + location: + description: Location optionally defines a location for a secret + type: string projectID: description: ProjectID project where secret is located type: string @@ -9532,6 +9850,77 @@ spec: required: - auth type: object + infisical: + description: Infisical configures this store to sync secrets using the Infisical provider + properties: + auth: + description: Auth configures how the Operator authenticates with the Infisical API + properties: + universalAuthCredentials: + properties: + clientId: + description: |- + A reference to a specific 'key' within a Secret resource, + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + clientSecret: + description: |- + A reference to a specific 'key' within a Secret resource, + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object + required: + - clientId + - clientSecret + type: object + type: object + hostAPI: + default: https://app.infisical.com/api + type: string + secretsScope: + properties: + environmentSlug: + type: string + projectSlug: + type: string + secretsPath: + default: / + type: string + required: + - environmentSlug + - projectSlug + type: object + required: + - auth + - secretsScope + type: object keepersecurity: description: KeeperSecurity configures this store to sync secrets using the KeeperSecurity provider properties: @@ -9656,6 +10045,23 @@ spec: type: object type: object type: object + authRef: + description: A reference to a secret that contains the auth information. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be + defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: |- + Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults + to the namespace of the referent. + type: string + type: object remoteNamespace: default: default description: Remote namespace to fetch the secrets from @@ -9696,8 +10102,6 @@ spec: description: configures the Kubernetes server Address. type: string type: object - required: - - auth type: object onboardbase: description: Onboardbase configures this store to sync secrets using the Onboardbase provider @@ -11039,6 +11443,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: vaultdynamicsecrets.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -11731,6 +12137,8 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 + labels: + external-secrets.io/component: controller name: webhooks.generators.external-secrets.io spec: group: generators.external-secrets.io @@ -11878,10 +12286,10 @@ kind: ClusterRole metadata: name: common-golang-external-secrets-cert-controller labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rules: - apiGroups: @@ -11945,10 +12353,10 @@ kind: ClusterRole metadata: name: common-golang-external-secrets-controller labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rules: - apiGroups: @@ -11982,6 +12390,7 @@ rules: - "pushsecrets/status" - "pushsecrets/finalizers" verbs: + - "get" - "update" - "patch" - apiGroups: @@ -12056,10 +12465,10 @@ kind: ClusterRole metadata: name: common-golang-external-secrets-view labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rbac.authorization.k8s.io/aggregate-to-view: "true" rbac.authorization.k8s.io/aggregate-to-edit: "true" @@ -12098,10 +12507,10 @@ kind: ClusterRole metadata: name: common-golang-external-secrets-edit labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rbac.authorization.k8s.io/aggregate-to-edit: "true" rbac.authorization.k8s.io/aggregate-to-admin: "true" @@ -12144,10 +12553,10 @@ metadata: name: common-golang-external-secrets-servicebindings labels: servicebinding.io/controller: "true" - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rules: - apiGroups: @@ -12165,10 +12574,10 @@ kind: ClusterRoleBinding metadata: name: common-golang-external-secrets-cert-controller labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io @@ -12185,10 +12594,10 @@ kind: ClusterRoleBinding metadata: name: common-golang-external-secrets-controller labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io @@ -12221,10 +12630,10 @@ metadata: name: common-golang-external-secrets-leaderelection namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm rules: - apiGroups: @@ -12260,10 +12669,10 @@ metadata: name: common-golang-external-secrets-leaderelection namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io @@ -12281,10 +12690,10 @@ metadata: name: common-golang-external-secrets-webhook namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm external-secrets.io/component: webhook spec: @@ -12305,10 +12714,10 @@ metadata: name: common-golang-external-secrets-cert-controller namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: replicas: 1 @@ -12320,10 +12729,10 @@ spec: template: metadata: labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-cert-controller app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: serviceAccountName: external-secrets-cert-controller @@ -12338,7 +12747,7 @@ spec: - ALL readOnlyRootFilesystem: true runAsNonRoot: true - image: ghcr.io/external-secrets/external-secrets:v0.9.18-ubi + image: ghcr.io/external-secrets/external-secrets:v0.9.20-ubi imagePullPolicy: IfNotPresent args: - certcontroller @@ -12349,7 +12758,9 @@ spec: - --secret-namespace=default - --metrics-addr=:8080 - --healthz-addr=:8081 - + - --loglevel=info + - --zap-time-encoding=epoch + - --enable-partial-cache=true ports: - containerPort: 8080 protocol: TCP @@ -12368,10 +12779,10 @@ metadata: name: common-golang-external-secrets namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: replicas: 1 @@ -12383,10 +12794,10 @@ spec: template: metadata: labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: serviceAccountName: common-golang-external-secrets @@ -12401,11 +12812,13 @@ spec: - ALL readOnlyRootFilesystem: true runAsNonRoot: true - image: ghcr.io/external-secrets/external-secrets:v0.9.18-ubi + image: ghcr.io/external-secrets/external-secrets:v0.9.20-ubi imagePullPolicy: IfNotPresent args: - --concurrent=1 - --metrics-addr=:8080 + - --loglevel=info + - --zap-time-encoding=epoch ports: - containerPort: 8080 protocol: TCP @@ -12419,10 +12832,10 @@ metadata: name: common-golang-external-secrets-webhook namespace: default labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: replicas: 1 @@ -12434,10 +12847,10 @@ spec: template: metadata: labels: - helm.sh/chart: external-secrets-0.9.18 + helm.sh/chart: external-secrets-0.9.20 app.kubernetes.io/name: external-secrets-webhook app.kubernetes.io/instance: common-golang-external-secrets - app.kubernetes.io/version: "v0.9.18" + app.kubernetes.io/version: "v0.9.20" app.kubernetes.io/managed-by: Helm spec: hostNetwork: false @@ -12452,7 +12865,7 @@ spec: - ALL readOnlyRootFilesystem: true runAsNonRoot: true - image: ghcr.io/external-secrets/external-secrets:v0.9.18-ubi + image: ghcr.io/external-secrets/external-secrets:v0.9.20-ubi imagePullPolicy: IfNotPresent args: - webhook @@ -12462,6 +12875,8 @@ spec: - --check-interval=5m - --metrics-addr=:8080 - --healthz-addr=:8081 + - --loglevel=info + - --zap-time-encoding=epoch ports: - containerPort: 8080 protocol: TCP diff --git a/tests/common-hashicorp-vault-industrial-edge-factory.expected.yaml b/tests/common-hashicorp-vault-industrial-edge-factory.expected.yaml index 62eadc16..19cef108 100644 --- a/tests/common-hashicorp-vault-industrial-edge-factory.expected.yaml +++ b/tests/common-hashicorp-vault-industrial-edge-factory.expected.yaml @@ -6,7 +6,7 @@ metadata: name: common-hashicorp-vault namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -18,7 +18,7 @@ metadata: name: common-hashicorp-vault-config namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -43,7 +43,7 @@ kind: ClusterRoleBinding metadata: name: common-hashicorp-vault-server-binding labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -64,7 +64,7 @@ metadata: name: common-hashicorp-vault-internal namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -96,7 +96,7 @@ metadata: name: common-hashicorp-vault namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -127,7 +127,7 @@ metadata: name: common-hashicorp-vault-ui namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault-ui app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -168,7 +168,7 @@ spec: template: metadata: labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault component: server @@ -206,7 +206,7 @@ spec: containers: - name: vault - image: registry.connect.redhat.com/hashicorp/vault:1.16.2-ubi + image: registry.connect.redhat.com/hashicorp/vault:1.17.2-ubi imagePullPolicy: IfNotPresent command: - "/bin/sh" @@ -348,7 +348,7 @@ metadata: name: common-hashicorp-vault namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -375,7 +375,7 @@ spec: containers: - name: common-hashicorp-vault-server-test - image: registry.connect.redhat.com/hashicorp/vault:1.16.2-ubi + image: registry.connect.redhat.com/hashicorp/vault:1.17.2-ubi imagePullPolicy: IfNotPresent env: - name: VAULT_ADDR diff --git a/tests/common-hashicorp-vault-industrial-edge-hub.expected.yaml b/tests/common-hashicorp-vault-industrial-edge-hub.expected.yaml index 62eadc16..19cef108 100644 --- a/tests/common-hashicorp-vault-industrial-edge-hub.expected.yaml +++ b/tests/common-hashicorp-vault-industrial-edge-hub.expected.yaml @@ -6,7 +6,7 @@ metadata: name: common-hashicorp-vault namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -18,7 +18,7 @@ metadata: name: common-hashicorp-vault-config namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -43,7 +43,7 @@ kind: ClusterRoleBinding metadata: name: common-hashicorp-vault-server-binding labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -64,7 +64,7 @@ metadata: name: common-hashicorp-vault-internal namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -96,7 +96,7 @@ metadata: name: common-hashicorp-vault namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -127,7 +127,7 @@ metadata: name: common-hashicorp-vault-ui namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault-ui app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -168,7 +168,7 @@ spec: template: metadata: labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault component: server @@ -206,7 +206,7 @@ spec: containers: - name: vault - image: registry.connect.redhat.com/hashicorp/vault:1.16.2-ubi + image: registry.connect.redhat.com/hashicorp/vault:1.17.2-ubi imagePullPolicy: IfNotPresent command: - "/bin/sh" @@ -348,7 +348,7 @@ metadata: name: common-hashicorp-vault namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -375,7 +375,7 @@ spec: containers: - name: common-hashicorp-vault-server-test - image: registry.connect.redhat.com/hashicorp/vault:1.16.2-ubi + image: registry.connect.redhat.com/hashicorp/vault:1.17.2-ubi imagePullPolicy: IfNotPresent env: - name: VAULT_ADDR diff --git a/tests/common-hashicorp-vault-medical-diagnosis-hub.expected.yaml b/tests/common-hashicorp-vault-medical-diagnosis-hub.expected.yaml index 62eadc16..19cef108 100644 --- a/tests/common-hashicorp-vault-medical-diagnosis-hub.expected.yaml +++ b/tests/common-hashicorp-vault-medical-diagnosis-hub.expected.yaml @@ -6,7 +6,7 @@ metadata: name: common-hashicorp-vault namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -18,7 +18,7 @@ metadata: name: common-hashicorp-vault-config namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -43,7 +43,7 @@ kind: ClusterRoleBinding metadata: name: common-hashicorp-vault-server-binding labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -64,7 +64,7 @@ metadata: name: common-hashicorp-vault-internal namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -96,7 +96,7 @@ metadata: name: common-hashicorp-vault namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -127,7 +127,7 @@ metadata: name: common-hashicorp-vault-ui namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault-ui app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -168,7 +168,7 @@ spec: template: metadata: labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault component: server @@ -206,7 +206,7 @@ spec: containers: - name: vault - image: registry.connect.redhat.com/hashicorp/vault:1.16.2-ubi + image: registry.connect.redhat.com/hashicorp/vault:1.17.2-ubi imagePullPolicy: IfNotPresent command: - "/bin/sh" @@ -348,7 +348,7 @@ metadata: name: common-hashicorp-vault namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -375,7 +375,7 @@ spec: containers: - name: common-hashicorp-vault-server-test - image: registry.connect.redhat.com/hashicorp/vault:1.16.2-ubi + image: registry.connect.redhat.com/hashicorp/vault:1.17.2-ubi imagePullPolicy: IfNotPresent env: - name: VAULT_ADDR diff --git a/tests/common-hashicorp-vault-naked.expected.yaml b/tests/common-hashicorp-vault-naked.expected.yaml index 16eadf00..1a62b9c0 100644 --- a/tests/common-hashicorp-vault-naked.expected.yaml +++ b/tests/common-hashicorp-vault-naked.expected.yaml @@ -6,7 +6,7 @@ metadata: name: common-hashicorp-vault namespace: default labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -18,7 +18,7 @@ metadata: name: common-hashicorp-vault-config namespace: default labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -43,7 +43,7 @@ kind: ClusterRoleBinding metadata: name: common-hashicorp-vault-server-binding labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -64,7 +64,7 @@ metadata: name: common-hashicorp-vault-internal namespace: default labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -96,7 +96,7 @@ metadata: name: common-hashicorp-vault namespace: default labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -127,7 +127,7 @@ metadata: name: common-hashicorp-vault-ui namespace: default labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault-ui app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -168,7 +168,7 @@ spec: template: metadata: labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault component: server @@ -206,7 +206,7 @@ spec: containers: - name: vault - image: registry.connect.redhat.com/hashicorp/vault:1.16.2-ubi + image: registry.connect.redhat.com/hashicorp/vault:1.17.2-ubi imagePullPolicy: IfNotPresent command: - "/bin/sh" @@ -348,7 +348,7 @@ metadata: name: common-hashicorp-vault namespace: default labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -375,7 +375,7 @@ spec: containers: - name: common-hashicorp-vault-server-test - image: registry.connect.redhat.com/hashicorp/vault:1.16.2-ubi + image: registry.connect.redhat.com/hashicorp/vault:1.17.2-ubi imagePullPolicy: IfNotPresent env: - name: VAULT_ADDR diff --git a/tests/common-hashicorp-vault-normal.expected.yaml b/tests/common-hashicorp-vault-normal.expected.yaml index 62eadc16..19cef108 100644 --- a/tests/common-hashicorp-vault-normal.expected.yaml +++ b/tests/common-hashicorp-vault-normal.expected.yaml @@ -6,7 +6,7 @@ metadata: name: common-hashicorp-vault namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -18,7 +18,7 @@ metadata: name: common-hashicorp-vault-config namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -43,7 +43,7 @@ kind: ClusterRoleBinding metadata: name: common-hashicorp-vault-server-binding labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -64,7 +64,7 @@ metadata: name: common-hashicorp-vault-internal namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -96,7 +96,7 @@ metadata: name: common-hashicorp-vault namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -127,7 +127,7 @@ metadata: name: common-hashicorp-vault-ui namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault-ui app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -168,7 +168,7 @@ spec: template: metadata: labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault component: server @@ -206,7 +206,7 @@ spec: containers: - name: vault - image: registry.connect.redhat.com/hashicorp/vault:1.16.2-ubi + image: registry.connect.redhat.com/hashicorp/vault:1.17.2-ubi imagePullPolicy: IfNotPresent command: - "/bin/sh" @@ -348,7 +348,7 @@ metadata: name: common-hashicorp-vault namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: common-hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -375,7 +375,7 @@ spec: containers: - name: common-hashicorp-vault-server-test - image: registry.connect.redhat.com/hashicorp/vault:1.16.2-ubi + image: registry.connect.redhat.com/hashicorp/vault:1.17.2-ubi imagePullPolicy: IfNotPresent env: - name: VAULT_ADDR

e9?vX&2{P`z*yEQ@&1J8iL1Z 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 Ls1SjK0N4Zo6jePG diff --git a/hashicorp-vault/charts/vault-0.28.1.tgz b/hashicorp-vault/charts/vault-0.28.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..ef0f05f52e28759a71fd4a2f08aa88d239748ec8 GIT binary patch literal 49807 zcmV)dK&QVSiwFP!000001MEF(bK^FW`K(`oQ}%A+)aYr+o^{o1m11i$zW8;PW;UtR zmWw7KiED~r_^?Mi$$!7bgD(&iDT$Wtu~3za1pF0{Gz7;Vr6KIrxG*1yw%Z*={8-Glvp7x1LBf7m#x~1@ipHh zws%xRNT-P4HHm|5Z)Q&Xrb$}1HpfTkqXrqr#C6bTiZV6LF+XG1gNjG!z6(E{=x3+d zIc#=o2KIEpX6tM%~k&}4||xa8khr@g3|It3G! zn4119xNYiW-kMQ>Isj~OTz0jG)}-4tfQIM>?zTJcCVvOIVqhI;P^a@w`}^&?UjN+z zZolicSRZb#Tyw6ui!(AMH$PdLe%EyDY3&X#9*AqeyfhF44gY#r4_wn4k@|8~FMmH2l&X+A4G)9x`cuw#)0Hh7V@?1MKWfn^|z zkUKPX#M3GsQk-{pJLFzOv*q<%075r;Hrr7aLeQ zu_xwqt~nc@3kvpsx83ig_dm_)@Am&T($}x8A8W_NS-9qO=A$3z^0*1x3p15P1Jy5 zw3InPnr)yT5})_b5BLwr`K(z1_UMNu!@?%!-_f7QCnMhl>amCFAVcH&9)p)UhIDFo zrfnRdV}`otnp2x&Uo$jcqh}i~Rm0wtdpQX#i+-ei{OhljESuU30*2>kItOIhx)m4^ zoaiG51jT`zVT&EC5F-;!Z`NW*ELC;(A*zZH9I2Xj5qXSHV(Nw!ozH>7XuK_kprB}~ zI{Z{)G;SB^S|jY<17^^Q;WYEPYR+`)2>r>xu}-3|>~ER`4up$6waBezHSrf88q_St z90rErhP|Pwu0aO&ygGW1>a+vJb?d42U>Wc-fYOY5u-U^o1rAh*G|fV6XnObhQKIJ_ z%p7nuk56FJA+De8H0%=5=f7&~A640z?b#KM*61dH^4Z~&0` zf4ke;@&9e4C*uE!FBvxO-fDVN3;Y>z&HpgvS@Z54<3cfm=NNho7`i!&PoTTRvR@bn zb_0tm3Sl;Xc1hr{VKh*kQhHzqp(c^$3BIH0ItgswYx(33+wcW=(yb_>yBKD0#{<6U zR6zf4VY`9My%`%QqW}8`lK!U)S?wMD-$r`z^#3Q0p_Q@$f%Pw(8^A!W@r3q0#=98&mkr)ORn8`X}^kD5+I7!s(O~+zO3QzzRwxZ9VR<4Z+;gx_Cp&OpnehnP@$q!Qr{7;VVv3Z# zN>^#p($XxHsyElZe6r(vC;N zFtI9JTn8J&#S~pj>`11MO!abUKjnS9yrb)FoV-2Y5F-csm+Sz!QjGiWQUKEU&vT?b zKtW}(pB4>wfU;VQQlS;nF|mE<69t$6qC|PeH3_R?X`Yv!q|B!bGB2qtsi{$@SPr)T8GTM`5;ufnR&}AZ4(2ByQxHRZ89-!7-y=e4wI~zHgKmHu^VW;4X0e!NHdda zc10A3dYJ)Y&Vg4PrEX0qD3%RvJH#_#b{6!aLs`Vvrm2ew0r3hJ@QPTbzQ~{pujfPs z(*4ogX<{b%Y&IHzLk=-*|9vZ*vX;1sA^KgWw1IDf>3f;v(#&*Q%B?V)Yx;=U>&e6- z1W!vexJh4wE~wnnatNyHrX`RYB~ggiy~B%aW6AxOJ8VY01~B=mvI>G1mybzZr>h*S z+&;GNx)Pk*eDVc6_)mzDB zs1iYaJ~xxatA0q_%yFp&`j$j(&-ND}siU+hyvX;6&7 zetwVAXtd_`OU_PqxpVels#08L^BEOGx#lDHoULgEC=Lvre$3Er8Av+wck? zDr(3;9Sl;8Q4UOTmrfA zl1uP5TXPB6hKnvi%U|^hh+-*OmH{jlDtWslM9XBs)dkFC?L09vBRlg-`NFnN=5x(9 zWX>hie3ker&kmFIxE<8{7WQ=^f5etiMa)91--;5OTx(^yjc)eL;G&bo6({Q;?6Z+f-W7X(t`r#KkzPy zeN6~VL1Z8mCe5#@(JK8c26(P_VTxZEHb6eSq@b!UH^20A+1{ z@~EP<({5)!i5ngGmi$;Ogh>{S$&{3N3elDl#amuDw?sHt#qg?^!&VTuRu#8O?4C>( z2c}ROsHNZ;@%S*)9E=S-SGO2~@=i?mk=Q~Gy6B;aZMwfz*w~iG4`{<*z|hlum}A2X zU`L(9EV+yP1zLhN86KO9EGb3cGIU5C^dknxwFrzE#c&R`cw?!$|EtXKPoyIIkHbz| zy8k=qb$9oFTS?FG{;!1nM>U3jZfxW5IxYnj27>7Kdi`Iuq zlC(Es8cHi!8!{_X7n9Xujq($k){-WO==bOiH)woAkA-v7qsZnVon6GBTk8Gg0W;Kn zz{uN0G)j(HP&;%+OHVp=K7(`f1iKiPtEI71UxOmA&Hn$N7RBb)_pAtIwGE#%qPbpk zCHOcXuL2&CNB=7^{1d5&{`cB_+5Y3Ozq9||N_x5UzcRzWw8h^m;s)y(2yS8-xHAcS zZb?P|)4lg=I>21K!6!FYJkv-Dnh0`|gn z<6$?p%U}}JIsWshv3ZwPP5Jb{x*z~W^uI6bf4ZIa!7l#SR?@Sh|67g(kS3v3#{zgt z0LBx-T!vGJsSUWNB+JqR#&tAla3sT>8&LyV5x3j~xHA+dkay$@>4p z_AdVCR?@Sh|KFpN2=iD-Vj7t@+V4x^1VpteU;wX7mqRP+WbP0f`f!AVv>*B7hhlWf z5H%}gZ|u9i#3x)aJL~#{D+VgvPDDfVgwuYs%G+>%R}OW32YBUh6DFyN`=MyuD>=t2 zYpv-WAHiDDJwC3d^59k%^@&3)GF^-uYNdV*EkXC;m?-;|tLx@@p{q(S^+HeB%|#W~ zcGfQgp_IpdeN~ECUpfOh0Sg-POi)ui$%!_4iYD$bHI=`>{sVFE)T2)nSTgQqj{Tl# zU|n;w+c0m0`F=$TSE;C0fv1#Iu7so1l2%fVQgwMx7q3}i}B6r#s3bE z$2VuEqw(+}RW9k~3>a(s6I4I?@B6v}pQ#gao-1#pPrkaJf(W6Zw;?sLFb6FRlI!d$TWJ?N8&6H&=u4$MQ%eAdLSI-A~-@EMBXjL$|l$HVLK&4<&oya6$XGa;e0SSu}6w|V>Y|DtuZ zhhV1pUxvR`*7_Y@C>zfY{E^csK%>iC3|dj$GMScd^XB8_XgsQ@W!P_T*Qr#zl^+Q# zr4VcH|01W;9R4C)P7@4<%I=2d8s(VG_3-oMFTx5z}6~@(wMhGV{ z*VMh}im22E9G(r&hvVztmJsrKOF&+wciXX|T;#7*a&^FIb&rdgM@ywi?CEGh6o^L$HIi9aHM%w0PV}usfW6ayo z>FU^_QlhI_akq;8(*gp(T&pusm-WUF!6r6xe|I)q& zjx(x(__kYVfZiw7nI_k0_VN{ zJSY)>qk_(s-xg^Jjj0ZY_Pyy6o2u|XYp$2o0xS*55Khh2<;e}@R*%c55=Crj~Ap%sTNe6ei7n_@FVnbJibbw3YLa>ip82rgL~zG-6-5s4$SpKKIH)1 zAna2P#3u^)wLRpiI8ay~+-lILvXEhU5UW6-(!s+Jec9CY1Lq~St-_(i3k!m>>z3MX%a zhhH?^kFJ8L_1SPTVJ;Ks0$5rt=M1;BDd`B8Xl=h8H5DQFHNH3TL%7SR8ysw-w}3Sq z$(cJGuvp6koZ$!^@_k`i6CZxo#Oma={EC7aPmXv$g0ZgXB2(9X3T#7qqD!_X5oKVK z{s@R4zx>60D8n-#aYCz4IzPwP!@+ncCWdbW*{v|jm*zG8mU271a(Pm2 z6WB|=mSvAoVHnPNa5ZX$l9JeJr{GmZvGAPkP`&btJgUQL0XvNR?I)?*+J=HBp|6o! zMDpc|hU(QC$0a_|iFJg=$5-E)7ytSxm;O7RQ&k}NLjV7LIsQw#d(hp{|81lfME?OJ zh0SCM2Jo0cZ{Kn?wL}ntp#1 zcsNy)9dbg_zcLS2Mk9Nj6n(W+NdGGc1Yaos?{{SR|Ddy@|656~oc>oBGv+n0fjFMb zTCw1jGgc-tO&mama)+D{GHV~;UUMkRW%R$QH=qjWf4A4^$nSsbcMf;-e;esrrT>vh z3BRI?>`F#LFnt2`&od$7s&%4Mn+>@UX_Ug3Esgj=%kL3&hA~}OHJ?BUd{0&OIC}ch zquDMYezR8Qeaw`>T_b*7Q2Y)b`V&7Lm(a<_hWO1*=)@1|;rO7r#^CC-CdG;fTceq$ zSI6m$tJ9M>BYu37L5)Vsq7g-r5ZD+48$Fo7vjU%uH=Zr88Qme#D`C&SPP`(@3~J6y zJNOc|FrJy7KwG4F9(!Amw#K4|APw3MJV1CfaGZfVCoXa|_)Oy?X*L=S8LVWBthIqn z?Q^}raV$(7D>O?S-&9@Wd73?q@4UW8ABcNv8b~v!oWwfBMmeQmnvue7Zo*>5ehqW& z%Mm*0_xJmdH4#shZn4R{M^^drzGi+er(FJD;Ukbm=f8vfuFU^?JN@5w(sSkiPZ|Gz zi@HNTn1;B}c&ZmEpFx;v<~66VpHRMr_!iZS%r2xKAs&%}T3w0Gyf?W7(3Uz`3{ zs5_L{z|*}(`2wR=Z>ED(G2qA5HilK#d8o2_?vP9W!+>cO907{&e`NaK?(}!@pSO~p z9sOVS5@Z#mmRlLWCc2s*l$G!BC5pe$sw%X%XOEz>o^T7RUT>fMf-MA+?o|ob@3a@$ zQ_iKr1nm`?4iwSRG9BIeETHKAAEbTR|98K)qyJk;Rnq@RZ1!wlQ_9`jdzgqNU) zV4BDSf*G)Mqf7V(%3H<^`bh4mioh17_FFby(5pN2>{67L@P8p33d;D1@jrTpvi~O> z0C)bMTS=Ajf0+Z$iII4DQF2?ag2xLKJr^h%vG~;){3r!!$KanmgO`^6dGYthiItUG zw~WVaY*)*+C92P~#M2Y3sfMQe=Dqw7K=xG=Uf8txdqAq}Dv_hupi5o> zVqi=WQaYtgF2Dd&ika={uIAt|4}!7^pj5>e8V^&ttn+^&z-k;lt0ZEj-gjEw!V4dg z5MNwv9^t}-y$zCZUe2NyH83sPec$qUe3q~uQO1#s|C!j4s`Zwt)5T%leRyf7v;3=fK6TR@5vye83WEr{p$KLYZOeq)p>RBWT~7$h@*iKHDqnvu*8lepW&MA* zv-AJkPI^@Nk0a9nw(ki{-Bk0V_bZj$LfW-Kdsj=LcH4O6?*BSBsE7X8uL6ae}g>w&p3V~va)^D``?51fqehl z>+babTS?nH|MLfaad`X)pA)TT*@40wG_Ggh`+6ATP0}cYPkpkN^(9y2HoHp^j>cP2WSS#cI+k4Zk zMy_;0wEmW!B3kLw2|h?5#x$p0r!inB$2o9;O!rytY6zqNMG;cS5g|xb*?0A8+_mm~ zxqg!SO?!$#Qh*@SF4TR>iL~ea?Qb4}>%`Z|h(+NeP5h`77+(N1OIPsY!>W4ThH}BpXT!g;Q!ysa}qKn%6qN|AS`S1Frl)|U_V2K ze4&_gbl&o~i}#UA9F5}MBgC-N49^(8#38l9bJ4LHRe_gv-({hXQ#w_K%$FOuRKIL8 z3TWNvh`e8?CiwPOI@F9H;)g5DOMHE==`|~c=W#~k%P36y@8awv@OzWJUJvW%Oh2fq zJ~E=Iqf;H3RB+ezjAw7vtU3V%xs;Zti^#tL-KyZlToPrNd(iIy>tok)DZzPW4vJU( zn#*R=p?o)OvF@zyf-QeoCy|DBp>_`O)%seeGx`7Zy#1%M^IZS=X+F>Ve-7^n*w+#Oq|akY z05Zk12v86K=H~R(%|5gG&#eA4tN%w}_2orBHLstW_LA?u69$(!5{IY z&ldLuCI~5s_}7=qN8s{IC6WA_r94AxMZA zxuh$7Z}upe1#o}AjN>e*8Y}@=@5H526tlp#icR%ve)Qpt>wv6MQHiENs zotbRr`8h|!C&)A7zlsNhyz{O;M#Kyx4_M@Z0IIWASakl{mI(7; zA4yc>En#ed*IaEbFWX%xO9y55pj&l*;YFS)q2J)UT&qjJdjl)kb-wgGL7MrmEu7?_ z=iHz)JxUOTZ()G(;1a2}HH0g@R13||%=aJmQ^EfW!ECXw+GEH6Z5H(Z>ub;a|C4+c z&i|M2rvgl@=9;EjsKK_qv&UROy0-f#6kd8Q63XMT=bsPn17|D$xYxC)>%@&DRpUjMVR`RxDyB%d!P{*SaB zM(>k%@1Lgz_>&g$gq1u@{{QmD`O*;Wm&_8r%m-?}#6WE+u1-zDAbn}YZR6+Xm*X^W zdRpoCT656sXOUykpBeanAr(Mp;{WaSJpaG3_U!-vB%f#e|FDSae+DvO!lCaK=*&kn zPbBqX3vWJCi#a~k_~%{)}Qr1PxARg<9{7#%jq<9xb3O%sZXIj z`a+O+ndJ-*b4u~gB)koy0LI<*$O#9&d*Ph~zl_5KuFeXN4$`h4@fi4Z631B^F@6-q zcgJd!L*2*>hXK1#;`r#me36WYd+7&Q z8Xtl_V2U({1Ihewh(YEtwj{$UCZ)$CHW!q(sV|Ca@F)SHo#3GF;^7H2BR8@);c)y( z&2ZKaQ+XPmpQd;NG#k3Ur5?JOj#G?v-y4ngl0lq!i4Q+xpu0cxP7i4;dq$dVZ-~Ch z>3B54%}7Jjmx}5?gD({K+D$F8n&NE&hvcDctcII z$MK@j9m*U9pT)C}$nWPDyJSsj__#X~1xEe?415^Lf zXFC30U*Flt=l@;XdXE2mn$MS$|Hb)rMpdvE-l+iSDQD_M;|S{S{cbk)BaR`@CF*sP z@B&Iqt?J)qw5Qjt{T@g`X^g8mv?)3*OAj@Vvxt=?VHEe?(%R6Tq;ioQ`-vY#K}5Ef z5q#&TrNgQp^>J}^m{TA%S#UiO#aBgY7Psx0lb}VZksp+pC9iKTwK1Lq_yx4*y-Nhz zJWcsTN@?#r-OK&?wPy1REN)(wNkUB}%d}oKej;bZWei-QxLb~cd+1K@yVt6`8B_SR zat3WWlUB}^y>j}yoEd*p*mw~&U_*r-syba=g~KqLI44%pE{jKT6kktHM`(%NhdE%? zSa5!J$0$e&t14|uc5#9ET-!2()hG#LbS}w-+v2D2QyKD^(!UVB3b=9*4rv=dBtTz| z1L%zIE%C5dni^nEBg$yaUG}q8Vcw4Mv4B`F zP0eCaC*_w8@R0#rw}G;hUF59P6@n>jM~~tOTR%^^ILGs)0`8B={D{FKu~}SbYjt4UUT&_9ImGQru%Ix=-S`-$#ppchCdXJr1neIms1!j z7~Z;3?&{87zdt=YKRR}P!>m$p9N#DLpcont!c5c?2j|k?jw#e1mpSJA1-a4H%*XE! z9&utoS{3tt-23q6?EJ@9r{}nWcYALS7rq9?J`s+eu?Sqi>G9tFBd>z!!jz@#9UPpL ztzg${PS10mgA$cnJRFv-v${J^YFQ_Y^|+?piJpR$V^Jh z-E*s7Eiu?Gmu$5JTe@d(`s2~@`TpzoKfSA%UZvx&=z4m1w!c^UVy5=RC;nN%eE-dd z)3d{qS~o9hi2Ap0cP!*bv8SC536zD9E?gboa(jMx9HFB#Cv@bztx8HXCH~d)vP{$Z zr9p+sWSdXXo$U9~_<^9XuiM%y>nw-3Y&9XDj9TA8^ zZ-Uz(ntlpz-v4m^=J4a;n`)dUM)rbdPEpB?sGn%Ymc zR6#w?>k8b<%1K%Hp+5ZLt=DNavJ&f>;WQ)bxY^mCDy45p3f}5LJEen`CZMezWc?m1 zYk@eEWArN|KAfhghMFeTaS!{#3qnN!xGS8A11#egr0H=IUmCAsr>EOycMiOk8x=Et z}JB>90!2oF62Y?2A8qhtqHOS8qHT1qH69isg9W?e~N3jmRzk z=8XY0`FPB>RVIaV&c?~mTg&x5>jz%&Da-&aVJ%5;g^IUS3NQMRjJlia<#}rW%4(*< zj~$FAN|HD!{IX7gM1@YlC!?NJA0;JwKWou=h2`NDIWt+D*UF-_mEMG-7VI>uRSxoO8YcOM{=P%$75buNr;SM3wGp?}sUKV>}9?yx)6wSGJ(%?hd+$*Pc7Thdy?9 zxQD-Wcf8t9JqoXa?xY(9d8)(pUQCo`FAmb-%M7SiH^7RJr$;}W9iF`Pu0X8xe$Ei@X4 z^j_K@XBZ=!;sx|QKlOS+5?rGx80BX#%+esb$_+^CMxz=Gu=MwMa2W>5G?Xs4T@Xov z(<~n4Uu_vmvMFhaMC}k)psgiMUU+*Pvgvzi6a*u$A7I36>|Nuj<0+2t@L-*2=<@v1 zA+R=cH{dwtc;sJ$Sg_)yFwooba4{_fP+u*L!d`sE9My8k85J3h5<_L2W~Z57 zM0Wazdbe4F#ON6wfut0(`&I}dWo9StGEEqnVP2}TekqcnZ8a?ArcEc5Y+JcoR2T!h z=&e!oYJ5P_!@U0=nwQem#rl|`m*39TR+axZe#rlCYkhNTYZJc5^3Q93^0pScjPlPv zx&L4J{fieU{;_}{@EQL98^!v6@ZGcj|C4;aDF4qAPtQ`v|KqrKzan}DtQ!vx>S`*V zv3?xiGuY_}>RNyNY8_J0?Z;k|G;PQUQyEHDvxUQ} z82-n5Y3rn3dLZ(Q#*P(f@9gaG?eW>^w;fvvH~iNAYYeYF@_zQ3Uk#gH3s||YR4<3e z?8UAof)=-z;q?FjeKl;iU2(xxmtC>#X2O;Ht^ruR)}idJ(+( z`<}eVDo$Hle-$Sw)LW zJKU#U@q&uL-Um?115IrAE^D`(*osu*AfI7UyyaZ7Ev@X!m3TFde$K|{DtQbOKT(-u zm`UNR<9SLPL;ERZjf-GXEGJxAi+EZG=lBZ2ZKh`~qOE3m>Tx)wZxs8z@B9eiD#>@T z!-byNwJ+n7=l{-udSQ%UI~y&A`TNrh{;$(nTi@Es>3_GeB-k_m_XM9s@_#rI=4T2# zUn`N2x0-mrjQt2Z^^gn^7H&6w3NWT?*roQFx4nTDxg_;21F~a!X$*wO7)_}cyW4V- z+9(`^86_fakOgk(azduRgLkLc7DaPpM3&p$(G^IKMBR80(X^#BVaDHqxQ+I{#wBLI z#dX3Yw0K!9?Gcd{Y%Cm>u#Pr|Dp*hb_#P-{6820z+sX#N@{!BZC$HJE z5=NrWgwBIGlmwXSyxaS@r?%s)TDk^Ur#=TB#bp8XTAgoeFEE!2(;bcHoomb-*~tIf zfj;Y6kx99gn!s?SbhQE}+=>|Y%Ig(Qy=pV|S@XYzZH0|s06JRooB!JMn&-`0yX4&* zej4HODK#@r5nq{gSFYFv#<`)Q{_6HHyEo@dw%!)Ua%M5w%wrxL5XQ8{iX2r~u?;9Z zYA!U>OjiL6z`TwD8bUd?H1v8&h}u{{7UG#zeetQ0KJ{BW$A^{%usE-2H&`OSLMLPa zex4TJfXxfx5tV&f70K|YOt8E>->HPdzmae;&zY#U(+{T5s^oN3o7zV-z2hUElj!m1 zI3>q~RdGhSHYF#dUHt2v&$Moje>!f`xcLvOB0<=cqbu(rM?%6-*|Frp)w@hBN^<|R z4Pi;U3)jDzLa)a@?6e<`qn_9IZ;|_=%!nRuut!9Yq87MpgBrxj?^ox3DiV0keOu-I z7j<{b^+w>ulwL>iHl|$%)-!^`i-K!Ei|_vw_F$L;HOkaObz9ClKHqLVt?Y#c{RP|t zjf4(#qz0Ng5-~VUd<4Irr&k-n72ZmDzQhu>clDz(M1(@wTnCCNS2*=J<~xmXIL`@; zXE0LZseIJ9J{wilc)@6b{A%Z#W)+tcqOvc!*|&(hZgTFtke6&X6zq(gDuF#8(HN_Rn2Ef|e@mu=Yi2eVU00>)zoQK=-D zS*>6hV{+JGaZT$6QE)7co$lpN%$-|}bl;9SnY9<*dQ0i}(p#c`4bb~}=5E%Oy><8x z{%a0NmD1M1z1{jrNDFz1TJo1Rd4}s8a0nFnBOAdLgjgyFl!kyk!mCL`qmd}S4!f0i z#@0BMMRQKfGS;axv_D=FAHB))ypx-1a%HtzEZJm+55Bh zqcCd6bhE(0DneuRkvl{y_ECz`bhf>jcPDc(k8XPv#s19JZhqeCme$4OqO`EzMs;#t zyK&VaxE?$CYaEZ{Y6kv@<(8CLju2y8Fun%W%eU}%8 zzG$vB>QV3r{?kX*beLftH~@#3*!bb3K^}d|$;n{cfj?pKil{0nvzJsXjW5OMIOyi= z&FOL_7S>t49PFB_euzk9nYr-l=g8YCCX>XJA^ejQU7@U>{F~(%rpxZR5ghZnOX%_J zv}`8yqb!EvW8OQ=tPYQwM{FTMALddY(k$(a?U!zFKl>Ws!=j&?dRxV$AjYw_YcnkNL zLMUzv&~f13uyBEnroiG~#-F_469xqa7_%1mX$Xi8C&l-YYF||7il#F{m2BUj;U$Fc zH996$;U&)3X45y}C5kkz(yv3^nn%-a0DHut8>oA0+{wlxxs@wegZ@*qQYYom>u}a3~ zAAVIW>W{3_FIB7?fBMz5sz1I;Nmeqx`sr8Gs{Z(ACwuQskIt&*uz&v5ZC!sZO4w8} zk^b#htKIxltd7%UHHy1_L|*s3xO)>MEkGK{WE2D6)lU0v9&w>`-t-*oD&ym2=O<6UfJh92|Z; zKY9QD?ELKgkB9Fna(9)H0F>q6|FAmi8L7l)PV?sI^bDpzP&zz4EuW|P^X~3nb-KLS z=Xlo-kxewGspzk0UNFAcRnO~Kphn?{EwN>aq|a%Ma_3!C3d4%#FNK^xH0qu^AuBmj z@iv_Kbjv(6&O?5Rg*>OHjGLME}=&jR85j zp&k)gW$L8brXh0I!YxC`D7*`7w`ySI;}{A_8Ri~{V?ip%uqz*Uo=>@LQ0{bcnzd#S2Gh;PTIm1&Qxayu`(f85 zNIFZoJ&DS6k`t+)fVwzqtmQ0e`b41=1%;=@Zf^VOk;bBPGd; z$XqfW4k=^P&@;G{u=MLawro`Ecyv{j*`y}Ff3+&TGxd#Ao8hZ$gf<-1nZ7SxMqv#5 zJz`g&4*1rZ#Y4?T1$IdfX9N2y@n6l)QOq<~&4=lMOT+dHoY>S$OdP(OnYOZ4 zTwB2!`=C3TGRpmKsW{-m?x{HR!fvXvpwNRK-;`2CwO?cPD)r_oo6P@S=a}U|54d{# zMZf6knH~T*Rd2j{vO14`UT`VAiARQwI`cdbaXbNh%rVyjQHv@$_6Vfisb_W%e4=~X zP@=!IMZy^;Eb$=zG`q0ao zK2+`NDjjYi7gjp*!>>#@ZH%wh;q{O3Cf&k;wI3yRKUJ&K8@0ck`&pI`b>DaCjJC*! z=?uK^mpS9Qr##Ln7g>PRMcmqq!S4S+7k_i*LofX9EMG4!&g-R8op;K$sV1|oOts^c zslQYPlNnd!cAkDURo9}&u&-p(xsv>KOuGs_-1IuWv#)?X;qaAM8mda=f~~|d5~!Os zv0O_dTCIJuwCw2~Ht6vjeGEuGNjR#^^YIQLOUOFC>rrHtX4IXUT_t&?!q2b)- z8*B0TXE0sSQQhypx(;i^_EeU%j-JCBbUrS3K7i4$b|&N)LEZ+Q8Cs6A!!0D|oD;z= z@TN+~eE40J4*Mv#rNWx#yD=3J;otr~3h?N#1f*_iDj7A?EIsra~L z*s4M2y1iVLR2^I7JiG`Cww3Uv*0M^fBG0;=Bdvf<}` zpLSG>8#hx@dAjm|K}Ok2-^D}pbIN%;&`&=k@p$A|HT3GQ!=7ct>8!1-IhGsj{UOC< zFJ+y_`ObFVtNTp*Ft9h3IBEmGRcN^06VM$UfT_Hyd%g#=GiRFlUPi6gVP>-5NO|?X z@`9sv9*dc6=3MuGH#0B9$6O}INq8GZ!F6z$cKwLZ^sYxahn==vD`R24fW0-_l0d$92=ve5VNRYj1t&3zFpG`-gMG)!?Q3Dk{==m(1O4OQjf%Kx*yk9our~>9Wm5u%&Ij-#X?}AILCo<=)OY6PL+eYWh zrDEW|^jluGH?v$4;a{9UIn2)i0ZWfC`*K}anR@{iEt=~X>I2rJE#;w5_%f$%S3nqF z;ulJ-KLrlmhBgd-b&CKo6A;`1%3vYi!VYeMNo3n@t17^R_EvoRbSNSqf)04y+N097 zmXyTEt1E|&Q@fRU5U76@kiqPKviLdrJS9^ipek7k;_tTsU5p1IE*u|{G*UdV%k{K zvU4a1uEpDw9^pM1oAUKP1oY<|vHokAJ@EY>$n3Ef$Ix73Jo`L1EKTRYR@z=z=y2cb zs~qay_f|IIgDT-{JEA*>>eN%^c$SoEJUfg9C$G+#C zF8b+_zu@Jh{#BNAtbLa=#(2PGmW{ly+bkRWQJ-iy`uaf3syhYhUfGK^}0o zr9&_5a!W^l%*Q&6hkf6<*>`ak?0P>1Ue}Kz%zpZk+Pvh9r`|B&Bpf zjMC8@S0*NgT;tjd@w8#;-&VzF_rIfx0T+e8Z4=)-*xIrl&Ht#%JKbA5Fm1T|zpsi> zAO5;327dSrT0!deF_QU~a&T}aimJPunyg`tycxNDmgKIO-pH|2+!Gcm#(N+vRE_#z zSg0C!v9Q1i3+@XBD&4^oKmboAmv5JQt#$9R-NjwG47kwSmN6gq(Q}rb>DN6yQAYhs zFHeLswbddXe${{v1cS<99}EnYBR|^PzZW#z|MlMk5bpo}ONLqG%`XZAlnuHdyRz}s z(Wzi`5fPZ(>x1ycOx>h1m{Rwgp>)<0m`vyRv2xHD<7{PLZL-z5*X9UTd)O|uoqN_s ziw)~+wWRlF*esU1o3&4;O`R>e9T&DcL{s~xM*z}$*En7p_JXdT)ZDd?edpSHu4Ua5 z$ak-O4lHxQj)5@?27vu%NnJQAH=R%7s%&4I&dwOAKAx=}@cwAFdd!DYRri+4Tx4zE z@mW_lzt{N8e&$3<-6-e1(kUZ9>}uzB4Zp_~&*=@m@T;EU_dI=pvs|9%?Cm*-YN7XD zm}9ZGKg*YS0YEU_ZFw$OSWM;-TqZP`Bk@Q{OLG9V@{UX$Y1UN|$;#hlezb+;G$)!Xa_+%8NBj5Yxrd(Wg8ovs*4_7rK zjbFZ*S!|6ge$|7_b5Z5^(iv}InYRif-#^b*8PBS(YGw`sy^y&W)?7>LlJe~8JTIzr zqD|jxWcr->4q*qxe1jjryLw}cVVV0t^?6}BdCtwB);LHmZ$0}sOWWlRby`dJD6!g$DY8YU@_iBy z=z;0_0w=+h;7QZ3q&^pdkM$dLoOYUpll4x!eW1%kr~82)Wqps*1(BMVYU*HnDx>37 znUQIPQm=incV|(05TB!f%Q;u*LYu*wp&S8GXrGT#r~^O^RXz4B zK~AMBjv*=T%U6CzFNv^~G(&sDhze@LQMVhXfIs2{UvoGdjd6qoE5nuew-9{lpqBCg zW~$;{Hmy}@n~E0#25h?UE8WlVSGVoAAH&HtRrp`&c!GRNr?U4^4GMhak+lxDWS@>U$N&4FnV9J}JMI4L zshlg~3I+C6IHd@jqw=hqwFf*p7HgIB9iLLMUG7NuW!ue8Nt1knPc|(MZ2#&$Zh4Q+ z%dLKer8mNt;8DRuLU@eZs%W3e`c{a9Eh!mQR+dC})9*(Gv?@4?+Yh62GW~N{v!oUrtLwS z#SJ}t;u>?7NE}t-$Df`*i~ewxE@c@?SNR%Sz$^EnAWd6}P)$I#yzd-q@Y&wn#Q%17 zw$|+b;%5W?{8MLhdvj}jb8Bl8zF+Tbu5bUzTU+Ett3JRG`-$iMX%GUR9|e`|X8ry< z{cxyrJenj_zig?y?7hY$tNU>>TJesCUEpnw5B^6>>ch2;@cm--^JLe1d;F%g-d3r^woBVN@DE}3|0$8d=JgRHuJ0&wo9LE9F@i+u+E5Jb9O>vH1u zQU@;`xm=(+qFteHdDUCVA(uv4w3#|pwJi_K!A`33l|ar?8Vmq(_T#|_IrZjWzV$lo z^^MjVwBENeytRLXJqxt7<-f}g&94e|8GY{$!f0Z|56^SIE6a#At#^Sw&YU~|RY0o0 zRD8PmdyYv%auyM7qG5&BXOV1qUMOI^12z=C8I3QaFzvsKGpr3Z*;5tHbzU+QnFRWk zyxuHAuTsDu{5D15i9M(71%J1Uls+&s+3}1%rj_cc7DYN6`F>ozo+;- z^M4QK|DM^t0^9c(yj@9jYzbpmMcXH%fL4b8n92m8w$5g5Y3ydJY^D+IGqy&RY#&GY;0Qj!J^KbnyBJ)~s8w|xoeDX30 zDDNm%n48cjTyQ+=hpBh)?i5Ro`%y{>#d?Ie{uYNrFCHl`wDwe{dI~pO(T6uv!i7&~ z!k?4}ca^J^(co+!Dp$8UZ`;we8oQF~8#im2s!fF-%$FlM7=uF9p(q-l{N?5-eSIH7 zk~^Pg>EsLfF#q31E+o7j#>rzaxHI_wwe5A*|8A~tZ)~k^0sp_*+1hyK|DWRX!aMde z#7;!M7zDWR;pI4tdgx99tm_T1d_a9(cxOneQZ{zOKj1_n58XbzfuD8z(0T=^8>Ya% z4WM7vx4sAb4Fe2=Yqq2>jgsIh`~--GEY1IAx$V6lMiURKD~@KbvwNq!T(~vPV z^|kfQFg zvwoa}efsb@{?o z-W*chRrKat#V*URl9ONnEAu`aAMBkSva5@V?`aLjDEJPqTPiy@&b9Muqvll517`vu zz)QOzTi_w8p*?%(&f3OK?QLxAEE_0V^Op8TNf>#r9sot#?M^)?Drr6!6s^w(MOy$x z>)$jQ-v@p+PGl?0#O~6m8WjZ)Gw~nuy0mXO*R@XVb6xAe;e9v0=IInn?0P;-I0(}e zFYf|`hzsw6qJu7wc+wBB2H4;}OT{N~q!&>iM%T9V4G=zb-`P3 z^5v%~UUlegNzi#Q!U13(Lpu+|Nq}F#xGcF};Hjfnerl2#(U!m2uDfICu{>otk|Y79 zJN~$z${gR+p5vQobEq`R$vBc2bb!daIJpre4^H}Or|vt29?K41px{pil0q*8R)+fZkq z8u6r7ZxNZlMJf5h8xPTQMlGg?tn>s0-U0cXqnjf2hqpP#o#7$l5veA--bJg$vAy}# zef!^1pgZToF+RG#T(t3!$mLXEul9Xx+xM|%?qhwY_@3u~&b9FM#=Y@%XFhzriTL`J z^~Bzfg5fFE`BCZaQ6U#v(47Q;i=g-V+9u!Cc!)7-p&x~RhuQeBw`(8v_OgxVT%sW| z6(_)t4hCnJ|v8+BdYe!YYr`r3Qr(|(G0iuQ?!JoSdKO2Ah;*3w^# zFQ$f4CSPgcxm2n7FElq{5jTop2{X)ld%<*zFSGVJuhBUxn&8rcO*j$0zS`Kbvu%dW z(SsZvc+eDu=dpi!wCla~Zvtkdm0DcMf)cHKVd6qiW|Z7OCNam$)S%E;+jY+rdMrC! zKE2gogeI88kKTlXFp~x8FHeGB#sEbZc%h8AQk4ya)`{0oiHk5;Np%7$L;1d}G)E*< ze)FoXQ2EU(T=82toWXeD-4sEb)mBzaWvaOCJmS5mT?FDXhT+~Xa-klVe zkz1Lw38JF;ouL{z8;_2)c>HRs_WRi)w67mG;1oC29NZb-7t)$zE5ij{r$CuUx?Hd8 zlifu&GYszhD18vL@w?t|^gipavOc};b@z3bKUV#uI-7M*rn5Qqv3BGoJ#^$LkM)6z zuN3_FvA!Wy(uL)%rkhH*Ib)Wb~Z}bqyLL?TwK_}oy@AC)Nvu%26)1? z+7qs6bhB=23D>vlVH?2-YqfX0Hk~zCQ>fs6BkQdJCOr*C8KY7gliIifVZ@l5-jgpF z7Kyg>Mcp`3kl^4B=#zxql*RO&+U(rUPU$)GfyhA!1M{jbPJ|xIqQ3L|YafB$<^<8q z^01N1VFGwA8Mdxg3wr3A>kw}{zQ$Y{oi!UK$&7xQKPzhuYiJc+Q#Vo6`G?iiL%PPzQiyn`%uyWEa)!jv{wfrIB2YOjifV z`P+I{O6H4vds*prT`L&$aQN+usi`}kdRaN`k5!C*AGL8M9T~+g*$`^Mk z?`aw#A2$lR;T7jEx)|zTNYtevX(Z{XSy0~pc5Sv~8`%h&HoRM&FgOZbSZBL}TTnzu@%p%SwDPC8q+Z+|ww zvSt_yC!_rMDlIml7r0ha``Ous4rC46Xm9^3eW?__E}2!BDT_yO6kktHN2tUCw4Y`P z(1MIIGs>~z32TbN2(h-hY8%y6<@OU)o);Ax+B&jAY|V z33kMJE`p;7l9oyejI#WSXIWWgEu;pgCDit-+h)Hybqgc%&sn|gU|GR~FiplJzJE9F zAx4CoaJk;jzY0YuTo1!^ZF054hAggD7%SC>f#uwI)) zxMp3pp;g-?3kEbtN3{J-UG^V(6b-)Oea9G$lZ5pUrTX4~?!A5E#g~+KQ(T=msTgM& zV;HEt1{OZw;&X%l(-=U}$)A`^?mIc<)U@dAd2!ph3^KoSA%{@=O@5T);>sEMk^&;^ayHtNUvl~nvL3Y zYGcz{jqUi^Ni)5gAK$(I>793UdisIk6a8t$jTS|VD?g0*^2tp$&apI|Z~m15Q;G88 z%AE6-y$rfOdVqn@crlV)U5Ict2c>$|-kb#yg@_Nsq^aWsV8GWeuGQo!b9_W+yH%SN z-TKDS6DT>2loX|*=FA*l*eP8_2V%4xic7{2Wj% zCD~ZB1ogvVI!2#sbPbB&$;EMY5Td1s@I40$;-&{E1#tdc64r4=>~HOA=knu(j>k2h zP+iXr=%Jql`KKH6%=$OwIJ*ieH>N`+dOhoj96OL!5#%O1{mevxo;>+RGm!%BR!OWv z;NmOJWWXq5F+`;8oy8s_4DrU&*36i-IhFgzgBp_>1kS;%V~s6?#9ojTo{%oZyMVU) zsx#xJb^##^+u$ey$e9}PabBjuh=d%_s!l0^tn&7q0@Vb^we=a>sL${W%-8@RC(p;` zu?bmR=eBCQIzf+RSz}%O81&F@ZObyKt#2f~3VO)Yu#jHf;4AGeyj9!SxwW&dI8dz@ z5vAsyrQLN{1DdI}jJWm6(B4h<7>*{!lcrO&{}!2-;8U2rAD#qRGWi~;Fe293Ov~1G zZBn*fDhmiy*`B3TUeJ`wT46(kILor42Nm=>tp({dNd)JW)ipA0ab#BBN%Pj#w^1$@ zlB>xnLXGCd$u(dd4(OBx)CJ!yW6rSI^<+F8Dr)a{yMWbw%J2e!nQD8dFO?@QF!j`h z@^O9mLh_6j8$l#M^@0yX%za81uENXGJ_SZ0zT~Bo`9yIY{G@6_&(2zYWh79|vo31* zn5!xS;){v`78eXdzN)X`Cy76i>FY9K&;y>7JpTru14;SjV7txQ;JLYDrZAGVGFYZEY+WgFi(C@zSi!L_cci#x zk8&3IayGRWzCjDep^cAIFQ?CH5ByIbh9=vSGh=O>wy|Z7N@!0DgaN=D!XytQILXu= zcJO;`Q~lPac4{G}$TceFDbXYkSvibvPQ| z)$!StC#PulwrZ;(w$|yze>hU6Swe!!Semy1Y}S4?n`HG=?~-gm)mYW1d}w#MoM-M{ z`BZD8hmQ7G?sQBfLT7U-lXam{pfRNepD;`;%z#BpZ^DrZP+{5YV;%)>*47ekz9OMq z`xB9?kIJt@3&E*S#8BD^o~X75)+T#k9T@}sw2OaL_r#%xGdv#+yRWO@BE_bq`sRxh ze^d7XK@XhxkV>ba76F)a5HWG|%RsPz6YHQ^9*d3Gtj!v4ZWA_m6JLWUbsI#4bEM>* zH9vxIFHGP}qKQI>0%cKr{XMmJ9bVw;H#p#hTtr=w40=?u5EnGk1!?hZ>!>~p0t&u| zy0ip(O(NOxVUaG?Kdlgd^?6b_LKN88cXi#Uh(O%)*u~0*e84ysX-xN6=$=Mf%p2{-K8w zC)vI7;PB)5o1@dS!*^sKKRiA4$eerYQTAek^q#ENXM)JK!N{&H-5m}9AsVmSx4|+Aoo1l`P#~$}WzFkZeuY>5Txap1BOzj3UwT|Ywf~mC_dXWk@ zYP(Ktuvf;@1}82!&2gb74in9Hm;sQIa|0b5pxXd>!YbclwoXn7HBqj{yu!M?$p*P} zS*k8FzL6A)F@K|RCIpy#L_e+bpwbz4;Q+S=@F+mf^qX(TMLS zsjhI9=l*bVPIhcW0;1TWrPdCtg&xc8a+j=3TMbRh1}_8NWPnD-35xYtt~IePnq}1^ zTcfs7+l;iaQ|1#ZXCy4|Ti`G*3d?18*^hFJG<$6}W`o(7_c~Bi!3kapYSE9$IgY|X z`0c(-i@M~3^J%Ace!0#LVNDgQbbKW7N>vzgy|$OdI(u0tm#Ll!`V!q);EjirXx|k0 zw!<{&fNLj>*x1&&GyS0xQJj?pf#fp~cD|`gf}w}w#p_&DF0h2f>s-NNOL@Oh+qSg9 zwk37QR$@!Egs|b5-By7CzA&QEMs4lX#!hG6gVnhfH@0gdjO|U=-hn8;$U1yr*Pr#; zL89xgwsKa9(Io4~C^$0XLtGG>aM(ym`>3sD-7vO^uK(S5*o(NZ#ASdO_7@Dz27Kr< zSpfDY?D4H(%0bv85pj+v;04rn{omkB6}SM6DU^DW9p7awOtKY`)NKh5WS%NDz>BC& zskStw+SZ0NkdT=bW)Q?6bgw3ccJGw9$mZ5gN_Hx&^Y$0M4rx``V zUU*S>6?7+ExI+@iNW37iFO{Mq#yTpboxV-RLxpE}dBgzvR~ZL>Qne9AfJ|L$%Zn_J zeivl^Zoz)1G-Et;ZNZ{b7EE@^SdDkH6*fO}12YTIVk**2rl-_h~@`J4CqKcWXV%YLbNIi+|02w_?Ul1biQE$%VyuM05H zWBIRWtVu;NOU~CE1vP*P0S2gx)Mnvn)@vs!gdQ{v2TV|eGgf_LXS~8OJ2aFgtj!}q z51z1;ZBud1CjiOpGorNBXar#eFwI*#(=PO&dGijCMTdI0K9;7K4AkD>D|>^s5?R?E zObIgY!Z@9_Z(dO~6%zx(&#NwP1U;r4uwSV8ggACdA zkZ8SBR+P)Eoh%c2Xe^Ms8w$ZaM6$f*`H^Y~T z%P2-|8jfbYHm+O$M$_^wW3TO(?>CUU2cugECarUc@>d^*dXu#&j`1;x;D7%fjI_YD%JkB({Hq!6#ow`R+y(;Gf?A%E- z{YGt4uwjz|;}GfiN-FP2Wyy2$cg|Q)ZOpmBnDea8BvcV5Mdh((Lg33TVl@+OmiB#OKY%da1;NnLuPaxm0>8CW_h_KUY_iGbl2aAx zCsWl0i;lwrrBM)!R1oSYfzjiUB^7|oF;b7QHV^sAC0y()rK%DU(NcmSGpV&-`#1Wv zBd(+hbJeO)oKJakT9E}5`e72#u#$rzueM(~^gzhdr7}=PH3W^}#+>aP#sZH>IPZz< zL?WUEPHlC`wRJZ;-{?26(cUoj-j1zHRr)xKu9cWIb<(#e_Ipwf!P1%Aitw>=9Fr|z z>ogdqq3{mG^roWNt8v||Jb+yp9fzfl{+q-Rn4`V}1bbb9X_1x4^AQ6)9n`Cnsu;c` zgEJN4QfIhs&hV9WgmWwg$2vv-t&ivmIH7yT7!ORDs~FRtKmPdYw6(Ei?yO_QPY-+Z z&8O5Z=#SV+C-8U&IzuOg&tPNJdC+W~O*0!{$%CLPQ9#1_biT>6K8HE*oZ;<+QnlbKd!za^pA@$Mry)n4fI4O+AbbM{cJriBhw;}`W9b$vD-SF{mJCe#5RuMcfl{+s(y^#i75} zn?sAx0g&r!pFD3wudVc12B-?aG9FzgNO}=epczF|k@|uVGx^6z+A(#-oL@|0t@Jn` zw#CRRUARi%3vUTQTYW3$tczvcPv^B=#hkYhSG~Z)5@V@)42WJ?H(Mia`s zZo#SEs?wNT;A~jc51k{v$EQs1;X*$WrI1AFMd>NwYs2Q4S#A4s<>TP{L>%c|N+_ke zeEqBT|I2+}m5)MVE|>OIUEvi^d6=(wcF^XE7i3*qVMJaelBIBz*5D}l{g4V$`=%VO)wG0QW%G0N@Wat!w?6H86;LY*RvOQ zZvrLh+3_xyJ~9)e*B*NNRO)d5$UcfdTMSS|2SC}gjRxr$^X#Se{P@_az^BBFgkB)D zD)cZ`?h$3}@()r)B;kupxp*bxP~waDK{C^qV*PJEkQK$shk@|#h(}FyfO&6*1hLbA z@)f{WYE<@$DEd=2bCssl`rVk!f!P_U{; z!>V!i%|0|l`=g)O?1$D#b0~sR4ftupD<}14{47cjSU*}cehPD~@K6?a<47{17;Fwx zupNc?A1h^x%Q#sPAi3BgUq4)VPO5lRru}lEGXQLMiT)ei^gQ;Jt7{+x!L!y@f+E=%l>AZku(S@tX}u7FrUW*haZ zWS*QJAUVS8M`=M;-pY(=L$nVTM<#k#rH=`{NNx~zF-z7sLWE%jnhp6KYHEgpSgRM` z4KK8m#`^zIqj~lf!E$u0&Vb7~?T<6;B#)D7d&3I>;*aSPa4s|>48n*Lyj!!FXWY@x zcxO84yT~ynD(e&ZUn_q?eKvXDYXDtX-X&mL)JKg**q9fI4lw9O5%(%-RX$^5SJBH0 zi4P*#a59K4JP!8|-ZhJ_uOozKw;Vyp3B3BM_|2vApV!YG^CJu~O1lcYb%?#?$Fgmm z-x1gJ@}&IfKV`9TMi%?;4-Vh|^zQKF^fBg`RsVZ!V=G_(ceC?c|My8gUwi*OFYO22 zm>I2q$_MdJ_EGQu-Py^}cOTA<-aSGI@agY=eWSCMum8QdzV-b6pXBobSsxJ1F2|X} z8X)rqwEgR2t|kMbO0fI&*WOP+l+hQB8d3BXYcEL#ipL4l^_QraNvWO`&LUNU1&O+?&g;)gxdi=mq;rOQ2E@&1N; z@zWcR>MmRkLh?{(@FLOkdQ37o)n9{ym|%Uqw)dZ~yStbTrrsooP%-4QR_U6hHW+7u zXLbqw8o?F(l5x@6yEwt(W_^hz?30F?nNy$oyyRRw=xUW=6%$w-3$4t2H&XI>MVA7+ zG3XAWVu<=SSRHU*2|3_*^~Gx|RFBqs=cBVE{0BXZuNqu>n97CeRGF|vPQc@5aH?mx ztQ1aeMNXB6ASYZpT2}122L;=S!W&#YYeok_0%F5TBlDvhwiEmpIzv1G5QY%EG6FH+ zLdVzrOr;1k6VPGWyK3}S%t+!iiD}>SuF<)hwu#bM zOqq?~#z`SbNtO7SV4ayU2i1KaC*#3ifA0L14kR>bn>lq7Rg(eX14j)I>Y_NNOk-?A zr&N}y1aiRz8SPlR@!dq_tQAbZ=10 zj>qkBRWQ^i`2xfywGX&J`k|r2L-5KF zOftLv2W4~O5}Cr0>&kv@?}z|q6sP$5QChe|^Cc^ZS+>LODBsDW4nBiQy^nOAN2{W&t`tmXgXoxGl6F&{Qc0 zQ{&yDC07ftV-jlU*S04ZTvZ3d8UQP#dP=(qno`p~h}_g(KafY<6p*9O{Wd(_V!g{L5_~xb!m8mQ@RkUN!@p2HfyS{3+;VV}F0Ux^p$b0fH;ZYNS}h#e$4`PQ^b_iGXRa}V%>m)0DQZ5` zSSNCapL&A3@r~*8iZC-9z9uY}ena=Xm0Kc14}g|Br4=?HR6rR3lsA z8|NG5#%C8&3|admz+|$#u$siX8l(0F03^5rM6lvX&=eW@S}{=UfS&O%KwkzwVd$ok zN2n-k;B*X$oG-5*j>I*ad@#pD2{Fs3k!o{S`kjsVOtnP=MNd=|SXMqx<-5$qK@f(s zpg|}~2mPMta=sJhIdc}ReYwqvqf56= zSLRH@yh%(zL>w$)pfF;pcTi=O!5?YYyN$-h#YGBZMGdjxaQD`g_tig+e>(VW72B=y zZ>zZQHvgNFp_erAS}Ls|F0e&Z6sBmrBk}@|raR68vjCHgvUmWyg|*>1v;e$Ytz_V} zZoMWiV3$_V%+JfW%d4aR!KXosIpR9ZhI}EBrqQ`{OxP_#hLCwAw8U{CALKP0-0yCK zFbzB7BQI-q+f*JdO@#^3ocAcZ#d|c<(caA)dMl0<4|p^{4~d>rNfI{DwacE%*WSu2(0& ztWFt?!*E)YU(9HDpk_S$tDW|z3}H%I(_P3w_Cr78n2gLp&hYYpRPb50E%3Bk=P_qV zAJe3PQgms0LA24Vi0zzBu2Rxlps$F98_0#Q71AVKA!OvRY>k)P`1wNMTw1MO%%kYB(XKKOqAO4QLny)>PMZRNg`kC!**P z+Jy!qe;5k?JVGEzLJqD}D^i4$lNm8@)AEkTYQX}1oVPG!mjs>JIZiNVh)6ERKMWNf zexh1x+mSy&?x1Cr5tLYeS-DtsnYHM1K9Y=e6O)u>Z@3UPxpSGF71BYFbiYfF4j(oC z_eE;~A0El^YEW~)E-2JQAI&96jhLK=mWh;0)k&0NFsNJdOf6BmWyR@+co@hUAk!Qy zyW9EiG)MElrOH#yI)lILdjAdXoNC2_Oc=7Kw4_(2eqC7GUz*-O%@sYI3z=4Fz)lF&8bgp$3O&TUgdR2!LHf4~Ke$Mv1>E>9r;*eopgX zB>%;I!tF{7a8rCNa@-OchDO>wd-oUAz%mGy{%5 zSrPS-^24Cp*3uci$9PN*Mat9Edd@1Yg`JUD3nAVDtfYW@JM?jpI4C7kfD-!$8TZs`5*AkEQia)u z!?T(H9oa+Q?QY|PmjSeMLf7r$c8$AyUO6{bfFti&ny? z@FJt6%FGQoSg$ zh9|Jk%|M(59={#^E5j;f3fyTg4#+Ev!03uRu<7Cu30^oj^pFJ^K%%e7F%2VTF`!KZ zoRp0NgMk#I!$>{!%tyYoZEE4(D|tUvk!L)^C3M)sk~e-v5+F__6SYK~$^bu%&!c=*2i)+FtR_ezks|{Nl9| z?`0byxsA(yS?sVZ?SDoQj+gmc)BDzI4&n7Ty}#1Wzqv$IA!99E0;|wx<-hi%(kcP% zoU4)V5|&M|(cH42$UAzx_OngM=4QNS80nDqf~rDZn7v()LX_E8Mg9a2@{>W8m?+Fk zUd_@4Zumk|LS!G76|%zDoDep;s5&Qv);y%?d)6SQ2?lZ5pj zSLeMn$*a-(@LSuf_~p}qsXc84xDrUPntft>t+DL}j#~P<^NP|Ld3?b<+Uo zi!Zw40<+~OnoUw1x>1-TtxHw*Q6hR|S;harZJ{APPHqb50vOL>hKdvoCak4k|9nMd z$|y=Y8Fu&m4B+5;^+1QL?3OV@^+=3Yo5)Oo-U6|4iza_dNh=Ff=2tK1_G7QvYPFin zvx&}2mLt5scx!bi4$WO8HTYj*P4AdH?aFlpBCg~?KzI~_9$i92Iq=xLg2mUQ*(4&5 z2rux{Fd}Pg3iJr(5>Fb7q9};aJco!pY|`5|23SuO&Dgt60&hQeX0N&2km}^@&!M8UL>SV}8|b_7Ch$R2qvywx-(7#=y+&Q>K32go zF6$l)OjP$yiT?P7xE)wZmb<&Vyz@uoFF(79{*FKF|M})<|M1=E;Ump4-T!lAXT6j6 z|J+#H*nal^e2UM0Jenk=OIzwLV_?K9gCSNxI_&}?c^m&dj3VDV#yH%r!b~f={@*&5 z*zB}142fdmP|pp2!#DrufB(N0PWwOq`~PDm!5aiVkmvxlgBX)?8}`s;36p{Z*OUS_ zqu4~U&QO+BU=}oX(?$y(iyE-TntU+gI~aN&z3l)`pT<|&9gvVVE@(Z!AQhdIUzpIA zODQd_$j!d(97h@>)X;$t4ipEd%`&UYQ2)q-*)#b{D}^jf*d-IQb2R@?>Wohd-f$OO zveNuMSqE1>2MxI?L%QAa!=7@zj(v2`LAwqfxM-aFoFxzAX6*g-F?uu0d?ugjZh(Wr zI35uF4?p$8OW^nRSS5Z)4g#chrtx9f6a$){n4IBwthaFw1$Ly>@Pbimi8F38$7l=>sn9M23iTQ1#F`wsT)SRNCkfGMk8MLDmhhOw528jIEg36X-Hc~big{k~^7tr< z*v4`ersm&R&GDS_J^KEwvXL|hxZf(^I;ZIAxC!gx2#^Y0x}Za1{1=6>WRU&?A!0G(YBm-Tz2^~t~Ph> znukWPAvWY9j>20|PO;9$@0*~9R012shcHdPX(;8>23I7M zb44XuT9NVSW=90*X!fJ|8UD=_1}c%#5e~Mo9qv>{)1rMiyh1w>TH6tWsH|23VtE`h z5dbEwv>jT6AoL8?k<%Wyr-Pt$^=FD{A? zVaZ?iI1=OzvyX^nk-|y%-$V{5W?x1mBa#Yp@i^&{e;ufL+Vq-vkA_l6d{yGp*fJ2& z$h#0h3PxGFTt>E=OLpTxM&)-EUcrHl;5JBwv9tR7z9T_Y*etUIG*Y za3Cde2DVm+Mk08TN>B0wViS%D+Se*ZYymixe-j8Ip9F_N14Im)yygKgnaI?6~)&MTfrxEvO+g&c_ zR=og23YImEnuTyFmVU)VlC0nZv-rLhJrcdR2?9zwiqQE37IZ~Ca}N_xl5EA%C;ED+ z{$Y%6`B|#Raj>R#RG_+>uycOb_yqhkM0-1ex7| z8Xj`Tf!kl3GMKbh&Q%T1Z9KsJ(lqO*WP zvkZV7HgPI16q7B{`6YokB*nr#m_=Y(j(8x?DbTZA5g%`#j%3#)9H12J_JY|-%YcIH z&OKtaqYZp{ilHC}VR~fVX&1nJ#_otS)LYb!$n2cWuS2!YV{MJJ-^F(RJL!dpT+OH5 z;s&EAbd2a~gPIZ4-6XMIK`bzu`{5Dc-Vi7HmoO5V^wkTO)gf6>JEXWI z>l!R9awP=XM9KIC$ug1TB(%NhTq*||GAqV)dxy9GEPDWSjlv?SwefgMX!lW@0XcJh8NshiLs8UBkos6m^Sgw@r&Z*I0Ftm}OPT>4t;(}80|uhdIR zMJOs91^h1Q!`{?`eM>PgBpihSS= zfMxfc*N>y`oy8dlPnPRPcS5?^%OJ1(ErTIV&;Wbb+Gq>cb@;@m+_)pmd4+|;T}`>B zQWd_|AkwAyY0QP(SmvefsIa8+(8D1LzQh=zPsKGV*KL0jVm;DK4+m2^uT8Y2dOJCx zL&1%8S+wH(CQHbL1GTo8kdj`8v1TSc;n|XhcgFo!RJ20RyeHMimSV~bDVp=J;G9u0 z)x?zIKrVcn)1C_FWo$5l{zeh>9Z62kQyr$DBT6@7&eiFmW>SY~u@G{W?g5d^j&Psj zeO!JgcPmN{scdyQeXJ*8cJ{KA)40vc<~#Cm5`#qAFB`L=TRf?olc2=Dw4xo(WmKUz z7MjGXoySzQ;_j9Co7CJyX3I}e5yUHHAOqu;cvzU9bkKIBzXmw1@U_l$fXWD^H_oVh z3YS0tsy|MM%+JR$7MG`WvDRVGE38;GLG&hxca-_ogbWxC zjV5A6uJhcEv{+FhqW+r_9D%HY7G@X~c8P2Vs}+qdKh=aa3MHrSvXweo3Z<4lXO|ee zpr-wI_4~r@^M=dzCy12IO^Tk<+v~9>-XQ2ryqh8B!Mu_TCGd#4-Erar&zjP)14q5b zT%megdq%i8!)wi>l75VeY7Fc~1S-!bRxgdXTp4x2#KM1|->cyZM1AU`pBmR3 zrGc*|k^;w3F|kHN1YA8QJdSZ9(-bs%IdQV)O)@sXb<$Q0O;<^E3>MU)Y1y-*?MAl7 z%X)Dp`hfLwJksCBNtpIH=`|-=IT~7NxA&P=9dKH2bTuC{mwrMS2((0bbR}s~P)8}L z4DcKUi`yj6vYwVQA`L~EEOjD9{z$#-D)zj`YfO2Km=LW;y7>mNG(7}#l5^F%iCxu@ zx=V(NJZY|6;B*T%acE?4P#mkUN9JY}4MnwC!xJgNC&eggHvqisI9Db5j3U3Q65e2r zBxTGcC{cy4BigdfLZ+36R;DyO6r`%%m(=c(nEXEE2^d%~XS%{Kqh#p~qQXk}M_NuX zvSMxXUD6BJ1$Y;OH*Qct%Bj~R{1XSFRg+Q^pic7caF`kc&T*`=Hr}q3xG2Wr32Wpxj%^=w6b5azNl9 z2*|{GrouO^z_^s@i7G4)voI)b+MfF0d0% zhG;QU#9YPeS!Qgc+8m8X8IhO)Rn*kj3D^;Y)Xt)D>ILu>WlozQEx4vuepifpluJBF zTH-$<4+&$s5;5} zq4rO~;Z8Y8Lz&we-AN!D!8;abF<~%S09qn_6tl(FV_Qb-GnO1EsHRi*V$4}=8Y6{& z5{&#XQRXoU50zxCoNUzrC4JK%38#ST$Y~ryeNwc;pjU~BBxBREZCJ*@X$JYdCw;xObV_E&;~Bgj;) zIvFN$aa9e&;2PvPv|=u=Xg?lfK4BLgex^B5Q~8H+CWqKze9L@i(LAfHXbN*-hRaYT z7eP?41VH7YWSo^GO9Z_%c<1mIBF?G^m&jH?yt$r_dG3^Dlz;)meb^Ow+^8p7`aV@x zE%~8o zgd@5ZN}!c=oyF4vNKc0}L31@^X_xzOkTfgagPwY{EDz~2ZY&${;PN6O2gJ0j+R#Lb zUgc=S37Cy6dqs6du{bk&rUB6)^-DMeadskdIC)+w#s&w}4gwauxjG@s-seUBotAh~ zUblT*^0X?=4_iV08Rp z5RX|`=vb*8Lwumqpc*a;x6y^8P|o$~nCh!xEI`JrmxPTVqfK0=+GfGH0RQXu008>$^w-_0ES3an=)Z+&o16N94wg-DXIH8*mje%=YOdSjMd653k3V zHdIA#Xjf0YA|j#5*h=|9aG0=6Vo-^d<4$#9?Td9PS_sL-B{eWM;G^S#tX;zC#}0r| zaHpFnXJ8eX_B|F5&`L|&UY2G7P^X?&z4#UzX)K*G989!9?pmbqHU60;1Cq;y6M(_q zmBvL@s#dz0!V9Kp@)l9PEy`!@Iz*bFqG@`ZPHhZ>Az-S;!!cH1Y}4^*|3aLg?4U|4 znRA*^=nvz3BjZ{3BYlixf$~#9Z$2e9mrZ6|ok~4*NP%5&|B+KQegcs#ed+6_Qvtc_ zt#U@qABdEq5M!kFH6x!b#}gs%d|*{KkfD@8lWy9w(=x(M^=>Cc11NHuzNb89WxNVc zCzZ4w@UBW6sKr2%@yINtwa*4eYdL`Wxy~&boRw1C^jgKOsD5meR3J>Wtz-@ zg`4;SdY1Bw6F*Av4rwXAABb6Xgb?Nx*j-&6@Mw~y4vg6-jr+{&5Vteva%_&v5tzcVCOr4o%thK=Y^)+ zh|;`z+!b~wx(bI@FyIWRBY1nxBk>tNoc{rDl?w+r1wS|NYy1KK~!yzyIOQ;raf_;lbg%v!lH?r-e4{zoo!E@4tEf;o$V($MgO7 zCx_?9C-48`aR1C{+Y4@6>zmtKoz2DzthlQZ@cLLm^*WMNpDizFUt8&~Ra&FI-wIIJ z10gpJTD_!=IV~G|`}>E-XM6AV56^KIusAzQ`U}L_D4|dqb*owi&)jZ&cz1Nh9nZf% zdUJMo^6%fiY=8Z-VHWt3b9$+z=JTyfnr|ixs7uyq)!)3|-+OajTpy)7!U^ow#FjOF zJbHI%AC zoA#e?iN{!F>4_^;MA7j9SC zxxK%rzxa0sj|NWBqVg2b{lB{fD5&T`=6$tfAaR+>QY`I%I5{{vS)N{*LbZ}f@Sd$X zsI&sjfHe|sJylu3R8w&0C0L=!3(&FbnO=4tf0`Ei?Rt6z{4X0C@e66dWjb^>ysc93 z!jP&T4+R>p;}~CwN;3>1L{F4iw>}zqP~F!x4Y=H~{b`A$ji(>^B>h%)p?Bv~e3 zo+tn8p$7{+lp$WCHFKqk__=cqZ5CFYcW=!W4sYX|px1Db!f-CEaNUjKagR%XQ#~ml zCn}R|OH~YSwQhn*3sG_T-N-}vGb7ek=8y1y!-1+9u=>?M@(cK_;?(r%s-v^u?%t)YKM-=&@Z16=_Rnm1Xx;jW!u{0{O|5Xe^KKMUK2ooRPFF3e+i@G@ zr>Ou=)FUnOh!ut`9&iq;?AjYwy__B3lC`$Y;h|Z>N^#{8esR~DmIfv7_0JN}HvJp@sDS4Og!HO4SD}%@G^kc=QTCco87-t$HU(2JGJxQTISed+?;MjfRa>35b~vEj zMx%ZF`u)5A-1QvxvA_Zuc1f3;D&jK-jNE5yH7mT=0@?c9!qyk~VfkOP|Bo`q4EcX! zy|a;*|2Njwp5_0i_`I-dqVA(`*l7I4+r9J23cBk#6~Mp#diP-!z)_{#xK9aiTHlIy zUMvLesY2lAUZboO_|N6F!2h~50O>Z1cgufXRz;k#iccDnr=!l_Mae3zBt4DEr)!na z;#3P%I1c@A?3!V?GTstkFH^Bg6$|4ETpZbudINN}7)4}RZD2w}(gK%s$Fgq$C!&xP zA5slR89T9VBzg#A9U7Hu&NnGRU}|gm7~yfPUEXOptZA-lCO6P*#fzXeW*NFtJI3Rq z?Lo?9;{n)rt0L6S={%s2{bBCTS&YbpeH^NM1%iUm8**nf)*{J5EvZ1yYO z&#%i0{;e)+V~kab6t55K9X5(Z?oelvWl|Z=`WbgfC&(o;s4y?N5MVwOw42fy3!YUq znaM<_taD|9IR_=hWwb3>2Uz(D=N|eRUMqFmXm9`P*I&yw*0`PaI{x6bbR7rsE}(3W zsgq*C>cmCD*f8W);Z|-08g8jPB*TPCA*ok;$(4sBkqi26@UVD=AFwbmU7f17$i4|# zZdGQg6|$CKtJextJkm><_e!r0nN?0AFC$-YDOB`Oh@+tKmFYzz_RVNEph#8kTV;gr^VoSuT>qJ4B2$GPOoe5qKpxjj zlWM-?m=~pS10ViG!&A_+T&sBueyNSS;1VCwy&ol=*RqX4P?^}!At|zTRprr?9(^|d ze3lPiqreXqt%f_k;^F}dn_~w5*IC=_0IhX4H!!k6znO%KEF#*ms)b4wj8vRUu~Y_2>Y8)_Hh2%vcZ$&0 zXmE)NEMciZa@Qk|vWBX1j6aG=fxTT6-rx0_NpOvR2@|Y%GQ_YypprnUN^8Xe&T7&K znGfu46EkG5x5k%Y6DcYTKg^CEK8rg;XGc%L2CfC|rE(Su@#>K?=y4KX$}}TC>qE=c z+s~F)2n3?EBgZWM=ZhxC^EIh%9<+|h)l7XWNlt;+ zh2K=gBly0XhRzq&L+D>ChSI+iYA*e0_TckQqT5NWq^XUZX)og#i=Q_uTmM$RBA)G2 zmiT+g_4GwK^I^QxJ%}gAaTInZbG3I?#8qgkH?KZZ4ndD; zNbl!e2N3Z`T)@;8)xS=IqA0%R0`T)g(yZmqnC=Y2THuR=*!dH6(q^d43Iy#r zscLYc51M&|J{i5IoiiPGF@XK44;eFg#pCP|_WA%QpT>wST6(*pGE(#7ky#91a|pO_ zCX+WWGx&(Y-Lu@vjTa%eq9f~R5RvWepAV8UV8D{aL(*K^_Y}kR_yG41goa7rP~wmL zG+jKe=Nd4d*@8!!`I#+Pz@!g&MYA={Gm&}Ouo9uN#{nwOYGdp3C6V6;0M2b3jR(P7 zyx!TcGey-fgCb2cG|s1H;DvrcYiyMNWv#u*?nsNaV9%=Kuh*+) z*6y!!Ife^hrOslNMHo_)j{NR|c?a!7w&0^4rK4w5YJKjBN{4f4vTL|jJOGWdKi(P0 zIfEdZqIz4jaxsaqBzrJU-;V-Hto?yE~hi1=wV%rM&tX7fv*Xud%(c*5PmY)`toVAKa3mH5#U?orSA zq&vkrb{Grvw6pC~IN0Yl_XeNB?EUZrY0>wri>PmKok<|nXC9j`=ED!gqIZJDUXvrt z%ye7A9?x9Zmuv|(p8rpUjQ?p3e)I6QUka5TXZ>S8>n~P5=>m8>9nJT@8xMPR814tr zd|1*{W$;30y9p*wH(5H{t06z%0xbfcPtpH7@@IKWMF?pC4~Ms55)Uz?_M@LHSZOLR{rv%c^+~E&;CwN zF!Qrva{-e+1j=W|2i=R_%!~uN*Qlub4ZBaql7CtFNE=~hdi&gq`IyU(XaPpRrw|8u zjz#R|DONj*dk0~fj46xEcjMl5jR3MaCrIWPu@cQZdlgmocqYEJ=X@r4;)Jqm*vG5SJ}K>-L{=!ueHeg=rrW zx;LkqDnIA%1aQ7c3L|)7?+bNpX_WtEJLIw_bYa#1Ebh2p=*5-#B=y4V6dv{y+Q)t3 zCEv!qC-SxV1Jk{_#-BO1HQT*LH+{T)MfHN?ekZpzKsCfv4?x{?AwFi|-=E5xjS&dh zSr&O|U%o#Z`g9%uZ*)C1?B)+`^5xPehFMv##=Ylf{xg9pO!zxNdCvsu_jFs&1j?TA z4?&=M!R=F_O_&N3)1JjQK{XL5%>AH{vM-7d{%(BRG3IKNglQm!S)K|&IOyTW;E5Dw z_lU80RCnbXIWlX<66`AnfiEaG#^;NBI2wl8@99JyBTj<`K91)J4*Tr;=ZMhSa8V;U z2u<^G&g?O@Qq=lSCY6lBsewrOX}=uyWeWUAVaz|^#_C0Y&#@<2>m0k9W$wYx{dU!x z*9BPjc;pE8IT^shauyoa{=l^Av+rK_m=msb`Zqt%m` z2Q}nZQv*!qMisipJSanb7E?^(%Xqpe2nca6IC|7|Ji@D)>6Beq?xR|)F>-e=3bD%Z zV!5m5h~TP*&k@08w>rE|f+;G#g&PX8@HRM|;m}=}{6Q4#*;ufkgJc2O&-zbODG^aw z?U`n99$^*?=43i*u{6}9CR;;&aFcVlcGgv=l+zr9oyH!`b-AU>nQ_t1YCa1CAee4; zXru122t;4g?DZhWL%h8+9_J}YSe%8qaYZ~!spLPPISAc#c%(74B|7}_6XB{k!;&zrCEWEKA}JM)2mtW zQZNDR=QbABQTOJTRKsHUN36X*jE7Uab9A%k`;^(;9_7o=IZm$aB^W&>bE<1Z~cG z0{I2~!5H^>>JR9~zr!Q=48$!9l0i76XZ%9~bnSR9XM_7WzdYx-{?hj~9`%qtmz?QS z{rT_ZpL9!}b8k^{`?3>V+|HSN;>p(7DF3UN#`i3U0xW7*6b7bKshRnF;ddCfAB@wJ zaa6-Y<#**=mQ3ARVXg=0cvDfxe_3YHxA8E1!rYjckTXugzfVs^SvC2SNC*pXOuDV( znDiihKsWJ6!5MqDJ(UV#@nAgNjbOi?;JUb1GY1MDhl|F#Z1|pke|r8r^mB_uWEGf^ageqr{vdjUIo9B_ zy}611?d)u=+5d%qZEkICbpF)Y+}_+;hktLv_npo4&gP%IwMSS>;WNgHcb@mBLD=mB z+fvzX*6+X5&kJuq9!-+)x}SMV-DU5!pZ3H3I2o;YN5gKr@xnVjKKLIkNi*9z>S1Kt zRTw0@-rM6ht@ZX=1KRAV%xT`pPkfLFgCzC*Vb256FigB&aD`yzF_?K*ae_a1#K3sn zzMo|6M&mk)Fa2m29`_4Rh`JZ1)NtTqhC%&pdKYHhe%m_@vJ6lXG{JVUmnGxCgR!st zC=FQ~IY5-{QF4crc2Gu%i@O!YD%?idN)ZPSm>FFqX`{OOrHc@G}@e zS9HSpd%-A*C-ASfcfdV)Sgbq5ocxk;`sUxz=%yA{|NINd6;;}<2<-H z*fC&KW>bVyYLx4Aphyo10K}=tYr{O!35fsQO2y&4LvTo~2deg|U_kI)%Py68&ZV9;g zVT%9W71*R6`(*a^j!CmhrUm9mXg8y{mqM#iI@%?2$MCnSVVka5bLrHjFi>0Co#8&= z|NGtmmL0aDa0u`k3`PKm_?+m{0XE>xCT~1=xV{*_IylZ3NW{aMj z%AdFEb>uyf4ggllL<7-@ixkp+JdS!^L;>4gJjC|}jds0PYp>SyE2cLxf@P`+06khL zbHySI@S;GrLG(gcYm!)}TQcoYL1!4kYx`4Xp+f958!@YO*u zN&;LNe0>ZH14@L{NL^GOH4?Fd<0{Rlt+G-He;n);~m`dKzgcUM<)NH^}Lt1x6YfTy;q#-@&|1AmB&ik_rp zR=rAtc1Pnk;UEP3(A-*E8#L9ICvdz$ieIm9sjmmYK(+0xzj_<$Z%yOvP4zYKx1&Db z-^7nfI$6KwJIn8KmYRfnC`!|fFvA5*4X}jp{JkznH}SwUMBq}0OmPRtahisVmg#20 zVK*B0kPrP^8V{QU*-c;$n%qH+waZ`T*Cc}oJ5Av5GS!{V`3gMrZ2G(J4#?VR zDa_svPmo4^&$0c2@Pvfp?RS|2JpqgsBuAoDH<;x^iku~~4?M z1xT^Ke_A-{{O$l{>yHB{1S#av;$eDPmn*dHdT$Irz6E(IW@Zik#P+*v1h<%(W~qo1 z#n&E4bC<}`P1GbdI}8%wctrevj~bHzd1#u@7D28Ah6eP^?qc=ugDAz3O3ZsVIk z^o|+UF=J*Z?T=aM(~Iwhgu=1i`{5~kk6&4mj@0f}&()gPsZp=CD$U!(B{#=I&0sY( z&wLpm6at%xDxv`4Dn?bK*5e!>c^@&67_z`T=ug4rYaCQ*Z~)AsxO;aDiy1`If?|s2>ziay*swt*20POX~(bqtNq8 zM)dyio4N#c9$DlKaB7p!b^5%Y`yIV|7IU0CYq_SMer`~$&8IOBKaJ3`LVAArzUAEn zfN}u;=2Y8wjnal}9ikR~7iUL9{XHuNcJ<#a?;rm#iisvIxJ^-VUfcWaw-#xQ^vWCh zT!3Yxq8fz(PO?;gxo<|FO?cI&xAYzFEEP}n9c{>p9gqy z4gm3QCH0?uK?StoUecnlcO~xrGB9^J@^DZ`1#%ld z*@_x={qM%ZUKFr#A4Q+-%@)8jEUD)mAHLQ9w$JU7yC^-%{+^bOd=#axhe5COyy z5P;q|$0ms_Lw&1E0CYq!7A*kH7yuyrZ;^foqbZm}v%KX8q=E2CGi&y#(0CT$tss&b z1zq;JAqD{67La|Wdr3U9{zSfa@6DTr zmp@X*i*VM2Eonft7KJ~xrBa%_u)a|TCxpn%I0y!0>s{a4ejDms?vtS-q5|>4s z;eZuWqS)`HtJoL+r==FtN+~QEIan2!ylP4l!dc3{8iKE_U>#(0QZMMJWc^V zu9A4*VaftvBa?|WFFnJ!cc8!cj@F^M%Cg@CFAV%oAB=8Md)}s!8-iXuiDU}9TCALT zs?}VSPs7<*Pz|kDXTJDVF}-nw+{XtJ1uY)d|8zP|t^;IQ|Hb~+*@5{Do#=MG6ML{m zgK;?zs=aJsq0Ls4{jXg&Wohuyj#1DiHIDrVdPX(HJPTG=T6{JoK2>vS{H-~+Yo{PcP_CBz+Ea;|<(kczc4#_?KMdXka zn_&2co+jd$AX2JecLYQLdBzz4{wySz_UsLd`{MS1fQO`7L6ur>++~?uMkQs=ZHVtL zM#Rnp5lfbc&IZ`C+rZW^T*7dGy_(Hs;il0>3B#kxfsg!z`PNkK$2zf2`;|vTJd-#N z{gVVfDV(5UeiTx!I8Agb;TK(YUT0d}Bz=_fL@6F{0xPlzM-;E$)PND5TU^u+HJjE_ z@enPI#(h?6O+fr?Q+^P*I}s67i=Hcj&sMx3>$bJ_K^{Xl8dE42+YaAF4BD5?_qmM z*b^rOH9NbCW3-fK8NsLfm}?^wjl`J9Q|WiSGv(`xKc1QlZyKr8lM`%(w#pX=Z)f!d zYt~wVZbS0_DrN$LV|Xt`=kk6!$}{L1v4QbYa^2ufXw^bpm8PymJeB5Mh`217l_mw6km-p`nPYu<(dD;iL+wBHz+h z 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 N=){|%&2WQ-0RUykeRBW+ literal 0 HcmV?d00001 diff --git a/hashicorp-vault/values.yaml b/hashicorp-vault/values.yaml index 691f7094..6029a2f0 100644 --- a/hashicorp-vault/values.yaml +++ b/hashicorp-vault/values.yaml @@ -48,4 +48,4 @@ vault: termination: "reencrypt" image: repository: "registry.connect.redhat.com/hashicorp/vault" - tag: "1.16.2-ubi" + tag: "1.17.2-ubi" diff --git a/tests/hashicorp-vault-industrial-edge-factory.expected.yaml b/tests/hashicorp-vault-industrial-edge-factory.expected.yaml index 8156e2af..a17a6974 100644 --- a/tests/hashicorp-vault-industrial-edge-factory.expected.yaml +++ b/tests/hashicorp-vault-industrial-edge-factory.expected.yaml @@ -6,7 +6,7 @@ metadata: name: hashicorp-vault namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -18,7 +18,7 @@ metadata: name: hashicorp-vault-config namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -43,7 +43,7 @@ kind: ClusterRoleBinding metadata: name: hashicorp-vault-server-binding labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -64,7 +64,7 @@ metadata: name: hashicorp-vault-internal namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -96,7 +96,7 @@ metadata: name: hashicorp-vault namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -127,7 +127,7 @@ metadata: name: hashicorp-vault-ui namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault-ui app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -168,7 +168,7 @@ spec: template: metadata: labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault component: server @@ -206,7 +206,7 @@ spec: containers: - name: vault - image: registry.connect.redhat.com/hashicorp/vault:1.16.2-ubi + image: registry.connect.redhat.com/hashicorp/vault:1.17.2-ubi imagePullPolicy: IfNotPresent command: - "/bin/sh" @@ -348,7 +348,7 @@ metadata: name: hashicorp-vault namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -375,7 +375,7 @@ spec: containers: - name: hashicorp-vault-server-test - image: registry.connect.redhat.com/hashicorp/vault:1.16.2-ubi + image: registry.connect.redhat.com/hashicorp/vault:1.17.2-ubi imagePullPolicy: IfNotPresent env: - name: VAULT_ADDR diff --git a/tests/hashicorp-vault-industrial-edge-hub.expected.yaml b/tests/hashicorp-vault-industrial-edge-hub.expected.yaml index 8156e2af..a17a6974 100644 --- a/tests/hashicorp-vault-industrial-edge-hub.expected.yaml +++ b/tests/hashicorp-vault-industrial-edge-hub.expected.yaml @@ -6,7 +6,7 @@ metadata: name: hashicorp-vault namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -18,7 +18,7 @@ metadata: name: hashicorp-vault-config namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -43,7 +43,7 @@ kind: ClusterRoleBinding metadata: name: hashicorp-vault-server-binding labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -64,7 +64,7 @@ metadata: name: hashicorp-vault-internal namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -96,7 +96,7 @@ metadata: name: hashicorp-vault namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -127,7 +127,7 @@ metadata: name: hashicorp-vault-ui namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault-ui app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -168,7 +168,7 @@ spec: template: metadata: labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault component: server @@ -206,7 +206,7 @@ spec: containers: - name: vault - image: registry.connect.redhat.com/hashicorp/vault:1.16.2-ubi + image: registry.connect.redhat.com/hashicorp/vault:1.17.2-ubi imagePullPolicy: IfNotPresent command: - "/bin/sh" @@ -348,7 +348,7 @@ metadata: name: hashicorp-vault namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -375,7 +375,7 @@ spec: containers: - name: hashicorp-vault-server-test - image: registry.connect.redhat.com/hashicorp/vault:1.16.2-ubi + image: registry.connect.redhat.com/hashicorp/vault:1.17.2-ubi imagePullPolicy: IfNotPresent env: - name: VAULT_ADDR diff --git a/tests/hashicorp-vault-medical-diagnosis-hub.expected.yaml b/tests/hashicorp-vault-medical-diagnosis-hub.expected.yaml index 8156e2af..a17a6974 100644 --- a/tests/hashicorp-vault-medical-diagnosis-hub.expected.yaml +++ b/tests/hashicorp-vault-medical-diagnosis-hub.expected.yaml @@ -6,7 +6,7 @@ metadata: name: hashicorp-vault namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -18,7 +18,7 @@ metadata: name: hashicorp-vault-config namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -43,7 +43,7 @@ kind: ClusterRoleBinding metadata: name: hashicorp-vault-server-binding labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -64,7 +64,7 @@ metadata: name: hashicorp-vault-internal namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -96,7 +96,7 @@ metadata: name: hashicorp-vault namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -127,7 +127,7 @@ metadata: name: hashicorp-vault-ui namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault-ui app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -168,7 +168,7 @@ spec: template: metadata: labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault component: server @@ -206,7 +206,7 @@ spec: containers: - name: vault - image: registry.connect.redhat.com/hashicorp/vault:1.16.2-ubi + image: registry.connect.redhat.com/hashicorp/vault:1.17.2-ubi imagePullPolicy: IfNotPresent command: - "/bin/sh" @@ -348,7 +348,7 @@ metadata: name: hashicorp-vault namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -375,7 +375,7 @@ spec: containers: - name: hashicorp-vault-server-test - image: registry.connect.redhat.com/hashicorp/vault:1.16.2-ubi + image: registry.connect.redhat.com/hashicorp/vault:1.17.2-ubi imagePullPolicy: IfNotPresent env: - name: VAULT_ADDR diff --git a/tests/hashicorp-vault-naked.expected.yaml b/tests/hashicorp-vault-naked.expected.yaml index 8727ef0e..c3950b6d 100644 --- a/tests/hashicorp-vault-naked.expected.yaml +++ b/tests/hashicorp-vault-naked.expected.yaml @@ -6,7 +6,7 @@ metadata: name: hashicorp-vault namespace: default labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -18,7 +18,7 @@ metadata: name: hashicorp-vault-config namespace: default labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -43,7 +43,7 @@ kind: ClusterRoleBinding metadata: name: hashicorp-vault-server-binding labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -64,7 +64,7 @@ metadata: name: hashicorp-vault-internal namespace: default labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -96,7 +96,7 @@ metadata: name: hashicorp-vault namespace: default labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -127,7 +127,7 @@ metadata: name: hashicorp-vault-ui namespace: default labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault-ui app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -168,7 +168,7 @@ spec: template: metadata: labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault component: server @@ -206,7 +206,7 @@ spec: containers: - name: vault - image: registry.connect.redhat.com/hashicorp/vault:1.16.2-ubi + image: registry.connect.redhat.com/hashicorp/vault:1.17.2-ubi imagePullPolicy: IfNotPresent command: - "/bin/sh" @@ -348,7 +348,7 @@ metadata: name: hashicorp-vault namespace: default labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -375,7 +375,7 @@ spec: containers: - name: hashicorp-vault-server-test - image: registry.connect.redhat.com/hashicorp/vault:1.16.2-ubi + image: registry.connect.redhat.com/hashicorp/vault:1.17.2-ubi imagePullPolicy: IfNotPresent env: - name: VAULT_ADDR diff --git a/tests/hashicorp-vault-normal.expected.yaml b/tests/hashicorp-vault-normal.expected.yaml index 8156e2af..a17a6974 100644 --- a/tests/hashicorp-vault-normal.expected.yaml +++ b/tests/hashicorp-vault-normal.expected.yaml @@ -6,7 +6,7 @@ metadata: name: hashicorp-vault namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -18,7 +18,7 @@ metadata: name: hashicorp-vault-config namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -43,7 +43,7 @@ kind: ClusterRoleBinding metadata: name: hashicorp-vault-server-binding labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -64,7 +64,7 @@ metadata: name: hashicorp-vault-internal namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -96,7 +96,7 @@ metadata: name: hashicorp-vault namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -127,7 +127,7 @@ metadata: name: hashicorp-vault-ui namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault-ui app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -168,7 +168,7 @@ spec: template: metadata: labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault component: server @@ -206,7 +206,7 @@ spec: containers: - name: vault - image: registry.connect.redhat.com/hashicorp/vault:1.16.2-ubi + image: registry.connect.redhat.com/hashicorp/vault:1.17.2-ubi imagePullPolicy: IfNotPresent command: - "/bin/sh" @@ -348,7 +348,7 @@ metadata: name: hashicorp-vault namespace: pattern-namespace labels: - helm.sh/chart: vault-0.28.0 + helm.sh/chart: vault-0.28.1 app.kubernetes.io/name: vault app.kubernetes.io/instance: hashicorp-vault app.kubernetes.io/managed-by: Helm @@ -375,7 +375,7 @@ spec: containers: - name: hashicorp-vault-server-test - image: registry.connect.redhat.com/hashicorp/vault:1.16.2-ubi + image: registry.connect.redhat.com/hashicorp/vault:1.17.2-ubi imagePullPolicy: IfNotPresent env: - name: VAULT_ADDR From 0b45eeada9359aeb447301799206859228dc4f2f Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Mon, 15 Jul 2024 11:20:54 -0600 Subject: [PATCH 57/64] Update ESO to 0.9.20 --- golang-external-secrets/Chart.yaml | 2 +- .../charts/external-secrets-0.9.19.tgz | Bin 76457 -> 0 bytes .../charts/external-secrets-0.9.20.tgz | Bin 0 -> 81759 bytes golang-external-secrets/values.yaml | 6 +- ...rets-industrial-edge-factory.expected.yaml | 505 ++++++++++++++++-- ...-secrets-industrial-edge-hub.expected.yaml | 505 ++++++++++++++++-- ...ecrets-medical-diagnosis-hub.expected.yaml | 505 ++++++++++++++++-- ...olang-external-secrets-naked.expected.yaml | 505 ++++++++++++++++-- ...lang-external-secrets-normal.expected.yaml | 505 ++++++++++++++++-- 9 files changed, 2279 insertions(+), 254 deletions(-) delete mode 100644 golang-external-secrets/charts/external-secrets-0.9.19.tgz create mode 100644 golang-external-secrets/charts/external-secrets-0.9.20.tgz diff --git a/golang-external-secrets/Chart.yaml b/golang-external-secrets/Chart.yaml index b304d092..802979b4 100644 --- a/golang-external-secrets/Chart.yaml +++ b/golang-external-secrets/Chart.yaml @@ -6,6 +6,6 @@ name: golang-external-secrets version: 0.1.0 dependencies: - name: external-secrets - version: "0.9.19" + version: "0.9.20" repository: "https://charts.external-secrets.io" #"https://external-secrets.github.io/kubernetes-external-secrets" diff --git a/golang-external-secrets/charts/external-secrets-0.9.19.tgz b/golang-external-secrets/charts/external-secrets-0.9.19.tgz deleted file mode 100644 index 66fffaa0b08d686867fc9e4307204eaae1e22964..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 76457 zcmV)gK%~DPiwFP!000001ML0#cH2glFpBrzehM6BX4(0EB565})1TMLH={^STJ4*b zq}Zp|tXXl9ghWIjzyUzXN;;2qUf?|0Z|_|f6z)|dNYS0bn(0_Xp)R|s_Wk02&io`| z;V|{5iJzt8zx4k+h3C6(zs3I^e)sKD{lD`0%i;4E-#mTs^y#w5o%K7M)skLN7OM)zzH_BIA?@Qdfq8~6Xar-!)z&%S%{ z;+yZD;{LxleERG!-qYS@(DMAr_n$3;4}OvcarDx=efEegm-(MhNB?_t_`e^`{B)WG z%Zz?}CC-b-&x^NU5xe#mew2AvapJvRP2jbk`RSv1yzpOo^DJAYFURBSAe*lyqiMVt zSB_lyheyE_hmxNr>~6$AU!{HmuQC|Ttf%pU1<{zLDZNbNVHjV-|FGoRA1$NnM>qcc zU7XC)myd?tjhgzfGNGX-|Anm-gdYE&@4Z6+(dg;$>ElN@RtEnMZ?Qig{tjPyH+~of z(PGMOSC{_@quDEpjkIz|`%e{uMtg#W*Lad_zP|1O^L{(Ezl zdK2G|yqUiY<9mPRrK{=GPt&Va7~Xq9M2IV0vZ?R={<|lSi#I6uG*ayb-pKpokN@k@ zqtnO(Z0jdp7Q-0V(AO#rqH9G|F8G%R-hI6C?t(D%A|ECItpS01tEI<0-sB>S6aNv= zo8u7n&rh^py#(<5DuLNOL4xFeW-vkjz?(=kM-`p9zA;W7CQ(c z_;5kk)`S1c=Ds%zuCDw9i5w#2)Qhk5FH?_2GjAT>;Y@)(T?N-G=m$PrJeslymI}0S z1x;YVFg5QdB4#fUd?U_o{S9a(fM`=>-oyTD_x~3-?@ORIqineuFW7$n51&7O{$26@ zKYRMEyZ^g+e*b;^zaG8%yu=fXCmk;>9&h~jl+Na(|22k_`TOrfzzA2s-89_vfj7*X z;pLKN`yKW;`oO}K&s)9+7A6U1zV}ZrOIFd;d+`nZGgw@#uC9X5-e5TJL|;Bk3;y|t zrg@C_*N59HN8l*we^x9Et^z<5z$eiHMvp%Fyl-ls;Rv`G#B5UrT%?!ch0B>$zHI0t zoWW&=yBh|JAmgYfn+K`)1keY94z3hXG0pvL8&i3sQEdo|0h3vCwy;m>Ib)k_V@rd6<|yP z&;sBS4D&{uilTg!8eSwpGHdo(y=~g)#s)gT3J~Ix>{z+DciMqQY#{^@Jj`^c#SP)D zLN@V3lY>po^VODjQ$J|@-$M9;olF3Z{Q7n8Q7zfc(H(vXsRZg!yEFs0x4LG z()pOCPn0}}rr~PVvcwUeL`%aIHf9P8#TzluNV`X3^+!rR$9I75M!DEJ3gWSn4s+f@ z`{bX1E90!Z-_>5YP(K?^?s-S@#9a8vZIGXrJK$r~*_#qH`P9Wqv-lru5$4ONJzvcL zAKv+sc^uzt9q?)(w*j?q87_RdPSfHISRbG@%jNyQ^akR?!A_Pp^^Y&GS2n6Rs%*LGLl;=OJoj%tcwjNQ=J2osI*t3j9Q@^