diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index 69528e853..000000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,70 +0,0 @@ -# Default code owners -* @openstack-k8s-operators/cifmw-squad - -# Adoption -roles/adoption_osp_deploy @openstack-k8s-operators/adoption-core-reviewers - -# BGP -roles/ci_gen_kustomize_values/templates/bgp_dt01 @openstack-k8s-operators/bgp -roles/ci_gen_kustomize_values/templates/bgp-l3-xl @openstack-k8s-operators/bgp -playbooks/bgp @openstack-k8s-operators/bgp -scenarios/reproducers/bgp-l3-xl.yml @openstack-k8s-operators/bgp - -# DCN -roles/ci_dcn_site @openstack-k8s-operators/dcn -playbooks/dcn.yml @openstack-k8s-operators/dcn -roles/ci_gen_kustomize_values/templates/dcn @openstack-k8s-operators/dcn - -# Must gather -roles/os_must_gather @openstack-k8s-operators/must-gather - -# NFV -roles/idrac_configuration @openstack-k8s-operators/nfv -roles/switch_config @openstack-k8s-operators/nfv -roles/tofu @eshulman2 @openstack-k8s-operators/nfv -roles/ci_gen_kustomize_values/templates/nfv-ovs-dpdk-sriov-hci @openstack-k8s-operators/nfv -roles/ci_gen_kustomize_values/templates/ovs-dpdk @openstack-k8s-operators/nfv -roles/ci_gen_kustomize_values/templates/ovs-dpdk-sriov @openstack-k8s-operators/nfv -roles/ci_gen_kustomize_values/templates/ovs-dpdk-sriov-2nodesets @openstack-k8s-operators/nfv -roles/ci_gen_kustomize_values/templates/sriov @openstack-k8s-operators/nfv - -# Polarion -roles/polarion @tosky @jparoly @jirimacku - -# Report portal -roles/reportportal @jirimacku @dsariel @sdatko - -# Security -roles/compliance @openstack-k8s-operators/security -roles/federation @openstack-k8s-operators/security -roles/ipa @openstack-k8s-operators/security - -# Shiftstack -roles/shiftstack @imatza-rh @eurijon -roles/ci_gen_kustomize_values/templates/shiftstack @imatza-rh @eurijon - -# Storage -roles/cifmw_block_device @openstack-k8s-operators/storage -roles/cifmw_ceph_client @openstack-k8s-operators/storage -roles/cifmw_ceph_spec @openstack-k8s-operators/storage -roles/cifmw_cephadm @openstack-k8s-operators/storage -roles/cifmw_create_admin @openstack-k8s-operators/storage -playbooks/ceph.yml @openstack-k8s-operators/storage - -# Storage -roles/nat64_appliance @hjensas -roles/ci_lvms_storage @fultonj @fmount @abays -roles/ci_local_storage @fultonj @fmount @abays - -# Test -roles/tempest @openstack-k8s-operators/ciops -roles/test_operator @openstack-k8s-operators/ciops - -# Uni -roles/ci_gen_kustomize_values/templates/uni* @openstack-k8s-operators/ciops - -# Update -roles/update @openstack-k8s-operators/updates - -# Validations -roles/validations @drosenfe diff --git a/.github/workflows/verify-pr-prefix.yml b/.github/workflows/verify-pr-prefix.yml index d446b1ddb..fc47fd237 100644 --- a/.github/workflows/verify-pr-prefix.yml +++ b/.github/workflows/verify-pr-prefix.yml @@ -20,7 +20,12 @@ jobs: with: fetch-depth: 0 + - name: Dump commit message to file + run: | + git fetch origin ${{ github.event.pull_request.head.sha }} + git log -1 --pretty=format:"%B" ${{ github.event.pull_request.head.sha }} | head -n1 > commit-message-file + - name: Run commit message check id: prefixcheck run: | - ./scripts/check-role-prefix.sh + ./scripts/check-role-prefix.sh commit-message-file diff --git a/.gitignore b/.gitignore index fa625530b..78e914338 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,7 @@ docs/dictionary/tmp .env .idea/ .ansible/ +# Cursor AI - personal configs not to commit +.cursor +# Claude AI +.claude diff --git a/Makefile b/Makefile index 3dbe6aebf..0d38c64e0 100644 --- a/Makefile +++ b/Makefile @@ -249,7 +249,3 @@ plugin-development-disable: # Revert all changes and delete .env if no longer ne grep -lEr --include=\*.py --exclude-dir=.venv 'from (?:plugins|tests)' | xargs gsed -i -e 's/from plugins/from ansible_collections\.cifmw\.general\.plugins/g' -e 's/from tests/from ansible_collections\.cifmw\.general\.tests/g' gsed -i '/PYTHONPATH=/d' .env [ -s .env ] || rm .env - -.PHONY: build-cifmw-client-container -build-cifmw-client-container: # Locally build cifmw-client container - podman build --security-opt label=disable -t localhost/cifmw-client:latest -f containerfiles/Containerfile.client . diff --git a/OSPRH-20772-cifmw-record-timing-metrics.md b/OSPRH-20772-cifmw-record-timing-metrics.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/OWNERS b/OWNERS new file mode 100644 index 000000000..86587d86f --- /dev/null +++ b/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - cifmw-squad + +reviewers: + - cifmw-squad diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES new file mode 100644 index 000000000..141e212cc --- /dev/null +++ b/OWNERS_ALIASES @@ -0,0 +1,119 @@ +# See the OWNERS_ALIASES docs: https://git.k8s.io/community/contributors/guide/owners.md#owners_aliases + +aliases: + cifmw-squad: + - rebtoor + - fultonj + - dasm + - danpawlik + - Valkyrie00 + - yorabl + - tosky + - eshulman2 + - evallesp + - bshewale + - amartyasinha + - brjackma + - michburk + + adoption-team: + - sathlan + - jistr + - holser + - ciecierski + - pinikomarov + - klgill + - archana203 + + bgp-team: + - lmiccini + - ccamposr + - eduolivares + - frenzyfriday + + dcn-team: + - fultonj + - jokke-ilujo + + must-gather-team: + - dprince + - olliewalsh + - gibizer + - fmount + - abays + - pkomarov + - juliakreger + - Akrog + - stuggi + + nfv-team: + - saneax + - atyronesmith + - eshulman2 + - mnietoji + - rdiazcam + + security-team: + - xek + - d34dh0r53 + - dmendiza + - pkomarov + - vakwetu + - mauricioharley + - afaranha + - Deydra71 + + storage-team: + - eharney + - fultonj + - fmount + - gfidente + - cschwede + - Akrog + - gouthampacha + - tosky + - ASBishop + - silvacarloss + - konan-abhi + + ciops-team: + - arxcruz + - dasm + - sdatko + - adrianfusco + - pojadhav + - kstrenkova + - imatza-rh + - sauragar + - belolipa + + updates-team: + - sathlan + - jistr + - holser + - ciecierski + - pinikomarov + - archana203 + + # Individual contributor groups (already expanded) + shiftstack-team: + - imatza-rh + - eurijon + + polarion-team: + - tosky + - jparoly + - jirimacku + + reportportal-team: + - jirimacku + - dsariel + - sdatko + + storage-contributors: + - fultonj + - fmount + - abays + + tofu-owners: + - eshulman2 diff --git a/ci/playbooks/build_push_container.yml b/ci/playbooks/build_push_container.yml deleted file mode 100644 index 737381196..000000000 --- a/ci/playbooks/build_push_container.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -- name: Run build_push_container role - hosts: "{{ cifmw_target_host | default('localhost') }}" - tasks: - - name: Run build_push_container role - ansible.builtin.include_role: - name: build_push_container diff --git a/ci/playbooks/build_push_container_runner.yml b/ci/playbooks/build_push_container_runner.yml deleted file mode 100644 index adbea8fdb..000000000 --- a/ci/playbooks/build_push_container_runner.yml +++ /dev/null @@ -1,14 +0,0 @@ ---- -- name: Run build_push_container role - hosts: "{{ cifmw_zuul_target_host | default('controller') }}" - tasks: - - name: Run build_push_container role - vars: - ci_framework_src_dir: "{{ ansible_user_dir }}/src/github.com/openstack-k8s-operators/ci-framework" - ansible.builtin.command: - chdir: "{{ ci_framework_src_dir }}" - cmd: >- - ~/test-python/bin/ansible-playbook ci/playbooks/build_push_container.yml - -i {{ ansible_user_dir }}/ci-framework-data/artifacts/zuul_inventory.yml - -e @group_vars/all.yml - -e "@{{ ansible_user_dir }}/ci-framework-data/artifacts/parameters/zuul-params.yml" diff --git a/ci/playbooks/content_provider/run.yml b/ci/playbooks/content_provider/run.yml index f73fc24bd..5dee1c01f 100644 --- a/ci/playbooks/content_provider/run.yml +++ b/ci/playbooks/content_provider/run.yml @@ -44,9 +44,15 @@ {{ content_provider_ip | default('nowhere') }} - name: Set up content registry IP address + vars: + _registry_ip: "{{ content_provider_ip | default('') | trim }}" + _registry_available: "{{ _registry_ip != '' }}" + _registry_ip_port: "{{ _registry_ip }}:{{ cifmw_rp_registry_port | default('5001') }}" zuul_return: data: zuul: pause: true - content_provider_registry_ip: "{{ content_provider_ip | default('nowhere') | trim }}" cifmw_operator_build_output: "{{ inner_ansible_vars.cifmw_operator_build_output }}" + content_provider_registry_available: "{{ _registry_available }}" + content_provider_registry_ip: "{{ _registry_ip }}" + content_provider_registry_ip_port: "{{ _registry_ip_port if _registry_available else '' }}" diff --git a/ci/playbooks/edpm_baremetal_update/run.yml b/ci/playbooks/edpm_baremetal_update/run.yml new file mode 100644 index 000000000..0c3d8415f --- /dev/null +++ b/ci/playbooks/edpm_baremetal_update/run.yml @@ -0,0 +1,127 @@ +--- +- name: "Run ci/playbooks/edpm_baremetal_update/run.yml" + hosts: "{{ cifmw_zuul_target_host | default('all') }}" + gather_facts: true + tasks: + - name: Filter out host if needed + when: + - cifmw_zuul_target_host is defined + - cifmw_zuul_target_host != 'all' + - inventory_hostname != cifmw_zuul_target_host + ansible.builtin.meta: end_host + + - name: Check for edpm-ansible.yml file + ansible.builtin.stat: + path: "{{ ansible_user_dir }}/ci-framework-data/artifacts/edpm-ansible.yml" + register: edpm_file + + - name: Check if new ssh keypair exists + ansible.builtin.include_role: + name: recognize_ssh_keypair + + - name: Add crc node in local inventory + ansible.builtin.add_host: + name: crc + ansible_ssh_private_key_file: "{{ ansible_user_dir }}/.crc/machines/crc/{{ crc_ssh_keypair }}" + ansible_ssh_user: core + ansible_host: api.crc.testing + + - name: Ensure we know ssh hosts + ansible.builtin.shell: + cmd: "ssh-keyscan {{ hostvars[item].ansible_host }} >> ~/.ssh/known_hosts" + loop: "{{ hostvars.keys() | reject('equalto', 'localhost') }}" + + - name: Inject CRC in zuul_inventory + block: + - name: Load zuul_inventory + register: _inventory + ansible.builtin.slurp: + path: "{{ ansible_user_dir }}/ci-framework-data/artifacts/zuul_inventory.yml" + + - name: Inject CRC in zuul_inventory.yml + vars: + _crc: + all: + hosts: + crc: "{{ dict(hostvars.crc) }}" + _updated: >- + {{ + _inventory.content | b64decode | from_yaml | combine(_crc, recursive=true) + }} + ansible.builtin.copy: + dest: "{{ ansible_user_dir }}/ci-framework-data/artifacts/zuul_inventory.yml" + content: "{{ _updated | to_nice_yaml }}" + mode: "0644" + + - name: Set default pre-update tag if not provided + ansible.builtin.set_fact: + cifmw_minor_update_pre_update_tag: "{{ cifmw_minor_update_pre_update_tag | default('18.0-fr3-latest') }}" + + - name: Get pre-update index image digest from tag + ansible.builtin.shell: >- + skopeo inspect + docker://quay.io/openstack-k8s-operators/openstack-operator-index:{{ cifmw_minor_update_pre_update_tag }} + | jq -r '.Digest' + register: pre_update_digest_result + changed_when: false + failed_when: pre_update_digest_result.rc != 0 + + - name: Set pre-update index image using digest from tag + ansible.builtin.set_fact: + cifmw_minor_update_pre_update_index_image: >- + quay.io/openstack-k8s-operators/openstack-operator-index@{{ pre_update_digest_result.stdout | trim }} + + - name: Get minor update index image from content provider or use default + ansible.builtin.set_fact: + cifmw_minor_update_index_image: >- + {{ + cifmw_operator_build_output.operators['openstack-operator'].image_catalog + if (cifmw_operator_build_output is defined and + cifmw_operator_build_output.operators is defined and + 'openstack-operator' in cifmw_operator_build_output.operators) + else cifmw_minor_update_pre_update_index_image + }} + + - name: Override operator build output with pre-update index image for Phase 1 + ansible.builtin.set_fact: + cifmw_operator_build_output_pre_update: >- + {{ + { + 'cifmw_operator_build_output': { + 'operators': { + 'openstack-operator': { + 'image_catalog': cifmw_minor_update_pre_update_index_image + } + } + } + } + }} + + - name: Phase 1 - Deploy with pre-update index image using deploy-edpm.yml + block: + - name: Write pre-update operator build output to temporary file + ansible.builtin.copy: + dest: "{{ ansible_user_dir }}/ci-framework-data/artifacts/operator_build_output_pre_update.yml" + content: "{{ cifmw_operator_build_output_pre_update | to_nice_yaml }}" + mode: "0644" + + - name: Perform Podified and EDPM deployment on compute nodes with virtual baremetal (pre-update) + ansible.builtin.command: + chdir: "{{ ansible_user_dir }}/src/github.com/openstack-k8s-operators/ci-framework" + cmd: >- + ansible-playbook deploy-edpm.yml + -i "{{ ansible_user_dir }}/ci-framework-data/artifacts/zuul_inventory.yml" + -e @group_vars/all.yml + -e @scenarios/centos-9/base.yml + -e @scenarios/centos-9/edpm_baremetal_deployment_ci.yml + {%- if edpm_file.stat.exists %} + -e @{{ ansible_user_dir }}/ci-framework-data/artifacts/edpm-ansible.yml + {%- endif %} + {%- if cifmw_extras is defined %} + {%- for extra_var in cifmw_extras %} + -e "{{ extra_var }}" + {%- endfor %} + {%- endif %} + -e "@{{ ansible_user_dir }}/ci-framework-data/artifacts/parameters/zuul-params.yml" + -e "@{{ ansible_user_dir }}/ci-framework-data/artifacts/operator_build_output_pre_update.yml" + -e "cifmw_prepare_openstackversion=false" diff --git a/ci/playbooks/edpm_baremetal_update/update-edpm.yml b/ci/playbooks/edpm_baremetal_update/update-edpm.yml new file mode 100644 index 000000000..23bca868f --- /dev/null +++ b/ci/playbooks/edpm_baremetal_update/update-edpm.yml @@ -0,0 +1,262 @@ +--- +# CI playbook for OpenStack minor version updates. +# This playbook performs a minor version update of an OpenStack deployment +# using index images and install_yamls make targets. +# This playbook depends on content provider variables from CI jobs. +# It runs on cifmw_target_host in the same execution context as deploy-edpm.yml, +# so it can use the install_yamls_makes role that was generated during bootstrap. + +- name: OpenStack minor version update + hosts: "{{ cifmw_target_host | default('localhost') }}" + gather_facts: false + tasks: + - name: Delete success flag if exists + ansible.builtin.file: + path: "{{ ansible_user_dir }}/cifmw-success" + state: absent + + - name: Set cifmw_basedir if not defined + ansible.builtin.set_fact: + cifmw_basedir: "{{ cifmw_basedir | default(ansible_user_dir ~ '/ci-framework-data') }}" + + - name: Set update artifacts basedir if not defined + ansible.builtin.set_fact: + cifmw_update_artifacts_basedir: "{{ cifmw_update_artifacts_basedir | default(cifmw_basedir ~ '/tests/update') }}" + + - name: Initialize monitoring + ansible.builtin.include_role: + name: update + tasks_from: init_monitoring.yml + + - name: Load parameters files + ansible.builtin.include_vars: + dir: "{{ cifmw_basedir }}/artifacts/parameters" + + - name: Set install_yamls environment for minor update phase + ansible.builtin.set_fact: + cifmw_minor_update_env: >- + {{ + (cifmw_install_yamls_environment | default({})) | + combine({'PATH': cifmw_path | default(ansible_user_dir ~ '/.crc/bin:' ~ ansible_user_dir ~ '/.crc/bin/oc:' ~ ansible_user_dir ~ '/bin:' ~ ansible_env.PATH)}) | + combine({'OPENSTACK_IMG': cifmw_minor_update_index_image}) | + combine({'BMO_CLEANUP': false}) + }} + + - name: Set update step to Running openstack cleanup + ansible.builtin.command: + cmd: > + {{ cifmw_update_artifacts_basedir }}/update_event.sh + Running openstack cleanup + + - name: Run make openstack_cleanup + vars: + make_openstack_cleanup_env: "{{ cifmw_minor_update_env }}" + make_openstack_cleanup_dryrun: false + ansible.builtin.include_role: + name: 'install_yamls_makes' + tasks_from: 'make_openstack_cleanup' + ignore_errors: true # Continue even if cleanup fails + + - name: Set update step to Running openstack wait + ansible.builtin.command: + cmd: > + {{ cifmw_update_artifacts_basedir }}/update_event.sh + Running openstack wait + + - name: Run make openstack_wait (minor update) + vars: + make_openstack_wait_env: "{{ cifmw_minor_update_env }}" + make_openstack_wait_dryrun: false + ansible.builtin.include_role: + name: 'install_yamls_makes' + tasks_from: 'make_openstack_wait' + + - name: Set update step to Running openstack init + ansible.builtin.command: + cmd: > + {{ cifmw_update_artifacts_basedir }}/update_event.sh + Running openstack init + + - name: Run make openstack_init (minor update) + vars: + make_openstack_init_env: "{{ cifmw_minor_update_env }}" + make_openstack_init_dryrun: false + ansible.builtin.include_role: + name: 'install_yamls_makes' + tasks_from: 'make_openstack_init' + + - name: Set update step to Waiting for new version to be available + ansible.builtin.command: + cmd: > + {{ cifmw_update_artifacts_basedir }}/update_event.sh + Waiting for new version to be available + + - name: Wait for availableVersion to be different from deployedVersion + kubernetes.core.k8s_info: + kubeconfig: "{{ cifmw_openshift_kubeconfig }}" + api_key: "{{ cifmw_openshift_token | default(omit) }}" + context: "{{ cifmw_openshift_context | default(omit) }}" + api_version: core.openstack.org/v1beta1 + kind: OpenStackVersion + namespace: "{{ cifmw_install_yamls_defaults['NAMESPACE'] | default('openstack') }}" + register: openstackversion_wait_info + retries: 10 + delay: 60 + until: > + openstackversion_wait_info.resources is defined and + openstackversion_wait_info.resources | length > 0 and + openstackversion_wait_info.resources[0].status.availableVersion is defined and + openstackversion_wait_info.resources[0].status.deployedVersion is defined and + openstackversion_wait_info.resources[0].status.availableVersion != openstackversion_wait_info.resources[0].status.deployedVersion + + - name: Get available version from OpenStackVersion CR + ansible.builtin.set_fact: + cifmw_minor_update_target_version: "{{ openstackversion_wait_info.resources[0].status.availableVersion }}" + + - name: Set update step to Patching OpenStackVersion CR + ansible.builtin.command: + cmd: > + {{ cifmw_update_artifacts_basedir }}/update_event.sh + Patching OpenStackVersion CR with version {{ cifmw_minor_update_target_version }} + + - name: Patch OpenStackVersion CR availableVersion + vars: + make_openstack_patch_version_env: "{{ cifmw_minor_update_env }}" + make_openstack_patch_version_dryrun: false + ansible.builtin.include_role: + name: 'install_yamls_makes' + tasks_from: 'make_openstack_patch_version' + + - name: Set vars related to update_containers content provider + when: + - content_provider_os_registry_url is defined + - content_provider_os_registry_url != 'null' + ansible.builtin.set_fact: + cifmw_update_containers_registry: "{{ content_provider_os_registry_url | split('/') | first }}" + cifmw_update_containers_org: "{{ content_provider_os_registry_url | split('/') | last }}" + cifmw_update_containers_tag: "{{ content_provider_dlrn_md5_hash }}" + cifmw_update_containers_openstack: true + + - name: Set update step to Updating container images + when: >- + (cifmw_update_containers_edpm_image_url is defined and + cifmw_update_containers_openstack is defined and + cifmw_update_containers_openstack | bool) or + (cifmw_update_containers_ansibleee_image_url is defined) or + (cifmw_update_containers_openstack is defined and + cifmw_update_containers_openstack | bool) or + (cifmw_update_containers_watcher is defined and + cifmw_update_containers_watcher | bool) + ansible.builtin.command: + cmd: > + {{ cifmw_update_artifacts_basedir }}/update_event.sh + Updating container images + + - name: Prepare and patch OpenStackVersion CR for update + vars: + cifmw_update_containers_metadata: "controlplane" + cifmw_update_containers: true + ansible.builtin.include_role: + name: update_containers + when: >- + (cifmw_update_containers_edpm_image_url is defined and + cifmw_update_containers_openstack is defined and + cifmw_update_containers_openstack | bool) or + (cifmw_update_containers_ansibleee_image_url is defined) or + (cifmw_update_containers_openstack is defined and + cifmw_update_containers_openstack | bool) or + ( cifmw_update_containers_watcher is defined and + cifmw_update_containers_watcher | bool) + + - name: Set update step to Starting the CI update sequence + ansible.builtin.command: + cmd: > + {{ cifmw_update_artifacts_basedir }}/update_event.sh + Starting the CI update sequence + + - name: Run make openstack_update_run + vars: + make_openstack_update_run_env: "{{ cifmw_minor_update_env }}" + make_openstack_update_run_params: + TIMEOUT: "1200s" + OPENSTACK_VERSION: "{{ cifmw_minor_update_target_version }}" + make_openstack_update_run_dryrun: false + ansible.builtin.include_role: + name: 'install_yamls_makes' + tasks_from: 'make_openstack_update_run' + + - name: Set update step to Verifying update completion + ansible.builtin.command: + cmd: > + {{ cifmw_update_artifacts_basedir }}/update_event.sh + Verifying update completion + + - name: Verify deployed version matches target version + kubernetes.core.k8s_info: + kubeconfig: "{{ cifmw_openshift_kubeconfig }}" + api_key: "{{ cifmw_openshift_token | default(omit) }}" + context: "{{ cifmw_openshift_context | default(omit) }}" + api_version: core.openstack.org/v1beta1 + kind: OpenStackVersion + namespace: "{{ cifmw_install_yamls_defaults['NAMESPACE'] | default('openstack') }}" + register: openstackversion_verify_info + until: > + openstackversion_verify_info.resources is defined and + openstackversion_verify_info.resources | length > 0 and + openstackversion_verify_info.resources[0].status.deployedVersion is defined and + openstackversion_verify_info.resources[0].status.deployedVersion == cifmw_minor_update_target_version + retries: 5 + delay: 2 + + - name: Set update step to CI update sequence complete + ansible.builtin.command: + cmd: > + {{ cifmw_update_artifacts_basedir }}/update_event.sh + CI update verification successful - Target version {{ cifmw_minor_update_target_version }} + matches deployed version {{ openstackversion_verify_info.resources[0].status.deployedVersion }} + + - name: Display update verification result + ansible.builtin.debug: + msg: >- + Update verification successful: Target version {{ cifmw_minor_update_target_version }} + matches deployed version {{ openstackversion_verify_info.resources[0].status.deployedVersion }} + + - name: Stop monitoring + block: + - name: Verify monitoring pid file + ansible.builtin.stat: + path: "{{ cifmw_update_artifacts_basedir }}/monitor_resources_changes.pid" + register: cifmw_update_monitoring_pid + + - name: Stop the monitoring process + ansible.builtin.shell: + cmd: >- + kill + $(cat {{ cifmw_update_artifacts_basedir }}/monitor_resources_changes.pid) + register: _kill_result + failed_when: _kill_result.rc not in [0, 1] + when: cifmw_update_monitoring_pid.stat.exists | bool + + - name: Run post-update admin setup + ansible.builtin.import_role: + name: cifmw_setup + tasks_from: admin_setup.yml + tags: + - admin-setup + + - name: Run post-update tests + vars: + cifmw_test_operator_artifacts_basedir: "{{ cifmw_basedir }}/tests/test_operator_update" + cifmw_test_operator_tempest_name: "post-update-tempest-tests" + ansible.builtin.import_role: + name: cifmw_setup + tasks_from: run_tests.yml + when: cifmw_run_tests | default(false) | bool + tags: + - run-tests + + - name: Inject success flag + ansible.builtin.file: + path: "{{ ansible_user_dir }}/cifmw-success" + state: touch + mode: "0644" diff --git a/ci/playbooks/edpm_baremetal_update/update.yml b/ci/playbooks/edpm_baremetal_update/update.yml new file mode 100644 index 000000000..3e53ab1e4 --- /dev/null +++ b/ci/playbooks/edpm_baremetal_update/update.yml @@ -0,0 +1,52 @@ +--- +# CI playbook orchestrator for OpenStack minor version updates. +# This playbook runs on the controller (cifmw_zuul_target_host) and orchestrates +# the update by calling update-edpm.yml on the target host (cifmw_target_host). +# This playbook depends on content provider variables from CI jobs. +# This is Phase 2 of the baremetal update workflow and should be called +# sequentially after run.yml (Phase 1). + +- name: OpenStack minor version update orchestrator + hosts: "{{ cifmw_zuul_target_host | default('all') }}" + gather_facts: false + tasks: + - name: Filter out host if needed + when: + - cifmw_zuul_target_host is defined + - cifmw_zuul_target_host != 'all' + - inventory_hostname != cifmw_zuul_target_host + ansible.builtin.meta: end_host + + - name: Set cifmw_basedir if not defined + ansible.builtin.set_fact: + cifmw_basedir: "{{ cifmw_basedir | default(ansible_user_dir ~ '/ci-framework-data') }}" + + - name: Get minor update index image from content provider or use default + ansible.builtin.set_fact: + cifmw_minor_update_index_image: >- + {{ + cifmw_operator_build_output.operators['openstack-operator'].image_catalog + if (cifmw_operator_build_output is defined and + cifmw_operator_build_output.operators is defined and + 'openstack-operator' in cifmw_operator_build_output.operators) + else cifmw_minor_update_pre_update_index_image | default('quay.io/openstack-k8s-operators/openstack-operator-index:18.0-fr3-latest') + }} + + - name: Write minor update index image to parameters file + ansible.builtin.copy: + dest: "{{ ansible_user_dir }}/ci-framework-data/artifacts/parameters/minor_update_index_image.yml" + content: "{{ {'cifmw_minor_update_index_image': cifmw_minor_update_index_image} | to_nice_yaml }}" + mode: "0644" + when: cifmw_minor_update_index_image is defined + + - name: Run update-edpm.yml on target host + ansible.builtin.command: + chdir: "{{ ansible_user_dir }}/src/github.com/openstack-k8s-operators/ci-framework" + cmd: >- + ansible-playbook ci/playbooks/edpm_baremetal_update/update-edpm.yml + -i "{{ ansible_user_dir }}/ci-framework-data/artifacts/zuul_inventory.yml" + -e @group_vars/all.yml + -e "@{{ ansible_user_dir }}/ci-framework-data/artifacts/parameters/zuul-params.yml" + {%- if cifmw_minor_update_index_image is defined %} + -e "@{{ ansible_user_dir }}/ci-framework-data/artifacts/parameters/minor_update_index_image.yml" + {%- endif %} diff --git a/ci/playbooks/edpm_build_images/edpm_build_images_content_provider_run.yaml b/ci/playbooks/edpm_build_images/edpm_build_images_content_provider_run.yaml index df85fed94..6b008ed6a 100644 --- a/ci/playbooks/edpm_build_images/edpm_build_images_content_provider_run.yaml +++ b/ci/playbooks/edpm_build_images/edpm_build_images_content_provider_run.yaml @@ -49,9 +49,15 @@ {{ content_provider_ip | default('nowhere') }} - name: Set up content registry IP address + vars: + _registry_ip: "{{ content_provider_ip | default('') }}" + _registry_available: "{{ _registry_ip != '' }}" + _registry_ip_port: "{{ _registry_ip }}:{{ cifmw_rp_registry_port | default('5001') }}" zuul_return: data: zuul: pause: true - content_provider_registry_ip: "{{ content_provider_ip | default('nowhere') }}" cifmw_build_images_output: "{{ inner_ansible_vars.cifmw_build_images_output }}" + content_provider_registry_available: "{{ _registry_available }}" + content_provider_registry_ip: "{{ _registry_ip }}" + content_provider_registry_ip_port: "{{ _registry_ip_port if _registry_available else '' }}" diff --git a/ci/playbooks/meta_content_provider/meta_content_provider.yml b/ci/playbooks/meta_content_provider/meta_content_provider.yml index 5954f93e9..934559eca 100644 --- a/ci/playbooks/meta_content_provider/meta_content_provider.yml +++ b/ci/playbooks/meta_content_provider/meta_content_provider.yml @@ -25,6 +25,11 @@ path: "{{ cifmw_build_containers_repo_dir }}/gating.repo" register: _gating_repo + - name: Set gating repo URL if available + when: _gating_repo.stat.exists + ansible.builtin.set_fact: + content_provider_gating_repo_url: "http://{{ cifmw_rp_registry_ip }}:{{ cifmw_bop_gating_port | default(8766) }}" + - name: Deploy content provider registry ansible.builtin.include_role: name: registry_deploy @@ -58,9 +63,10 @@ ansible.builtin.include_role: name: build_containers - - name: Return registry_url + - name: Return registry_url and namespace ansible.builtin.set_fact: content_provider_os_registry_url: "{{ cifmw_build_containers_push_registry }}/{{ cifmw_build_containers_registry_namespace }}" + content_provider_os_registry_namespace: "{{ cifmw_build_containers_registry_namespace }}" - name: Build EDPM Images when: "'edpm-image-builder' in zuul_change_list" diff --git a/ci/playbooks/meta_content_provider/run.yml b/ci/playbooks/meta_content_provider/run.yml index 71b44d2c3..8b1dee9bd 100644 --- a/ci/playbooks/meta_content_provider/run.yml +++ b/ci/playbooks/meta_content_provider/run.yml @@ -45,12 +45,21 @@ {%- else -%} null {%- endif -%} + _gating_repo_available: "{{ (_inner_ansible_vars.content_provider_gating_repo_url | default('') | trim) != '' }}" + _registry_ip: "{{ cifmw_rp_registry_ip | default('') | trim }}" + _registry_available: "{{ _registry_ip != '' }}" + _registry_ip_port: "{{ _registry_ip }}:{{ cifmw_rp_registry_port | default('5001') }}" zuul_return: data: zuul: pause: true - content_provider_registry_ip: "{{ cifmw_rp_registry_ip | default('nowhere') | trim }}" cifmw_operator_build_output: "{{ _inner_ansible_vars.cifmw_operator_build_output }}" cifmw_build_images_output: "{{ _inner_ansible_vars.cifmw_build_images_output }}" content_provider_dlrn_md5_hash: "{{ _dlrn_md5 | default('') }}" content_provider_os_registry_url: "{{ _tcib_registry | trim }}" + content_provider_gating_repo_available: "{{ _gating_repo_available }}" + content_provider_gating_repo_url: "{{ _inner_ansible_vars.content_provider_gating_repo_url | default('') | trim }}" + content_provider_os_registry_namespace: "{{ _inner_ansible_vars.content_provider_os_registry_namespace | default('') }}" + content_provider_registry_available: "{{ _registry_available }}" + content_provider_registry_ip: "{{ _registry_ip }}" + content_provider_registry_ip_port: "{{ _registry_ip_port if _registry_available else '' }}" diff --git a/ci/playbooks/tcib/run.yml b/ci/playbooks/tcib/run.yml index d4ddc6008..0765c0b7f 100644 --- a/ci/playbooks/tcib/run.yml +++ b/ci/playbooks/tcib/run.yml @@ -44,6 +44,10 @@ vars: _inner_ansible_vars: "{{ _inner_ansible.content | b64decode | from_yaml }}" _dlrn_md5: "{{ _inner_ansible_vars.cifmw_repo_setup_full_hash }}" + _gating_repo_available: "{{ (_inner_ansible_vars.content_provider_gating_repo_url | default('') | trim) != '' }}" + _registry_ip: "{{ node_ip | default('') }}" + _registry_available: "{{ _registry_ip != '' }}" + _registry_ip_port: "{{ _registry_ip }}:{{ cifmw_rp_registry_port | default('5001') }}" block: - name: Return Zuul Data ansible.builtin.debug: @@ -57,5 +61,11 @@ data: zuul: pause: true - content_provider_registry_ip: "{{ node_ip | default('nowhere') }}" content_provider_dlrn_md5_hash: "{{ _dlrn_md5 | default('') }}" + content_provider_registry_available: "{{ _registry_available }}" + content_provider_registry_ip: "{{ _registry_ip }}" + content_provider_registry_ip_port: "{{ _registry_ip_port if _registry_available else '' }}" + content_provider_gating_repo_available: "{{ _gating_repo_available }}" + content_provider_gating_repo_url: "{{ _inner_ansible_vars.content_provider_gating_repo_url | default('') | trim }}" + content_provider_os_registry_namespace: "{{ _inner_ansible_vars.content_provider_os_registry_namespace | default('') }}" + content_provider_os_registry_url: "{{ _inner_ansible_vars.content_provider_os_registry_url | default('') | trim }}" diff --git a/ci/playbooks/tcib/tcib.yml b/ci/playbooks/tcib/tcib.yml index 54a422ad8..f96b94182 100644 --- a/ci/playbooks/tcib/tcib.yml +++ b/ci/playbooks/tcib/tcib.yml @@ -32,6 +32,16 @@ ansible.builtin.include_role: name: build_openstack_packages + - name: Check for gating repo + ansible.builtin.stat: + path: "{{ cifmw_build_containers_repo_dir }}/gating.repo" + register: _gating_repo + + - name: Set gating repo URL if available + when: _gating_repo.stat.exists + ansible.builtin.set_fact: + content_provider_gating_repo_url: "http://{{ cifmw_rp_registry_ip }}:{{ cifmw_bop_gating_port | default(8766) }}" + - name: Construct project change list ansible.builtin.set_fact: zuul_change_list: "{{ zuul_change_list | default([]) + [item.project.short_name] }}" @@ -64,6 +74,14 @@ ansible.builtin.include_role: name: build_containers + - name: Save registry namespace and URL + when: + - cifmw_build_containers_registry_namespace is defined + - cifmw_build_containers_push_registry is defined + ansible.builtin.set_fact: + content_provider_os_registry_namespace: "{{ cifmw_build_containers_registry_namespace }}" + content_provider_os_registry_url: "{{ cifmw_build_containers_push_registry }}/{{ cifmw_build_containers_registry_namespace }}" + - name: Get the containers list from container registry ansible.builtin.uri: url: "http://{{ cifmw_rp_registry_ip }}:{{ cifmw_rp_registry_port }}/v2/_catalog" diff --git a/ci/templates/projects.yaml b/ci/templates/projects.yaml index 857c9e85a..75ae430ae 100644 --- a/ci/templates/projects.yaml +++ b/ci/templates/projects.yaml @@ -21,9 +21,4 @@ - cifmw-tcib - cifmw-architecture-validate-hci - ci-framework-openstack-meta-content-provider - - build-push-container-cifmw-client - - github-post: - jobs: - - build-push-container-cifmw-client-post # Start generated content diff --git a/cleanup-edpm.yml b/cleanup-edpm.yml index 9d5a9e985..da0cd0bce 100644 --- a/cleanup-edpm.yml +++ b/cleanup-edpm.yml @@ -8,6 +8,11 @@ hosts: localhost gather_facts: true tasks: + - name: Clean up hypervisor firewall rules + ansible.builtin.include_role: + name: fdp_update_edpm + tasks_from: cleanup_hypervisor_firewall.yml + - name: Clean up all directories ansible.builtin.import_role: name: ci_setup diff --git a/containerfiles/Containerfile.client b/containerfiles/Containerfile.client deleted file mode 100644 index 8ab69287a..000000000 --- a/containerfiles/Containerfile.client +++ /dev/null @@ -1,35 +0,0 @@ -FROM quay.io/centos/centos:stream9 - -LABEL summary="CI-Framework client image" \ - maintainer="CI Framework" - -# USER root -RUN dnf update -y && \ - dnf install -y git python3.11 python3.11-pip \ - python3-netaddr make gcc sudo rsync vim && \ - dnf clean all - -RUN adduser cifmw - -RUN echo "cifmw ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/cifmw - -ENV PATH="/home/cifmw/test-python/bin:$PATH:/home/cifmw/.local/bin" - -USER cifmw - -COPY --chown=cifmw:cifmw . /home/cifmw/ci-framework - -WORKDIR /home/cifmw/ci-framework - -RUN /usr/bin/make -C /home/cifmw/ci-framework setup_molecule USE_VENV=yes - -# todo(Lewis): Possible enhancements: -# - Add pre-commit install so more dependencies are bundled -# RUN /home/cifmw/test-python/bin/pre-commit install --install-hooks -# - Add entrypoint script to source python venv -# - Use ansible-dev-environment -# https://github.com/ansible/ansible-dev-environment -# RUN ade install --venv ~/test-python/ -r requirements.yml -# Requires ability to skip ansible-galaxy install call in setup_molecule -# Skip installing collections in job that builds container -# - Copy python venv from host during build rather than downloading twice. diff --git a/docs/dictionary/en-custom.txt b/docs/dictionary/en-custom.txt index 1c4ee523c..378259a0c 100644 --- a/docs/dictionary/en-custom.txt +++ b/docs/dictionary/en-custom.txt @@ -23,6 +23,7 @@ arxcruz AssignedTeam auth authfile +autoconfiguration autohold autoholds autoscale @@ -147,10 +148,12 @@ dfb dfce dfg dhcp +dhcpv dib dicts dirs disablecertificateverification +diskimage disksize distro dlrn @@ -186,6 +189,7 @@ ezzmy favorit fbqufbqkfbzxrja fci +fdp fedoraproject fil filesystem @@ -256,6 +260,7 @@ ipam ipi ipmi ips +iptables ipv iscsi isdir @@ -414,6 +419,7 @@ openstack openstackclient openstackcontrolplane openstackdataplane +openstackdataplanedeployment openstackdataplanenodeset openstackdataplanenodesets openstackprovisioner @@ -479,9 +485,11 @@ qtjhbpzc quickstart rabbitmq radosgw +radvd raukadah rbd rdk +rdnss rdo rdoinfo rdoproject @@ -528,6 +536,7 @@ Sinha sizepercent skbg skiplist +slaac snr specificities spnego @@ -536,6 +545,7 @@ src sshkey ssl sso +stateful stderr stdout stp @@ -547,7 +557,6 @@ subnet subnets sudo sudoers -supercedent sushy svc svg @@ -583,6 +592,7 @@ uidmap unclaim undefine undercloud +unicast unittest unmanaged uoyt diff --git a/group_vars/all.yml b/group_vars/all.yml index b55c0b393..ab8684d80 100644 --- a/group_vars/all.yml +++ b/group_vars/all.yml @@ -10,3 +10,5 @@ cifmw_installyamls_repos_relative: src/github.com/openstack-k8s-operators/instal cifmw_installyamls_repos: "{{ ansible_user_dir }}/{{ cifmw_installyamls_repos_relative }}" cifmw_architecture_repo_relative: src/github.com/openstack-k8s-operators/architecture cifmw_architecture_repo: "{{ ansible_user_dir }}/{{ cifmw_architecture_repo_relative }}" + +cifmw_openstack_namespace: "{{ cifmw_install_yamls_defaults['NAMESPACE'] | default('openstack') }}" diff --git a/hooks/playbooks/README.md b/hooks/playbooks/README.md index 56e64b60b..93b2d71b8 100644 --- a/hooks/playbooks/README.md +++ b/hooks/playbooks/README.md @@ -24,6 +24,21 @@ on removing "import_playbook" usage in ci-framework project. ### Output None +## install-openstack-lightspeed.yml +Installs OpenShift Lightspeed and OpenStack Lightspeed operators on CRC cluster. +This hook deploys both operators sequentially, setting up required namespaces, +operator groups, catalog sources, and subscriptions. + +### Input +* `cifmw_openstack_lightspeed_namespace`: (String) Namespace for OpenStack Lightspeed operator. Defaults to `openshift-lightspeed`. +* `cifmw_openstack_lightspeed_operator_group`: (String) OperatorGroup name for OpenStack Lightspeed. Defaults to `openstack-lightspeed-operator-group`. +* `cifmw_openstack_lightspeed_catalog_image`: (String) Container image for OpenStack Lightspeed catalog source. Defaults to `quay.io/openstack-lightspeed/operator-catalog:latest`. +* `cifmw_openstack_lightspeed_catalog_name`: (String) Name for OpenStack Lightspeed CatalogSource resource. Defaults to `openstack-lightspeed-catalog`. +* `cifmw_openshift_kubeconfig`: (String) Path to kubeconfig file for OpenShift cluster. Defaults to `{{ ansible_env.HOME }}/.crc/machines/crc/kubeconfig`. + +### Output +None + ## kustomize_cr.yml This hook enables customization of CR files, using oc kustomize. ### Input diff --git a/hooks/playbooks/apply_cinder_replication_kustomization.yml b/hooks/playbooks/apply_cinder_replication_kustomization.yml index 8626e0b93..dbff15193 100644 --- a/hooks/playbooks/apply_cinder_replication_kustomization.yml +++ b/hooks/playbooks/apply_cinder_replication_kustomization.yml @@ -30,7 +30,7 @@ KUBECONFIG: "{{ cifmw_openshift_kubeconfig }}" PATH: "{{ cifmw_path }}" ansible.builtin.command: - cmd: oc get openstackcontrolplane -n openstack -o yaml + cmd: "oc get openstackcontrolplane -n {{ cifmw_openstack_namespace }} -o yaml" register: current_controlplane_config - name: Parse existing Cinder backend configuration @@ -58,7 +58,7 @@ kind: OpenStackControlPlane metadata: name: controlplane - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" spec: cinder: template: @@ -70,4 +70,4 @@ KUBECONFIG: "{{ cifmw_openshift_kubeconfig }}" PATH: "{{ cifmw_path }}" ansible.builtin.command: - cmd: oc wait --for=condition=Ready openstackcontrolplane/controlplane -n openstack --timeout=1200s + cmd: "oc wait --for=condition=Ready openstackcontrolplane/controlplane -n {{ cifmw_openstack_namespace }} --timeout=1200s" diff --git a/hooks/playbooks/ceph.yml b/hooks/playbooks/ceph.yml index eecf70eaa..be0db4ed1 100644 --- a/hooks/playbooks/ceph.yml +++ b/hooks/playbooks/ceph.yml @@ -162,7 +162,6 @@ - name: Set IPv4 facts when: - - ansible_all_ipv4_addresses | length > 0 - not cifmw_ceph_ipv6 | default(false) ansible.builtin.set_fact: ssh_network_range: 192.168.122.0/24 @@ -174,7 +173,6 @@ - name: Set IPv6 facts when: - - ansible_all_ipv6_addresses | length > 0 - cifmw_ceph_ipv6 | default(false) ansible.builtin.set_fact: ssh_network_range: "2620:cf:cf:aaaa::/64" diff --git a/hooks/playbooks/delete_all_pre_adoption_resources.yaml b/hooks/playbooks/delete_all_pre_adoption_resources.yaml index 3ae88f2bb..8a9c5c17c 100644 --- a/hooks/playbooks/delete_all_pre_adoption_resources.yaml +++ b/hooks/playbooks/delete_all_pre_adoption_resources.yaml @@ -14,7 +14,7 @@ - name: Fetch cloud config to host kubernetes.core.k8s_cp: kubeconfig: "{{ cifmw_resource_delete_kubeconfig }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: openstackclient remote_path: /home/cloud-admin/.config/openstack/ local_path: "/home/zuul/.config/openstack/" diff --git a/hooks/playbooks/dz_storage_post_deploy_az.yaml b/hooks/playbooks/dz_storage_post_deploy_az.yaml index 28cc88c8f..46e9bc4e9 100644 --- a/hooks/playbooks/dz_storage_post_deploy_az.yaml +++ b/hooks/playbooks/dz_storage_post_deploy_az.yaml @@ -11,7 +11,7 @@ PATH: "{{ cifmw_path | default(ansible_env.PATH) }}" ansible.builtin.command: >- oc rsh - -n openstack + -n "{{ cifmw_openstack_namespace }}" openstackclient openstack project show service -c id -f value register: service_project_result @@ -26,7 +26,7 @@ PATH: "{{ cifmw_path | default(ansible_env.PATH) }}" ansible.builtin.command: >- oc rsh - -n openstack + -n "{{ cifmw_openstack_namespace }}" openstackclient openstack volume type create --private --project "{{ service_project_id }}" @@ -44,7 +44,7 @@ PATH: "{{ cifmw_path | default(ansible_env.PATH) }}" ansible.builtin.command: >- oc rsh - -n openstack + -n "{{ cifmw_openstack_namespace }}" openstackclient openstack aggregate create {{ item }} --zone {{ item }} loop: @@ -59,7 +59,7 @@ PATH: "{{ cifmw_path | default(ansible_env.PATH) }}" ansible.builtin.command: >- oc rsh - -n openstack + -n "{{ cifmw_openstack_namespace }}" openstackclient openstack aggregate add host {{ item.az }} {{ item.host }} loop: diff --git a/hooks/playbooks/dz_storage_pre_test_images.yaml b/hooks/playbooks/dz_storage_pre_test_images.yaml index c5feb6a7c..f05a14be9 100644 --- a/hooks/playbooks/dz_storage_pre_test_images.yaml +++ b/hooks/playbooks/dz_storage_pre_test_images.yaml @@ -8,7 +8,6 @@ cirros_version: "0.6.2" cirros_image_name: "cirros-{{ cirros_version }}-x86_64-disk.img" cirros_download_url: "https://github.com/cirros-dev/cirros/releases/download/{{ cirros_version }}/{{ cirros_image_name }}" - openstack_namespace: "{{ cifmw_openstack_namespace | default('openstack') }}" tasks: - name: Check if cirros image already exists environment: @@ -16,7 +15,7 @@ PATH: "{{ cifmw_path | default(ansible_env.PATH) }}" ansible.builtin.command: >- oc rsh - -n {{ openstack_namespace }} + -n {{ cifmw_openstack_namespace }} openstackclient openstack image show {{ cirros_image_name }} register: _image_exists @@ -31,7 +30,7 @@ PATH: "{{ cifmw_path | default(ansible_env.PATH) }}" ansible.builtin.command: >- oc rsh - -n {{ openstack_namespace }} + -n {{ cifmw_openstack_namespace }} openstackclient openstack endpoint list --service keystone --interface public -f value -c URL register: keystone_url @@ -41,7 +40,7 @@ KUBECONFIG: "{{ cifmw_openshift_kubeconfig | default('/home/' + ansible_user | default('zuul') + '/.kube/config') }}" PATH: "{{ cifmw_path | default(ansible_env.PATH) }}" ansible.builtin.command: >- - oc get secret osp-secret -n {{ openstack_namespace }} -o jsonpath='{.data.AdminPassword}' + oc get secret osp-secret -n {{ cifmw_openstack_namespace }} -o jsonpath='{.data.AdminPassword}' register: admin_password_b64 - name: Decode admin password @@ -61,7 +60,7 @@ ansible.builtin.command: >- oc cp "/tmp/{{ cirros_image_name }}" - "{{ openstack_namespace }}/openstackclient:/home/cloud-admin/{{ cirros_image_name }}" + "{{ cifmw_openstack_namespace }}/openstackclient:/home/cloud-admin/{{ cirros_image_name }}" - name: Create cirros image in default glance store (az0) environment: @@ -69,7 +68,7 @@ PATH: "{{ cifmw_path | default(ansible_env.PATH) }}" ansible.builtin.command: >- oc rsh - -n {{ openstack_namespace }} + -n {{ cifmw_openstack_namespace }} openstackclient openstack image create --disk-format qcow2 @@ -85,7 +84,7 @@ PATH: "{{ cifmw_path | default(ansible_env.PATH) }}" ansible.builtin.command: >- oc rsh - -n {{ openstack_namespace }} + -n {{ cifmw_openstack_namespace }} openstackclient openstack image show {{ cirros_image_name }} -f value -c status register: image_status @@ -99,7 +98,7 @@ PATH: "{{ cifmw_path | default(ansible_env.PATH) }}" ansible.builtin.command: >- oc rsh - -n {{ openstack_namespace }} + -n {{ cifmw_openstack_namespace }} openstackclient openstack image show {{ cirros_image_name }} -f value -c id register: image_id @@ -110,7 +109,7 @@ PATH: "{{ cifmw_path | default(ansible_env.PATH) }}" ansible.builtin.command: >- oc rsh - -n {{ openstack_namespace }} + -n {{ cifmw_openstack_namespace }} openstackclient glance --os-auth-url {{ keystone_url.stdout | trim }} --os-project-name admin @@ -128,7 +127,7 @@ PATH: "{{ cifmw_path | default(ansible_env.PATH) }}" ansible.builtin.command: >- oc rsh - -n {{ openstack_namespace }} + -n {{ cifmw_openstack_namespace }} openstackclient openstack image show {{ image_id.stdout | trim }} -c properties -f value register: image_stores diff --git a/hooks/playbooks/group_vars b/hooks/playbooks/group_vars new file mode 120000 index 000000000..14bb1b3d9 --- /dev/null +++ b/hooks/playbooks/group_vars @@ -0,0 +1 @@ +../../group_vars \ No newline at end of file diff --git a/hooks/playbooks/install-openstack-lightspeed.yml b/hooks/playbooks/install-openstack-lightspeed.yml new file mode 100644 index 000000000..7f7d6c6f9 --- /dev/null +++ b/hooks/playbooks/install-openstack-lightspeed.yml @@ -0,0 +1,128 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Deploy OpenStack Lightspeed operator + hosts: "{{ cifmw_target_hook_host | default('localhost') }}" + connection: local + vars: + # OpenStack Lightspeed configuration + # Note: Installing in openshift-lightspeed namespace to ensure compatibility + openstack_lightspeed_namespace: "{{ cifmw_openstack_lightspeed_namespace | default('openshift-lightspeed') }}" + openstack_lightspeed_operator_group: "{{ cifmw_openstack_lightspeed_operator_group | default('openstack-lightspeed-operator-group') }}" + openstack_lightspeed_catalog_image: "{{ cifmw_openstack_lightspeed_catalog_image | default('quay.io/openstack-lightspeed/operator-catalog:latest') }}" + openstack_lightspeed_catalog_name: "{{ cifmw_openstack_lightspeed_catalog_name | default('openstack-lightspeed-catalog') }}" + + # Kubeconfig path - use user-provided or default to CRC location + cifmw_openshift_kubeconfig: "{{ cifmw_openshift_kubeconfig | default(ansible_env.HOME ~ '/.crc/machines/crc/kubeconfig') }}" + environment: + KUBECONFIG: "{{ cifmw_openshift_kubeconfig }}" + + tasks: + # STEP 1: Deploy OpenStack Lightspeed catalog + + - name: Create CatalogSource for OpenStack Lightspeed + kubernetes.core.k8s: + state: present + definition: + apiVersion: operators.coreos.com/v1alpha1 + kind: CatalogSource + metadata: + name: "{{ openstack_lightspeed_catalog_name }}" + namespace: "openshift-marketplace" + spec: + sourceType: grpc + image: "{{ openstack_lightspeed_catalog_image }}" + displayName: "OpenStack Lightspeed Operator" + publisher: "Red Hat" + + - name: Wait for CatalogSource to be ready + kubernetes.core.k8s_info: + api_version: operators.coreos.com/v1alpha1 + kind: CatalogSource + name: "{{ openstack_lightspeed_catalog_name }}" + namespace: "openshift-marketplace" + register: catalog_source + until: + - catalog_source.resources is defined + - catalog_source.resources | length > 0 + - catalog_source.resources[0].status.connectionState.lastObservedState is defined + - catalog_source.resources[0].status.connectionState.lastObservedState == "READY" + retries: 30 + delay: 10 + + # STEP 2: Deploy OpenStack Lightspeed operator + # Note: OpenStack Lightspeed operator will automatically install + # and manage the OpenShift Lightspeed operator as a dependency + + - name: Create namespace for OpenStack Lightspeed + kubernetes.core.k8s: + state: present + definition: + apiVersion: v1 + kind: Namespace + metadata: + name: "{{ openstack_lightspeed_namespace }}" + + - name: Create OperatorGroup for OpenStack Lightspeed + kubernetes.core.k8s: + state: present + definition: + apiVersion: operators.coreos.com/v1 + kind: OperatorGroup + metadata: + name: "{{ openstack_lightspeed_operator_group }}" + namespace: "{{ openstack_lightspeed_namespace }}" + spec: + targetNamespaces: + - "{{ openstack_lightspeed_namespace }}" + + - name: Subscribe to OpenStack Lightspeed operator + kubernetes.core.k8s: + state: present + definition: + apiVersion: operators.coreos.com/v1alpha1 + kind: Subscription + metadata: + name: "openstack-lightspeed-operator" + namespace: "{{ openstack_lightspeed_namespace }}" + spec: + channel: "alpha" + name: "openstack-lightspeed-operator" + source: "{{ openstack_lightspeed_catalog_name }}" + sourceNamespace: "openshift-marketplace" + installPlanApproval: "Automatic" + + - name: Wait for OpenStack Lightspeed CSV to be ready + kubernetes.core.k8s_info: + api_version: operators.coreos.com/v1alpha1 + kind: ClusterServiceVersion + namespace: "{{ openstack_lightspeed_namespace }}" + label_selectors: + - "operators.coreos.com/openstack-lightspeed-operator.{{ openstack_lightspeed_namespace }}" + register: osls_csv + until: + - osls_csv.resources is defined + - osls_csv.resources | length > 0 + - osls_csv.resources[0].status.phase is defined + - osls_csv.resources[0].status.phase == "Succeeded" + retries: 30 + delay: 10 + + - name: Display deployment summary + ansible.builtin.debug: + msg: + - "✓ OpenStack Lightspeed operator deployed in namespace: {{ openstack_lightspeed_namespace }}" + - "✓ OpenShift Lightspeed operator will be automatically managed by OpenStack Lightspeed" diff --git a/hooks/playbooks/install_custom_ca_certs.yaml b/hooks/playbooks/install_custom_ca_certs.yaml index dbcd4a6d4..87e35b462 100644 --- a/hooks/playbooks/install_custom_ca_certs.yaml +++ b/hooks/playbooks/install_custom_ca_certs.yaml @@ -1,12 +1,22 @@ --- -- name: Set up custom CA secret for OpenStack control plane +- name: Prepare custom CA secret hosts: "{{ cifmw_target_hook_host | default('localhost') }}" gather_facts: false + connection: local vars: - _custom_ca_cert_filepath: "{{ custom_ca_cert_filepath | mandatory }}" - _namespace: "{{ namespace | default('openstack') }}" - _controlplane_name: "{{ controlplane_name | default('controlplane') }}" + _custom_ca_cert_filepath: "{{ custom_ca_cert_filepath | default('/tmp/ca_cert.txt') }}" tasks: + - name: Download cert + ansible.builtin.get_url: + url: "{{ custom_ca_cert_url }}" + dest: "{{ _custom_ca_cert_filepath }}" + mode: '0644' + when: custom_ca_cert_url is defined + register: download_status + until: download_status is not failed and (download_status.status_code is undefined or download_status.status_code == 200) + retries: 10 + delay: 5 + - name: Read custom CA certificate file ansible.builtin.slurp: src: "{{ _custom_ca_cert_filepath }}" @@ -14,6 +24,7 @@ - name: Create custom CA secret kubernetes.core.k8s: + kubeconfig: "{{ cifmw_openshift_kubeconfig }}" state: present definition: apiVersion: v1 @@ -21,20 +32,6 @@ type: Opaque metadata: name: custom-ca-certs - namespace: "{{ _namespace }}" + namespace: "{{ cifmw_openstack_namespace }}" data: CustomCACerts: "{{ custom_ca_certs.content }}" - - - name: Patch OpenStack control plane to use custom CA secret - kubernetes.core.k8s: - state: patched - kind: OpenStackControlPlane - api_version: core.openstack.org/v1beta1 - name: "{{ _controlplane_name }}" - namespace: "{{ _namespace }}" - definition: - spec: - tls: - podLevel: - enabled: true - caBundleSecretName: custom-ca-certs diff --git a/hooks/playbooks/ipa-controlplane-config.yml b/hooks/playbooks/ipa-controlplane-config.yml index 75a02cca8..97c74ed1b 100644 --- a/hooks/playbooks/ipa-controlplane-config.yml +++ b/hooks/playbooks/ipa-controlplane-config.yml @@ -66,7 +66,7 @@ kind: Secret metadata: name: keystone-domains - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" type: Opaque stringData: "{{ {keystone_conf_key: keystone_ldap_config_content} }}" vars: diff --git a/hooks/playbooks/ironic_enroll_nodes.yml b/hooks/playbooks/ironic_enroll_nodes.yml index e4edb5779..43319ce02 100644 --- a/hooks/playbooks/ironic_enroll_nodes.yml +++ b/hooks/playbooks/ironic_enroll_nodes.yml @@ -4,7 +4,6 @@ gather_facts: false vars: _baremetal_info_path: "{{ cifmw_basedir }}/parameters/baremetal-info.yml" - _namespace: openstack _ironic_node_name_prefix: ironic- _ironic_network_interface: flat _ironic_network_physical_network: ironic @@ -38,6 +37,7 @@ { 'name': item.key, 'driver': 'redfish', + 'resource_class': 'BAREMETAL', 'driver_info': { 'redfish_address': (_conn.scheme | split('+') | last) + '://' + _conn.hostname + ':' + (_conn.port | string), @@ -66,7 +66,7 @@ - name: Enroll ironic nodes ansible.builtin.shell: | set -xe -o pipefail - oc project {{ _namespace }} - oc cp {{ cifmw_basedir }}/parameters/ironic_nodes.yaml {{ _namespace }}/openstackclient:/tmp/ + oc project {{ cifmw_openstack_namespace }} + oc cp {{ cifmw_basedir }}/parameters/ironic_nodes.yaml {{ cifmw_openstack_namespace }}/openstackclient:/tmp/ oc rsh openstackclient \ openstack baremetal create /tmp/ironic_nodes.yaml diff --git a/hooks/playbooks/ironic_flavor.yml b/hooks/playbooks/ironic_flavor.yml index 874a48be1..e86719639 100644 --- a/hooks/playbooks/ironic_flavor.yml +++ b/hooks/playbooks/ironic_flavor.yml @@ -3,7 +3,6 @@ hosts: "{{ cifmw_target_hook_host | default('localhost') }}" gather_facts: false vars: - _namespace: openstack _flavor_name: baremetal _flavor_id: 123456789-1234-1234-1234-000000000001 _boot_mode: uefi @@ -14,7 +13,7 @@ - name: Create baremetal flavor ansible.builtin.shell: | set -xe -o pipefail - oc project {{ _namespace }} + oc project {{ cifmw_openstack_namespace }} oc rsh openstackclient \ openstack flavor create {{ _flavor_name }} \ --id {{ _flavor_id }} \ diff --git a/hooks/playbooks/ironic_network.yml b/hooks/playbooks/ironic_network.yml index 3e00483b3..14f55265e 100644 --- a/hooks/playbooks/ironic_network.yml +++ b/hooks/playbooks/ironic_network.yml @@ -3,7 +3,6 @@ hosts: "{{ cifmw_target_hook_host | default('localhost') }}" gather_facts: false vars: - _namespace: openstack _subnet_range: '172.20.1.0/24' _subnet_gateway: '172.20.1.1' _subnet_nameserver: '192.168.122.80' @@ -15,6 +14,7 @@ _provider_physical_network: ironic _provider_network_type: flat _availability_zone_hints: null # Comma separated list of strings + _create_provisioning_router: true # Set to false to opt out of router creation environment: KUBECONFIG: "{{ cifmw_openshift_kubeconfig }}" PATH: "{{ cifmw_path }}" @@ -22,7 +22,7 @@ - name: Create baremetal network ansible.builtin.shell: | set -xe -o pipefail - oc project {{ _namespace }} + oc project {{ cifmw_openstack_namespace }} oc rsh openstackclient \ openstack network create provisioning \ --share \ @@ -51,9 +51,11 @@ - name: Create router for IPv6 provisioning network ansible.builtin.shell: | set -xe -o pipefail - oc project {{ _namespace }} + oc project {{ cifmw_openstack_namespace }} oc rsh openstackclient \ openstack router create provisioning oc rsh openstackclient \ openstack router add subnet provisioning provisioning-subnet - when: _subnet_ip_version | int == 6 + when: + - _subnet_ip_version | int == 6 + - _create_provisioning_router | bool diff --git a/hooks/playbooks/ironic_network_agent_cleanup.yml b/hooks/playbooks/ironic_network_agent_cleanup.yml index 1470b8679..5bdf89058 100644 --- a/hooks/playbooks/ironic_network_agent_cleanup.yml +++ b/hooks/playbooks/ironic_network_agent_cleanup.yml @@ -2,8 +2,6 @@ - name: Delete neutron network agents for Baremetal Nodes hosts: "{{ cifmw_target_hook_host | default('localhost') }}" gather_facts: false - vars: - _namespace: openstack environment: KUBECONFIG: "{{ cifmw_openshift_kubeconfig }}" PATH: "{{ cifmw_path }}" @@ -11,7 +9,7 @@ - name: Delete baremetal network agents ansible.builtin.shell: | set -xe -o pipefail - oc project {{ _namespace }} + oc project {{ cifmw_openstack_namespace }} echo "Discovering baremetal network agents..." diff --git a/hooks/playbooks/pcp-metrics-pre.yml b/hooks/playbooks/pcp-metrics-pre.yml index 44e4770df..c2b007e32 100644 --- a/hooks/playbooks/pcp-metrics-pre.yml +++ b/hooks/playbooks/pcp-metrics-pre.yml @@ -14,6 +14,15 @@ name: pcp_metrics tasks_from: coreos +- name: Setup PCP repositories for network nodes + hosts: leafs,spines,routers + gather_facts: false + tasks: + - name: Setup repositories for PCP + ansible.builtin.include_role: + name: pcp_metrics + tasks_from: repo + - name: Start collecting performance metrics hosts: all,!localhost gather_facts: false diff --git a/hooks/playbooks/run_tofu.yml b/hooks/playbooks/run_tofu.yml index e0b5a78a8..84349a8d3 100644 --- a/hooks/playbooks/run_tofu.yml +++ b/hooks/playbooks/run_tofu.yml @@ -29,7 +29,7 @@ - name: Fetch cloud congig to host kubernetes.core.k8s_cp: kubeconfig: "{{ cifmw_tofu_kubeconfig }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: openstackclient remote_path: /home/cloud-admin/.config/openstack/ local_path: "{{ ansible_user_dir }}/.config/openstack/" diff --git a/hooks/playbooks/setup_cephnodes.yaml b/hooks/playbooks/setup_cephnodes.yaml new file mode 100644 index 000000000..1dbaf8740 --- /dev/null +++ b/hooks/playbooks/setup_cephnodes.yaml @@ -0,0 +1,98 @@ +--- +- name: Setup repos, CA and networks on ceph nodes + hosts: "{{ cifmw_ceph_target | default('ceph') }}" + gather_facts: true + become: true + vars: + cifmw_adoption_osp_deploy_ntp_server: "pool.ntp.org" + cifmw_adoption_osp_deploy_repos: + - rhel-9-for-x86_64-baseos-eus-rpms + - rhel-9-for-x86_64-appstream-eus-rpms + - rhel-9-for-x86_64-highavailability-eus-rpms + - openstack-17.1-for-rhel-9-x86_64-rpms + - fast-datapath-for-rhel-9-x86_64-rpms + - rhceph-7-tools-for-rhel-9-x86_64-rpms + common_dns: ["192.168.122.1"] + base_config: "/etc/os-net-config" + tasks: + - name: Setup repositories via rhos-release if needed + ansible.builtin.import_role: + name: repo_setup + tasks_from: rhos_release.yml + + - name: Install custom CA if needed + ansible.builtin.import_role: + name: install_ca + - name: Ensure needed logins + ansible.builtin.import_role: + name: adoption_osp_deploy + tasks_from: login_registries.yml + + - name: Ensure repos are setup + become: true + community.general.rhsm_repository: + name: "{{ cifmw_adoption_osp_deploy_repos }}" + state: enabled + + - name: Ensure os-net-config folder exists in ceph nodes + become: true + ansible.builtin.file: + path: "/etc/os-net-config" + state: directory + mode: '0755' + + - name: Ensure os-net-config and openvswitch is installed in ceph nodes + become: true + ansible.builtin.dnf: + name: + - os-net-config + - openvswitch + state: present + + - name: Generate os-net-config YAML + ansible.builtin.copy: + dest: "{{ base_config }}/network-os-net-config.yaml" + mode: '0644' + content: | + network_config: + - type: ovs_bridge + name: br-ex + mtu: 1500 + use_dhcp: false + dns_servers: {{ common_dns }} + addresses: + - ip_netmask: "{{ hostvars[inventory_hostname]['bridge_ip'] }}" + routes: [] + members: + - type: interface + name: nic2 + mtu: 1500 + primary: true + addresses: + - ip_netmask: "{{ hostvars[inventory_hostname]['external_ip'] }}" + routes: [] + - type: vlan + vlan_id: 20 + addresses: + - ip_netmask: "{{ hostvars[inventory_hostname]['internalapi_ip'] }}" + routes: [] + - type: vlan + vlan_id: 21 + addresses: + - ip_netmask: "{{ hostvars[inventory_hostname]['storage_ip'] }}" + routes: [] + - type: vlan + vlan_id: 23 + addresses: + - ip_netmask: "{{ hostvars[inventory_hostname]['storagemgmt_ip'] }}" + routes: [] + - type: vlan + vlan_id: 22 + addresses: + - ip_netmask: "{{ hostvars[inventory_hostname]['tenant_ip'] }}" + routes: [] + + - name: Apply network configuration + ansible.builtin.command: > + os-net-config -c {{ base_config }}/network-os-net-config.yaml -v + changed_when: true diff --git a/hooks/playbooks/tempest_store_timing_data.yaml b/hooks/playbooks/tempest_store_timing_data.yaml new file mode 100644 index 000000000..c5c363b2c --- /dev/null +++ b/hooks/playbooks/tempest_store_timing_data.yaml @@ -0,0 +1,46 @@ +--- +- name: Store stestr timing data in repository + hosts: localhost + gather_facts: false + vars: + repo_path: "/tmp/timing-data" + tests_log_dir: "{{ ansible_user_dir }}/ci-framework-data/tests/test_operator" + timing_data_repo: "https://repo.example.org/project/timing-data" + tasks: + - name: All tasks required for storing timing data + # Note(kstrenko): This playbook introduces an additional feature + # and should not interfere with existing jobs. + ignore_errors: true # noqa: ignore-errors + block: + - name: Clone timing data repository + ansible.builtin.git: + repo: "{{ timing_data_repo }}" + dest: "{{ repo_path }}" + version: "main" + + - name: Configure git settings + community.general.git_config: + repo: "{{ repo_path }}" + scope: local + name: "{{ item.name }}" + value: "{{ item.value }}" + loop: + - {name: 'user.name', value: 'Zuul'} + - {name: 'user.email', value: 'rhos-dfg-ciops@redhat.com'} + - {name: 'remote.origin.url', value: '{{ timing_data_repo }}'} + + - name: Find all 'tempest' directories + ansible.builtin.find: + paths: "{{ tests_log_dir }}" + file_type: directory + patterns: "*-tempest*" + register: tempest_dirs + + - name: Store timing data for every tempest-test directory + ansible.builtin.include_tasks: ../tasks/tempest_store_timing_data_each.yaml + vars: + stestr_tar_path: "{{ tests_log_dir }}/{{ tempest_tests_name.path | basename }}/stestr.tar.gz" + timing_data_repo_dir: "{{ repo_path }}/{{ job_name }}/{{ tempest_tests_name.path | basename }}" + loop: "{{ tempest_dirs.files }}" + loop_control: + loop_var: tempest_tests_name diff --git a/hooks/playbooks/validate_podified_deployment.yml b/hooks/playbooks/validate_podified_deployment.yml index c38f08d69..7de942c39 100644 --- a/hooks/playbooks/validate_podified_deployment.yml +++ b/hooks/playbooks/validate_podified_deployment.yml @@ -8,7 +8,7 @@ KUBECONFIG: "{{ cifmw_openshift_kubeconfig }}" PATH: "{{ cifmw_path }}" ansible.builtin.shell: | - oc get pods -n {{ openstack_namespace }} --selector service=nova-api -o jsonpath={.items[*].status.phase} + oc get pods -n {{ cifmw_openstack_namespace }} --selector service=nova-api -o jsonpath={.items[*].status.phase} register: nova_service until: nova_service.stdout == "Running" changed_when: false @@ -22,5 +22,5 @@ KUBECONFIG: "{{ cifmw_openshift_kubeconfig }}" PATH: "{{ cifmw_path }}" ansible.builtin.shell: | - oc rsh -n {{ openstack_namespace }} openstackclient openstack compute service list; - oc rsh -n {{ openstack_namespace }} openstackclient openstack network agent list; + oc rsh -n {{ cifmw_openstack_namespace }} openstackclient openstack compute service list; + oc rsh -n {{ cifmw_openstack_namespace }} openstackclient openstack network agent list; diff --git a/hooks/tasks/tempest_store_timing_data_each.yaml b/hooks/tasks/tempest_store_timing_data_each.yaml new file mode 100644 index 000000000..82b6d3d69 --- /dev/null +++ b/hooks/tasks/tempest_store_timing_data_each.yaml @@ -0,0 +1,42 @@ +--- +# +# Included by tempest_store_timing_data.yaml playbook +# +# There are two variables passed by the loop +# - stestr_tar_path - a path to the data which will be copied +# - timing_data_repo_dir - a path to a directory to be created +# +- name: Ensure the defined directory exists + ansible.builtin.file: + path: "{{ timing_data_repo_dir }}" + state: directory + mode: '0755' + +- name: Copy timing data to commit + ansible.builtin.copy: + src: "{{ stestr_tar_path }}" + dest: "{{ timing_data_repo_dir }}" + mode: '0644' + +- name: Add all changes + ansible.builtin.command: + cmd: git add . + chdir: "{{ repo_path }}" + changed_when: false + # noqa command-instead-of-module + +- name: Commit changes + ansible.builtin.command: + cmd: git commit -m "Automatic update" + chdir: "{{ repo_path }}" + register: commit_result + changed_when: commit_result.rc == 0 + # noqa command-instead-of-module + +- name: Push changes to the repository + ansible.builtin.command: + cmd: git push origin main + chdir: "{{ repo_path }}" + when: commit_result.rc == 0 + changed_when: false + # noqa command-instead-of-module diff --git a/playbooks/06-deploy-architecture.yml b/playbooks/06-deploy-architecture.yml index 408e7acc9..38e2907b8 100644 --- a/playbooks/06-deploy-architecture.yml +++ b/playbooks/06-deploy-architecture.yml @@ -281,7 +281,7 @@ PATH: "{{ cifmw_path }}" ansible.builtin.command: >- oc rsh - -n openstack + -n "{{ cifmw_openstack_namespace }}" nova-cell0-conductor-0 nova-manage cell_v2 discover_hosts --verbose diff --git a/playbooks/bgp/OWNERS b/playbooks/bgp/OWNERS new file mode 100644 index 000000000..6839704e6 --- /dev/null +++ b/playbooks/bgp/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - bgp-team + +reviewers: + - bgp-team diff --git a/playbooks/ceph/OWNERS b/playbooks/ceph/OWNERS new file mode 100644 index 000000000..d5b92d858 --- /dev/null +++ b/playbooks/ceph/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - storage-team + +reviewers: + - storage-team diff --git a/playbooks/dcn/OWNERS b/playbooks/dcn/OWNERS new file mode 100644 index 000000000..8366991fc --- /dev/null +++ b/playbooks/dcn/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - dcn-team + +reviewers: + - dcn-team diff --git a/plugins/README.md b/plugins/README.md index 12161f14c..dde6d2347 100644 --- a/plugins/README.md +++ b/plugins/README.md @@ -213,7 +213,7 @@ Module that approves pending certificate requests in OpenShift platform. tasks: - name: Wait and approve all - approve_csr: + cifmw.general.approve_csr: k8s_config: "{{ k8s_config }}" ``` diff --git a/plugins/modules/approve_csr.py b/plugins/modules/approve_csr.py index a6d7714de..16f9d3e36 100644 --- a/plugins/modules/approve_csr.py +++ b/plugins/modules/approve_csr.py @@ -39,7 +39,7 @@ EXAMPLES = r""" - name: Approve all pending certificate requests - approve_csr: + cifmw.general.approve_csr: k8s_config: "{{ lookup('env', 'KUBECONFIG') }}" """ diff --git a/plugins/modules/bridge_vlan.py b/plugins/modules/bridge_vlan.py index a3d03efdf..0a5753d6c 100644 --- a/plugins/modules/bridge_vlan.py +++ b/plugins/modules/bridge_vlan.py @@ -54,7 +54,7 @@ EXAMPLES = r""" - name: Attach all configured VLANs to the interfaces of osp_trunk become: true - bridge_vlan: + cifmw.general.bridge_vlan: networks: - osp_trunk """ # noqa diff --git a/plugins/modules/cephx_key.py b/plugins/modules/cephx_key.py index 3295902b2..d84cff29e 100644 --- a/plugins/modules/cephx_key.py +++ b/plugins/modules/cephx_key.py @@ -22,7 +22,7 @@ EXAMPLES = r""" - name: Generate a cephx key - cephx_key: + cifmw.general.cephx_key: register: cephx - name: Show cephx key diff --git a/plugins/modules/crawl_n_mask.py b/plugins/modules/crawl_n_mask.py index 8470b9e5d..1ea75c71d 100755 --- a/plugins/modules/crawl_n_mask.py +++ b/plugins/modules/crawl_n_mask.py @@ -13,13 +13,12 @@ --- module: crawl_n_mask -short_description: This module mask secrets in yaml files/dirs +short_description: This module mask secrets in yaml/json/log files/dirs version_added: "1.0.0" description: - - This module crawls over a directory (default) and find yaml files which may have secrets in it, and proceeds with masking it. - - If you pass a yaml file, it will directly check and mask secret in it. + - This module crawls over a directory (default) and find yaml/json/log files which may have secrets in it, and proceeds with masking it. - If you pass a directory, it will crawl the directory and find eligible files to mask. options: @@ -43,14 +42,18 @@ """ EXAMPLES = r""" -- name: Mask secrets in all yaml files within /home/zuul/logs - crawl_n_mask: +- name: Mask secrets in all yaml/json/log files within /home/zuul/logs + cifmw.general.crawl_n_mask: path: /home/zuul/logs isdir: True - name: Mask my_secrets.yaml - crawl_n_mask: + cifmw.general.crawl_n_mask: path: /home/zuul/logs/my_secrets.yaml + +- name: Mask application.log + cifmw.general.crawl_n_mask: + path: /var/log/application.log """ RETURN = r""" @@ -62,8 +65,9 @@ """ import os -import re import pathlib +import re +from multiprocessing import Pool, cpu_count from ansible.module_utils.basic import AnsibleModule @@ -86,85 +90,211 @@ # python3 plugins/modules/crawl_n_mask.py ./args.json ################ -# files which are yaml but do not end with .yaml or .yml -ALLOWED_YAML_FILES = [ - "Standalone", -] # dirs which we do not want to scan EXCLUDED_DIRS = [ "openstack-k8s-operators-openstack-must-gather", "tmp", "venv", + ".git", ".github", ] -# file extensions which we do not want to process +# Used to skip Ansible task headers from txt/log masked files +ANSIBLE_SKIP_PATTERNS = [ + "TASK [", + "TASK: ", + "PLAY [", +] +# File extensions which we do not want to process EXCLUDED_FILE_EXT = [ ".py", ".html", ".DS_Store", - ".tar.gz", + ".tar.*", + ".rpm", ".zip", ".j2", + ".subunit", + ".tmp", ] # keys in files whose values need to be masked PROTECT_KEYS = [ - "literals", - "PASSWORD", - "Password", - "password", + "_client_cert_passphrase", + "_client_key_passphrase", + "_local_rsync_password", "_pwd", "_PWD", - "Token", - "Secret", - "secret", - "SECRET", + "_secret_content", + "abotrabbitmq", + "accessSecret", + "adcCredentialSecret", + "admin_password", + "adminPassword", + "AdminPassword", + "ADMIN_PASSWORD", + "adminPasswordSecretKeyRef", + "alt_password", + "AodhDatabasePassword", + "AodhPassword", + "api_secret", + "auth_encryption_key", + "authCertSecret", "Authkey", "authkey", - "private_key", - "privatekey", - "Passphrase", - "passphrase", - "PASSPHRASE", - "encryption_key", - "ENCRYPTION_KEY", - "HeatAuthEncryptionKey", - "oc_login_command", - "METADATA_SHARED_SECRET", - "KEYSTONE_FEDERATION_CLIENT_SECRET", - "rabbit", - "database_connection", - "slave_connection", - "sql_connection", + "aws_secret_access_key", + "BARBICAN_SIMPLE_CRYPTO_ENCRYPTION_KEY", + "BarbicanDatabasePassword", + "BarbicanPassword", + "BarbicanSimpleCryptoKEK", + "BarbicanSimpleCryptoKek", + "bearerToken", + "bind_password", + "bindPassword", + "bootstrapPassword", + "bootstrapToken", + "ca_secret", + "caSecret", + "CeilometerPassword", + "CephClientKey", + "CephClusterFSID", + "CephRgwKey", + "chap_password", "cifmw_openshift_login_password", "cifmw_openshift_login_token", - "BarbicanSimpleCryptoKEK", - "OctaviaHeartbeatKey", - "server-ca-passphrase", - "KeystoneFernetKeys", - "KeystoneFernetKey", - "KeystoneCredential", + "cifmw_openshift_password", + "CinderDatabasePassword", + "CinderPassword", + "client_secret", + "clientSecret", + "clientsecret", + "ClientKey", + "cloud_admin_user_password", + "database_connection", + "databasePassword", + "DatabasePassword", + "db-password", + "DB_ROOT_PASSWORD", + "DbRootPassword", + "defaultAdminPassword", + "DesignateDatabasePassword", + "DesignatePassword", "DesignateRndcKey", - "CephRgwKey", - "CephClusterFSID", - "CephClientKey", - "BarbicanSimpleCryptoKek", - "HashSuffix", - "RabbitCookie", + "docker-password", + "EMAIL_HOST_PASSWORD", + "ENCRYPTION_KEY", + "encryption_key", "erlang_cookie", - "ClientKey", - "swift_store_key", - "secret_key", - "heartbeat_key", "fernet_keys", - "sshkey", + "fromConnectionSecretKey", + "git-password", + "GlanceDatabasePassword", + "GlancePassword", + "HashSuffix", + "HEAT_AUTH_ENCRYPTION_KEY", + "HeatAuthEncryptionKey", + "HeatDatabasePassword", + "HeatPassword", + "heartbeat_key", + "http_basic_password", + "idp_password", + "idp_test_user_password", + "iibpassword", + "ilo_password", + "image_alt_ssh_password", + "image_password", + "image_server_password", + "image_ssh_password", + "infoblox_password", + "ipmi_password", + "IronicDatabasePassword", + "IronicInspectorDatabasePassword", + "IronicInspectorPassword", + "IronicPassword", + "key-password", + "key-store-password", + "key_password", + "keyPassword", + "keystoreKeyPassword", + "keystoreKeypassword", + "keystorePassword", + "keyStorePassword", + "KeystoneCredential", + "KeystoneDatabasePassword", + "KEYSTONE_FEDERATION_CLIENT_SECRET", + "KeystoneFernetKey", + "KeystoneFernetKeys", "keytab_base64", -] -# connection keys which may be part of the value itself -CONNECTION_KEYS = [ + "LibvirtPassword", + "licenseSecret", + "literals", + "managementPassword", + "ManilaDatabasePassword", + "ManilaPassword", + "MARIADB_PASSWORD", + "master-password", + "masterPassword", + "MASTER_PASSWORD", + "metadata_proxy_shared_secret", + "MetadataSecret", + "METADATA_SHARED_SECRET", + "MONGODB_BACKUP_PASSWORD", + "MONGODB_CLUSTER_ADMIN_PASSWORD", + "MONGODB_CLUSTER_MONITOR_PASSWORD", + "MONGODB_DATABASE_ADMIN_PASSWORD", + "MONGODB_USER_ADMIN_PASSWORD", + "mqpassword", + "mysql_root_password", + "mysql_zabbix_password", + "netapp_password", + "NeutronDatabasePassword", + "NeutronPassword", + "nexusInitialPassword", + "NodeRootPassword", + "NovaAPIDatabasePassword", + "NovaCell0DatabasePassword", + "NovaCell1DatabasePassword", + "NovaPassword", + "oc_login_command", + "OctaviaDatabasePassword", + "OctaviaHeartbeatKey", + "OctaviaPassword", + "Passphrase", + "passphrase", + "PASSPHRASE", + "Password", + "password", + "PASSWORD", + "pgpassword", + "pgreplpassword", + "pg_restic_password", + "pgRewindPassword", + "PlacementDatabasePassword", + "PlacementPassword", + "postgresPassword", + "postgresqlPassword", + "private_key", + "privatekey", + "proxy_password", "rabbit", - "database_connection", + "rabbitmqPassword", + "RabbitCookie", + "redfish_password", + "redis_password", + "remote_image_user_password", + "scimAdminPassword", + "Secret", + "secret", + "SECRET", + "secret_key", + "server-ca-passphrase", + "ServicePassword", "slave_connection", + "SPRING_DATASOURCE_PASSWORD", "sql_connection", + "ssh-privatekey", + "sshkey", + "stack_domain_admin_password", + "staticPasswords", + "X-Auth-Token", ] # Masking string MASK_STR = "**********" @@ -172,6 +302,48 @@ # regex of excluded file extensions excluded_file_ext_regex = r"(^.*(%s).*)" % "|".join(EXCLUDED_FILE_EXT) +QUICK_KEYWORDS = frozenset([key.lower() for key in PROTECT_KEYS]) + +# Pre-compiled regex patterns for log file masking. +LOG_PATTERNS = { + # Matches: 'password': 'value' OR \n'password': 'value' + # Groups: (1=prefix, 2=", 3=key, 4=", 5=space-before, 6=sep, 7=space-after, 8=", 9=value, 10=") + "python_dict_quoted": re.compile( + r"((?:\s|\\n)*)(['\"])(" + + "|".join(PROTECT_KEYS) + + r")(['\"])(\s*)([:=])(\s*)(['\"])([^'\"]+)(['\"])", + re.IGNORECASE, + ), + # Matches: 'password': 123456789 OR \n'password': 123456789 + # Groups: (1=prefix, 2=", 3=key, 4=", 5=space-before, 6=sep, 7=space-after, 8=value) + "python_dict_numeric": re.compile( + r"((?:\s|\\n)*)(['\"])(" + + "|".join(PROTECT_KEYS) + + r")(['\"])(\s*)(:)(\s*)(\d{6,})", + re.IGNORECASE, + ), + # Matches: password: value OR netapp_password=secret OR \npassword: value + # Groups: (1=prefix, 2=key, 3=space-before, 4=sep, 5=space-after, + # 6=open-quote(optional), 7=value, 8=close-quote(optional)) + "plain_key_value": re.compile( + r"((?:\s|\\n)*)\b(" + + "|".join(PROTECT_KEYS) + + r')\b(\s*)([:=])(\s*)(["\']?)([^\s\\"\']+)(["\']?)', + re.IGNORECASE, + ), + # Matches: SHA256 tokens (OpenShift style) + "sha256_token": re.compile(r"sha256~[A-Za-z0-9_-]+"), + # Matches: Bearer + "bearer": re.compile(r"Bearer\s+[a-zA-Z0-9_-]{20,}", re.IGNORECASE), + # Matches: ://user:pass@host + "connection_string": re.compile( + r"://([a-zA-Z0-9_-]+):([a-zA-Z0-9_@!#$%^&*]+)@([a-zA-Z0-9.-]+)" + ), +} + +# Available CPU-1, Max 8 +NUM_WORKERS = min(cpu_count() - 1, 8) + def handle_walk_errors(e): raise e @@ -182,8 +354,9 @@ def crawl(module, path) -> bool: Crawler function which will crawl through the log directory and find eligible files for masking. """ - changed = False + files_to_process = [] base_path = os.path.normpath(path) + results = [] for root, _, files in os.walk(base_path, onerror=handle_walk_errors): # Get relative path from our base path rel_path = os.path.relpath(root, base_path) @@ -191,100 +364,111 @@ def crawl(module, path) -> bool: # Check if any parent directory (not the root) is excluded if any(part in EXCLUDED_DIRS for part in rel_path.split(os.sep)): continue - for f in files: if not re.search(excluded_file_ext_regex, f): - if mask(module, os.path.join(root, f)): - # even if one file is masked, the final result will be True - changed = True - return changed + files_to_process.append(os.path.join(root, f)) + try: + with Pool(processes=NUM_WORKERS) as pool: + results = pool.map(mask_file, files_to_process) + except Exception as e: + module.fail_json(msg=f"Failed to mask files: {str(e)}") + + return any(results) def _get_masked_string(value): + # Not process empty strings + if len(value.strip("'\"")) == 0: + return value if len(value) <= 4: return value[:2] + MASK_STR return value[:2] + MASK_STR + value[-2:] -def partial_mask(value): +def mask_log_line(line: str) -> str: """ - Check length of the string. If it is too long, take 2 chars - from beginning, then add mask string and add 2 chars from the - end. - If value is short, take just 2 chars and add mask string + Masks several secrets occurrence in a single line. + Works good with big file with long lines and sparse secrets. + + Returns masked line with secrets replaced by MASK_STR """ - if not value.strip(): - return - - if "'" in value: - parsed_value = value.split("'") - if len(parsed_value) > 2 and parsed_value[1] != "": - prefix = parsed_value[0] - value = _get_masked_string(parsed_value[1]) - suffix = parsed_value[2] - return f"{prefix}'{value}'{suffix}" - else: - match = re.match(r"^(\s*)(.*?)(\n?)$", value) - if match: - parts = list(match.groups()) - prefix = parts[0] - value = _get_masked_string(parts[1]) - suffix = parts[2] - return f"{prefix}'{value}'{suffix}" + line_lower = line.lower() + has_keyword = any(kw in line_lower for kw in QUICK_KEYWORDS) + + if not has_keyword: + return line -def mask(module, path: str) -> bool: + # Pattern 1: 'password': 'value' + # Groups: (1=prefix, 2=", 3=key, 4=", 5=space-before, 6=sep, 7=space-after, 8=", 9=value, 10=") + line = LOG_PATTERNS["python_dict_quoted"].sub( + lambda m: f"{m.group(1)}{m.group(2)}{m.group(3)}{m.group(4)}{m.group(5)}{m.group(6)}{m.group(7)}{m.group(8)}{_get_masked_string(m.group(9))}{m.group(10)}", + line, + ) + + # Pattern 2: 'password': 123456789 + # Groups: (1=prefix, 2=", 3=key, 4=", 5=space-before, 6=sep, 7=space-after, 8=value) + line = LOG_PATTERNS["python_dict_numeric"].sub( + lambda m: f"{m.group(1)}{m.group(2)}{m.group(3)}{m.group(4)}{m.group(5)}{m.group(6)}{m.group(7)}{_get_masked_string(m.group(8))}", + line, + ) + + # Pattern 3: password: value OR password = value + # Groups: (1=prefix, 2=key, 3=space-before, 4=sep, 5=space-after, + # 6=open-quote(optional), 7=value, 8=close-quote(optional)) + line = LOG_PATTERNS["plain_key_value"].sub( + lambda m: f"{m.group(1)}{m.group(2)}{m.group(3)}{m.group(4)}{m.group(5)}{m.group(6)}{_get_masked_string(m.group(7))}{m.group(8)}", + line, + ) + # SHA256 tokens + # sha256~abc123... -> sha256~********** + line = LOG_PATTERNS["sha256_token"].sub(f"sha256~{MASK_STR}", line) + + # Bearer tokens + # Bearer abc123... -> Bearer ********** + line = LOG_PATTERNS["bearer"].sub(f"Bearer {MASK_STR}", line) + + # Connection_string tokens + # mysql://user:pas123@localhost:3306/db -> mysql://*****:*******@:3306/db" + line = LOG_PATTERNS["connection_string"].sub(f"://{MASK_STR}:{MASK_STR}@", line) + + return line + + +def should_skip_ansible_line(line: str) -> bool: """ - Function responsible to begin masking on a provided - log file. It checks for file type, and calls - respective masking methods for that file. + Identifies if the line is in an Ansible header for Tasks or Plays. + + Returns True for lines that should not be masked. """ - changed = False - if ( - path.endswith((tuple(["yaml", "yml"]))) - or os.path.basename(path).split(".")[0] in ALLOWED_YAML_FILES - ): - extension = "yaml" - changed = mask_file(module, path, extension) - return changed + line_upper = line.upper() + return any(pattern.upper() in line_upper for pattern in ANSIBLE_SKIP_PATTERNS) -def mask_yaml(infile, outfile, changed) -> bool: +def mask_log_file_lines(infile, outfile, changed) -> bool: """ - Read the file, search for colon (':'), take value and - mask sensitive data + Mask log file lines with skip logic. + """ for line in infile: - # Skip lines without colon - if ":" not in line: + # Skip Ansible task headers + if should_skip_ansible_line(line): outfile.write(line) continue - key, sep, value = line.partition(":") - masked_value = value - for word in PROTECT_KEYS: - if key.strip() == word: - masked = partial_mask(value) - if not masked: - continue - masked_value = masked_value.replace(value, masked) - changed = True - - outfile.write(f"{key}{sep}{masked_value}") - return changed - + masked_line = mask_log_line(line) + if masked_line != line: + changed = True + outfile.write(masked_line) -def replace_file(temp_path, file_path, changed): - if changed: - temp_path.replace(file_path) - else: - temp_path.unlink(missing_ok=True) + return changed -def mask_file(module, path, extension) -> bool: +def mask_file(path) -> bool: """ Create temporary file, replace sensitive string with masked, then replace the tmp file with original. + Unlink temp file when failure. """ changed = False @@ -293,12 +477,23 @@ def mask_file(module, path, extension) -> bool: try: with file_path.open("r", encoding="utf-8") as infile: with temp_path.open("w", encoding="utf-8") as outfile: - if extension == "yaml": - changed = mask_yaml(infile, outfile, changed) - replace_file(temp_path, file_path, changed) - return changed + changed = mask_log_file_lines(infile, outfile, changed) + replace_file(temp_path, file_path, changed) + return changed + except FileNotFoundError: + print(f"Warning: File not found (possibly broken symlink): {file_path}") + return False except Exception as e: print(f"An unexpected error occurred on masking file {file_path}: {e}") + temp_path.unlink(missing_ok=True) + return False + + +def replace_file(temp_path, file_path, changed): + if changed: + temp_path.replace(file_path) + else: + temp_path.unlink(missing_ok=True) def run_module(): @@ -344,7 +539,10 @@ def run_module(): changed = crawl(module, path) if not isdir and not re.search(excluded_file_ext_regex, path): - changed = mask(module, path) + try: + changed = mask_file(path) + except Exception as e: + module.fail_json(e) result.update(changed=changed) # in the event of a successful module execution, you will want to diff --git a/plugins/modules/generate_make_tasks.py b/plugins/modules/generate_make_tasks.py index ff72a9026..3d538ecb3 100644 --- a/plugins/modules/generate_make_tasks.py +++ b/plugins/modules/generate_make_tasks.py @@ -41,7 +41,7 @@ mode: "0644" - name: Generate make tasks - generate_make_tasks: + cifmw.general.generate_make_tasks: install_yamls_path: "{{ cifmw_installyamls_repos }}" output_directory: "{{ ansible_user_dir }}/make_installyamls/tasks" """ # noqa diff --git a/plugins/modules/get_makefiles_env.py b/plugins/modules/get_makefiles_env.py index 4716f40c4..880a0dda0 100644 --- a/plugins/modules/get_makefiles_env.py +++ b/plugins/modules/get_makefiles_env.py @@ -33,7 +33,7 @@ # Recursively get all the variables of the Makefiles under /home/user - name: Generate env var fact register: get_makefiles_env_out - get_makefiles_env: + cifmw.general.get_makefiles_env: base_path: /home/user """ diff --git a/plugins/modules/krb_request.py b/plugins/modules/krb_request.py index 0cb8ce188..2ece429a8 100644 --- a/plugins/modules/krb_request.py +++ b/plugins/modules/krb_request.py @@ -54,7 +54,7 @@ EXAMPLES = r""" - name: Get some content - krb_request: + cifmw.general.krb_request: url: "http://someurl.local/resource" dest: "{{ ansible_user_dir }}/content.raw" mode: "0644" diff --git a/plugins/modules/pem_read.py b/plugins/modules/pem_read.py index 5f8985689..fbbb07545 100644 --- a/plugins/modules/pem_read.py +++ b/plugins/modules/pem_read.py @@ -41,12 +41,12 @@ EXAMPLES = r""" - name: Get pem certs from crt file - pem_read: + cifmw.general.pem_read: path: "/etc/ssl/certs/ca-certificates.crt" register: _certs - name: Get pem certs from crt file by OU - pem_read: + cifmw.general.pem_read: path: "/etc/ssl/certs/ca-certificates.crt" ou_filter: "Red Hat" register: _certs2 diff --git a/plugins/modules/tempest_list_allowed.py b/plugins/modules/tempest_list_allowed.py index c8c704f04..32a67ea0e 100644 --- a/plugins/modules/tempest_list_allowed.py +++ b/plugins/modules/tempest_list_allowed.py @@ -47,7 +47,7 @@ EXAMPLES = r""" - name: Get list of allowed tests - tempest_list_allowed: + cifmw.general.tempest_list_allowed: yaml_file: /tmp/allowed.yaml job: tripleo-ci-centos-8-standalone groups: diff --git a/plugins/modules/tempest_list_skipped.py b/plugins/modules/tempest_list_skipped.py index 5fbaf104d..cb7c3b978 100644 --- a/plugins/modules/tempest_list_skipped.py +++ b/plugins/modules/tempest_list_skipped.py @@ -45,7 +45,7 @@ EXAMPLES = r""" - name: Get list of skipped tests - tempest_list_skipped: + cifmw.general.tempest_list_skipped: yaml_file: /tmp/skipped.yaml job: edpm release: master diff --git a/post-deployment.yml b/post-deployment.yml index b0e66a41c..746d3eaa7 100644 --- a/post-deployment.yml +++ b/post-deployment.yml @@ -9,6 +9,40 @@ tags: - admin-setup + # FDP Update - OpenStack package updates across all layers + - name: FDP Update - Validate required variables + when: cifmw_fdp_update_enabled | default(false) | bool + tags: + - fdp-update + block: + - name: Validate required variables are set + ansible.builtin.assert: + that: + - cifmw_fdp_update_target_package is defined + - cifmw_fdp_update_target_package | length > 0 + - cifmw_fdp_update_repo_baseurl is defined + - cifmw_fdp_update_repo_baseurl | length > 0 + fail_msg: | + Required variables are missing! + + You must set: + - cifmw_fdp_update_target_package: Name of the RPM package to update + - cifmw_fdp_update_repo_baseurl: Repository base URL containing the updated package + success_msg: "Required variables validated successfully" + + - name: Update control plane container images + ansible.builtin.import_role: + name: fdp_update_container_images + vars: + cifmw_fdp_update_container_images_target_package: "{{ cifmw_fdp_update_target_package }}" + cifmw_fdp_update_container_images_repo_baseurl: "{{ cifmw_fdp_update_repo_baseurl }}" + + - name: Update EDPM (containers and host packages) + ansible.builtin.import_role: + name: fdp_update_edpm + vars: + cifmw_fdp_update_edpm_repo_baseurl: "{{ cifmw_fdp_update_repo_baseurl }}" + - name: Run Test ansible.builtin.import_role: name: cifmw_setup diff --git a/reproducer-clean.yml b/reproducer-clean.yml index 68ba76654..d8487477c 100644 --- a/reproducer-clean.yml +++ b/reproducer-clean.yml @@ -72,7 +72,7 @@ - deepscrub delegate_to: localhost ansible.builtin.file: - path: "{{ lookup('env', 'HOME') }}/ci-framework-data/ci-reproducer" + path: "{{ ansible_user_dir }}/ci-framework-data/ci-reproducer" state: absent - name: Remove basedir diff --git a/roles/adoption_osp_deploy/OWNERS b/roles/adoption_osp_deploy/OWNERS new file mode 100644 index 000000000..91d325c37 --- /dev/null +++ b/roles/adoption_osp_deploy/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - adoption-team + +reviewers: + - adoption-team diff --git a/roles/adoption_osp_deploy/molecule/default/converge.yml b/roles/adoption_osp_deploy/molecule/default/converge.yml index 7e33851b4..9e88ebe7d 100644 --- a/roles/adoption_osp_deploy/molecule/default/converge.yml +++ b/roles/adoption_osp_deploy/molecule/default/converge.yml @@ -12,7 +12,6 @@ cifmw_adoption_osp_deploy_repos: [] cifmw_adoption_source_scenario_path: "." cifmw_basedir: "{{ playbook_dir }}" - ansible_user_dir: "{{ lookup('env', 'HOME') }}" tasks: - name: Gather stack nodes and facts diff --git a/roles/artifacts/tasks/main.yml b/roles/artifacts/tasks/main.yml index 36e10f79a..682058fcf 100644 --- a/roles/artifacts/tasks/main.yml +++ b/roles/artifacts/tasks/main.yml @@ -92,6 +92,7 @@ - name: Mask secrets in yaml log files when: cifmw_artifacts_mask_logs |bool + become: true ignore_errors: true # noqa: ignore-errors timeout: 3600 cifmw.general.crawl_n_mask: diff --git a/roles/build_containers/molecule/default/prepare.yml b/roles/build_containers/molecule/default/prepare.yml index 2a369e1e8..4b9207043 100644 --- a/roles/build_containers/molecule/default/prepare.yml +++ b/roles/build_containers/molecule/default/prepare.yml @@ -18,7 +18,6 @@ - name: Prepare hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_basedir: "{{ ansible_user_dir }}/ci-framework-data/" roles: - role: test_deps diff --git a/roles/build_containers/molecule/hotfix/prepare.yml b/roles/build_containers/molecule/hotfix/prepare.yml index 2a369e1e8..4b9207043 100644 --- a/roles/build_containers/molecule/hotfix/prepare.yml +++ b/roles/build_containers/molecule/hotfix/prepare.yml @@ -18,7 +18,6 @@ - name: Prepare hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_basedir: "{{ ansible_user_dir }}/ci-framework-data/" roles: - role: test_deps diff --git a/roles/build_openstack_packages/molecule/default/converge.yml b/roles/build_openstack_packages/molecule/default/converge.yml index 31c1356e1..dddda28a1 100644 --- a/roles/build_openstack_packages/molecule/default/converge.yml +++ b/roles/build_openstack_packages/molecule/default/converge.yml @@ -18,7 +18,6 @@ - name: Converge hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_basedir: "{{ cifmw_project_dir_absolute }}" cifmw_bop_openstack_release: master cifmw_bop_dlrn_baseurl: https://trunk.rdoproject.org/centos9-master diff --git a/roles/build_openstack_packages/molecule/default/prepare.yml b/roles/build_openstack_packages/molecule/default/prepare.yml index ba0e8f86f..9f1ea0b62 100644 --- a/roles/build_openstack_packages/molecule/default/prepare.yml +++ b/roles/build_openstack_packages/molecule/default/prepare.yml @@ -18,7 +18,6 @@ - name: Prepare hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_basedir: "{{ cifmw_project_dir_absolute }}" roles: - role: test_deps diff --git a/roles/build_push_container/README.md b/roles/build_push_container/README.md deleted file mode 100644 index 5792dce44..000000000 --- a/roles/build_push_container/README.md +++ /dev/null @@ -1,143 +0,0 @@ -# build_push_container - -`build_push_container` aims to be a generic role that can build multi-arch containers and push them to remote registry. - -## Privilege escalation - -- Installing packages -- Installing qemu-user-static - -### Tagging - -A single image or manifest can have multiple tags moving independently. By default each push can have a tag, each PR and branch can have a latest tag. -Care should be taken with the latest tag, when running in a Zuul job, the latest tag should only be moved by a [Supercedent Pipeline](https://zuul-ci.org/docs/zuul/latest/config/pipeline.html#value-pipeline.manager.supercedent) which runs after check and gate jobs have passed. - -### Multi-arch Builds - -Multi-arch builds are made possible by using QEMU emulation via `qemu-user-static`. -When the non native arch is build a `binfmt_misc` rule is triggered instructing the process to be emulated transparently. - -The `binfmt_misc` rules live in `/proc/sys/fs/binfmt_misc/` and can be queried like so: - -```shell -cat /proc/sys/fs/binfmt_misc/qemu-arm64 -enabled -interpreter /usr/bin/qemu-arm64-static -flags: F -offset 0 -magic 7f454c460201010000000000000000000200b700 -mask ffffffffffffff00fffffffffffffffffeffffff -``` - -When a multi-arch build is requested, a manifest is first created to hold the container images. This manifest is allows clients to call the same image reference and get a different base architecture image. - -For example: - -```shell -# On ARM based MacBook -$ podman run -t --rm quay.rdoproject.org/openstack-k8s-operators/cifmw-client:latest uname -m -aarch64 - -# On X86 based server -$ podman run -t --rm quay.rdoproject.org/openstack-k8s-operators/cifmw-client:latest uname -m -x86_64 -``` - -## Testing - -Molecule tests are ran to build single and multi-arch images, these are pushed to a local registry deployed via our `registry_deploy` role. - -## Parameters - -*`cifmw_build_push_container_basedir`: (String) Base directory. Defaults to `cifmw_basedir` which defaults to `~/ci-framework`. -*`cifmw_build_push_container_artifacts`: (String) Role artifacts directory. Defaults to `{{ cifmw_build_push_container_basedir }}/artifacts/build_push_container` -*`cifmw_build_push_container_name`: (String) Name of container to be build and/or pushed, this is mandatory. Defaults to `Null` -*`cifmw_build_push_container_build_context_path`: (String) Directory that will be used for the container build context. Defaults to Zuul project src_dir. -*`cifmw_build_push_container_containerfile_name`: (String) Filename of Containerfile. Defaults to `Containerfile` -*`cifmw_build_push_container_containerfile_path`: (String) Path to Containerfile. Defaults to {{ zuul.project.src_dir }}/Containerfile -*`cifmw_build_push_container_local_build_tag`: (String) Local tag used when building container. Defaults to `"{{ (cifmw_build_push_container_name,'latest') | join(':') }}"` -*`cifmw_build_push_container_supported_platform`: (List) List of architectures to build, supported architectures can be found [here](https://github.com/multiarch/qemu-user-static) Defaults to `[linux/amd64]` -*`cifmw_build_push_container_qemu_user_static_image`: (String) Container to pull when QEMU is required. Defaults to `quay.rdoproject.org/ci-framework/qemu-user-static:latest` -*`cifmw_build_push_container_git_sha`: (String) Git SHA that can be provided to tag container image on registry. Defaults to `"{{ zuul.commit_id }}"` -*`cifmw_build_push_container_patch_number`: (Int) Patch number that can be provided to tag container image on registry. Defaults to `"{{ zuul.change }}"` -*`cifmw_build_push_container_tag_override`: (List) Variable to add additional tags for container on registry. Defaults to `[]` -*`cifmw_build_push_container_push`: (Boolean) Enables pushing to remote registry. Defaults to `false` -*`cifmw_build_push_container_registry_name`: (String) Name of remote registry like `//`. Defaults to `Null` -*`cifmw_build_push_container_registry_username`: (String) Username to authenticate to registry. Defaults to `Null` -*`cifmw_build_push_container_registry_password`: (String) Password to authenticate to registry. Defaults to `Null` -*`cifmw_build_push_container_registry_tls_verify`: (Boolean) Defaults to `true` - -## Examples - -Build container locally: - -```yaml ---- -- name: Build container - hosts: localhost - tasks: - - name: Call build_push_container role - vars: - cifmw_build_push_container_name: test_container - cifmw_build_push_container_build_context_path: /home/user/cool_project - cifmw_build_push_container_tag_override: [super, cool, tags] - ansible.builtin.include_role - name: build_push_container -``` - -Build container locally and push to remote registry with multi-arch build: - -```yaml ---- -- name: Build container - hosts: localhost - tasks: - - name: Call build_push_container role - vars: - cifmw_build_push_container_name: Test container - cifmw_build_push_container_build_context_path: /home/user/cool_project - cifmw_build_push_container_tag_override: [super, cool, tags] - cifmw_build_push_container_supported_platform: [linux/amd64, linux/arm64] - cifmw_build_push_container_push: true - cifmw_build_push_container_registry_name: quay.rdoproject.org/cool_project/test_container - cifmw_build_push_container_registry_username: username - cifmw_build_push_container_registry_password: Passw0rd - ansible.builtin.include_role - name: build_push_container -``` - -Building a container from a Zuul job: - -```yaml -- job: - name: build-push-container-cifmw-client - description: | - Build and push cifmw-client container to - quay.rdoproject.com registry. - vars: - cifmw_build_push_container_push - Used by build_push_container role to trigger pushing to registry. - cifmw_build_push_container_name - Name of container being build and pushed. - cifmw_build_push_container_containerfile_path - Path to containerfile. - cifmw_build_push_container_registry_name - Registry built containers will be pushed too. - Runtime: ~30mins. - parent: build-push-container-build - vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" - cifmw_ci_framework_src: >- - {{ - (ansible_user_dir, - zuul.project.src_dir) | ansible.builtin.path_join - }} - cifmw_build_push_container_push: true - cifmw_build_push_container_name: cifmw-client - cifmw_build_push_container_containerfile_path: >- - {{ - (cifmw_ci_framework_src, - 'containerfiles', - 'Containerfile.client') | ansible.builtin.path_join - }} - cifmw_build_push_container_registry_name: >- - quay.rdoproject.org/openstack-k8s-operators/cifmw-client - cifmw_build_push_container_supported_platform: [linux/arm64, linux/amd64] - timeout: 5400 -``` diff --git a/roles/build_push_container/defaults/main.yml b/roles/build_push_container/defaults/main.yml deleted file mode 100644 index a29b96f6e..000000000 --- a/roles/build_push_container/defaults/main.yml +++ /dev/null @@ -1,48 +0,0 @@ ---- -# Copyright Red Hat, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -# All variables intended for modification should be placed in this file. -# All variables within this role should have a prefix of "cifmw_build_push_container" - -# Meta vars -cifmw_build_push_container_basedir: "{{ cifmw_basedir | default(ansible_user_dir ~ '/ci-framework-data') }}" -cifmw_build_push_container_artifacts: "{{ (cifmw_build_push_container_basedir, 'artifacts', 'build_push_container')| ansible.builtin.path_join }}" - -# Build vars -cifmw_build_push_container_name: -cifmw_build_push_container_build_context_path: "{{ (ansible_user_dir, zuul.project.src_dir) | ansible.builtin.path_join }}" -cifmw_build_push_container_containerfile_name: Containerfile -cifmw_build_push_container_containerfile_path: >- - {{ - (ansible_user_dir, - zuul.project.src_dir, - cifmw_build_push_container_containerfile_name - ) | ansible.builtin.path_join - }} -cifmw_build_push_container_local_build_tag: "{{ (cifmw_build_push_container_name,'latest') | join(':') }}" -cifmw_build_push_container_supported_platform: [linux/amd64] -cifmw_build_push_container_qemu_user_static_image: quay.rdoproject.org/ci-framework/qemu-user-static:latest - -# Tagging vars -cifmw_build_push_container_git_sha: "{{ zuul.commit_id }}" -cifmw_build_push_container_patch_number: "{{ zuul.change }}" -cifmw_build_push_container_tag_override: [] -# Push vars -cifmw_build_push_container_push: false -cifmw_build_push_container_registry_name: -cifmw_build_push_container_registry_username: -cifmw_build_push_container_registry_password: -cifmw_build_push_container_registry_tls_verify: true diff --git a/roles/build_push_container/molecule/default/converge.yml b/roles/build_push_container/molecule/default/converge.yml deleted file mode 100644 index 720ea1057..000000000 --- a/roles/build_push_container/molecule/default/converge.yml +++ /dev/null @@ -1,104 +0,0 @@ ---- -# Copyright Red Hat, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -- name: Converge - hosts: all - tasks: - - name: Deploy Local Registry - ansible.builtin.include_role: - name: registry_deploy - - - name: Call and test cifmw_build_push_container with multi-arch scenario - block: - - name: Run cifmw_build_push_container multi-arch - vars: - cifmw_build_push_container_push: true - cifmw_build_push_container_build_context_path: ./ - cifmw_build_push_container_git_sha: c4ee373c848aa16d1f0767117f61426f17f2a9f3 - cifmw_build_push_container_patch_number: 123 - cifmw_build_push_container_name: test_container_multi_arch - cifmw_build_push_container_containerfile_path: >- - "{{ cifmw_project_dir_absolute }}/roles/build_push_container/molecule/default/files/containerfile" - cifmw_build_push_container_registry_name: 127.0.0.1:5001/cifmw-client/test_container_multi_arch - cifmw_build_push_container_registry_tls_verify: false - cifmw_build_push_container_supported_platform: [linux/amd64, linux/arm64] - ansible.builtin.include_role: - name: build_push_container - - - name: Request tags from local registry - ansible.builtin.uri: - headers: - Accept: application/vnd.oci.image.index.v1+json - url: http://localhost:5001/v2/cifmw-client/test_container_multi_arch/tags/list - register: _registry_tag_output - - - name: Check all tags exist - ansible.builtin.assert: - that: item is in _registry_tag_output.json.tags - loop: - - c4ee373c848aa16d1f0767117f61426f17f2a9f3 - - 123-latest - - - name: Request manifest from local registry - ansible.builtin.uri: - headers: - Accept: application/vnd.oci.image.index.v1+json - url: http://localhost:5001/v2/cifmw-client/test_container_multi_arch/manifests/123-latest - register: _registry_manifests_output - - - name: Check manifest for multi-arch image - vars: - architectures: "{{ _registry_manifests_output.json.manifests | json_query('[].platform.architecture') }}" - ansible.builtin.assert: - that: - - "'arm64' in architectures" - - "'amd64' in architectures" - - - name: Call and test cifmw_build_push_container with single-arch scenario - block: - - name: Run cifmw_build_push_container single-arch - vars: - cifmw_build_push_container_push: true - cifmw_build_push_container_build_context_path: ./ - cifmw_build_push_container_git_sha: c4ee373c848aa16d1f0767117f61426f17f2a9f3 - cifmw_build_push_container_patch_number: 123 - cifmw_build_push_container_name: test_container_single_arch - cifmw_build_push_container_containerfile_path: >- - "{{ cifmw_project_dir_absolute }}/roles/build_push_container/molecule/default/files/containerfile" - cifmw_build_push_container_registry_name: 127.0.0.1:5001/cifmw-client/test_container_single_arch - cifmw_build_push_container_registry_tls_verify: false - ansible.builtin.include_role: - name: build_push_container - - - name: Request tags from local registry - ansible.builtin.uri: - headers: - Accept: application/vnd.oci.image.index.v1+json - url: http://localhost:5001/v2/cifmw-client/test_container_single_arch/tags/list - register: _registry_tag_output - - - name: Check all tags exist - ansible.builtin.assert: - that: item is in _registry_tag_output.json.tags - loop: - - c4ee373c848aa16d1f0767117f61426f17f2a9f3 - - 123-latest - - - name: Call cleanup - ansible.builtin.include_role: - name: build_push_container - tasks_from: cleanup.yml diff --git a/roles/build_push_container/molecule/default/files/containerfile b/roles/build_push_container/molecule/default/files/containerfile deleted file mode 100644 index d43c03197..000000000 --- a/roles/build_push_container/molecule/default/files/containerfile +++ /dev/null @@ -1,2 +0,0 @@ -FROM quay.io/centos/centos:stream9-minimal -RUN echo test > test.txt diff --git a/roles/build_push_container/tasks/main.yml b/roles/build_push_container/tasks/main.yml deleted file mode 100644 index de9a04c30..000000000 --- a/roles/build_push_container/tasks/main.yml +++ /dev/null @@ -1,164 +0,0 @@ ---- -# Copyright Red Hat, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -- name: Ensure directories are present - ansible.builtin.file: - path: "{{ item }}" - state: directory - mode: "0755" - recurse: true - loop: - - "{{ (cifmw_build_push_container_artifacts, 'scripts') | ansible.builtin.path_join }}" - - "{{ (cifmw_build_push_container_artifacts, 'logs') | ansible.builtin.path_join }}" - -- name: Install podman and configure session linger - ansible.builtin.import_role: - name: podman - -# Note(Lewis): Using Podman command over podman module: -# Can't do multi-arch builds. -# Module output is lacking. -# Very slow when pushing multiple tags -- name: Render varibles and optionally print - vars: - _rendered_tags: >- - {% set out = [] -%} - {% if cifmw_build_push_container_git_sha is defined -%} - {% set _ = out.append(cifmw_build_push_container_git_sha) -%} - {% endif -%} - {% if cifmw_build_push_container_patch_number is defined -%} - {% set _ = out.append(cifmw_build_push_container_patch_number ~ '-latest') -%} - {% endif -%} - {{ out }} - _rendered_tags_with_overrides: > - {{ - _rendered_tags + - ( - cifmw_build_push_container_tag_override - if cifmw_build_push_container_tag_override - is not none else [] - ) - }} - _multi_arch_build: "{{ cifmw_build_push_container_supported_platform | length > 1 }}" - _container_manifest_name: "{{ 'localhost/' ~ cifmw_build_push_container_name ~ '-manifest' }}" - _podman_qemu_user_static_cmd: >- - sudo podman run - --rm - --privileged - {{ cifmw_build_push_container_qemu_user_static_image }} - --reset - -c yes - -p yes - _podman_build_cmd: >- - podman build - --security-opt="label=disable" - --platform={{ cifmw_build_push_container_supported_platform | join(',') }} - {% if _multi_arch_build -%} - --manifest={{ _container_manifest_name }} - {% endif -%} - --tag={{ cifmw_build_push_container_local_build_tag }} - --label="build_push_role=true" - --file={{ cifmw_build_push_container_containerfile_path }} - {{ cifmw_build_push_container_build_context_path }} - _podman_push_container_cmd: >- - podman push - {% if cifmw_build_push_container_registry_username is not none -%} - {% if cifmw_build_push_container_registry_password is not none -%} - --creds {{ cifmw_build_push_container_registry_username }}:{{ cifmw_build_push_container_registry_password }} - {% endif -%} - {% endif -%} - {% if not cifmw_build_push_container_registry_tls_verify -%} - --tls-verify=false - {% endif -%} - {{ cifmw_build_push_container_local_build_tag }} - {{ cifmw_build_push_container_registry_name }} - _podman_push_manifest_cmd: >- - podman manifest push - {% if cifmw_build_push_container_registry_username is not none -%} - {% if cifmw_build_push_container_registry_password is not none -%} - --creds {{ cifmw_build_push_container_registry_username }}:{{ cifmw_build_push_container_registry_password }} - {% endif -%} - {% endif -%} - {% if not cifmw_build_push_container_registry_tls_verify -%} - --tls-verify=false - {% endif -%} - {{ _container_manifest_name }} - {{ cifmw_build_push_container_registry_name }} - block: - - name: Create manifest if multi-arch requested - when: _multi_arch_build - block: - - name: Install qemu-user-static for multi arch builds - cifmw.general.ci_script: - output_dir: "{{ (cifmw_build_push_container_artifacts, 'scripts') | ansible.builtin.path_join }}" - script: "{{ _podman_qemu_user_static_cmd }}" - - - name: Ensure manifest doesn't exist - ansible.builtin.command: - cmd: podman manifest rm {{ _container_manifest_name }} - register: _podman_manifest_create_output - changed_when: _podman_manifest_create_output.rc == 0 - failed_when: - - (_podman_manifest_create_output.rc != 0 and 'image not known' not in _podman_manifest_create_output.stderr) - - - name: Create manifest - ansible.builtin.command: - cmd: podman manifest create {{ _container_manifest_name }} - register: _podman_manifest_create_output - changed_when: _podman_manifest_create_output.rc == 0 - - - name: Build container - block: - - name: Build container - cifmw.general.ci_script: - output_dir: "{{ (cifmw_build_push_container_artifacts, 'scripts') | ansible.builtin.path_join }}" - script: "{{ _podman_build_cmd }}" - - - name: Push manifest - when: - - cifmw_build_push_container_push - - _multi_arch_build - cifmw.general.ci_script: - output_dir: "{{ (cifmw_build_push_container_artifacts, 'scripts') | ansible.builtin.path_join }}" - script: "{{ (_podman_push_manifest_cmd, item) | join(':') }}" - loop: "{{ _rendered_tags_with_overrides }}" - - - name: Push container - when: - - cifmw_build_push_container_push - - not _multi_arch_build - cifmw.general.ci_script: - output_dir: "{{ (cifmw_build_push_container_artifacts, 'scripts') | ansible.builtin.path_join }}" - script: "{{ (_podman_push_container_cmd, item) | join(':') }}" - loop: "{{ _rendered_tags_with_overrides }}" - - rescue: - - name: Failure detected, output varibles - ansible.builtin.debug: - msg: - - "_rendered_tags: {{ _rendered_tags }}" - - "_rendered_tags_with_overrides: {{ _rendered_tags_with_overrides }}" - - "_container_manifest_name: {{ _container_manifest_name }}" - - "_multi_arch_build: {{ _multi_arch_build }}" - - "{{ _podman_build_cmd }}" - - "{{ _podman_push_container_cmd }}" - - "{{ _podman_push_manifest_cmd }}" - - "{{ _podman_qemu_user_static_cmd }}" - - - name: Re-trigger failure - ansible.builtin.fail: - msg: >- - Failure detected. Check the debug outputs above diff --git a/roles/cert_manager/defaults/main.yml b/roles/cert_manager/defaults/main.yml index ba473507e..e018fec6c 100644 --- a/roles/cert_manager/defaults/main.yml +++ b/roles/cert_manager/defaults/main.yml @@ -23,7 +23,7 @@ cifmw_cert_manager_manifests_dir: "{{ cifmw_manifests | default(cifmw_cert_manag cifmw_cert_manager_operator_namespace: cert-manager-operator cifmw_cert_manager_openshift_version: stable-v1 -cifmw_cert_manager_release_manifest: "https://github.com/cert-manager/cert-manager/releases/download/v1.14.4/cert-manager.yaml" +cifmw_cert_manager_release_manifest: "https://github.com/cert-manager/cert-manager/releases/download/v1.19.2/cert-manager.yaml" cifmw_cert_manager_install_from_release_manifest: true cifmw_cert_manager_olm_operator_group: diff --git a/roles/cert_manager/tasks/validate_certs.yml b/roles/cert_manager/tasks/validate_certs.yml index 49c3a754a..87786f6a7 100644 --- a/roles/cert_manager/tasks/validate_certs.yml +++ b/roles/cert_manager/tasks/validate_certs.yml @@ -16,7 +16,7 @@ - name: Create $HOME/bin dir ansible.builtin.file: - path: "{{ lookup('env', 'HOME') }}/bin" + path: "{{ ansible_user_dir }}/bin" state: directory mode: '0755' @@ -30,11 +30,11 @@ _arch: "{{ lookup('pipe', 'go env GOARCH') }}" ansible.builtin.get_url: url: "https://github.com/cert-manager/cmctl/releases/{{ cifmw_cert_manager_version }}/download/cmctl_{{ _os }}_{{ _arch }}" - dest: "{{ lookup('env', 'HOME') }}/bin/cmctl" + dest: "{{ ansible_user_dir }}/bin/cmctl" mode: "0755" - name: Verify cert_manager api environment: KUBECONFIG: "{{ cifmw_openshift_kubeconfig }}" PATH: "{{ cifmw_path }}" - ansible.builtin.command: "{{ lookup('env', 'HOME') }}/bin/cmctl check api --wait=2m" + ansible.builtin.command: "{{ ansible_user_dir }}/bin/cmctl check api --wait=2m" diff --git a/roles/ci_dcn_site/OWNERS b/roles/ci_dcn_site/OWNERS new file mode 100644 index 000000000..8366991fc --- /dev/null +++ b/roles/ci_dcn_site/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - dcn-team + +reviewers: + - dcn-team diff --git a/roles/ci_dcn_site/tasks/add_node.yml b/roles/ci_dcn_site/tasks/add_node.yml index 8442e4d8b..95ba6d29c 100644 --- a/roles/ci_dcn_site/tasks/add_node.yml +++ b/roles/ci_dcn_site/tasks/add_node.yml @@ -107,7 +107,7 @@ - name: Run Nova cell discovery for new DCN hosts kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: nova-cell0-conductor-0 command: nova-manage cell_v2 discover_hosts --verbose diff --git a/roles/ci_dcn_site/tasks/az.yml b/roles/ci_dcn_site/tasks/az.yml index 94a85b46e..0909f1dcc 100644 --- a/roles/ci_dcn_site/tasks/az.yml +++ b/roles/ci_dcn_site/tasks/az.yml @@ -19,7 +19,7 @@ ignore_errors: true kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: openstackclient command: >- openstack aggregate show {{ _az }} -c hosts -f value @@ -36,7 +36,7 @@ - az_hosts.rc == 1 kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: openstackclient command: >- openstack aggregate create {{ _az }} --zone {{ _az }} @@ -49,7 +49,7 @@ - item.key not in az_hosts_list kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: openstackclient command: >- openstack aggregate add host {{ _az }} {{ item.key }}.ctlplane.example.com diff --git a/roles/ci_dcn_site/tasks/deploy_site.yml b/roles/ci_dcn_site/tasks/deploy_site.yml index e4bcd93c0..bd23aa4ca 100644 --- a/roles/ci_dcn_site/tasks/deploy_site.yml +++ b/roles/ci_dcn_site/tasks/deploy_site.yml @@ -26,7 +26,7 @@ - name: Run Nova cell discovery for new DCN hosts kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: nova-cell0-conductor-0 command: nova-manage cell_v2 discover_hosts --verbose diff --git a/roles/ci_dcn_site/tasks/remove_node.yml b/roles/ci_dcn_site/tasks/remove_node.yml index 06ccb5778..0cc43f9e4 100644 --- a/roles/ci_dcn_site/tasks/remove_node.yml +++ b/roles/ci_dcn_site/tasks/remove_node.yml @@ -41,7 +41,7 @@ register: removed_compute kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: openstackclient command: >- sh -c "openstack compute service list -c Host -c Zone -f value | grep {{ _node_to_remove}} | awk '{print $1}'" @@ -54,7 +54,7 @@ register: compute_az kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: openstackclient command: >- sh -c "openstack compute service list -c Host -c Zone -f value | grep {{ _removed_compute }} | awk '{print $2}'" @@ -67,7 +67,7 @@ register: osp_instances kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: openstackclient command: >- openstack server list --availability-zone {{ _compute_az }} --host {{ _removed_compute }} --all-projects -f value -c ID @@ -75,7 +75,7 @@ - name: Clean the running instances from the node up kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: openstackclient command: >- openstack server delete --force {{ item }} @@ -84,7 +84,7 @@ - name: Delete the compute nodes from the aggregate kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: openstackclient command: >- openstack aggregate remove host {{ _compute_az }} {{ _removed_compute }} @@ -92,7 +92,7 @@ - name: Disable the compute service on scale-downed compute nodes kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: openstackclient command: >- openstack compute service set {{ _removed_compute }} nova-compute --disable @@ -117,7 +117,7 @@ register: cell_uuid kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: nova-cell0-conductor-0 command: >- sh -c "nova-manage cell_v2 list_hosts | grep {{ _removed_compute }} | awk '{print $4}'" @@ -125,7 +125,7 @@ - name: Remove the compute hosts from the cell kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: nova-cell0-conductor-0 command: >- nova-manage cell_v2 delete_host --cell_uuid {{ cell_uuid.stdout }} --host {{ _removed_compute }} @@ -162,7 +162,7 @@ - name: Delete the network agents on scale-downed compute nodes kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: openstackclient command: >- sh -c "openstack network agent list --host {{ _removed_compute }} -c ID -f value | xargs openstack network agent delete" @@ -173,7 +173,7 @@ api_version: dataplane.openstack.org/v1beta1 kind: OpenStackDataPlaneNodeSet name: "{{ az_to_group_map[_compute_az] }}-edpm" - namespace: "openstack" + namespace: "{{ cifmw_openstack_namespace }}" patch: - op: "remove" path: "/spec/nodes/edpm-{{ _node_to_remove }}" @@ -189,7 +189,7 @@ kubernetes.core.k8s: api_key: "{{ _auth_results.openshift_auth.api_key }}" state: present - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" src: "{{ ci_dcn_site_arch_path }}/dataplane_remove_node_deploy.yaml" - name: Wait for the node to be removed from the OpenStackDataPlaneNodeSet CR @@ -197,7 +197,7 @@ api_version: openstack.org/v1beta1 kind: OpenStackDataPlaneNodeSet name: "{{ az_to_group_map[_compute_az] }}-edpm" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" register: nodeset_status until: (_node_to_remove not in (nodeset_status.resources[0].spec.nodes | default({})).keys()) retries: 30 diff --git a/roles/ci_dcn_site/tasks/scaledown_site.yml b/roles/ci_dcn_site/tasks/scaledown_site.yml index 5665a058d..1ee17f8a5 100644 --- a/roles/ci_dcn_site/tasks/scaledown_site.yml +++ b/roles/ci_dcn_site/tasks/scaledown_site.yml @@ -19,7 +19,7 @@ ignore_errors: true kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: openstackclient command: >- openstack aggregate show {{ _az_to_scaledown }} -c hosts -f value @@ -28,7 +28,7 @@ register: az_compute_hosts kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: openstackclient command: >- sh -c "openstack compute service list -c Host -c Zone -f value | grep {{ _az_to_scaledown }} | awk '{print $1}'" @@ -46,7 +46,7 @@ register: osp_instances kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: openstackclient command: >- openstack server list --availability-zone {{ _az_to_scaledown }} --all-projects -f value -c ID @@ -54,7 +54,7 @@ - name: Clean the running instances from the AZ up before deleting the hosts kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: openstackclient command: >- openstack server delete --force {{ item }} @@ -64,7 +64,7 @@ loop: "{{ az_hosts_list }}" kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: openstackclient command: >- openstack aggregate remove host {{ _az_to_scaledown }} {{ item }} @@ -73,7 +73,7 @@ - name: Delete the host aggregate kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: openstackclient command: >- openstack aggregate delete {{ _az_to_scaledown }} @@ -83,7 +83,7 @@ loop: "{{ az_compute_hosts.stdout_lines }}" kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: openstackclient command: >- openstack compute service set {{ item }} nova-compute --disable @@ -125,7 +125,7 @@ register: cell_uuid kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: nova-cell0-conductor-0 command: >- sh -c "nova-manage cell_v2 list_hosts | grep {{ az_compute_hosts.stdout_lines[0] }} | awk '{print $4}'" @@ -133,7 +133,7 @@ - name: Remove the compute hosts from the cell kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: nova-cell0-conductor-0 command: >- nova-manage cell_v2 delete_host --cell_uuid {{ cell_uuid.stdout }} --host {{ item }} @@ -177,13 +177,13 @@ az1: cell2 az2: cell3 ansible.builtin.shell: | - oc delete -n openstack rabbitmqclusters rabbitmq-{{ az_to_cell_map[_az_to_scaledown] }} - oc delete -n openstack galera openstack-{{ az_to_cell_map[_az_to_scaledown] }} + oc delete -n {{ cifmw_openstack_namespace }} rabbitmqclusters rabbitmq-{{ az_to_cell_map[_az_to_scaledown] }} + oc delete -n {{ cifmw_openstack_namespace }} galera openstack-{{ az_to_cell_map[_az_to_scaledown] }} - name: Get list of pods in the openstack namespace kubernetes.core.k8s_info: kind: Pod - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" api_key: "{{ _auth_results.openshift_auth.api_key }}" register: pod_list @@ -197,7 +197,7 @@ - name: Delete the cinder-volume service kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: "{{ cinder_prefix }}-scheduler-0" command: >- cinder-manage service remove cinder-volume {{ cinder_prefix }}-volume-{{ _az_to_scaledown }}-0@ceph @@ -208,7 +208,7 @@ api_key: "{{ _auth_results.openshift_auth.api_key }}" kind: Secret name: ceph-conf-files - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" - name: Create temporary directory for ceph conf files ansible.builtin.file: @@ -230,7 +230,7 @@ api_key: "{{ _auth_results.openshift_auth.api_key }}" kind: Secret name: "{{ item }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" state: absent loop: - "ceph-conf-files-{{ _az_to_scaledown }}" @@ -292,7 +292,7 @@ - name: Delete the network agents on scale-downed compute nodes kubernetes.core.k8s_exec: api_key: "{{ _auth_results.openshift_auth.api_key }}" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" pod: openstackclient command: >- sh -c "openstack network agent list --host {{ item }} -c ID -f value | xargs openstack network agent delete" @@ -305,7 +305,7 @@ api_version: dataplane.openstack.org/v1beta1 kind: OpenStackDataPlaneNodeSet name: "{{ _group_name }}-edpm" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" - name: Delete OpenStackDataPlaneNodeSet kubernetes.core.k8s: @@ -314,11 +314,11 @@ state: absent kind: OpenStackDataPlaneNodeSet name: "{{ _group_name }}-edpm" - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" - name: Delete each Secret which contains TLS certificate for the NodeSet nodes ansible.builtin.command: - cmd: oc -n openstack delete Secret {{ item }} + cmd: oc -n {{ cifmw_openstack_namespace }} delete Secret {{ item }} loop: "{{ osdpns_info.resources[0].status.secretHashes.keys() | select('search', 'cert') | list }}" - name: Delete temporary files with ceph client variables and keys diff --git a/roles/ci_dcn_site/templates/ceph_secrets.yaml.j2 b/roles/ci_dcn_site/templates/ceph_secrets.yaml.j2 index d0bcfe501..46ca91e1f 100644 --- a/roles/ci_dcn_site/templates/ceph_secrets.yaml.j2 +++ b/roles/ci_dcn_site/templates/ceph_secrets.yaml.j2 @@ -2,7 +2,7 @@ kind: Secret metadata: name: ceph-conf-files-{{ _az }} - namespace: openstack + namespace: {{ cifmw_openstack_namespace }} type: Opaque apiVersion: v1 data: diff --git a/roles/ci_gen_kustomize_values/molecule/default/prepare.yml b/roles/ci_gen_kustomize_values/molecule/default/prepare.yml index b11327d26..f6dc328a3 100644 --- a/roles/ci_gen_kustomize_values/molecule/default/prepare.yml +++ b/roles/ci_gen_kustomize_values/molecule/default/prepare.yml @@ -20,7 +20,7 @@ vars: cifmw_ci_gen_kustomize_values_src_dir: >- {{ - (lookup('env', 'HOME'), + (ansible_user_dir, 'ci-framework-data', 'artifacts', 'ci_k8s_snippets') | path_join }} diff --git a/roles/ci_gen_kustomize_values/templates/bgp-l3-xl/OWNERS b/roles/ci_gen_kustomize_values/templates/bgp-l3-xl/OWNERS new file mode 100644 index 000000000..6839704e6 --- /dev/null +++ b/roles/ci_gen_kustomize_values/templates/bgp-l3-xl/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - bgp-team + +reviewers: + - bgp-team diff --git a/roles/ci_gen_kustomize_values/templates/bgp-l3-xl/network-values/values.yaml.j2 b/roles/ci_gen_kustomize_values/templates/bgp-l3-xl/network-values/values.yaml.j2 index 6c6cdc4ca..1c80b592c 100644 --- a/roles/ci_gen_kustomize_values/templates/bgp-l3-xl/network-values/values.yaml.j2 +++ b/roles/ci_gen_kustomize_values/templates/bgp-l3-xl/network-values/values.yaml.j2 @@ -20,7 +20,7 @@ data: }, recursive=true) %} {{ network.network_name }}_ip: {{ network.ip_v4 }} -{% if 'worker-9' == hostname and 'ctlplane' == network.network_name %} +{% if 'ctlplane' == network.network_name %} base_if: {{ network.interface_name }} {% endif %} {% endfor %} @@ -50,6 +50,7 @@ data: {% endfor %} {% for network in cifmw_networking_env_definition.networks.values() %} +{% if network.network_name != 'ctlplane_ocp_nad' %} {% set ns.lb_tools = {} %} {{ network.network_name }}: dnsDomain: {{ network.search_domain }} @@ -95,7 +96,8 @@ data: {% if ns.lb_tools | length > 0 %} lb_addresses: {% for tool in ns.lb_tools.keys() %} -{% for lb_range in network.tools[tool].ipv4_ranges %} +{% set lb_range_network = network if network.network_name != "ctlplane" else cifmw_networking_env_definition.networks.ctlplane_ocp_nad %} +{% for lb_range in lb_range_network.tools[tool].ipv4_ranges %} - {{ lb_range.start }}-{{ lb_range.end }} {% set _ = ns.lb_tools[tool].append(lb_range.start) %} {% endfor %} @@ -114,10 +116,10 @@ data: iface: {{ network.network_name }} base_iface: {{ ns.interfaces[network.network_name] }} {% endif %} -{% else %} -{% if ns.interfaces[network.network_name] is defined %} +{% elif network.network_name == "ctlplane" %} iface: {{ ns.interfaces[network.network_name] }} -{% endif %} +{% elif ns.interfaces[network.network_name] is defined %} + iface: {{ network.network_name }} {% endif %} {% if network.tools.multus is defined %} net-attach-def: | @@ -139,42 +141,36 @@ data: {% endif %} "ipam": { "type": "whereabouts", - "range": "{{ network.network_v4 }}", {% if network.network_name == "octavia" and network.tools.multus.ipv4_routes | default([]) | length > 0 %} "routes": [ -{% for route in network.tools.multus.ipv4_routes %} +{% for route in network.tools.multus.ipv4_routes %} { "dst": "{{ route.destination }}", "gw": "{{ route.gateway }}" }{% if not loop.last %},{% endif %} -{% endfor %} +{% endfor %} ], {% endif %} - "range_start": "{{ network.tools.multus.ipv4_ranges.0.start }}", - "range_end": "{{ network.tools.multus.ipv4_ranges.0.end }}", -{% if network.network_name == "ctlplane" %} - "gateway": "{{ network.network_v4 |ansible.utils.nthhost(2) }}" -{% else %} - "gateway": "{{ network.network_v4 |ansible.utils.nthhost(1) }}" -{% endif %} +{% set range_network = network if network.network_name != "ctlplane" else cifmw_networking_env_definition.networks.ctlplane_ocp_nad %} + "range": "{{ range_network.network_v4 }}", + "range_start": "{{ range_network.tools.multus.ipv4_ranges.0.start }}", + "range_end": "{{ range_network.tools.multus.ipv4_ranges.0.end }}", + "gateway": "{{ range_network.network_v4 |ansible.utils.nthhost(1) }}" } } {% endif %} +{% endif %} {% endfor %} dns-resolver: config: server: -# We set ctlplane = 192.168.125.0/24 and we rely on this definition to create the nad above. -# BGP exposes nad ips by advertising a 192.168.125.X address on the worker, and this would break dns -# because the traffic will not be sent to the right nic if a local ip on the same network is present. -# To avoid messing with routes etc we hardcode the 122.1 ip here - - 192.168.122.1 + - "{{ cifmw_networking_env_definition.networks.ctlplane.gw_v4 }}" search: [] options: - key: server values: - - 192.168.122.1 + - {{ cifmw_networking_env_definition.networks.ctlplane.gw_v4 }} {% for nameserver in cifmw_ci_gen_kustomize_values_nameservers %} - key: server values: diff --git a/roles/ci_gen_kustomize_values/templates/bgp_dt01/OWNERS b/roles/ci_gen_kustomize_values/templates/bgp_dt01/OWNERS new file mode 100644 index 000000000..6839704e6 --- /dev/null +++ b/roles/ci_gen_kustomize_values/templates/bgp_dt01/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - bgp-team + +reviewers: + - bgp-team diff --git a/roles/ci_gen_kustomize_values/templates/bgp_dt01/network-values/values.yaml.j2 b/roles/ci_gen_kustomize_values/templates/bgp_dt01/network-values/values.yaml.j2 index 78a491e5f..896f3a19e 100644 --- a/roles/ci_gen_kustomize_values/templates/bgp_dt01/network-values/values.yaml.j2 +++ b/roles/ci_gen_kustomize_values/templates/bgp_dt01/network-values/values.yaml.j2 @@ -20,7 +20,7 @@ data: }, recursive=true) %} {{ network.network_name }}_ip: {{ network.ip_v4 }} -{% if 'worker-3' == hostname and 'ctlplane' == network.network_name %} +{% if 'ctlplane' == network.network_name %} base_if: {{ network.interface_name }} {% endif %} {% endfor %} @@ -56,6 +56,7 @@ data: {% endfor %} {% for network in cifmw_networking_env_definition.networks.values() %} +{% if network.network_name != 'ctlplane_ocp_nad' %} {% set ns.lb_tools = {} %} {{ network.network_name }}: dnsDomain: {{ network.search_domain }} @@ -101,7 +102,8 @@ data: {% if ns.lb_tools | length > 0 %} lb_addresses: {% for tool in ns.lb_tools.keys() %} -{% for lb_range in network.tools[tool].ipv4_ranges %} +{% set lb_range_network = network if network.network_name != "ctlplane" else cifmw_networking_env_definition.networks.ctlplane_ocp_nad %} +{% for lb_range in lb_range_network.tools[tool].ipv4_ranges %} - {{ lb_range.start }}-{{ lb_range.end }} {% set _ = ns.lb_tools[tool].append(lb_range.start) %} {% endfor %} @@ -120,10 +122,10 @@ data: iface: {{ network.network_name }} base_iface: {{ ns.interfaces[network.network_name] }} {% endif %} -{% else %} -{% if ns.interfaces[network.network_name] is defined %} +{% elif network.network_name == "ctlplane" %} + iface: {{ ns.interfaces[network.network_name] }} +{% elif ns.interfaces[network.network_name] is defined %} iface: {{ network.network_name }} -{% endif %} {% endif %} {% if network.tools.multus is defined %} net-attach-def: | @@ -147,23 +149,25 @@ data: {% endif %} "ipam": { "type": "whereabouts", - "range": "{{ network.network_v4 }}", {% if network.network_name == "octavia" and network.tools.multus.ipv4_routes | default([]) | length > 0 %} "routes": [ -{% for route in network.tools.multus.ipv4_routes %} +{% for route in network.tools.multus.ipv4_routes %} { "dst": "{{ route.destination }}", "gw": "{{ route.gateway }}" }{% if not loop.last %},{% endif %} -{% endfor %} +{% endfor %} ], {% endif %} - "range_start": "{{ network.tools.multus.ipv4_ranges.0.start }}", - "range_end": "{{ network.tools.multus.ipv4_ranges.0.end }}", - "gateway": "{{ network.network_v4 |ansible.utils.nthhost(1) }}" +{% set range_network = network if network.network_name != "ctlplane" else cifmw_networking_env_definition.networks.ctlplane_ocp_nad %} + "range": "{{ range_network.network_v4 }}", + "range_start": "{{ range_network.tools.multus.ipv4_ranges.0.start }}", + "range_end": "{{ range_network.tools.multus.ipv4_ranges.0.end }}", + "gateway": "{{ range_network.network_v4 |ansible.utils.nthhost(1) }}" } } {% endif %} +{% endif %} {% endfor %} dns-resolver: diff --git a/roles/ci_gen_kustomize_values/templates/common/network-values/values.yaml.j2 b/roles/ci_gen_kustomize_values/templates/common/network-values/values.yaml.j2 index 9530d5444..1769515a9 100644 --- a/roles/ci_gen_kustomize_values/templates/common/network-values/values.yaml.j2 +++ b/roles/ci_gen_kustomize_values/templates/common/network-values/values.yaml.j2 @@ -19,6 +19,7 @@ data: node_{{ ns.ocp_index }}: {% set ns.ocp_index = ns.ocp_index+1 %} name: {{ cifmw_networking_env_definition.instances[host]['hostname'] }} + node_name: {{ cifmw_networking_env_definition.instances[host]['hostname'] }}.ocp.openstack.lab {% for network in cifmw_networking_env_definition.instances[host]['networks'].values() %} {% set ns.interfaces = ns.interfaces | combine({network.network_name: (network.parent_interface | diff --git a/roles/ci_gen_kustomize_values/templates/dcn/OWNERS b/roles/ci_gen_kustomize_values/templates/dcn/OWNERS new file mode 100644 index 000000000..8366991fc --- /dev/null +++ b/roles/ci_gen_kustomize_values/templates/dcn/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - dcn-team + +reviewers: + - dcn-team diff --git a/roles/ci_gen_kustomize_values/templates/nfv-ovs-dpdk-sriov-hci/OWNERS b/roles/ci_gen_kustomize_values/templates/nfv-ovs-dpdk-sriov-hci/OWNERS new file mode 100644 index 000000000..7a15ba5da --- /dev/null +++ b/roles/ci_gen_kustomize_values/templates/nfv-ovs-dpdk-sriov-hci/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - nfv-team + +reviewers: + - nfv-team diff --git a/roles/ci_gen_kustomize_values/templates/ovs-dpdk-sriov-2nodesets/OWNERS b/roles/ci_gen_kustomize_values/templates/ovs-dpdk-sriov-2nodesets/OWNERS new file mode 100644 index 000000000..7a15ba5da --- /dev/null +++ b/roles/ci_gen_kustomize_values/templates/ovs-dpdk-sriov-2nodesets/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - nfv-team + +reviewers: + - nfv-team diff --git a/roles/ci_gen_kustomize_values/templates/ovs-dpdk-sriov-ipv6-2nodesets/edpm-nodeset-values/values.yaml.j2 b/roles/ci_gen_kustomize_values/templates/ovs-dpdk-sriov-ipv6-2nodesets/edpm-nodeset-values/values.yaml.j2 new file mode 100644 index 000000000..62ec8dad0 --- /dev/null +++ b/roles/ci_gen_kustomize_values/templates/ovs-dpdk-sriov-ipv6-2nodesets/edpm-nodeset-values/values.yaml.j2 @@ -0,0 +1,58 @@ +--- +# source: ovs-dpdk-sriov-ipv6-2nodesets/edpm-nodeset-values/values.yaml.j2 +{% set instances_names = [] %} +{% set _original_nodeset = (original_content.data | default({})).nodeset | default({}) %} +{% set _original_nodes = _original_nodeset.nodes | default({}) %} +{% set _original_services = _original_nodeset['services'] | default([]) %} +{% if cifmw_baremetal_hosts | default([]) | length > 0 %} +{% for _inst in cifmw_baremetal_hosts.keys() %} +{% if (('label' in cifmw_baremetal_hosts[_inst]) and + (cifmw_baremetal_hosts[_inst]['label'] == 'openstack')) %} +{% set _ = instances_names.append(_inst) %} +{% endif %} +{% endfor %} +{% else %} +# Needed for verification gate +{% set _vm_type = (_original_nodes.keys() | first).split('-')[1] %} +{% for _inst in cifmw_networking_env_definition.instances.keys() %} +{% if _inst.startswith(_vm_type) %} +{% set _ = instances_names.append(_inst) %} +{% endif %} +{% endfor %} +{% endif %} +data: + ssh_keys: + authorized: {{ cifmw_ci_gen_kustomize_values_ssh_authorizedkeys | b64encode }} + private: {{ cifmw_ci_gen_kustomize_values_ssh_private_key | b64encode }} + public: {{ cifmw_ci_gen_kustomize_values_ssh_public_key | b64encode }} + nova: + migration: + ssh_keys: + private: {{ cifmw_ci_gen_kustomize_values_migration_priv_key | b64encode }} + public: {{ cifmw_ci_gen_kustomize_values_migration_pub_key | b64encode }} + nodeset: + ansible: + ansibleVars: + edpm_fips_mode: "{{ 'enabled' if cifmw_fips_enabled|default(false)|bool else 'check' }}" + timesync_ntp_servers: + - hostname: "{{ cifmw_ci_gen_kustomize_values_ntp_srv | default('pool.ntp.org') }}" +{% if cifmw_ci_gen_kustomize_values_sshd_ranges | default([]) | length > 0 %} + edpm_sshd_allowed_ranges: +{% for range in cifmw_ci_gen_kustomize_values_sshd_ranges %} + - "{{ range }}" +{% endfor %} +{% endif %} + nodes: +{% for instance in instances_names %} + edpm-{{ instance }}: + hostName: {{ instance }} +{% endfor %} + +{% if ('repo-setup' not in (_original_nodeset['services'] | default([]))) and + ('repo-setup' in ci_gen_kustomize_edpm_nodeset_predeployed_services) %} + services: + - "repo-setup" +{% for svc in _original_services %} + - "{{ svc }}" +{% endfor %} +{% endif %} diff --git a/roles/ci_gen_kustomize_values/templates/ovs-dpdk-sriov-ipv6-2nodesets/edpm-nodeset2-values/values.yaml.j2 b/roles/ci_gen_kustomize_values/templates/ovs-dpdk-sriov-ipv6-2nodesets/edpm-nodeset2-values/values.yaml.j2 new file mode 100644 index 000000000..80103686c --- /dev/null +++ b/roles/ci_gen_kustomize_values/templates/ovs-dpdk-sriov-ipv6-2nodesets/edpm-nodeset2-values/values.yaml.j2 @@ -0,0 +1,58 @@ +--- +# source: ovs-dpdk-sriov-ipv6-2nodesets/edpm-nodeset2-values/values.yaml.j2 +{% set instances_names = [] %} +{% set _original_nodeset = (original_content.data | default({})).nodeset | default({}) %} +{% set _original_nodes = _original_nodeset.nodes | default({}) %} +{% set _original_services = _original_nodeset['services'] | default([]) %} +{% if cifmw_baremetal_hosts | default([]) | length > 0 %} +{% for _inst in cifmw_baremetal_hosts.keys() %} +{% if (('label' in cifmw_baremetal_hosts[_inst]) and + (cifmw_baremetal_hosts[_inst]['label'] == 'openstack-2')) %} +{% set _ = instances_names.append(_inst) %} +{% endif %} +{% endfor %} +{% else %} +# Needed for verification gate +{% set _vm_type = (_original_nodes.keys() | first).split('-')[1] %} +{% for _inst in cifmw_networking_env_definition.instances.keys() %} +{% if _inst.startswith(_vm_type) %} +{% set _ = instances_names.append(_inst) %} +{% endif %} +{% endfor %} +{% endif %} +data: + ssh_keys: + authorized: {{ cifmw_ci_gen_kustomize_values_ssh_authorizedkeys | b64encode }} + private: {{ cifmw_ci_gen_kustomize_values_ssh_private_key | b64encode }} + public: {{ cifmw_ci_gen_kustomize_values_ssh_public_key | b64encode }} + nova: + migration: + ssh_keys: + private: {{ cifmw_ci_gen_kustomize_values_migration_priv_key | b64encode }} + public: {{ cifmw_ci_gen_kustomize_values_migration_pub_key | b64encode }} + nodeset: + ansible: + ansibleVars: + edpm_fips_mode: "{{ 'enabled' if cifmw_fips_enabled|default(false)|bool else 'check' }}" + timesync_ntp_servers: + - hostname: "{{ cifmw_ci_gen_kustomize_values_ntp_srv | default('pool.ntp.org') }}" +{% if cifmw_ci_gen_kustomize_values_sshd_ranges | default([]) | length > 0 %} + edpm_sshd_allowed_ranges: +{% for range in cifmw_ci_gen_kustomize_values_sshd_ranges %} + - "{{ range }}" +{% endfor %} +{% endif %} + nodes: +{% for instance in instances_names %} + edpm-{{ instance }}: + hostName: {{ instance }} +{% endfor %} + +{% if ('repo-setup' not in (_original_nodeset['services'] | default([]))) and + ('repo-setup' in ci_gen_kustomize_edpm_nodeset_predeployed_services) %} + services: + - "repo-setup" +{% for svc in _original_services %} + - "{{ svc }}" +{% endfor %} +{% endif %} diff --git a/roles/ci_gen_kustomize_values/templates/ovs-dpdk-sriov-ipv6/edpm-nodeset-values/values.yaml.j2 b/roles/ci_gen_kustomize_values/templates/ovs-dpdk-sriov-ipv6/edpm-nodeset-values/values.yaml.j2 new file mode 100644 index 000000000..cf1e9ce62 --- /dev/null +++ b/roles/ci_gen_kustomize_values/templates/ovs-dpdk-sriov-ipv6/edpm-nodeset-values/values.yaml.j2 @@ -0,0 +1,45 @@ +--- +# source: ovs-dpdk-sriov-ipv6/edpm-nodeset-values/values.yaml.j2 +{% set instances_names = [] %} +{% set _original_nodeset = (original_content.data | default({})).nodeset | default({}) %} +{% set _original_nodes = _original_nodeset.nodes | default({}) %} +{% set _original_services = _original_nodeset['services'] | default([]) %} +{% for _inst in cifmw_baremetal_hosts.keys() %} +{% set _ = instances_names.append(_inst) %} +{% endfor %} +data: + ssh_keys: + authorized: {{ cifmw_ci_gen_kustomize_values_ssh_authorizedkeys | b64encode }} + private: {{ cifmw_ci_gen_kustomize_values_ssh_private_key | b64encode }} + public: {{ cifmw_ci_gen_kustomize_values_ssh_public_key | b64encode }} + nova: + migration: + ssh_keys: + private: {{ cifmw_ci_gen_kustomize_values_migration_priv_key | b64encode }} + public: {{ cifmw_ci_gen_kustomize_values_migration_pub_key | b64encode }} + nodeset: + ansible: + ansibleVars: + edpm_fips_mode: "{{ 'enabled' if cifmw_fips_enabled|default(false)|bool else 'check' }}" + timesync_ntp_servers: + - hostname: "{{ cifmw_ci_gen_kustomize_values_ntp_srv | default('pool.ntp.org') }}" +{% if cifmw_ci_gen_kustomize_values_sshd_ranges | default([]) | length > 0 %} + edpm_sshd_allowed_ranges: +{% for range in cifmw_ci_gen_kustomize_values_sshd_ranges %} + - "{{ range }}" +{% endfor %} +{% endif %} + nodes: +{% for instance in instances_names %} + edpm-{{ instance }}: + hostName: {{ instance }} +{% endfor %} + +{% if ('repo-setup' not in (_original_nodeset['services'] | default([]))) and + ('repo-setup' in ci_gen_kustomize_edpm_nodeset_predeployed_services) %} + services: + - "repo-setup" +{% for svc in _original_services %} + - "{{ svc }}" +{% endfor %} +{% endif %} diff --git a/roles/ci_gen_kustomize_values/templates/ovs-dpdk-sriov/OWNERS b/roles/ci_gen_kustomize_values/templates/ovs-dpdk-sriov/OWNERS new file mode 100644 index 000000000..7a15ba5da --- /dev/null +++ b/roles/ci_gen_kustomize_values/templates/ovs-dpdk-sriov/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - nfv-team + +reviewers: + - nfv-team diff --git a/roles/ci_gen_kustomize_values/templates/ovs-dpdk/OWNERS b/roles/ci_gen_kustomize_values/templates/ovs-dpdk/OWNERS new file mode 100644 index 000000000..7a15ba5da --- /dev/null +++ b/roles/ci_gen_kustomize_values/templates/ovs-dpdk/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - nfv-team + +reviewers: + - nfv-team diff --git a/roles/ci_gen_kustomize_values/templates/shiftstack/OWNERS b/roles/ci_gen_kustomize_values/templates/shiftstack/OWNERS new file mode 100644 index 000000000..a081fc3e4 --- /dev/null +++ b/roles/ci_gen_kustomize_values/templates/shiftstack/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - shiftstack-team + +reviewers: + - shiftstack-team diff --git a/roles/ci_gen_kustomize_values/templates/sriov/OWNERS b/roles/ci_gen_kustomize_values/templates/sriov/OWNERS new file mode 100644 index 000000000..7a15ba5da --- /dev/null +++ b/roles/ci_gen_kustomize_values/templates/sriov/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - nfv-team + +reviewers: + - nfv-team diff --git a/roles/ci_gen_kustomize_values/templates/uni01alpha-adoption/OWNERS b/roles/ci_gen_kustomize_values/templates/uni01alpha-adoption/OWNERS new file mode 100644 index 000000000..b7883e567 --- /dev/null +++ b/roles/ci_gen_kustomize_values/templates/uni01alpha-adoption/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - ciops-team + +reviewers: + - ciops-team diff --git a/roles/ci_gen_kustomize_values/templates/uni01alpha/OWNERS b/roles/ci_gen_kustomize_values/templates/uni01alpha/OWNERS new file mode 100644 index 000000000..b7883e567 --- /dev/null +++ b/roles/ci_gen_kustomize_values/templates/uni01alpha/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - ciops-team + +reviewers: + - ciops-team diff --git a/roles/ci_gen_kustomize_values/templates/uni02beta-adoption/OWNERS b/roles/ci_gen_kustomize_values/templates/uni02beta-adoption/OWNERS new file mode 100644 index 000000000..b7883e567 --- /dev/null +++ b/roles/ci_gen_kustomize_values/templates/uni02beta-adoption/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - ciops-team + +reviewers: + - ciops-team diff --git a/roles/ci_gen_kustomize_values/templates/uni02beta/OWNERS b/roles/ci_gen_kustomize_values/templates/uni02beta/OWNERS new file mode 100644 index 000000000..b7883e567 --- /dev/null +++ b/roles/ci_gen_kustomize_values/templates/uni02beta/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - ciops-team + +reviewers: + - ciops-team diff --git a/roles/ci_gen_kustomize_values/templates/uni04delta-ipv6-adoption/OWNERS b/roles/ci_gen_kustomize_values/templates/uni04delta-ipv6-adoption/OWNERS new file mode 100644 index 000000000..b7883e567 --- /dev/null +++ b/roles/ci_gen_kustomize_values/templates/uni04delta-ipv6-adoption/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - ciops-team + +reviewers: + - ciops-team diff --git a/roles/ci_gen_kustomize_values/templates/uni04delta-ipv6/OWNERS b/roles/ci_gen_kustomize_values/templates/uni04delta-ipv6/OWNERS new file mode 100644 index 000000000..b7883e567 --- /dev/null +++ b/roles/ci_gen_kustomize_values/templates/uni04delta-ipv6/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - ciops-team + +reviewers: + - ciops-team diff --git a/roles/ci_gen_kustomize_values/templates/uni05epsilon/OWNERS b/roles/ci_gen_kustomize_values/templates/uni05epsilon/OWNERS new file mode 100644 index 000000000..b7883e567 --- /dev/null +++ b/roles/ci_gen_kustomize_values/templates/uni05epsilon/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - ciops-team + +reviewers: + - ciops-team diff --git a/roles/ci_gen_kustomize_values/templates/uni06zeta/OWNERS b/roles/ci_gen_kustomize_values/templates/uni06zeta/OWNERS new file mode 100644 index 000000000..b7883e567 --- /dev/null +++ b/roles/ci_gen_kustomize_values/templates/uni06zeta/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - ciops-team + +reviewers: + - ciops-team diff --git a/roles/ci_gen_kustomize_values/templates/uni07eta/OWNERS b/roles/ci_gen_kustomize_values/templates/uni07eta/OWNERS new file mode 100644 index 000000000..b7883e567 --- /dev/null +++ b/roles/ci_gen_kustomize_values/templates/uni07eta/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - ciops-team + +reviewers: + - ciops-team diff --git a/roles/ci_local_storage/OWNERS b/roles/ci_local_storage/OWNERS new file mode 100644 index 000000000..5c927dbf6 --- /dev/null +++ b/roles/ci_local_storage/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - storage-contributors + +reviewers: + - storage-contributors diff --git a/roles/ci_lvms_storage/OWNERS b/roles/ci_lvms_storage/OWNERS new file mode 100644 index 000000000..5c927dbf6 --- /dev/null +++ b/roles/ci_lvms_storage/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - storage-contributors + +reviewers: + - storage-contributors diff --git a/roles/ci_multus/molecule/default/nads_output.yml b/roles/ci_multus/molecule/default/nads_output.yml index e8dbd98e0..7c5a0895c 100644 --- a/roles/ci_multus/molecule/default/nads_output.yml +++ b/roles/ci_multus/molecule/default/nads_output.yml @@ -5,7 +5,7 @@ metadata: labels: osp/net: bridge-to-linux-bridge name: bridge-to-linux-bridge - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" spec: config: | { @@ -27,7 +27,7 @@ metadata: labels: osp/net: default name: default - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" spec: config: | { @@ -49,7 +49,7 @@ metadata: labels: osp/net: patchnetwork name: patchnetwork - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" spec: config: | { diff --git a/roles/ci_nmstate/library/ci_nmstate_apply_state.py b/roles/ci_nmstate/library/ci_nmstate_apply_state.py index a8aefc9b0..44df2e538 100755 --- a/roles/ci_nmstate/library/ci_nmstate_apply_state.py +++ b/roles/ci_nmstate/library/ci_nmstate_apply_state.py @@ -30,7 +30,7 @@ # Apply some network config to eth0 using nmstate - name: Generate env var fact register: get_makefiles_env_out - get_makefiles_env: + cifmw.general.get_makefiles_env: state: dns-resolver: running: diff --git a/roles/cifmw_block_device/OWNERS b/roles/cifmw_block_device/OWNERS new file mode 100644 index 000000000..d5b92d858 --- /dev/null +++ b/roles/cifmw_block_device/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - storage-team + +reviewers: + - storage-team diff --git a/roles/cifmw_ceph_client/OWNERS b/roles/cifmw_ceph_client/OWNERS new file mode 100644 index 000000000..d5b92d858 --- /dev/null +++ b/roles/cifmw_ceph_client/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - storage-team + +reviewers: + - storage-team diff --git a/roles/cifmw_ceph_spec/OWNERS b/roles/cifmw_ceph_spec/OWNERS new file mode 100644 index 000000000..d5b92d858 --- /dev/null +++ b/roles/cifmw_ceph_spec/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - storage-team + +reviewers: + - storage-team diff --git a/roles/cifmw_cephadm/OWNERS b/roles/cifmw_cephadm/OWNERS new file mode 100644 index 000000000..d5b92d858 --- /dev/null +++ b/roles/cifmw_cephadm/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - storage-team + +reviewers: + - storage-team diff --git a/roles/cifmw_cephadm/README.md b/roles/cifmw_cephadm/README.md index bd940e9ec..368af7ca4 100644 --- a/roles/cifmw_cephadm/README.md +++ b/roles/cifmw_cephadm/README.md @@ -103,6 +103,11 @@ that they do not need to be changed for a typical EDPM deployment. * `cifmw_cephadm_config_key_set_ssl_option`: Optional colon separated list of SSL context options (default: `no_sslv2:sslv3:no_tlsv1:no_tlsv1_1`) +* `cifmw_rgw_ssl_backward_compatibility`: This option is true by default + because this role is able to manage older Ceph releases (starting from + Squid). Set it to false if the target Ceph release is equal to or greater + than Tentacle. + Use the `cifmw_cephadm_pools` list of dictionaries to define pools for Nova (vms), Cinder (volumes), Cinder-backups (backups), and Glance (images). ``` diff --git a/roles/cifmw_cephadm/defaults/main.yml b/roles/cifmw_cephadm/defaults/main.yml index 5e049aeca..c407da07a 100644 --- a/roles/cifmw_cephadm/defaults/main.yml +++ b/roles/cifmw_cephadm/defaults/main.yml @@ -153,3 +153,6 @@ cifmw_cephadm_wait_install_retries: 8 cifmw_cephadm_wait_install_delay: 15 cifmw_cephadm_rgw_ingress_service_name: "ingress.rgw.default" cifmw_cephadm_rgw_ingress_service_id: "rgw.default" +# set ssl_backward compatibily to False if ceph version is equal or greater +# than Tentacle +cifmw_rgw_ssl_backward_compatibility: true diff --git a/roles/cifmw_cephadm/tasks/configure_object.yml b/roles/cifmw_cephadm/tasks/configure_object.yml index 45bf02fec..d86c03fb2 100644 --- a/roles/cifmw_cephadm/tasks/configure_object.yml +++ b/roles/cifmw_cephadm/tasks/configure_object.yml @@ -21,7 +21,7 @@ when: cifmw_openshift_kubeconfig is defined block: - name: Check if swift is enabled in deployed controlplane - ansible.builtin.shell: "set -o pipefail && oc -n {{ cifmw_cephadm_ns }} get $(oc get oscp -n openstack -o name) -o json| jq .spec.swift.enabled" + ansible.builtin.shell: "set -o pipefail && oc -n {{ cifmw_cephadm_ns }} get $(oc get oscp -n {{ cifmw_openstack_namespace }} -o name) -o json| jq .spec.swift.enabled" register: swift_in_ctlplane # checking swift_endpoints_count will avoid unnecessary errors during ceph deployment re-run diff --git a/roles/cifmw_cephadm/tasks/rgw.yml b/roles/cifmw_cephadm/tasks/rgw.yml index 2135d76ee..8fe6d89aa 100644 --- a/roles/cifmw_cephadm/tasks/rgw.yml +++ b/roles/cifmw_cephadm/tasks/rgw.yml @@ -56,10 +56,11 @@ ansible.builtin.slurp: src: "{{ cifmw_cephadm_key }}" - - name: Set rgw_frontend_cert to cert/key concatenation + - name: Set SSL cert/key variables based on rgw_compatibility mode ansible.builtin.set_fact: - rgw_frontend_cert: "{{ slurp_cert['content'] | b64decode ~ - slurp_key['content'] | b64decode }}" + rgw_frontend_cert: "{{ (slurp_cert['content'] | b64decode ~ slurp_key['content'] | b64decode) if cifmw_rgw_ssl_backward_compatibility else omit }}" + rgw_ssl_cert: "{{ slurp_cert['content'] | b64decode if not cifmw_rgw_ssl_backward_compatibility else omit }}" + rgw_ssl_key: "{{ slurp_key['content'] | b64decode if not cifmw_rgw_ssl_backward_compatibility else omit }}" - name: Create a Ceph RGW spec ansible.builtin.template: diff --git a/roles/cifmw_cephadm/templates/ceph_rgw.yml.j2 b/roles/cifmw_cephadm/templates/ceph_rgw.yml.j2 index 76ba5ee26..81a7f51e3 100644 --- a/roles/cifmw_cephadm/templates/ceph_rgw.yml.j2 +++ b/roles/cifmw_cephadm/templates/ceph_rgw.yml.j2 @@ -11,11 +11,19 @@ networks: - {{ cifmw_cephadm_rgw_network }} spec: rgw_frontend_port: 8082 -{% if rgw_frontend_cert is defined %} +{% if rgw_frontend_cert is defined and cifmw_rgw_ssl_backward_compatibility %} ssl: true rgw_frontend_ssl_certificate: | {{ rgw_frontend_cert | indent( width=4 ) }} {% endif %} +{% if rgw_ssl_cert is defined %} + ssl: true + certificate_source: inline + ssl_cert: |- + {{ rgw_ssl_cert | indent( width=4 ) }} + ssl_key: |- + {{ rgw_ssl_key | indent( width=4 ) }} +{% endif %} --- {% if _hosts|length > 1 %} service_type: ingress @@ -28,8 +36,15 @@ spec: virtual_interface_networks: - {{ cifmw_cephadm_rgw_network }} virtual_ip: {{ cifmw_cephadm_rgw_vip }}/{{ cidr }} -{% if rgw_frontend_cert is defined %} +{% if rgw_frontend_cert is defined and cifmw_rgw_ssl_backward_compatibility %} ssl_cert: | {{ rgw_frontend_cert | indent( width=6 ) }} {% endif %} +{% if rgw_ssl_cert is defined %} + ssl: true + ssl_cert: |- + {{ rgw_ssl_cert | indent( width=6 ) }} + ssl_key: |- + {{ rgw_ssl_key | indent( width=6 ) }} +{% endif %} {% endif %} diff --git a/roles/cifmw_create_admin/OWNERS b/roles/cifmw_create_admin/OWNERS new file mode 100644 index 000000000..d5b92d858 --- /dev/null +++ b/roles/cifmw_create_admin/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - storage-team + +reviewers: + - storage-team diff --git a/roles/cifmw_helpers/tasks/inventory_file.yml b/roles/cifmw_helpers/tasks/inventory_file.yml index 4eb8389b2..c8b2ac2ce 100644 --- a/roles/cifmw_helpers/tasks/inventory_file.yml +++ b/roles/cifmw_helpers/tasks/inventory_file.yml @@ -17,8 +17,23 @@ inventory_data: "{{ _inventory_file.content | b64decode | from_yaml }}" - name: Process each group with hosts + when: + - inventory_data is mapping + - inventory_data | dict2items | selectattr('value.hosts', 'defined') | list | length > 0 ansible.builtin.include_tasks: file: parse_inventory.yml loop: "{{ inventory_data | dict2items | selectattr('value.hosts', 'defined') | list }}" loop_control: loop_var: group_item + + - name: Process each group with hosts when in groups + when: + - inventory_data.all is defined + - inventory_data.all.children is defined + - inventory_data.all.children is mapping + - inventory_data.all.children | dict2items | selectattr('value.hosts', 'defined') | list | length > 0 + ansible.builtin.include_tasks: + file: parse_inventory.yml + loop: "{{ inventory_data.all.children | dict2items | selectattr('value.hosts', 'defined') | list }}" + loop_control: + loop_var: group_item diff --git a/roles/cifmw_setup/defaults/main.yml b/roles/cifmw_setup/defaults/main.yml index 74cdfebb7..fbb8f7104 100644 --- a/roles/cifmw_setup/defaults/main.yml +++ b/roles/cifmw_setup/defaults/main.yml @@ -1,3 +1,2 @@ --- -ansible_user_dir: "{{ lookup('env', 'HOME') }}" -openstack_namespace: openstack +cifmw_openstack_namespace: openstack diff --git a/roles/cifmw_setup/tasks/deploy_architecture.yml b/roles/cifmw_setup/tasks/deploy_architecture.yml index 7bce8976f..3a11b4dbd 100644 --- a/roles/cifmw_setup/tasks/deploy_architecture.yml +++ b/roles/cifmw_setup/tasks/deploy_architecture.yml @@ -258,7 +258,7 @@ PATH: "{{ cifmw_path }}" ansible.builtin.command: >- oc rsh - -n {{ openstack_namespace }} + -n {{ cifmw_openstack_namespace }} nova-cell0-conductor-0 nova-manage cell_v2 discover_hosts --verbose diff --git a/roles/cleanup_openstack/tasks/main.yaml b/roles/cleanup_openstack/tasks/main.yaml index b8e194df9..3378e34a1 100644 --- a/roles/cleanup_openstack/tasks/main.yaml +++ b/roles/cleanup_openstack/tasks/main.yaml @@ -51,6 +51,19 @@ ansible.builtin.import_tasks: detach_bmh.yaml when: cifmw_cleanup_openstack_detach_bmh +- name: Work around for stale rabbit cluster deletion + kubernetes.core.k8s_json_patch: + kubeconfig: "{{ cifmw_openshift_kubeconfig }}" + api_key: "{{ cifmw_openshift_token | default(omit) }}" + context: "{{ cifmw_openshift_context | default(omit) }}" + namespace: "{{ cifmw_openstack_namespace }}" + kind: RabbitmqCluster + name: rabbitmq-cell1 + patch: + - op: replace + path: /metadata/finalizers + value: [] + - name: Delete deployment CRs vars: _stages_crs: >- diff --git a/roles/compliance/OWNERS b/roles/compliance/OWNERS new file mode 100644 index 000000000..e74ebe306 --- /dev/null +++ b/roles/compliance/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - security-team + +reviewers: + - security-team diff --git a/roles/compliance/molecule/default/converge.yml b/roles/compliance/molecule/default/converge.yml index 31b95ac11..b4e025358 100644 --- a/roles/compliance/molecule/default/converge.yml +++ b/roles/compliance/molecule/default/converge.yml @@ -18,7 +18,6 @@ - name: Converge test of controller tasks hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_compliance_dry_run: true roles: - role: "compliance" @@ -26,7 +25,6 @@ - name: Converge test of compute tasks hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_compliance_dry_run: true roles: - role: "compliance" diff --git a/roles/config_drive/molecule/default/converge.yml b/roles/config_drive/molecule/default/converge.yml index cbb896b55..ce6516de0 100644 --- a/roles/config_drive/molecule/default/converge.yml +++ b/roles/config_drive/molecule/default/converge.yml @@ -18,7 +18,7 @@ - name: Converge hosts: all tasks: - - name: Include config_drive role + - name: Include config_drive role with full configuration vars: cifmw_config_drive_uuid: de2f369a-1886-4a90-8e50-e419289e6850 cifmw_config_drive_name: test01 @@ -54,3 +54,158 @@ - 192.168.0.1 ansible.builtin.include_role: name: config_drive + + - name: Run config_drive role again without user-data or network-config (soft-clean scenario) + vars: + cifmw_config_drive_uuid: de2f369a-1886-4a90-8e50-e419289e6850 + cifmw_config_drive_name: test01 + cifmw_config_drive_hostname: test01.example.com + # cifmw_config_drive_userdata is not defined (simulating soft clean) + # cifmw_config_drive_networkconfig is not defined (simulating soft clean) + ansible.builtin.include_role: + name: config_drive + + - name: Verify ISO still exists after soft-clean + ansible.builtin.stat: + path: "{{ cifmw_config_drive_basedir | default(ansible_user_dir ~ '/ci-framework-data') }}/artifacts/cifmw_config_drive/de2f369a-1886-4a90-8e50-e419289e6850.iso" + register: _iso_check + + - name: Assert ISO exists + ansible.builtin.assert: + that: + - _iso_check.stat.exists + fail_msg: "ISO file should exist after soft-clean scenario" + success_msg: "Soft-clean scenario passed - ISO exists and role didn't fail on skipped tasks" + + - name: Run config_drive role again with same configuration (should pass - no changes) + vars: + cifmw_config_drive_uuid: de2f369a-1886-4a90-8e50-e419289e6850 + cifmw_config_drive_name: test01 + cifmw_config_drive_hostname: test01.example.com + cifmw_config_drive_userdata: + ssh_authorized_keys: + - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCg1LHRahLiT1NFv4l/XH + packages: + - git + - bind-utils + write_files: + - path: /root/test.file + owner: root:root + content: |- + # Test file content + runcmd: + - ['sh', '-c', 'echo foo | tee -a /tmp/foo'] + cifmw_config_drive_networkconfig: + network: + version: 2 + ethernets: + id0: + match: + macaddress: "aa:bb:cc:dd:ee:ff" + addresses: + - 192.168.0.101/24 + routes: + - to: 0.0.0.0/0 + via: 192.168.0.1 + on-link: true + nameservers: + addresses: + - 192.168.0.1 + ansible.builtin.include_role: + name: config_drive + + - name: Attempt to change user-data on existing ISO (should fail) + block: + - name: Include config_drive with modified user-data + vars: + cifmw_config_drive_uuid: de2f369a-1886-4a90-8e50-e419289e6850 + cifmw_config_drive_name: test01 + cifmw_config_drive_hostname: test01.example.com + cifmw_config_drive_userdata: + ssh_authorized_keys: + - ssh-rsa DIFFERENT_KEY_HERE + packages: + - vim # Changed from git + cifmw_config_drive_networkconfig: + network: + version: 2 + ethernets: + id0: + match: + macaddress: "aa:bb:cc:dd:ee:ff" + addresses: + - 192.168.0.101/24 + routes: + - to: 0.0.0.0/0 + via: 192.168.0.1 + on-link: true + nameservers: + addresses: + - 192.168.0.1 + ansible.builtin.include_role: + name: config_drive + + - name: Fail if role didn't reject the change + ansible.builtin.fail: + msg: "Role should have failed when trying to change user-data on existing ISO" + + rescue: + - name: Verify the failure was due to ISO modification attempt + ansible.builtin.assert: + that: + - ansible_failed_result.msg is defined + - ansible_failed_result.msg is regex('trying to edit an existing ISO', ignorecase=True) + fail_msg: "Role failed but not with expected error message. Got: {{ ansible_failed_result.msg | default('no message') }}" + success_msg: "Role correctly rejected attempt to change user-data" + + - name: Attempt to change network-config on existing ISO (should fail) + block: + - name: Include config_drive with modified network-config + vars: + cifmw_config_drive_uuid: de2f369a-1886-4a90-8e50-e419289e6850 + cifmw_config_drive_name: test01 + cifmw_config_drive_hostname: test01.example.com + cifmw_config_drive_userdata: + ssh_authorized_keys: + - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCg1LHRahLiT1NFv4l/XH + packages: + - git + - bind-utils + write_files: + - path: /root/test.file + owner: root:root + content: |- + # Test file content + runcmd: + - ['sh', '-c', 'echo foo | tee -a /tmp/foo'] + cifmw_config_drive_networkconfig: + network: + version: 2 + ethernets: + id0: + match: + macaddress: "11:22:33:44:55:66" # Changed MAC address + addresses: + - 192.168.0.200/24 # Changed IP + routes: + - to: 0.0.0.0/0 + via: 192.168.0.1 + on-link: true + nameservers: + addresses: + - 192.168.0.1 + ansible.builtin.include_role: + name: config_drive + + - name: Fail if role didn't reject the change + ansible.builtin.fail: + msg: "Role should have failed when trying to change network-config on existing ISO" + + rescue: + - name: Verify the failure was due to ISO modification attempt + ansible.builtin.assert: + that: + - ansible_failed_result.msg is defined + - ansible_failed_result.msg is regex('trying to edit an existing ISO', ignorecase=True) + fail_msg: "Role failed but not with expected error message. Got: {{ ansible_failed_result.msg | default('no message') }}" + success_msg: "Role correctly rejected attempt to change network-config" diff --git a/roles/config_drive/tasks/main.yml b/roles/config_drive/tasks/main.yml index 67b38d8c5..e41c89ba1 100644 --- a/roles/config_drive/tasks/main.yml +++ b/roles/config_drive/tasks/main.yml @@ -51,7 +51,7 @@ - name: Generate user-data register: _user_data_change when: - - cifmw_config_drive_userdata is defined + - cifmw_config_drive_userdata is not none - cifmw_config_drive_userdata | length > 0 ansible.builtin.template: backup: true @@ -62,8 +62,8 @@ - name: Generate network-data register: _net_data_change when: - - cifmw_config_drive_networkconfig is defined - - cifmw_config_drive_networkconfig + - cifmw_config_drive_networkconfig is not none + - cifmw_config_drive_networkconfig | length > 0 ansible.builtin.template: backup: true src: "network-config.j2" @@ -84,8 +84,8 @@ ansible.builtin.assert: that: - _meta_data_change is not changed - - _user_data_change is not changed - - _net_data_change is not changed + - _user_data_change is skipped or _user_data_change is not changed + - _net_data_change is skipped or _net_data_change is not changed msg: >- You're trying to edit an existing ISO. This isn't possible, since the ISO is usually attached to a virtual machine, and diff --git a/roles/devscripts/molecule/default/prepare.yml b/roles/devscripts/molecule/default/prepare.yml index 683c54952..78bb43ce7 100644 --- a/roles/devscripts/molecule/default/prepare.yml +++ b/roles/devscripts/molecule/default/prepare.yml @@ -19,7 +19,6 @@ hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_path: "{{ ansible_user_dir }}/.crc/bin:{{ ansible_user_dir }}/.crc/bin/oc:{{ ansible_user_dir }}/bin:{{ ansible_env.PATH }}" cifmw_use_libvirt: true diff --git a/roles/edpm_build_images/molecule/default/converge.yml b/roles/edpm_build_images/molecule/default/converge.yml index e9ff2242c..05ea6c710 100644 --- a/roles/edpm_build_images/molecule/default/converge.yml +++ b/roles/edpm_build_images/molecule/default/converge.yml @@ -18,7 +18,6 @@ - name: Converge hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_edpm_build_images_dry_run: true cifmw_edpm_build_images_via_rpm: false roles: diff --git a/roles/edpm_deploy/molecule/default/converge.yml b/roles/edpm_deploy/molecule/default/converge.yml index 5fa7bc7a5..0ba92a5a7 100644 --- a/roles/edpm_deploy/molecule/default/converge.yml +++ b/roles/edpm_deploy/molecule/default/converge.yml @@ -18,7 +18,6 @@ - name: Converge hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_edpm_deploy_dryrun: true roles: - role: "edpm_deploy" diff --git a/roles/edpm_deploy/molecule/default/prepare.yml b/roles/edpm_deploy/molecule/default/prepare.yml index 2a57c338a..76fa523e6 100644 --- a/roles/edpm_deploy/molecule/default/prepare.yml +++ b/roles/edpm_deploy/molecule/default/prepare.yml @@ -18,7 +18,6 @@ - name: Prepare hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_install_yamls_tasks_out: "{{ ansible_user_dir }}/zuul-jobs/roles/install_yamls_makes/tasks" cifmw_install_yamls_defaults: NAMESPACE: openstack diff --git a/roles/edpm_deploy_baremetal/molecule/default/prepare.yml b/roles/edpm_deploy_baremetal/molecule/default/prepare.yml index 39b3a811a..2ff6b8110 100644 --- a/roles/edpm_deploy_baremetal/molecule/default/prepare.yml +++ b/roles/edpm_deploy_baremetal/molecule/default/prepare.yml @@ -18,7 +18,6 @@ - name: Prepare hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_basedir: "{{ ansible_user_dir }}/ci-framework-data" cifmw_install_yamls_tasks_out: "{{ ansible_user_dir }}/zuul-jobs/roles/install_yamls_makes/tasks" roles: diff --git a/roles/edpm_prepare/defaults/main.yml b/roles/edpm_prepare/defaults/main.yml index 9d4f6e2b4..814cecf5d 100644 --- a/roles/edpm_prepare/defaults/main.yml +++ b/roles/edpm_prepare/defaults/main.yml @@ -33,3 +33,4 @@ cifmw_edpm_prepare_kustomizations: [] # false 'ready' status. cifmw_edpm_prepare_wait_controplane_status_change_sec: 30 cifmw_edpm_prepare_extra_kustomizations: [] +cifmw_prepare_openstackversion: true diff --git a/roles/edpm_prepare/molecule/default/prepare.yml b/roles/edpm_prepare/molecule/default/prepare.yml index 810486ac1..0c6d52693 100644 --- a/roles/edpm_prepare/molecule/default/prepare.yml +++ b/roles/edpm_prepare/molecule/default/prepare.yml @@ -18,7 +18,6 @@ - name: Prepare hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_basedir: "{{ ansible_user_dir }}/ci-framework-data" cifmw_install_yamls_tasks_out: "{{ ansible_user_dir }}/zuul-jobs/roles/install_yamls_makes/tasks" cifmw_install_yamls_defaults: diff --git a/roles/edpm_prepare/tasks/kustomize_and_deploy.yml b/roles/edpm_prepare/tasks/kustomize_and_deploy.yml index 0a65a2039..3267e4dee 100644 --- a/roles/edpm_prepare/tasks/kustomize_and_deploy.yml +++ b/roles/edpm_prepare/tasks/kustomize_and_deploy.yml @@ -30,14 +30,15 @@ - name: Prepare OpenStackVersion CR when: >- - (cifmw_update_containers_edpm_image_url is defined and + (cifmw_prepare_openstackversion | bool) and + ((cifmw_update_containers_edpm_image_url is defined and cifmw_update_containers_openstack is defined and cifmw_update_containers_openstack | bool) or (cifmw_update_containers_ansibleee_image_url is defined) or (cifmw_update_containers_openstack is defined and cifmw_update_containers_openstack | bool) or (cifmw_update_containers_watcher is defined and - cifmw_update_containers_watcher | bool) + cifmw_update_containers_watcher | bool)) vars: cifmw_update_containers_metadata: "{{ _ctlplane_name }}" ansible.builtin.include_role: diff --git a/roles/fdp_update_container_images/README.md b/roles/fdp_update_container_images/README.md new file mode 100644 index 000000000..50875c80f --- /dev/null +++ b/roles/fdp_update_container_images/README.md @@ -0,0 +1,120 @@ +# fdp_update_container_images + +Ansible role to update specific RPM packages in OpenStack container images by rebuilding them with custom repositories. + +This role automates the process of: +1. Fetching container images from OpenStackVersion CR +2. Checking if target package exists in each image +3. Building new images with updated packages from custom repository +4. Pushing updated images to OpenShift internal registry +5. Patching OpenStackVersion CR to use the new images + +## Privilege escalation +None - Runs as the user executing Ansible + +## Parameters + +* `cifmw_fdp_update_container_images_basedir`: (String) Base directory. Defaults to `cifmw_basedir` which defaults to `~/ci-framework-data`. +* `cifmw_fdp_update_container_images_namespace`: (String) OpenShift namespace where OpenStack is deployed. Defaults to `openstack`. +* `cifmw_fdp_update_container_images_openstack_cr_name`: (String) Name of the OpenStackVersion CR. Defaults to `controlplane`. +* `cifmw_fdp_update_container_images_target_package`: (String) Name of the RPM package to update (e.g., `ovn24.03`). **Required**. +* `cifmw_fdp_update_container_images_images_to_scan`: (List) List of container image keys to update. Only these images will be processed. Defaults to `['ovnControllerImage', 'ovnControllerOvsImage', 'ovnNbDbclusterImage', 'ovnNorthdImage', 'ovnSbDbclusterImage', 'ceilometerSgcoreImage']`. +* `cifmw_fdp_update_container_images_repo_name`: (String) Repository name. Defaults to `custom-repo`. +* `cifmw_fdp_update_container_images_repo_baseurl`: (String) Repository base URL. **Required**. +* `cifmw_fdp_update_container_images_repo_enabled`: (Integer) Enable repository (0 or 1). Defaults to `1`. +* `cifmw_fdp_update_container_images_repo_gpgcheck`: (Integer) Enable GPG check (0 or 1). Defaults to `0`. +* `cifmw_fdp_update_container_images_repo_priority`: (Integer) Repository priority. Defaults to `0`. +* `cifmw_fdp_update_container_images_repo_sslverify`: (Integer) Enable SSL verification (0 or 1). Defaults to `0`. +* `cifmw_fdp_update_container_images_image_registry`: (String) External OpenShift image registry URL. Auto-detected from cluster if not specified. Leave empty for auto-detection. +* `cifmw_fdp_update_container_images_image_registry_internal`: (String) Internal OpenShift image registry URL. Defaults to `image-registry.openshift-image-registry.svc:5000`. +* `cifmw_fdp_update_container_images_image_name_prefix`: (String) Prefix for new image names. Defaults to `fdp-update`. +* `cifmw_fdp_update_container_images_temp_dir`: (String) Temporary directory for build context. Auto-generated if not specified. +* `cifmw_fdp_update_container_images_update_dnf_args`: (String) Additional arguments for dnf update command. Defaults to `--disablerepo='*' --enablerepo={{ cifmw_fdp_update_container_images_repo_name }}`. + +## Examples + +### Update OVN package in default images +```yaml +--- +- hosts: localhost + vars: + cifmw_fdp_update_container_images_target_package: "ovn24.03" + cifmw_fdp_update_container_images_repo_name: "custom-repo" + cifmw_fdp_update_container_images_repo_baseurl: "http://example.com/custom-repo/" + cifmw_fdp_update_container_images_namespace: "openstack" + roles: + - role: "fdp_update_container_images" +``` + +### Update with custom registry and image prefix +```yaml +--- +- hosts: localhost + vars: + cifmw_fdp_update_container_images_target_package: "ovn24.03" + cifmw_fdp_update_container_images_repo_baseurl: "http://custom-repo.example.com/repo/" + cifmw_fdp_update_container_images_image_registry: "registry.example.com" + cifmw_fdp_update_container_images_image_name_prefix: "ovn-hotfix" + roles: + - role: "fdp_update_container_images" +``` + +### Update with specific DNF arguments +```yaml +--- +- hosts: localhost + vars: + cifmw_fdp_update_container_images_target_package: "neutron-ovn-metadata-agent" + cifmw_fdp_update_container_images_repo_baseurl: "http://custom-repo.example.com/repo/" + cifmw_fdp_update_container_images_update_dnf_args: "--disablerepo='*' --enablerepo={{ cifmw_fdp_update_container_images_repo_name }} --nobest" + roles: + - role: "fdp_update_container_images" +``` + +### Update specific images only +```yaml +--- +- hosts: localhost + vars: + cifmw_fdp_update_container_images_target_package: "ovn24.03" + cifmw_fdp_update_container_images_repo_baseurl: "http://custom-repo.example.com/repo/" + cifmw_fdp_update_container_images_images_to_scan: + - ovnControllerImage + - ovnNorthdImage + roles: + - role: "fdp_update_container_images" +``` + +## How it works + +1. **Registry Setup**: + - Enables the default route for OpenShift image registry + - Auto-detects the registry hostname or uses the configured value +2. **Authentication**: Obtains a token from OpenShift and authenticates with the internal registry using TLS +3. **Image Discovery**: Queries the OpenStackVersion CR for all container images +4. **Package Check**: For each image, creates a temporary container to check if the target package is installed +5. **Image Build**: If the package exists, builds a new image with the updated package from the custom repository +6. **Registry Push**: Pushes the new image to the OpenShift internal registry +7. **CR Update**: Patches the OpenStackVersion CR's `spec.customContainerImages` field with the new image reference +8. **Summary**: Provides a summary of all updated images + +## Requirements + +* OpenShift CLI (`oc`) must be available +* Podman must be installed and accessible +* User must have permissions to: + - Create tokens in the target namespace + - Get and patch OpenStackVersion CRs + - Push images to the internal registry + - Patch image registry configuration (`configs.imageregistry.operator.openshift.io/cluster`) + +## Notes + +* The role uses podman to build and push images with TLS verification +* Each updated image gets a unique tag with timestamp: `--` +* Only images containing the target package will be updated +* The role cleans up temporary containers automatically +* All build contexts are created in a temporary directory that is cleaned up after execution +* The role automatically configures the OpenShift image registry for external access: + - Enables the default route if not already enabled + - Auto-detects the registry hostname from the route diff --git a/roles/fdp_update_container_images/defaults/main.yml b/roles/fdp_update_container_images/defaults/main.yml new file mode 100644 index 000000000..81c4c9b5e --- /dev/null +++ b/roles/fdp_update_container_images/defaults/main.yml @@ -0,0 +1,67 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# ============================================================================ +# Base Configuration +# ============================================================================ + +# Base directory for artifacts and temporary files +cifmw_fdp_update_container_images_basedir: "{{ cifmw_basedir | default(ansible_user_dir ~ '/ci-framework-data') }}" + +# OpenShift namespace where OpenStack is deployed +cifmw_fdp_update_container_images_namespace: "openstack" + +# Name of the OpenStackVersion custom resource +cifmw_fdp_update_container_images_openstack_cr_name: "controlplane" + +# Target package to update (REQUIRED - must be set by user) +cifmw_fdp_update_container_images_target_package: "" + +# List of images to update with the target package +# Only these images will be updated (no package scanning is performed) +cifmw_fdp_update_container_images_images_to_scan: + - ovnControllerImage + - ovnControllerOvsImage + - ovnNbDbclusterImage + - ovnNorthdImage + - ovnSbDbclusterImage + - ceilometerSgcoreImage + +# Repository configuration +cifmw_fdp_update_container_images_repo_name: "custom-repo" +cifmw_fdp_update_container_images_repo_baseurl: "" # REQUIRED - must be set by user +cifmw_fdp_update_container_images_repo_enabled: 1 +cifmw_fdp_update_container_images_repo_gpgcheck: 0 +cifmw_fdp_update_container_images_repo_priority: 0 +cifmw_fdp_update_container_images_repo_sslverify: 0 + +# Image registry configuration +# External registry URL (for compute nodes/EDPM and pushing images) +# Leave empty to auto-detect external route from OpenShift cluster +cifmw_fdp_update_container_images_image_registry: "" + +# Internal registry URL (for OpenShift pods to pull images) +# This is auto-detected and should not normally need to be changed +cifmw_fdp_update_container_images_image_registry_internal: "image-registry.openshift-image-registry.svc:5000" + +# Image naming +cifmw_fdp_update_container_images_image_name_prefix: "fdp-update" + +# Temporary directory for build context +cifmw_fdp_update_container_images_temp_dir: "" + +# DNF update arguments +cifmw_fdp_update_container_images_update_dnf_args: "--disablerepo='*' --enablerepo={{ cifmw_fdp_update_container_images_repo_name }}" diff --git a/roles/build_push_container/tasks/cleanup.yml b/roles/fdp_update_container_images/meta/main.yml similarity index 54% rename from roles/build_push_container/tasks/cleanup.yml rename to roles/fdp_update_container_images/meta/main.yml index 89bf37f9d..d727c787b 100644 --- a/roles/build_push_container/tasks/cleanup.yml +++ b/roles/fdp_update_container_images/meta/main.yml @@ -14,20 +14,25 @@ # License for the specific language governing permissions and limitations # under the License. -- name: Stop and remove registry container - containers.podman.podman_container: - name: registry - state: absent +galaxy_info: + author: Red Hat + description: Update RPM packages in OpenStack container images + company: Red Hat + license: Apache-2.0 + min_ansible_version: "2.15" + platforms: + - name: Fedora + versions: + - all + - name: EL + versions: + - "9" + galaxy_tags: + - openstack + - containers + - kubernetes + - openshift + - podman + - rpm -- name: List images created and used by role - ansible.builtin.command: - cmd: >- - podman images -q - --filter=label=build_push_role=true - --filter=reference=docker.io/library/registry:2 - register: podman_images_output - -- name: Remove images created and used by role - ansible.builtin.command: - cmd: podman rmi -f {{ item }} - loop: "{{ podman_images_output.stdout_lines }}" +dependencies: [] diff --git a/roles/fdp_update_container_images/tasks/authenticate_registry.yml b/roles/fdp_update_container_images/tasks/authenticate_registry.yml new file mode 100644 index 000000000..464633739 --- /dev/null +++ b/roles/fdp_update_container_images/tasks/authenticate_registry.yml @@ -0,0 +1,28 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Create registry token + ansible.builtin.command: oc create token builder -n {{ cifmw_fdp_update_container_images_namespace }} + register: _cifmw_fdp_update_container_images_token + changed_when: false + no_log: true + +- name: Authenticate podman with TLS verification + containers.podman.podman_login: + username: unused + password: "{{ _cifmw_fdp_update_container_images_token.stdout }}" + registry: "{{ cifmw_fdp_update_container_images_image_registry }}" + no_log: true diff --git a/roles/fdp_update_container_images/tasks/configure_ca_cert.yml b/roles/fdp_update_container_images/tasks/configure_ca_cert.yml new file mode 100644 index 000000000..ea3fd29bd --- /dev/null +++ b/roles/fdp_update_container_images/tasks/configure_ca_cert.yml @@ -0,0 +1,40 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Get OpenShift ingress CA certificate + kubernetes.core.k8s_info: + api_version: v1 + kind: Secret + name: router-ca + namespace: openshift-ingress-operator + register: _cifmw_fdp_update_container_images_ca_secret + +- name: Extract CA certificate from secret + ansible.builtin.set_fact: + _cifmw_fdp_update_container_images_ca_cert_b64: + stdout: "{{ _cifmw_fdp_update_container_images_ca_secret.resources[0].data['tls.crt'] }}" + +- name: Decode CA certificate + ansible.builtin.copy: + content: "{{ _cifmw_fdp_update_container_images_ca_cert_b64.stdout | b64decode }}" + dest: /etc/pki/ca-trust/source/anchors/openshift-registry-ca.crt + mode: '0644' + become: true + +- name: Update CA trust + ansible.builtin.command: update-ca-trust extract + become: true + changed_when: true diff --git a/roles/fdp_update_container_images/tasks/detect_registry.yml b/roles/fdp_update_container_images/tasks/detect_registry.yml new file mode 100644 index 000000000..70bfe3bcb --- /dev/null +++ b/roles/fdp_update_container_images/tasks/detect_registry.yml @@ -0,0 +1,50 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Enable OpenShift registry route + kubernetes.core.k8s: + api_version: imageregistry.operator.openshift.io/v1 + kind: Config + name: cluster + state: patched + definition: + spec: + defaultRoute: true + register: _cifmw_fdp_update_container_images_enable_route + failed_when: false + +- name: Wait for route + ansible.builtin.pause: + seconds: 10 + when: _cifmw_fdp_update_container_images_enable_route is not failed + +- name: Get registry route + kubernetes.core.k8s_info: + api_version: route.openshift.io/v1 + kind: Route + name: default-route + namespace: openshift-image-registry + register: _cifmw_fdp_update_container_images_route_info + failed_when: false + +- name: Verify registry URL + ansible.builtin.fail: + msg: "Failed to determine registry URL. Set cifmw_fdp_update_container_images_image_registry manually." + when: (_cifmw_fdp_update_container_images_route_info.resources | length == 0) + +- name: Set registry URL + ansible.builtin.set_fact: + cifmw_fdp_update_container_images_image_registry: "{{ _cifmw_fdp_update_container_images_route_info.resources[0].spec.host }}" diff --git a/roles/fdp_update_container_images/tasks/fetch_images.yml b/roles/fdp_update_container_images/tasks/fetch_images.yml new file mode 100644 index 000000000..b3362efc8 --- /dev/null +++ b/roles/fdp_update_container_images/tasks/fetch_images.yml @@ -0,0 +1,38 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Get OpenStackVersion CR + kubernetes.core.k8s_info: + api_version: core.openstack.org/v1beta1 + kind: OpenStackVersion + name: "{{ cifmw_fdp_update_container_images_openstack_cr_name }}" + namespace: "{{ cifmw_fdp_update_container_images_namespace }}" + register: _cifmw_fdp_update_container_images_cr_info + +- name: Extract container images + ansible.builtin.set_fact: + _cifmw_fdp_update_container_images_container_images: "{{ _cifmw_fdp_update_container_images_cr_info.resources[0].status.containerImageVersionDefaults.values() | first | default({}) }}" + +- name: Filter images to process + ansible.builtin.set_fact: + _cifmw_fdp_update_container_images_image_entries: "{{ _cifmw_fdp_update_container_images_container_images | dict2items | selectattr('key', 'in', cifmw_fdp_update_container_images_images_to_scan) | list }}" + _cifmw_fdp_update_container_images_modified_images: [] + _cifmw_fdp_update_container_images_updated_cr_keys: [] + _cifmw_fdp_update_container_images_processed_images: 0 + +- name: Display images to process + ansible.builtin.debug: + msg: "Processing {{ _cifmw_fdp_update_container_images_image_entries | length }} images: {{ _cifmw_fdp_update_container_images_image_entries | map(attribute='key') | list | join(', ') }}" diff --git a/roles/fdp_update_container_images/tasks/main.yml b/roles/fdp_update_container_images/tasks/main.yml new file mode 100644 index 000000000..f3aaec14b --- /dev/null +++ b/roles/fdp_update_container_images/tasks/main.yml @@ -0,0 +1,78 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# ============================================ +# Validate and Initialize +# ============================================ + +- name: Validate parameters and initialize + ansible.builtin.include_tasks: validate.yml + +# ============================================ +# Detect Registry +# ============================================ + +- name: Detect OpenShift registry URL + ansible.builtin.include_tasks: detect_registry.yml + +# ============================================ +# Configure Registry Authentication +# ============================================ + +- name: Configure registry CA certificate + ansible.builtin.include_tasks: configure_ca_cert.yml + +- name: Authenticate with registry + ansible.builtin.include_tasks: authenticate_registry.yml + +# ============================================ +# Fetch Images +# ============================================ + +- name: Fetch images to process + ansible.builtin.include_tasks: fetch_images.yml + +# ============================================ +# Process Each Image +# ============================================ + +- name: Build and push updated images + ansible.builtin.include_tasks: process_image.yml + loop: "{{ _cifmw_fdp_update_container_images_image_entries }}" + loop_control: + loop_var: image_entry + label: "{{ image_entry.key }}" + when: _cifmw_fdp_update_container_images_image_entries | length > 0 + +# ============================================ +# Summary +# ============================================ + +- name: Display summary + ansible.builtin.debug: + msg: + - "==========================================" + - "Container image update complete" + - "Target package: {{ cifmw_fdp_update_container_images_target_package }}" + - "Images processed: {{ _cifmw_fdp_update_container_images_processed_images }}" + - "Updated: {{ _cifmw_fdp_update_container_images_updated_cr_keys | join(', ') if _cifmw_fdp_update_container_images_updated_cr_keys | length > 0 else 'None' }}" + - "==========================================" + +- name: Cleanup temporary directory + ansible.builtin.file: + path: "{{ _cifmw_fdp_update_container_images_temp_dir }}" + state: absent + when: _cifmw_fdp_update_container_images_temp_dir is defined diff --git a/roles/fdp_update_container_images/tasks/process_image.yml b/roles/fdp_update_container_images/tasks/process_image.yml new file mode 100644 index 000000000..06ed6e7b1 --- /dev/null +++ b/roles/fdp_update_container_images/tasks/process_image.yml @@ -0,0 +1,66 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Create repository file + ansible.builtin.template: + src: repo.j2 + dest: "{{ _cifmw_fdp_update_container_images_temp_dir }}/{{ cifmw_fdp_update_container_images_repo_name }}.repo" + mode: '0644' + +- name: Create Dockerfile + ansible.builtin.template: + src: Dockerfile.j2 + dest: "{{ _cifmw_fdp_update_container_images_temp_dir }}/Dockerfile" + mode: '0644' + vars: + base_image: "{{ image_entry.value }}" + +- name: Generate image paths + ansible.builtin.set_fact: + _cifmw_fdp_update_container_images_new_image_path_external: "{{ cifmw_fdp_update_container_images_image_registry }}/{{ cifmw_fdp_update_container_images_namespace }}/{{ cifmw_fdp_update_container_images_image_name_prefix }}-{{ image_entry.key | lower }}-{{ ansible_date_time.epoch }}" + _cifmw_fdp_update_container_images_new_image_path_internal: "{{ cifmw_fdp_update_container_images_image_registry_internal }}/{{ cifmw_fdp_update_container_images_namespace }}/{{ cifmw_fdp_update_container_images_image_name_prefix }}-{{ image_entry.key | lower }}-{{ ansible_date_time.epoch }}" + +- name: Build and push image + containers.podman.podman_image: + name: "{{ _cifmw_fdp_update_container_images_new_image_path_external }}" + path: "{{ _cifmw_fdp_update_container_images_temp_dir }}" + build: + file: "{{ _cifmw_fdp_update_container_images_temp_dir }}/Dockerfile" + push: true + push_args: + dest: "{{ _cifmw_fdp_update_container_images_new_image_path_external }}" + state: build + +- name: Patch OpenStackVersion CR + kubernetes.core.k8s: + state: patched + api_version: core.openstack.org/v1beta1 + kind: OpenStackVersion + name: "{{ cifmw_fdp_update_container_images_openstack_cr_name }}" + namespace: "{{ cifmw_fdp_update_container_images_namespace }}" + definition: + spec: + customContainerImages: "{{ { image_entry.key: _cifmw_fdp_update_container_images_new_image_path_internal } }}" + +- name: Update tracking + ansible.builtin.set_fact: + _cifmw_fdp_update_container_images_modified_images: "{{ _cifmw_fdp_update_container_images_modified_images + [image_entry.key ~ ': ' ~ _cifmw_fdp_update_container_images_new_image_path_internal] }}" + _cifmw_fdp_update_container_images_updated_cr_keys: "{{ _cifmw_fdp_update_container_images_updated_cr_keys + [image_entry.key] }}" + _cifmw_fdp_update_container_images_processed_images: "{{ _cifmw_fdp_update_container_images_processed_images | int + 1 }}" + +- name: Display progress + ansible.builtin.debug: + msg: "✓ Updated {{ image_entry.key }} ({{ _cifmw_fdp_update_container_images_processed_images }}/{{ _cifmw_fdp_update_container_images_image_entries | length }})" diff --git a/roles/fdp_update_container_images/tasks/validate.yml b/roles/fdp_update_container_images/tasks/validate.yml new file mode 100644 index 000000000..061632c22 --- /dev/null +++ b/roles/fdp_update_container_images/tasks/validate.yml @@ -0,0 +1,38 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Validate required parameters + ansible.builtin.assert: + that: + - cifmw_fdp_update_container_images_target_package is defined + - cifmw_fdp_update_container_images_target_package | length > 0 + - cifmw_fdp_update_container_images_repo_baseurl is defined + - cifmw_fdp_update_container_images_repo_baseurl | length > 0 + fail_msg: "Required: cifmw_fdp_update_container_images_target_package and cifmw_fdp_update_container_images_repo_baseurl" + +- name: Check oc command is available + ansible.builtin.command: oc version --client + changed_when: false + +- name: Create temporary directory + ansible.builtin.tempfile: + state: directory + prefix: "cifmw_fdp_update_build_" + register: _cifmw_fdp_update_container_images_temp_dir_result + +- name: Set temporary directory + ansible.builtin.set_fact: + _cifmw_fdp_update_container_images_temp_dir: "{{ cifmw_fdp_update_container_images_temp_dir if (cifmw_fdp_update_container_images_temp_dir is defined and cifmw_fdp_update_container_images_temp_dir | length > 0) else _cifmw_fdp_update_container_images_temp_dir_result.path }}" diff --git a/roles/fdp_update_container_images/templates/Dockerfile.j2 b/roles/fdp_update_container_images/templates/Dockerfile.j2 new file mode 100644 index 000000000..5a844f8ee --- /dev/null +++ b/roles/fdp_update_container_images/templates/Dockerfile.j2 @@ -0,0 +1,3 @@ +FROM {{ base_image }} +COPY ./{{ cifmw_fdp_update_container_images_repo_name }}.repo /etc/yum.repos.d/ +RUN dnf update -y {{ cifmw_fdp_update_container_images_update_dnf_args }} {{ cifmw_fdp_update_container_images_target_package }}* && dnf clean all diff --git a/roles/fdp_update_container_images/templates/repo.j2 b/roles/fdp_update_container_images/templates/repo.j2 new file mode 100644 index 000000000..cee92cf1b --- /dev/null +++ b/roles/fdp_update_container_images/templates/repo.j2 @@ -0,0 +1,7 @@ +[{{ cifmw_fdp_update_container_images_repo_name }}] +name={{ cifmw_fdp_update_container_images_repo_name }} +baseurl={{ cifmw_fdp_update_container_images_repo_baseurl }} +enabled={{ cifmw_fdp_update_container_images_repo_enabled }} +gpgcheck={{ cifmw_fdp_update_container_images_repo_gpgcheck }} +priority={{ cifmw_fdp_update_container_images_repo_priority }} +sslverify={{ cifmw_fdp_update_container_images_repo_sslverify }} diff --git a/roles/fdp_update_edpm/README.md b/roles/fdp_update_edpm/README.md new file mode 100644 index 000000000..7c94a14ae --- /dev/null +++ b/roles/fdp_update_edpm/README.md @@ -0,0 +1,185 @@ +# fdp_update_edpm + +Role for updating OpenStack EDPM (Edge Data Plane Management) nodes with custom container images and host packages. + +## Description + +This role provides a declarative approach to update EDPM nodes with: + +1. **Updates container images** by patching OpenStackDataPlaneNodeSet CRs with new image references +2. **Updates host packages** by configuring `edpm_bootstrap_packages` and `edpm_bootstrap_repos` in the nodeset +3. **Configures registry authentication** with OpenShift service account tokens +4. **Installs CA certificates** for secure registry access +5. **Optionally creates deployments** to apply the changes to EDPM nodes + +### Key Features + +- **Declarative approach**: Only modifies Kubernetes CRs, doesn't execute commands directly on EDPM nodes +- **Uses native EDPM capabilities**: Leverages `edpm_bootstrap` and `edpm_podman` roles from edpm-ansible +- **Secure by default**: Installs OpenShift CA certificates instead of using insecure registries +- **Flexible**: Supports updating containers, packages, or both +- **Idempotent**: Can be run multiple times safely + +## Requirements + +- OpenShift cluster with OpenStack operators installed +- Access to `oc` command +- OpenStackVersion CR with custom container images +- Custom repository with updated packages (if updating host packages) + +## Role Variables + +### General Configuration + +| Variable | Default | Description | +|----------|---------|-------------| +| `cifmw_fdp_update_edpm_namespace` | `"openstack"` | OpenShift namespace | +| `cifmw_fdp_update_edpm_nodeset_name` | `"all"` | NodeSet to update (`"all"` or specific name) | +| `cifmw_fdp_update_edpm_dry_run` | `false` | Show changes without applying | + +### Container Image Updates + +| Variable | Default | Description | +|----------|---------|-------------| +| `cifmw_fdp_update_edpm_containers_enabled` | `true` | Enable container image updates | +| `cifmw_fdp_update_edpm_image_registry` | `""` | External registry URL (auto-detected if empty) | +| `cifmw_fdp_update_edpm_image_variable_mapping` | See defaults | Mapping of image keys to EDPM variables | + +### Host Package Updates + +| Variable | Default | Description | +|----------|---------|-------------| +| `cifmw_fdp_update_edpm_packages_enabled` | `true` | Enable host package updates | +| `cifmw_fdp_update_edpm_repo_baseurl` | `""` | **REQUIRED** Repository base URL | +| `cifmw_fdp_update_edpm_repo_name` | `"fdp-update"` | Repository name | +| `cifmw_fdp_update_edpm_packages` | See defaults | List of packages to install/update | + +### Hypervisor Firewall Configuration + +| Variable | Default | Description | +|----------|---------|-------------| +| `cifmw_fdp_update_edpm_setup_hypervisor_firewall` | `true` | Enable/disable hypervisor firewall setup for registry access | +| `cifmw_fdp_update_edpm_hypervisor_host` | `"hypervisor"` | Hostname or inventory name of the hypervisor where firewall rules will be configured via delegate_to | +| `cifmw_fdp_update_compute_interface` | `"osp_trunk"` | Network interface on hypervisor connected to compute nodes (EDPM) | +| `cifmw_fdp_update_registry_interface` | `"ocpbm"` | Network interface on hypervisor connected to OpenShift/registry | +| `cifmw_fdp_update_compute_network` | `"192.168.122.0/24"` | Compute nodes network CIDR (source for NAT) | +| `cifmw_fdp_update_registry_network` | `"192.168.201.0/24"` | OpenShift/registry network CIDR (destination for NAT) | + +### Registry Configuration + +| Variable | Default | Description | +|----------|---------|-------------| +| `cifmw_fdp_update_edpm_configure_registry_ca` | `true` | Install OpenShift CA certificate via bootstrap command | +| `cifmw_fdp_update_edpm_configure_registry_auth` | `true` | Configure registry authentication | + +### Deployment Configuration + +| Variable | Default | Description | +|----------|---------|-------------| +| `cifmw_fdp_update_edpm_auto_deploy` | `true` | Automatically create deployment | +| `cifmw_fdp_update_edpm_deployment_per_nodeset` | `true` | Create separate deployment per nodeset | +| `cifmw_fdp_update_edpm_wait_for_deployment` | `true` | Wait for deployment to complete | +| `cifmw_fdp_update_edpm_deployment_timeout` | `3600` | Deployment timeout (seconds) | +| `cifmw_fdp_update_edpm_deployment_services` | See defaults | Services to run in deployment | + +## Dependencies + +None (uses native OpenStack Data Plane operators and edpm-ansible roles) + +## Example Playbook + +### Update both containers and packages + +```yaml +- hosts: localhost + roles: + - role: fdp_update_edpm + vars: + cifmw_fdp_update_edpm_namespace: openstack + cifmw_fdp_update_edpm_nodeset_name: openstack-edpm + cifmw_fdp_update_edpm_repo_baseurl: "http://example.com/repos/fdp-updates" + cifmw_fdp_update_edpm_packages: + - openvswitch3.5 + - openvswitch-selinux-extra-policy +``` + +### Update only containers + +```yaml +- hosts: localhost + roles: + - role: fdp_update_edpm + vars: + cifmw_fdp_update_edpm_packages_enabled: false + cifmw_fdp_update_edpm_containers_enabled: true +``` + +### Update only packages + +```yaml +- hosts: localhost + roles: + - role: fdp_update_edpm + vars: + cifmw_fdp_update_edpm_containers_enabled: false + cifmw_fdp_update_edpm_packages_enabled: true + cifmw_fdp_update_edpm_repo_baseurl: "http://example.com/repos/updates" +``` + +### Dry run (show changes without applying) + +```yaml +- hosts: localhost + roles: + - role: fdp_update_edpm + vars: + cifmw_fdp_update_edpm_dry_run: true +``` + +### Custom network configuration + +```yaml +- hosts: localhost + roles: + - role: fdp_update_edpm + vars: + cifmw_fdp_update_compute_interface: "br-ex" + cifmw_fdp_update_registry_interface: "br-ocp" + cifmw_fdp_update_compute_network: "10.0.0.0/24" + cifmw_fdp_update_registry_network: "172.16.0.0/24" +``` + +## How It Works + +1. **Validates parameters**: Ensures required variables are set +2. **Configures hypervisor firewall** (if enabled): Sets up iptables rules to allow EDPM nodes to access the OpenShift registry +3. **Fetches NodeSets**: Gets OpenStackDataPlaneNodeSet CRs from the cluster +4. **Fetches container images** (if enabled): Gets custom images from OpenStackVersion CR +5. **For each NodeSet**: + - Patches container image variables (e.g., `edpm_ovn_controller_agent_image`) + - Patches `edpm_bootstrap_packages` with packages to install + - Patches `edpm_bootstrap_repos` with custom repository configuration + - Configures registry authentication (`edpm_container_registry_logins`) + - Installs CA certificate via `edpm_bootstrap_command` (if enabled) +6. **Creates deployment** (if enabled): Creates OpenStackDataPlaneDeployment CR +7. **Waits for completion** (if enabled): Monitors deployment until Ready + +## Architecture: Declarative vs Imperative + +This role follows the **declarative** approach of Kubernetes/OpenStack: + +- [X] **Does NOT** SSH to nodes and run `dnf install` directly +- [X] **Does NOT** SSH to nodes and run `systemctl restart` directly +- [OK] **Does** patch NodeSet CRs with desired state +- [OK] **Does** let OpenStack Data Plane Operator apply the changes +- [OK] **Does** use native `edpm_bootstrap` role for package installation +- [OK] **Does** use native `edpm_podman` role for container management +- [OK] **Does** use `edpm_bootstrap_command` for CA certificate installation + +## License + +Apache 2.0 + +## Author Information + +Red Hat OpenStack CI Framework Team diff --git a/roles/fdp_update_edpm/defaults/main.yml b/roles/fdp_update_edpm/defaults/main.yml new file mode 100644 index 000000000..f0e902340 --- /dev/null +++ b/roles/fdp_update_edpm/defaults/main.yml @@ -0,0 +1,111 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# General Configuration +# OpenShift namespace where EDPM resources are deployed +cifmw_fdp_update_edpm_namespace: "openstack" + +# NodeSet selector - can be a specific name or 'all' for all nodesets +cifmw_fdp_update_edpm_nodeset_name: "all" + +# Dry run - show changes without applying +cifmw_fdp_update_edpm_dry_run: false + +# Container Image Updates +# Enable/disable container image updates +cifmw_fdp_update_edpm_containers_enabled: true + +# Image registry URL (auto-detected from OpenShift if empty) +cifmw_fdp_update_edpm_image_registry: "" + +# Mapping of control plane image keys to EDPM ansible variables +# Only ovnControllerImage is used on EDPM compute nodes +cifmw_fdp_update_edpm_image_variable_mapping: + ovnControllerImage: edpm_ovn_controller_agent_image + +# Host Package Updates +# Enable/disable host package updates +cifmw_fdp_update_edpm_packages_enabled: true + +# Repository configuration for host package updates +cifmw_fdp_update_edpm_repo_name: "fdp-update" +cifmw_fdp_update_edpm_repo_baseurl: "" # REQUIRED if packages_enabled is true +cifmw_fdp_update_edpm_repo_enabled: true +cifmw_fdp_update_edpm_repo_gpgcheck: false +cifmw_fdp_update_edpm_repo_priority: 1 + +# Packages to update on the host +# These will be added to edpm_bootstrap_packages in the nodeset +cifmw_fdp_update_edpm_packages: + - openvswitch3.5 + - openvswitch-selinux-extra-policy + +# Hypervisor Firewall Configuration +# Enable/disable hypervisor firewall setup for registry access +cifmw_fdp_update_edpm_setup_hypervisor_firewall: true + +# Network interface on hypervisor connected to compute nodes (EDPM) +cifmw_fdp_update_compute_interface: "osp_trunk" + +# Network interface on hypervisor connected to OpenShift/registry +cifmw_fdp_update_registry_interface: "ocpbm" + +# Compute nodes network CIDR (source for NAT) +cifmw_fdp_update_compute_network: "192.168.122.0/24" + +# OpenShift/registry network CIDR (destination for NAT) +cifmw_fdp_update_registry_network: "192.168.201.0/24" + +# Registry Configuration +# Configure OpenShift registry CA certificate on EDPM nodes +cifmw_fdp_update_edpm_configure_registry_ca: true + +# Configure registry authentication automatically +# Uses 'oc create token' or 'oc whoami -t' to get a service account token +cifmw_fdp_update_edpm_configure_registry_auth: true + +# Deployment Configuration +# Automatically create OpenStackDataPlaneDeployment after updating NodeSets +# Creates a single deployment for all updated NodeSets +cifmw_fdp_update_edpm_auto_deploy: true + +# Wait for deployment to complete before continuing +cifmw_fdp_update_edpm_wait_for_deployment: true + +# Timeout for deployment completion (in seconds) +# Default: 3600 seconds (60 minutes / 1 hour) +cifmw_fdp_update_edpm_deployment_timeout: 3600 + +# Polling interval when waiting for deployment (in seconds) +cifmw_fdp_update_edpm_deployment_poll_interval: 30 + +# Services to run in the deployment +# For updates, we need to: +# 1. bootstrap - Install host packages and configure repos +# 2. configure-os - Configure registry authentication +# 3. configure-network - Ensure network is configured +# 4. Service-specific services (ovn, nova, etc) - Pull updated images and restart +cifmw_fdp_update_edpm_deployment_services: + - bootstrap # MUST be first to install packages and configure repos + - configure-os # MUST be second to authenticate before pulling images + - configure-network + - ovn + +# Internal Variables (do not override) +_cifmw_fdp_update_edpm_updated_images: {} +_cifmw_fdp_update_edpm_nodesets: [] +_cifmw_fdp_update_edpm_updated_nodesets: [] +_cifmw_fdp_update_edpm_external_registry: "" diff --git a/roles/fdp_update_edpm/meta/main.yml b/roles/fdp_update_edpm/meta/main.yml new file mode 100644 index 000000000..3bfc3f70f --- /dev/null +++ b/roles/fdp_update_edpm/meta/main.yml @@ -0,0 +1,39 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +galaxy_info: + author: Red Hat + description: Update OpenStack EDPM container images and host packages with FDP updates + company: Red Hat + license: Apache-2.0 + min_ansible_version: "2.15" + platforms: + - name: Fedora + versions: + - all + - name: EL + versions: + - "9" + galaxy_tags: + - openstack + - edpm + - dataplane + - kubernetes + - openshift + - rpm + - containers + +dependencies: [] diff --git a/roles/fdp_update_edpm/tasks/cleanup_hypervisor_firewall.yml b/roles/fdp_update_edpm/tasks/cleanup_hypervisor_firewall.yml new file mode 100644 index 000000000..2539b93d6 --- /dev/null +++ b/roles/fdp_update_edpm/tasks/cleanup_hypervisor_firewall.yml @@ -0,0 +1,62 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# ============================================ +# Cleanup Hypervisor Firewall for Registry Access +# ============================================ +# This task removes iptables rules previously configured on the hypervisor +# to allow compute nodes (EDPM) to access the OpenShift registry. +# These rules should be cleaned up when tearing down the EDPM deployment. + +- name: Remove traffic rule from compute to registry interface + delegate_to: "{{ cifmw_fdp_update_edpm_hypervisor_host | default('hypervisor') }}" + become: true + ansible.builtin.iptables: + chain: FORWARD + in_interface: "{{ cifmw_fdp_update_compute_interface }}" + out_interface: "{{ cifmw_fdp_update_registry_interface }}" + jump: ACCEPT + state: absent + +- name: Remove return traffic rule from registry to compute interface + delegate_to: "{{ cifmw_fdp_update_edpm_hypervisor_host | default('hypervisor') }}" + become: true + ansible.builtin.iptables: + chain: FORWARD + in_interface: "{{ cifmw_fdp_update_registry_interface }}" + out_interface: "{{ cifmw_fdp_update_compute_interface }}" + ctstate: RELATED,ESTABLISHED + jump: ACCEPT + state: absent + +- name: Remove NAT rule for compute nodes to access registry + delegate_to: "{{ cifmw_fdp_update_edpm_hypervisor_host | default('hypervisor') }}" + become: true + ansible.builtin.iptables: + table: nat + chain: POSTROUTING + source: "{{ cifmw_fdp_update_compute_network }}" + destination: "{{ cifmw_fdp_update_registry_network }}" + out_interface: "{{ cifmw_fdp_update_registry_interface }}" + jump: MASQUERADE + state: absent + +- name: Persist firewall rules cleanup + delegate_to: "{{ cifmw_fdp_update_edpm_hypervisor_host | default('hypervisor') }}" + become: true + community.general.iptables_state: + state: saved + path: /etc/sysconfig/iptables diff --git a/roles/fdp_update_edpm/tasks/configure_ca_cert.yml b/roles/fdp_update_edpm/tasks/configure_ca_cert.yml new file mode 100644 index 000000000..6643b7522 --- /dev/null +++ b/roles/fdp_update_edpm/tasks/configure_ca_cert.yml @@ -0,0 +1,79 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# This file configures OpenShift registry CA certificate on EDPM nodes +# Embeds CA certificate installation in edpm_bootstrap_command + +- name: Get OpenShift ingress CA certificate + kubernetes.core.k8s_info: + api_version: v1 + kind: Secret + name: router-ca + namespace: openshift-ingress-operator + register: _cifmw_fdp_update_edpm_ca_cert_result + +- name: Decode CA certificate + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_ca_cert: "{{ _cifmw_fdp_update_edpm_ca_cert_result.resources[0].data['tls.crt'] | b64decode }}" + +- name: Get current edpm_bootstrap_command from nodeset + kubernetes.core.k8s_info: + api_version: dataplane.openstack.org/v1beta1 + kind: OpenStackDataPlaneNodeSet + name: "{{ _cifmw_fdp_update_edpm_current_nodeset_name }}" + namespace: "{{ cifmw_fdp_update_edpm_namespace }}" + register: _cifmw_fdp_update_edpm_current_bootstrap_result + failed_when: false + +- name: Check if CA certificate is already in bootstrap command + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_ca_already_present: "{{ (_cifmw_fdp_update_edpm_current_bootstrap_result.resources | length > 0) and ('openshift-registry-ca.crt' in (_cifmw_fdp_update_edpm_current_bootstrap_result.resources[0].spec.nodeTemplate.ansible.ansibleVars.edpm_bootstrap_command | default(''))) }}" + +- name: Get existing bootstrap command + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_existing_bootstrap: "{{ _cifmw_fdp_update_edpm_current_bootstrap_result.resources[0].spec.nodeTemplate.ansible.ansibleVars.edpm_bootstrap_command | default('') if (_cifmw_fdp_update_edpm_current_bootstrap_result.resources | length > 0) else '' }}" + +- name: Build bootstrap command with CA certificate installation (if not present) + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_bootstrap_with_ca: | + # Install OpenShift registry CA certificate + cat > /etc/pki/ca-trust/source/anchors/openshift-registry-ca.crt <<'EOF' + {{ _cifmw_fdp_update_edpm_ca_cert }} + EOF + update-ca-trust extract + + {{ _cifmw_fdp_update_edpm_existing_bootstrap }} + when: not _cifmw_fdp_update_edpm_ca_already_present + +- name: Keep existing bootstrap command (CA already present) + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_bootstrap_with_ca: "{{ _cifmw_fdp_update_edpm_existing_bootstrap }}" + when: _cifmw_fdp_update_edpm_ca_already_present + +- name: Patch NodeSet with updated bootstrap command + kubernetes.core.k8s: + state: patched + api_version: dataplane.openstack.org/v1beta1 + kind: OpenStackDataPlaneNodeSet + name: "{{ _cifmw_fdp_update_edpm_current_nodeset_name }}" + namespace: "{{ cifmw_fdp_update_edpm_namespace }}" + definition: + spec: + nodeTemplate: + ansible: + ansibleVars: + edpm_bootstrap_command: "{{ _cifmw_fdp_update_edpm_bootstrap_with_ca }}" + when: not cifmw_fdp_update_edpm_dry_run diff --git a/roles/fdp_update_edpm/tasks/create_deployment.yml b/roles/fdp_update_edpm/tasks/create_deployment.yml new file mode 100644 index 000000000..ed17139a3 --- /dev/null +++ b/roles/fdp_update_edpm/tasks/create_deployment.yml @@ -0,0 +1,61 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Set deployment name + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_deployment_name: "edpm-fdp-update-{{ ansible_date_time.epoch }}" + +- name: Create OpenStackDataPlaneDeployment + kubernetes.core.k8s: + state: present + api_version: dataplane.openstack.org/v1beta1 + kind: OpenStackDataPlaneDeployment + definition: + metadata: + name: "{{ _cifmw_fdp_update_edpm_deployment_name }}" + namespace: "{{ cifmw_fdp_update_edpm_namespace }}" + spec: + nodeSets: "{{ _cifmw_fdp_update_edpm_updated_nodesets }}" + servicesOverride: "{{ cifmw_fdp_update_edpm_deployment_services }}" + +- name: Display deployment information + ansible.builtin.debug: + msg: + - "Created deployment: {{ _cifmw_fdp_update_edpm_deployment_name }}" + - "NodeSets: {{ _cifmw_fdp_update_edpm_updated_nodesets }}" + - "Services: {{ cifmw_fdp_update_edpm_deployment_services }}" + +- name: Wait for deployment to complete + when: cifmw_fdp_update_edpm_wait_for_deployment | bool + block: + - name: Wait for deployment Ready condition + kubernetes.core.k8s_info: + api_version: dataplane.openstack.org/v1beta1 + kind: OpenStackDataPlaneDeployment + name: "{{ _cifmw_fdp_update_edpm_deployment_name }}" + namespace: "{{ cifmw_fdp_update_edpm_namespace }}" + register: _cifmw_fdp_update_edpm_deployment_result + until: >- + _cifmw_fdp_update_edpm_deployment_result.resources | length > 0 and + _cifmw_fdp_update_edpm_deployment_result.resources[0].status.conditions | + selectattr('type', 'equalto', 'Ready') | + map(attribute='status') | first | default('False') == 'True' + retries: "{{ (cifmw_fdp_update_edpm_deployment_timeout / cifmw_fdp_update_edpm_deployment_poll_interval) | int }}" + delay: "{{ cifmw_fdp_update_edpm_deployment_poll_interval }}" + + - name: Display deployment completion + ansible.builtin.debug: + msg: "Deployment {{ _cifmw_fdp_update_edpm_deployment_name }} completed successfully" diff --git a/roles/fdp_update_edpm/tasks/fetch_nodesets.yml b/roles/fdp_update_edpm/tasks/fetch_nodesets.yml new file mode 100644 index 000000000..7c2f4fb08 --- /dev/null +++ b/roles/fdp_update_edpm/tasks/fetch_nodesets.yml @@ -0,0 +1,32 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Get OpenStackDataPlaneNodeSets + kubernetes.core.k8s_info: + api_version: dataplane.openstack.org/v1beta1 + kind: OpenStackDataPlaneNodeSet + name: "{{ cifmw_fdp_update_edpm_nodeset_name if cifmw_fdp_update_edpm_nodeset_name != 'all' else omit }}" + namespace: "{{ cifmw_fdp_update_edpm_namespace }}" + register: _cifmw_fdp_update_edpm_nodesets_result + +- name: Parse NodeSets + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_nodesets: "{{ _cifmw_fdp_update_edpm_nodesets_result.resources }}" + +- name: Fail if no NodeSets found + ansible.builtin.fail: + msg: "No OpenStackDataPlaneNodeSets found in namespace {{ cifmw_fdp_update_edpm_namespace }}" + when: _cifmw_fdp_update_edpm_nodesets | length == 0 diff --git a/roles/fdp_update_edpm/tasks/main.yml b/roles/fdp_update_edpm/tasks/main.yml new file mode 100644 index 000000000..ca80f65b8 --- /dev/null +++ b/roles/fdp_update_edpm/tasks/main.yml @@ -0,0 +1,59 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# Validate and Initialize +- name: Validate parameters and initialize + ansible.builtin.include_tasks: validate.yml + +# Setup Hypervisor Firewall +- name: Setup hypervisor firewall for registry access + ansible.builtin.include_tasks: setup_hypervisor_firewall.yml + when: cifmw_fdp_update_edpm_setup_hypervisor_firewall | default(true) | bool + +# Fetch NodeSets +- name: Fetch EDPM NodeSets + ansible.builtin.include_tasks: fetch_nodesets.yml + +# Update Container Images (Optional) +- name: Update container images + when: cifmw_fdp_update_edpm_containers_enabled | bool + ansible.builtin.include_tasks: update_container_images.yml + +# Process Each NodeSet +- name: Process each NodeSet + ansible.builtin.include_tasks: process_nodeset.yml + loop: "{{ _cifmw_fdp_update_edpm_nodesets }}" + loop_control: + loop_var: nodeset + label: "{{ nodeset.metadata.name }}" + +# Deploy Updates to EDPM Nodes (Optional) +- name: Deploy updates to EDPM nodes + when: + - cifmw_fdp_update_edpm_auto_deploy | bool + - not cifmw_fdp_update_edpm_dry_run | bool + - _cifmw_fdp_update_edpm_updated_nodesets | length > 0 + ansible.builtin.include_tasks: create_deployment.yml + +# Summary +- name: Display update summary + ansible.builtin.debug: + msg: + - "EDPM Update Summary" + - "Updated {{ _cifmw_fdp_update_edpm_updated_nodesets | length }} NodeSet(s): {{ _cifmw_fdp_update_edpm_updated_nodesets }}" + - "Container images updated: {{ cifmw_fdp_update_edpm_containers_enabled }}" + - "Host packages updated: {{ cifmw_fdp_update_edpm_packages_enabled }}" + when: not cifmw_fdp_update_edpm_dry_run diff --git a/roles/fdp_update_edpm/tasks/process_nodeset.yml b/roles/fdp_update_edpm/tasks/process_nodeset.yml new file mode 100644 index 000000000..a218f2bd5 --- /dev/null +++ b/roles/fdp_update_edpm/tasks/process_nodeset.yml @@ -0,0 +1,139 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Set NodeSet name + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_current_nodeset_name: "{{ nodeset.metadata.name }}" + +# Patch Container Images +- name: Patch container images in nodeset + when: + - cifmw_fdp_update_edpm_containers_enabled | bool + - _cifmw_fdp_update_edpm_updated_images | length > 0 + block: + - name: Initialize EDPM image variables patch + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_image_vars_patch: {} + + - name: Add each EDPM variable to patch + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_image_vars_patch: >- + {{ + _cifmw_fdp_update_edpm_image_vars_patch | combine({ + cifmw_fdp_update_edpm_image_variable_mapping[item.key]: item.value + }) + }} + loop: "{{ _cifmw_fdp_update_edpm_updated_images | dict2items }}" + loop_control: + label: "{{ item.key }}" + + - name: Apply container images using k8s patch + kubernetes.core.k8s: + state: patched + api_version: dataplane.openstack.org/v1beta1 + kind: OpenStackDataPlaneNodeSet + name: "{{ _cifmw_fdp_update_edpm_current_nodeset_name }}" + namespace: "{{ cifmw_fdp_update_edpm_namespace }}" + definition: + spec: + nodeTemplate: + ansible: + ansibleVars: "{{ _cifmw_fdp_update_edpm_image_vars_patch }}" + when: + - not cifmw_fdp_update_edpm_dry_run + - _cifmw_fdp_update_edpm_image_vars_patch | length > 0 + +# Patch Host Packages and Repositories +- name: Patch host packages and repositories in nodeset + when: cifmw_fdp_update_edpm_packages_enabled | bool + ansible.builtin.include_tasks: update_host_packages.yml + +# Configure Registry Authentication +- name: Configure registry authentication + when: + - not cifmw_fdp_update_edpm_dry_run + - cifmw_fdp_update_edpm_configure_registry_auth | bool + - _cifmw_fdp_update_edpm_external_registry is defined + - _cifmw_fdp_update_edpm_external_registry | length > 0 + block: + - name: Get authentication token for OpenShift registry + ansible.builtin.command: oc whoami -t + register: _cifmw_fdp_update_edpm_oc_token_result + changed_when: false + + - name: Get existing registry logins + kubernetes.core.k8s_info: + api_version: dataplane.openstack.org/v1beta1 + kind: OpenStackDataPlaneNodeSet + name: "{{ _cifmw_fdp_update_edpm_current_nodeset_name }}" + namespace: "{{ cifmw_fdp_update_edpm_namespace }}" + register: _cifmw_fdp_update_edpm_current_logins_result + failed_when: false + + - name: Initialize existing registry logins as empty + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_existing_logins: {} + + - name: Extract existing registry logins from NodeSet + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_existing_logins: >- + {{ + _cifmw_fdp_update_edpm_current_logins_result.resources[0].spec.nodeTemplate.ansible.ansibleVars.edpm_container_registry_logins | default({}) + }} + when: _cifmw_fdp_update_edpm_current_logins_result.resources | length > 0 + + - name: Configure registry authentication with token + when: _cifmw_fdp_update_edpm_oc_token_result.stdout | length > 0 + block: + - name: Merge with new registry login + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_merged_logins: >- + {{ + _cifmw_fdp_update_edpm_existing_logins | combine({ + _cifmw_fdp_update_edpm_external_registry: { + 'serviceaccount': _cifmw_fdp_update_edpm_oc_token_result.stdout + } + }) + }} + + - name: Build registry authentication patch + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_registry_auth_patch: + spec: + nodeTemplate: + ansible: + ansibleVars: + edpm_container_registry_logins: "{{ _cifmw_fdp_update_edpm_merged_logins }}" + + - name: Apply registry authentication configuration + kubernetes.core.k8s: + state: patched + api_version: dataplane.openstack.org/v1beta1 + kind: OpenStackDataPlaneNodeSet + name: "{{ _cifmw_fdp_update_edpm_current_nodeset_name }}" + namespace: "{{ cifmw_fdp_update_edpm_namespace }}" + definition: "{{ _cifmw_fdp_update_edpm_registry_auth_patch }}" + +# Configure Registry CA Certificate +- name: Configure registry CA certificate + when: cifmw_fdp_update_edpm_configure_registry_ca | bool + ansible.builtin.include_tasks: configure_ca_cert.yml + +# Record NodeSet as Processed +- name: Record NodeSet as processed + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_updated_nodesets: "{{ _cifmw_fdp_update_edpm_updated_nodesets + [_cifmw_fdp_update_edpm_current_nodeset_name] }}" + when: not cifmw_fdp_update_edpm_dry_run diff --git a/roles/fdp_update_edpm/tasks/setup_hypervisor_firewall.yml b/roles/fdp_update_edpm/tasks/setup_hypervisor_firewall.yml new file mode 100644 index 000000000..61bf370e1 --- /dev/null +++ b/roles/fdp_update_edpm/tasks/setup_hypervisor_firewall.yml @@ -0,0 +1,63 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# ============================================ +# Setup Hypervisor Firewall for Registry Access +# ============================================ +# This task configures iptables rules on the hypervisor to allow +# compute nodes (EDPM) to access the OpenShift registry for pulling +# container images during FDP updates. + +- name: Allow traffic from compute to registry interface + delegate_to: "{{ cifmw_fdp_update_edpm_hypervisor_host | default('hypervisor') }}" + become: true + ansible.builtin.iptables: + chain: FORWARD + in_interface: "{{ cifmw_fdp_update_compute_interface }}" + out_interface: "{{ cifmw_fdp_update_registry_interface }}" + jump: ACCEPT + action: insert + rule_num: '1' + +- name: Allow return traffic from registry to compute interface + delegate_to: "{{ cifmw_fdp_update_edpm_hypervisor_host | default('hypervisor') }}" + become: true + ansible.builtin.iptables: + chain: FORWARD + in_interface: "{{ cifmw_fdp_update_registry_interface }}" + out_interface: "{{ cifmw_fdp_update_compute_interface }}" + ctstate: RELATED,ESTABLISHED + jump: ACCEPT + action: insert + rule_num: '1' + +- name: Enable NAT for compute nodes to access registry + delegate_to: "{{ cifmw_fdp_update_edpm_hypervisor_host | default('hypervisor') }}" + become: true + ansible.builtin.iptables: + table: nat + chain: POSTROUTING + source: "{{ cifmw_fdp_update_compute_network }}" + destination: "{{ cifmw_fdp_update_registry_network }}" + out_interface: "{{ cifmw_fdp_update_registry_interface }}" + jump: MASQUERADE + +- name: Persist firewall rules + delegate_to: "{{ cifmw_fdp_update_edpm_hypervisor_host | default('hypervisor') }}" + become: true + community.general.iptables_state: + state: saved + path: /etc/sysconfig/iptables diff --git a/roles/fdp_update_edpm/tasks/update_container_images.yml b/roles/fdp_update_edpm/tasks/update_container_images.yml new file mode 100644 index 000000000..dda665e23 --- /dev/null +++ b/roles/fdp_update_edpm/tasks/update_container_images.yml @@ -0,0 +1,89 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# Fetch Updated Container Images +- name: Get OpenStackVersion CR list + kubernetes.core.k8s_info: + api_version: core.openstack.org/v1beta1 + kind: OpenStackVersion + namespace: "{{ cifmw_fdp_update_edpm_namespace }}" + register: _cifmw_fdp_update_edpm_osv_result + +- name: Fail if no OpenStackVersion CR found + ansible.builtin.fail: + msg: "No OpenStackVersion CR found in namespace {{ cifmw_fdp_update_edpm_namespace }}" + when: _cifmw_fdp_update_edpm_osv_result.resources | length == 0 + +- name: Parse and filter EDPM-relevant custom images + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_updated_images: >- + {{ + (_cifmw_fdp_update_edpm_osv_result.resources[0].spec.customContainerImages | default({})) | dict2items | + selectattr('key', 'in', cifmw_fdp_update_edpm_image_variable_mapping.keys()) | + items2dict + }} + +- name: Fail if no EDPM container images found + ansible.builtin.fail: + msg: | + No EDPM container images found in OpenStackVersion CR. + The OpenStackVersion CR must contain customContainerImages with EDPM-relevant images. + Expected image keys: {{ cifmw_fdp_update_edpm_image_variable_mapping.keys() | list }} + when: _cifmw_fdp_update_edpm_updated_images | length == 0 + +# Convert Internal Registry URLs to External +- name: Convert internal registry URLs to external for EDPM compute nodes + block: + - name: Determine external registry URL + block: + - name: Try to auto-detect registry route if not configured + kubernetes.core.k8s_info: + api_version: route.openshift.io/v1 + kind: Route + name: default-route + namespace: openshift-image-registry + register: _cifmw_fdp_update_edpm_registry_route_result + failed_when: false + when: cifmw_fdp_update_edpm_image_registry is not defined or cifmw_fdp_update_edpm_image_registry | length == 0 + + - name: Set external registry URL + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_external_registry: >- + {%- if cifmw_fdp_update_edpm_image_registry is defined and cifmw_fdp_update_edpm_image_registry | length > 0 -%} + {{ cifmw_fdp_update_edpm_image_registry }} + {%- elif _cifmw_fdp_update_edpm_registry_route_result.resources | default([]) | length > 0 -%} + {{ _cifmw_fdp_update_edpm_registry_route_result.resources[0].spec.host }} + {%- else -%} + UNDEFINED + {%- endif -%} + + - name: Fail if no external registry URL could be determined + ansible.builtin.fail: + msg: | + Cannot determine external registry URL! + EDPM compute nodes require an external registry URL to pull images. + Please set: cifmw_fdp_update_edpm_image_registry + when: _cifmw_fdp_update_edpm_external_registry == 'UNDEFINED' + + - name: Convert URLs (handle all internal registry variations) + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_updated_images: "{{ dict(_cifmw_fdp_update_edpm_updated_images.keys() | zip(_cifmw_fdp_update_edpm_updated_images.values() | map('regex_replace', 'image-registry\\.openshift-image-registry\\.svc\\.cluster\\.local:5000', _cifmw_fdp_update_edpm_external_registry) | map('regex_replace', 'image-registry\\.openshift-image-registry\\.svc:5000', _cifmw_fdp_update_edpm_external_registry) | list)) }}" + +- name: Display container images to update + ansible.builtin.debug: + msg: + - "Container images found in OpenStackVersion CR:" + - "{{ _cifmw_fdp_update_edpm_updated_images }}" diff --git a/roles/fdp_update_edpm/tasks/update_host_packages.yml b/roles/fdp_update_edpm/tasks/update_host_packages.yml new file mode 100644 index 000000000..99fb83683 --- /dev/null +++ b/roles/fdp_update_edpm/tasks/update_host_packages.yml @@ -0,0 +1,93 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# This file patches the nodeset with edpm_bootstrap_* variables +# The actual package installation happens during deployment via edpm_bootstrap role + +# Get Current Bootstrap Configuration +- name: Get current bootstrap configuration from nodeset + kubernetes.core.k8s_info: + api_version: dataplane.openstack.org/v1beta1 + kind: OpenStackDataPlaneNodeSet + name: "{{ _cifmw_fdp_update_edpm_current_nodeset_name }}" + namespace: "{{ cifmw_fdp_update_edpm_namespace }}" + register: _cifmw_fdp_update_edpm_current_bootstrap_result + failed_when: false + +# Merge New Packages with Existing +- name: Parse current bootstrap packages + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_bootstrap_packages_list: >- + {{ + _cifmw_fdp_update_edpm_current_bootstrap_result.resources[0].spec.nodeTemplate.ansible.ansibleVars.edpm_bootstrap_packages | default([]) + if (_cifmw_fdp_update_edpm_current_bootstrap_result.resources | length > 0) + else [] + }} + +- name: Merge new packages with existing packages + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_merged_packages: "{{ (_cifmw_fdp_update_edpm_bootstrap_packages_list + cifmw_fdp_update_edpm_packages) | unique }}" + +# Build Repository Configuration +- name: Parse current bootstrap repos + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_bootstrap_repos_list: >- + {{ + _cifmw_fdp_update_edpm_current_bootstrap_result.resources[0].spec.nodeTemplate.ansible.ansibleVars.edpm_bootstrap_repos | default([]) + if (_cifmw_fdp_update_edpm_current_bootstrap_result.resources | length > 0) + else [] + }} + +- name: Remove existing repo if it exists + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_bootstrap_repos_list: "{{ _cifmw_fdp_update_edpm_bootstrap_repos_list | rejectattr('name', 'equalto', cifmw_fdp_update_edpm_repo_name) | list }}" + when: _cifmw_fdp_update_edpm_bootstrap_repos_list | selectattr('name', 'equalto', cifmw_fdp_update_edpm_repo_name) | list | length > 0 + +- name: Add new repo to repos list + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_merged_repos: >- + {{ + _cifmw_fdp_update_edpm_bootstrap_repos_list + [{ + 'name': cifmw_fdp_update_edpm_repo_name, + 'baseurl': cifmw_fdp_update_edpm_repo_baseurl, + 'enabled': cifmw_fdp_update_edpm_repo_enabled | int, + 'gpgcheck': cifmw_fdp_update_edpm_repo_gpgcheck | int, + 'priority': cifmw_fdp_update_edpm_repo_priority + }] + }} + +# Patch NodeSet with Bootstrap Configuration +- name: Patch nodeset with bootstrap packages and repos + kubernetes.core.k8s: + state: patched + api_version: dataplane.openstack.org/v1beta1 + kind: OpenStackDataPlaneNodeSet + name: "{{ _cifmw_fdp_update_edpm_current_nodeset_name }}" + namespace: "{{ cifmw_fdp_update_edpm_namespace }}" + definition: + spec: + nodeTemplate: + ansible: + ansibleVars: + edpm_bootstrap_packages: "{{ _cifmw_fdp_update_edpm_merged_packages }}" + edpm_bootstrap_repos: "{{ _cifmw_fdp_update_edpm_merged_repos }}" + when: not cifmw_fdp_update_edpm_dry_run + +- name: Display packages and repos configuration + ansible.builtin.debug: + msg: + - "Packages to install on host: {{ _cifmw_fdp_update_edpm_merged_packages }}" + - "Repositories configured: {{ _cifmw_fdp_update_edpm_merged_repos | map(attribute='name') | list }}" diff --git a/roles/fdp_update_edpm/tasks/validate.yml b/roles/fdp_update_edpm/tasks/validate.yml new file mode 100644 index 000000000..795c3a012 --- /dev/null +++ b/roles/fdp_update_edpm/tasks/validate.yml @@ -0,0 +1,27 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Validate package update configuration + ansible.builtin.assert: + that: + - cifmw_fdp_update_edpm_repo_baseurl is defined + - cifmw_fdp_update_edpm_repo_baseurl | length > 0 + fail_msg: "Package updates require: cifmw_fdp_update_edpm_repo_baseurl" + when: cifmw_fdp_update_edpm_packages_enabled | bool + +- name: Verify oc command is available + ansible.builtin.command: oc version --client + changed_when: false diff --git a/roles/federation/OWNERS b/roles/federation/OWNERS new file mode 100644 index 000000000..e74ebe306 --- /dev/null +++ b/roles/federation/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - security-team + +reviewers: + - security-team diff --git a/roles/federation/tasks/hook_multirealm_controlplane_config.yml b/roles/federation/tasks/hook_multirealm_controlplane_config.yml index 5e5ca60e7..eb2421dd3 100644 --- a/roles/federation/tasks/hook_multirealm_controlplane_config.yml +++ b/roles/federation/tasks/hook_multirealm_controlplane_config.yml @@ -153,6 +153,6 @@ type: Opaque metadata: name: federation-realm-data - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" stringData: federation-config.json: "{{ federation_config_json_string }}" diff --git a/roles/hci_prepare/molecule/default/converge.yml b/roles/hci_prepare/molecule/default/converge.yml index acf186080..a4ba3f0c9 100644 --- a/roles/hci_prepare/molecule/default/converge.yml +++ b/roles/hci_prepare/molecule/default/converge.yml @@ -17,7 +17,6 @@ - name: Converge hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_basedir: "{{ ansible_user_dir }}/ci-framework-data" cifmw_path: "/path/to/bin" cifmw_openshift_kubeconfig: "path/to/kubeconfig" diff --git a/roles/hive/molecule/default/converge.yml b/roles/hive/molecule/default/converge.yml index 1617ee4d4..abaaf5315 100644 --- a/roles/hive/molecule/default/converge.yml +++ b/roles/hive/molecule/default/converge.yml @@ -18,7 +18,6 @@ hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_path: "{{ ansible_user_dir }}/.crc/bin:{{ ansible_user_dir }}/.crc/bin/oc:{{ ansible_user_dir }}/bin:{{ ansible_env.PATH }}" cifmw_hive_artifacts_dir: "{{ ansible_user_dir }}/ci-framework-data" cifmw_hive_kubeconfig: test_path diff --git a/roles/hive/molecule/default/prepare.yml b/roles/hive/molecule/default/prepare.yml index 1e1fb6b25..08cf3aefb 100644 --- a/roles/hive/molecule/default/prepare.yml +++ b/roles/hive/molecule/default/prepare.yml @@ -19,7 +19,6 @@ hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_path: "{{ ansible_user_dir }}/.crc/bin:{{ ansible_user_dir }}/.crc/bin/oc:{{ ansible_user_dir }}/bin:{{ ansible_env.PATH }}" roles: diff --git a/roles/idrac_configuration/OWNERS b/roles/idrac_configuration/OWNERS new file mode 100644 index 000000000..7a15ba5da --- /dev/null +++ b/roles/idrac_configuration/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - nfv-team + +reviewers: + - nfv-team diff --git a/roles/install_ca/molecule/default/converge.yml b/roles/install_ca/molecule/default/converge.yml index c6e721910..5479b74b4 100644 --- a/roles/install_ca/molecule/default/converge.yml +++ b/roles/install_ca/molecule/default/converge.yml @@ -17,8 +17,6 @@ - name: Converge hosts: all - vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" tasks: - name: Run role without any CA ansible.builtin.include_role: diff --git a/roles/install_ca/molecule/default/prepare.yml b/roles/install_ca/molecule/default/prepare.yml index f845024f5..8e568ef5c 100644 --- a/roles/install_ca/molecule/default/prepare.yml +++ b/roles/install_ca/molecule/default/prepare.yml @@ -18,7 +18,6 @@ - name: Prepare hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_install_yamls_defaults: NAMESPACE: openstack roles: diff --git a/roles/install_openstack_ca/molecule/default/files/minimal_openstack_controlplane.yml b/roles/install_openstack_ca/molecule/default/files/minimal_openstack_controlplane.yml index 0033e1c3c..c7be49af1 100644 --- a/roles/install_openstack_ca/molecule/default/files/minimal_openstack_controlplane.yml +++ b/roles/install_openstack_ca/molecule/default/files/minimal_openstack_controlplane.yml @@ -2,7 +2,7 @@ apiVersion: core.openstack.org/v1beta1 kind: OpenStackControlPlane metadata: name: openstack-galera - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" spec: barbican: enabled: false diff --git a/roles/install_openstack_ca/tasks/main.yml b/roles/install_openstack_ca/tasks/main.yml index 1dbaf5b6b..6523b994b 100644 --- a/roles/install_openstack_ca/tasks/main.yml +++ b/roles/install_openstack_ca/tasks/main.yml @@ -23,7 +23,7 @@ KUBECONFIG: "{{ cifmw_openshift_kubeconfig }}" PATH: "{{ cifmw_path }}" ansible.builtin.command: - cmd: 'oc get secret combined-ca-bundle -n openstack -o "jsonpath={.data.tls-ca-bundle\.pem}"' + cmd: 'oc get secret combined-ca-bundle -n {{ cifmw_openstack_namespace }} -o "jsonpath={.data.tls-ca-bundle\.pem}"' retries: 10 no_log: true delay: 3 diff --git a/roles/install_yamls/molecule/default/converge.yml b/roles/install_yamls/molecule/default/converge.yml index 1835746df..361b15774 100644 --- a/roles/install_yamls/molecule/default/converge.yml +++ b/roles/install_yamls/molecule/default/converge.yml @@ -21,7 +21,6 @@ cifmw_install_yamls_vars: namespace: foobar openstack_ctlplane: controlplane-yaml-file.yaml - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_install_yamls_repo: "{{ cifmw_installyamls_repos }}" zuul: branch: main diff --git a/roles/install_yamls/tasks/main.yml b/roles/install_yamls/tasks/main.yml index de8ac8dde..5a18eccb8 100644 --- a/roles/install_yamls/tasks/main.yml +++ b/roles/install_yamls/tasks/main.yml @@ -152,7 +152,7 @@ tags: - bootstrap register: cifmw_generate_makes - generate_make_tasks: + cifmw.general.generate_make_tasks: install_yamls_path: "{{ cifmw_install_yamls_repo }}" output_directory: "{{ cifmw_install_yamls_tasks_out }}" diff --git a/roles/ipa/OWNERS b/roles/ipa/OWNERS new file mode 100644 index 000000000..e74ebe306 --- /dev/null +++ b/roles/ipa/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - security-team + +reviewers: + - security-team diff --git a/roles/kustomize_deploy/README.md b/roles/kustomize_deploy/README.md index 0cd373b7a..c94068e09 100644 --- a/roles/kustomize_deploy/README.md +++ b/roles/kustomize_deploy/README.md @@ -101,6 +101,7 @@ with a message. Some tasks uses timeouts when applying or waiting for resources. Those timeouts can be controlled by: * `cifmw_kustomize_deploy_delay`: (Int) Ansible `delay` passed to tasks that waits for a resource to reach a target state (default `10`) +* `cifmw_kustomize_deploy_retries_subscription`: (Int) Ansible `retries` passed to tasks that wait for the Subscription (default `90`) * `cifmw_kustomize_deploy_retries_install_plan`: (Int) Ansible `retries` passed to tasks that wait for the InstallPlan (default `60`) ### Task tagging diff --git a/roles/kustomize_deploy/defaults/main.yml b/roles/kustomize_deploy/defaults/main.yml index 8b42ff26d..653c4440c 100644 --- a/roles/kustomize_deploy/defaults/main.yml +++ b/roles/kustomize_deploy/defaults/main.yml @@ -222,6 +222,7 @@ cifmw_kustomize_deploy_dp_dest_file: >- # timeouts and retry configuration cifmw_kustomize_deploy_delay: 10 +cifmw_kustomize_deploy_retries_subscription: 90 cifmw_kustomize_deploy_retries_install_plan: 60 # Default retry settings for k8s_info operations to handle transient auth failures diff --git a/roles/kustomize_deploy/tasks/install_operators.yml b/roles/kustomize_deploy/tasks/install_operators.yml index fcf3650b4..981e19153 100644 --- a/roles/kustomize_deploy/tasks/install_operators.yml +++ b/roles/kustomize_deploy/tasks/install_operators.yml @@ -47,16 +47,19 @@ ansible.builtin.include_role: name: ci_gen_kustomize_values -- name: Copy generated values.yaml for OLM resources - ansible.builtin.copy: - backup: true - remote_src: true +- name: Slurp generated values.yaml for OLM resources + ansible.builtin.slurp: src: >- {{ (cifmw_kustomize_deploy_basedir, 'artifacts', 'ci_gen_kustomize_values', 'olm-values', 'values.yaml') | path_join }} + register: _cifmw_kustomize_deploy_olm_values_content + +- name: Copy generated values.yaml for OLM resources to localhost + ansible.builtin.copy: + content: "{{ _cifmw_kustomize_deploy_olm_values_content.content | b64decode }}" dest: >- {{ ( @@ -65,6 +68,7 @@ ) | path_join }} mode: "0644" + delegate_to: localhost - name: Generate the OLM kustomization file ansible.builtin.copy: @@ -91,9 +95,9 @@ src: "{{ cifmw_kustomize_deploy_olm_dest_file }}" register: _cifmw_kustomize_deploy_olm_apply_out - - name: Wait for the openstack operators InstallPlan to be created + - name: Wait for the openstack operators Subscription to be created vars: - _cifmw_kustomize_deploy_olm_osp_operator_sub: >- + _cifmw_kustomize_deploy_olm_osp_operator_subscription: >- {{ ( _cifmw_kustomize_deploy_olm_apply_out.result.results | @@ -108,18 +112,18 @@ kubeconfig: "{{ cifmw_openshift_kubeconfig }}" api_key: "{{ cifmw_openshift_token | default(omit) }}" context: "{{ cifmw_openshift_context | default(omit) }}" - api_version: "{{ _cifmw_kustomize_deploy_olm_osp_operator_sub.apiVersion }}" + api_version: "{{ _cifmw_kustomize_deploy_olm_osp_operator_subscription.apiVersion }}" kind: Subscription - namespace: "{{ _cifmw_kustomize_deploy_olm_osp_operator_sub.metadata.namespace }}" - name: "{{ _cifmw_kustomize_deploy_olm_osp_operator_sub.metadata.name }}" - register: _cifmw_kustomize_deploy_olm_osp_operator_sub_out - retries: "{{ cifmw_kustomize_deploy_retries_install_plan }}" + namespace: "{{ _cifmw_kustomize_deploy_olm_osp_operator_subscription.metadata.namespace }}" + name: "{{ _cifmw_kustomize_deploy_olm_osp_operator_subscription.metadata.name }}" + register: _cifmw_kustomize_deploy_olm_osp_operator_subscription_out + retries: "{{ cifmw_kustomize_deploy_retries_subscription }}" delay: "{{ cifmw_kustomize_deploy_delay }}" until: - - _cifmw_kustomize_deploy_olm_osp_operator_sub_out.failed is false - - _cifmw_kustomize_deploy_olm_osp_operator_sub_out.resources is defined - - _cifmw_kustomize_deploy_olm_osp_operator_sub_out.resources | length == 1 - - (_cifmw_kustomize_deploy_olm_osp_operator_sub_out.resources | first)['status']['installPlanRef'] is defined + - _cifmw_kustomize_deploy_olm_osp_operator_subscription_out.failed is false + - _cifmw_kustomize_deploy_olm_osp_operator_subscription_out.resources is defined + - _cifmw_kustomize_deploy_olm_osp_operator_subscription_out.resources | length == 1 + - (_cifmw_kustomize_deploy_olm_osp_operator_subscription_out.resources | first)['status']['installPlanRef'] is defined - name: Install plan ansible.builtin.include_tasks: install_plan.yml @@ -131,7 +135,7 @@ vars: _install_plan: >- {{ - (_cifmw_kustomize_deploy_olm_osp_operator_sub_out.resources | first).status.installPlanRef + (_cifmw_kustomize_deploy_olm_osp_operator_subscription_out.resources | first).status.installPlanRef }} kubernetes.core.k8s_info: kubeconfig: "{{ cifmw_openshift_kubeconfig }}" diff --git a/roles/libvirt_manager/README.md b/roles/libvirt_manager/README.md index e5aa0e530..dc3aefce9 100644 --- a/roles/libvirt_manager/README.md +++ b/roles/libvirt_manager/README.md @@ -45,6 +45,7 @@ Used for checking if: * `cifmw_libvirt_manager_default_gw_nets`: (List[String]) List of networks used as default gateway. If not set, defaults to the `cifmw_libvirt_manager_pub_net`. Read bellow for more information about that parameter. * `cifmw_libvirt_manager_vm_users`: (List[Dict]) Used to override the default list of users enabled in the vm. For its format, refers to cloud-init [documentation](https://cloudinit.readthedocs.io/en/latest/reference/modules.html#users-and-groups) about `users`. Defaults to `[]`. * `cifmw_libvirt_manager_extra_network_configuration`: (Dict) Extra network configuration in nmstate format for the hypervisor. This configuration is applied after creating the libvirt networks, so it can be used to create VLAN interfaces on the libvirt bridges. In addition to nmstate, it also supports a `cifmw_firewall_zone` hint in nmstate interfaces. Defaults to: `{}`. +* `cifmw_libvirt_manager_radvd_networks`: (List[Dict]) List of networks to configure with radvd for IPv6 router advertisements. When defined, the `radvd` role will be included after network creation. Each network definition follows the format documented in the `radvd` role. Defaults to `[]`. ### `cifmw_libvirt_manager_default_gw_nets` parameter usage @@ -245,3 +246,20 @@ layout used by the role. name: libvirt_manager tasks_from: attack_interface.yml ``` + +## IPv6 Router Advertisements with radvd + +The libvirt_manager role can automatically configure IPv6 router advertisements using the `radvd` role. This is useful for providing SLAAC and/or DHCPv6 configuration to VMs on IPv6-enabled networks. + +To enable radvd, define `cifmw_libvirt_manager_radvd_networks` with a list of network configurations: + +```yaml +cifmw_libvirt_manager_radvd_networks: + - name: cifmw-testnet1 + adv_managed_flag: true + adv_other_config_flag: true + prefixes: + - network: "2001:db8:1::/64" +``` + +For complete documentation on available parameters and configuration options, refer to the [radvd role documentation](../radvd/README.md). diff --git a/roles/libvirt_manager/defaults/main.yml b/roles/libvirt_manager/defaults/main.yml index 144a96493..5a9fdc915 100644 --- a/roles/libvirt_manager/defaults/main.yml +++ b/roles/libvirt_manager/defaults/main.yml @@ -46,7 +46,7 @@ cifmw_libvirt_manager_configuration: memory: "{{ cifmw_libvirt_manager_compute_memory }}" cpus: "{{ cifmw_libvirt_manager_compute_cpus }}" -cifmw_libvirt_manager_crc_pool: "{{ cifmw_crc_pool | default(lookup('env', 'HOME')) ~ '/.crc/machines/crc' }}" +cifmw_libvirt_manager_crc_pool: "{{ cifmw_crc_pool | default(ansible_user_dir ~ '/.crc/machines/crc') }}" cifmw_libvirt_manager_vol_prefix: '' cifmw_libvirt_manager_pool: cifmw_libvirt_manager_pool_dir: "{{ cifmw_libvirt_manager_basedir }}/volumes" @@ -88,3 +88,4 @@ cifmw_libvirt_manager_attach_dummy_interface_on_bridges: true cifmw_libvirt_manager_extra_network_configuration: {} cifmw_libvirt_manager_vm_users: [] +cifmw_libvirt_manager_radvd_networks: [] diff --git a/roles/libvirt_manager/molecule/boot_order/converge.yml b/roles/libvirt_manager/molecule/boot_order/converge.yml index 4b3d7b3aa..1c3506e87 100644 --- a/roles/libvirt_manager/molecule/boot_order/converge.yml +++ b/roles/libvirt_manager/molecule/boot_order/converge.yml @@ -20,7 +20,6 @@ vars_files: - vars/net-def.yml vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_basedir: "/opt/basedir" cifmw_libvirt_manager_configuration: vms: diff --git a/roles/libvirt_manager/molecule/check_dns/converge.yml b/roles/libvirt_manager/molecule/check_dns/converge.yml index a35a9ee1c..3298d1cf7 100644 --- a/roles/libvirt_manager/molecule/check_dns/converge.yml +++ b/roles/libvirt_manager/molecule/check_dns/converge.yml @@ -18,7 +18,6 @@ hosts: instance gather_facts: true vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_basedir: "/opt/basedir" _cifmw_libvirt_manager_layout: vms: diff --git a/roles/libvirt_manager/molecule/deploy_layout/converge.yml b/roles/libvirt_manager/molecule/deploy_layout/converge.yml index 77e3099fe..0f6782992 100644 --- a/roles/libvirt_manager/molecule/deploy_layout/converge.yml +++ b/roles/libvirt_manager/molecule/deploy_layout/converge.yml @@ -18,7 +18,6 @@ hosts: instance gather_facts: true vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_basedir: "/opt/basedir" cifmw_libvirt_manager_vm_net_ip_set: compute: 100 diff --git a/roles/libvirt_manager/molecule/ocp_layout/converge.yml b/roles/libvirt_manager/molecule/ocp_layout/converge.yml index 549f3491e..2d757ad9f 100644 --- a/roles/libvirt_manager/molecule/ocp_layout/converge.yml +++ b/roles/libvirt_manager/molecule/ocp_layout/converge.yml @@ -19,7 +19,6 @@ gather_facts: true vars: cifmw_run_id: aabbcc11 - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_basedir: "/opt/basedir" _cifmw_libvirt_manager_layout: vms: diff --git a/roles/libvirt_manager/molecule/spine_leaf/converge.yml b/roles/libvirt_manager/molecule/spine_leaf/converge.yml index 9b3a79d15..ad158e9b8 100644 --- a/roles/libvirt_manager/molecule/spine_leaf/converge.yml +++ b/roles/libvirt_manager/molecule/spine_leaf/converge.yml @@ -18,7 +18,6 @@ hosts: instance gather_facts: true vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_basedir: "/opt/basedir" cifmw_libvirt_manager_spineleaf_setup: true cifmw_libvirt_manager_network_interface_types: diff --git a/roles/libvirt_manager/molecule/spine_leaf/verify.yml b/roles/libvirt_manager/molecule/spine_leaf/verify.yml index c75516b0d..fce75f14f 100644 --- a/roles/libvirt_manager/molecule/spine_leaf/verify.yml +++ b/roles/libvirt_manager/molecule/spine_leaf/verify.yml @@ -3,7 +3,6 @@ hosts: instance gather_facts: true vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_basedir: "/opt/basedir" compare_nets: >- {{ diff --git a/roles/libvirt_manager/tasks/clean_layout.yml b/roles/libvirt_manager/tasks/clean_layout.yml index 11d22bcef..af652b55a 100644 --- a/roles/libvirt_manager/tasks/clean_layout.yml +++ b/roles/libvirt_manager/tasks/clean_layout.yml @@ -191,6 +191,13 @@ immediate: true loop: "{{ cleanup_nets }}" + - name: Ensure firewalld is enabled and started + become: true + ansible.builtin.systemd_service: + name: firewalld + enabled: true + state: started + - name: Disable masquerade in firewalld default zone become: true ansible.posix.firewalld: @@ -210,7 +217,7 @@ # Pool management - name: Remove cifmw storage pool vars: - action: "delete" + pool_action: "delete" ansible.builtin.include_tasks: storage_pool.yml - name: Remove overlay images from ocp_volume pools if exists @@ -231,7 +238,7 @@ when: - _is_deepscrub | bool vars: - action: "delete" + pool_action: "delete" cifmw_libvirt_manager_storage_pool: >- {{ cifmw_libvirt_manager_ocp_pool }} cifmw_libvirt_manager_pool_dir: >- @@ -341,3 +348,8 @@ ansible.builtin.import_role: name: dnsmasq tasks_from: cleanup.yml + +- name: Clean radvd + ansible.builtin.import_role: + name: radvd + tasks_from: cleanup.yml diff --git a/roles/libvirt_manager/tasks/create_networks.yml b/roles/libvirt_manager/tasks/create_networks.yml index 4ecaf0dd9..db61fb1e7 100644 --- a/roles/libvirt_manager/tasks/create_networks.yml +++ b/roles/libvirt_manager/tasks/create_networks.yml @@ -229,6 +229,14 @@ loop_control: label: "{{ item.name }}" +- name: Deploy radvd for IPv6 router advertisements + when: + - cifmw_libvirt_manager_radvd_networks | length > 0 + vars: + cifmw_radvd_networks: "{{ cifmw_libvirt_manager_radvd_networks }}" + ansible.builtin.include_role: + name: radvd + - name: Ensure network is in correct zone become: true notify: Restart firewalld diff --git a/roles/libvirt_manager/tasks/deploy_layout.yml b/roles/libvirt_manager/tasks/deploy_layout.yml index 9705c4e11..509f12884 100644 --- a/roles/libvirt_manager/tasks/deploy_layout.yml +++ b/roles/libvirt_manager/tasks/deploy_layout.yml @@ -110,7 +110,7 @@ when: - (require_extra_disks | int) > 0 vars: - action: "create" + pool_action: "create" _extra_disks: >- {{ _cifmw_libvirt_manager_layout.vms | diff --git a/roles/libvirt_manager/tasks/generate_networking_data.yml b/roles/libvirt_manager/tasks/generate_networking_data.yml index c464a0867..3f69c76cb 100644 --- a/roles/libvirt_manager/tasks/generate_networking_data.yml +++ b/roles/libvirt_manager/tasks/generate_networking_data.yml @@ -182,12 +182,12 @@ networks: {{ _lnet_data.name | replace('cifmw_', '') }}: {% if _lnet_data.ranges[0].start_v4 is defined and _lnet_data.ranges[0].start_v4 %} - {% set net_4 = _lnet_data.ranges[0].start_v4 | ansible.utils.ipsubnet(_lnet_data.ranges[0].prefix_length_v4) %} - network-v4: {{ net_4}} + {%- set net_4 = _lnet_data.ranges[0].start_v4 | ansible.utils.ipsubnet(_lnet_data.ranges[0].prefix_length_v4) %} + network-v4: '{{ net_4 }}' {% endif %} {% if _lnet_data.ranges[0].start_v6 is defined and _lnet_data.ranges[0].start_v6 %} - {% set net_6 = _lnet_data.ranges[0].start_v6 | ansible.utils.ipsubnet(_lnet_data.ranges[0].prefix_length_v6) %} - network-v6: {{ net_6 }} + {%- set net_6 = _lnet_data.ranges[0].start_v6 | ansible.utils.ipsubnet(_lnet_data.ranges[0].prefix_length_v6) %} + network-v6: '{{ net_6 }}' {% endif %} group-templates: {% for group in _cifmw_libvirt_manager_layout.vms.keys() if group != 'controller' and @@ -202,12 +202,12 @@ {% if cifmw_networking_definition['group-templates'][_gr ~ 's']['network-template'] is undefined %} {% if net_4 is defined %} range-v4: - start: {{ net_4 | ansible.utils.nthhost(ns.ip_start | int ) }} + start: '{{ net_4 | ansible.utils.nthhost(ns.ip_start | int ) }}' length: {{ _cifmw_libvirt_manager_layout.vms[group].amount | default(1) }} {% endif %} {% if net_6 is defined %} range-v6: - start: {{ net_6 | ansible.utils.nthhost(ns.ip_start | int) }} + start: '{{ net_6 | ansible.utils.nthhost(ns.ip_start | int) }}' length: {{ _cifmw_libvirt_manager_layout.vms[group].amount | default(1) }} {% endif %} {% set ns.ip_start = ns.ip_start|int + (_cifmw_libvirt_manager_layout.vms[group].amount | default(1) | int ) + 1 %} @@ -220,12 +220,12 @@ {{ cifmw_libvirt_manager_pub_net }}: {% if net_4 is defined and cifmw_networking_definition['group-templates']['baremetals']['network-template'] is undefined %} range-v4: - start: {{ net_4 | ansible.utils.nthhost(ns.ip_start) }} + start: '{{ net_4 | ansible.utils.nthhost(ns.ip_start) }}' length: {{ cifmw_baremetal_hosts | length }} {% endif %} {% if net_6 is defined and cifmw_networking_definition['group-templates']['baremetals']['network-template'] is undefined %} range-v6: - start: {{ net_6 | ansible.utils.nthhost(ns.ip_start) }} + start: '{{ net_6 | ansible.utils.nthhost(ns.ip_start) }}' length: {{ cifmw_baremetal_hosts | length }} {% endif %} {% endif %} @@ -235,10 +235,10 @@ networks: {{ _lnet_data.name | replace('cifmw_', '') }}: {% if net_4 is defined %} - ip-v4: "{{ net_4 | ansible.utils.nthhost(9) }}" + ip-v4: '{{ net_4 | ansible.utils.nthhost(9) }}' {% endif %} {% if net_6 is defined %} - ip-v6: "{{ net_6 | ansible.utils.nthhost(9) }}" + ip-v6: '{{ net_6 | ansible.utils.nthhost(9) }}' {% endif %} {% endif %} block: diff --git a/roles/libvirt_manager/tasks/manage_vms.yml b/roles/libvirt_manager/tasks/manage_vms.yml index b41a943f0..9ffbb4c2c 100644 --- a/roles/libvirt_manager/tasks/manage_vms.yml +++ b/roles/libvirt_manager/tasks/manage_vms.yml @@ -40,7 +40,7 @@ target: localhost proxy_host: "{{ ansible_host | default(inventory_hostname) }}" proxy_user: "{{ ansible_user | default(lookup('env', 'USER')) }}" - ssh_dir: "{{ lookup('env', 'HOME') }}/.ssh" + ssh_dir: "{{ ansible_user_dir }}/.ssh" ssh_ident: identity_file: >- {{ diff --git a/roles/libvirt_manager/tasks/ocp_layout.yml b/roles/libvirt_manager/tasks/ocp_layout.yml index f7333c07a..1024a74c9 100644 --- a/roles/libvirt_manager/tasks/ocp_layout.yml +++ b/roles/libvirt_manager/tasks/ocp_layout.yml @@ -26,14 +26,28 @@ {{ cifmw_libvirt_manager_ocp_pool_dir }} _layout_overrides: image_local_dir: "{{ cifmw_libvirt_manager_basedir }}/images" - disksize: "50" disk_file_name: "blank" + _disksize_override_master: + disksize: >- + {{ + _cifmw_libvirt_manager_layout.vms.ocp.disksize | default('50') + if not (cifmw_use_ocp_overlay | default(true) | bool) + else '50' + }} + _disksize_override_worker: + disksize: >- + {{ + _cifmw_libvirt_manager_layout.vms.ocp_worker.disksize | default('50') + if not (cifmw_use_ocp_overlay | default(true) | bool) + else '50' + }} _ocp_layout: vms: ocp_master: >- {{ _cifmw_libvirt_manager_layout.vms.ocp | combine(_layout_overrides, recursive=true) | + combine(_disksize_override_master, recursive=true) | ansible.utils.remove_keys(target="xml_paths") }} ocp_worker: >- @@ -41,6 +55,7 @@ _cifmw_libvirt_manager_layout.vms.ocp_worker | default({'amount': 0}) | combine(_layout_overrides, recursive=true) | + combine(_disksize_override_worker, recursive=true) | ansible.utils.remove_keys(target="xml_paths") }} _vm_list: >- @@ -69,8 +84,8 @@ - name: Create pool in libvirt vars: - action: 'create' - ansible.builtin.import_tasks: "storage_pool.yml" + pool_action: 'create' + ansible.builtin.include_tasks: "storage_pool.yml" - name: Create blank images for OCP cluster resources vars: diff --git a/roles/libvirt_manager/tasks/storage_pool.yml b/roles/libvirt_manager/tasks/storage_pool.yml index 33cf6e303..d0f05e912 100644 --- a/roles/libvirt_manager/tasks/storage_pool.yml +++ b/roles/libvirt_manager/tasks/storage_pool.yml @@ -17,8 +17,8 @@ - name: Ensure we have a known action ansible.builtin.assert: that: - - action is defined - - action in ['create', 'delete'] + - pool_action is defined + - pool_action in ['create', 'delete'] - name: Gather the status of cifmw-pool storage pool. register: pool_exists @@ -30,7 +30,7 @@ - name: Create and start the storage pool. when: - - action == "create" + - pool_action == "create" - pool_exists.rc == 1 block: - name: Create the storage pool @@ -54,7 +54,7 @@ - name: Remove the storage pool. when: - - action == "delete" + - pool_action == "delete" - pool_exists.rc == 0 block: - name: Gather all the volumes in the pool to delete diff --git a/roles/libvirt_manager/templates/domain.xml.j2 b/roles/libvirt_manager/templates/domain.xml.j2 index c62a8b6db..d52bfb4f9 100644 --- a/roles/libvirt_manager/templates/domain.xml.j2 +++ b/roles/libvirt_manager/templates/domain.xml.j2 @@ -1,4 +1,5 @@ + {{ vm | ansible.builtin.to_uuid }} cifmw-{{ vm }} {{ vm_data.memory | default(2) }} {{ vm_data.cpus | default(2) }} diff --git a/roles/manage_secrets/molecule/osp_secrets/converge.yml b/roles/manage_secrets/molecule/osp_secrets/converge.yml index 50c5239fd..ffab4354b 100644 --- a/roles/manage_secrets/molecule/osp_secrets/converge.yml +++ b/roles/manage_secrets/molecule/osp_secrets/converge.yml @@ -22,7 +22,7 @@ cifmw_openshift_login_kubeconfig: "{{ ansible_user_dir }}/.crc/machines/crc/kubeconfig" cifmw_manage_secrets_ospsecrets_list: - name: secret1 - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" data: foo: "{{ 'bar' | ansible.builtin.b64encode }}" bar: "{{ 'foo' | ansible.builtin.b64encode }}" @@ -30,7 +30,7 @@ type: very-secret newlabel: new-value - name: secret2 - namespace: openstack + namespace: "{{ cifmw_openstack_namespace }}" data: foobar: "{{ 'barfoo' | ansible.builtin.b64encode }}" label: diff --git a/roles/nat64_appliance/OWNERS b/roles/nat64_appliance/OWNERS new file mode 100644 index 000000000..6d371eddd --- /dev/null +++ b/roles/nat64_appliance/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - hjensas # Individual contributor + +reviewers: + - hjensas diff --git a/roles/nat64_appliance/README.md b/roles/nat64_appliance/README.md index f7933cc07..36bd1c0cc 100644 --- a/roles/nat64_appliance/README.md +++ b/roles/nat64_appliance/README.md @@ -25,6 +25,9 @@ * `cifmw_nat64_appliance_memory`: (Integer) Memory in GiB for the nat64 appliance VM. Defaults to: `2`. * `cifmw_nat64_appliance_cpus`: (Integer) Virtual CPUs for the nat64 appliance VM. Defaults to: `2`. * `cifmw_nat64_appliance_ssh_pub_keys`: (List) List of SSH public key for the nat64 appliance VM. Defaults to: `[]`. +* `cifmw_nat64_appliance_image_url`: (String) URL to download a pre-built NAT64 appliance image. If empty, the image will be built from source using diskimage-builder. Defaults to: `""`. +* `cifmw_nat64_appliance_image_checksum`: (String) Optional checksum for the downloaded image in the format `algorithm:hash` (e.g., `sha256:xxxxx`). Only used when `cifmw_nat64_appliance_image_url` is set. Defaults to: undefined. +* `cifmw_nat64_appliance_download_timeout`: (Integer) Timeout in seconds for image download. Only used when `cifmw_nat64_appliance_image_url` is set. Defaults to: `600`. * `cifmw_nat64_ipv6_prefix`: (String) IPv6 prefix for nat64. Defaults to: `fc00:abcd:abcd:fc00::/64`. * `cifmw_nat64_ipv6_tayga_address`: (String) Tayga IPv6 address. Defaults to: `fc00:abcd:abcd:fc00::3`. @@ -32,14 +35,28 @@ Include the `nat64_appliance` role in a playbook. For example: +### Build from source + +```yaml +- name: Build nat64-appliance from source + hosts: "{{ cifmw_target_host | default('localhost') }}" + roles: + - nat64_appliance ``` -- name: Build nat64-appliance + +### Download pre-built image + +```yaml +- name: Download pre-built nat64-appliance image hosts: "{{ cifmw_target_host | default('localhost') }}" + vars: + cifmw_nat64_appliance_image_url: "http://example.com/nat64-appliance.qcow2" + # cifmw_nat64_appliance_image_checksum: "sha256:xxxxx" # Optional roles: - nat64_appliance ``` -The built image will be in: `{{ cifmw_nat64_appliance_workdir }}/nat64-appliance.qcow2` +The image will be in: `{{ cifmw_nat64_appliance_workdir }}/nat64-appliance.qcow2` ## Using the nat64-appliance diff --git a/roles/nat64_appliance/defaults/main.yml b/roles/nat64_appliance/defaults/main.yml index 3c4ea8ac1..94158a434 100644 --- a/roles/nat64_appliance/defaults/main.yml +++ b/roles/nat64_appliance/defaults/main.yml @@ -40,6 +40,14 @@ cifmw_nat64_appliance_memory: 2 cifmw_nat64_appliance_cpus: 2 cifmw_nat64_appliance_ssh_pub_keys: [] +# Image download configuration +# Set cifmw_nat64_appliance_image_url to download a pre-built image +cifmw_nat64_appliance_image_url: "" +cifmw_nat64_appliance_download_timeout: 600 # 10 minutes cifmw_nat64_ipv6_prefix: "2620:cf:cf:fc00::/64" cifmw_nat64_ipv6_tayga_address: "2620:cf:cf:fc00::3" + +# Set to false to use standard ansible.builtin.shell instead of cifmw.general.ci_script +# This makes the role usable outside of ci-framework context +cifmw_nat64_appliance_use_ci_script: true diff --git a/roles/nat64_appliance/molecule/default/cleanup.yml b/roles/nat64_appliance/molecule/default/cleanup.yml index 395b8b1fd..28d4a5a52 100644 --- a/roles/nat64_appliance/molecule/default/cleanup.yml +++ b/roles/nat64_appliance/molecule/default/cleanup.yml @@ -1,7 +1,5 @@ - name: Cleanup hosts: instance - vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" tasks: - name: "Destroy the test-node" community.libvirt.virt: diff --git a/roles/nat64_appliance/molecule/default/converge.yml b/roles/nat64_appliance/molecule/default/converge.yml index c321d6d1c..c0ed9ecb9 100644 --- a/roles/nat64_appliance/molecule/default/converge.yml +++ b/roles/nat64_appliance/molecule/default/converge.yml @@ -17,7 +17,6 @@ - name: Converge hosts: instance vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_basedir: "{{ ansible_user_dir }}/ci-framework-data" tasks: - name: Crate SSH keypair @@ -56,6 +55,7 @@ retries: 60 delay: 10 + # Build the image - name: Build nat64 appliance image vars: # TODO(hjensas): Running as root should not be required here. @@ -86,6 +86,81 @@ owner: "{{ ansible_user_id }}" group: "{{ ansible_user_gid }}" + # Test download functionality + - name: Set download test directory + ansible.builtin.set_fact: + cifmw_nat64_download_dir: "{{ cifmw_basedir }}/nat64_download" + cifmw_nat64_http_port: 8765 + + - name: Start HTTP server to serve the built image + ansible.builtin.shell: | + cd {{ cifmw_basedir }}/nat64_appliance + nohup python3 -m http.server {{ cifmw_nat64_http_port }} > /tmp/nat64_http_server.log 2>&1 & + echo $! > /tmp/nat64_http_server.pid + sleep 2 + + - name: Verify HTTP server is running + ansible.builtin.uri: + url: "http://localhost:{{ cifmw_nat64_http_port }}/nat64-appliance.qcow2" + method: HEAD + register: _http_check + until: _http_check.status == 200 + retries: 5 + delay: 2 + + - name: Download nat64 appliance image from HTTP server + vars: + cifmw_nat64_appliance_basedir: "{{ cifmw_nat64_download_dir }}" + cifmw_nat64_appliance_image_url: "http://localhost:{{ cifmw_nat64_http_port }}/nat64-appliance.qcow2" + ansible.builtin.include_role: + name: nat64_appliance + + - name: Verify downloaded image exists + ansible.builtin.stat: + path: "{{ cifmw_nat64_download_dir }}/nat64_appliance/nat64-appliance.qcow2" + checksum_algorithm: sha256 + register: _downloaded_image + failed_when: not _downloaded_image.stat.exists + + - name: Get built image info with checksum + ansible.builtin.stat: + path: "{{ cifmw_basedir }}/nat64_appliance/nat64-appliance.qcow2" + checksum_algorithm: sha256 + register: _built_image + + - name: Show download test results + ansible.builtin.debug: + msg: + - "Built image: {{ _built_image.stat.path }} ({{ _built_image.stat.size }} bytes, SHA256: {{ _built_image.stat.checksum }})" + - "Downloaded image: {{ _downloaded_image.stat.path }} ({{ _downloaded_image.stat.size }} bytes, SHA256: {{ _downloaded_image.stat.checksum }})" + + - name: Verify images are identical using checksum + ansible.builtin.assert: + that: + - _downloaded_image.stat.size > 0 + - _built_image.stat.size > 0 + - _downloaded_image.stat.checksum == _built_image.stat.checksum + fail_msg: | + Downloaded image differs from built image! + Built: {{ _built_image.stat.size }} bytes, SHA256: {{ _built_image.stat.checksum }} + Downloaded: {{ _downloaded_image.stat.size }} bytes, SHA256: {{ _downloaded_image.stat.checksum }} + success_msg: "Images are identical - SHA256: {{ _built_image.stat.checksum }} ({{ _built_image.stat.size }} bytes)" + + - name: Stop HTTP server + ansible.builtin.shell: | + if [ -f /tmp/nat64_http_server.pid ]; then + kill $(cat /tmp/nat64_http_server.pid) || true + rm -f /tmp/nat64_http_server.pid + fi + + # Deploy nat64 appliance for testing + - name: Copy downloaded image to working location for deployment + ansible.builtin.copy: + src: "{{ cifmw_nat64_download_dir }}/nat64_appliance/nat64-appliance.qcow2" + dest: "{{ cifmw_basedir }}/nat64_appliance/nat64-appliance.qcow2" + remote_src: true + mode: "0644" + - name: "Deploy the nat64 appliance and networks" vars: cifmw_nat64_appliance_ssh_pub_keys: diff --git a/roles/nat64_appliance/molecule/default/prepare.yml b/roles/nat64_appliance/molecule/default/prepare.yml index 99ae481dd..83d82c798 100644 --- a/roles/nat64_appliance/molecule/default/prepare.yml +++ b/roles/nat64_appliance/molecule/default/prepare.yml @@ -17,7 +17,6 @@ - name: Prepare hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_basedir: "{{ ansible_user_dir }}/ci-framework-data" pre_tasks: - name: Create custom basedir diff --git a/roles/nat64_appliance/tasks/build_image.yml b/roles/nat64_appliance/tasks/build_image.yml new file mode 100644 index 000000000..3eadd7e81 --- /dev/null +++ b/roles/nat64_appliance/tasks/build_image.yml @@ -0,0 +1,60 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Install required RPM packages + tags: + - packages + become: true + ansible.builtin.package: + name: + - python3-pip + - qemu-img + - dosfstools + - xfsprogs + state: present + +- name: Install diskimage-builder in virtualenv + tags: + - packages + ansible.builtin.pip: + virtualenv_command: "python3 -m venv" + virtualenv: "{{ cifmw_nat64_appliance_venv_dir }}" + name: + - diskimage-builder + - setuptools + +- name: Copy files to cifmw_nat64_appliance_dir + ansible.builtin.copy: + src: "{{ item }}" + dest: "{{ cifmw_nat64_appliance_workdir }}/{{ item }}" + mode: preserve + loop: + - "elements/" + - nat64-appliance.yaml + +- name: Clone edpm-image-builder (reset-bls-entries dib element) + ansible.builtin.git: + repo: https://github.com/openstack-k8s-operators/edpm-image-builder.git + dest: "{{ cifmw_nat64_appliance_workdir }}/edpm-image-builder" + version: main + +- name: Build the nat64-appliance image using DIB (with ci_script) + when: cifmw_nat64_appliance_use_ci_script | bool + ansible.builtin.include_tasks: build_with_ci_script.yml + +- name: Build the nat64-appliance image using DIB (with shell) + when: not (cifmw_nat64_appliance_use_ci_script | bool) + ansible.builtin.include_tasks: build_with_shell.yml diff --git a/roles/nat64_appliance/tasks/build_with_ci_script.yml b/roles/nat64_appliance/tasks/build_with_ci_script.yml new file mode 100644 index 000000000..fed170702 --- /dev/null +++ b/roles/nat64_appliance/tasks/build_with_ci_script.yml @@ -0,0 +1,28 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Build the nat64-appliance image using DIB (with ci_script) + become: "{{ cifmw_nat64_appliance_run_dib_as_root | default(false) | bool }}" + environment: + ELEMENTS_PATH: "{{ cifmw_nat64_appliance_workdir }}/elements:{{ cifmw_nat64_appliance_workdir }}/edpm-image-builder/dib/" + DIB_IMAGE_CACHE: "{{ cifmw_nat64_appliance_workdir }}/cache" + DIB_DEBUG_TRACE: '1' + cifmw.general.ci_script: + chdir: "{{ cifmw_nat64_appliance_workdir }}" + output_dir: "{{ cifmw_nat64_appliance_basedir }}/artifacts" + creates: "{{ cifmw_nat64_appliance_workdir }}/nat64-appliance.qcow2" + script: "{{ cifmw_nat64_appliance_venv_dir }}/bin/diskimage-builder nat64-appliance.yaml {{ extra_args | default('') }}" + executable: "/bin/bash" diff --git a/roles/nat64_appliance/tasks/build_with_shell.yml b/roles/nat64_appliance/tasks/build_with_shell.yml new file mode 100644 index 000000000..9dd5eee20 --- /dev/null +++ b/roles/nat64_appliance/tasks/build_with_shell.yml @@ -0,0 +1,28 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Build the nat64-appliance image using DIB (with shell) + become: "{{ cifmw_nat64_appliance_run_dib_as_root | default(false) | bool }}" + environment: + ELEMENTS_PATH: "{{ cifmw_nat64_appliance_workdir }}/elements:{{ cifmw_nat64_appliance_workdir }}/edpm-image-builder/dib/" + DIB_IMAGE_CACHE: "{{ cifmw_nat64_appliance_workdir }}/cache" + DIB_DEBUG_TRACE: '1' + ansible.builtin.shell: | + {{ cifmw_nat64_appliance_venv_dir }}/bin/diskimage-builder nat64-appliance.yaml {{ extra_args | default('') }} + args: + chdir: "{{ cifmw_nat64_appliance_workdir }}" + creates: "{{ cifmw_nat64_appliance_workdir }}/nat64-appliance.qcow2" + executable: /bin/bash diff --git a/roles/nat64_appliance/tasks/cleanup.yml b/roles/nat64_appliance/tasks/cleanup.yml index f58b4cc8a..02e6c9e6d 100644 --- a/roles/nat64_appliance/tasks/cleanup.yml +++ b/roles/nat64_appliance/tasks/cleanup.yml @@ -32,8 +32,19 @@ community.libvirt.virt: command: list_vms - - name: Stop the nat64_appliance VM + - name: Get nat64_appliance VM state when: cifmw_nat64_appliance_name in _list_vms.list_vms + register: _vm_state + community.libvirt.virt: + command: status + name: "{{ cifmw_nat64_appliance_name }}" + uri: "{{ cifmw_nat64_libvirt_uri }}" + + - name: Stop the nat64_appliance VM + when: + - cifmw_nat64_appliance_name in _list_vms.list_vms + - _vm_state.status is defined + - _vm_state.status == "running" community.libvirt.virt: command: destroy name: "{{ cifmw_nat64_appliance_name }}" diff --git a/roles/nat64_appliance/tasks/main.yml b/roles/nat64_appliance/tasks/main.yml index 2a9aa941c..c30669fb1 100644 --- a/roles/nat64_appliance/tasks/main.yml +++ b/roles/nat64_appliance/tasks/main.yml @@ -29,52 +29,17 @@ state: directory mode: "0755" -- name: Install required RPM packages - tags: - - packages - become: true - ansible.builtin.package: - name: - - python3-pip - - qemu-img - - dosfstools - - xfsprogs - state: present +- name: Build NAT64 appliance image from source + when: + - cifmw_nat64_appliance_image_url | length == 0 + ansible.builtin.include_tasks: build_image.yml -- name: Install diskimage-builder in virtualenv - tags: - - packages - ansible.builtin.pip: - virtualenv_command: "python3 -m venv" - virtualenv: "{{ cifmw_nat64_appliance_venv_dir }}" - name: - - diskimage-builder - - setuptools - -- name: Copy files to cifmw_nat64_appliance_dir - ansible.builtin.copy: - src: "{{ item }}" - dest: "{{ cifmw_nat64_appliance_workdir }}/{{ item }}" - mode: preserve - loop: - - "elements/" - - nat64-appliance.yaml - -- name: Clone edpm-image-builder (reset-bls-entries dib element) - ansible.builtin.git: - repo: https://github.com/openstack-k8s-operators/edpm-image-builder.git - dest: "{{ cifmw_nat64_appliance_workdir }}/edpm-image-builder" - version: main - -- name: Build the nat64-appliance image using DIB - become: "{{ cifmw_nat64_appliance_run_dib_as_root | default(false) | bool }}" - environment: - ELEMENTS_PATH: "{{ cifmw_nat64_appliance_workdir }}/elements:{{ cifmw_nat64_appliance_workdir }}/edpm-image-builder/dib/" - DIB_IMAGE_CACHE: "{{ cifmw_nat64_appliance_workdir }}/cache" - DIB_DEBUG_TRACE: '1' - cifmw.general.ci_script: - chdir: "{{ cifmw_nat64_appliance_workdir }}" - output_dir: "{{ cifmw_nat64_appliance_basedir }}/artifacts" - creates: "{{ cifmw_nat64_appliance_workdir }}/nat64-appliance.qcow2" - script: "{{ cifmw_nat64_appliance_venv_dir }}/bin/diskimage-builder nat64-appliance.yaml {{ extra_args | default('') }}" - executable: "/bin/bash" +- name: Download pre-built NAT64 appliance image + when: + - cifmw_nat64_appliance_image_url | length > 0 + ansible.builtin.get_url: + url: "{{ cifmw_nat64_appliance_image_url }}" + dest: "{{ cifmw_nat64_appliance_workdir }}/nat64-appliance.qcow2" + checksum: "{{ cifmw_nat64_appliance_image_checksum | default(omit) }}" + timeout: "{{ cifmw_nat64_appliance_download_timeout }}" + mode: "0644" diff --git a/roles/openshift_adm/tasks/wait_for_cluster.yml b/roles/openshift_adm/tasks/wait_for_cluster.yml index f96a14518..8fd5838dd 100644 --- a/roles/openshift_adm/tasks/wait_for_cluster.yml +++ b/roles/openshift_adm/tasks/wait_for_cluster.yml @@ -60,7 +60,7 @@ - name: Approve pending certificate requests register: _approve_csr - approve_csr: + cifmw.general.approve_csr: k8s_config: "{{ cifmw_openshift_kubeconfig }}" retries: 10 delay: 30 diff --git a/roles/openshift_provisioner_node/molecule/default/converge.yml b/roles/openshift_provisioner_node/molecule/default/converge.yml index 15ac7e03f..969768286 100644 --- a/roles/openshift_provisioner_node/molecule/default/converge.yml +++ b/roles/openshift_provisioner_node/molecule/default/converge.yml @@ -19,7 +19,6 @@ hosts: all gather_facts: true vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_path: "{{ ansible_user_dir ~ '/.crc/bin:' ~ ansible_user_dir ~ '/.crc/bin/oc:' ~ ansible_user_dir ~ '/bin:' ~ ansible_env.PATH }}" cifmw_opn_dry_run: true cifmw_use_opn: true diff --git a/roles/openshift_provisioner_node/molecule/default/prepare.yml b/roles/openshift_provisioner_node/molecule/default/prepare.yml index 29b0d5455..48d469f25 100644 --- a/roles/openshift_provisioner_node/molecule/default/prepare.yml +++ b/roles/openshift_provisioner_node/molecule/default/prepare.yml @@ -19,7 +19,6 @@ hosts: all gather_facts: true vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_path: "{{ ansible_user_dir }}/.crc/bin:{{ ansible_user_dir }}/.crc/bin/oc:{{ ansible_user_dir }}/bin:{{ ansible_env.PATH }}" cifmw_basedir: "{{ ansible_user_dir }}/ci-framework-data" cifmw_use_libvirt_manager: true diff --git a/roles/os_must_gather/OWNERS b/roles/os_must_gather/OWNERS new file mode 100644 index 000000000..2ca6683f8 --- /dev/null +++ b/roles/os_must_gather/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - must-gather-team + +reviewers: + - must-gather-team diff --git a/roles/os_must_gather/defaults/main.yml b/roles/os_must_gather/defaults/main.yml index aa7b8b9b1..96b54f574 100644 --- a/roles/os_must_gather/defaults/main.yml +++ b/roles/os_must_gather/defaults/main.yml @@ -23,11 +23,11 @@ cifmw_os_must_gather_image_registry: "quay.rdoproject.org/openstack-k8s-operator cifmw_os_must_gather_output_dir: "{{ cifmw_basedir | default(ansible_user_dir ~ '/ci-framework-data') }}" cifmw_os_must_gather_output_log_dir: "{{ cifmw_os_must_gather_output_dir }}/logs/openstack-must-gather" cifmw_os_must_gather_repo_path: "{{ ansible_user_dir }}/src/github.com/openstack-k8s-operators/openstack-must-gather" -cifmw_os_must_gather_timeout: "10m" +cifmw_os_must_gather_timeout: "30m" cifmw_os_must_gather_additional_namespaces: "kuttl,openshift-storage,openshift-marketplace,openshift-operators,sushy-emulator,tobiko" cifmw_os_must_gather_namespaces: - openstack-operators - - openstack + - "{{ cifmw_openstack_namespace }}" - baremetal-operator-system - openshift-machine-api - cert-manager diff --git a/roles/os_must_gather/tasks/main.yml b/roles/os_must_gather/tasks/main.yml index a40996116..7b578d5fa 100644 --- a/roles/os_must_gather/tasks/main.yml +++ b/roles/os_must_gather/tasks/main.yml @@ -56,6 +56,8 @@ - _kubeconfig_stat.stat.exists block: - name: Run openstack-must-gather command + vars: + shell_cmd_timeout: "{{ (cifmw_os_must_gather_timeout | community.general.to_seconds) + 900 }}" environment: KUBECONFIG: "{{ cifmw_openshift_kubeconfig | default(cifmw_os_must_gather_kubeconfig) }}" PATH: "{{ cifmw_path }}" @@ -65,7 +67,7 @@ cifmw.general.ci_script: output_dir: "{{ cifmw_os_must_gather_output_dir }}/artifacts" script: >- - timeout {{ (cifmw_os_must_gather_timeout | community.general.to_seconds) + 120 }} + timeout {{ shell_cmd_timeout }} oc adm must-gather --image {{ cifmw_os_must_gather_image }} --timeout {{ cifmw_os_must_gather_timeout }} --host-network={{ cifmw_os_must_gather_host_network }} @@ -75,7 +77,13 @@ SOS_EDPM=$SOS_EDPM SOS_DECOMPRESS=$SOS_DECOMPRESS gather - 2>&1 + 2>&1 || { + rc=$? + if [ $rc -eq 124 ]; then + echo "The must gather command did not finish on time!" + echo "{{ shell_cmd_timeout }} seconds was not enough to finish the task." + fi + } - name: Find existing os-must-gather directories ansible.builtin.find: diff --git a/roles/os_net_setup/templates/subnet_command.j2 b/roles/os_net_setup/templates/subnet_command.j2 index 731cbeac5..4e1e513a6 100644 --- a/roles/os_net_setup/templates/subnet_command.j2 +++ b/roles/os_net_setup/templates/subnet_command.j2 @@ -47,17 +47,16 @@ oc exec -n {{ cifmw_os_net_setup_namespace }} openstackclient -- openstack subne --host-routes destination={{ hr.destination }},gateway={{ hr.nexthop }} \ {% endfor %} {% endif %} -{% if subnet_args.ip_version is defined and - subnet_args.ip_version | int == 6 %} +{% if subnet_args.ip_version is defined %} --ip-version {{subnet_args.ip_version }} \ {% endif %} {% if subnet_args.ipv6_address_mode is defined and subnet_args.ipv6_address_mode in ipv6_modes_arguments %} - --ipv6-address-mode {{subnet_args.provider_physical_network }} \ + --ipv6-address-mode {{subnet_args.ipv6_address_mode }} \ {% endif %} {% if subnet_args.ipv6_ra_mode is defined and subnet_args.ipv6_ra_mode in ipv6_modes_arguments %} - --ipv6-ra-mode {{subnet_args.provider_physical_network }} \ + --ipv6-ra-mode {{subnet_args.ipv6_ra_mode }} \ {% endif %} {% if (subnet_args.is_dhcp_enabled is defined and not subnet_args.is_dhcp_enabled) or diff --git a/roles/pcp_metrics/files/plot.py b/roles/pcp_metrics/files/plot.py index 39cb1780f..2ee1e5b5f 100755 --- a/roles/pcp_metrics/files/plot.py +++ b/roles/pcp_metrics/files/plot.py @@ -410,7 +410,11 @@ def annotate(axs: Iterable[plt.Axes]) -> None: data = file.read().strip().split("\n") for annotation in data: - time, details = annotation.split(" | ", maxsplit=1) + try: + time, details = annotation.split(" | ", maxsplit=1) + except ValueError: + print("WARNING Skipping malformed annotation line:", annotation.strip()) + continue time = datetime.strptime(time, "%Y-%m-%d %H:%M:%S,%f") if details.startswith("PLAY"): diff --git a/roles/pcp_metrics/tasks/coreos.yaml b/roles/pcp_metrics/tasks/coreos.yaml index 39ed6224a..8bbf16e5c 100644 --- a/roles/pcp_metrics/tasks/coreos.yaml +++ b/roles/pcp_metrics/tasks/coreos.yaml @@ -8,24 +8,8 @@ # So, this play allows to setup the PCP easily in our CI jobs, # even though it may not be the way advised for real-world env. # -- name: Set repositories - become: true - block: - - name: Set repositories (BaseOS) - ansible.builtin.yum_repository: - file: pcp-coreos-hack - name: baseos - description: BaseOS repository - baseurl: "{{ pcp_repo_url }}/BaseOS/$basearch/os/" - gpgcheck: false - - - name: Set repositories (AppStream) - ansible.builtin.yum_repository: - file: pcp-coreos-hack - name: appstream - description: AppStream repository - baseurl: "{{ pcp_repo_url }}/AppStream/$basearch/os/" - gpgcheck: false +- name: Setup repositories for PCP + ansible.builtin.include_tasks: repo.yml - name: Make /usr writable become: true diff --git a/roles/pcp_metrics/tasks/repo.yml b/roles/pcp_metrics/tasks/repo.yml new file mode 100644 index 000000000..7bcdce5fc --- /dev/null +++ b/roles/pcp_metrics/tasks/repo.yml @@ -0,0 +1,23 @@ +--- +# +# Setup repositories for PCP package installation. +# Used by both CoreOS nodes and network infrastructure nodes. +# +- name: Set repositories + become: true + block: + - name: Set repositories (BaseOS) + ansible.builtin.yum_repository: + file: pcp-repo-setup + name: baseos + description: BaseOS repository + baseurl: "{{ pcp_repo_url }}/BaseOS/$basearch/os/" + gpgcheck: false + + - name: Set repositories (AppStream) + ansible.builtin.yum_repository: + file: pcp-repo-setup + name: appstream + description: AppStream repository + baseurl: "{{ pcp_repo_url }}/AppStream/$basearch/os/" + gpgcheck: false diff --git a/roles/polarion/OWNERS b/roles/polarion/OWNERS new file mode 100644 index 000000000..69b601061 --- /dev/null +++ b/roles/polarion/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - polarion-team + +reviewers: + - polarion-team diff --git a/roles/radvd/README.md b/roles/radvd/README.md new file mode 100644 index 000000000..2a1319863 --- /dev/null +++ b/roles/radvd/README.md @@ -0,0 +1,179 @@ +# radvd + +Manage radvd (Router Advertisement Daemon) configuration. + +This role provides IPv6 Router Advertisements for network interfaces, enabling +Stateless Address Autoconfiguration (SLAAC) and/or DHCPv6. + +## Privilege escalation + +- Package installation +- Writing in protected locations `/etc/radvd.conf`, `/etc/cifmw-radvd.d` +- Managing system service `radvd.service` + +## Common Parameters + +* `cifmw_radvd_basedir`: (String) Configuration fragments directory. Defaults to `/etc/cifmw-radvd.d`. +* `cifmw_radvd_networks`: (List) List of networks to configure. Defaults to `[]`. +* `cifmw_radvd_remove_package`: (Bool) Remove the radvd package during cleanup. Defaults to `false`. + +## Network Configuration + +Each network in `cifmw_radvd_networks` supports the following parameters: + +* `name`: (String) Network/interface name. **Required**. +* `state`: (String) Network status. Must be either `present` or `absent`. Defaults to `present`. +* `prefixes`: (List[mapping]) List of IPv6 prefixes to advertise. **Required when state is present**. +* `adv_send_advert`: (Bool) Enable/disable router advertisements. Defaults to `true`. +* `adv_managed_flag`: (Bool) Managed address configuration flag (M-flag). Indicates DHCPv6 for addresses. +* `adv_other_config_flag`: (Bool) Other configuration flag (O-flag). Indicates DHCPv6 for other configuration. +* `adv_ra_solicited_unicast`: (Bool) Enable unicast router advertisements. +* `adv_link_mtu`: (Int) Advertised MTU for the link. +* `min_rtr_adv_interval`: (Int) Minimum router advertisement interval in seconds. +* `max_rtr_adv_interval`: (Int) Maximum router advertisement interval in seconds. +* `routes`: (List[mapping]) List of routes to advertise. Optional. +* `rdnss`: (List[mapping]) List of recursive DNS servers to advertise. Optional. + +### Prefix mapping + +* `network`: (String) IPv6 prefix (e.g., `2001:db8:1::/64`). **Required**. +* `adv_on_link`: (Bool) On-link flag. Defaults to `true`. +* `adv_autonomous`: (Bool) Autonomous address configuration flag (SLAAC). Defaults to `true`. +* `adv_router_addr`: (Bool) Include router address in prefix information. +* `adv_valid_lifetime`: (String/Int) Valid lifetime for the prefix (e.g., `86400`, `infinity`). +* `adv_preferred_lifetime`: (String/Int) Preferred lifetime for the prefix. + +### Route mapping + +* `network`: (String) IPv6 route prefix. **Required**. +* `adv_route_preference`: (String) Route preference (`low`, `medium`, `high`). +* `adv_route_lifetime`: (Int) Route lifetime in seconds. + +### RDNSS mapping + +* `servers`: (List[String]) List of IPv6 DNS server addresses. **Required**. +* `adv_rdnss_lifetime`: (Int) RDNSS lifetime in seconds. + +## Examples + +### Basic network with SLAAC only + +```yaml +- name: Configure radvd networks + vars: + cifmw_radvd_networks: + - name: testnet + adv_managed_flag: false + adv_other_config_flag: false + adv_link_mtu: 1500 + min_rtr_adv_interval: 30 + max_rtr_adv_interval: 100 + prefixes: + - network: "2001:db8:1::/64" + adv_on_link: true + adv_autonomous: true + adv_router_addr: true + ansible.builtin.include_role: + name: radvd +``` + +### Network with DHCPv6 for addresses and other configuration + +```yaml +- name: Configure radvd with DHCPv6 + vars: + cifmw_radvd_networks: + - name: provisioning + adv_managed_flag: true + adv_other_config_flag: true + adv_ra_solicited_unicast: true + adv_link_mtu: 1500 + min_rtr_adv_interval: 30 + max_rtr_adv_interval: 100 + prefixes: + - network: "2001:db8:2::/64" + adv_on_link: true + adv_autonomous: false + rdnss: + - servers: + - "2001:db8:2::53" + adv_rdnss_lifetime: 300 + ansible.builtin.include_role: + name: radvd +``` + +### Multiple networks + +```yaml +- name: Configure multiple networks + vars: + cifmw_radvd_networks: + - name: net1 + adv_managed_flag: true + adv_other_config_flag: true + adv_link_mtu: 1500 + min_rtr_adv_interval: 30 + max_rtr_adv_interval: 100 + prefixes: + - network: "2001:db8:1::/64" + adv_on_link: true + adv_autonomous: true + - name: net2 + adv_managed_flag: false + adv_other_config_flag: false + prefixes: + - network: "2001:db8:2::/64" + adv_on_link: true + adv_autonomous: true + ansible.builtin.include_role: + name: radvd +``` + +### Remove a network configuration + +```yaml +- name: Remove radvd configuration for a network + vars: + cifmw_radvd_networks: + - name: testnet + state: absent + ansible.builtin.include_role: + name: radvd +``` + +### Cleanup entire radvd service + +```yaml +- name: Cleanup radvd + vars: + # Set to true to also remove the radvd package (default: false) + cifmw_radvd_remove_package: false + ansible.builtin.include_role: + name: radvd + tasks_from: cleanup.yml +``` + +## Understanding the flags + +### Managed Flag (M-flag) - `adv_managed_flag` + +When set to `true`, hosts should use DHCPv6 to obtain IPv6 addresses (stateful DHCPv6). +When set to `false`, hosts should use SLAAC (Stateless Address Autoconfiguration) based on the advertised prefix. + +### Other Config Flag (O-flag) - `adv_other_config_flag` + +When set to `true`, hosts should use DHCPv6 to obtain other configuration information (DNS, NTP, etc.). + +### Common configurations + +1. **SLAAC only**: `adv_managed_flag: false`, `adv_other_config_flag: false`, `adv_autonomous: true` +2. **SLAAC + DHCPv6 for options**: `adv_managed_flag: false`, `adv_other_config_flag: true`, `adv_autonomous: true` +3. **DHCPv6 for everything**: `adv_managed_flag: true`, `adv_other_config_flag: true`, `adv_autonomous: false` + +## Notes + +- The interface/bridge specified by the `name` parameter must exist before radvd can advertise on it. +- IPv6 forwarding must be enabled on the host for router advertisements to work properly. +- Multiple prefixes can be advertised on the same interface. +- The role uses the system `radvd.service` from the RPM package. +- Configuration is assembled from fragments in `/etc/cifmw-radvd.d/` into `/etc/radvd.conf`. diff --git a/roles/radvd/defaults/main.yml b/roles/radvd/defaults/main.yml new file mode 100644 index 000000000..1e644a736 --- /dev/null +++ b/roles/radvd/defaults/main.yml @@ -0,0 +1,22 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +# All variables within this role should have a prefix of "cifmw_radvd" + +cifmw_radvd_basedir: "/etc/cifmw-radvd.d" +cifmw_radvd_networks: [] +cifmw_radvd_remove_package: false diff --git a/roles/radvd/handlers/main.yml b/roles/radvd/handlers/main.yml new file mode 100644 index 000000000..bbaa821a9 --- /dev/null +++ b/roles/radvd/handlers/main.yml @@ -0,0 +1,21 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Restart radvd service + become: true + ansible.builtin.systemd: + name: radvd.service + state: restarted diff --git a/roles/build_push_container/meta/main.yml b/roles/radvd/meta/main.yml similarity index 91% rename from roles/build_push_container/meta/main.yml rename to roles/radvd/meta/main.yml index 68d3b79a8..8fd358bb2 100644 --- a/roles/build_push_container/meta/main.yml +++ b/roles/radvd/meta/main.yml @@ -17,10 +17,10 @@ galaxy_info: author: CI Framework - description: CI Framework Role -- build_push_container + description: CI Framework Role -- radvd company: Red Hat license: Apache-2.0 - min_ansible_version: 2.14 + min_ansible_version: "2.14" namespace: cifmw galaxy_tags: - cifmw diff --git a/roles/radvd/molecule/default/cleanup.yml b/roles/radvd/molecule/default/cleanup.yml new file mode 100644 index 000000000..00eac85ed --- /dev/null +++ b/roles/radvd/molecule/default/cleanup.yml @@ -0,0 +1,52 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Cleanup + hosts: all + tasks: + - name: Copy generated content in ci-framework-data/artifacts + vars: + dest_dir: >- + {{ + (ansible_user_dir, + 'ci-framework-data', + 'artifacts') | path_join + }} + ansible.posix.synchronize: + src: "{{ item }}" + dest: "{{ dest_dir }}" + loop: + - /etc/radvd.conf + - /etc/cifmw-radvd.d/ + + - name: Cleanup radvd + ansible.builtin.import_role: + name: "radvd" + tasks_from: "cleanup.yml" + + - name: Check if cleanup files still exist + become: true + ansible.builtin.stat: + path: "{{ item }}" + register: _cleanup_check + loop: + - /etc/radvd.conf + - /etc/cifmw-radvd.d + + - name: Assert cleanup was successful + ansible.builtin.assert: + that: + - not (_cleanup_check.results | map(attribute='stat.exists') | list | max) diff --git a/roles/radvd/molecule/default/converge.yml b/roles/radvd/molecule/default/converge.yml new file mode 100644 index 000000000..edcbd5cef --- /dev/null +++ b/roles/radvd/molecule/default/converge.yml @@ -0,0 +1,180 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +- name: Converge + hosts: all + vars: + cifmw_radvd_networks: + - name: testnet1 + adv_managed_flag: true + adv_other_config_flag: true + adv_ra_solicited_unicast: true + adv_link_mtu: 1500 + min_rtr_adv_interval: 30 + max_rtr_adv_interval: 100 + prefixes: + - network: "2001:db8:1::/64" + adv_on_link: true + adv_autonomous: true + adv_router_addr: true + - name: testnet2 + adv_managed_flag: true + adv_other_config_flag: true + adv_link_mtu: 1500 + min_rtr_adv_interval: 30 + max_rtr_adv_interval: 100 + prefixes: + - network: "2001:db8:2::/64" + adv_on_link: true + adv_autonomous: false + rdnss: + - servers: + - "2001:db8:2::53" + adv_rdnss_lifetime: 300 + - name: testnet3 + adv_managed_flag: false + adv_other_config_flag: false + adv_link_mtu: 9000 + min_rtr_adv_interval: 30 + max_rtr_adv_interval: 600 + prefixes: + - network: "2001:db8:3::/64" + adv_on_link: true + adv_autonomous: true + rdnss: + - servers: + - "2001:db8:3::53" + adv_rdnss_lifetime: 600 + roles: + - role: "radvd" + tasks: + - name: Verify radvd configuration is valid + become: true + ansible.builtin.command: + cmd: /usr/sbin/radvd -c -C /etc/radvd.conf + changed_when: false + + - name: Check if configuration files exist + become: true + ansible.builtin.stat: + path: "{{ item }}" + register: _config_files + loop: + - /etc/radvd.conf + - /etc/cifmw-radvd.d/testnet1.conf + - /etc/cifmw-radvd.d/testnet2.conf + - /etc/cifmw-radvd.d/testnet3.conf + + - name: Assert all configuration files exist + ansible.builtin.assert: + that: + - _config_files.results | map(attribute='stat.exists') | list | min + + - name: Verify testnet1 configuration content + become: true + ansible.builtin.slurp: + path: /etc/cifmw-radvd.d/testnet1.conf + register: _testnet1_conf + + - name: Check testnet1 configuration has expected content + vars: + _config: "{{ _testnet1_conf.content | b64decode }}" + ansible.builtin.assert: + that: + - "'interface testnet1' in _config" + - "'AdvSendAdvert on' in _config" + - "'AdvManagedFlag on' in _config" + - "'AdvOtherConfigFlag on' in _config" + - "'AdvRASolicitedUnicast on' in _config" + - "'AdvLinkMTU 1500' in _config" + - "'MinRtrAdvInterval 30' in _config" + - "'MaxRtrAdvInterval 100' in _config" + - "'prefix 2001:db8:1::/64' in _config" + - "'AdvOnLink on' in _config" + - "'AdvAutonomous on' in _config" + - "'AdvRouterAddr on' in _config" + + - name: Verify testnet1 configuration formatting is correct + vars: + _config_lines: "{{ (_testnet1_conf.content | b64decode).split('\n') }}" + ansible.builtin.assert: + that: + # Check directives are on separate lines (not squished together) + - _config_lines | select('match', '.*;.*AdvManagedFlag') | list | length == 0 + - _config_lines | select('match', '.*;.*AdvOtherConfigFlag') | list | length == 0 + - _config_lines | select('match', '.*;.*AdvLinkMTU') | list | length == 0 + # Check specific lines have proper formatting (one directive per line) + - _config_lines | select('match', '^ AdvManagedFlag on;$') | list | length == 1 + - _config_lines | select('match', '^ AdvOtherConfigFlag on;$') | list | length == 1 + - _config_lines | select('match', '^ AdvLinkMTU 1500;$') | list | length == 1 + msg: "Configuration formatting is incorrect - directives may be squished together on the same line" + + - name: Verify testnet2 configuration has RDNSS + become: true + ansible.builtin.slurp: + path: /etc/cifmw-radvd.d/testnet2.conf + register: _testnet2_conf + + - name: Check testnet2 configuration has RDNSS + vars: + _config: "{{ _testnet2_conf.content | b64decode }}" + ansible.builtin.assert: + that: + - "'RDNSS 2001:db8:2::53' in _config" + - "'AdvRDNSSLifetime 300' in _config" + - "'AdvAutonomous off' in _config" + + - name: Verify service is running + become: true + ansible.builtin.systemd: + name: radvd.service + register: _service_status + + - name: Assert service is active + ansible.builtin.assert: + that: + - _service_status.status.ActiveState == 'active' + + - name: Remove testnet3 network configuration + vars: + cifmw_radvd_networks: + - name: testnet3 + state: absent + ansible.builtin.include_role: + name: radvd + + - name: Verify testnet3 network configuration was removed + become: true + ansible.builtin.stat: + path: /etc/cifmw-radvd.d/testnet3.conf + register: _testnet3_conf + + - name: Assert testnet3 configuration is removed + ansible.builtin.assert: + that: + - not _testnet3_conf.stat.exists + + - name: Verify service is still running after network removal + become: true + ansible.builtin.systemd: + name: radvd.service + register: _service_status_after + + - name: Assert service is still active + ansible.builtin.assert: + that: + - _service_status_after.status.ActiveState == 'active' diff --git a/roles/build_push_container/molecule/default/molecule.yml b/roles/radvd/molecule/default/molecule.yml similarity index 81% rename from roles/build_push_container/molecule/default/molecule.yml rename to roles/radvd/molecule/default/molecule.yml index 7c38fbee9..fda947caf 100644 --- a/roles/build_push_container/molecule/default/molecule.yml +++ b/roles/radvd/molecule/default/molecule.yml @@ -9,9 +9,3 @@ provisioner: log: true env: ANSIBLE_STDOUT_CALLBACK: yaml - -prerun: false - -scenario: - test_sequence: - - converge diff --git a/roles/radvd/molecule/default/prepare.yml b/roles/radvd/molecule/default/prepare.yml new file mode 100644 index 000000000..d922cb656 --- /dev/null +++ b/roles/radvd/molecule/default/prepare.yml @@ -0,0 +1,45 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +- name: Prepare + hosts: all + roles: + - role: test_deps + tasks: + - name: Create dummy interface for testnet1 network + become: true + community.general.nmcli: + type: dummy + conn_name: testnet1 + ip6: "2001:db8:1::1/64" + state: present + + - name: Create dummy interface for testnet2 network + become: true + community.general.nmcli: + type: dummy + conn_name: testnet2 + ip6: "2001:db8:2::1/64" + state: present + + - name: Create dummy interface for testnet3 network + become: true + community.general.nmcli: + type: dummy + conn_name: testnet3 + ip6: "2001:db8:3::1/64" + state: present diff --git a/roles/radvd/tasks/cleanup.yml b/roles/radvd/tasks/cleanup.yml new file mode 100644 index 000000000..79681b6e1 --- /dev/null +++ b/roles/radvd/tasks/cleanup.yml @@ -0,0 +1,48 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Gather package facts + ansible.builtin.package_facts: + manager: auto + +- name: Stop and disable radvd service + become: true + when: + - "'radvd' in ansible_facts.packages" + ansible.builtin.systemd: + name: radvd.service + enabled: false + state: stopped + +- name: Remove radvd configuration file + become: true + ansible.builtin.file: + path: "/etc/radvd.conf" + state: absent + +- name: Remove configuration directory + become: true + ansible.builtin.file: + path: "{{ cifmw_radvd_basedir }}" + state: absent + +- name: Remove radvd package + become: true + when: + - cifmw_radvd_remove_package | bool + ansible.builtin.package: + name: radvd + state: absent diff --git a/roles/radvd/tasks/configure.yml b/roles/radvd/tasks/configure.yml new file mode 100644 index 000000000..a2b8cfb45 --- /dev/null +++ b/roles/radvd/tasks/configure.yml @@ -0,0 +1,34 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Install radvd package + become: true + ansible.builtin.package: + name: radvd + state: present + +- name: Manage configuration directory + become: true + ansible.builtin.file: + mode: "0755" + path: "{{ cifmw_radvd_basedir }}" + state: directory + +- name: Enable radvd service + become: true + ansible.builtin.systemd: + name: radvd.service + enabled: true diff --git a/roles/radvd/tasks/main.yml b/roles/radvd/tasks/main.yml new file mode 100644 index 000000000..2b9d528e0 --- /dev/null +++ b/roles/radvd/tasks/main.yml @@ -0,0 +1,32 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Install and configure radvd + ansible.builtin.import_tasks: configure.yml + +- name: Manage radvd networks + when: + - cifmw_radvd_networks | length > 0 + ansible.builtin.include_tasks: manage_network.yml + loop: "{{ cifmw_radvd_networks }}" + loop_control: + loop_var: cifmw_radvd_network + +# Flush handlers to ensure the service is started before the role completes. +# This guarantees that radvd is running when control returns to the caller, +# so any subsequent tasks that depend on radvd will work correctly. +- name: Flush handlers to start/restart radvd service + ansible.builtin.meta: flush_handlers diff --git a/roles/radvd/tasks/manage_network.yml b/roles/radvd/tasks/manage_network.yml new file mode 100644 index 000000000..2da8e828c --- /dev/null +++ b/roles/radvd/tasks/manage_network.yml @@ -0,0 +1,52 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Assert mandatory parameters + ansible.builtin.assert: + that: + - cifmw_radvd_network.name is defined + - cifmw_radvd_network.state | default('present') in ['present', 'absent'] + - cifmw_radvd_network.state | default('present') == 'absent' or cifmw_radvd_network.prefixes is defined + - cifmw_radvd_network.state | default('present') == 'absent' or cifmw_radvd_network.prefixes | type_debug == "list" + +- name: Create network configuration fragment + become: true + when: + - cifmw_radvd_network.state | default('present') == 'present' + ansible.builtin.template: + dest: >- + {{ cifmw_radvd_basedir }}/{{ cifmw_radvd_network.name }}.conf + mode: "0644" + src: "network.conf.j2" + +- name: Remove network configuration fragment + become: true + when: + - cifmw_radvd_network.state | default('present') == 'absent' + ansible.builtin.file: + path: >- + {{ cifmw_radvd_basedir }}/{{ cifmw_radvd_network.name }}.conf + state: absent + +- name: Assemble radvd configuration from fragments + become: true + notify: Restart radvd service + ansible.builtin.assemble: + src: "{{ cifmw_radvd_basedir }}" + dest: "/etc/radvd.conf" + regexp: '\.conf$' + mode: "0644" + validate: "/usr/sbin/radvd -c -C %s" diff --git a/roles/radvd/templates/network.conf.j2 b/roles/radvd/templates/network.conf.j2 new file mode 100644 index 000000000..e258e93be --- /dev/null +++ b/roles/radvd/templates/network.conf.j2 @@ -0,0 +1,63 @@ +# Managed by ci-framework/radvd +# Configuration for {{ cifmw_radvd_network.name }} network + +interface {{ cifmw_radvd_network.name }} +{ + AdvSendAdvert {{ (cifmw_radvd_network.adv_send_advert | default(true)) | ternary('on', 'off') }}; +{% if cifmw_radvd_network.adv_managed_flag is defined %} + AdvManagedFlag {{ cifmw_radvd_network.adv_managed_flag | ternary('on', 'off') }}; +{% endif %} +{% if cifmw_radvd_network.adv_other_config_flag is defined %} + AdvOtherConfigFlag {{ cifmw_radvd_network.adv_other_config_flag | ternary('on', 'off') }}; +{% endif %} +{% if cifmw_radvd_network.adv_ra_solicited_unicast is defined %} + AdvRASolicitedUnicast {{ cifmw_radvd_network.adv_ra_solicited_unicast | ternary('on', 'off') }}; +{% endif %} +{% if cifmw_radvd_network.adv_link_mtu is defined %} + AdvLinkMTU {{ cifmw_radvd_network.adv_link_mtu }}; +{% endif %} +{% if cifmw_radvd_network.min_rtr_adv_interval is defined %} + MinRtrAdvInterval {{ cifmw_radvd_network.min_rtr_adv_interval }}; +{% endif %} +{% if cifmw_radvd_network.max_rtr_adv_interval is defined %} + MaxRtrAdvInterval {{ cifmw_radvd_network.max_rtr_adv_interval }}; +{% endif %} +{% for prefix in cifmw_radvd_network.prefixes | default([]) %} + prefix {{ prefix.network }} + { + AdvOnLink {{ (prefix.adv_on_link | default(true)) | ternary('on', 'off') }}; + AdvAutonomous {{ (prefix.adv_autonomous | default(true)) | ternary('on', 'off') }}; +{% if prefix.adv_router_addr is defined %} + AdvRouterAddr {{ prefix.adv_router_addr | ternary('on', 'off') }}; +{% endif %} +{% if prefix.adv_valid_lifetime is defined %} + AdvValidLifetime {{ prefix.adv_valid_lifetime }}; +{% endif %} +{% if prefix.adv_preferred_lifetime is defined %} + AdvPreferredLifetime {{ prefix.adv_preferred_lifetime }}; +{% endif %} + }; + +{% endfor %} +{% for route in cifmw_radvd_network.routes | default([]) %} + route {{ route.network }} + { +{% if route.adv_route_preference is defined %} + AdvRoutePreference {{ route.adv_route_preference }}; +{% endif %} +{% if route.adv_route_lifetime is defined %} + AdvRouteLifetime {{ route.adv_route_lifetime }}; +{% endif %} + }; + +{% endfor %} +{% for rdnss in cifmw_radvd_network.rdnss | default([]) %} + RDNSS {{ rdnss.servers | join(' ') }} + { +{% if rdnss.adv_rdnss_lifetime is defined %} + AdvRDNSSLifetime {{ rdnss.adv_rdnss_lifetime }}; +{% endif %} + }; + +{% endfor %} +}; diff --git a/roles/reportportal/OWNERS b/roles/reportportal/OWNERS new file mode 100644 index 000000000..02382fd16 --- /dev/null +++ b/roles/reportportal/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - reportportal-team + +reviewers: + - reportportal-team diff --git a/roles/reproducer/tasks/configure_controller.yml b/roles/reproducer/tasks/configure_controller.yml index 4890ea46d..81db115a1 100644 --- a/roles/reproducer/tasks/configure_controller.yml +++ b/roles/reproducer/tasks/configure_controller.yml @@ -11,6 +11,10 @@ delegate_to: controller-0 delegate_facts: false vars: + # Pass the layout from hypervisor to controller-0 so generate_bm_info.yml + # can access the uefi field to set correct boot_mode in baremetal-info.yml + _cifmw_libvirt_manager_layout: >- + {{ hostvars[inventory_hostname]._cifmw_libvirt_manager_layout }} cifmw_sushy_emulator_hypervisor_target: "{{ inventory_hostname }}" cifmw_sushy_emulator_install_type: podman cifmw_sushy_emulator_hypervisor_address: >- diff --git a/roles/reproducer/tasks/generate_bm_info.yml b/roles/reproducer/tasks/generate_bm_info.yml index 585758b5e..45d9df72d 100644 --- a/roles/reproducer/tasks/generate_bm_info.yml +++ b/roles/reproducer/tasks/generate_bm_info.yml @@ -79,7 +79,7 @@ }} _host: "{{ item.key | replace('cifmw-', '') }}" _uefi: >- - {% set _type = _host | regex_replace('-[0-9]+$', '') -%} + {% set _type = _host | regex_replace('(-[a-z0-9]+)+$', '') -%} {{ _cifmw_libvirt_manager_layout.vms[_type].uefi | default(false) | bool }} _data: | "{{ _host }}": diff --git a/roles/reproducer/tasks/parse_cifmw_job_uri.yml b/roles/reproducer/tasks/parse_cifmw_job_uri.yml index 73ee62d86..6686da8b5 100644 --- a/roles/reproducer/tasks/parse_cifmw_job_uri.yml +++ b/roles/reproducer/tasks/parse_cifmw_job_uri.yml @@ -17,8 +17,7 @@ - name: Extract job id for later reference vars: - user_dir: "{{ lookup('env', 'HOME') }}" - basedir: "{{ user_dir ~ '/ci-framework-data' }}" + basedir: "{{ ansible_user_dir ~ '/ci-framework-data' }}" job_id: "{{ _matched_url| basename }}" ansible.builtin.set_fact: cacheable: true diff --git a/roles/reproducer/tasks/prepare_networking.yml b/roles/reproducer/tasks/prepare_networking.yml index 237f43a5d..125681787 100644 --- a/roles/reproducer/tasks/prepare_networking.yml +++ b/roles/reproducer/tasks/prepare_networking.yml @@ -202,6 +202,7 @@ - names: - "ipmi.utility" - "{{ inventory_hostname }}.utility" + - "virthost.{{ cifmw_devscripts_config.cluster_name }}.{{ cifmw_devscripts_config.base_domain }}" ips: - >- {%- if _target_net.network_v4 is defined -%} diff --git a/roles/rhol_crc/molecule/add_crc_creds/converge.yml b/roles/rhol_crc/molecule/add_crc_creds/converge.yml index f96c0addb..3db5c64b6 100644 --- a/roles/rhol_crc/molecule/add_crc_creds/converge.yml +++ b/roles/rhol_crc/molecule/add_crc_creds/converge.yml @@ -18,7 +18,6 @@ hosts: all gather_facts: true vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_path: "{{ ansible_user_dir }}/.crc/bin:{{ ansible_user_dir }}/.crc/bin/oc:{{ ansible_user_dir }}/bin:{{ ansible_env.PATH }}" tasks: - name: Verify crc creds playbook diff --git a/roles/rhol_crc/molecule/binary/cleanup.yml b/roles/rhol_crc/molecule/binary/cleanup.yml index 0c084d76c..a3e003a09 100644 --- a/roles/rhol_crc/molecule/binary/cleanup.yml +++ b/roles/rhol_crc/molecule/binary/cleanup.yml @@ -18,7 +18,6 @@ - name: Prepare hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_path: "{{ ansible_user_dir }}/.crc/bin:{{ ansible_user_dir }}/.crc/bin/oc:{{ ansible_user_dir }}/bin:{{ ansible_env.PATH }}" tasks: - name: Cleanup RHOL/CRC after tests diff --git a/roles/rhol_crc/molecule/default/cleanup.yml b/roles/rhol_crc/molecule/default/cleanup.yml index cbc74a797..76fed228e 100644 --- a/roles/rhol_crc/molecule/default/cleanup.yml +++ b/roles/rhol_crc/molecule/default/cleanup.yml @@ -18,7 +18,6 @@ - name: Prepare hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_path: "{{ ansible_user_dir }}/.crc/bin:{{ ansible_user_dir }}/.crc/bin/oc:{{ ansible_user_dir }}/bin:{{ ansible_env.PATH }}" tasks: - name: Cleanup CRC diff --git a/roles/rhol_crc/molecule/default/converge.yml b/roles/rhol_crc/molecule/default/converge.yml index bd9afe9b4..524d7d2df 100644 --- a/roles/rhol_crc/molecule/default/converge.yml +++ b/roles/rhol_crc/molecule/default/converge.yml @@ -18,7 +18,6 @@ hosts: all gather_facts: true vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_path: "{{ ansible_user_dir }}/.crc/bin:{{ ansible_user_dir }}/.crc/bin/oc:{{ ansible_user_dir }}/bin:{{ ansible_env.PATH }}" cifmw_manage_secrets_pullsecret_content: > {"auths":{"fake":{"auth": "Zm9vOmJhcgo="}}} diff --git a/roles/rhol_crc/molecule/default/prepare.yml b/roles/rhol_crc/molecule/default/prepare.yml index d9a08b4eb..fd0041a7f 100644 --- a/roles/rhol_crc/molecule/default/prepare.yml +++ b/roles/rhol_crc/molecule/default/prepare.yml @@ -18,7 +18,6 @@ - name: Prepare hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_basedir: "{{ ansible_user_dir }}/ci-framework-data" async_duration: 6000 tasks: diff --git a/roles/rhol_crc/molecule/find_crc/cleanup.yml b/roles/rhol_crc/molecule/find_crc/cleanup.yml index 0c084d76c..a3e003a09 100644 --- a/roles/rhol_crc/molecule/find_crc/cleanup.yml +++ b/roles/rhol_crc/molecule/find_crc/cleanup.yml @@ -18,7 +18,6 @@ - name: Prepare hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_path: "{{ ansible_user_dir }}/.crc/bin:{{ ansible_user_dir }}/.crc/bin/oc:{{ ansible_user_dir }}/bin:{{ ansible_env.PATH }}" tasks: - name: Cleanup RHOL/CRC after tests diff --git a/roles/rhol_crc/molecule/get_versions/cleanup.yml b/roles/rhol_crc/molecule/get_versions/cleanup.yml index 0c084d76c..a3e003a09 100644 --- a/roles/rhol_crc/molecule/get_versions/cleanup.yml +++ b/roles/rhol_crc/molecule/get_versions/cleanup.yml @@ -18,7 +18,6 @@ - name: Prepare hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_path: "{{ ansible_user_dir }}/.crc/bin:{{ ansible_user_dir }}/.crc/bin/oc:{{ ansible_user_dir }}/bin:{{ ansible_env.PATH }}" tasks: - name: Cleanup RHOL/CRC after tests diff --git a/roles/rhol_crc/molecule/get_versions/converge.yml b/roles/rhol_crc/molecule/get_versions/converge.yml index 539cd3c8e..c85ae7f34 100644 --- a/roles/rhol_crc/molecule/get_versions/converge.yml +++ b/roles/rhol_crc/molecule/get_versions/converge.yml @@ -18,7 +18,6 @@ hosts: all gather_facts: true vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_path: "{{ ansible_user_dir }}/.crc/bin:{{ ansible_user_dir }}/.crc/bin/oc:{{ ansible_user_dir }}/bin:{{ ansible_env.PATH }}" tasks: - name: Get CRC and openshift versions diff --git a/roles/run_hook/molecule/default/prepare.yml b/roles/run_hook/molecule/default/prepare.yml index bad6d093d..b3a877abe 100644 --- a/roles/run_hook/molecule/default/prepare.yml +++ b/roles/run_hook/molecule/default/prepare.yml @@ -16,8 +16,6 @@ - name: Prepare hosts: all - vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" tasks: - name: Create dummy env file ansible.builtin.copy: diff --git a/roles/run_hook/tasks/playbook.yml b/roles/run_hook/tasks/playbook.yml index 5f6e79afd..faaafbb78 100644 --- a/roles/run_hook/tasks/playbook.yml +++ b/roles/run_hook/tasks/playbook.yml @@ -19,11 +19,6 @@ cifmw_install_yamls_defaults['OPERATOR_NAMESPACE'] | default('openstack-operators') }} - _namespace: >- - {{ - cifmw_install_yamls_defaults['NAMESPACE'] | - default('openstack') - }} ansible.builtin.set_fact: cifmw_basedir: "{{ _bdir }}" hook_name: "{{ _hook_name }}" @@ -32,7 +27,7 @@ {{ _bdir }}/logs/{{ step }}_{{ _hook_name }}.log extra_vars: >- -e operator_namespace={{ _operator_namespace }} - -e namespace={{ _namespace}} + -e namespace={{ cifmw_openstack_namespace }} {%- if hook.extra_vars is defined and hook.extra_vars|length > 0 -%} {% for key,value in hook.extra_vars.items() -%} {%- if key == 'file' %} diff --git a/roles/set_openstack_containers/molecule/default/converge.yml b/roles/set_openstack_containers/molecule/default/converge.yml index 0b8a125c6..981146840 100644 --- a/roles/set_openstack_containers/molecule/default/converge.yml +++ b/roles/set_openstack_containers/molecule/default/converge.yml @@ -34,6 +34,13 @@ name: 'install_yamls_makes' tasks_from: 'make_download_tools' + - name: Run make crds + vars: + make_keystone_env: "{{ cifmw_install_yamls_environment | combine({'PATH': cifmw_path}) }}" + ansible.builtin.include_role: + name: 'install_yamls_makes' + tasks_from: 'make_openstack_crds' + - name: Run make keystone vars: make_keystone_env: "{{ cifmw_install_yamls_environment | combine({'PATH': cifmw_path}) }}" diff --git a/roles/set_openstack_containers/tasks/main.yml b/roles/set_openstack_containers/tasks/main.yml index 9fb4bc521..576a5f9f0 100644 --- a/roles/set_openstack_containers/tasks/main.yml +++ b/roles/set_openstack_containers/tasks/main.yml @@ -52,13 +52,24 @@ cacheable: true - name: Get meta operator environment variable - environment: - KUBECONFIG: "{{ cifmw_openshift_kubeconfig }}" - PATH: "{{ cifmw_path }}" - cifmw.general.ci_script: - output_dir: "{{ cifmw_set_openstack_containers_basedir }}/artifacts" - script: "oc set env $(oc get pods -n {{ operator_namespace }} -o name -l openstack.org/operator-name={{ operator_name }}) -n {{ operator_namespace }} --list" - register: containers_env_list + block: + - name: Get meta operator environment variable with generic k8s labels + environment: + KUBECONFIG: "{{ cifmw_openshift_kubeconfig }}" + PATH: "{{ cifmw_path }}" + cifmw.general.ci_script: + output_dir: "{{ cifmw_set_openstack_containers_basedir }}/artifacts" + script: "oc set env $(oc get pods -n {{ operator_namespace }} -o name -l app.kubernetes.io/name={{ operator_name }}-operator) -n {{ operator_namespace }} --list" + register: containers_env_list + rescue: + - name: Get meta operator environment variable (for operators not having generic k8s labels) + environment: + KUBECONFIG: "{{ cifmw_openshift_kubeconfig }}" + PATH: "{{ cifmw_path }}" + cifmw.general.ci_script: + output_dir: "{{ cifmw_set_openstack_containers_basedir }}/artifacts" + script: "oc set env $(oc get pods -n {{ operator_namespace }} -o name -l openstack.org/operator-name={{ operator_name }}) -n {{ operator_namespace }} --list" + register: containers_env_list - name: Generate update_env_vars.sh script ansible.builtin.template: diff --git a/roles/shiftstack/OWNERS b/roles/shiftstack/OWNERS new file mode 100644 index 000000000..a081fc3e4 --- /dev/null +++ b/roles/shiftstack/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - shiftstack-team + +reviewers: + - shiftstack-team diff --git a/roles/shiftstack/molecule/default/cleanup.yml b/roles/shiftstack/molecule/default/cleanup.yml index e53697447..cf339403a 100644 --- a/roles/shiftstack/molecule/default/cleanup.yml +++ b/roles/shiftstack/molecule/default/cleanup.yml @@ -17,10 +17,8 @@ - name: Cleanup hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_path: "{{ ansible_user_dir }}/.crc/bin:{{ ansible_user_dir }}/.crc/bin/oc:{{ ansible_user_dir }}/bin:{{ ansible_env.PATH }}" cifmw_openshift_kubeconfig: "{{ ansible_user_dir }}/.crc/machines/crc/kubeconfig" - openstack_namespace_name: openstack tasks: - name: Include the shiftstack role and run the cleanup ansible.builtin.include_role: @@ -35,4 +33,4 @@ apiVersion: v1 kind: Namespace metadata: - name: "{{ openstack_namespace_name }}" + name: "{{ cifmw_openstack_namespace }}" diff --git a/roles/shiftstack/molecule/default/converge.yml b/roles/shiftstack/molecule/default/converge.yml index fb30de541..aaaac4a03 100644 --- a/roles/shiftstack/molecule/default/converge.yml +++ b/roles/shiftstack/molecule/default/converge.yml @@ -18,7 +18,6 @@ - name: Converge hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_path: "{{ ansible_user_dir }}/.crc/bin:{{ ansible_user_dir }}/.crc/bin/oc:{{ ansible_user_dir }}/bin:{{ ansible_env.PATH }}" cifmw_openshift_kubeconfig: "{{ ansible_user_dir }}/.crc/machines/crc/kubeconfig" cifmw_shiftstack_run_playbook: cifmw-gate.yaml diff --git a/roles/shiftstack/molecule/default/prepare.yml b/roles/shiftstack/molecule/default/prepare.yml index 531e0efe4..f2bdc984e 100644 --- a/roles/shiftstack/molecule/default/prepare.yml +++ b/roles/shiftstack/molecule/default/prepare.yml @@ -18,10 +18,8 @@ - name: Prepare hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_path: "{{ ansible_user_dir }}/.crc/bin:{{ ansible_user_dir }}/.crc/bin/oc:{{ ansible_user_dir }}/bin:{{ ansible_env.PATH }}" cifmw_openshift_kubeconfig: "{{ ansible_user_dir }}/.crc/machines/crc/kubeconfig" - openstack_namespace_name: openstack openstack_config_name: openstack-config openstack_config_secret_name: openstack-config-secret openstack_root_ca_secret_name: rootca-public @@ -41,7 +39,7 @@ apiVersion: v1 kind: Namespace metadata: - name: "{{ openstack_namespace_name }}" + name: "{{ cifmw_openstack_namespace }}" - name: Create a dummy configmap kubernetes.core.k8s: @@ -52,7 +50,7 @@ kind: ConfigMap metadata: name: "{{ openstack_config_name }}" - namespace: "{{ openstack_namespace_name }}" + namespace: "{{ cifmw_openstack_namespace }}" data: key1: dummy1 key2: dummy2 @@ -66,7 +64,7 @@ kind: Secret metadata: name: "{{ openstack_config_secret_name }}" - namespace: "{{ openstack_namespace_name }}" + namespace: "{{ cifmw_openstack_namespace }}" type: Opaque data: secure.yaml: ZHVtbXkK # Base64 encoded value of "dummy" @@ -80,7 +78,7 @@ kind: Secret metadata: name: "{{ openstack_root_ca_secret_name }}" - namespace: "{{ openstack_namespace_name }}" + namespace: "{{ cifmw_openstack_namespace }}" type: Opaque data: ca.crt: ZHVtbXkK # Base64 encoded value of "dummy" diff --git a/roles/shiftstack/tasks/cleanup.yml b/roles/shiftstack/tasks/cleanup.yml index 131f2968a..0184ec45b 100644 --- a/roles/shiftstack/tasks/cleanup.yml +++ b/roles/shiftstack/tasks/cleanup.yml @@ -24,7 +24,7 @@ kubeconfig: "{{ cifmw_openshift_kubeconfig }}" api_version: v1 kind: Secret - namespace: openstack + namespace: "{{ cifmw_shiftstack_client_pod_namespace }}" name: "{{ cifmw_shiftstack_client_incluster_secret_name }}" proxy: "{{ cifmw_shiftstack_proxy | default(omit) }}" diff --git a/roles/shiftstack/templates/shiftstackclient_incluster_kubeconfig_secret.yml.j2 b/roles/shiftstack/templates/shiftstackclient_incluster_kubeconfig_secret.yml.j2 index 9e4e2b83f..c9ce45407 100644 --- a/roles/shiftstack/templates/shiftstackclient_incluster_kubeconfig_secret.yml.j2 +++ b/roles/shiftstack/templates/shiftstackclient_incluster_kubeconfig_secret.yml.j2 @@ -2,7 +2,7 @@ apiVersion: v1 kind: Secret metadata: name: "{{ cifmw_shiftstack_client_incluster_secret_name }}" - namespace: openstack + namespace: "{{ cifmw_shiftstack_client_pod_namespace }}" type: Opaque data: kubeconfig: {{ incluster_kubeconfig_base64 }} diff --git a/roles/shiftstack/templates/shiftstackclient_pvc.yml.j2 b/roles/shiftstack/templates/shiftstackclient_pvc.yml.j2 index b6d9b175a..dfd85bb0d 100644 --- a/roles/shiftstack/templates/shiftstackclient_pvc.yml.j2 +++ b/roles/shiftstack/templates/shiftstackclient_pvc.yml.j2 @@ -2,7 +2,7 @@ apiVersion: v1 kind: PersistentVolumeClaim metadata: name: {{ cifmw_shiftstack_client_pod_name }}-pvc - namespace: openstack + namespace: {{ cifmw_shiftstack_client_pod_namespace }} spec: storageClassName: {{ cifmw_shiftstack_sc }} accessModes: diff --git a/roles/ssh_jumper/tasks/manage_ssh_jumper_entry.yml b/roles/ssh_jumper/tasks/manage_ssh_jumper_entry.yml index 51ddf72e0..e1fbd0e87 100644 --- a/roles/ssh_jumper/tasks/manage_ssh_jumper_entry.yml +++ b/roles/ssh_jumper/tasks/manage_ssh_jumper_entry.yml @@ -18,31 +18,42 @@ delegate_to: "{{ _config.target | default(omit) }}" vars: _ssh_dir: >- - {{ - _config.ssh_dir | - default(cifmw_ssh_jumper_defaults.ssh_dir) - }} + {%- if _config.target is defined and _config.target == 'localhost' -%} + {{ lookup('env', 'HOME') }}/.ssh + {%- else -%} + {{ _config.ssh_dir }} + {%- endif -%} ansible.builtin.file: - path: "{{ _ssh_dir }}/cifmw_ssh_config.d//{{ inventory_hostname }}" + path: "{{ _ssh_dir }}/cifmw_ssh_config.d/{{ inventory_hostname }}" state: directory mode: '0700' - name: Include ~/.ssh/cifmw_ssh_config.d/inventory_hostname/*.conf delegate_to: "{{ _config.target | default(omit) }}" vars: - _ssh_dir: "{{ _config.ssh_dir | default(cifmw_ssh_jumper_defaults.ssh_dir) }}" + _ssh_dir: >- + {%- if _config.target is defined and _config.target == 'localhost' -%} + {{ lookup('env', 'HOME') }}/.ssh + {%- else -%} + {{ _config.ssh_dir }} + {%- endif -%} ansible.builtin.lineinfile: insertbefore: BOF create: true state: present - path: "{{ _ssh_dir | default((ansible_user_dir, '/.ssh') | path_join) }}/config" + path: "{{ _ssh_dir }}/config" mode: '0600' line: 'Include cifmw_ssh_config.d/{{ inventory_hostname }}/*.conf' - name: "Inject ssh jumpers for {{ _config.hostname }}" delegate_to: "{{ _config.target | default(omit) }}" vars: - _ssh_dir: "{{ _config.ssh_dir | default(cifmw_ssh_jumper_defaults.ssh_dir) }}" + _ssh_dir: >- + {%- if _config.target is defined and _config.target == 'localhost' -%} + {{ lookup('env', 'HOME') }}/.ssh + {%- else -%} + {{ _config.ssh_dir }} + {%- endif -%} _dir: "{{ _ssh_dir }}/cifmw_ssh_config.d/{{ inventory_hostname }}" _filename: >- {%- if _config.proxy_host is defined and _config.proxy_host is not none -%} diff --git a/roles/ssh_jumper/templates/ssh_host.conf.j2 b/roles/ssh_jumper/templates/ssh_host.conf.j2 index 5cbf906fa..e989774c7 100644 --- a/roles/ssh_jumper/templates/ssh_host.conf.j2 +++ b/roles/ssh_jumper/templates/ssh_host.conf.j2 @@ -1,4 +1,4 @@ -Host {{ (_config.patterns | default(cifmw_ssh_jumper_defaults.patterns) + [_config.hostname]) | join(' ') }} +Host {{ (_config.patterns | default(cifmw_ssh_jumper_defaults.patterns) + [_config.hostname]) | unique | join(' ') }} Hostname {{ _config.hostname }} {% if _config.proxy_host is defined and _config.proxy_host is not none %} ProxyJump {{ _config.proxy_user | default(cifmw_ssh_jumper_defaults.user) }}@{{ _config.proxy_host }} diff --git a/roles/ssh_jumper/vars/main.yml b/roles/ssh_jumper/vars/main.yml index 7d26c9909..69c09a839 100644 --- a/roles/ssh_jumper/vars/main.yml +++ b/roles/ssh_jumper/vars/main.yml @@ -15,7 +15,7 @@ # under the License. cifmw_ssh_jumper_defaults: - ssh_dir: "{{ ansible_user_dir }}/.ssh" + ssh_dir: "{{ ansible_user_dir | default(lookup('env', 'HOME')) }}/.ssh" user: zuul patterns: [] proxy_user: "{{ ansible_user | default(lookup('env', 'USER')) }}" diff --git a/roles/sushy_emulator/tasks/create_container.yml b/roles/sushy_emulator/tasks/create_container.yml index 8982e20e4..28f8f9855 100644 --- a/roles/sushy_emulator/tasks/create_container.yml +++ b/roles/sushy_emulator/tasks/create_container.yml @@ -19,9 +19,13 @@ name: podman - name: Pull Sushy Emulator container image + register: _sushy_emulator_fetch_img containers.podman.podman_image: name: "{{ cifmw_sushy_emulator_image }}" state: present + retries: 3 + delay: 5 + until: _sushy_emulator_fetch_img is success - name: Create and start Sushy Emulator container vars: diff --git a/roles/switch_config/OWNERS b/roles/switch_config/OWNERS new file mode 100644 index 000000000..7a15ba5da --- /dev/null +++ b/roles/switch_config/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - nfv-team + +reviewers: + - nfv-team diff --git a/roles/tempest/OWNERS b/roles/tempest/OWNERS new file mode 100644 index 000000000..b7883e567 --- /dev/null +++ b/roles/tempest/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - ciops-team + +reviewers: + - ciops-team diff --git a/roles/tempest/molecule/default/converge.yml b/roles/tempest/molecule/default/converge.yml index d14ceb88e..338a069ad 100644 --- a/roles/tempest/molecule/default/converge.yml +++ b/roles/tempest/molecule/default/converge.yml @@ -18,7 +18,6 @@ - name: Converge hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_tempest_dry_run: true roles: - role: "tempest" diff --git a/roles/tempest/molecule/default/prepare.yml b/roles/tempest/molecule/default/prepare.yml index 810486ac1..0c6d52693 100644 --- a/roles/tempest/molecule/default/prepare.yml +++ b/roles/tempest/molecule/default/prepare.yml @@ -18,7 +18,6 @@ - name: Prepare hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_basedir: "{{ ansible_user_dir }}/ci-framework-data" cifmw_install_yamls_tasks_out: "{{ ansible_user_dir }}/zuul-jobs/roles/install_yamls_makes/tasks" cifmw_install_yamls_defaults: diff --git a/roles/tempest/tasks/create-clouds-file.yml b/roles/tempest/tasks/create-clouds-file.yml index 16da82bb0..1d18ed804 100644 --- a/roles/tempest/tasks/create-clouds-file.yml +++ b/roles/tempest/tasks/create-clouds-file.yml @@ -4,7 +4,7 @@ KUBECONFIG: "{{ cifmw_openshift_kubeconfig }}" PATH: "{{ cifmw_path }}" ansible.builtin.command: - cmd: oc get keystoneapi keystone -n openstack -o json + cmd: 'oc get keystoneapi keystone -n {{ cifmw_openstack_namespace }} -o json' - name: Set keystone vars vars: @@ -20,7 +20,7 @@ KUBECONFIG: "{{ cifmw_openshift_kubeconfig }}" PATH: "{{ cifmw_path }}" ansible.builtin.command: - cmd: 'oc get secret {{ keystone_secret_name }} -n openstack -o json' + cmd: 'oc get secret {{ keystone_secret_name }} -n {{ cifmw_openstack_namespace }} -o json' - name: Get password data vars: diff --git a/roles/tempest/tasks/tempest-tests.yml b/roles/tempest/tasks/tempest-tests.yml index b13f3c9f4..bb48d2069 100644 --- a/roles/tempest/tasks/tempest-tests.yml +++ b/roles/tempest/tasks/tempest-tests.yml @@ -26,7 +26,7 @@ src: "list_allowed.yml" - name: Get list of tests to be executed - tempest_list_allowed: + cifmw.general.tempest_list_allowed: yaml_file: "{{ cifmw_tempest_artifacts_basedir }}/list_allowed.yml" groups: "{{ cifmw_tempest_default_groups }}" job: "{{ cifmw_tempest_job_name | default(omit) }}" @@ -55,7 +55,7 @@ src: "list_skipped.yml" - name: Get list of tests to be excluded - tempest_list_skipped: + cifmw.general.tempest_list_skipped: yaml_file: "{{ cifmw_tempest_artifacts_basedir }}/list_skipped.yml" jobs: "{{ cifmw_tempest_default_jobs }}" register: diff --git a/roles/test_operator/OWNERS b/roles/test_operator/OWNERS new file mode 100644 index 000000000..b7883e567 --- /dev/null +++ b/roles/test_operator/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - ciops-team + +reviewers: + - ciops-team diff --git a/roles/test_operator/README.md b/roles/test_operator/README.md index fed1cc58c..a66df11c5 100644 --- a/roles/test_operator/README.md +++ b/roles/test_operator/README.md @@ -139,7 +139,7 @@ Default value: {} * `cifmw_test_operator_tobiko_pytest_addopts`: (String) `PYTEST_ADDOPTS` env variable with input pytest args. Example: `-m --maxfail --skipregex `. Defaults to `null`. In case of `null` value, `PYTEST_ADDOPTS` is not set (tobiko tests are executed without any extra pytest options). * `cifmw_test_operator_tobiko_prevent_create`: (Boolean) Sets the value of the env variable `TOBIKO_PREVENT_CREATE` that specifies whether tobiko scenario tests create new resources or expect that those resource had been created before. Default to `null`. In case of `null` value, `TOBIKO_PREVENT_CREATE` is not set (tobiko tests create new resources). * `cifmw_test_operator_tobiko_num_processes`: (Integer) Sets the value of the env variable `TOX_NUM_PROCESSES` that is used to run pytest with `--numprocesses $TOX_NUM_PROCESSES`. Defaults to `null`. In case of `null` value, `TOX_NUM_PROCESSES` is not set (tobiko internally uses the value `auto`, see pytest documentation about the `--numprocesses` option). -* `cifmw_test_operator_tobiko_advanced_image_url`: (String) Tobiko will download images from this URL that will be used to create advance VM instances. By default, the provided image will include all the customizations required by the tobiko tests. Defaults to `https://softwarefactory-project.io/ubuntu-minimal-customized-enp3s0`. +* `cifmw_test_operator_tobiko_advanced_image_url`: (String) Tobiko will download images from this URL that will be used to create advance VM instances. By default, the provided image will include all the customizations required by the tobiko tests. Defaults to `https://github.com/openstack-k8s-operators/openstack-k8s-operators-ci/releases/download/v1.0.0/tobiko-custom-v1.0.0.qcow2`. * `cifmw_test_operator_tobiko_kubeconfig_secret`: (String) Name of the Openshift Secret required to use Openshift Client from the Tobiko pod. Default value: `tobiko-secret` * `cifmw_test_operator_tobiko_openstack_cmd`: (String) Openstack command is used by tobiko to cleanup resources. Default value: `oc -n openstack exec openstackclient -- openstack` * `cifmw_test_operator_tobiko_override_conf`: (Dict) Overrides the default configuration from `cifmw_test_operator_tobiko_default_conf` that is used to generate the tobiko.conf file. Default value: empty dictionary diff --git a/roles/test_operator/defaults/main.yml b/roles/test_operator/defaults/main.yml index 2b664340a..5ceef7368 100644 --- a/roles/test_operator/defaults/main.yml +++ b/roles/test_operator/defaults/main.yml @@ -58,6 +58,7 @@ cifmw_test_operator_log_pod_definition: volumeMounts: "{{ _test_operator_volume_mounts }}" volumes: "{{ _test_operator_volumes }}" tolerations: "{{ cifmw_test_operator_tolerations | default(omit) }}" + nodeSelector: "{{ cifmw_test_operator_node_selector | default(omit) }}" # default test framework registry, namespace and tag can be overridden per test framework (tempest, tobiko, horizontest and ansibletest) cifmw_test_operator_default_registry: quay.io cifmw_test_operator_default_namespace: podified-antelope-centos9 @@ -183,10 +184,10 @@ cifmw_test_operator_tobiko_version: master cifmw_test_operator_tobiko_pytest_addopts: null cifmw_test_operator_tobiko_prevent_create: null cifmw_test_operator_tobiko_num_processes: null -cifmw_test_operator_tobiko_advanced_image_url: "https://softwarefactory-project.io/ubuntu-minimal-customized-enp3s0" +cifmw_test_operator_tobiko_advanced_image_url: "https://github.com/openstack-k8s-operators/openstack-k8s-operators-ci/releases/download/v1.0.0/tobiko-custom-v1.0.0.qcow2" cifmw_test_operator_tobiko_override_conf: {} cifmw_test_operator_tobiko_kubeconfig_secret: tobiko-secret -cifmw_test_operator_tobiko_openstack_cmd: 'oc -n openstack exec openstackclient -- openstack' +cifmw_test_operator_tobiko_openstack_cmd: 'oc -n {{ cifmw_openstack_namespace }} exec openstackclient -- openstack' cifmw_test_operator_tobiko_cleanup: false cifmw_test_operator_tobiko_ssh_keytype: "{{ cifmw_ssh_keytype | default('ecdsa') }}" cifmw_test_operator_tobiko_ssh_keysize: "{{ cifmw_ssh_keysize | default(521) }}" @@ -269,6 +270,8 @@ cifmw_test_operator_ansibletest_config: workflow: "{{ stage_vars_dict.cifmw_test_operator_ansibletest_workflow }}" debug: "{{ stage_vars_dict.cifmw_test_operator_ansibletest_debug }}" resources: "{{ stage_vars_dict.cifmw_test_operator_ansibletest_resources | default(omit) }}" + tolerations: "{{ cifmw_test_operator_tolerations | default(omit) }}" + nodeSelector: "{{ cifmw_test_operator_node_selector | default(omit) }}" # Section 5: horizontest parameters - used when run_test_fw is 'horizontest' cifmw_test_operator_horizontest_name: "horizontest-tests" @@ -322,3 +325,5 @@ cifmw_test_operator_horizontest_config: horizonTestDir: "{{ stage_vars_dict.cifmw_test_operator_horizontest_horizon_test_dir }}" extraMounts: "{{ stage_vars_dict.cifmw_test_operator_horizontest_extra_mounts | default(omit) }}" resources: "{{ stage_vars_dict.cifmw_test_operator_horizontest_resources | default(omit) }}" + tolerations: "{{ cifmw_test_operator_tolerations | default(omit) }}" + nodeSelector: "{{ cifmw_test_operator_node_selector | default(omit) }}" diff --git a/roles/test_operator/molecule/default/converge.yml b/roles/test_operator/molecule/default/converge.yml index a90f6c812..85508e5a9 100644 --- a/roles/test_operator/molecule/default/converge.yml +++ b/roles/test_operator/molecule/default/converge.yml @@ -18,7 +18,6 @@ - name: Converge hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_test_operator_dry_run: true roles: - role: "test_operator" diff --git a/roles/test_operator/molecule/default/prepare.yml b/roles/test_operator/molecule/default/prepare.yml index a90f6c812..85508e5a9 100644 --- a/roles/test_operator/molecule/default/prepare.yml +++ b/roles/test_operator/molecule/default/prepare.yml @@ -18,7 +18,6 @@ - name: Converge hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_test_operator_dry_run: true roles: - role: "test_operator" diff --git a/roles/test_operator/tasks/collect-logs.yaml b/roles/test_operator/tasks/collect-logs.yaml index cbb0c6b28..5d847624e 100644 --- a/roles/test_operator/tasks/collect-logs.yaml +++ b/roles/test_operator/tasks/collect-logs.yaml @@ -37,9 +37,13 @@ loop_var: pvc index_var: index +- name: Set log pod fact to process omitted vars + ansible.builtin.set_fact: + _test_operator_log_pod: "{{ cifmw_test_operator_log_pod_definition }}" + - name: Write log pod definition to file ansible.builtin.copy: - content: "{{ cifmw_test_operator_log_pod_definition }}" + content: "{{ _test_operator_log_pod | to_nice_yaml }}" dest: "{{ cifmw_test_operator_crs_path }}/{{ test_operator_instance_name }}-log-pod.yaml" mode: '0644' diff --git a/roles/test_operator/tasks/run-test-operator-job.yml b/roles/test_operator/tasks/run-test-operator-job.yml index 3078a45da..66e8adaec 100644 --- a/roles/test_operator/tasks/run-test-operator-job.yml +++ b/roles/test_operator/tasks/run-test-operator-job.yml @@ -38,7 +38,7 @@ - name: Write test-operator CR to file ansible.builtin.copy: - content: "{{ test_operator_cr }}" + content: "{{ test_operator_cr | to_nice_yaml }}" dest: "{{ cifmw_test_operator_crs_path }}/{{ test_operator_instance_name }}.yaml" mode: '0644' diff --git a/roles/test_operator/tasks/tempest-tests.yml b/roles/test_operator/tasks/tempest-tests.yml index 31f5aa49a..73f90a926 100644 --- a/roles/test_operator/tasks/tempest-tests.yml +++ b/roles/test_operator/tasks/tempest-tests.yml @@ -26,7 +26,7 @@ src: "list_allowed.yml" - name: Get list of tests to be executed - tempest_list_allowed: + cifmw.general.tempest_list_allowed: yaml_file: "{{ cifmw_test_operator_artifacts_basedir }}/list_allowed.yml" groups: "{{ cifmw_test_operator_default_groups }}" job: "{{ cifmw_test_operator_instance_name | default(omit) }}" @@ -60,7 +60,7 @@ mode: "0644" - name: Get list of tests to be excluded - tempest_list_skipped: + cifmw.general.tempest_list_skipped: yaml_file: "{{ cifmw_test_operator_artifacts_basedir }}/list_skipped.yml" jobs: "{{ cifmw_test_operator_default_jobs }}" register: diff --git a/roles/test_operator/vars/main.yml b/roles/test_operator/vars/main.yml index 20fb5d353..ed8288041 100644 --- a/roles/test_operator/vars/main.yml +++ b/roles/test_operator/vars/main.yml @@ -33,9 +33,8 @@ cifmw_test_operator_tobiko_default_conf: testcase: timeout: 1800.0 test_runner_timeout: 14400.0 - ubuntu: - interface_name: enp3s0 - customized_image_provided: "True" + advanced_vm: + username: fedora image_url: "{{ cifmw_test_operator_tobiko_advanced_image_url }}" keystone: interface: public diff --git a/roles/tofu/OWNERS b/roles/tofu/OWNERS new file mode 100644 index 000000000..1a0f05f41 --- /dev/null +++ b/roles/tofu/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - tofu-owners + +reviewers: + - tofu-owners diff --git a/roles/tofu/molecule/default/prepare.yml b/roles/tofu/molecule/default/prepare.yml index d6287b5be..822af8b1e 100644 --- a/roles/tofu/molecule/default/prepare.yml +++ b/roles/tofu/molecule/default/prepare.yml @@ -18,7 +18,6 @@ - name: Prepare hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_basedir: "{{ ansible_user_dir }}/ci-framework-data" cifmw_install_yamls_tasks_out: "{{ ansible_user_dir }}/zuul-jobs/roles/install_yamls_makes/tasks" cifmw_install_yamls_defaults: diff --git a/roles/update/OWNERS b/roles/update/OWNERS new file mode 100644 index 000000000..5194dfd10 --- /dev/null +++ b/roles/update/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - updates-team + +reviewers: + - updates-team diff --git a/roles/update/molecule/default/converge.yml b/roles/update/molecule/default/converge.yml index d5482b8bb..fb4aae26d 100644 --- a/roles/update/molecule/default/converge.yml +++ b/roles/update/molecule/default/converge.yml @@ -18,9 +18,8 @@ - name: Converge hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_update_run_dryrun: true - cifmw_openshift_kubeconfig: "{{ lookup('env', 'HOME') }}/.crc/machines/crc/kubeconfig" + cifmw_openshift_kubeconfig: "{{ ansible_user_dir }}/.crc/machines/crc/kubeconfig" cifmw_nolog: false tasks: - name: Initialize monitoring diff --git a/roles/update/molecule/default/prepare.yml b/roles/update/molecule/default/prepare.yml index 15e5eefb1..5a145c1b3 100644 --- a/roles/update/molecule/default/prepare.yml +++ b/roles/update/molecule/default/prepare.yml @@ -18,7 +18,6 @@ - name: Prepare hosts: all vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_install_yamls_tasks_out: "{{ ansible_user_dir }}/zuul-jobs/roles/install_yamls_makes/tasks" cifmw_install_yamls_defaults: NAMESPACE: openstack diff --git a/roles/update/tasks/collect_openstackclient_config.yml b/roles/update/tasks/collect_openstackclient_config.yml index 84466b7f0..e0cf41dca 100644 --- a/roles/update/tasks/collect_openstackclient_config.yml +++ b/roles/update/tasks/collect_openstackclient_config.yml @@ -2,7 +2,7 @@ - name: Collect file from openstackclient container kubernetes.core.k8s_exec: kubeconfig: "{{ cifmw_openshift_kubeconfig }}" - namespace: "openstack" + namespace: "{{ cifmw_openstack_namespace }}" api_key: "{{ cifmw_openshift_token | default(omit) }}" context: "{{ cifmw_openshift_context | default(omit) }}" pod: "openstackclient" diff --git a/roles/update/tasks/create_local_openstackclient.yml b/roles/update/tasks/create_local_openstackclient.yml index 2d8b20999..78e79fb01 100644 --- a/roles/update/tasks/create_local_openstackclient.yml +++ b/roles/update/tasks/create_local_openstackclient.yml @@ -2,7 +2,7 @@ - name: Retrieve the openstackclient Pod kubernetes.core.k8s_info: kubeconfig: "{{ cifmw_openshift_kubeconfig }}" - namespace: "openstack" + namespace: "{{ cifmw_openstack_namespace }}" api_key: "{{ cifmw_openshift_token | default(omit) }}" context: "{{ cifmw_openshift_context | default(omit) }}" kind: "Pod" diff --git a/roles/validations/OWNERS b/roles/validations/OWNERS new file mode 100644 index 000000000..604f4ecc3 --- /dev/null +++ b/roles/validations/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - drosenfe # Individual contributor + +reviewers: + - drosenfe diff --git a/scenarios/adoption/uni04delta.yml b/scenarios/adoption/uni04delta.yml new file mode 100644 index 000000000..4e9e5200e --- /dev/null +++ b/scenarios/adoption/uni04delta.yml @@ -0,0 +1,2 @@ +libvirt_manager_patch_layout: {} +networking_mapper_definition_patch: {} diff --git a/scenarios/centos-9/ci.yml b/scenarios/centos-9/ci.yml index a0340e03f..95e9357bb 100644 --- a/scenarios/centos-9/ci.yml +++ b/scenarios/centos-9/ci.yml @@ -1,6 +1,4 @@ --- -ansible_user_dir: "{{ lookup('env', 'HOME') }}" - cifmw_openshift_user: "kubeadmin" cifmw_openshift_password: "123456789" cifmw_openshift_kubeconfig: "{{ ansible_user_dir }}/.crc/machines/crc/kubeconfig" diff --git a/scenarios/centos-9/content_provider.yml b/scenarios/centos-9/content_provider.yml index a51b7a953..049da1da5 100644 --- a/scenarios/centos-9/content_provider.yml +++ b/scenarios/centos-9/content_provider.yml @@ -1,5 +1,4 @@ --- -ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_operator_build_push_registry: "{{ cifmw_rp_registry_ip | default('localhost') }}:5001" cifmw_operator_build_push_org: "openstack-k8s-operators" cifmw_operator_build_org: "openstack-k8s-operators" diff --git a/scenarios/centos-9/edpm_baremetal_deployment_ci.yml b/scenarios/centos-9/edpm_baremetal_deployment_ci.yml index f2a859afe..fa9fb2a8f 100644 --- a/scenarios/centos-9/edpm_baremetal_deployment_ci.yml +++ b/scenarios/centos-9/edpm_baremetal_deployment_ci.yml @@ -1,5 +1,4 @@ --- -ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_install_yamls_vars: DEPLOY_DIR: "{{ cifmw_basedir }}/artifacts/edpm_compute" # used during Baremetal deployment BMAAS_INSTANCE_MEMORY: 8192 diff --git a/scenarios/centos-9/edpm_build_images_content_provider.yml b/scenarios/centos-9/edpm_build_images_content_provider.yml index c6c53ff3c..c49f40534 100644 --- a/scenarios/centos-9/edpm_build_images_content_provider.yml +++ b/scenarios/centos-9/edpm_build_images_content_provider.yml @@ -1,3 +1,2 @@ --- -ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_edmp_build_images_push_registry: "{{ cifmw_rp_registry_ip | default('localhost') }}:5001" diff --git a/scenarios/centos-9/edpm_ci.yml b/scenarios/centos-9/edpm_ci.yml index dbf9ab699..07501a52e 100644 --- a/scenarios/centos-9/edpm_ci.yml +++ b/scenarios/centos-9/edpm_ci.yml @@ -1,5 +1,4 @@ --- -ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_install_yamls_vars: BMO_SETUP: false INSTALL_CERT_MANAGER: false @@ -42,4 +41,3 @@ post_ctlplane_deploy: podified_validation: "{{ podified_validation | default (false) | bool }}" cifmw_openshift_kubeconfig: "{{ cifmw_openshift_kubeconfig }}" cifmw_path: "{{ cifmw_path }}" - openstack_namespace: "{{ cifmw_install_yamls_defaults['NAMESPACE'] }}" diff --git a/scenarios/centos-9/hci_ceph_backends.yml b/scenarios/centos-9/hci_ceph_backends.yml index d4ba9620b..e8037863c 100644 --- a/scenarios/centos-9/hci_ceph_backends.yml +++ b/scenarios/centos-9/hci_ceph_backends.yml @@ -1,4 +1,17 @@ --- +# Ceph Overrides: with the following parameters we are able to +# customize the container version and the cephadm package that +# is installed in the HCI nodes. +# +# Override the Ceph container tag and deploy Tentacle +cifmw_cephadm_container_tag: "v20" +# Override the Ceph Tools repo and install cephadm Tentacle +cifmw_cephadm_repository_override: true +cifmw_cephadm_version: "tentacle" +cifmw_cephadm_prepare_host: true +# Apply the new spec version for RGW/TLS +cifmw_rgw_ssl_backward_compatibility: false + cifmw_install_yamls_vars: BMO_SETUP: false INSTALL_CERT_MANAGER: false diff --git a/scenarios/centos-9/meta_content_provider.yml b/scenarios/centos-9/meta_content_provider.yml index a5317f7f2..0ebeba1ca 100644 --- a/scenarios/centos-9/meta_content_provider.yml +++ b/scenarios/centos-9/meta_content_provider.yml @@ -1,6 +1,4 @@ --- -ansible_user_dir: "{{ lookup('env', 'HOME') }}" - # build_operators vars cifmw_operator_build_push_registry: "{{ cifmw_rp_registry_ip }}:{{ cifmw_rp_registry_port }}" cifmw_operator_build_push_org: "openstack-k8s-operators" diff --git a/scenarios/centos-9/podified_common.yml b/scenarios/centos-9/podified_common.yml index c50db2a4b..2c4066d99 100644 --- a/scenarios/centos-9/podified_common.yml +++ b/scenarios/centos-9/podified_common.yml @@ -1,8 +1,6 @@ --- # It is the common scenario file for EDPM multinode podified deployment -ansible_user_dir: "{{ lookup('env', 'HOME') }}" - cifmw_openshift_user: "kubeadmin" cifmw_openshift_password: "123456789" cifmw_openshift_kubeconfig: "{{ ansible_user_dir }}/.crc/machines/crc/kubeconfig" diff --git a/scenarios/centos-9/tcib.yml b/scenarios/centos-9/tcib.yml index b28f9ccab..62023a89c 100644 --- a/scenarios/centos-9/tcib.yml +++ b/scenarios/centos-9/tcib.yml @@ -1,5 +1,4 @@ --- -ansible_user_dir: "{{ lookup('env', 'HOME') }}" cifmw_build_containers_tcib_src: "{{ ansible_user_dir }}/src/github.com/openstack-k8s-operators/tcib" cifmw_repo_setup_src: "{{ ansible_user_dir }}/src/github.com/openstack-k8s-operators/repo-setup" cifmw_build_containers_repo_dir: "{{ cifmw_basedir }}/artifacts/repositories" diff --git a/scenarios/reproducers/bgp-l3-xl.yml b/scenarios/reproducers/bgp-l3-xl.yml index e658f81ce..1bd1c30b0 100644 --- a/scenarios/reproducers/bgp-l3-xl.yml +++ b/scenarios/reproducers/bgp-l3-xl.yml @@ -830,7 +830,7 @@ cifmw_networking_definition: network: "192.168.125.0/24" gateway: "192.168.125.1" dns: - - "192.168.122.1" + - "192.168.125.1" mtu: 1500 tools: multus: @@ -848,6 +848,22 @@ cifmw_networking_definition: - start: 150 end: 200 + ctlplane_ocp_nad: + network: "192.168.126.0/24" + gateway: "192.168.126.1" + dns: + - "192.168.126.1" + mtu: 1500 + tools: + multus: + ranges: + - start: 30 + end: 70 + metallb: + ranges: + - start: 80 + end: 90 + ctlplaner0: network: "192.168.122.0/24" gateway: "192.168.122.1" @@ -1077,13 +1093,15 @@ cifmw_networking_definition: range: start: 10 length: 10 - networks: {} + networks: + ctlplane: {} ocp_workers: network-template: range: start: 20 length: 10 - networks: {} + networks: + ctlplane: {} instances: controller-0: diff --git a/scenarios/reproducers/bgp-l3-xl/OWNERS b/scenarios/reproducers/bgp-l3-xl/OWNERS new file mode 100644 index 000000000..6839704e6 --- /dev/null +++ b/scenarios/reproducers/bgp-l3-xl/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - bgp-team + +reviewers: + - bgp-team diff --git a/scenarios/reproducers/dt-nfv-ovs-dpdk-sriov-ipv6-2nodesets.yml b/scenarios/reproducers/dt-nfv-ovs-dpdk-sriov-ipv6-2nodesets.yml new file mode 100644 index 000000000..8ccecadfa --- /dev/null +++ b/scenarios/reproducers/dt-nfv-ovs-dpdk-sriov-ipv6-2nodesets.yml @@ -0,0 +1,128 @@ +--- +# IPv6 variant of dt-nfv-ovs-dpdk-sriov-2nodesets +# This reproducer configures NFV OVS-DPDK SR-IOV with 2 different nodesets using IPv6 as primary IP + +cifmw_architecture_scenario: "ovs-dpdk-sriov-ipv6-2nodesets" + +# Automation section. Most of those parameters will be passed to the +# controller-0 as-is and be consumed by the `deploy-va.sh` script. +# Please note, all paths are on the controller-0, meaning managed by the +# Framework. Please do not edit them! +_arch_repo: "{{ cifmw_architecture_repo }}" + +# Enable IPv6 as primary IP version +cifmw_ci_gen_kustomize_values_primary_ip_version: 6 + +# Enable libvirt and NAT64 for IPv6-only deployment +cifmw_use_libvirt: true +cifmw_use_nat64: true + +# HERE if you want to override kustomization, you can uncomment this parameter +# and push the data structure you want to apply. +# cifmw_architecture_user_kustomize: +# stage_0: +# 'network-values': +# data: +# starwars: Obiwan + +# HERE, if you want to stop the deployment loop at any stage, you can uncomment +# the following parameter and update the value to match the stage you want to +# reach. Known stages are: +# pre_kustomize_stage_INDEX +# pre_apply_stage_INDEX +# post_apply_stage_INDEX +# +# cifmw_deploy_architecture_stopper: + +cifmw_libvirt_manager_net_prefix_add: false +cifmw_libvirt_manager_fixed_networks: + - ocpbm + - ocppr + - osp_external + - osp_trunk + +cifmw_libvirt_manager_configuration: + networks: + ocpbm: | + + ocpbm + + + + ocppr: | + + ocppr + + + + osp_external: | + + osp_external + + + + osp_trunk: | + + osp_trunk + + + + vms: + controller: + uefi: "{{ cifmw_use_uefi }}" + root_part_id: "{{ cifmw_root_partition_id }}" + image_url: "{{ cifmw_discovered_image_url }}" + sha256_image_name: "{{ cifmw_discovered_hash }}" + image_local_dir: "{{ cifmw_basedir }}/images/" + disk_file_name: "base-os.qcow2" + disksize: 50 + memory: 8 + cpus: 4 + nets: + - ocpbm + - osp_trunk + ocp: + amount: 3 + uefi: true + root_part_id: 4 + admin_user: core + image_local_dir: "{{ cifmw_basedir }}/images/" + disk_file_name: "ocp_master" + disksize: "100" + extra_disks_num: 3 + extra_disks_size: "50G" + cpus: 10 + memory: 32 + nets: + - ocppr + - ocpbm + - osp_trunk + - osp_external + +# Note: with that extra_network_names "osp_trunk", we instruct +# devscripts role to create a new network, and associate it to +# the OCP nodes. This one is a "private network", and will hold +# the VLANs used for network isolation. + +# Please create a custom env file to provide: +# cifmw_devscripts_ci_token: +# cifmw_devscripts_pull_secret: + +# Baremetal host configuration +cifmw_config_bmh: true + +# BMH are deployed in a different NS than the secret OSP BMO +# references in each BMH. Metal3 requires the referenced +# secrets to be in the same NS or be allowed to access them +cifmw_devscripts_config_overrides_patch_bmo_watch_all_namespaces: + bmo_watch_all_namespaces: true + +# Use EDPM image for computes +cifmw_update_containers_edpm_image_url: "{{ cifmw_update_containers_registry }}/{{ cifmw_update_containers_org }}/edpm-hardened-uefi:{{ cifmw_update_containers_tag }}" + +# Set Logical Volume Manager Storage by default for local storage +cifmw_use_lvms: true +cifmw_lvms_disk_list: + - /dev/vda + - /dev/vdb + - /dev/vdc diff --git a/scenarios/reproducers/va-nfv-ovs-dpdk-sriov-ipv6.yml b/scenarios/reproducers/va-nfv-ovs-dpdk-sriov-ipv6.yml new file mode 100644 index 000000000..55573ce63 --- /dev/null +++ b/scenarios/reproducers/va-nfv-ovs-dpdk-sriov-ipv6.yml @@ -0,0 +1,128 @@ +--- +# IPv6 variant of va-nfv-ovs-dpdk-sriov +# This reproducer configures NFV OVS-DPDK SR-IOV with 1 nodeset using IPv6 as primary IP + +cifmw_architecture_scenario: "ovs-dpdk-sriov-ipv6" + +# Automation section. Most of those parameters will be passed to the +# controller-0 as-is and be consumed by the `deploy-va.sh` script. +# Please note, all paths are on the controller-0, meaning managed by the +# Framework. Please do not edit them! +_arch_repo: "{{ cifmw_architecture_repo }}" + +# Enable IPv6 as primary IP version +cifmw_ci_gen_kustomize_values_primary_ip_version: 6 + +# Enable libvirt and NAT64 for IPv6-only deployment +cifmw_use_libvirt: true +cifmw_use_nat64: true + +# HERE if you want to override kustomization, you can uncomment this parameter +# and push the data structure you want to apply. +# cifmw_architecture_user_kustomize: +# stage_0: +# 'network-values': +# data: +# starwars: Obiwan + +# HERE, if you want to stop the deployment loop at any stage, you can uncomment +# the following parameter and update the value to match the stage you want to +# reach. Known stages are: +# pre_kustomize_stage_INDEX +# pre_apply_stage_INDEX +# post_apply_stage_INDEX +# +# cifmw_deploy_architecture_stopper: + +cifmw_libvirt_manager_net_prefix_add: false +cifmw_libvirt_manager_fixed_networks: + - ocpbm + - ocppr + - osp_external + - osp_trunk + +cifmw_libvirt_manager_configuration: + networks: + ocpbm: | + + ocpbm + + + + ocppr: | + + ocppr + + + + osp_external: | + + osp_external + + + + osp_trunk: | + + osp_trunk + + + + vms: + controller: + uefi: "{{ cifmw_use_uefi }}" + root_part_id: "{{ cifmw_root_partition_id }}" + image_url: "{{ cifmw_discovered_image_url }}" + sha256_image_name: "{{ cifmw_discovered_hash }}" + image_local_dir: "{{ cifmw_basedir }}/images/" + disk_file_name: "base-os.qcow2" + disksize: 50 + memory: 8 + cpus: 4 + nets: + - ocpbm + - osp_trunk + ocp: + amount: 3 + uefi: true + root_part_id: 4 + admin_user: core + image_local_dir: "{{ cifmw_basedir }}/images/" + disk_file_name: "ocp_master" + disksize: "100" + extra_disks_num: 3 + extra_disks_size: "50G" + cpus: 10 + memory: 32 + nets: + - ocppr + - ocpbm + - osp_trunk + - osp_external + +# Note: with that extra_network_names "osp_trunk", we instruct +# devscripts role to create a new network, and associate it to +# the OCP nodes. This one is a "private network", and will hold +# the VLANs used for network isolation. + +# Please create a custom env file to provide: +# cifmw_devscripts_ci_token: +# cifmw_devscripts_pull_secret: + +# Baremetal host configuration +cifmw_config_bmh: true + +# BMH are deployed in a differnt NS than the secret OSP BMO +# references in each BMH. Metal3 requires the referenced +# secrets to be in the same NS or be allowed to access them +cifmw_devscripts_config_overrides_patch_bmo_watch_all_namespaces: + bmo_watch_all_namespaces: true + +# Use EDPM image for computes +cifmw_update_containers_edpm_image_url: "{{ cifmw_update_containers_registry }}/{{ cifmw_update_containers_org }}/edpm-hardened-uefi:{{ cifmw_update_containers_tag }}" + +# Set Logical Volume Manager Storage by default for local storage +cifmw_use_lvms: true +cifmw_lvms_disk_list: + - /dev/vda + - /dev/vdb + - /dev/vdc diff --git a/scripts/check-role-prefix.sh b/scripts/check-role-prefix.sh index 73e5a8dea..6ee3ba722 100755 --- a/scripts/check-role-prefix.sh +++ b/scripts/check-role-prefix.sh @@ -1,8 +1,12 @@ #!/bin/bash # Get the latest commit message file -TMP_MSG_FILE=$(mktemp) -git log -1 --pretty=format:"%s%n%n%b" >"$TMP_MSG_FILE" +TMP_MSG_FILE="$1" + +if [ -z "$TMP_MSG_FILE" ]; then + TMP_MSG_FILE=$(mktemp) + git log -1 --pretty=format:"%B" | head -n1 +fi echo "Checking latest commit message:" cat "$TMP_MSG_FILE" diff --git a/scripts/check_k8s_snippets_comment.sh b/scripts/check_k8s_snippets_comment.sh index 4d6642152..5bc8063b5 100755 --- a/scripts/check_k8s_snippets_comment.sh +++ b/scripts/check_k8s_snippets_comment.sh @@ -1,9 +1,9 @@ -#!/bin/sh +#!/usr/bin/env bash set -o pipefail exit_code=0 -missing_comment=$(grep -rL '^# source: ' roles/ci_gen_kustomize_values/templates) +missing_comment=$(grep -rL --exclude="OWNERS" '^# source: ' roles/ci_gen_kustomize_values/templates) if [[ $missing_comment != '' ]]; then echo "!! Following templates are missing the needed '# source: path/to/template' comment." echo " Path must be relative to 'templates'" @@ -13,13 +13,13 @@ if [[ $missing_comment != '' ]]; then let "exit_code+=1" fi -set_path=$(grep -r '^# source: ' roles/ci_gen_kustomize_values/templates | sed 's!roles/ci_gen_kustomize_values/templates/!!') +set_path=$(grep -r --exclude="OWNERS" '^# source: ' roles/ci_gen_kustomize_values/templates | sed 's!roles/ci_gen_kustomize_values/templates/!!') while read match; do - tmpl=$(echo -n "${match}" | cut -d ':' -f 1) - comment=$(echo -n "${match}" | cut -d ':' -f 3 | tr -d '[:space:]') + tmpl=$(echo "${match}" | cut -d ':' -f 1) + comment=$(echo "${match}" | cut -d ':' -f 3 | tr -d '[:space:]') if [[ "${tmpl}" != "${comment}" ]]; then let "exit_code+=1" echo "${tmpl} doesn't have correct 'source': ${comment}" fi -done <<< ${set_path} +done <<< "${set_path}" exit $exit_code diff --git a/scripts/git-check-commit-body-length.sh b/scripts/git-check-commit-body-length.sh index 2ce9e64ea..656806a9a 100755 --- a/scripts/git-check-commit-body-length.sh +++ b/scripts/git-check-commit-body-length.sh @@ -20,7 +20,7 @@ FAIL_LENGTH=0 FAIL_SIGNED_OFF_BY=0 BODY=$(tail -n +3 "$MSG_FILE" | sed '/^\s*#/d' | sed '/^\s*$/d') -BODY_LEN=$(echo -n "$BODY" | wc -m) +BODY_LEN=$(echo -n "$BODY" | sed '/Signed-off-by:/d' | wc -m) if [ "$BODY_LEN" -lt "$MIN_BODY_LEN" ]; then echo -e "\n\n**WARNING: Commit message body is too short (has $BODY_LEN chars, minimum $MIN_BODY_LEN required).**\n" >&2 diff --git a/tests/unit/modules/test_crawl_n_mask.py b/tests/unit/modules/test_crawl_n_mask.py index 519bdd279..8330ae4d2 100644 --- a/tests/unit/modules/test_crawl_n_mask.py +++ b/tests/unit/modules/test_crawl_n_mask.py @@ -1,5 +1,9 @@ +import os +import tempfile +from unittest.mock import MagicMock, patch + import pytest -from unittest.mock import patch, MagicMock + from plugins.modules import crawl_n_mask as cnm @@ -14,10 +18,13 @@ class TestCrawlNMask: ) def test_crawl_true(self, test_dir, expected_files): with patch("os.walk") as mock_walk, patch( - "plugins.modules.crawl_n_mask.mask" - ) as mock_mask: + "plugins.modules.crawl_n_mask.Pool" + ) as mock_pool: mock_walk.return_value = expected_files - mock_mask.return_value = True + # Mock the Pool context manager and map method + mock_pool_instance = MagicMock() + mock_pool.return_value.__enter__.return_value = mock_pool_instance + mock_pool_instance.map.return_value = [True] # At least one file changed module = MagicMock() changed = cnm.crawl(module, test_dir) assert changed @@ -33,33 +40,220 @@ def test_crawl_true(self, test_dir, expected_files): ) def test_crawl_false(self, test_dir, expected_files): with patch("os.walk") as mock_walk, patch( - "plugins.modules.crawl_n_mask.mask" - ) as mock_mask: + "plugins.modules.crawl_n_mask.Pool" + ) as mock_pool: mock_walk.return_value = expected_files - mock_mask.return_value = False + # Mock the Pool context manager and map method + mock_pool_instance = MagicMock() + mock_pool.return_value.__enter__.return_value = mock_pool_instance + mock_pool_instance.map.return_value = [False] # No files changed module = MagicMock() changed = cnm.crawl(module, test_dir) assert not changed - def test_partial_mask_scenario_1(self): - example_value = " 'test1234'\n" - expected_value = " 'te**********34'\n" - test_value = cnm.partial_mask(example_value) + def test_get_masked_string_scenario_1(self): + example_value = "test1234" + expected_value = "te**********34" + test_value = cnm._get_masked_string(example_value) assert expected_value == test_value - def test_partial_mask_scenario_2(self): - example_value = " osp_ci_framework_keytab\n" - expected_value = " 'os**********ab'\n" - test_value = cnm.partial_mask(example_value) + def test_get_masked_string_scenario_2(self): + example_value = "examplea_keytab" + expected_value = "ex**********ab" + test_value = cnm._get_masked_string(example_value) assert expected_value == test_value - def test_partial_mask_scenario_3(self): - example_value = " ''\n" - test_value = cnm.partial_mask(example_value) - assert test_value is None + def test_get_masked_string_scenario_3(self): + example_value = "" + expected_value = "" + test_value = cnm._get_masked_string(example_value) + assert expected_value == test_value - def test_partial_mask_scenario_4(self): - example_value = "tet" - expected_value = "'te**********'" - test_value = cnm.partial_mask(example_value) + def test_get_masked_string_scenario_4(self): + example_value = "test" + expected_value = "te**********" + test_value = cnm._get_masked_string(example_value) assert expected_value == test_value + + @pytest.mark.parametrize( + "input_line, expected_output", + [ + # Test python dict quoted pattern + ( + "'admin_password': 'SuperSecret123'", + "'admin_password': 'Su**********23'", + ), + ( + '"AdminPassword": "MyP@ssw0rd"', + '"AdminPassword": "My**********rd"', + ), + # Test numeric passwords + ( + "'db-password': 123456789", + "'db-password': 12**********89", + ), + # Test empty value + ( + "password: ''", + "password: ''", + ), + # Test plain key-value pattern + ( + "admin_password: secret123", + "admin_password: se**********23", + ), + ( + 'password: "abc123"', + 'password: "ab**********23"', + ), + ( + "password: 'abc123'", + "password: 'ab**********23'", + ), + ( + "mysql_root_password=MyPassword", + "mysql_root_password=My**********rd", + ), + # Test SHA256 tokens - treated as plain key:value + ( + "X-Auth-Token sha256~abc123def456ghi789", + "X-Auth-Token sha256~**********", + ), + # Test Bearer tokens - value gets masked + ( + "bearerToken: eyJhbGciOiJIU2d12ansnR5cCI6IkpXVCJ9", + "bearerToken: ey**********J9", + ), + # Test connection strings - credentials in URL get masked + ( + "admin_password in mysql://user:password123@localhost:3306/db", + "admin_password in mysql://**********:**********@:3306/db", + ), + # Test line without secrets - should remain unchanged + ( + "This is a normal log line without secrets", + "This is a normal log line without secrets", + ), + # Test multiple secrets in one line + ( + "'admin_password': 'secret1' and 'db-password'= 'secret2'", + "'admin_password': 'se**********t1' and 'db-password'= 'se**********t2'", + ), + # Test additional keys from PROTECT_KEYS + ( + "redis_password: myRedisSecret", + "redis_password: my**********et", + ), + ( + "clientSecret:oauth2secret", + "clientSecret:oa**********et", + ), + ( + "postgresPassword :dbP@ssw0rd!", + "postgresPassword :db**********d!", + ), + ( + "'BARBICAN_SIMPLE_CRYPTO_ENCRYPTION_KEY' : 'sE12312341==48943y21'", + "'BARBICAN_SIMPLE_CRYPTO_ENCRYPTION_KEY' : 'sE**********21'", + ), + ], + ) + def test_mask_log_line(self, input_line, expected_output): + result = cnm.mask_log_line(input_line) + assert result == expected_output + + def test_should_skip_ansible_line(self): + assert cnm.should_skip_ansible_line("TASK [Install packages]") == True + assert cnm.should_skip_ansible_line("TASK: Configure database") == True + assert cnm.should_skip_ansible_line("PLAY [Deploy application]") == True + assert cnm.should_skip_ansible_line("Some regular log line") == False + + def test_mask_file_with_real_file(self): + # Create a temporary file with secrets + with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".yaml") as f: + f.write("admin_password: SuperSecret123\n") + f.write( + "db_connection: admin_password in mysql://user:pass123@localhost/db\n" + ) + f.write("normal_config: some_value\n") + temp_path = f.name + + try: + # Mask the file + changed = cnm.mask_file(temp_path) + + # Verify it was changed + assert changed == True + + # Read the masked file + with open(temp_path, "r") as f: + content = f.read() + + # Verify secrets are masked + assert "SuperSecret123" not in content + assert "pass123" not in content + assert "**********" in content + + # Verify normal content is preserved + assert "normal_config: some_value" in content + + finally: + # Clean up + if os.path.exists(temp_path): + os.unlink(temp_path) + + def test_mask_file_no_changes(self): + # Create a temporary file without secrets + with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".yaml") as f: + f.write("normal_config: some_value\n") + f.write("another_config: another_value\n") + temp_path = f.name + + try: + # Mask the file + changed = cnm.mask_file(temp_path) + + # Verify it was not changed + assert changed == False + + # Read the file + with open(temp_path, "r") as f: + content = f.read() + + # Verify content is unchanged + assert "normal_config: some_value" in content + assert "another_config: another_value" in content + + finally: + # Clean up + if os.path.exists(temp_path): + os.unlink(temp_path) + + def test_mask_file_preserves_ansible_task_headers(self): + # Create a temporary file with Ansible task headers + with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".log") as f: + f.write("TASK [Setup admin_password variable]\n") + f.write("admin_password: SuperSecret123\n") + f.write("PLAY [Configure mysql_root_password]\n") + temp_path = f.name + + try: + # Mask the file + changed = cnm.mask_file(temp_path) + + # Read the masked file + with open(temp_path, "r") as f: + content = f.read() + + # Verify task headers are preserved exactly + assert "TASK [Setup admin_password variable]" in content + assert "PLAY [Configure mysql_root_password]" in content + + # Verify the actual secret is masked + assert "SuperSecret123" not in content + assert "**********" in content + + finally: + # Clean up + if os.path.exists(temp_path): + os.unlink(temp_path) diff --git a/update-edpm.yml b/update-edpm.yml index c61026247..22f37dca5 100644 --- a/update-edpm.yml +++ b/update-edpm.yml @@ -28,6 +28,7 @@ vars: cifmw_test_operator_artifacts_basedir: "{{ cifmw_basedir|default(ansible_user_dir ~ '/ci-framework-data') }}/tests/test_operator_update" cifmw_test_operator_tempest_name: "post-update-tempest-tests" + cifmw_test_operator_tobiko_name: "post-update-tobiko-tests" ansible.builtin.import_role: name: cifmw_setup tasks_from: run_tests.yml diff --git a/zuul.d/edpm.yaml b/zuul.d/edpm.yaml index dcd9cf514..54d565e2a 100644 --- a/zuul.d/edpm.yaml +++ b/zuul.d/edpm.yaml @@ -16,6 +16,9 @@ nodeset: centos-9-crc-2-48-0-6xlarge parent: cifmw-base-crc-openstack run: ci/playbooks/edpm_baremetal_deployment/run.yml + irrelevant-files: + - ^hooks/playbooks/ironic_.*\.yml$ + - ^\.github/workflows/* vars: crc_parameters: "--memory 32000 --disk-size 240 --cpus 12" cifmw_manage_secrets_pullsecret_content: '{}' @@ -39,6 +42,23 @@ cifmw_edpm_deploy_baremetal_bootc: true cifmw_update_containers: true +# Virtual Baremetal job with CRC for minor update testing. +# First deploys with pre-update index image (Phase 1), then updates with PR index image (Phase 2). +- job: + name: cifmw-crc-podified-edpm-baremetal-minor-update + nodeset: centos-9-crc-2-48-0-6xlarge + parent: cifmw-base-crc-openstack + run: + - ci/playbooks/edpm_baremetal_update/run.yml + - ci/playbooks/edpm_baremetal_update/update.yml + dependencies: + - openstack-k8s-operators-content-provider + vars: + crc_parameters: "--memory 32000 --disk-size 240 --cpus 12" + cifmw_manage_secrets_pullsecret_content: '{}' + cifmw_rhol_crc_binary_folder: "/usr/local/bin" + cifmw_minor_update_pre_update_tag: "18.0-fr3-latest" + # Podified galera job - job: name: cifmw-crc-podified-galera-deployment diff --git a/zuul.d/edpm_multinode.yaml b/zuul.d/edpm_multinode.yaml index 76cafd702..4b1a50b6e 100644 --- a/zuul.d/edpm_multinode.yaml +++ b/zuul.d/edpm_multinode.yaml @@ -317,6 +317,9 @@ - job: name: podified-multinode-edpm-deployment-crc parent: cifmw-podified-multinode-edpm-base-crc + irrelevant-files: + - ^hooks/playbooks/ironic_.*\.yml$ + - ^\.github/workflows/* vars: cifmw_extras: - '@scenarios/centos-9/multinode-ci.yml' diff --git a/zuul.d/molecule.yaml b/zuul.d/molecule.yaml index 10decae4b..31db44ea9 100644 --- a/zuul.d/molecule.yaml +++ b/zuul.d/molecule.yaml @@ -44,17 +44,6 @@ parent: cifmw-molecule-base vars: TEST_RUN: build_openstack_packages -- job: - files: - - ^common-requirements.txt - - ^test-requirements.txt - - ^roles/build_push_container/.* - - ^ci/playbooks/molecule.* - - ^.config/molecule/.* - name: cifmw-molecule-build_push_container - parent: cifmw-molecule-base - vars: - TEST_RUN: build_push_container - job: files: - ^common-requirements.txt @@ -661,6 +650,17 @@ parent: cifmw-molecule-base vars: TEST_RUN: podman +- job: + files: + - ^common-requirements.txt + - ^test-requirements.txt + - ^roles/radvd/.* + - ^ci/playbooks/molecule.* + - ^.config/molecule/.* + name: cifmw-molecule-radvd + parent: cifmw-molecule-base + vars: + TEST_RUN: radvd - job: files: - ^common-requirements.txt @@ -927,6 +927,24 @@ - ^.config/molecule/.* name: cifmw-molecule-cleanup_openstack parent: cifmw-molecule-noop +- job: + files: + - ^common-requirements.txt + - ^test-requirements.txt + - ^roles/fdp_update_container_images/.* + - ^ci/playbooks/molecule.* + - ^.config/molecule/.* + name: cifmw-molecule-fdp_update_container_images + parent: cifmw-molecule-noop +- job: + files: + - ^common-requirements.txt + - ^test-requirements.txt + - ^roles/fdp_update_edpm/.* + - ^ci/playbooks/molecule.* + - ^.config/molecule/.* + name: cifmw-molecule-fdp_update_edpm + parent: cifmw-molecule-noop - job: files: - ^common-requirements.txt diff --git a/zuul.d/nodeset.yaml b/zuul.d/nodeset.yaml index 1a94cc077..7ef369734 100644 --- a/zuul.d/nodeset.yaml +++ b/zuul.d/nodeset.yaml @@ -278,6 +278,26 @@ nodes: - crc +- nodeset: + name: centos-9-medium-2x-centos-9-crc-extracted-2-39-0-3xl-vexxhost + nodes: + - name: controller + label: cloud-centos-9-stream-tripleo-vexxhost-medium + - name: compute-0 + label: cloud-centos-9-stream-tripleo-vexxhost + - name: compute-1 + label: cloud-centos-9-stream-tripleo-vexxhost + - name: crc + label: coreos-crc-extracted-2-39-0-3xl + groups: + - name: computes + nodes: + - compute-0 + - compute-1 + - name: ocps + nodes: + - crc + - nodeset: name: centos-9-2x-centos-9-xxl-crc-extracted-2-39-0-xxl nodes: @@ -425,6 +445,26 @@ nodes: - crc +- nodeset: + name: centos-9-medium-2x-centos-9-crc-cloud-ocp-4-18-1-3xl-vexxhost + nodes: + - name: controller + label: cloud-centos-9-stream-tripleo-vexxhost-medium + - name: compute-0 + label: cloud-centos-9-stream-tripleo-vexxhost + - name: compute-1 + label: cloud-centos-9-stream-tripleo-vexxhost + - name: crc + label: crc-cloud-ocp-4-18-1-3xl + groups: + - name: computes + nodes: + - compute-0 + - compute-1 + - name: ocps + nodes: + - crc + - nodeset: name: centos-9-2x-centos-9-xxl-crc-cloud-ocp-4-18-1-xxl nodes: @@ -482,6 +522,20 @@ nodes: - crc +- nodeset: + name: centos-9-medium-crc-cloud-ocp-4-18-1-3xl-vexxhost + nodes: + - name: controller + label: cloud-centos-9-stream-tripleo-vexxhost-medium + - name: crc + label: crc-cloud-ocp-4-18-1-3xl + groups: + - name: computes + nodes: [] + - name: ocps + nodes: + - crc + - nodeset: name: centos-9-rhel-9-2-crc-cloud-ocp-4-18-1-3xl nodes: @@ -688,3 +742,352 @@ nodes: - name: controller label: centos-9-stream-crc-2-48-0-6xlarge-ibm + +# +# CRC CLOUD (OCP 4.20) (CRC 2.56.0) nodesets +# + +- nodeset: + name: centos-9-crc-2-56-0-xxl + nodes: + - name: controller + label: centos-9-stream-crc-2-56-0-xxl + +- nodeset: + name: centos-9-medium-2x-centos-9-crc-cloud-ocp-4-20-1-xxl + nodes: + - name: controller + label: cloud-centos-9-stream-tripleo-medium + # Note(Chandan Kumar): Switch to xxl nodeset once RHOSZUUL-1940 resolves + - name: compute-0 + label: cloud-centos-9-stream-tripleo + - name: compute-1 + label: cloud-centos-9-stream-tripleo + - name: crc + label: crc-cloud-ocp-4-20-1-xxl + groups: + - name: computes + nodes: + - compute-0 + - compute-1 + - name: ocps + nodes: + - crc + +- nodeset: + name: centos-9-medium-2x-centos-9-crc-cloud-ocp-4-20-1-3xl + nodes: + - name: controller + label: cloud-centos-9-stream-tripleo-medium + - name: compute-0 + label: cloud-centos-9-stream-tripleo + - name: compute-1 + label: cloud-centos-9-stream-tripleo + - name: crc + label: crc-cloud-ocp-4-20-1-3xl + groups: + - name: computes + nodes: + - compute-0 + - compute-1 + - name: ocps + nodes: + - crc + +- nodeset: + name: centos-9-medium-2x-centos-9-crc-cloud-ocp-4-20-1-3xl-vexxhost + nodes: + - name: controller + label: cloud-centos-9-stream-tripleo-vexxhost-medium + - name: compute-0 + label: cloud-centos-9-stream-tripleo-vexxhost + - name: compute-1 + label: cloud-centos-9-stream-tripleo-vexxhost + - name: crc + label: crc-cloud-ocp-4-20-1-3xl + groups: + - name: computes + nodes: + - compute-0 + - compute-1 + - name: ocps + nodes: + - crc + +- nodeset: + name: centos-9-2x-centos-9-xxl-crc-cloud-ocp-4-20-1-xxl + nodes: + - name: controller + label: cloud-centos-9-stream-tripleo + - name: compute-0 + label: cloud-centos-9-stream-tripleo-xxl + - name: compute-1 + label: cloud-centos-9-stream-tripleo-xxl + - name: crc + label: crc-cloud-ocp-4-20-1-xxl + groups: + - name: computes + nodes: + - compute-0 + - compute-1 + - name: ocps + nodes: + - crc + +- nodeset: + name: centos-9-medium-3x-centos-9-crc-cloud-ocp-4-20-1-xxl + nodes: + - name: controller + label: cloud-centos-9-stream-tripleo-medium + - name: compute-0 + label: cloud-centos-9-stream-tripleo + - name: compute-1 + label: cloud-centos-9-stream-tripleo + - name: compute-2 + label: cloud-centos-9-stream-tripleo + - name: crc + label: crc-cloud-ocp-4-20-1-xxl + groups: + - name: computes + nodes: + - compute-0 + - compute-1 + - compute-2 + - name: ocps + nodes: + - crc + +- nodeset: + name: centos-9-medium-crc-cloud-ocp-4-20-1-3xl + nodes: + - name: controller + label: cloud-centos-9-stream-tripleo-medium + - name: crc + label: crc-cloud-ocp-4-20-1-3xl + groups: + - name: computes + nodes: [] + - name: ocps + nodes: + - crc + +- nodeset: + name: centos-9-medium-crc-cloud-ocp-4-20-1-3xl-vexxhost + nodes: + - name: controller + label: cloud-centos-9-stream-tripleo-vexxhost-medium + - name: crc + label: crc-cloud-ocp-4-20-1-3xl + groups: + - name: computes + nodes: [] + - name: ocps + nodes: + - crc + +- nodeset: + name: centos-9-rhel-9-2-crc-cloud-ocp-4-20-1-3xl + nodes: + - name: controller + label: cloud-centos-9-stream-tripleo + - name: crc + label: crc-cloud-ocp-4-20-1-3xl + - name: standalone + label: cloud-rhel-9-2-tripleo + groups: + - name: computes + nodes: [] + - name: ocps + nodes: + - crc + - name: rh-subscription + nodes: + - standalone + +- nodeset: + name: centos-9-multinode-rhel-9-2-crc-cloud-ocp-4-20-1-3xl + nodes: + - name: controller + label: cloud-centos-9-stream-tripleo + - name: crc + label: crc-cloud-ocp-4-20-1-3xl + - name: undercloud + label: cloud-rhel-9-2-tripleo + - name: overcloud-controller-0 + label: cloud-rhel-9-2-tripleo + - name: overcloud-controller-1 + label: cloud-rhel-9-2-tripleo + - name: overcloud-controller-2 + label: cloud-rhel-9-2-tripleo + - name: overcloud-novacompute-0 + label: cloud-rhel-9-2-tripleo + - name: overcloud-novacompute-1 + label: cloud-rhel-9-2-tripleo + - name: overcloud-novacompute-2 + label: cloud-rhel-9-2-tripleo + groups: + - name: computes + nodes: [] + - name: ocps + nodes: + - crc + - name: rh-subscription + nodes: + - undercloud + - overcloud-controller-0 + - overcloud-controller-1 + - overcloud-controller-2 + - overcloud-novacompute-0 + - overcloud-novacompute-1 + - overcloud-novacompute-2 + - name: tripleo_controllers + nodes: + - overcloud-controller-0 + - overcloud-controller-1 + - overcloud-controller-2 + - name: tripleo_computes + nodes: + - overcloud-novacompute-0 + - overcloud-novacompute-1 + - overcloud-novacompute-2 + +- nodeset: + name: centos-9-multinode-rhel-9-2-crc-cloud-ocp-4-20-1-3xl-novacells + nodes: + - name: controller + label: cloud-centos-9-stream-tripleo + - name: crc + label: crc-cloud-ocp-4-20-1-3xl + - name: undercloud + label: cloud-rhel-9-2-tripleo + - name: overcloud-controller-0 + label: cloud-rhel-9-2-tripleo + - name: cell1-controller-0 + label: cloud-rhel-9-2-tripleo + - name: cell1-compute-0 + label: cloud-rhel-9-2-tripleo + - name: cell2-controller-compute-0 + label: cloud-rhel-9-2-tripleo + groups: + - name: computes + nodes: [] + - name: ocps + nodes: + - crc + - name: rh-subscription + nodes: + - undercloud + - overcloud-controller-0 + - cell1-controller-0 + - cell2-controller-compute-0 + - cell1-compute-0 + - name: tripleo_controllers + nodes: + - overcloud-controller-0 + - cell1-controller-0 + - cell2-controller-compute-0 + - name: tripleo_computes + nodes: + - cell1-compute-0 + - cell2-controller-compute-0 + +- nodeset: + name: centos-9-medium-centos-9-crc-cloud-ocp-4-20-1-3xl + nodes: + - name: controller + label: cloud-centos-9-stream-tripleo-medium + - name: compute-0 + label: cloud-centos-9-stream-tripleo + - name: crc + label: crc-cloud-ocp-4-20-1-3xl + groups: + - name: computes + nodes: + - compute-0 + - name: ocps + nodes: + - crc + +- nodeset: + name: centos-9-crc-2-56-0-3xl + nodes: + - name: controller + label: centos-9-stream-crc-2-56-0-3xl + +- nodeset: + name: centos-9-medium-3x-centos-9-crc-cloud-ocp-4-20-1-3xl + nodes: + - name: controller + label: cloud-centos-9-stream-tripleo-medium + - name: compute-0 + label: cloud-centos-9-stream-tripleo + - name: compute-1 + label: cloud-centos-9-stream-tripleo + - name: compute-2 + label: cloud-centos-9-stream-tripleo + - name: crc + label: crc-cloud-ocp-4-20-1-3xl + groups: + - name: computes + nodes: + - compute-0 + - compute-1 + - compute-2 + - name: ocps + nodes: + - crc + +# todo: Remove. Temporal. Needed as the credentials used in ci-bootstrap jobs for IBM don't work +- nodeset: + name: centos-9-medium-centos-9-crc-cloud-ocp-4-20-1-3xl-vexxhost + nodes: + - name: controller + label: cloud-centos-9-stream-tripleo-vexxhost-medium + - name: compute-0 + label: cloud-centos-9-stream-tripleo-vexxhost + - name: crc + label: crc-cloud-ocp-4-20-1-3xl + groups: + - name: computes + nodes: + - compute-0 + - name: ocps + nodes: + - crc + +- nodeset: + name: centos-9-crc-2-56-0-6xlarge + nodes: + - name: controller + label: centos-9-stream-crc-2-56-0-6xlarge + +- nodeset: + name: centos-9-crc-2-56-0-xl + nodes: + - name: controller + label: centos-9-stream-crc-2-56-0-xl + +### Molecule jobs - force use IBM hosts ### +- nodeset: + name: centos-9-crc-2-56-0-xl-ibm + nodes: + - name: controller + label: centos-9-stream-crc-2-56-0-xl-ibm + +- nodeset: + name: centos-9-crc-2-56-0-xxl-ibm + nodes: + - name: controller + label: centos-9-stream-crc-2-56-0-xxl-ibm + +- nodeset: + name: centos-9-crc-2-56-0-3xl-ibm + nodes: + - name: controller + label: centos-9-stream-crc-2-56-0-3xl-ibm + +- nodeset: + name: centos-9-crc-2-56-0-6xlarge-ibm + nodes: + - name: controller + label: centos-9-stream-crc-2-56-0-6xlarge-ibm diff --git a/zuul.d/pods.yaml b/zuul.d/pods.yaml index 9c61e3cf2..ff1755627 100644 --- a/zuul.d/pods.yaml +++ b/zuul.d/pods.yaml @@ -41,76 +41,3 @@ run_test: "check_k8s_snippets_comment" files: - ^roles/ci_gen_kustomize_values/templates/.* - -# -# cifmw-client container build and push jobs -# -- job: - name: build-push-container-build - description: | - Build container using build_push_container - role. - This is a base job that can be consumed by other projects. - pre-run: - molecule-prepare.yml - Copies required projects and installs dependencies. - dump_zuul_data.yml - Copies Zuul inventory and variables to disk for later use. - run: - build_push_container_runner.yml - Nested ansible-playbook call to run - build_push_container.yml on controller. - vars: - buildah_login & registry_login_enabled - Both used by build-push-container-base job - in config repo to trigger logging into quay.rdoproject.org for later use. - parent: build-push-container-base - nodeset: centos-stream-9 - pre-run: - - ci/playbooks/molecule-prepare.yml - - ci/playbooks/dump_zuul_data.yml - run: ci/playbooks/build_push_container_runner.yml - post-run: ci/playbooks/collect-logs.yml - vars: - buildah_login: true - registry_login_enabled: true -- job: - name: build-push-container-cifmw-client - description: | - Build and push cifmw-client container to - quay.rdoproject.com registry. - vars: - cifmw_build_push_container_push - Used by build_push_container role to trigger pushing to registry. - cifmw_build_push_container_name - Name of container being build and pushed. - cifmw_build_push_container_containerfile_path - Path to containerfile. - cifmw_build_push_container_registry_name - Registry built containers will be pushed too. - Runtime: ~30mins. - parent: build-push-container-build - vars: - ansible_user_dir: "{{ lookup('env', 'HOME') }}" - cifmw_ci_framework_src: >- - {{ - (ansible_user_dir, - zuul.project.src_dir) | ansible.builtin.path_join - }} - cifmw_build_push_container_push: true - cifmw_build_push_container_name: cifmw-client - cifmw_build_push_container_containerfile_path: >- - {{ - (cifmw_ci_framework_src, - 'containerfiles', - 'Containerfile.client') | ansible.builtin.path_join - }} - cifmw_build_push_container_registry_name: >- - quay.rdoproject.org/openstack-k8s-operators/cifmw-client - cifmw_build_push_container_supported_platform: [linux/arm64, linux/amd64] - timeout: 5400 - -- job: - name: build-push-container-cifmw-client-post - description: | - Build and push cifmw-client container to - quay.rdoproject.com registry and tag with latest - To be ran in post pipeline as it controls the 'latest' tag - vars: - cifmw_build_push_container_tag_override - If branch is main, add latest tag, - otherwise tag with -latest - parent: build-push-container-cifmw-client - vars: - cifmw_build_push_container_tag_override: "{{ ['latest'] if zuul.branch == 'main' else [zuul.branch ~ 'latest'] }}" diff --git a/zuul.d/project-templates.yaml b/zuul.d/project-templates.yaml index 0257ae19f..394382b5a 100644 --- a/zuul.d/project-templates.yaml +++ b/zuul.d/project-templates.yaml @@ -59,8 +59,10 @@ - cifmw-molecule irrelevant-files: - scripts/check-role-prefix.sh + - ^\.github/workflows/* - podified-multinode-edpm-deployment-crc: *content_provider - cifmw-crc-podified-edpm-baremetal: *content_provider + - cifmw-crc-podified-edpm-baremetal-minor-update: *content_provider - podified-multinode-hci-deployment-crc: *content_provider - cifmw-multinode-tempest: *content_provider - cifmw-pod-zuul-files diff --git a/zuul.d/projects.yaml b/zuul.d/projects.yaml index f68e2c335..b51fad17f 100644 --- a/zuul.d/projects.yaml +++ b/zuul.d/projects.yaml @@ -12,12 +12,10 @@ - cifmw-tcib - cifmw-architecture-validate-hci - ci-framework-openstack-meta-content-provider - - build-push-container-cifmw-client - cifmw-molecule-adoption_osp_deploy - cifmw-molecule-artifacts - cifmw-molecule-build_containers - cifmw-molecule-build_openstack_packages - - cifmw-molecule-build_push_container - cifmw-molecule-cert_manager - cifmw-molecule-ci_dcn_site - cifmw-molecule-ci_gen_kustomize_values @@ -55,6 +53,8 @@ - cifmw-molecule-edpm_kustomize - cifmw-molecule-edpm_prepare - cifmw-molecule-env_op_images + - cifmw-molecule-fdp_update_container_images + - cifmw-molecule-fdp_update_edpm - cifmw-molecule-federation - cifmw-molecule-fix_python_encodings - cifmw-molecule-hci_prepare @@ -85,6 +85,7 @@ - cifmw-molecule-pkg_build - cifmw-molecule-podman - cifmw-molecule-polarion + - cifmw-molecule-radvd - cifmw-molecule-recognize_ssh_keypair - cifmw-molecule-registry_deploy - cifmw-molecule-repo_setup @@ -108,9 +109,6 @@ - edpm-ansible-molecule-edpm_podman - edpm-ansible-molecule-edpm_ovs - edpm-ansible-molecule-edpm_kernel - github-post: - jobs: - - build-push-container-cifmw-client-post name: openstack-k8s-operators/ci-framework templates: - podified-multinode-edpm-ci-framework-pipeline