From 0aef0f39f4a7f13e3ddb596c3fcdb7a608cd1706 Mon Sep 17 00:00:00 2001 From: Martin Jackson Date: Fri, 8 May 2026 09:46:09 -0500 Subject: [PATCH 1/4] Add Ansible DevMode --- Chart.yaml | 2 +- README.md | 6 ++- README.md.gotmpl | 1 + templates/imperative/_helpers.tpl | 26 +++++++++++ .../imperative/auto-approve-installplans.yaml | 1 + templates/imperative/job.yaml | 1 + templates/imperative/unsealjob.yaml | 1 + tests/application_vault_unseal_test.yaml | 30 ++++++++++++ ...rative_auto_approve_installplans_test.yaml | 39 ++++++++++++++++ tests/imperative_job_test.yaml | 46 +++++++++++++++++++ values.schema.json | 25 ++++++++++ values.yaml | 4 ++ 12 files changed, 180 insertions(+), 2 deletions(-) create mode 100644 tests/imperative_auto_approve_installplans_test.yaml diff --git a/Chart.yaml b/Chart.yaml index c065c65..66ed6e0 100644 --- a/Chart.yaml +++ b/Chart.yaml @@ -3,7 +3,7 @@ description: A Helm chart to create per-clustergroup ArgoCD applications and any keywords: - pattern name: clustergroup -version: 0.9.50 +version: 0.9.51 home: https://github.com/validatedpatterns/clustergroup-chart maintainers: - name: Validated Patterns Team diff --git a/README.md b/README.md index 0a269c3..1288a13 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # clustergroup -![Version: 0.9.50](https://img.shields.io/badge/Version-0.9.50-informational?style=flat-square) +![Version: 0.9.51](https://img.shields.io/badge/Version-0.9.51-informational?style=flat-square) A Helm chart to create per-clustergroup ArgoCD applications and any required namespaces or subscriptions. @@ -8,6 +8,7 @@ This chart is used to set up the basic building blocks in [Validated Patterns](h ### Notable changes +* v0.9.51: Add ansibleDevMode to simplify rhvp.cluster_utils development * v0.9.50: Add support to custom `rbac` in `ArgoDC.spec` * v0.9.49: Boolean Templates in override values now also render correctly * v0.9.48: Templates in override values now render @@ -85,6 +86,9 @@ clusterGroup: | clusterGroup.imperative.adminClusterRoleName | string | `"imperative-admin-cluster-role"` | | | clusterGroup.imperative.adminServiceAccountCreate | bool | `true` | | | clusterGroup.imperative.adminServiceAccountName | string | `"imperative-admin-sa"` | | +| clusterGroup.imperative.ansibleDevMode.enabled | bool | `false` | | +| clusterGroup.imperative.ansibleDevMode.requirementsContent | string | `""` | | +| clusterGroup.imperative.ansibleDevMode.requirementsFile | string | `"requirements.yml"` | | | clusterGroup.imperative.clusterRoleName | string | `"imperative-cluster-role"` | | | clusterGroup.imperative.clusterRoleYaml | string | `""` | | | clusterGroup.imperative.cronJobName | string | `"imperative-cronjob"` | | diff --git a/README.md.gotmpl b/README.md.gotmpl index 2701416..ef87981 100644 --- a/README.md.gotmpl +++ b/README.md.gotmpl @@ -9,6 +9,7 @@ This chart is used to set up the basic building blocks in [Validated Patterns](h ### Notable changes +* v0.9.51: Add ansibleDevMode to simplify rhvp.cluster_utils development * v0.9.50: Add support to custom `rbac` in `ArgoDC.spec` * v0.9.49: Boolean Templates in override values now also render correctly * v0.9.48: Templates in override values now render diff --git a/templates/imperative/_helpers.tpl b/templates/imperative/_helpers.tpl index 8e66e9a..cd1c0e3 100644 --- a/templates/imperative/_helpers.tpl +++ b/templates/imperative/_helpers.tpl @@ -73,6 +73,32 @@ git clone --recurse-submodules --single-branch ${BRANCH} --depth 1 -- "${URL}" /git/repo; chmod 0770 /git/{repo,home}; {{- end }} + +{{/* Optional ansible dev mode init container */}} +{{- define "imperative.initcontainers.ansible-dev-mode" }} +{{- if $.Values.clusterGroup.imperative.ansibleDevMode.enabled }} +- name: ansible-dev-mode + image: {{ $.Values.clusterGroup.imperative.image }} + imagePullPolicy: {{ $.Values.clusterGroup.imperative.imagePullPolicy }} + env: + - name: HOME + value: /git/home + workingDir: /git/repo + command: + - 'sh' + - '-c' + - |- + {{- with $.Values.clusterGroup.imperative.ansibleDevMode.requirementsContent }} + cat <<'EOF' > {{ $.Values.clusterGroup.imperative.ansibleDevMode.requirementsFile | quote }} +{{ . | nindent 4 }} + EOF + {{- end }} + ansible-galaxy collection install -r {{ $.Values.clusterGroup.imperative.ansibleDevMode.requirementsFile | quote }} + volumeMounts: + {{- include "imperative.volumemounts_ca" $ | indent 4 }} +{{- end }} +{{- end }} + {{/* Final done container */}} {{- define "imperative.containers.done" }} - name: "done" diff --git a/templates/imperative/auto-approve-installplans.yaml b/templates/imperative/auto-approve-installplans.yaml index dc69b6b..a233631 100644 --- a/templates/imperative/auto-approve-installplans.yaml +++ b/templates/imperative/auto-approve-installplans.yaml @@ -22,6 +22,7 @@ spec: # reason for that is ansible refuses to create temporary folders in there {{- include "imperative.initcontainers.fetch-ca" . | indent 12 }} {{- include "imperative.initcontainers.gitinit-ca" . | indent 12 }} + {{- include "imperative.initcontainers.ansible-dev-mode" . | indent 12 }} - name: auto-approve-installplans image: {{ $.Values.clusterGroup.imperative.image }} imagePullPolicy: {{ $.Values.clusterGroup.imperative.imagePullPolicy }} diff --git a/templates/imperative/job.yaml b/templates/imperative/job.yaml index 3260969..c7d262e 100644 --- a/templates/imperative/job.yaml +++ b/templates/imperative/job.yaml @@ -23,6 +23,7 @@ spec: # reason for that is ansible refuses to create temporary folders in there {{- include "imperative.initcontainers.fetch-ca" . | indent 12 }} {{- include "imperative.initcontainers.gitinit-ca" . | indent 12 }} + {{- include "imperative.initcontainers.ansible-dev-mode" . | indent 12 }} {{- range $.Values.clusterGroup.imperative.jobs }} {{- if ne (.disabled | default "false" | toString | lower ) "true" }} - name: {{ .name }} diff --git a/templates/imperative/unsealjob.yaml b/templates/imperative/unsealjob.yaml index cb0358c..a50a3ea 100644 --- a/templates/imperative/unsealjob.yaml +++ b/templates/imperative/unsealjob.yaml @@ -36,6 +36,7 @@ spec: # reason for that is ansible refuses to create temporary folders in there {{- include "imperative.initcontainers.fetch-ca" . | indent 12 }} {{- include "imperative.initcontainers.gitinit-ca" . | indent 12 }} + {{- include "imperative.initcontainers.ansible-dev-mode" . | indent 12 }} - name: unseal-playbook image: {{ $.Values.clusterGroup.imperative.image }} imagePullPolicy: {{ $.Values.clusterGroup.imperative.imagePullPolicy }} diff --git a/tests/application_vault_unseal_test.yaml b/tests/application_vault_unseal_test.yaml index c70a286..828066b 100644 --- a/tests/application_vault_unseal_test.yaml +++ b/tests/application_vault_unseal_test.yaml @@ -158,3 +158,33 @@ tests: asserts: - hasDocuments: count: 0 + + - it: should include ansible dev mode init container when enabled + set: + global: + repoURL: https://github.com/validatedpatterns/multicloud-gitops + multiSourceRepoUrl: https://charts.validatedpatterns.io + clusterGroup: + isHubCluster: true + imperative: + ansibleDevMode: + enabled: true + requirementsFile: dev/requirements.yml + applications: + acm: + name: acm + namespace: open-cluster-management + project: hub + chart: acm + chartVersion: 0.1.* + asserts: + - isKind: + of: CronJob + - hasDocuments: + count: 1 + - equal: + path: spec.jobTemplate.spec.template.spec.initContainers[2].name + value: ansible-dev-mode + - equal: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + value: ansible-galaxy collection install -r "dev/requirements.yml" diff --git a/tests/imperative_auto_approve_installplans_test.yaml b/tests/imperative_auto_approve_installplans_test.yaml new file mode 100644 index 0000000..d433d0f --- /dev/null +++ b/tests/imperative_auto_approve_installplans_test.yaml @@ -0,0 +1,39 @@ +suite: Test auto-approve installplans job +templates: + - templates/imperative/auto-approve-installplans.yaml +release: + name: release-test +tests: + - it: should create auto-approve cronjob when option is enabled + set: + global: + options: + autoApproveManualInstallPlans: true + clusterGroup: + imperative: + adminServiceAccountName: imperative-admin-sa + asserts: + - hasDocuments: + count: 1 + - isKind: + of: CronJob + + - it: should include ansible dev mode init container when enabled + set: + global: + options: + autoApproveManualInstallPlans: true + clusterGroup: + imperative: + ansibleDevMode: + enabled: true + requirementsFile: ansible/requirements.yml + asserts: + - hasDocuments: + count: 1 + - equal: + path: spec.jobTemplate.spec.template.spec.initContainers[2].name + value: ansible-dev-mode + - equal: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + value: ansible-galaxy collection install -r "ansible/requirements.yml" diff --git a/tests/imperative_job_test.yaml b/tests/imperative_job_test.yaml index b5d2684..4d3ed3f 100644 --- a/tests/imperative_job_test.yaml +++ b/tests/imperative_job_test.yaml @@ -143,3 +143,49 @@ tests: asserts: - hasDocuments: count: 1 + + - it: should add ansible dev mode init container when enabled + set: + clusterGroup: + imperative: + jobs: + - name: deploy-app + playbook: deploy-application.yml + ansibleDevMode: + enabled: true + requirementsFile: collections/requirements.yml + asserts: + - hasDocuments: + count: 1 + - equal: + path: spec.jobTemplate.spec.template.spec.initContainers[2].name + value: ansible-dev-mode + - equal: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + value: ansible-galaxy collection install -r "collections/requirements.yml" + + - it: should inject inline requirements content when provided + set: + clusterGroup: + imperative: + jobs: + - name: deploy-app + playbook: deploy-application.yml + ansibleDevMode: + enabled: true + requirementsFile: collections/requirements.yml + requirementsContent: | + collections: + - name: rhvp.cluster_utils + asserts: + - hasDocuments: + count: 1 + - equal: + path: spec.jobTemplate.spec.template.spec.initContainers[2].name + value: ansible-dev-mode + - matchRegex: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + pattern: 'cat <<''EOF'' > "collections/requirements.yml"' + - matchRegex: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + pattern: 'ansible-galaxy collection install -r "collections/requirements.yml"' diff --git a/values.schema.json b/values.schema.json index c17c0d1..a4f36d2 100644 --- a/values.schema.json +++ b/values.schema.json @@ -824,6 +824,9 @@ "type": "string", "default": "quay.io/validatedpatterns/imperative-container:v1" }, + "ansibleDevMode": { + "$ref": "#/definitions/AnsibleDevMode" + }, "namespace": { "type": "string", "default": "imperative", @@ -905,6 +908,28 @@ ], "title": "Imperative" }, + "AnsibleDevMode": { + "type": "object", + "additionalProperties": false, + "properties": { + "enabled": { + "type": "boolean", + "default": false + }, + "requirementsFile": { + "type": "string", + "default": "requirements.yml" + }, + "requirementsContent": { + "type": "string", + "default": "" + } + }, + "required": [ + "enabled" + ], + "title": "AnsibleDevMode" + }, "Job": { "type": "object", "additionalProperties": false, diff --git a/values.yaml b/values.yaml index c62f67e..0c191a3 100644 --- a/values.yaml +++ b/values.yaml @@ -147,6 +147,10 @@ clusterGroup: imperative: jobs: [] image: quay.io/validatedpatterns/imperative-container:v1 + ansibleDevMode: + enabled: false + requirementsFile: "requirements.yml" + requirementsContent: "" namespace: "imperative" # configmap name in the namespace that will contain all helm values valuesConfigMap: "helm-values-configmap" From 0dda1b77aa4eefb3ae42f27fb742b9ecbb5554a4 Mon Sep 17 00:00:00 2001 From: Martin Jackson Date: Fri, 8 May 2026 11:05:24 -0500 Subject: [PATCH 2/4] Add ability to inject ansible-config as well as requirements.yml --- README.md | 10 ++- README.md.gotmpl | 2 +- templates/imperative/_helpers.tpl | 5 ++ tests/application_vault_unseal_test.yaml | 37 ++++++++ ...rative_auto_approve_installplans_test.yaml | 28 ++++++ tests/imperative_job_test.yaml | 88 +++++++++++++++++++ values.schema.json | 8 ++ values.yaml | 7 ++ 8 files changed, 180 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1288a13..2d1d987 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ This chart is used to set up the basic building blocks in [Validated Patterns](h ### Notable changes -* v0.9.51: Add ansibleDevMode to simplify rhvp.cluster_utils development +* v0.9.51: Add ansibleDevMode (requirements.yml injection and optional ansibleCfgFile/ansibleCfgContent) to simplify rhvp.cluster_utils development * v0.9.50: Add support to custom `rbac` in `ArgoDC.spec` * v0.9.49: Boolean Templates in override values now also render correctly * v0.9.48: Templates in override values now render @@ -86,9 +86,11 @@ clusterGroup: | clusterGroup.imperative.adminClusterRoleName | string | `"imperative-admin-cluster-role"` | | | clusterGroup.imperative.adminServiceAccountCreate | bool | `true` | | | clusterGroup.imperative.adminServiceAccountName | string | `"imperative-admin-sa"` | | -| clusterGroup.imperative.ansibleDevMode.enabled | bool | `false` | | -| clusterGroup.imperative.ansibleDevMode.requirementsContent | string | `""` | | -| clusterGroup.imperative.ansibleDevMode.requirementsFile | string | `"requirements.yml"` | | +| clusterGroup.imperative.ansibleDevMode.ansibleCfgContent | string | `""` | Inline ansible.cfg; when non-empty, written to ansibleCfgFile before ansible-galaxy (so galaxy and playbooks honor collections_path, etc.). | +| clusterGroup.imperative.ansibleDevMode.ansibleCfgFile | string | `"ansible.cfg"` | Path under the cloned pattern repo for optional injected ansible.cfg (written from ansibleCfgContent when set). | +| clusterGroup.imperative.ansibleDevMode.enabled | bool | `false` | When true, run an init container before imperative playbooks that can install collections and optionally write ansible.cfg into the cloned repo (/git/repo). | +| clusterGroup.imperative.ansibleDevMode.requirementsContent | string | `""` | Inline requirements.yml; when non-empty, written to requirementsFile before galaxy install. | +| clusterGroup.imperative.ansibleDevMode.requirementsFile | string | `"requirements.yml"` | Path under the cloned pattern repo for ansible-galaxy -r (written from requirementsContent when set). | | clusterGroup.imperative.clusterRoleName | string | `"imperative-cluster-role"` | | | clusterGroup.imperative.clusterRoleYaml | string | `""` | | | clusterGroup.imperative.cronJobName | string | `"imperative-cronjob"` | | diff --git a/README.md.gotmpl b/README.md.gotmpl index ef87981..30bd5eb 100644 --- a/README.md.gotmpl +++ b/README.md.gotmpl @@ -9,7 +9,7 @@ This chart is used to set up the basic building blocks in [Validated Patterns](h ### Notable changes -* v0.9.51: Add ansibleDevMode to simplify rhvp.cluster_utils development +* v0.9.51: Add ansibleDevMode (requirements.yml injection and optional ansibleCfgFile/ansibleCfgContent) to simplify rhvp.cluster_utils development * v0.9.50: Add support to custom `rbac` in `ArgoDC.spec` * v0.9.49: Boolean Templates in override values now also render correctly * v0.9.48: Templates in override values now render diff --git a/templates/imperative/_helpers.tpl b/templates/imperative/_helpers.tpl index cd1c0e3..4b07778 100644 --- a/templates/imperative/_helpers.tpl +++ b/templates/imperative/_helpers.tpl @@ -90,6 +90,11 @@ - |- {{- with $.Values.clusterGroup.imperative.ansibleDevMode.requirementsContent }} cat <<'EOF' > {{ $.Values.clusterGroup.imperative.ansibleDevMode.requirementsFile | quote }} +{{ . | nindent 4 }} + EOF + {{- end }} + {{- with $.Values.clusterGroup.imperative.ansibleDevMode.ansibleCfgContent }} + cat <<'EOF' > {{ $.Values.clusterGroup.imperative.ansibleDevMode.ansibleCfgFile | quote }} {{ . | nindent 4 }} EOF {{- end }} diff --git a/tests/application_vault_unseal_test.yaml b/tests/application_vault_unseal_test.yaml index 828066b..035562b 100644 --- a/tests/application_vault_unseal_test.yaml +++ b/tests/application_vault_unseal_test.yaml @@ -188,3 +188,40 @@ tests: - equal: path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] value: ansible-galaxy collection install -r "dev/requirements.yml" + + - it: should inject ansible.cfg in unseal ansible dev mode init when ansibleCfgContent is set + set: + global: + repoURL: https://github.com/validatedpatterns/multicloud-gitops + multiSourceRepoUrl: https://charts.validatedpatterns.io + clusterGroup: + isHubCluster: true + imperative: + ansibleDevMode: + enabled: true + requirementsFile: dev/requirements.yml + ansibleCfgFile: dev/imperative-ansible.cfg + ansibleCfgContent: | + [defaults] + collections_path=~/.ansible/collections:/usr/share/ansible/collections + applications: + acm: + name: acm + namespace: open-cluster-management + project: hub + chart: acm + chartVersion: 0.1.* + asserts: + - isKind: + of: CronJob + - hasDocuments: + count: 1 + - equal: + path: spec.jobTemplate.spec.template.spec.initContainers[2].name + value: ansible-dev-mode + - matchRegex: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + pattern: 'cat <<''EOF'' > "dev/imperative-ansible.cfg"' + - matchRegex: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + pattern: 'ansible-galaxy collection install -r "dev/requirements.yml"' diff --git a/tests/imperative_auto_approve_installplans_test.yaml b/tests/imperative_auto_approve_installplans_test.yaml index d433d0f..f803a74 100644 --- a/tests/imperative_auto_approve_installplans_test.yaml +++ b/tests/imperative_auto_approve_installplans_test.yaml @@ -37,3 +37,31 @@ tests: - equal: path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] value: ansible-galaxy collection install -r "ansible/requirements.yml" + + - it: should inject ansible.cfg in auto-approve ansible dev mode when ansibleCfgContent is set + set: + global: + options: + autoApproveManualInstallPlans: true + clusterGroup: + imperative: + adminServiceAccountName: imperative-admin-sa + ansibleDevMode: + enabled: true + requirementsFile: ansible/requirements.yml + ansibleCfgFile: ansible/ansible.cfg + ansibleCfgContent: | + [defaults] + collections_path=~/.ansible/collections:/usr/share/ansible/collections + asserts: + - hasDocuments: + count: 1 + - equal: + path: spec.jobTemplate.spec.template.spec.initContainers[2].name + value: ansible-dev-mode + - matchRegex: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + pattern: 'cat <<''EOF'' > "ansible/ansible.cfg"' + - matchRegex: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + pattern: 'ansible-galaxy collection install -r "ansible/requirements.yml"' diff --git a/tests/imperative_job_test.yaml b/tests/imperative_job_test.yaml index 4d3ed3f..39925a2 100644 --- a/tests/imperative_job_test.yaml +++ b/tests/imperative_job_test.yaml @@ -189,3 +189,91 @@ tests: - matchRegex: path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] pattern: 'ansible-galaxy collection install -r "collections/requirements.yml"' + + - it: should inject requirements and ansible.cfg heredocs when both contents are set + set: + clusterGroup: + imperative: + jobs: + - name: deploy-app + playbook: deploy-application.yml + ansibleDevMode: + enabled: true + requirementsFile: collections/requirements.yml + requirementsContent: | + collections: + - name: rhvp.cluster_utils + ansibleCfgFile: dev/ansible.cfg + ansibleCfgContent: | + [defaults] + collections_path=~/.ansible/collections:/usr/share/ansible/collections + asserts: + - hasDocuments: + count: 1 + - matchRegex: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + pattern: 'cat <<''EOF'' > "collections/requirements.yml"' + - matchRegex: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + pattern: 'cat <<''EOF'' > "dev/ansible.cfg"' + - matchRegex: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + pattern: 'ansible-galaxy collection install -r "collections/requirements.yml"' + + - it: should inject ansible.cfg only when requirementsContent is empty + set: + clusterGroup: + imperative: + jobs: + - name: deploy-app + playbook: deploy-application.yml + ansibleDevMode: + enabled: true + requirementsFile: collections/requirements.yml + requirementsContent: "" + ansibleCfgFile: dev/ansible.cfg + ansibleCfgContent: | + [defaults] + collections_path=~/.ansible/collections:/usr/share/ansible/collections + asserts: + - hasDocuments: + count: 1 + - matchRegex: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + pattern: 'cat <<''EOF'' > "dev/ansible.cfg"' + - notMatchRegex: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + pattern: 'cat <<''EOF'' > "collections/requirements.yml"' + - matchRegex: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + pattern: 'ansible-galaxy collection install -r "collections/requirements.yml"' + + - it: should inject inline ansible.cfg when ansibleCfgContent is provided + set: + clusterGroup: + imperative: + jobs: + - name: deploy-app + playbook: deploy-application.yml + ansibleDevMode: + enabled: true + requirementsFile: collections/requirements.yml + ansibleCfgFile: dev/ansible.cfg + ansibleCfgContent: | + [defaults] + collections_path=~/.ansible/collections:/usr/share/ansible/collections + asserts: + - hasDocuments: + count: 1 + - equal: + path: spec.jobTemplate.spec.template.spec.initContainers[2].name + value: ansible-dev-mode + - matchRegex: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + pattern: 'cat <<''EOF'' > "dev/ansible.cfg"' + - matchRegex: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + pattern: 'collections_path=~/.ansible/collections:/usr/share/ansible/collections' + - matchRegex: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + pattern: 'ansible-galaxy collection install -r "collections/requirements.yml"' diff --git a/values.schema.json b/values.schema.json index a4f36d2..41c5a42 100644 --- a/values.schema.json +++ b/values.schema.json @@ -923,6 +923,14 @@ "requirementsContent": { "type": "string", "default": "" + }, + "ansibleCfgFile": { + "type": "string", + "default": "ansible.cfg" + }, + "ansibleCfgContent": { + "type": "string", + "default": "" } }, "required": [ diff --git a/values.yaml b/values.yaml index 0c191a3..bc85842 100644 --- a/values.yaml +++ b/values.yaml @@ -148,9 +148,16 @@ clusterGroup: jobs: [] image: quay.io/validatedpatterns/imperative-container:v1 ansibleDevMode: + # -- When true, run an init container before imperative playbooks that can install collections and optionally write ansible.cfg into the cloned repo (/git/repo). enabled: false + # -- Path under the cloned pattern repo for ansible-galaxy -r (written from requirementsContent when set). requirementsFile: "requirements.yml" + # -- Inline requirements.yml; when non-empty, written to requirementsFile before galaxy install. requirementsContent: "" + # -- Path under the cloned pattern repo for optional injected ansible.cfg (written from ansibleCfgContent when set). + ansibleCfgFile: "ansible.cfg" + # -- Inline ansible.cfg; when non-empty, written to ansibleCfgFile before ansible-galaxy (so galaxy and playbooks honor collections_path, etc.). + ansibleCfgContent: "" namespace: "imperative" # configmap name in the namespace that will contain all helm values valuesConfigMap: "helm-values-configmap" From dc73f8cc8b310c6160898d12d4c249f64e29a206 Mon Sep 17 00:00:00 2001 From: Martin Jackson Date: Fri, 8 May 2026 12:23:47 -0500 Subject: [PATCH 3/4] Add extraPlaybokArgs --- README.md | 3 +- README.md.gotmpl | 2 +- .../imperative/auto-approve-installplans.yaml | 3 ++ templates/imperative/job.yaml | 3 ++ templates/imperative/unsealjob.yaml | 3 ++ ...rative_auto_approve_installplans_test.yaml | 17 +++++++++ tests/imperative_job_test.yaml | 37 +++++++++++++++++++ tests/unsealjob_null_handling_test.yaml | 32 ++++++++++++++++ values.schema.json | 8 ++++ values.yaml | 2 + 10 files changed, 108 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2d1d987..ecd4695 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ This chart is used to set up the basic building blocks in [Validated Patterns](h ### Notable changes -* v0.9.51: Add ansibleDevMode (requirements.yml injection and optional ansibleCfgFile/ansibleCfgContent) to simplify rhvp.cluster_utils development +* v0.9.51: Add ansibleDevMode (requirements.yml injection and optional ansibleCfgFile/ansibleCfgContent) to simplify rhvp.cluster_utils development. Add extraPlaybookArgs to imperative as well. * v0.9.50: Add support to custom `rbac` in `ArgoDC.spec` * v0.9.49: Boolean Templates in override values now also render correctly * v0.9.48: Templates in override values now render @@ -94,6 +94,7 @@ clusterGroup: | clusterGroup.imperative.clusterRoleName | string | `"imperative-cluster-role"` | | | clusterGroup.imperative.clusterRoleYaml | string | `""` | | | clusterGroup.imperative.cronJobName | string | `"imperative-cronjob"` | | +| clusterGroup.imperative.extraPlaybookArgs | list | `[]` | Optional extra arguments for every ansible-playbook invocation (imperative jobs, vault unseal, auto-approve installplans). Each list entry is one argv token. Empty by default. | | clusterGroup.imperative.image | string | `"quay.io/validatedpatterns/imperative-container:v1"` | | | clusterGroup.imperative.imagePullPolicy | string | `"Always"` | | | clusterGroup.imperative.insecureUnsealVaultInsideClusterSchedule | string | `"*/5 * * * *"` | | diff --git a/README.md.gotmpl b/README.md.gotmpl index 30bd5eb..ccbcce7 100644 --- a/README.md.gotmpl +++ b/README.md.gotmpl @@ -9,7 +9,7 @@ This chart is used to set up the basic building blocks in [Validated Patterns](h ### Notable changes -* v0.9.51: Add ansibleDevMode (requirements.yml injection and optional ansibleCfgFile/ansibleCfgContent) to simplify rhvp.cluster_utils development +* v0.9.51: Add ansibleDevMode (requirements.yml injection and optional ansibleCfgFile/ansibleCfgContent) to simplify rhvp.cluster_utils development. Add extraPlaybookArgs to imperative as well. * v0.9.50: Add support to custom `rbac` in `ArgoDC.spec` * v0.9.49: Boolean Templates in override values now also render correctly * v0.9.48: Templates in override values now render diff --git a/templates/imperative/auto-approve-installplans.yaml b/templates/imperative/auto-approve-installplans.yaml index a233631..dc7f7f9 100644 --- a/templates/imperative/auto-approve-installplans.yaml +++ b/templates/imperative/auto-approve-installplans.yaml @@ -39,6 +39,9 @@ spec: {{- end }} - -e - "@/values/values.yaml" + {{- range ($.Values.clusterGroup.imperative.extraPlaybookArgs | default list) }} + - {{ . | quote }} + {{- end }} - rhvp.cluster_utils.auto_approve_installplans volumeMounts: {{- include "imperative.volumemounts_ca" . | indent 16 }} diff --git a/templates/imperative/job.yaml b/templates/imperative/job.yaml index c7d262e..9e5d335 100644 --- a/templates/imperative/job.yaml +++ b/templates/imperative/job.yaml @@ -52,6 +52,9 @@ spec: - -e - {{ . | quote }} {{- end }} + {{- range ($.Values.clusterGroup.imperative.extraPlaybookArgs | default list) }} + - {{ . | quote }} + {{- end }} - {{ .playbook }} volumeMounts: {{- include "imperative.volumemounts_ca" . | indent 16 }} diff --git a/templates/imperative/unsealjob.yaml b/templates/imperative/unsealjob.yaml index a50a3ea..526ae01 100644 --- a/templates/imperative/unsealjob.yaml +++ b/templates/imperative/unsealjob.yaml @@ -55,6 +55,9 @@ spec: {{- end }} - -e - "@/values/values.yaml" + {{- range ($.Values.clusterGroup.imperative.extraPlaybookArgs | default list) }} + - {{ . | quote }} + {{- end }} - -t - 'vault_init,vault_unseal,vault_secrets_init,vault_spokes_init' - "rhvp.cluster_utils.vault" diff --git a/tests/imperative_auto_approve_installplans_test.yaml b/tests/imperative_auto_approve_installplans_test.yaml index f803a74..762b2bc 100644 --- a/tests/imperative_auto_approve_installplans_test.yaml +++ b/tests/imperative_auto_approve_installplans_test.yaml @@ -18,6 +18,23 @@ tests: - isKind: of: CronJob + - it: should append extraPlaybookArgs to auto-approve ansible-playbook command + set: + global: + options: + autoApproveManualInstallPlans: true + clusterGroup: + imperative: + adminServiceAccountName: imperative-admin-sa + extraPlaybookArgs: + - "--diff" + asserts: + - hasDocuments: + count: 1 + - contains: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command + content: "--diff" + - it: should include ansible dev mode init container when enabled set: global: diff --git a/tests/imperative_job_test.yaml b/tests/imperative_job_test.yaml index 39925a2..223e291 100644 --- a/tests/imperative_job_test.yaml +++ b/tests/imperative_job_test.yaml @@ -54,6 +54,43 @@ tests: path: spec.jobTemplate.spec.template.spec.serviceAccountName value: imperative-sa + - it: should append clusterGroup.imperative.extraPlaybookArgs before the playbook path + set: + clusterGroup: + imperative: + cronJobName: pattern-cronjob + jobName: pattern-job + namespace: imperative + schedule: "0 2 * * *" + activeDeadlineSeconds: 3600 + serviceAccountName: imperative-sa + image: quay.io/validatedpatterns/imperative-container:v1 + imagePullPolicy: Always + extraPlaybookArgs: + - "--diff" + - "--check" + jobs: + - name: deploy-app + playbook: deploy-application.yml + verbosity: "-v" + tags: "deploy,config" + timeout: "900" + extravars: + - "environment=production" + - "region=us-east-1" + asserts: + - hasDocuments: + count: 1 + - contains: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command + content: "--diff" + - contains: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command + content: "--check" + - contains: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command + content: "deploy-application.yml" + - it: should create multiple init containers for multiple jobs set: clusterGroup: diff --git a/tests/unsealjob_null_handling_test.yaml b/tests/unsealjob_null_handling_test.yaml index 30db97a..70013c8 100644 --- a/tests/unsealjob_null_handling_test.yaml +++ b/tests/unsealjob_null_handling_test.yaml @@ -35,6 +35,38 @@ tests: - hasDocuments: count: 1 + - it: should append extraPlaybookArgs to vault unseal ansible-playbook command + set: + global: + repoURL: https://github.com/validatedpatterns/multicloud-gitops + multiSourceRepoUrl: https://charts.validatedpatterns.io + clusterGroup: + isHubCluster: false + imperative: + extraPlaybookArgs: + - "--diff" + applications: + acm: + name: acm + namespace: open-cluster-management + project: hub + chart: acm + chartVersion: 0.1.* + vault: + name: vault + namespace: vault + project: hub + chart: hashicorp-vault + chartVersion: 0.1.* + asserts: + - isKind: + of: CronJob + - hasDocuments: + count: 1 + - contains: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command + content: "--diff" + - it: should render the unsealVault job when hashicorp-vault exists with null applications mixed in set: global: diff --git a/values.schema.json b/values.schema.json index 41c5a42..3fd612d 100644 --- a/values.schema.json +++ b/values.schema.json @@ -878,6 +878,14 @@ "-vvvv" ] }, + "extraPlaybookArgs": { + "type": "array", + "description": "Optional argv tokens appended to each ansible-playbook invocation (imperative jobs, vault unseal, and auto-approve installplans CronJobs), after values -e @/values/values.yaml and job extravars (where applicable), and before tags or the playbook name. Empty by default.", + "items": { + "type": "string" + }, + "default": [] + }, "serviceAccountName": { "type": "string" }, diff --git a/values.yaml b/values.yaml index bc85842..07295dd 100644 --- a/values.yaml +++ b/values.yaml @@ -174,6 +174,8 @@ clusterGroup: insecureUnsealVaultInsideClusterSchedule: "*/5 * * * *" # Increase ansible verbosity with '-v' or '-vv..' verbosity: "" + # -- Optional extra arguments for every ansible-playbook invocation (imperative jobs, vault unseal, auto-approve installplans). Each list entry is one argv token. Empty by default. + extraPlaybookArgs: [] serviceAccountCreate: true # service account to be used to run the cron pods serviceAccountName: imperative-sa From 59d674083000b0d0c2e3854e18a3220bae0306df Mon Sep 17 00:00:00 2001 From: Martin Jackson Date: Fri, 8 May 2026 12:31:45 -0500 Subject: [PATCH 4/4] Override pattern_dir for development --- templates/imperative/_helpers.tpl | 1 + tests/application_vault_unseal_test.yaml | 10 ++++++++-- ...rative_auto_approve_installplans_test.yaml | 10 ++++++++-- tests/imperative_job_test.yaml | 19 +++++++++++++++++-- 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/templates/imperative/_helpers.tpl b/templates/imperative/_helpers.tpl index 4b07778..fe7bed9 100644 --- a/templates/imperative/_helpers.tpl +++ b/templates/imperative/_helpers.tpl @@ -99,6 +99,7 @@ EOF {{- end }} ansible-galaxy collection install -r {{ $.Values.clusterGroup.imperative.ansibleDevMode.requirementsFile | quote }} + ansible-galaxy collection list volumeMounts: {{- include "imperative.volumemounts_ca" $ | indent 4 }} {{- end }} diff --git a/tests/application_vault_unseal_test.yaml b/tests/application_vault_unseal_test.yaml index 035562b..f9ca8d2 100644 --- a/tests/application_vault_unseal_test.yaml +++ b/tests/application_vault_unseal_test.yaml @@ -185,9 +185,12 @@ tests: - equal: path: spec.jobTemplate.spec.template.spec.initContainers[2].name value: ansible-dev-mode - - equal: + - matchRegex: path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] - value: ansible-galaxy collection install -r "dev/requirements.yml" + pattern: 'ansible-galaxy collection install -r "dev/requirements.yml"' + - matchRegex: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + pattern: 'ansible-galaxy collection list' - it: should inject ansible.cfg in unseal ansible dev mode init when ansibleCfgContent is set set: @@ -225,3 +228,6 @@ tests: - matchRegex: path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] pattern: 'ansible-galaxy collection install -r "dev/requirements.yml"' + - matchRegex: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + pattern: 'ansible-galaxy collection list' diff --git a/tests/imperative_auto_approve_installplans_test.yaml b/tests/imperative_auto_approve_installplans_test.yaml index 762b2bc..24d447e 100644 --- a/tests/imperative_auto_approve_installplans_test.yaml +++ b/tests/imperative_auto_approve_installplans_test.yaml @@ -51,9 +51,12 @@ tests: - equal: path: spec.jobTemplate.spec.template.spec.initContainers[2].name value: ansible-dev-mode - - equal: + - matchRegex: path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] - value: ansible-galaxy collection install -r "ansible/requirements.yml" + pattern: 'ansible-galaxy collection install -r "ansible/requirements.yml"' + - matchRegex: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + pattern: 'ansible-galaxy collection list' - it: should inject ansible.cfg in auto-approve ansible dev mode when ansibleCfgContent is set set: @@ -82,3 +85,6 @@ tests: - matchRegex: path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] pattern: 'ansible-galaxy collection install -r "ansible/requirements.yml"' + - matchRegex: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + pattern: 'ansible-galaxy collection list' diff --git a/tests/imperative_job_test.yaml b/tests/imperative_job_test.yaml index 223e291..9c80699 100644 --- a/tests/imperative_job_test.yaml +++ b/tests/imperative_job_test.yaml @@ -197,9 +197,12 @@ tests: - equal: path: spec.jobTemplate.spec.template.spec.initContainers[2].name value: ansible-dev-mode - - equal: + - matchRegex: path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] - value: ansible-galaxy collection install -r "collections/requirements.yml" + pattern: 'ansible-galaxy collection install -r "collections/requirements.yml"' + - matchRegex: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + pattern: 'ansible-galaxy collection list' - it: should inject inline requirements content when provided set: @@ -226,6 +229,9 @@ tests: - matchRegex: path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] pattern: 'ansible-galaxy collection install -r "collections/requirements.yml"' + - matchRegex: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + pattern: 'ansible-galaxy collection list' - it: should inject requirements and ansible.cfg heredocs when both contents are set set: @@ -256,6 +262,9 @@ tests: - matchRegex: path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] pattern: 'ansible-galaxy collection install -r "collections/requirements.yml"' + - matchRegex: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + pattern: 'ansible-galaxy collection list' - it: should inject ansible.cfg only when requirementsContent is empty set: @@ -284,6 +293,9 @@ tests: - matchRegex: path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] pattern: 'ansible-galaxy collection install -r "collections/requirements.yml"' + - matchRegex: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + pattern: 'ansible-galaxy collection list' - it: should inject inline ansible.cfg when ansibleCfgContent is provided set: @@ -314,3 +326,6 @@ tests: - matchRegex: path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] pattern: 'ansible-galaxy collection install -r "collections/requirements.yml"' + - matchRegex: + path: spec.jobTemplate.spec.template.spec.initContainers[2].command[2] + pattern: 'ansible-galaxy collection list'