diff --git a/deploy-edpm-reuse.yaml b/deploy-edpm-reuse.yaml index 5d5e202bd8..44e90f35ff 100644 --- a/deploy-edpm-reuse.yaml +++ b/deploy-edpm-reuse.yaml @@ -42,6 +42,7 @@ when: - cifmw_architecture_scenario is defined - cifmw_architecture_scenario | length > 0 + - _cifmw_va_common_loaded is not defined ansible.builtin.include_vars: file: "scenarios/reproducers/va-common.yml" diff --git a/playbooks/adoption/pre.yml b/playbooks/adoption/pre.yml index 30a4965f18..e6fe4c8adf 100644 --- a/playbooks/adoption/pre.yml +++ b/playbooks/adoption/pre.yml @@ -46,6 +46,8 @@ not exist. - name: Include common architecture parameter file if needed + when: + - _cifmw_va_common_loaded is not defined ansible.builtin.include_vars: file: "{{ _default_scenario_dir }}/reproducers/va-common.yml" diff --git a/playbooks/skmo/ensure-central-ca-bundle.yaml b/playbooks/skmo/ensure-central-ca-bundle.yaml new file mode 100644 index 0000000000..a37bccb458 --- /dev/null +++ b/playbooks/skmo/ensure-central-ca-bundle.yaml @@ -0,0 +1,28 @@ +--- +- name: Ensure central control plane uses custom CA bundle + hosts: localhost + gather_facts: false + vars: + central_namespace: openstack + controlplane_name: controlplane + ca_bundle_secret_name: custom-ca-certs + tasks: + - name: Check current caBundleSecretName + ansible.builtin.shell: | + set -euo pipefail + oc -n {{ central_namespace }} get osctlplane {{ controlplane_name }} \ + -o jsonpath='{.spec.tls.caBundleSecretName}' + args: + executable: /bin/bash + register: ca_bundle_name + changed_when: false + failed_when: false + + - name: Patch control plane to use custom CA bundle when unset + ansible.builtin.shell: | + set -euo pipefail + oc -n {{ central_namespace }} patch osctlplane {{ controlplane_name }} \ + --type json -p '[{"op":"add","path":"/spec/tls","value":{}},{"op":"add","path":"/spec/tls/caBundleSecretName","value":"{{ ca_bundle_secret_name }}"}]' + args: + executable: /bin/bash + when: ca_bundle_name.stdout | trim == "" diff --git a/playbooks/skmo/prepare-leaf.yaml b/playbooks/skmo/prepare-leaf.yaml new file mode 100644 index 0000000000..a2219d4467 --- /dev/null +++ b/playbooks/skmo/prepare-leaf.yaml @@ -0,0 +1,131 @@ +--- +- name: Prepare SKMO leaf prerequisites in regionZero + hosts: localhost + gather_facts: false + vars: + skmo_values_file: "{{ cifmw_architecture_repo }}/examples/va/multi-namespace-skmo/control-plane2/skmo-values.yaml" + osp_secrets_env_file: "{{ cifmw_architecture_repo }}/lib/control-plane/base/osp-secrets.env" + central_namespace: openstack + leaf_namespace: openstack2 + leaf_secret_name: osp-secret + central_rootca_secret: rootca-public + tasks: + - name: Load SKMO values + ansible.builtin.set_fact: + skmo_values: "{{ lookup('file', skmo_values_file) | from_yaml }}" + + - name: Set SKMO leaf facts + ansible.builtin.set_fact: + leaf_region: "{{ skmo_values.data.leafRegion }}" + leaf_admin_user: "{{ skmo_values.data.leafAdminUser }}" + leaf_admin_project: "{{ skmo_values.data.leafAdminProject }}" + leaf_admin_password_key: "{{ skmo_values.data.leafAdminPasswordKey }}" + keystone_internal_url: "{{ skmo_values.data.keystoneInternalURL }}" + keystone_public_url: "{{ skmo_values.data.keystonePublicURL }}" + ca_bundle_secret_name: "{{ skmo_values.data.leafCaBundleSecretName }}" + + - name: Ensure leaf osp-secret exists (pre-create from env file) + ansible.builtin.shell: | + set -euo pipefail + if ! oc -n {{ leaf_namespace }} get secret {{ leaf_secret_name }} >/dev/null 2>&1; then + oc -n {{ leaf_namespace }} create secret generic {{ leaf_secret_name }} \ + --from-env-file="{{ osp_secrets_env_file }}" \ + --dry-run=client -o yaml | oc apply -f - + fi + args: + executable: /bin/bash + + - name: Read leaf admin password from leaf secret + ansible.builtin.shell: | + set -euo pipefail + oc -n {{ leaf_namespace }} get secret {{ leaf_secret_name }} \ + -o jsonpath='{.data.{{ leaf_admin_password_key }}}' | base64 -d + args: + executable: /bin/bash + register: leaf_admin_password + changed_when: false + + - name: Ensure leaf region exists in central Keystone + ansible.builtin.shell: | + set -euo pipefail + oc -n {{ central_namespace }} rsh openstackclient \ + openstack region show {{ leaf_region }} >/dev/null 2>&1 || \ + oc -n {{ central_namespace }} rsh openstackclient \ + openstack region create {{ leaf_region }} + args: + executable: /bin/bash + + - name: Ensure keystone catalog endpoints exist for leaf region + ansible.builtin.shell: | + set -euo pipefail + if ! oc -n {{ central_namespace }} rsh openstackclient \ + openstack endpoint list --service keystone --interface public --region {{ leaf_region }} \ + -f value -c ID | head -1 | grep -q .; then + oc -n {{ central_namespace }} rsh openstackclient \ + openstack endpoint create --region {{ leaf_region }} identity public "{{ keystone_public_url }}" + fi + if ! oc -n {{ central_namespace }} rsh openstackclient \ + openstack endpoint list --service keystone --interface internal --region {{ leaf_region }} \ + -f value -c ID | head -1 | grep -q .; then + oc -n {{ central_namespace }} rsh openstackclient \ + openstack endpoint create --region {{ leaf_region }} identity internal "{{ keystone_internal_url }}" + fi + args: + executable: /bin/bash + + - name: Ensure leaf admin project exists in central Keystone + ansible.builtin.shell: | + set -euo pipefail + oc -n {{ central_namespace }} rsh openstackclient \ + openstack project show {{ leaf_admin_project }} >/dev/null 2>&1 || \ + oc -n {{ central_namespace }} rsh openstackclient \ + openstack project create {{ leaf_admin_project }} + args: + executable: /bin/bash + + - name: Ensure leaf admin user exists and has admin role + ansible.builtin.shell: | + set -euo pipefail + if ! oc -n {{ central_namespace }} rsh openstackclient \ + openstack user show {{ leaf_admin_user }} >/dev/null 2>&1; then + oc -n {{ central_namespace }} rsh openstackclient \ + openstack user create --domain Default --password "{{ leaf_admin_password.stdout | trim }}" {{ leaf_admin_user }} + fi + oc -n {{ central_namespace }} rsh openstackclient \ + openstack role add --project {{ leaf_admin_project }} --user {{ leaf_admin_user }} admin + args: + executable: /bin/bash + + - name: Create or append leaf CA bundle secret + ansible.builtin.shell: | + set -euo pipefail + tmpdir="$(mktemp -d)" + newkey="skmo-central-rootca.crt" + export TMPDIR="${tmpdir}" + + if oc -n {{ leaf_namespace }} get secret {{ ca_bundle_secret_name }} \ + >/dev/null 2>&1; then + oc -n {{ leaf_namespace }} get secret {{ ca_bundle_secret_name }} \ + -o json | python3 -c ' + import base64, json, os, sys + tmpdir = os.environ.get("TMPDIR") + data = json.load(sys.stdin).get("data", {}) + for key, value in data.items(): + path = os.path.join(tmpdir, key) + with open(path, "wb") as f: + f.write(base64.b64decode(value)) + ' + fi + + oc -n {{ central_namespace }} get secret {{ central_rootca_secret }} \ + -o jsonpath='{.data.tls\.crt}' | base64 -d \ + > "${tmpdir}/${newkey}" + + oc -n {{ leaf_namespace }} create secret generic \ + {{ ca_bundle_secret_name }} \ + --from-file="${tmpdir}" \ + --dry-run=client -o yaml | oc apply -f - + + rm -rf "${tmpdir}" + args: + executable: /bin/bash diff --git a/playbooks/skmo/trust-leaf-ca.yaml b/playbooks/skmo/trust-leaf-ca.yaml new file mode 100644 index 0000000000..5fd86d48e3 --- /dev/null +++ b/playbooks/skmo/trust-leaf-ca.yaml @@ -0,0 +1,51 @@ +--- +- name: Trust SKMO leaf CA in central region + hosts: localhost + gather_facts: false + vars: + skmo_values_file: "{{ cifmw_architecture_repo }}/examples/va/multi-namespace-skmo/control-plane2/skmo-values.yaml" + central_namespace: openstack + leaf_namespace: openstack2 + leaf_rootca_secret: rootca-public + tasks: + - name: Load SKMO values + ansible.builtin.set_fact: + skmo_values: "{{ lookup('file', skmo_values_file) | from_yaml }}" + + - name: Set central CA bundle secret name + ansible.builtin.set_fact: + central_ca_bundle_secret_name: "{{ skmo_values.data.centralCaBundleSecretName }}" + + - name: Create or append central CA bundle secret + ansible.builtin.shell: | + set -euo pipefail + tmpdir="$(mktemp -d)" + newkey="skmo-leaf-rootca.crt" + export TMPDIR="${tmpdir}" + + if oc -n {{ central_namespace }} get secret \ + {{ central_ca_bundle_secret_name }} >/dev/null 2>&1; then + oc -n {{ central_namespace }} get secret \ + {{ central_ca_bundle_secret_name }} -o json | python3 -c ' + import base64, json, os, sys + tmpdir = os.environ.get("TMPDIR") + data = json.load(sys.stdin).get("data", {}) + for key, value in data.items(): + path = os.path.join(tmpdir, key) + with open(path, "wb") as f: + f.write(base64.b64decode(value)) + ' + fi + + oc -n {{ leaf_namespace }} get secret {{ leaf_rootca_secret }} \ + -o jsonpath='{.data.tls\.crt}' | base64 -d \ + > "${tmpdir}/${newkey}" + + oc -n {{ central_namespace }} create secret generic \ + {{ central_ca_bundle_secret_name }} \ + --from-file="${tmpdir}" \ + --dry-run=client -o yaml | oc apply -f - + + rm -rf "${tmpdir}" + args: + executable: /bin/bash diff --git a/reproducer.yml b/reproducer.yml index 5dee7c8e30..3e771457d0 100644 --- a/reproducer.yml +++ b/reproducer.yml @@ -18,6 +18,7 @@ when: - cifmw_architecture_scenario is defined - cifmw_architecture_scenario | length > 0 + - _cifmw_va_common_loaded is not defined ansible.builtin.include_vars: file: "scenarios/reproducers/va-common.yml" diff --git a/roles/ci_gen_kustomize_values/templates/multi-namespace-skmo b/roles/ci_gen_kustomize_values/templates/multi-namespace-skmo new file mode 120000 index 0000000000..67c8e7f36c --- /dev/null +++ b/roles/ci_gen_kustomize_values/templates/multi-namespace-skmo @@ -0,0 +1 @@ +multi-namespace \ No newline at end of file diff --git a/scenarios/reproducers/va-common.yml b/scenarios/reproducers/va-common.yml index b5dfcc72fa..03b6e941ee 100644 --- a/scenarios/reproducers/va-common.yml +++ b/scenarios/reproducers/va-common.yml @@ -1,13 +1,17 @@ --- # This file groups common parameters for Architecture based deployment. # It is *automatically* included in any run having cifmw_architecture_scenario -# parameter set. +# parameter set, unless it has already been loaded via cifmw_parent_scenario. # You can of course manually pass it, it won't make any difference. # # Any of those parameter might be overridden from your own parameter file! # # This file should NOT be used for the CRC based deployment (3-nodes.yml). +# Sentinel variable to prevent double-loading of this file. +# When this file is loaded via cifmw_parent_scenario, this variable +# signals to the auto-include logic that va-common.yml was already loaded. +_cifmw_va_common_loaded: true # Ensure some basic directories and parameter are set cifmw_path: "{{ ansible_user_dir }}/bin:{{ ansible_env.PATH }}" diff --git a/scenarios/reproducers/va-multi-skmo.yml b/scenarios/reproducers/va-multi-skmo.yml new file mode 100644 index 0000000000..147dc19a9e --- /dev/null +++ b/scenarios/reproducers/va-multi-skmo.yml @@ -0,0 +1,16 @@ +--- +# SKMO (Shared Keystone Multi-region OpenStack) variant of multi-namespace. +# Inherits all configuration from va-multi.yml, only overriding the +# architecture scenario and automation file. +# +# va-common.yml is listed first to ensure variables like cifmw_use_uefi +# are available when va-multi.yml templates are evaluated. +# The sentinel _cifmw_va_common_loaded prevents it from being loaded +# again by the auto-include logic in reproducer.yml / deploy-edpm-reuse.yaml. + +cifmw_parent_scenario: + - "scenarios/reproducers/va-common.yml" + - "scenarios/reproducers/va-multi.yml" + +cifmw_architecture_scenario: multi-namespace-skmo +cifmw_arch_automation_file: multi-namespace-skmo.yaml