From d5e6a9e782081fb2f89c61fafd67bcf9af3b8567 Mon Sep 17 00:00:00 2001 From: Pierre Riteau Date: Fri, 31 Oct 2025 09:41:01 +0100 Subject: [PATCH 01/10] Add centos/rocky 10 seed-images jobs Change-Id: Ia0f7040cfd009ff25c3b4dfa910560eae5eafc23 Signed-off-by: Pierre Riteau --- playbooks/kayobe-seed-base/overrides.yml.j2 | 21 +++++++++++++++++---- zuul.d/jobs.yaml | 20 ++++++++++++++++++++ zuul.d/project.yaml | 6 +++--- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/playbooks/kayobe-seed-base/overrides.yml.j2 b/playbooks/kayobe-seed-base/overrides.yml.j2 index 2c4c6213f..8f4987390 100644 --- a/playbooks/kayobe-seed-base/overrides.yml.j2 +++ b/playbooks/kayobe-seed-base/overrides.yml.j2 @@ -1,4 +1,13 @@ --- +{% if ansible_facts.os_family == 'RedHat' and ansible_facts.distribution_major_version == '10' %} +# Configure EPEL repository. Necessary for gdisk to be available. +# dnf_install_epel and dnf_use_local_mirror are both necessary to trigger +# templating of epel.repo. We use the official EPEL repository because there is +# no OpenDev mirror for EL10. +dnf_install_epel: true +dnf_use_local_mirror: true +{% endif %} + docker_daemon_debug: true # Use alternative registry image to avoid Docker Hub pull rate limit. docker_registry_image_full: "quay.io/libpod/registry:2.8.2" @@ -40,7 +49,9 @@ ipa_build_images: {{ build_images }} ipa_build_dib_elements_extra: # extra-hardware is currently failing on Ubuntu - "{% raw %}{{ 'extra-hardware' if os_distribution != 'ubuntu' else '' }}{% endraw %}" - - "openstack-ci-mirrors" + # Broken openstack-ci-mirrors for CentOS Stream 10. TODO(priteau): Remove + # conditional once https://review.opendev.org/965344 is released. + - "{% raw %}{{ 'openstack-ci-mirrors' if os_distribution != 'centos' else '' }}{% endraw %}" # Workaround for limited tmpfs space in CI ipa_build_dib_env_extra: @@ -49,10 +60,12 @@ ipa_build_dib_env_extra: # Build overcloud host image. overcloud_dib_build_host_images: {{ build_images }} overcloud_dib_elements_extra: - - "openstack-ci-mirrors" + # Broken openstack-ci-mirrors for CentOS Stream 10. TODO(priteau): Remove + # conditional once https://review.opendev.org/965344 is released. + - "{% raw %}{{ 'openstack-ci-mirrors' if os_distribution != 'centos' else '' }}{% endraw %}" -# NOTE(bbezak): Kolla does not build CentOS Stream 9 container images. -# Using Rocky Linux 9 images on CentOS Stream 9 in CI. +# NOTE(bbezak): Kolla does not build CentOS Stream 10 container images. +# Using Rocky Linux 10 images on CentOS Stream 10 in CI. kolla_base_distro: "{% raw %}{{ 'rocky' if os_distribution == 'centos' else os_distribution }}{% endraw %}" # Support overriding container_engine diff --git a/zuul.d/jobs.yaml b/zuul.d/jobs.yaml index 19b877921..2d7272bab 100644 --- a/zuul.d/jobs.yaml +++ b/zuul.d/jobs.yaml @@ -312,6 +312,12 @@ nodeset: kayobe-centos9s voting: false +- job: + name: kayobe-seed-images-centos10s + parent: kayobe-seed-images-base + nodeset: kayobe-centos10s + voting: false + # Build only the base container image in the kayobe-seed-images-rocky9 job # which always runs. Use `check experimental` to run the other jobs which build # more images. @@ -331,6 +337,20 @@ vars: container_engine: podman +- job: + name: kayobe-seed-images-rocky10 + parent: kayobe-seed-images-base + nodeset: kayobe-rocky10 + vars: + kayobe_control_host_become: false + +- job: + name: kayobe-seed-images-rocky10-podman + parent: kayobe-seed-images-base + nodeset: kayobe-rocky10 + vars: + container_engine: podman + - job: name: kayobe-seed-images-ubuntu-noble parent: kayobe-seed-images-base diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml index 17b729553..8303a77a9 100644 --- a/zuul.d/project.yaml +++ b/zuul.d/project.yaml @@ -77,9 +77,9 @@ - kayobe-overcloud-tls-rocky9 - kayobe-overcloud-upgrade-rocky9 - kayobe-seed-centos10s - - kayobe-seed-images-centos9s - - kayobe-seed-images-rocky9 - - kayobe-seed-images-rocky9-podman + - kayobe-seed-images-centos10s + - kayobe-seed-images-rocky10 + - kayobe-seed-images-rocky10-podman - kayobe-seed-images-ubuntu-noble - kayobe-seed-images-ubuntu-noble-podman - kayobe-seed-rocky9 From 2f8cc7bec13180e247a4491eb5ae69621a50bf4e Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Fri, 17 Oct 2025 16:05:10 +0000 Subject: [PATCH 02/10] Replace local_action with delegate to localhost In preparation for the ansible bump: [DEPRECATION WARNING]: Using a mapping for `action` is deprecated. This feature will be removed from ansible-core version 2.23. Origin: /home/ubuntu/kayobe/ansible/roles/ssh-known-host/tasks/main.yml:31:5 29 - name: Ensure SSH keys are in known hosts 30 local_action: 31 module: known_hosts ^ column 5 Use a string value for `action`. Change-Id: I9ac26db07f68ecd3859412d3d33a964342be4cd0 Signed-off-by: Will Szumski --- ...baremetal-compute-introspection-data-save.yml | 8 ++++---- ansible/docker-registry.yml | 2 +- ansible/drac-facts.yml | 8 ++++---- ansible/dump-config.yml | 16 ++++++++-------- ansible/opensm.yml | 2 +- ansible/overcloud-introspection-data-save.yml | 8 ++++---- ansible/overcloud-inventory-discover.yml | 4 ++-- ansible/overcloud-provision.yml | 4 ++-- ansible/roles/console-allocation/tasks/main.yml | 4 ++-- ansible/roles/dell-switch/tasks/main.yml | 12 ++++++------ ansible/roles/ip-allocation/tasks/main.yml | 4 ++-- ansible/roles/junos-switch/tasks/main.yml | 4 ++-- .../molecule/enable-everything/prepare.yml | 16 ++++++++-------- ansible/roles/ssh-known-host/tasks/main.yml | 8 ++++---- ansible/seed-manage-containers.yml | 4 ++-- ansible/seed-vm-provision.yml | 4 ++-- requirements.yml | 6 ++++++ 17 files changed, 60 insertions(+), 54 deletions(-) diff --git a/ansible/baremetal-compute-introspection-data-save.yml b/ansible/baremetal-compute-introspection-data-save.yml index 0d07932a2..505349e5a 100644 --- a/ansible/baremetal-compute-introspection-data-save.yml +++ b/ansible/baremetal-compute-introspection-data-save.yml @@ -44,14 +44,14 @@ ansible_host: "{{ hostvars[controller_host].ansible_host | default(controller_host) }}" - name: Ensure introspection data output directory exists - local_action: - module: file + delegate_to: localhost + file: path: "{{ output_dir }}" state: directory - name: Ensure introspection data is saved locally - local_action: - module: copy + delegate_to: localhost + copy: content: "{{ introspection_data_map[output_format | lower] }}" dest: "{{ output_dir }}/{{ inventory_hostname }}.{{ output_format | lower }}" when: save_result.rc == 0 diff --git a/ansible/docker-registry.yml b/ansible/docker-registry.yml index c721e023a..2fb05bb90 100644 --- a/ansible/docker-registry.yml +++ b/ansible/docker-registry.yml @@ -12,5 +12,5 @@ - docker-registry roles: - role: docker-registry - docker_registry_action: "{{ kayobe_action }}" + docker_registry_action: "{{ kayobe_action | default('deploy') }}" docker_registry_config_path: "{{ config_path }}/docker-registry" diff --git a/ansible/drac-facts.yml b/ansible/drac-facts.yml index 41bf7e486..83af97d00 100644 --- a/ansible/drac-facts.yml +++ b/ansible/drac-facts.yml @@ -11,8 +11,8 @@ - role: stackhpc.drac-facts tasks: - name: Gather facts via DRAC - local_action: - module: drac_facts + delegate_to: localhost + drac_facts: address: "{{ ipmi_address }}" username: "{{ ipmi_username }}" password: "{{ ipmi_password }}" @@ -23,7 +23,7 @@ var: result - name: Write facts to a file - local_action: - module: copy + delegate_to: localhost + copy: content: "{{ result }}" dest: "/tmp/drac-facts-{{ inventory_hostname }}.json" diff --git a/ansible/dump-config.yml b/ansible/dump-config.yml index 46ebc089f..f740a063a 100644 --- a/ansible/dump-config.yml +++ b/ansible/dump-config.yml @@ -20,27 +20,27 @@ dump_hosts: all tasks: - name: Create configuration dump directory - local_action: - module: file + delegate_to: localhost + file: path: "{{ dump_path }}" state: directory - name: Write host config to file - local_action: - module: copy + delegate_to: localhost + copy: content: "{{ hostvars[inventory_hostname] | to_nice_yaml }}" dest: "{{ dump_path }}/{{ inventory_hostname }}.yml" when: dump_var_name is not defined - name: Write host variable to file - local_action: - module: copy + delegate_to: localhost + copy: content: "{{ hostvars[inventory_hostname][dump_var_name] | to_nice_yaml }}" dest: "{{ dump_path }}/{{ inventory_hostname }}.yml" when: dump_var_name is defined # - name: Write merged config to file -# local_action: -# module: copy +# delegate_to: localhost +# copy: # content: "{{ hostvars | merge_config | to_nice_yaml }}" # dest: "{{ dump_path }}/merged.yml diff --git a/ansible/opensm.yml b/ansible/opensm.yml index bee7e5175..19b94dd9d 100644 --- a/ansible/opensm.yml +++ b/ansible/opensm.yml @@ -12,4 +12,4 @@ - opensm roles: - role: opensm - opensm_action: "{{ kayobe_action }}" + opensm_action: "{{ kayobe_action | default('deploy') }}" diff --git a/ansible/overcloud-introspection-data-save.yml b/ansible/overcloud-introspection-data-save.yml index 236a06bbb..284a899f2 100644 --- a/ansible/overcloud-introspection-data-save.yml +++ b/ansible/overcloud-introspection-data-save.yml @@ -38,14 +38,14 @@ become: "{{ container_engine == 'podman' }}" - name: Ensure introspection data output directory exists - local_action: - module: file + delegate_to: localhost + file: path: "{{ output_dir }}" state: directory - name: Ensure introspection data is saved locally - local_action: - module: copy + delegate_to: localhost + copy: content: "{{ introspection_data_map[output_format | lower] }}" dest: "{{ output_dir }}/{{ inventory_hostname }}.{{ output_format | lower }}" when: save_result.rc == 0 diff --git a/ansible/overcloud-inventory-discover.yml b/ansible/overcloud-inventory-discover.yml index cabcaa5fd..c41466a53 100644 --- a/ansible/overcloud-inventory-discover.yml +++ b/ansible/overcloud-inventory-discover.yml @@ -23,8 +23,8 @@ ironic_inventory: "{{ inventory_result.stdout | from_json }}" - name: Ensure Kayobe overcloud inventory exists - local_action: - module: copy + delegate_to: localhost + copy: content: | # Managed by Ansible - do not edit. # This is the Kayobe overcloud inventory, autogenerated from the seed diff --git a/ansible/overcloud-provision.yml b/ansible/overcloud-provision.yml index 6b49a6fa0..424b45756 100644 --- a/ansible/overcloud-provision.yml +++ b/ansible/overcloud-provision.yml @@ -221,8 +221,8 @@ - final_provision_state != 'active' - name: Wait for SSH access to the nodes - local_action: - module: wait_for + delegate_to: localhost + wait_for: host: "{{ ansible_host }}" port: 22 state: started diff --git a/ansible/roles/console-allocation/tasks/main.yml b/ansible/roles/console-allocation/tasks/main.yml index 2445181b7..cb67e2f12 100644 --- a/ansible/roles/console-allocation/tasks/main.yml +++ b/ansible/roles/console-allocation/tasks/main.yml @@ -35,8 +35,8 @@ # NOTE(mgoddard): Use the Python interpreter used to run ansible-playbook, # since this has Python dependencies available to it (PyYAML). ansible_python_interpreter: "{{ ansible_playbook_python }}" - local_action: - module: console_allocation + delegate_to: localhost + console_allocation: allocation_file: "{{ console_allocation_filename }}" nodes: "{{ console_allocation_ironic_nodes }}" allocation_pool_start: "{{ console_allocation_pool_start }}" diff --git a/ansible/roles/dell-switch/tasks/main.yml b/ansible/roles/dell-switch/tasks/main.yml index fc3d6268e..958b04b71 100644 --- a/ansible/roles/dell-switch/tasks/main.yml +++ b/ansible/roles/dell-switch/tasks/main.yml @@ -1,23 +1,23 @@ --- - name: Ensure DellOS6 switches are configured - local_action: - module: dellos6_config + delegate_to: localhost + dellemc.os6.os6: provider: "{{ dell_switch_provider }}" src: "{{ lookup('template', 'dellos6-config.j2') }}" save: "{{ dell_switch_save | bool }}" when: dell_switch_type == 'dellos6' - name: Ensure DellOS9 switches are configured - local_action: - module: dellos9_config + delegate_to: localhost + dellemc.os9.os9: provider: "{{ dell_switch_provider }}" src: "{{ lookup('template', 'dellos9-config.j2') }}" save: "{{ dell_switch_save | bool }}" when: dell_switch_type == 'dellos9' - name: Ensure DellOS10 switches are configured - local_action: - module: dellos10_config + delegate_to: localhost + dellemc.os10.os10: provider: "{{ dell_switch_provider }}" src: "{{ lookup('template', 'dellos10-config.j2') }}" save: "{{ dell_switch_save | bool }}" diff --git a/ansible/roles/ip-allocation/tasks/main.yml b/ansible/roles/ip-allocation/tasks/main.yml index 93360a00c..a30457be5 100644 --- a/ansible/roles/ip-allocation/tasks/main.yml +++ b/ansible/roles/ip-allocation/tasks/main.yml @@ -4,8 +4,8 @@ # NOTE(mgoddard): Use the Python interpreter used to run ansible-playbook, # since this has Python dependencies available to it (PyYAML). ansible_python_interpreter: "{{ ansible_playbook_python }}" - local_action: - module: ip_allocation + delegate_to: localhost + ip_allocation: allocation_file: "{{ ip_allocation_filename }}" hostname: "{{ ip_allocation_hostname }}" net_name: "{{ item.net_name }}" diff --git a/ansible/roles/junos-switch/tasks/main.yml b/ansible/roles/junos-switch/tasks/main.yml index d5fea0cce..c76f006f1 100644 --- a/ansible/roles/junos-switch/tasks/main.yml +++ b/ansible/roles/junos-switch/tasks/main.yml @@ -6,8 +6,8 @@ # NOTE(mgoddard): 0.6.7 includes a fix for host key checking: # https://github.com/ncclient/ncclient/issues/302. ncclient_version: ">=0.6.7,<0.7.0" - local_action: - module: pip + delegate_to: localhost + pip: name: "ncclient{{ ncclient_version }}" virtualenv: "{{ lookup('env', 'VIRTUAL_ENV') | default(omit, true) }}" become: "{{ lookup('env', 'VIRTUAL_ENV') == None }}" diff --git a/ansible/roles/kolla-openstack/molecule/enable-everything/prepare.yml b/ansible/roles/kolla-openstack/molecule/enable-everything/prepare.yml index a39c596c9..4e945b3aa 100644 --- a/ansible/roles/kolla-openstack/molecule/enable-everything/prepare.yml +++ b/ansible/roles/kolla-openstack/molecule/enable-everything/prepare.yml @@ -4,8 +4,8 @@ gather_facts: false tasks: - name: Ensure ironic inspector kernel and ramdisk image directory exists - local_action: - module: file + delegate_to: localhost + file: path: "{{ item | dirname }}" state: directory recurse: true @@ -18,8 +18,8 @@ # versions of docker. Using non-empty files seems to resolve the issue. # See https://github.com/ansible/ansible/issues/36725. - name: Ensure ironic inspector kernel and ramdisk images exist - local_action: - module: copy + delegate_to: localhost + copy: content: fake image dest: "{{ item }}" with_items: @@ -117,8 +117,8 @@ label: "{{ item.dest }}" - name: Ensure nova libvirt certificates directory exists - local_action: - module: file + delegate_to: localhost + file: path: "{{ kolla_nova_libvirt_certificates_src }}" state: directory @@ -127,8 +127,8 @@ # versions of docker. Using non-empty files seems to resolve the issue. # See https://github.com/ansible/ansible/issues/36725. - name: Ensure nova libvirt certificates exist - local_action: - module: copy + delegate_to: localhost + copy: content: fake cert dest: "{{ kolla_nova_libvirt_certificates_src }}/{{ item }}" with_items: diff --git a/ansible/roles/ssh-known-host/tasks/main.yml b/ansible/roles/ssh-known-host/tasks/main.yml index a59ceffc1..75257f71c 100644 --- a/ansible/roles/ssh-known-host/tasks/main.yml +++ b/ansible/roles/ssh-known-host/tasks/main.yml @@ -16,8 +16,8 @@ # NOTE(priteau): Exclude comments from ssh-keyscan output because they break # known_hosts on centos/rocky 10. - name: Scan for SSH keys - local_action: - module: shell ssh-keyscan {{ item }} | grep -v '^#' + delegate_to: localhost + shell: ssh-keyscan {{ item }} | grep -v '^#' with_items: - "{{ ansible_host | default(inventory_hostname) }}" register: keyscan_result @@ -27,8 +27,8 @@ # concurrently, and some keys can end up being dropped. For more details see # https://github.com/ansible/proposals/issues/113 - name: Ensure SSH keys are in known hosts - local_action: - module: known_hosts + delegate_to: localhost + known_hosts: host: "{{ item[0].item }}" key: "{{ item[1] }}" with_subelements: diff --git a/ansible/seed-manage-containers.yml b/ansible/seed-manage-containers.yml index dd81a079b..10cd6c0ab 100644 --- a/ansible/seed-manage-containers.yml +++ b/ansible/seed-manage-containers.yml @@ -1,10 +1,10 @@ --- -- name: "Ensure defined container images are {{ kayobe_action }}ed on seed node" +- name: "Ensure defined container images are {{ kayobe_action | default('deploy') }}ed on seed node" hosts: seed tags: - seed-deploy-containers - seed-manage-containers vars: - manage_containers_action: "{{ kayobe_action }}" + manage_containers_action: "{{ kayobe_action | default('deploy') }}" roles: - role: manage-containers diff --git a/ansible/seed-vm-provision.yml b/ansible/seed-vm-provision.yml index 1424cc5b0..87a142121 100644 --- a/ansible/seed-vm-provision.yml +++ b/ansible/seed-vm-provision.yml @@ -124,8 +124,8 @@ console_log_enabled: true tasks: - name: Wait for SSH access to the seed VM - local_action: - module: wait_for + delegate_to: localhost + wait_for: host: "{{ hostvars[seed_host].ansible_host }}" port: 22 state: started diff --git a/requirements.yml b/requirements.yml index ef419f34d..b87c418c3 100644 --- a/requirements.yml +++ b/requirements.yml @@ -5,6 +5,12 @@ collections: version: master - name: community.docker version: 3.11.0 + - name: community.network + version: 5.1.0 + - name: dellemc.os6 + version: 1.0.7 + - name: dellemc.os9 + version: 1.0.4 - name: dellemc.os10 version: 1.2.7 - name: nvidia.nvue From a6e29d219cdbbbbc5730799e16d31c5e4496bf09 Mon Sep 17 00:00:00 2001 From: Pierre Riteau Date: Wed, 12 Nov 2025 12:59:32 +0100 Subject: [PATCH 03/10] Drop support for CentOS Stream 9 and Rocky Linux 9 CentOS Stream 9 and Rocky Linux 9 are no longer supported as host operating systems or base container images. This also drops all the related testing in CI. Note that IPA images still use CentOS Stream 9 until images built on CentOS Stream 10 are fully validated. Change-Id: I3f0eccec38c644484ffc27891e844cdf05cb28bd Signed-off-by: Pierre Riteau --- ansible/inventory/group_vars/all/globals | 11 +- ansible/inventory/group_vars/all/infra-vms | 14 +- ansible/inventory/group_vars/all/seed-vm | 14 +- ansible/roles/kolla-ansible/vars/RedHat.yml | 4 +- dev/functions | 20 +-- .../configuration/reference/bifrost.rst | 2 +- .../configuration/reference/network.rst | 9 +- .../reference/os-distribution.rst | 8 +- .../configuration/reference/overcloud-dib.rst | 2 +- doc/source/contributor/testing.rst | 2 +- doc/source/installation.rst | 4 +- doc/source/resources.rst | 11 +- doc/source/support-matrix.rst | 16 +- etc/kayobe/globals.yml | 6 +- etc/kayobe/infra-vms.yml | 6 +- etc/kayobe/seed-vm.yml | 6 +- kayobe/plugins/filter/networks.py | 6 +- .../infra-vms-group-vars.j2 | 2 +- .../kayobe-overcloud-base/overrides.yml.j2 | 4 +- .../overrides.yml.j2 | 15 -- .../pre.yml | 13 +- .../kayobe-seed-vm-base/seed-group-vars.j2 | 2 +- .../notes/rocky-10-8d56e4bfffe39c08.yaml | 14 ++ zuul.d/jobs.yaml | 168 +----------------- zuul.d/nodesets.yaml | 12 -- zuul.d/project.yaml | 26 +-- 26 files changed, 78 insertions(+), 319 deletions(-) create mode 100644 releasenotes/notes/rocky-10-8d56e4bfffe39c08.yaml diff --git a/ansible/inventory/group_vars/all/globals b/ansible/inventory/group_vars/all/globals index 492307337..719368a6f 100644 --- a/ansible/inventory/group_vars/all/globals +++ b/ansible/inventory/group_vars/all/globals @@ -52,13 +52,12 @@ kayobe_ansible_user: "stack" # is "rocky". os_distribution: "rocky" -# OS release. Valid options are "9-stream" and "10-stream" (with "9-stream" -# being the default) when os_distribution is "centos", "9" and "10" (with "9" -# being the default) when os_distribution is "rocky", or "noble" when -# os_distribution is "ubuntu". +# OS release. Valid options are "10-stream" when os_distribution is "centos", +# "10" when os_distribution is "rocky", or "noble" when os_distribution is +# "ubuntu". os_release: >- - {{ '9-stream' if os_distribution == 'centos' - else '9' if os_distribution == 'rocky' + {{ '10-stream' if os_distribution == 'centos' + else '10' if os_distribution == 'rocky' else 'noble' }} ############################################################################### diff --git a/ansible/inventory/group_vars/all/infra-vms b/ansible/inventory/group_vars/all/infra-vms index ea0527e3d..58b91b97a 100644 --- a/ansible/inventory/group_vars/all/infra-vms +++ b/ansible/inventory/group_vars/all/infra-vms @@ -43,30 +43,18 @@ infra_vm_root_format: qcow2 # Base image for the infra VM root volume. Default is # "https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img" # when os_distribution is "ubuntu", -# "https://dl.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud.latest.x86_64.qcow2" -# when os_distribution is "rocky" and os_release is "9", # "https://dl.rockylinux.org/pub/rocky/10/images/x86_64/Rocky-10-GenericCloud-Base.latest.x86_64.qcow2" -# when os_distribution is "rocky" and os_release is "10", -# "https://cloud.centos.org/centos/9-stream/x86_64/images/CentOS-Stream-GenericCloud-x86_64-9-latest.x86_64.qcow2" -# when os_distribution is "centos" and os_release is "9-stream", or +# when os_distribution is "rocky", or # "https://cloud.centos.org/centos/10-stream/x86_64/images/CentOS-Stream-GenericCloud-x86_64-10-latest.x86_64.qcow2" # otherwise. infra_vm_root_image: >- {%- if os_distribution == 'ubuntu' %} https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img {%- elif os_distribution == 'rocky' %} - {%- if os_release == '9' %} - https://dl.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud.latest.x86_64.qcow2 - {%- else -%} https://dl.rockylinux.org/pub/rocky/10/images/x86_64/Rocky-10-GenericCloud-Base.latest.x86_64.qcow2 - {%- endif %} - {%- else -%} - {%- if os_release == '9-stream' %} - https://cloud.centos.org/centos/9-stream/x86_64/images/CentOS-Stream-GenericCloud-x86_64-9-latest.x86_64.qcow2 {%- else -%} https://cloud.centos.org/centos/10-stream/x86_64/images/CentOS-Stream-GenericCloud-x86_64-10-latest.x86_64.qcow2 {%- endif %} - {%- endif %} # Capacity of the infra VM data volume. infra_vm_data_capacity: 100G diff --git a/ansible/inventory/group_vars/all/seed-vm b/ansible/inventory/group_vars/all/seed-vm index 4283c413e..674d0384b 100644 --- a/ansible/inventory/group_vars/all/seed-vm +++ b/ansible/inventory/group_vars/all/seed-vm @@ -43,30 +43,18 @@ seed_vm_root_format: qcow2 # Base image for the seed VM root volume. Default is # "https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img" # when os_distribution is "ubuntu", -# "https://dl.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud.latest.x86_64.qcow2" -# when os_distribution is "rocky" and os_release is "9", # "https://dl.rockylinux.org/pub/rocky/10/images/x86_64/Rocky-10-GenericCloud-Base.latest.x86_64.qcow2" -# when os_distribution is "rocky" and os_release is "10", -# "https://cloud.centos.org/centos/9-stream/x86_64/images/CentOS-Stream-GenericCloud-x86_64-9-latest.x86_64.qcow2" -# when os_distribution is "centos" and os_release is "9-stream", or +# when os_distribution is "rocky", or # "https://cloud.centos.org/centos/10-stream/x86_64/images/CentOS-Stream-GenericCloud-x86_64-10-latest.x86_64.qcow2" # otherwise. seed_vm_root_image: >- {%- if os_distribution == 'ubuntu' %} https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img {%- elif os_distribution == 'rocky' %} - {%- if os_release == '9' %} - https://dl.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud.latest.x86_64.qcow2 - {%- else -%} https://dl.rockylinux.org/pub/rocky/10/images/x86_64/Rocky-10-GenericCloud-Base.latest.x86_64.qcow2 - {%- endif %} - {%- else -%} - {%- if os_release == '9-stream' %} - https://cloud.centos.org/centos/9-stream/x86_64/images/CentOS-Stream-GenericCloud-x86_64-9-latest.x86_64.qcow2 {%- else -%} https://cloud.centos.org/centos/10-stream/x86_64/images/CentOS-Stream-GenericCloud-x86_64-10-latest.x86_64.qcow2 {%- endif %} - {%- endif %} # Capacity of the seed VM data volume. seed_vm_data_capacity: 100G diff --git a/ansible/roles/kolla-ansible/vars/RedHat.yml b/ansible/roles/kolla-ansible/vars/RedHat.yml index 008dcd0f5..dd9e59bc3 100644 --- a/ansible/roles/kolla-ansible/vars/RedHat.yml +++ b/ansible/roles/kolla-ansible/vars/RedHat.yml @@ -5,6 +5,6 @@ kolla_ansible_package_dependencies: - git - libffi-devel - openssl-devel - - "{{ 'python3.12' if ansible_facts.distribution_major_version == '9' else 'python3' }}" - - "{{ 'python3.12-devel' if ansible_facts.distribution_major_version == '9' else 'python3-devel' }}" + - python3 + - python3-devel - rsync diff --git a/dev/functions b/dev/functions index d59c28ca6..4a627e2a9 100644 --- a/dev/functions +++ b/dev/functions @@ -141,18 +141,10 @@ function is_yum { fi } -function get_python { - if is_dnf; then - echo python3.12 - else - echo python3 - fi -} - function install_dependencies { echo "Installing package dependencies for kayobe" if is_dnf; then - sudo dnf -y install gcc git vim python3-devel python3-pyyaml libffi-devel python3.12-devel python3.12 python3.12-pyyaml + sudo dnf -y install gcc git vim python3-devel python3-pyyaml libffi-devel elif is_yum; then echo "CentOS 7 is no longer supported" exit 1 @@ -174,7 +166,7 @@ function install_venv { fi if [[ ! -f "${venv_path}/bin/activate" ]]; then echo "Creating virtual environment in ${venv_path}" - $(get_python) -m venv "${venv_path}" + python3 -m venv "${venv_path}" # NOTE: Virtualenv's activate and deactivate scripts reference an # unbound variable. set +u @@ -200,9 +192,7 @@ function install_venv_system_site_packages { fi if [[ ! -f "${venv_path}/bin/activate" ]]; then echo "Creating virtual environment in ${venv_path}" - # NOTE(wszumski): tenks doesn't currently support not using the system python - # interpreter with: "Failed to detect selinux python bindings" - /usr/bin/python3 -m venv --system-site-packages "${venv_path}" + python3 -m venv --system-site-packages "${venv_path}" # NOTE: Virtualenv's activate and deactivate scripts reference an # unbound variable. set +u @@ -228,9 +218,7 @@ function install_kayobe_dev_venv { function upgrade_kayobe_venv { echo "Upgrading kayobe virtual environment in ${KAYOBE_VENV_PATH}" - # NOTE(wszumski): We need to recreate the old virtualenv to switch to python3.12 - rm -rf "${KAYOBE_VENV_PATH}" - $(get_python) -m venv "${KAYOBE_VENV_PATH}" + python3 -m venv "${KAYOBE_VENV_PATH}" # NOTE: Virtualenv's activate and deactivate scripts reference an # unbound variable. set +u diff --git a/doc/source/configuration/reference/bifrost.rst b/doc/source/configuration/reference/bifrost.rst index 90e270f75..4180dd3da 100644 --- a/doc/source/configuration/reference/bifrost.rst +++ b/doc/source/configuration/reference/bifrost.rst @@ -77,7 +77,7 @@ information on building disk images. The default configuration builds a whole disk (partitioned) image using the selected :ref:`OS distribution ` with serial console enabled, -and SELinux disabled if CentOS Stream is used. Rocky Linux 9 users should use +and SELinux disabled if CentOS Stream is used. Rocky Linux 10 users should use the default method of building images with :ref:`Diskimage builder directly `. diff --git a/doc/source/configuration/reference/network.rst b/doc/source/configuration/reference/network.rst index 595d1e110..e134c1343 100644 --- a/doc/source/configuration/reference/network.rst +++ b/doc/source/configuration/reference/network.rst @@ -302,8 +302,7 @@ String format rules (CentOS Stream/Rocky Linux only) The string format of a rule is the string which would be appended to ``ip rule `` to create or delete the rule. Note that when using NetworkManager -(the default since Zed and in Yoga when using Rocky Linux 9) the table must be -specified by ID. +(the default when using Rocky Linux 10) the table must be specified by ID. To configure a network called ``example`` with an IP routing policy rule to handle traffic from the subnet ``10.1.0.0/24`` using the routing table with ID @@ -396,9 +395,9 @@ The following attributes are supported: ``bridge_stp`` .. note:: - For Rocky Linux 9, the ``bridge_stp`` attribute is set to false to preserve - backwards compatibility with network scripts. This is because the Network - Manager sets STP to true by default on bridges. + For Rocky Linux 10, the ``bridge_stp`` attribute is set to false to + preserve backwards compatibility with network scripts. This is because + the Network Manager sets STP to true by default on bridges. Enable or disable the Spanning Tree Protocol (STP) on this bridge. Should be set to a boolean value. The default is not set on Ubuntu systems. diff --git a/doc/source/configuration/reference/os-distribution.rst b/doc/source/configuration/reference/os-distribution.rst index 153f035b0..5f29d95ec 100644 --- a/doc/source/configuration/reference/os-distribution.rst +++ b/doc/source/configuration/reference/os-distribution.rst @@ -15,10 +15,10 @@ or ``rocky`` or ``ubuntu``, and defaults to ``rocky``. The ``os_release`` variable in ``etc/kayobe/globals.yml`` can be used to set the release of the OS. When ``os_distribution`` is set to ``centos`` it may be -set to ``9-stream`` or ``10-stream``, and ``9-stream`` is its default value. -When ``os_distribution`` is set to ``rocky`` it may be set to ``9`` or ``10``, -and ``9`` is its default value. When ``os_distribution`` is set to ``ubuntu`` -it may be set to ``noble``, and this is its default value. +set to ``10-stream``, and this is its default value. When ``os_distribution`` +is set to ``rocky`` it may be set to ``10``, and this is its default value. +When ``os_distribution`` is set to ``ubuntu`` it may be set to ``noble``, and +this is its default value. These variables are used to set various defaults, including: diff --git a/doc/source/configuration/reference/overcloud-dib.rst b/doc/source/configuration/reference/overcloud-dib.rst index 1593e20b4..db537f9a6 100644 --- a/doc/source/configuration/reference/overcloud-dib.rst +++ b/doc/source/configuration/reference/overcloud-dib.rst @@ -34,7 +34,7 @@ how these images are built. Consult the information on building disk images. The default configuration builds a whole disk (partitioned) image using the -selected :ref:`OS distribution ` (Rocky Linux 9 by default) +selected :ref:`OS distribution ` (Rocky Linux 10 by default) with serial console enabled, and SELinux disabled if CentOS Stream or Rocky Linux is used. `Cloud-init `__ is used to process diff --git a/doc/source/contributor/testing.rst b/doc/source/contributor/testing.rst index b11cd4e48..c2ed7088a 100644 --- a/doc/source/contributor/testing.rst +++ b/doc/source/contributor/testing.rst @@ -18,7 +18,7 @@ running kayobe's tests. sudo apt-get install build-essential python3-dev libssl-dev python3-pip git -* Fedora or CentOS Stream 9/Rocky 9/RHEL 9:: +* Fedora or CentOS Stream 10/Rocky 10/RHEL 10:: sudo dnf install python3-devel openssl-devel python3-pip git gcc diff --git a/doc/source/installation.rst b/doc/source/installation.rst index 01fd80f2f..b301e8d18 100644 --- a/doc/source/installation.rst +++ b/doc/source/installation.rst @@ -15,8 +15,8 @@ Prerequisites Currently Kayobe supports the following Operating Systems on the Ansible control host: -- CentOS Stream 9 (since Zed 13.0.0 release) -- Rocky Linux 9 (since Zed 13.0.0 release) +- CentOS Stream 10 (since Flamingo 19.0.0 release) +- Rocky Linux 10 (since Flamingo 19.0.0 release) - Ubuntu Noble 24.04 (since Dalmatian 17.0.0 release) See the :doc:`support matrix ` for details of supported diff --git a/doc/source/resources.rst b/doc/source/resources.rst index 31b67e565..8874f7fc8 100644 --- a/doc/source/resources.rst +++ b/doc/source/resources.rst @@ -22,8 +22,9 @@ OpenStack using Kolla, Ansible and Kayobe. The guide makes use of baremetal environment running on a single hypervisor. To complete the walkthrough you will require a baremetal or VM hypervisor -running CentOS Stream 9, Rocky Linux 9 or Ubuntu Noble 24.04 (since Dalmatian -17.0.0) with at least 32GB RAM & 80GB disk space. Preparing the deployment can -take some time - where possible it is beneficial to snapshot the hypervisor. We -advise making a snapshot after creating the initial 'seed' VM as this will make -additional deployments significantly faster. +running CentOS Stream 10 (since Flamingo 19.0.0), Rocky Linux 10 (since +Flamingo 19.0.0) or Ubuntu Noble 24.04 (since Dalmatian 17.0.0) with at least +32GB RAM & 80GB disk space. Preparing the deployment can take some time - where +possible it is beneficial to snapshot the hypervisor. We advise making a +snapshot after creating the initial 'seed' VM as this will make additional +deployments significantly faster. diff --git a/doc/source/support-matrix.rst b/doc/source/support-matrix.rst index e52fa111c..fe973e3ef 100644 --- a/doc/source/support-matrix.rst +++ b/doc/source/support-matrix.rst @@ -9,22 +9,24 @@ Supported Operating Systems Kayobe supports the following host Operating Systems (OS): -* Rocky Linux 9 (since Zed 13.0.0 release) +* Rocky Linux 10 (since Flamingo 19.0.0 release) * Ubuntu Noble 24.04 (since Dalmatian 17.0.0 release) -In addition to that CentOS Stream 9 host OS is functional, but not officially -supported. Kolla does not publish CentOS Stream 9 images to Docker Hub/Quay.io, +In addition to that CentOS Stream 10 host OS is functional, but not officially +supported. Kolla does not publish CentOS Stream 10 images to Docker Hub/Quay.io, therefore users need to build them by themselves. .. note:: - CentOS Stream 8 is no longer supported as a host OS. The Yoga release - supports both CentOS Stream 8 and 9, and provides a route for migration. + CentOS Stream 9 is no longer supported as a host OS. The 2025.1 Epoxy + release will in future support both CentOS Stream 9 and 10 to provide a + route for migration. .. note:: - Rocky Linux 8 is no longer supported as a host OS. The Yoga release supports - both Rocky Linux 8 and 9, and provides a route for migration. + Rocky Linux 9 is no longer supported as a host OS. The 2025.1 Epoxy release + will in future support both CentOS Stream 9 and 10 to provide a route for + migration. Supported container images ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/etc/kayobe/globals.yml b/etc/kayobe/globals.yml index bb21aca71..13f340e57 100644 --- a/etc/kayobe/globals.yml +++ b/etc/kayobe/globals.yml @@ -48,9 +48,9 @@ # is "rocky". #os_distribution: -# OS release. Valid options are "9-stream" and "10-stream" (with "9-stream" -# being the default) when os_distribution is "centos", "9" and "10" (with "9" -# being the default) when os_distribution is "rocky", or "noble" when +# OS release. Valid options are "10-stream" when os_distribution is "centos", +# "10" when os_distribution is "rocky", or "noble" when os_distribution is +# "ubuntu". # os_distribution is "ubuntu". #os_release: diff --git a/etc/kayobe/infra-vms.yml b/etc/kayobe/infra-vms.yml index 2b012b8e5..076a3e695 100644 --- a/etc/kayobe/infra-vms.yml +++ b/etc/kayobe/infra-vms.yml @@ -32,12 +32,8 @@ # Base image for the infra VM root volume. Default is # "https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img" # when os_distribution is "ubuntu", -# "https://dl.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud.latest.x86_64.qcow2" -# when os_distribution is "rocky" and os_release is "9", # "https://dl.rockylinux.org/pub/rocky/10/images/x86_64/Rocky-10-GenericCloud-Base.latest.x86_64.qcow2" -# when os_distribution is "rocky" and os_release is "10", -# "https://cloud.centos.org/centos/9-stream/x86_64/images/CentOS-Stream-GenericCloud-x86_64-9-latest.x86_64.qcow2" -# when os_distribution is "centos" and os_release is "9-stream", or +# when os_distribution is "rocky", or # "https://cloud.centos.org/centos/10-stream/x86_64/images/CentOS-Stream-GenericCloud-x86_64-10-latest.x86_64.qcow2" # otherwise. #infra_vm_root_image: diff --git a/etc/kayobe/seed-vm.yml b/etc/kayobe/seed-vm.yml index 1a575a10b..86be2708f 100644 --- a/etc/kayobe/seed-vm.yml +++ b/etc/kayobe/seed-vm.yml @@ -32,12 +32,8 @@ # Base image for the seed VM root volume. Default is # "https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img" # when os_distribution is "ubuntu", -# "https://dl.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud.latest.x86_64.qcow2" -# when os_distribution is "rocky" and os_release is "9", # "https://dl.rockylinux.org/pub/rocky/10/images/x86_64/Rocky-10-GenericCloud-Base.latest.x86_64.qcow2" -# when os_distribution is "rocky" and os_release is "10", -# "https://cloud.centos.org/centos/9-stream/x86_64/images/CentOS-Stream-GenericCloud-x86_64-9-latest.x86_64.qcow2" -# when os_distribution is "centos" and os_release is "9-stream", or +# when os_distribution is "rocky", or # "https://cloud.centos.org/centos/10-stream/x86_64/images/CentOS-Stream-GenericCloud-x86_64-10-latest.x86_64.qcow2" # otherwise. #seed_vm_root_image: diff --git a/kayobe/plugins/filter/networks.py b/kayobe/plugins/filter/networks.py index f949d7982..7c8cff7b1 100644 --- a/kayobe/plugins/filter/networks.py +++ b/kayobe/plugins/filter/networks.py @@ -283,9 +283,9 @@ def net_macaddress(context, name, inventory_hostname=None): def net_bridge_stp(context, name, inventory_hostname=None): """Return the Spanning Tree Protocol (STP) state for a bridge. - On RL9 if STP is not defined, default it to 'false' to preserve - compatibility with network scripts. STP is 'true' in NetworkManager - by default, so we set it to 'false' here. + On RL10 if STP is not defined, default it to 'false' to preserve + compatibility with network scripts. STP is 'true' in NetworkManager by + default, so we set it to 'false' here. :param context: Jinja2 Context object. :param name: The name of the network. diff --git a/playbooks/kayobe-infra-vm-base/infra-vms-group-vars.j2 b/playbooks/kayobe-infra-vm-base/infra-vms-group-vars.j2 index 9ce8d7318..1d30f2122 100644 --- a/playbooks/kayobe-infra-vm-base/infra-vms-group-vars.j2 +++ b/playbooks/kayobe-infra-vm-base/infra-vms-group-vars.j2 @@ -1,5 +1,5 @@ --- -{% if infra_vm_use_cirros | default(true) or ansible_os_family == 'RedHat' and ansible_distribution_major_version == '9' %} +{% if infra_vm_use_cirros | default(true) %} aio_interface: eth0 {% else %} # Required for official cloud images (CentOS Stream 10, Rocky Linux 10, Ubuntu) diff --git a/playbooks/kayobe-overcloud-base/overrides.yml.j2 b/playbooks/kayobe-overcloud-base/overrides.yml.j2 index a0a46b5c6..8f1a2bbec 100644 --- a/playbooks/kayobe-overcloud-base/overrides.yml.j2 +++ b/playbooks/kayobe-overcloud-base/overrides.yml.j2 @@ -56,8 +56,8 @@ kolla_ironic_kernel_append_params_extra: - ipa-insecure=1 {% endif %} -# NOTE(bbezak): Kolla does not build CentOS Stream 9 container images. -# Using Rocky Linux 9 images on CentOS Stream 9 in CI. +# NOTE(bbezak): Kolla does not build CentOS Stream 10 container images. +# Using Rocky Linux 10 images on CentOS Stream 10 in CI. kolla_base_distro: "{% raw %}{{ 'rocky' if os_distribution == 'centos' else os_distribution }}{% endraw %}" # Support overriding container_engine diff --git a/playbooks/kayobe-overcloud-host-configure-base/overrides.yml.j2 b/playbooks/kayobe-overcloud-host-configure-base/overrides.yml.j2 index 9e9424981..d2e75f779 100644 --- a/playbooks/kayobe-overcloud-host-configure-base/overrides.yml.j2 +++ b/playbooks/kayobe-overcloud-host-configure-base/overrides.yml.j2 @@ -164,21 +164,6 @@ apt_auth: {% endif %} {% if ansible_facts.os_family == 'RedHat' %} -# NOTE: There are OpenDev mirrors only for centos-stream/9-stream and epel/9. -{% if ansible_facts.distribution_major_version == "9" %} -# Use a local DNF mirror. -dnf_use_local_mirror: true -{% if ansible_facts.distribution == 'CentOS' %} -# Mirror FQDN for DNF repos. -dnf_centos_mirror_host: "{{ zuul_site_mirror_fqdn }}" -# Mirror directory for DNF CentOS repos. -dnf_centos_mirror_directory: 'centos-stream' -{% endif %} -# Mirror FQDN for DNF EPEL repos. -dnf_epel_mirror_host: "{{ zuul_site_mirror_fqdn }}" -# Mirror directory for DNF EPEL repos. -dnf_epel_mirror_directory: 'epel' -{% endif %} # Configure a custom DNF repository. dnf_custom_repos: fluent-package: diff --git a/playbooks/kayobe-overcloud-host-configure-base/pre.yml b/playbooks/kayobe-overcloud-host-configure-base/pre.yml index 58603157a..a0bfb9252 100644 --- a/playbooks/kayobe-overcloud-host-configure-base/pre.yml +++ b/playbooks/kayobe-overcloud-host-configure-base/pre.yml @@ -10,25 +10,14 @@ - python3-setuptools become: true - - name: Install Python3.12 on RHEL derivatives - dnf: - name: - - python3.12 - - python3.12-devel - state: latest - when: ansible_facts.os_family == 'RedHat' - become: true - - name: Ensure testinfra is installed - vars: - cmd: "{{ 'python3.12' if ansible_facts.os_family == 'RedHat' else 'python3' }} -m venv" pip: name: - distro - pytest-testinfra - pytest-html virtualenv: "{{ testinfra_venv }}" - virtualenv_command: "{{ cmd }}" + virtualenv_command: python3 -m venv # NOTE(mgoddard): Use the name zz-30-overrides.yml to ensure this takes # precedence over the standard config files and zz-20-overrides.yml from diff --git a/playbooks/kayobe-seed-vm-base/seed-group-vars.j2 b/playbooks/kayobe-seed-vm-base/seed-group-vars.j2 index 757d3686f..ccf57a4e8 100644 --- a/playbooks/kayobe-seed-vm-base/seed-group-vars.j2 +++ b/playbooks/kayobe-seed-vm-base/seed-group-vars.j2 @@ -1,5 +1,5 @@ --- -{% if seed_vm_use_cirros | default(true) or ansible_os_family == 'RedHat' and ansible_distribution_major_version == '9' %} +{% if seed_vm_use_cirros | default(true) %} aio_interface: eth0 {% else %} # Required for official cloud images (CentOS Stream 10, Rocky Linux 10, Ubuntu) diff --git a/releasenotes/notes/rocky-10-8d56e4bfffe39c08.yaml b/releasenotes/notes/rocky-10-8d56e4bfffe39c08.yaml new file mode 100644 index 000000000..eb5abc988 --- /dev/null +++ b/releasenotes/notes/rocky-10-8d56e4bfffe39c08.yaml @@ -0,0 +1,14 @@ +--- +features: + - | + Adds support for CentOS Stream 10 and Rocky Linux 10 as host operating + systems and base container images. These are the only major versions of + CentOS Stream and Rocky Linux supported from the 2025.2 Flamingo release. + The 2025.1 Epoxy release will support both Rocky Linux 9 and 10 hosts to + provide a route for migration. +upgrade: + - | + CentOS Stream 9 and Rocky Linux 9 are no longer supported as host operating + systems or base container images. Users should migrate to CentOS Stream 10 + or Rocky Linux 10. The 2025.1 Epoxy release will support both Rocky Linux 9 + and 10 hosts to provide a route for migration. diff --git a/zuul.d/jobs.yaml b/zuul.d/jobs.yaml index 2d7272bab..2af930cf3 100644 --- a/zuul.d/jobs.yaml +++ b/zuul.d/jobs.yaml @@ -121,32 +121,12 @@ run: playbooks/kayobe-overcloud-base/run.yml timeout: 7200 -- job: - name: kayobe-overcloud-centos9s - parent: kayobe-overcloud-base - nodeset: kayobe-centos9s - voting: false - - job: name: kayobe-overcloud-centos10s parent: kayobe-overcloud-base nodeset: kayobe-centos10s voting: false -- job: - name: kayobe-overcloud-rocky9 - parent: kayobe-overcloud-base - vars: - kayobe_control_host_become: false - nodeset: kayobe-rocky9 - -- job: - name: kayobe-overcloud-rocky9-podman - parent: kayobe-overcloud-base - nodeset: kayobe-rocky9 - vars: - container_engine: podman - - job: name: kayobe-overcloud-rocky10 parent: kayobe-overcloud-base @@ -181,23 +161,12 @@ tls_enabled: true ironic_boot_mode: "uefi" -- job: - name: kayobe-overcloud-tls-centos9s - parent: kayobe-overcloud-tls-base - nodeset: kayobe-centos9s - voting: false - - job: name: kayobe-overcloud-tls-centos10s parent: kayobe-overcloud-tls-base nodeset: kayobe-centos10s voting: false -- job: - name: kayobe-overcloud-tls-rocky9 - parent: kayobe-overcloud-tls-base - nodeset: kayobe-rocky9 - - job: name: kayobe-overcloud-tls-rocky10 parent: kayobe-overcloud-tls-base @@ -216,9 +185,9 @@ timeout: 10800 - job: - name: kayobe-overcloud-upgrade-rocky9 + name: kayobe-overcloud-upgrade-rocky10 parent: kayobe-overcloud-upgrade-base - nodeset: kayobe-rocky9 + nodeset: kayobe-rocky10 - job: name: kayobe-overcloud-upgrade-ubuntu-noble @@ -226,9 +195,9 @@ nodeset: kayobe-ubuntu-noble - job: - name: kayobe-overcloud-upgrade-slurp-rocky9 + name: kayobe-overcloud-upgrade-slurp-rocky10 parent: kayobe-overcloud-upgrade-base - nodeset: kayobe-rocky9 + nodeset: kayobe-rocky10 - job: name: kayobe-overcloud-upgrade-slurp-ubuntu-noble @@ -248,30 +217,12 @@ vars: build_images: false -- job: - name: kayobe-seed-centos9s - parent: kayobe-seed-base - nodeset: kayobe-centos9s - voting: false - - job: name: kayobe-seed-centos10s parent: kayobe-seed-base nodeset: kayobe-centos10s voting: false -- job: - name: kayobe-seed-rocky9 - parent: kayobe-seed-base - nodeset: kayobe-rocky9 - -- job: - name: kayobe-seed-rocky9-podman - parent: kayobe-seed-base - nodeset: kayobe-rocky9 - vars: - container_engine: podman - - job: name: kayobe-seed-rocky10 parent: kayobe-seed-base @@ -306,37 +257,12 @@ vars: build_images: true -- job: - name: kayobe-seed-images-centos9s - parent: kayobe-seed-images-base - nodeset: kayobe-centos9s - voting: false - - job: name: kayobe-seed-images-centos10s parent: kayobe-seed-images-base nodeset: kayobe-centos10s voting: false -# Build only the base container image in the kayobe-seed-images-rocky9 job -# which always runs. Use `check experimental` to run the other jobs which build -# more images. -- job: - name: kayobe-seed-images-rocky9 - parent: kayobe-seed-images-base - nodeset: kayobe-rocky9 - vars: - overcloud_container_image_regex: "^base" - seed_container_image_regex: "^base" - kayobe_control_host_become: false - -- job: - name: kayobe-seed-images-rocky9-podman - parent: kayobe-seed-images-base - nodeset: kayobe-rocky9 - vars: - container_engine: podman - - job: name: kayobe-seed-images-rocky10 parent: kayobe-seed-images-base @@ -377,23 +303,12 @@ run: playbooks/kayobe-overcloud-host-configure-base/run.yml timeout: 7200 -- job: - name: kayobe-overcloud-host-configure-centos9s - parent: kayobe-overcloud-host-configure-base - nodeset: kayobe-centos9s - voting: false - - job: name: kayobe-overcloud-host-configure-centos10s parent: kayobe-overcloud-host-configure-base nodeset: kayobe-centos10s voting: false -- job: - name: kayobe-overcloud-host-configure-rocky9 - parent: kayobe-overcloud-host-configure-base - nodeset: kayobe-rocky9 - - job: name: kayobe-overcloud-host-configure-rocky10 parent: kayobe-overcloud-host-configure-base @@ -417,9 +332,9 @@ timeout: 5400 - job: - name: kayobe-seed-upgrade-rocky9 + name: kayobe-seed-upgrade-rocky10 parent: kayobe-seed-upgrade-base - nodeset: kayobe-rocky9 + nodeset: kayobe-rocky10 - job: name: kayobe-seed-upgrade-ubuntu-noble @@ -427,9 +342,9 @@ nodeset: kayobe-ubuntu-noble - job: - name: kayobe-seed-upgrade-slurp-rocky9 + name: kayobe-seed-upgrade-slurp-rocky10 parent: kayobe-seed-upgrade-base - nodeset: kayobe-rocky9 + nodeset: kayobe-rocky10 - job: name: kayobe-seed-upgrade-slurp-ubuntu-noble @@ -448,23 +363,12 @@ run: playbooks/kayobe-seed-vm-base/run.yml timeout: 5400 -- job: - name: kayobe-seed-vm-centos9s - parent: kayobe-seed-vm-base - nodeset: kayobe-centos9s - voting: false - - job: name: kayobe-seed-vm-centos10s parent: kayobe-seed-vm-base nodeset: kayobe-centos10s voting: false -- job: - name: kayobe-seed-vm-rocky9 - parent: kayobe-seed-vm-base - nodeset: kayobe-rocky9 - - job: name: kayobe-seed-vm-rocky10 parent: kayobe-seed-vm-base @@ -477,14 +381,6 @@ vars: kayobe_control_host_become: false -- job: - name: kayobe-seed-vm-centos9s-cloud-image - parent: kayobe-seed-vm-base - nodeset: kayobe-centos9s - voting: false - vars: - seed_vm_use_cirros: false - - job: name: kayobe-seed-vm-centos10s-cloud-image parent: kayobe-seed-vm-base @@ -493,13 +389,6 @@ vars: seed_vm_use_cirros: false -- job: - name: kayobe-seed-vm-rocky9-cloud-image - parent: kayobe-seed-vm-base - nodeset: kayobe-rocky9 - vars: - seed_vm_use_cirros: false - - job: name: kayobe-seed-vm-rocky10-cloud-image parent: kayobe-seed-vm-base @@ -523,25 +412,12 @@ vars: seed_vm_machine: q35 -- job: - name: kayobe-seed-vm-centos9s-q35 - parent: kayobe-seed-vm-q35-base - nodeset: kayobe-centos9s - voting: false - - job: name: kayobe-seed-vm-centos10s-q35 parent: kayobe-seed-vm-q35-base nodeset: kayobe-centos10s voting: false -- job: - name: kayobe-seed-vm-rocky9-q35 - parent: kayobe-seed-vm-q35-base - nodeset: kayobe-rocky9 - vars: - kayobe_control_host_become: false - - job: name: kayobe-seed-vm-rocky10-q35 parent: kayobe-seed-vm-q35-base @@ -566,25 +442,12 @@ run: playbooks/kayobe-infra-vm-base/run.yml timeout: 5400 -- job: - name: kayobe-infra-vm-centos9s - parent: kayobe-infra-vm-base - nodeset: kayobe-centos9s - voting: false - - job: name: kayobe-infra-vm-centos10s parent: kayobe-infra-vm-base nodeset: kayobe-centos10s voting: false -- job: - name: kayobe-infra-vm-rocky9 - parent: kayobe-infra-vm-base - nodeset: kayobe-rocky9 - vars: - kayobe_control_host_become: false - - job: name: kayobe-infra-vm-rocky10 parent: kayobe-infra-vm-base @@ -597,14 +460,6 @@ parent: kayobe-infra-vm-base nodeset: kayobe-ubuntu-noble -- job: - name: kayobe-infra-vm-centos9s-cloud-image - parent: kayobe-infra-vm-base - nodeset: kayobe-centos9s - voting: false - vars: - infra_vm_use_cirros: false - - job: name: kayobe-infra-vm-centos10s-cloud-image parent: kayobe-infra-vm-base @@ -613,13 +468,6 @@ vars: infra_vm_use_cirros: false -- job: - name: kayobe-infra-vm-rocky9-cloud-image - parent: kayobe-infra-vm-base - nodeset: kayobe-rocky9 - vars: - infra_vm_use_cirros: false - - job: name: kayobe-infra-vm-rocky10-cloud-image parent: kayobe-infra-vm-base diff --git a/zuul.d/nodesets.yaml b/zuul.d/nodesets.yaml index 3db1e785c..b7bd14d8b 100644 --- a/zuul.d/nodesets.yaml +++ b/zuul.d/nodesets.yaml @@ -1,22 +1,10 @@ --- -- nodeset: - name: kayobe-centos9s - nodes: - - name: primary - label: centos-9-stream - - nodeset: name: kayobe-centos10s nodes: - name: primary label: centos-10-stream-8GB -- nodeset: - name: kayobe-rocky9 - nodes: - - name: primary - label: rockylinux-9 - - nodeset: name: kayobe-rocky10 nodes: diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml index 8303a77a9..390132fda 100644 --- a/zuul.d/project.yaml +++ b/zuul.d/project.yaml @@ -13,10 +13,8 @@ - kayobe-tox-ansible - kayobe-tox-molecule - kayobe-infra-vm-rocky10 - - kayobe-infra-vm-rocky9 - kayobe-infra-vm-ubuntu-noble - kayobe-overcloud-host-configure-rocky10 - - kayobe-overcloud-host-configure-rocky9 - kayobe-overcloud-host-configure-ubuntu-noble - kayobe-overcloud-rocky10 - kayobe-overcloud-rocky10-podman @@ -30,7 +28,6 @@ - kayobe-seed-ubuntu-noble-podman - kayobe-seed-upgrade-ubuntu-noble - kayobe-seed-vm-rocky10 - - kayobe-seed-vm-rocky9 - kayobe-seed-vm-ubuntu-noble gate: jobs: @@ -38,10 +35,8 @@ - kayobe-tox-ansible - kayobe-tox-molecule - kayobe-infra-vm-rocky10 - - kayobe-infra-vm-rocky9 - kayobe-infra-vm-ubuntu-noble - kayobe-overcloud-host-configure-rocky10 - - kayobe-overcloud-host-configure-rocky9 - kayobe-overcloud-host-configure-ubuntu-noble - kayobe-overcloud-rocky10 - kayobe-overcloud-rocky10-podman @@ -55,45 +50,28 @@ - kayobe-seed-ubuntu-noble-podman - kayobe-seed-upgrade-ubuntu-noble - kayobe-seed-vm-rocky10 - - kayobe-seed-vm-rocky9 - kayobe-seed-vm-ubuntu-noble experimental: jobs: - kayobe-infra-vm-centos10s - kayobe-infra-vm-centos10s-cloud-image - - kayobe-infra-vm-centos9s - - kayobe-infra-vm-centos9s-cloud-image - kayobe-infra-vm-rocky10-cloud-image - - kayobe-infra-vm-rocky9-cloud-image - kayobe-infra-vm-ubuntu-noble-cloud-image - kayobe-overcloud-centos10s - - kayobe-overcloud-centos9s - - kayobe-overcloud-host-configure-centos10s - - kayobe-overcloud-host-configure-centos9s - - kayobe-overcloud-rocky9 - - kayobe-overcloud-rocky9-podman - kayobe-overcloud-tls-centos10s - - kayobe-overcloud-tls-rocky9 - - kayobe-overcloud-upgrade-rocky9 + - kayobe-overcloud-upgrade-rocky10 - kayobe-seed-centos10s - kayobe-seed-images-centos10s - kayobe-seed-images-rocky10 - kayobe-seed-images-rocky10-podman - kayobe-seed-images-ubuntu-noble - kayobe-seed-images-ubuntu-noble-podman - - kayobe-seed-rocky9 - - kayobe-seed-rocky9-podman - - kayobe-seed-upgrade-rocky9 + - kayobe-seed-upgrade-rocky10 - kayobe-seed-vm-centos10s - kayobe-seed-vm-centos10s-cloud-image - kayobe-seed-vm-centos10s-q35 - - kayobe-seed-vm-centos9s - - kayobe-seed-vm-centos9s-cloud-image - - kayobe-seed-vm-centos9s-q35 - kayobe-seed-vm-rocky10-cloud-image - kayobe-seed-vm-rocky10-q35 - - kayobe-seed-vm-rocky9-cloud-image - - kayobe-seed-vm-rocky9-q35 - kayobe-seed-vm-ubuntu-noble-cloud-image - kayobe-seed-vm-ubuntu-noble-q35 From d759b5fb00381338ae8f32203a672bfe59493e63 Mon Sep 17 00:00:00 2001 From: Pierre Riteau Date: Wed, 12 Nov 2025 14:41:34 +0100 Subject: [PATCH 04/10] [release] Fix kolla-feature-flags.sh This script was broken by the refactoring of group variables in kolla-ansible [1]. [1] https://review.opendev.org/c/openstack/kolla-ansible/+/962200 Change-Id: Ic923a7c270b93b450fd3a2ecae1057f05a2c373e Signed-off-by: Pierre Riteau --- tools/kolla-feature-flags.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/kolla-feature-flags.sh b/tools/kolla-feature-flags.sh index 8d4277a87..73a34f950 100755 --- a/tools/kolla-feature-flags.sh +++ b/tools/kolla-feature-flags.sh @@ -10,12 +10,12 @@ set -e set -o pipefail KOLLA_ANSIBLE_SRC=$1 -KOLLA_GROUP_VARS_ALL=${KOLLA_ANSIBLE_SRC}/ansible/group_vars/all.yml +KOLLA_GROUP_VARS_ALL=${KOLLA_ANSIBLE_SRC}/ansible/group_vars/all -if [[ ! -f $KOLLA_GROUP_VARS_ALL ]]; then +if [[ ! -d $KOLLA_GROUP_VARS_ALL ]]; then echo "Usage: $0 " exit 1 fi # Find all feature flags, strip the enable_ prefix and value, sort. -cat ${KOLLA_GROUP_VARS_ALL} | grep '^enable_'| sed -e 's/enable_\(.*\):.*/ - \1/' | sort +cat ${KOLLA_GROUP_VARS_ALL}/*.yml | grep '^enable_'| sed -e 's/enable_\(.*\):.*/ - \1/' | sort From a846cccc6369bc14928d60df22b83761325bcffa Mon Sep 17 00:00:00 2001 From: Pierre Riteau Date: Wed, 12 Nov 2025 14:56:03 +0100 Subject: [PATCH 05/10] [release] Sync with Kolla Ansible for 2025.2 Change-Id: I5902105a348deace4ff93b1659d454bcf361e341 Signed-off-by: Pierre Riteau --- .../roles/kolla-ansible/templates/overcloud-components.j2 | 5 +---- ansible/roles/kolla-ansible/templates/overcloud-services.j2 | 6 ------ ansible/roles/kolla-ansible/vars/main.yml | 5 ++--- etc/kayobe/kolla.yml | 6 ++---- 4 files changed, 5 insertions(+), 17 deletions(-) diff --git a/ansible/roles/kolla-ansible/templates/overcloud-components.j2 b/ansible/roles/kolla-ansible/templates/overcloud-components.j2 index 88781653f..6734b619b 100644 --- a/ansible/roles/kolla-ansible/templates/overcloud-components.j2 +++ b/ansible/roles/kolla-ansible/templates/overcloud-components.j2 @@ -151,14 +151,11 @@ control [skyline:children] control -[redis:children] +[valkey:children] control [blazar:children] control -[venus:children] -monitoring - [letsencrypt:children] loadbalancer diff --git a/ansible/roles/kolla-ansible/templates/overcloud-services.j2 b/ansible/roles/kolla-ansible/templates/overcloud-services.j2 index b87737dbb..086045cb1 100644 --- a/ansible/roles/kolla-ansible/templates/overcloud-services.j2 +++ b/ansible/roles/kolla-ansible/templates/overcloud-services.j2 @@ -447,12 +447,6 @@ ovn-database [ovn-sb-db-relay:children] ovn-database -[venus-api:children] -venus - -[venus-manager:children] -venus - [letsencrypt-webserver:children] letsencrypt diff --git a/ansible/roles/kolla-ansible/vars/main.yml b/ansible/roles/kolla-ansible/vars/main.yml index 288fef215..6533227b0 100644 --- a/ansible/roles/kolla-ansible/vars/main.yml +++ b/ansible/roles/kolla-ansible/vars/main.yml @@ -136,7 +136,6 @@ kolla_feature_flags: - horizon_octavia - horizon_tacker - horizon_trove - - horizon_venus - horizon_watcher - horizon_zun - influxdb @@ -144,6 +143,7 @@ kolla_feature_flags: - ironic_dnsmasq - ironic_neutron_agent - ironic_prometheus_exporter + - ironic_pxe_filter - iscsid - keepalived - keystone @@ -227,12 +227,11 @@ kolla_feature_flags: - prometheus_server - proxysql - rabbitmq - - redis - skyline - tacker - telegraf - trove - trove_singletenant - - venus + - valkey - watcher - zun diff --git a/etc/kayobe/kolla.yml b/etc/kayobe/kolla.yml index b0ddc74bd..6eb02a5ec 100644 --- a/etc/kayobe/kolla.yml +++ b/etc/kayobe/kolla.yml @@ -284,7 +284,6 @@ #kolla_enable_aodh: #kolla_enable_barbican: -#kolla_enable_bifrost: #kolla_enable_blazar: #kolla_enable_ceilometer: #kolla_enable_ceilometer_horizon_policy_file: @@ -344,7 +343,6 @@ #kolla_enable_horizon_octavia: #kolla_enable_horizon_tacker: #kolla_enable_horizon_trove: -#kolla_enable_horizon_venus: #kolla_enable_horizon_watcher: #kolla_enable_horizon_zun: #kolla_enable_influxdb: @@ -352,6 +350,7 @@ #kolla_enable_ironic_dnsmasq: #kolla_enable_ironic_neutron_agent: #kolla_enable_ironic_prometheus_exporter: +#kolla_enable_ironic_pxe_filter: #kolla_enable_iscsid: #kolla_enable_keepalived: #kolla_enable_keystone: @@ -435,13 +434,12 @@ #kolla_enable_prometheus_server: #kolla_enable_proxysql: #kolla_enable_rabbitmq: -#kolla_enable_redis: #kolla_enable_skyline: #kolla_enable_tacker: #kolla_enable_telegraf: #kolla_enable_trove: #kolla_enable_trove_singletenant: -#kolla_enable_venus: +#kolla_enable_valkey: #kolla_enable_watcher: #kolla_enable_zun: From 237e8b07e046b1736f74f648e4c489644e4aad3c Mon Sep 17 00:00:00 2001 From: Pierre Riteau Date: Wed, 12 Nov 2025 18:33:01 +0100 Subject: [PATCH 06/10] [release] Use OpenStack 2025.2 release Switch all dependencies to use the OpenStack 2025.2 release. This commit should be reverted on the master branch once the Kayobe stable/2025.2 branch has been cut and RC1 released. Depends-On: https://review.opendev.org/c/openstack/kayobe-config-dev/+/966901 Change-Id: I96f89ce707b950e266cee0625998286634d8baed Signed-off-by: Pierre Riteau --- ansible/inventory/group_vars/all/openstack | 6 +++--- etc/kayobe/openstack.yml | 4 ++-- requirements.yml | 2 +- tox.ini | 10 +++++----- zuul.d/jobs.yaml | 8 ++++++++ 5 files changed, 19 insertions(+), 11 deletions(-) diff --git a/ansible/inventory/group_vars/all/openstack b/ansible/inventory/group_vars/all/openstack index e2525ac78..fe673cc33 100644 --- a/ansible/inventory/group_vars/all/openstack +++ b/ansible/inventory/group_vars/all/openstack @@ -2,10 +2,10 @@ ############################################################################### # OpenStack release configuration. -# Name of the current OpenStack release. Default is "master". -openstack_release: "master" +# Name of the current OpenStack release. Default is "2025.2". +openstack_release: "2025.2" -# Name of the current OpenStack branch. Default is "master". +# Name of the current OpenStack branch. Default is "stable/2025.2". openstack_branch: >- {% if openstack_release != 'master' %}stable/{% endif %}{{ openstack_release | lower }} diff --git a/etc/kayobe/openstack.yml b/etc/kayobe/openstack.yml index 1acfd0756..d58a145fe 100644 --- a/etc/kayobe/openstack.yml +++ b/etc/kayobe/openstack.yml @@ -2,10 +2,10 @@ ############################################################################### # OpenStack release configuration. -# Name of the current OpenStack release. Default is "master". +# Name of the current OpenStack release. Default is "2025.2". #openstack_release: -# Name of the current OpenStack branch. Default is "master". +# Name of the current OpenStack branch. Default is "stable/2025.2". #openstack_branch: ############################################################################### diff --git a/requirements.yml b/requirements.yml index ef419f34d..ff8020124 100644 --- a/requirements.yml +++ b/requirements.yml @@ -2,7 +2,7 @@ collections: - name: https://opendev.org/openstack/ansible-collection-kolla type: git - version: master + version: stable/2025.2 - name: community.docker version: 3.11.0 - name: dellemc.os10 diff --git a/tox.ini b/tox.ini index 5801e7136..701bbcfd9 100644 --- a/tox.ini +++ b/tox.ini @@ -18,7 +18,7 @@ setenv = OS_STDERR_CAPTURE=1 OS_TEST_TIMEOUT=60 deps = - -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} + -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/2025.2} -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt commands = stestr run {posargs} @@ -26,7 +26,7 @@ commands = stestr run {posargs} [testenv:pep8] # sphinx8 needs the sphinx package which is required via doc/requirements.txt deps = - -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} + -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/2025.2} -r{toxinidir}/requirements.txt -r{toxinidir}/doc/requirements.txt -r{toxinidir}/test-requirements.txt @@ -41,7 +41,7 @@ commands = [testenv:venv] deps = - -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} + -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/2025.2} -r{toxinidir}/test-requirements.txt -r{toxinidir}/doc/requirements.txt commands = {posargs} @@ -59,7 +59,7 @@ commands = [testenv:molecule] deps = - -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} + -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/2025.2} -r{toxinidir}/requirements.txt -r{toxinidir}/molecule-requirements.txt commands = @@ -130,7 +130,7 @@ commands = [testenv:docs] deps = - -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} + -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/2025.2} -r{toxinidir}/doc/requirements.txt commands = rm -rf doc/build/html diff --git a/zuul.d/jobs.yaml b/zuul.d/jobs.yaml index 2d7272bab..a88ae8b60 100644 --- a/zuul.d/jobs.yaml +++ b/zuul.d/jobs.yaml @@ -71,11 +71,19 @@ required-projects: # Include kayobe to ensure other projects can use this job. - name: openstack/ansible-collection-kolla + # TODO(priteau): Remove when kayobe stable/2025.2 exists. + override-checkout: stable/2025.2 - name: openstack/kayobe - name: openstack/kayobe-config-dev - name: openstack/kolla + # TODO(priteau): Remove when kayobe stable/2025.2 exists. + override-checkout: stable/2025.2 - name: openstack/kolla-ansible + # TODO(priteau): Remove when kayobe stable/2025.2 exists. + override-checkout: stable/2025.2 - name: openstack/requirements + # TODO(priteau): Remove when kayobe stable/2025.2 exists. + override-checkout: stable/2025.2 - name: openstack/tenks irrelevant-files: - ^\..+ From 2f845652dd6d70c67f9454c2b09f983076bbca92 Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Thu, 25 Sep 2025 11:18:28 +0100 Subject: [PATCH 07/10] Bump up Ansible supported versions to 11.x/12.x This change bumps up the maximum supported version of Ansible to 12.x (ansible-core 2.19.x) and minimum to 11.x (ansible-core 2.18.x). Change-Id: I3ab49d28804733733474565d33cc7b564b203ba6 Signed-off-by: Will Szumski --- ansible/action_plugins/template_content.py | 19 +++++++ ansible/kolla-ansible.yml | 4 +- ansible/roles/kolla-ansible/defaults/main.yml | 2 +- ansible/roles/kolla-ansible/tasks/install.yml | 2 +- .../kolla-ansible/tests/test-defaults.yml | 2 +- .../roles/kolla-openstack/tasks/config.yml | 4 +- kayobe/ansible.py | 14 ++++- .../plugins/action/kolla_ansible_host_vars.py | 43 +++++++++----- kayobe/plugins/action/merge_configs.py | 13 ++++- kayobe/plugins/action/merge_yaml.py | 12 +++- kayobe/plugins/action/template_content.py | 47 ++++++++++++++++ kayobe/tests/unit/test_ansible.py | 56 +++++++++++++------ kayobe/tests/unit/test_utils.py | 14 ++++- kayobe/utils.py | 3 +- playbooks/kayobe-base/post.yml | 14 +++-- .../bump-ansible-12-536bc4a3ff55dc3b.yaml | 6 ++ requirements.txt | 2 +- requirements.yml | 11 ++-- tox.ini | 1 + zuul.d/project.yaml | 6 ++ 20 files changed, 219 insertions(+), 56 deletions(-) create mode 100644 ansible/action_plugins/template_content.py create mode 100644 kayobe/plugins/action/template_content.py create mode 100644 releasenotes/notes/bump-ansible-12-536bc4a3ff55dc3b.yaml diff --git a/ansible/action_plugins/template_content.py b/ansible/action_plugins/template_content.py new file mode 100644 index 000000000..88eae2588 --- /dev/null +++ b/ansible/action_plugins/template_content.py @@ -0,0 +1,19 @@ +# Copyright (c) 2025 StackHPC Ltd. +# +# 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. + +__metaclass__ = type + +import kayobe.plugins.action.template_content + +ActionModule = kayobe.plugins.action.template_content.ActionModule diff --git a/ansible/kolla-ansible.yml b/ansible/kolla-ansible.yml index 55b79c530..24f3a9c14 100644 --- a/ansible/kolla-ansible.yml +++ b/ansible/kolla-ansible.yml @@ -93,7 +93,7 @@ kolla_ansible_passwords_path: "{{ kayobe_env_config_path }}/kolla/passwords.yml" kolla_overcloud_inventory_search_paths_static: - "{{ kayobe_config_path }}" - kolla_overcloud_inventory_search_paths: "{{ kolla_overcloud_inventory_search_paths_static + kayobe_env_search_paths }}" + kolla_overcloud_inventory_search_paths: "{{ kolla_overcloud_inventory_search_paths_static + kayobe_env_search_paths | default([]) }}" kolla_ansible_certificates_path: "{{ kayobe_env_config_path }}/kolla/certificates" kolla_inspector_dhcp_pool_start: "{{ inspection_net_name | net_inspection_allocation_pool_start }}" kolla_inspector_dhcp_pool_end: "{{ inspection_net_name | net_inspection_allocation_pool_end }}" @@ -103,7 +103,7 @@ kolla_libvirt_tls: "{{ compute_libvirt_enable_tls | bool }}" kolla_globals_paths_static: - "{{ kayobe_config_path }}" - kolla_globals_paths_extra: "{{ kolla_globals_paths_static + kayobe_env_search_paths }}" + kolla_globals_paths_extra: "{{ kolla_globals_paths_static + kayobe_env_search_paths | default([]) }}" kolla_ironic_inspector_host: "{{ groups[controller_ironic_inspector_group][0] if groups[controller_ironic_inspector_group] | length > 0 else '' }}" - name: Generate Kolla Ansible host vars for the seed host diff --git a/ansible/roles/kolla-ansible/defaults/main.yml b/ansible/roles/kolla-ansible/defaults/main.yml index 9ea9849c0..db99c0cd8 100644 --- a/ansible/roles/kolla-ansible/defaults/main.yml +++ b/ansible/roles/kolla-ansible/defaults/main.yml @@ -26,7 +26,7 @@ kolla_ansible_venv_extra_requirements: [] # tested code. Changes to this limit should be tested. It is possible to only # install ansible-core by setting kolla_ansible_venv_ansible to None. kolla_ansible_venv_ansible: -kolla_ansible_venv_ansible_core: 'ansible-core>=2.17,<2.19' +kolla_ansible_venv_ansible_core: 'ansible-core>=2.18,<2.20' # Path to a requirements.yml file for Ansible collections. kolla_ansible_requirements_yml: "{{ kolla_ansible_venv }}/share/kolla-ansible/requirements.yml" diff --git a/ansible/roles/kolla-ansible/tasks/install.yml b/ansible/roles/kolla-ansible/tasks/install.yml index 5a643b179..d328ed4f2 100644 --- a/ansible/roles/kolla-ansible/tasks/install.yml +++ b/ansible/roles/kolla-ansible/tasks/install.yml @@ -141,7 +141,7 @@ - "{{ kolla_ansible_venv_ansible_core }}" - "{{ kolla_ansible_venv_ansible }}" pip: - name: "{{ (kolla_ansible_packages + kolla_ansible_venv_extra_requirements) | select | list }}" + name: "{{ (kolla_ansible_packages | default([]) + kolla_ansible_venv_extra_requirements | default([])) | select | list }}" state: latest extra_args: "{% if kolla_upper_constraints_file %}-c {{ kolla_upper_constraints_file }}{% endif %}" virtualenv: "{{ kolla_ansible_venv }}" diff --git a/ansible/roles/kolla-ansible/tests/test-defaults.yml b/ansible/roles/kolla-ansible/tests/test-defaults.yml index 5f16456f7..f5832c0d1 100644 --- a/ansible/roles/kolla-ansible/tests/test-defaults.yml +++ b/ansible/roles/kolla-ansible/tests/test-defaults.yml @@ -11,7 +11,7 @@ - block: - name: Test the kolla-ansible role with default values include_role: - name: ../../kolla-ansible + name: "{{ playbook_dir }}/.." vars: kolla_ansible_source_path: "{{ temp_path }}/src" kolla_ansible_ctl_install_type: "source" diff --git a/ansible/roles/kolla-openstack/tasks/config.yml b/ansible/roles/kolla-openstack/tasks/config.yml index 2aa8948a3..ce318fbc6 100644 --- a/ansible/roles/kolla-openstack/tasks/config.yml +++ b/ansible/roles/kolla-openstack/tasks/config.yml @@ -119,11 +119,11 @@ params: content: | {%- for path in item.sources -%} - {{ lookup('template', path) }} + {{ lookup('file', path) }} {%- endfor -%} dest: "{{ item.dest }}" mode: 0640 - copy: "{{ params | combine(item.params) }}" + template_content: "{{ params | combine(item.params) }}" with_items: "{{ kolla_custom_config_info.concat }}" - name: Ensure unnecessary extra configuration files are absent diff --git a/kayobe/ansible.py b/kayobe/ansible.py index 882e2385f..f6cf8dbb0 100644 --- a/kayobe/ansible.py +++ b/kayobe/ansible.py @@ -21,7 +21,14 @@ import sys import tempfile -from ansible.parsing.yaml.objects import AnsibleVaultEncryptedUnicode +# TODO(dougszu): Backwards compatibility for Ansible 11. This exception +# handler can be removed in the G cycle. +try: + from ansible.parsing.vault import EncryptedString +except ImportError: + # Ansible 11 + from ansible.parsing.yaml.objects import AnsibleVaultEncryptedUnicode + EncryptedString = AnsibleVaultEncryptedUnicode from kayobe import exception from kayobe import utils @@ -222,6 +229,9 @@ def _get_environment(parsed_args, external_playbook=False): """Return an environment dict for executing an Ansible playbook.""" env = os.environ.copy() vault.update_environment(parsed_args, env) + # TODO(wszusmki): Kayobe still uses broken conditions. Work on fixing these + # and remove when that work is complete. + env.setdefault("ANSIBLE_ALLOW_BROKEN_CONDITIONALS", "true") # If the configuration path has been specified via --config-path, ensure # the environment variable is set, so that it can be referenced by # playbooks. @@ -340,7 +350,7 @@ def run_playbook(parsed_args, playbook, *args, **kwargs): def _sanitise_hostvar(var): """Sanitise a host variable.""" - if isinstance(var, AnsibleVaultEncryptedUnicode): + if isinstance(var, EncryptedString): return "******" # Recursively sanitise dicts and lists. if isinstance(var, dict): diff --git a/kayobe/plugins/action/kolla_ansible_host_vars.py b/kayobe/plugins/action/kolla_ansible_host_vars.py index b4ee02db8..d6b620980 100644 --- a/kayobe/plugins/action/kolla_ansible_host_vars.py +++ b/kayobe/plugins/action/kolla_ansible_host_vars.py @@ -14,6 +14,16 @@ from ansible.plugins.action import ActionBase +# TODO(dougszu): From Ansible 12 onwards we must explicitly trust templates. +# Since this feature is not supported in previous releases, we define a +# noop method here for backwards compatibility. This can be removed in the +# G cycle. +try: + from ansible.template import trust_as_template +except ImportError: + def trust_as_template(template): + return template + class ConfigError(Exception): pass @@ -28,6 +38,11 @@ class ActionModule(ActionBase): TRANSFERS_FILES = False + def trusted_template(self, input): + # Mark all input as trusted. + trusted_input = trust_as_template(input) + return self._templar.template(trusted_input) + def run(self, tmp=None, task_vars=None): if task_vars is None: task_vars = dict() @@ -97,11 +112,11 @@ def _run(self, interfaces, external_networks): def _get_interface_fact(self, net_name, required, description): # Check whether the network is mapped to this host. condition = "{{ '%s' in network_interfaces }}" % net_name - condition = self._templar.template(condition) + condition = self.trusted_template(condition) if condition: # Get the network interface for this network. iface = ("{{ '%s' | net_interface }}" % net_name) - iface = self._templar.template(iface) + iface = self.trusted_template(iface) if required and not iface: msg = ("Required network '%s' (%s) does not have an interface " "configured for this host" % (net_name, description)) @@ -114,20 +129,20 @@ def _get_interface_fact(self, net_name, required, description): def _get_external_interface(self, net_name, required): condition = "{{ '%s' in network_interfaces }}" % net_name - condition = self._templar.template(condition) + condition = self.trusted_template(condition) if condition: - iface = self._templar.template("{{ '%s' | net_interface }}" % - net_name) + iface = self.trusted_template("{{ '%s' | net_interface }}" % + net_name) if iface: # When these networks are VLANs, we need to use the # underlying tagged bridge interface rather than the # untagged interface. We therefore strip the . suffix # of the interface name. We use a union here as a single # tagged interface may be shared between these networks. - vlan = self._templar.template("{{ '%s' | net_vlan }}" % - net_name) - parent = self._templar.template("{{ '%s' | net_parent }}" % - net_name) + vlan = self.trusted_template("{{ '%s' | net_vlan }}" % + net_name) + parent = self.trusted_template("{{ '%s' | net_parent }}" % + net_name) if vlan and parent: iface = parent elif vlan and iface.endswith(".%s" % vlan): @@ -146,15 +161,15 @@ def _get_external_interface_facts(self, external_interfaces): neutron_external_interfaces = [] neutron_physical_networks = [] missing_physical_networks = [] - bridge_suffix = self._templar.template( + bridge_suffix = self.trusted_template( "{{ network_bridge_suffix_ovs }}") - patch_prefix = self._templar.template("{{ network_patch_prefix }}") - patch_suffix = self._templar.template("{{ network_patch_suffix_ovs }}") + patch_prefix = self.trusted_template("{{ network_patch_prefix }}") + patch_suffix = self.trusted_template("{{ network_patch_suffix_ovs }}") for interface, iface_networks in external_interfaces.items(): is_bridge = ("{{ '%s' in (network_interfaces |" "net_select_bridges |" "map('net_interface')) }}" % interface) - is_bridge = self._templar.template(is_bridge) + is_bridge = self.trusted_template(is_bridge) neutron_bridge_names.append(interface + bridge_suffix) # For a bridge, use a veth pair connected to the bridge. Otherwise # use the interface directly. @@ -171,7 +186,7 @@ def _get_external_interface_facts(self, external_interfaces): # attribute set, and if so, whether they are consistent. iface_physical_networks = [] for iface_network in iface_networks: - physical_network = self._templar.template( + physical_network = self.trusted_template( "{{ '%s' | net_physical_network }}" % iface_network) if (physical_network and physical_network not in iface_physical_networks): diff --git a/kayobe/plugins/action/merge_configs.py b/kayobe/plugins/action/merge_configs.py index 3aff18d53..d1c22e25a 100644 --- a/kayobe/plugins/action/merge_configs.py +++ b/kayobe/plugins/action/merge_configs.py @@ -24,10 +24,21 @@ from ansible import constants from ansible.plugins import action +# TODO(dougszu): From Ansible 12 onwards we must explicitly trust templates. +# Since this feature is not supported in previous releases, we define a +# noop method here for backwards compatibility. This can be removed in the +# G cycle. +try: + from ansible.template import trust_as_template +except ImportError: + def trust_as_template(template): + return template + from io import StringIO from oslo_config import iniparser + _ORPHAN_SECTION = 'TEMPORARY_ORPHAN_VARIABLE_SECTION' DOCUMENTATION = ''' @@ -154,7 +165,7 @@ def read_config(self, source, config): # Only use config if present if os.access(source, os.R_OK): with open(source, 'r') as f: - template_data = f.read() + template_data = trust_as_template(f.read()) # set search path to mimic 'template' module behavior searchpath = [ diff --git a/kayobe/plugins/action/merge_yaml.py b/kayobe/plugins/action/merge_yaml.py index 73f954832..41ab5f099 100644 --- a/kayobe/plugins/action/merge_yaml.py +++ b/kayobe/plugins/action/merge_yaml.py @@ -27,6 +27,16 @@ from ansible import errors as ansible_errors from ansible.plugins import action +# TODO(dougszu): From Ansible 12 onwards we must explicitly trust templates. +# Since this feature is not supported in previous releases, we define a +# noop method here for backwards compatibility. This can be removed in the +# G cycle. +try: + from ansible.template import trust_as_template +except ImportError: + def trust_as_template(template): + return template + DOCUMENTATION = ''' --- module: merge_yaml @@ -95,7 +105,7 @@ def read_config(self, source): # Only use config if present if source and os.access(source, os.R_OK): with open(source, 'r') as f: - template_data = f.read() + template_data = trust_as_template(f.read()) # set search path to mimic 'template' module behavior searchpath = [ diff --git a/kayobe/plugins/action/template_content.py b/kayobe/plugins/action/template_content.py new file mode 100644 index 000000000..cd330bdca --- /dev/null +++ b/kayobe/plugins/action/template_content.py @@ -0,0 +1,47 @@ +# Copyright (c) 2025 StackHPC Ltd. +# +# 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. + +import os +import tempfile + +from ansible.module_utils.common.text.converters import to_bytes +from ansible.plugins.action.template import ActionModule as TemplateBase + +from ansible import errors as ansible_errors + + +class ActionModule(TemplateBase): + """Decorates template action to support using content parameter""" + + def run(self, *args, **kwargs): + module_args = self._task.args + if "src" in module_args and "content" in module_args: + raise ansible_errors.AnsibleActionFail( + "Invalid argument: content and src are mutually exclusive." + ) + if "content" not in module_args and "src" not in module_args: + raise ansible_errors.AnsibleActionFail( + "Invalid argument: You must speicfy either content or src" + ) + + if "src" in module_args: + return super().run(*args, **kwargs) + + with tempfile.NamedTemporaryFile() as fp: + content = module_args.pop("content", "") + fp.write(to_bytes(content)) + fp.flush() + tempfile_path = os.path.join(tempfile.gettempdir(), str(fp.name)) + module_args["src"] = tempfile_path + return super().run(*args, **kwargs) diff --git a/kayobe/tests/unit/test_ansible.py b/kayobe/tests/unit/test_ansible.py index 458373f9a..00600287d 100644 --- a/kayobe/tests/unit/test_ansible.py +++ b/kayobe/tests/unit/test_ansible.py @@ -28,6 +28,9 @@ from kayobe import utils from kayobe import vault +from ansible.parsing.vault import VaultSecret +from ansible.parsing.vault import VaultSecretsContext + @mock.patch.dict(os.environ, clear=True) class TestCase(unittest.TestCase): @@ -56,6 +59,7 @@ def test_run_playbooks(self, mock_validate, mock_vars, mock_run): ] expected_env = { + "ANSIBLE_ALLOW_BROKEN_CONDITIONALS": "true", "KAYOBE_CONFIG_PATH": "/etc/kayobe", "ANSIBLE_ROLES_PATH": ":".join([ "/etc/kayobe/ansible/roles", @@ -106,6 +110,7 @@ def test_run_playbooks_internal(self, mock_validate, mock_vars, mock_run): ] expected_env = { + "ANSIBLE_ALLOW_BROKEN_CONDITIONALS": "true", "KAYOBE_CONFIG_PATH": "/etc/kayobe", "ANSIBLE_ROLES_PATH": ":".join([ utils.get_data_files_path("ansible", "roles"), @@ -223,6 +228,7 @@ def test_run_playbooks_all_the_args(self, mock_validate, mock_vars, ] expected_env = { + "ANSIBLE_ALLOW_BROKEN_CONDITIONALS": "true", "KAYOBE_CONFIG_PATH": "/path/to/config", "KAYOBE_ENVIRONMENT": "test-env", "ANSIBLE_ROLES_PATH": ":".join([ @@ -299,6 +305,7 @@ def test_run_playbooks_all_the_long_args(self, mock_ask, mock_validate, "playbook2.yml", ] expected_env = { + "ANSIBLE_ALLOW_BROKEN_CONDITIONALS": "true", "KAYOBE_CONFIG_PATH": "/path/to/config", "KAYOBE_ENVIRONMENT": "test-env", "KAYOBE_VAULT_PASSWORD": "test-pass", @@ -342,6 +349,7 @@ def test_run_playbooks_vault_password_file(self, mock_update, "playbook1.yml", ] expected_env = { + "ANSIBLE_ALLOW_BROKEN_CONDITIONALS": "true", "KAYOBE_CONFIG_PATH": "/etc/kayobe", "ANSIBLE_ROLES_PATH": mock.ANY, "ANSIBLE_COLLECTIONS_PATH": mock.ANY, @@ -379,6 +387,7 @@ def test_run_playbooks_vault_password_helper(self, mock_validate, "playbook1.yml", ] expected_env = { + "ANSIBLE_ALLOW_BROKEN_CONDITIONALS": "true", "KAYOBE_CONFIG_PATH": "/etc/kayobe", "KAYOBE_VAULT_PASSWORD": "test-pass", "ANSIBLE_ROLES_PATH": mock.ANY, @@ -446,6 +455,7 @@ def test_run_playbooks_func_args(self, mock_validate, mock_vars, mock_run): "playbook2.yml", ] expected_env = { + "ANSIBLE_ALLOW_BROKEN_CONDITIONALS": "true", "KAYOBE_CONFIG_PATH": "/etc/kayobe", "ANSIBLE_ROLES_PATH": mock.ANY, "ANSIBLE_COLLECTIONS_PATH": mock.ANY, @@ -483,6 +493,7 @@ def test_run_playbooks_ignore_limit(self, mock_validate, mock_vars, "playbook2.yml", ] expected_env = { + "ANSIBLE_ALLOW_BROKEN_CONDITIONALS": "true", "KAYOBE_CONFIG_PATH": "/etc/kayobe", "ANSIBLE_ROLES_PATH": mock.ANY, "ANSIBLE_COLLECTIONS_PATH": mock.ANY, @@ -520,6 +531,7 @@ def test_run_playbooks_list_tasks_arg(self, mock_validate, mock_vars, "playbook2.yml", ] expected_env = { + "ANSIBLE_ALLOW_BROKEN_CONDITIONALS": "true", "KAYOBE_CONFIG_PATH": "/etc/kayobe", "ANSIBLE_ROLES_PATH": mock.ANY, "ANSIBLE_COLLECTIONS_PATH": mock.ANY, @@ -553,6 +565,7 @@ def test_run_playbooks_ansible_cfg(self, mock_validate, mock_vars, expected_env = { "ANSIBLE_CONFIG": "/etc/kayobe/ansible.cfg", "KAYOBE_CONFIG_PATH": "/etc/kayobe", + "ANSIBLE_ALLOW_BROKEN_CONDITIONALS": "true", "ANSIBLE_ROLES_PATH": mock.ANY, "ANSIBLE_COLLECTIONS_PATH": mock.ANY, "ANSIBLE_ACTION_PLUGINS": mock.ANY, @@ -585,6 +598,7 @@ def test_run_playbooks_ansible_cfg_env(self, mock_validate, mock_vars, "playbook1.yml", ] expected_env = { + "ANSIBLE_ALLOW_BROKEN_CONDITIONALS": "true", "ANSIBLE_CONFIG": "/path/to/ansible.cfg", "KAYOBE_CONFIG_PATH": "/etc/kayobe", "ANSIBLE_ROLES_PATH": mock.ANY, @@ -656,6 +670,10 @@ def test_config_dump(self, mock_mkdtemp, mock_run, mock_listdir, mock_read, @mock.patch.object(tempfile, 'mkdtemp') def test_config_dump_vaulted(self, mock_mkdtemp, mock_run, mock_listdir, mock_read, mock_rmtree): + + secret = VaultSecret(b'test-pass') + VaultSecretsContext.initialize( + VaultSecretsContext(secrets=[('default', secret)])) parser = argparse.ArgumentParser() parsed_args = parser.parse_args([]) dump_dir = "/path/to/dump" @@ -663,31 +681,31 @@ def test_config_dump_vaulted(self, mock_mkdtemp, mock_run, mock_listdir, mock_listdir.return_value = ["host1.yml", "host2.yml"] config = """--- key1: !vault | - $ANSIBLE_VAULT;1.1;AES256 - 633230623736383232323862393364323037343430393530316636363961626361393133646437 - 643438663261356433656365646138666133383032376532310a63323432306431303437623637 - 346236316161343635636230613838316566383933313338636237616338326439616536316639 - 6334343462333062363334300a3930313762313463613537626531313230303731343365643766 - 666436333037 + $ANSIBLE_VAULT;1.1;AES256 + 65393836643335346138373665636564643436353231623838636261373565633731303835653139 + 6335343464383063373734636161323236636431316532650a333366333366396262353635313531 + 64666236636262326662323931313065376533333961356239363637333363623464666636616233 + 6130373664393533350a663266613165646565346433313536313461653236303563643262323936 + 6262 key2: value2 key3: - !vault | $ANSIBLE_VAULT;1.1;AES256 - 633230623736383232323862393364323037343430393530316636363961626361393133646437 - 643438663261356433656365646138666133383032376532310a63323432306431303437623637 - 346236316161343635636230613838316566383933313338636237616338326439616536316639 - 6334343462333062363334300a3930313762313463613537626531313230303731343365643766 - 666436333037 + 65393836643335346138373665636564643436353231623838636261373565633731303835653139 + 6335343464383063373734636161323236636431316532650a333366333366396262353635313531 + 64666236636262326662323931313065376533333961356239363637333363623464666636616233 + 6130373664393533350a663266613165646565346433313536313461653236303563643262323936 + 6262 """ config_nested = """--- key1: key2: !vault | $ANSIBLE_VAULT;1.1;AES256 - 633230623736383232323862393364323037343430393530316636363961626361393133646437 - 643438663261356433656365646138666133383032376532310a63323432306431303437623637 - 346236316161343635636230613838316566383933313338636237616338326439616536316639 - 6334343462333062363334300a3930313762313463613537626531313230303731343365643766 - 666436333037 + 65393836643335346138373665636564643436353231623838636261373565633731303835653139 + 6335343464383063373734636161323236636431316532650a333366333366396262353635313531 + 64666236636262326662323931313065376533333961356239363637333363623464666636616233 + 6130373664393533350a663266613165646565346433313536313461653236303563643262323936 + 6262 """ mock_read.side_effect = [config, config_nested] result = ansible.config_dump(parsed_args) @@ -951,6 +969,7 @@ def test_multiple_inventory_args(self, mock_validate, mock_vars, mock_run): "playbook2.yml", ] expected_env = { + "ANSIBLE_ALLOW_BROKEN_CONDITIONALS": "true", "KAYOBE_CONFIG_PATH": "/etc/kayobe", "ANSIBLE_ROLES_PATH": mock.ANY, "ANSIBLE_COLLECTIONS_PATH": mock.ANY, @@ -994,6 +1013,7 @@ def exists_replacement(path): "playbook2.yml", ] expected_env = { + "ANSIBLE_ALLOW_BROKEN_CONDITIONALS": "true", "KAYOBE_CONFIG_PATH": "/etc/kayobe", "KAYOBE_ENVIRONMENT": "test-env", "ANSIBLE_ROLES_PATH": mock.ANY, @@ -1036,6 +1056,7 @@ def exists_replacement(path): "playbook2.yml", ] expected_env = { + "ANSIBLE_ALLOW_BROKEN_CONDITIONALS": "true", "KAYOBE_CONFIG_PATH": "/etc/kayobe", "KAYOBE_ENVIRONMENT": "test-env", "ANSIBLE_ROLES_PATH": mock.ANY, @@ -1079,6 +1100,7 @@ def exists_replacement(path): "playbook2.yml", ] expected_env = { + "ANSIBLE_ALLOW_BROKEN_CONDITIONALS": "true", "KAYOBE_CONFIG_PATH": "/etc/kayobe", "KAYOBE_ENVIRONMENT": "test-env", "ANSIBLE_ROLES_PATH": mock.ANY, @@ -1127,6 +1149,7 @@ def exists_replacement(path): "playbook2.yml", ] expected_env = { + "ANSIBLE_ALLOW_BROKEN_CONDITIONALS": "true", "KAYOBE_CONFIG_PATH": "/etc/kayobe", "KAYOBE_ENVIRONMENT": "test-env", "ANSIBLE_ROLES_PATH": mock.ANY, @@ -1207,6 +1230,7 @@ def exists_replacement(path): "playbook2.yml", ] expected_env = { + "ANSIBLE_ALLOW_BROKEN_CONDITIONALS": "true", "KAYOBE_CONFIG_PATH": "/etc/kayobe", "KAYOBE_ENVIRONMENT": "test-env", "ANSIBLE_ROLES_PATH": mock.ANY, diff --git a/kayobe/tests/unit/test_utils.py b/kayobe/tests/unit/test_utils.py index 91d076937..fc975c221 100644 --- a/kayobe/tests/unit/test_utils.py +++ b/kayobe/tests/unit/test_utils.py @@ -18,7 +18,15 @@ import unittest from unittest import mock -from ansible.parsing.yaml.objects import AnsibleVaultEncryptedUnicode +# TODO(dougszu): Backwards compatibility for Ansible 11. This exception +# handler can be removed in the G cycle. +try: + from ansible.parsing.vault import EncryptedString +except ImportError: + # Ansible 11 + from ansible.parsing.yaml.objects import AnsibleVaultEncryptedUnicode + EncryptedString = AnsibleVaultEncryptedUnicode + import yaml from kayobe import exception @@ -167,9 +175,9 @@ def test_read_config_dump_yaml_file_vaulted(self, mock_read): mock_read.return_value = config result = utils.read_config_dump_yaml_file("/path/to/file") # Can't read the value without an encryption key, so just check type. - self.assertIsInstance(result["key1"], AnsibleVaultEncryptedUnicode) + self.assertIsInstance(result["key1"], EncryptedString) self.assertEqual(result["key2"], "value2") - self.assertIsInstance(result["key3"][0], AnsibleVaultEncryptedUnicode) + self.assertIsInstance(result["key3"][0], EncryptedString) mock_read.assert_called_once_with("/path/to/file") @mock.patch.object(utils, "read_file") diff --git a/kayobe/utils.py b/kayobe/utils.py index ff4c35ca0..14cbf6637 100644 --- a/kayobe/utils.py +++ b/kayobe/utils.py @@ -189,7 +189,8 @@ def read_config_dump_yaml_file(path): sys.exit(1) try: # AnsibleLoader supports loading vault encrypted variables. - return AnsibleLoader(content).get_single_data() + data = AnsibleLoader(content).get_single_data() + return data except yaml.YAMLError as e: print("Failed to decode config dump YAML file %s: %s" % (path, repr(e))) diff --git a/playbooks/kayobe-base/post.yml b/playbooks/kayobe-base/post.yml index d2e5eb345..89314aee2 100644 --- a/playbooks/kayobe-base/post.yml +++ b/playbooks/kayobe-base/post.yml @@ -11,11 +11,15 @@ --- - hosts: localhost tasks: - - name: Testing become fails - command: "true" - become: true - register: result - failed_when: '"CONTROL_HOST_BECOME_VIOLATION" not in result.module_stderr' + - block: + - name: Testing become fails + command: "true" + become: true + register: result + rescue: + - name: Check for become failure + fail: + when: '"CONTROL_HOST_BECOME_VIOLATION" not in result.msg' dest: /tmp/test-control-host-become.yml - name: Check that that kayobe become validator was correctly configured diff --git a/releasenotes/notes/bump-ansible-12-536bc4a3ff55dc3b.yaml b/releasenotes/notes/bump-ansible-12-536bc4a3ff55dc3b.yaml new file mode 100644 index 000000000..5901b6a26 --- /dev/null +++ b/releasenotes/notes/bump-ansible-12-536bc4a3ff55dc3b.yaml @@ -0,0 +1,6 @@ +--- + upgrade: + - | + Updates the maximum supported version of Ansible from 12 (ansible-core + 2.18) to 13 (ansible-core 2.19). The minimum supported version is updated + from 10.x to 11.x. This is true for both Kayobe and Kolla Ansible. diff --git a/requirements.txt b/requirements.txt index c4141c12d..75e9edefe 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ pbr>=2.0 # Apache-2.0 Jinja2>3 # BSD -ansible>=10,<12 # GPLv3 +ansible>=11,<13 # GPLv3 cliff>=3.1.0 # Apache netaddr!=0.7.16,>=0.7.13 # BSD PyYAML>=3.10.0 # MIT diff --git a/requirements.yml b/requirements.yml index b87c418c3..2490a5bcb 100644 --- a/requirements.yml +++ b/requirements.yml @@ -29,9 +29,9 @@ roles: version: 1.3.1 - src: giovtorres.tuned version: 1.2.0 - - src: jriguera.configdrive - # There are no versioned releases of this role. - version: 71ddface5540ee0ff9e35bcc4334c766ed5d5d3f + - src: git+https://github.com/stackhpc/ansible-role-configdrive.git + name: jriguera.configdrive + version: fb199247333e72e38a9d414cf7b6144daa645477 - src: MichaelRigart.interfaces version: v1.15.6 - src: mrlesmithjr.chrony @@ -46,8 +46,9 @@ roles: version: 1.1.6 - src: stackhpc.drac-facts version: 1.0.0 - - src: stackhpc.libvirt-host - version: v1.14.0 + - src: git+https://github.com/stackhpc/ansible-role-libvirt-host.git + name: stackhpc.libvirt-host + version: 9a947f74abdcd2e0d4e3371162f8299aef259271 - src: stackhpc.libvirt-vm version: v1.16.3 - src: stackhpc.luks diff --git a/tox.ini b/tox.ini index 5801e7136..a8ea73ca1 100644 --- a/tox.ini +++ b/tox.ini @@ -17,6 +17,7 @@ setenv = OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 OS_TEST_TIMEOUT=60 + ANSIBLE_VERBOSITY=3 deps = -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} -r{toxinidir}/requirements.txt diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml index 17b729553..a49b11c60 100644 --- a/zuul.d/project.yaml +++ b/zuul.d/project.yaml @@ -9,6 +9,9 @@ - release-notes-jobs-python3 check: jobs: + - openstack-tox-py310: + #NOTE(wszumski): We have dropped python3.10 support, so disable this job. + files: THIS-JOB-IS-DISABLED - kayobe-tox-ansible-syntax - kayobe-tox-ansible - kayobe-tox-molecule @@ -34,6 +37,9 @@ - kayobe-seed-vm-ubuntu-noble gate: jobs: + - openstack-tox-py310: + #NOTE(wszumski): We have dropped python3.10 support, so disable this job. + files: THIS-JOB-IS-DISABLED - kayobe-tox-ansible-syntax - kayobe-tox-ansible - kayobe-tox-molecule From 75d93c8da05484e23ffa83ba26fc1b8c10be5ec8 Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Mon, 8 Sep 2025 12:22:12 +0000 Subject: [PATCH 08/10] Support built-in inspector Switches to using the builtin inspector rather than the standalone ironic-inspector service since this has now been dropped from kolla-ansible. Where possible, the new service has been configured to maintain the same behaviour of the old standalone service. When using the standalone inspector, Kayobe has a few opinionated defaults for the set of processing hooks. These defaults have been translated over to the built-in inspector equivalents for a more consistent experience. Inspection rules have rewritten to use the new format. CLI invocations have been updated to use the commands for the new inspection service. Change-Id: I09bd59d085c7ec3fa0ccd6abb84bd2d0c8b9825d Depends-On: https://review.opendev.org/c/openstack/kolla-ansible/+/961266 Signed-off-by: Will Szumski --- ...emetal-compute-introspection-data-save.yml | 4 +- ansible/inventory/group_vars/all/bifrost | 4 +- ansible/inventory/group_vars/all/inspector | 365 ++++++++++-------- ansible/inventory/group_vars/all/kolla | 8 +- ansible/inventory/group_vars/all/openstack | 33 ++ ansible/kolla-bifrost-hostvars.yml | 2 +- ansible/kolla-openstack.yml | 2 +- ansible/overcloud-introspection-data-save.yml | 2 +- ansible/overcloud-introspection-rules.yml | 20 + .../ironic-inspector-rules/defaults/main.yml | 2 +- .../library/os_ironic_inspector_rule.py | 21 +- .../ironic-inspector-rules/tasks/main.yml | 13 +- .../kolla-ansible/templates/kolla/globals.yml | 2 +- ansible/roles/kolla-bifrost/defaults/main.yml | 2 +- .../kolla/config/bifrost/bifrost.yml | 4 +- .../roles/kolla-openstack/defaults/main.yml | 4 +- .../templates/kolla/config/ironic.conf | 32 ++ ansible/seed-introspection-rules.yml | 2 +- dev/functions | 4 +- .../configuration/reference/bifrost.rst | 4 +- etc/kayobe/bifrost.yml | 2 +- etc/kayobe/inspector.yml | 36 +- playbooks/kayobe-overcloud-base/run.yml | 1 - .../kayobe-overcloud-upgrade-base/run.yml | 1 - ...ng-builtin-inspector-04ab4ea4f1a1c3c8.yaml | 26 ++ requirements.yml | 2 +- 26 files changed, 377 insertions(+), 221 deletions(-) create mode 100644 releasenotes/notes/adds-support-for-configuring-builtin-inspector-04ab4ea4f1a1c3c8.yaml diff --git a/ansible/baremetal-compute-introspection-data-save.yml b/ansible/baremetal-compute-introspection-data-save.yml index 505349e5a..28ae86c96 100644 --- a/ansible/baremetal-compute-introspection-data-save.yml +++ b/ansible/baremetal-compute-introspection-data-save.yml @@ -10,7 +10,7 @@ virtualenv: "{{ venv }}" name: - python-openstackclient - - python-ironic-inspector-client + - python-ironicclient state: latest virtualenv_command: python3.{{ ansible_facts.python.version.minor }} -m venv extra_args: "{% if pip_upper_constraints_file %}-c {{ pip_upper_constraints_file }}{% endif %}" @@ -31,7 +31,7 @@ tasks: - name: Query baremetal compute nodes' hardware introspection data command: > - {{ venv }}/bin/openstack baremetal introspection data save {{ inventory_hostname }} + {{ venv }}/bin/openstack baremetal node inventory save {{ inventory_hostname }} register: save_result changed_when: False # Ignore errors, log a message later. diff --git a/ansible/inventory/group_vars/all/bifrost b/ansible/inventory/group_vars/all/bifrost index 76042ff6b..fc02cf5a0 100644 --- a/ansible/inventory/group_vars/all/bifrost +++ b/ansible/inventory/group_vars/all/bifrost @@ -89,8 +89,8 @@ kolla_bifrost_extra_kernel_options: [] ############################################################################### # Ironic Inspector configuration. -# List of of inspector processing plugins. -kolla_bifrost_inspector_processing_hooks: "{{ inspector_processing_hooks }}" +# List of of inspector plugins. +kolla_bifrost_inspector_hooks: "{{ inspector_hooks }}" # Which MAC addresses to add as ports during introspection. One of 'all', # 'active' or 'pxe'. diff --git a/ansible/inventory/group_vars/all/inspector b/ansible/inventory/group_vars/all/inspector index 4497d39eb..f74f39a09 100644 --- a/ansible/inventory/group_vars/all/inspector +++ b/ansible/inventory/group_vars/all/inspector @@ -31,40 +31,47 @@ inspector_ipa_ramdisk_checksum_url: "{{ ipa_ramdisk_checksum_url }}" inspector_ipa_ramdisk_checksum_algorithm: "{{ ipa_ramdisk_checksum_algorithm }}" ############################################################################### -# Ironic inspector processing configuration. +# Ironic inspector processing configuration for the inspector implementation +# built-in to Ironic. + +# List of hooks to enable for inspection. Default is [$default_hooks, memory, +# boot-mode, cpu-capabilities, pci-devices, parse-lldp]. +inspector_hooks_default: + - $default_hooks + - memory + - boot-mode + - cpu-capabilities + - pci-devices + - parse-lldp + +# List of extra inspection hooks to enable. Default is an empty list. +inspector_hooks_extra: [] + +# List of of additional inspector hooks to enable. Default is +# {{ inspector_hooks_default + inspector_hooks_extra }}. +inspector_hooks: > + {{ inspector_hooks_default + inspector_hooks_extra }} -# List of of default inspector processing plugins. -inspector_processing_hooks_default: - - ramdisk_error - - scheduler - - validate_interfaces - - capabilities - - pci_devices - - lldp_basic - - local_link_connection - -# List of of additional inspector processing plugins. -inspector_processing_hooks_extra: [] - -# List of of additional inspector processing plugins. -inspector_processing_hooks: > - {{ inspector_processing_hooks_default + inspector_processing_hooks_extra }} +############################################################################### +# Common Ironic Inspector processing configuration. # Which MAC addresses to add as ports during introspection. One of 'all', -# 'active' or 'pxe'. +# 'active' or 'pxe'. Default is 'pxe'. inspector_add_ports: "pxe" # Which ports to keep after introspection. One of 'all', 'present', or 'added'. +# Default is 'added'. inspector_keep_ports: "added" -# Whether to enable discovery of nodes not managed by Ironic. +# Whether to enable discovery of nodes not managed by Ironic. Default is true. inspector_enable_discovery: True -# The Ironic driver with which to register newly discovered nodes. +# The Ironic driver with which to register newly discovered nodes. Default is +# 'ipmi'. inspector_discovery_enroll_node_driver: "ipmi" ############################################################################### -# Ironic inspector configuration. +# Ironic inspector introspection rules configuration. # Ironic inspector IPMI username to set. inspector_ipmi_username: "{{ ipmi_username }}" @@ -86,9 +93,6 @@ inspector_lldp_switch_port_interface_default: eth0 # check for an LLDP switch port description to use as the node's name. inspector_lldp_switch_port_interface_map: {} -############################################################################### -# Ironic inspector introspection rules configuration. - # Enable IPMI rules: inspector_rules_ipmi_enabled: True @@ -114,17 +118,24 @@ inspector_rule_var_redfish_verify_ca: True inspector_rule_ipmi_credentials: description: "Set IPMI driver_info if no credentials" conditions: - - field: "node://driver_info.ipmi_username" - op: "is-empty" - - field: "node://driver_info.ipmi_password" - op: "is-empty" + - args: + value: "{node.driver_info.ipmi_username}" + regex: '\\{node\\.driver_info\\.ipmi_username\\}' + op: "matches" + - args: + value: "{node.driver_info.ipmi_password}" + regex: '\\{node\\.driver_info\\.ipmi_password\\}' + op: "matches" + sensitive: "true" actions: - - action: "set-attribute" - path: "driver_info/ipmi_username" - value: "{{ inspector_rule_var_ipmi_username }}" - - action: "set-attribute" - path: "driver_info/ipmi_password" - value: "{{ inspector_rule_var_ipmi_password }}" + - op: "set-attribute" + args: + path: "driver_info/ipmi_username" + value: "{{ inspector_rule_var_ipmi_username }}" + - op: "set-attribute" + args: + path: "driver_info/ipmi_password" + value: "{{ inspector_rule_var_ipmi_password }}" # Deployment kernel referenced by inspector rule. inspector_rule_var_deploy_kernel: @@ -133,12 +144,15 @@ inspector_rule_var_deploy_kernel: inspector_rule_deploy_kernel: description: "Set deploy kernel" conditions: - - field: "node://driver_info.deploy_kernel" - op: "is-empty" + - args: + value: "{node.driver_info.deploy_kernel}" + regex: '\\{node\\.driver_info\\.deploy_kernel\\}' + op: "matches" actions: - - action: "set-attribute" - path: "driver_info/deploy_kernel" - value: "{{ inspector_rule_var_deploy_kernel }}" + - op: "set-attribute" + args: + path: "driver_info/deploy_kernel" + value: "{{ inspector_rule_var_deploy_kernel }}" # Deployment ramdisk referenced by inspector rule. inspector_rule_var_deploy_ramdisk: @@ -147,220 +161,233 @@ inspector_rule_var_deploy_ramdisk: inspector_rule_deploy_ramdisk: description: "Set deploy ramdisk" conditions: - - field: "node://driver_info.deploy_ramdisk" - op: "is-empty" - actions: - - action: "set-attribute" - path: "driver_info/deploy_ramdisk" - value: "{{ inspector_rule_var_deploy_ramdisk }}" - -# Ironic inspector rule to initialise root device hints. -inspector_rule_root_hint_init: - description: "Initialise root device hint" - conditions: - - field: "node://properties.root_device" - op: "is-empty" + - args: + value: "{node.driver_info.deploy_ramdisk}" + regex: '\\{node\\.driver_info\\.deploy_ramdisk\\}' + op: "matches" actions: - # Inspector can't combine references to introspection data with non-string - # types, see https://bugs.launchpad.net/ironic-inspector/+bug/1670768. We - # must therefore first set the root_device property to an empty dict, then - # update the fields within it. - - action: "set-attribute" - path: "properties/root_device" - value: {} + - op: "set-attribute" + args: + path: "driver_info/deploy_ramdisk" + value: "{{ inspector_rule_var_deploy_ramdisk }}" # Ironic inspector rule to set serial root device hint. inspector_rule_root_hint_serial: description: "Set serial root device hint" conditions: - - field: "data://root_disk.serial" - op: "is-empty" - invert: True + - args: + value: "{node.properties[root_device]}" + regex: "\\{node\\.properties\\[root_device\\]\\}" + op: "matches" actions: - - action: "set-attribute" - path: "properties/root_device/serial" - value: "{data[root_disk][serial]}" + - op: "set-attribute" + args: + path: "properties/root_device/name" + value: "{plugin_data[root_disk][by_path]}" + # Ironic inspector rule to set the interface on which the node PXE booted. inspector_rule_set_pxe_interface_mac: description: "Set node PXE interface MAC address" conditions: - - field: "data://boot_interface" - op: "is-empty" - invert: True + - args: + value: "{plugin_data[boot_interface]}" + regex: "'\\{plugin_data\\[boot_interface\\]\\}'" + op: "!matches" actions: - - action: "set-attribute" - path: "extra/pxe_interface_mac" - value: "{data[boot_interface]}" + - op: "set-attribute" + args: + path: "extra/pxe_interface_mac" + value: "{plugin_data[boot_interface]}" # Name of network interface to use for LLDP referenced by switch port # description rule. inspector_rule_var_lldp_switch_port_interface: +# Internal variables. Not meant for use externally. +_inspector_rule_interface_path: "{all_interfaces.{{ inspector_rule_var_lldp_switch_port_interface }}}" +_inspector_rule_lldp_processed_path: "{all_interfaces.{{ inspector_rule_var_lldp_switch_port_interface }}.lldp_processed}" +_inspector_rule_switch_port_description_path: "{all_interfaces.{{inspector_rule_var_lldp_switch_port_interface}}.lldp_processed.switch_port_description}" + # Ironic inspector rule to set the node's name from an interface's LLDP switch # port description. inspector_rule_lldp_switch_port_desc_to_name: description: "Set node name from {{ inspector_rule_var_lldp_switch_port_interface }} LLDP switch port description" conditions: # Check for the existence of the switch_port_description field. - - field: "data://all_interfaces.{{ inspector_rule_var_lldp_switch_port_interface }}" - op: "is-empty" - invert: True - - field: "data://all_interfaces.{{ inspector_rule_var_lldp_switch_port_interface }}.lldp_processed" - op: "is-empty" - invert: True - - field: "data://all_interfaces.{{ inspector_rule_var_lldp_switch_port_interface }}.lldp_processed.switch_port_description" - op: "is-empty" - invert: True + - args: + value: "{{ _inspector_rule_interface_path }}" + regex: "{{ _inspector_rule_interface_path | regex_escape }}" + op: "!matches" + - args: + value: "{{ _inspector_rule_lldp_processed_path }}" + regex: "{{ _inspector_rule_lldp_processed_path | regex_escape }}" + op: "!matches" + - args: + value: "{{ _inspector_rule_switch_port_description_path }}" + regex: "{{ _inspector_rule_switch_port_description_path | regex_escape }}" + op: "!matches" # Filter out switch port descriptions using the switch's interface names. # On some switches (including Dell Network OS 9.10(0.1) and some Ruckus # switches), the port description TLV is sent but contains the interface # name rather than the interface's description. Dell switches use a space # character between port type and port number, while Ruckus switches don't. - - field: "data://all_interfaces.{{inspector_rule_var_lldp_switch_port_interface}}.lldp_processed.switch_port_description" - op: "matches" - value: "^GigabitEthernet ?([0-9/]*)$" - invert: True - - field: "data://all_interfaces.{{inspector_rule_var_lldp_switch_port_interface}}.lldp_processed.switch_port_description" - op: "matches" - value: "^TenGigabitEthernet ?([0-9/]*)$" - invert: True - - field: "data://all_interfaces.{{inspector_rule_var_lldp_switch_port_interface}}.lldp_processed.switch_port_description" - op: "matches" - value: "^twentyFiveGigE ?([0-9/]*)$" - invert: True - - field: "data://all_interfaces.{{inspector_rule_var_lldp_switch_port_interface}}.lldp_processed.switch_port_description" - op: "matches" - value: "^fortyGigE ?([0-9/]*)$" - invert: True - - field: "data://all_interfaces.{{inspector_rule_var_lldp_switch_port_interface}}.lldp_processed.switch_port_description" - op: "matches" - value: "^Port-channel ?([0-9/]*)$" - invert: True + - op: "!matches" + args: + value: "{{ _inspector_rule_switch_port_description_path }}" + regex: "^GigabitEthernet ?([0-9/]*)$" + - op: "!matches" + args: + value: "{{ _inspector_rule_switch_port_description_path }}" + regex: "^TenGigabitEthernet ?([0-9/]*)$" + - op: "!matches" + args: + value: "{{ _inspector_rule_switch_port_description_path }}" + regex: "^twentyFiveGigE ?([0-9/]*)$" + - op: "!matches" + args: + value: "{{ _inspector_rule_switch_port_description_path }}" + regex: "^fortyGigE ?([0-9/]*)$" + - op: "!matches" + args: + value: "{{ _inspector_rule_switch_port_description_path }}" + regex: "^Port-channel ?([0-9/]*)$" actions: - - action: "set-attribute" - path: "name" - value: "{data[all_interfaces][{{ inspector_rule_var_lldp_switch_port_interface }}][lldp_processed][switch_port_description]}" - -# Ironic inspector rule to initialise system vendor data in the node's metadata. -inspector_rule_save_system_vendor_init: - description: "Initialise system vendor data in Ironic node metadata" - conditions: - - field: "data://inventory.system_vendor" - op: "is-empty" - invert: True - - field: "node://extra.system_vendor" - op: "is-empty" - actions: - - action: "set-attribute" - path: "extra/system_vendor" - value: {} + - op: "set-attribute" + args: + path: "name" + value: "{{ _inspector_rule_switch_port_description_path }}" # Ironic inspector rule to save system vendor manufacturer data in the node's # metadata. inspector_rule_save_system_vendor_manufacturer: description: "Save system vendor manufacturer data in Ironic node metadata" conditions: - - field: "data://inventory.system_vendor" - op: "is-empty" - invert: True - - field: "data://inventory.system_vendor.manufacturer" - op: "is-empty" - invert: True + - args: + value: "{inventory.system_vendor}" + regex: "\\{inventory\\.system_vendor\\}" + op: "!matches" + - args: + value: "{inventory.system_vendor.manufacturer}" + regex: "\\{inventory\\.system_vendor\\.manufacturer\\}" + op: "!matches" actions: - - action: "set-attribute" - path: "extra/system_vendor/manufacturer" - value: "{data[inventory][system_vendor][manufacturer]}" + - op: "set-attribute" + args: + path: "extra/system_vendor/manufacturer" + value: "{inventory[system_vendor][manufacturer]}" # Ironic inspector rule to save system vendor serial number in the node's # metadata. inspector_rule_save_system_vendor_serial_number: description: "Save system vendor serial number in Ironic node metadata" conditions: - - field: "data://inventory.system_vendor" - op: "is-empty" - invert: True - - field: "data://inventory.system_vendor.serial_number" - op: "is-empty" - invert: True + - args: + value: "{inventory.system_vendor}" + regex: "\\{inventory\\.system_vendor\\}" + op: "!matches" + - args: + value: "{inventory.system_vendor.serial_number}" + regex: "\\{inventory\\.system_vendor\\.serial_number\\}" + op: "!matches" actions: - - action: "set-attribute" - path: "extra/system_vendor/serial_number" - value: "{data[inventory][system_vendor][serial_number]}" + - op: "set-attribute" + args: + path: "extra/system_vendor/serial_number" + value: "{inventory[system_vendor][serial_number]}" # Ironic inspector rule to save system vendor product name in the node's # metadata. inspector_rule_save_system_vendor_product_name: description: "Save system vendor product name in Ironic node metadata" conditions: - - field: "data://inventory.system_vendor" - op: "is-empty" - invert: True - - field: "data://inventory.system_vendor.product_name" - op: "is-empty" - invert: True + - args: + value: "{inventory.system_vendor}" + regex: "\\{inventory\\.system_vendor\\}" + op: "!matches" + - args: + value: "{inventory.system_vendor.product_name}" + regex: "\\{inventory\\.system_vendor\\.product_name\\}" + op: "!matches" actions: - - action: "set-attribute" - path: "extra/system_vendor/product_name" - value: "{data[inventory][system_vendor][product_name]}" + - op: "set-attribute" + args: + path: "extra/system_vendor/product_name" + value: "{inventory[system_vendor][product_name]}" # Ironic inspector rule to save introspection data to the node. inspector_rule_save_data: description: "Save introspection data to Ironic node" conditions: [] actions: - - action: "set-attribute" - path: "extra/introspection_data" - value: "{data}" + - op: "set-attribute" + args: + path: "extra/introspection_data/inventory" + value: "{inventory}" + - op: "set-attribute" + args: + path: "extra/introspection_data/plugin_data" + value: "{plugin_data}" # Redfish rules # Ironic inspector rule to set Redfish credentials. inspector_rule_redfish_credentials: description: "Set Redfish driver_info if no credentials" conditions: - - field: "node://driver_info.redfish_username" - op: "is-empty" - - field: "node://driver_info.redfish_password" - op: "is-empty" + - args: + value: "{node.driver_info.redfish_username}" + regex: "\\{node\\.driver_info\\.redfish_username\\}" + op: "matches" + - args: + value: "{node.driver_info.redfish_password}" + regex: "\\{node\\.driver_info\\.redfish_password\\}" + op: "matches" + sensitive: true actions: - - action: "set-attribute" - path: "driver_info/redfish_username" - value: "{{ inspector_rule_var_redfish_username }}" - - action: "set-attribute" - path: "driver_info/redfish_password" - value: "{{ inspector_rule_var_redfish_password }}" + - op: "set-attribute" + args: + path: "driver_info/redfish_username" + value: "{{ inspector_rule_var_redfish_username }}" + - op: "set-attribute" + args: + path: "driver_info/redfish_password" + value: "{{ inspector_rule_var_redfish_password }}" # Ironic inspector rule to set Redfish address. inspector_rule_redfish_address: description: "Set Redfish address" conditions: - - field: "node://driver_info.redfish_address" - op: "is-empty" + - args: + value: "{node.driver_info.redfish_address}" + regex: "\\{node\\.driver_info\\.redfish_address\\}" + op: "matches" actions: - - action: "set-attribute" - path: "driver_info/redfish_address" - value: "{data[inventory][bmc_address]}" + - op: "set-attribute" + args: + path: "driver_info/redfish_address" + value: "{inventory[bmc_address]}" # Ironic inspector rule to set Redfish certificate authority. inspector_rule_redfish_verify_ca: description: "Set Redfish Verify CA" conditions: - - field: "node://driver_info.redfish_verify_ca" - op: "is-empty" + - args: + value: "{node.driver_info.redfish_verify_ca}" + regex: "\\{node\\.driver_info\\.redfish_verify_ca\\}" + op: "matches" actions: - - action: "set-attribute" - path: "driver_info/redfish_verify_ca" - value: "{{ inspector_rule_var_redfish_verify_ca }}" + - op: "set-attribute" + args: + path: "driver_info/redfish_verify_ca" + value: "{{ inspector_rule_var_redfish_verify_ca }}" # List of default ironic inspector rules. inspector_rules_default: - "{{ inspector_rule_deploy_kernel }}" - "{{ inspector_rule_deploy_ramdisk }}" - - "{{ inspector_rule_root_hint_init }}" - "{{ inspector_rule_root_hint_serial }}" - "{{ inspector_rule_set_pxe_interface_mac }}" - "{{ inspector_rule_lldp_switch_port_desc_to_name }}" - - "{{ inspector_rule_save_system_vendor_init }}" - "{{ inspector_rule_save_system_vendor_manufacturer }}" - "{{ inspector_rule_save_system_vendor_serial_number }}" - "{{ inspector_rule_save_system_vendor_product_name }}" diff --git a/ansible/inventory/group_vars/all/kolla b/ansible/inventory/group_vars/all/kolla index ec74668ff..411b116e6 100644 --- a/ansible/inventory/group_vars/all/kolla +++ b/ansible/inventory/group_vars/all/kolla @@ -153,7 +153,7 @@ overcloud_container_image_regex_map: - regex: ^designate enabled: "{{ kolla_enable_designate | bool }}" - regex: ^dnsmasq - enabled: "{{ kolla_enable_ironic | bool }}" + enabled: "{{ kolla_enable_ironic_dnsmasq | bool }}" - regex: ^etcd enabled: "{{ kolla_enable_etcd | bool }}" - regex: ^fluentd @@ -548,6 +548,8 @@ kolla_enable_heat: "{{ kolla_enable_openstack_core | bool }}" kolla_enable_horizon: "{{ kolla_enable_openstack_core | bool }}" kolla_enable_influxdb: "{{ kolla_enable_cloudkitty | bool }}" kolla_enable_ironic: "no" +kolla_enable_ironic_dnsmasq: "{{ kolla_enable_ironic | bool and kolla_inspector_enable_discovery | bool }}" +kolla_enable_ironic_pxe_filter: "{{ kolla_enable_ironic | bool and kolla_inspector_enable_discovery | bool }}" kolla_enable_ironic_neutron_agent: "{{ kolla_enable_neutron | bool and kolla_enable_ironic | bool }}" kolla_enable_iscsid: "{{ kolla_enable_cinder | bool and kolla_enable_cinder_backend_iscsi | bool }}" kolla_enable_kuryr: "no" @@ -695,3 +697,7 @@ kolla_https_proxy: "{{ https_proxy }}" # List of domains, hostnames, IP addresses and networks for which no proxy is # used. Default value is "{{ no_proxy }}". kolla_no_proxy: "{{ no_proxy }}" + +############################################################################## +# Inspector configuration +kolla_inspector_enable_discovery: "{{ inspector_enable_discovery | bool }}" \ No newline at end of file diff --git a/ansible/inventory/group_vars/all/openstack b/ansible/inventory/group_vars/all/openstack index e2525ac78..430293d3f 100644 --- a/ansible/inventory/group_vars/all/openstack +++ b/ansible/inventory/group_vars/all/openstack @@ -9,6 +9,11 @@ openstack_release: "master" openstack_branch: >- {% if openstack_release != 'master' %}stable/{% endif %}{{ openstack_release | lower }} +############################################################################### +# OpenStack virtualenv configuration. + +os_virtualenv_python: "{{ '/usr/bin/python3.12' if ansible_facts.os_family == 'RedHat' else '/usr/bin/python3' }}" + ############################################################################### # OpenStack authentication configuration. @@ -28,6 +33,19 @@ openstack_auth: auth_url: "{{ lookup('env', 'OS_AUTH_URL') }}" system_scope: "{{ lookup('env', 'OS_SYSTEM_SCOPE') }}" +# Internal variable to set the system scope authentication. +openstack_auth_system_scope_value: 'all' + +# Overcloud authentication parameters for system scope. By default this will +# use the user defined in openstack_auth. +# NOTE(wszumski): Not all projects support system scope yet and we sometimes need +# to use system scope and project scope in the same ansible run. +openstack_auth_system_scope: >- + {{ openstack_auth | combine( + {'system_scope': openstack_auth_system_scope_value, + 'project_domain_name': '', + 'project_name': ''})}} + # Overcloud CA certificate path. openstack_cacert: "{{ lookup('env', 'OS_CACERT') }}" @@ -49,6 +67,14 @@ openstack_auth_env: OS_CACERT: "{{ lookup('env', 'OS_CACERT') }}" OS_SYSTEM_SCOPE: "{{ lookup('env', 'OS_SYSTEM_SCOPE') }}" +# Overcloud authentication environment variables for system scope. By default +# this will use the user defined in openstack_auth_env. +openstack_auth_env_system_scope: >- + {{ openstack_auth_env | combine( + {'OS_SYSTEM_SCOPE': openstack_auth_system_scope_value, + 'OS_PROJECT_DOMAIN_NAME': '', + 'OS_PROJECT_NAME': ''})}} + # List of parameters required in openstack_auth when openstack_auth_type is # password. openstack_auth_password_required_params: @@ -56,3 +82,10 @@ openstack_auth_password_required_params: - "username" - "password" - "auth_url" + +# List of parameters required in openstack_auth when openstack_auth_type is +# password and using system scope +openstack_auth_password_required_params_system: + - "username" + - "password" + - "auth_url" diff --git a/ansible/kolla-bifrost-hostvars.yml b/ansible/kolla-bifrost-hostvars.yml index d560e4d0e..ebe13ceb0 100644 --- a/ansible/kolla-bifrost-hostvars.yml +++ b/ansible/kolla-bifrost-hostvars.yml @@ -61,7 +61,7 @@ -e @/etc/bifrost/dib.yml --limit {{ inventory_hostname }} -m shell - -a "env OS_CLOUD=bifrost baremetal introspection data save {% raw %}{{ inventory_hostname }}{% endraw %}"' + -a "env OS_CLOUD=bifrost baremetal inventory save {% raw %}{{ inventory_hostname }}{% endraw %}"' register: save_result changed_when: False # Ignore errors, log a message later. diff --git a/ansible/kolla-openstack.yml b/ansible/kolla-openstack.yml index bb116330d..ea2aec967 100644 --- a/ansible/kolla-openstack.yml +++ b/ansible/kolla-openstack.yml @@ -131,7 +131,7 @@ roles: - role: kolla-openstack # Ironic inspector configuration. - kolla_inspector_processing_hooks: "{{ inspector_processing_hooks }}" + kolla_inspector_hooks: "{{ inspector_hooks }}" kolla_inspector_add_ports: "{{ inspector_add_ports }}" kolla_inspector_keep_ports: "{{ inspector_keep_ports }}" kolla_inspector_enable_discovery: "{{ inspector_enable_discovery }}" diff --git a/ansible/overcloud-introspection-data-save.yml b/ansible/overcloud-introspection-data-save.yml index 284a899f2..0e2b16111 100644 --- a/ansible/overcloud-introspection-data-save.yml +++ b/ansible/overcloud-introspection-data-save.yml @@ -25,7 +25,7 @@ -e @/etc/bifrost/dib.yml --limit {{ inventory_hostname }} -m shell - -a "env OS_CLOUD=bifrost baremetal introspection data save {% raw %}{{ inventory_hostname }}{% endraw %}"' + -a "env OS_CLOUD=bifrost baremetal node inventory save {% raw %}{{ inventory_hostname }}{% endraw %}"' register: save_result changed_when: False # Ignore errors, log a message later. diff --git a/ansible/overcloud-introspection-rules.yml b/ansible/overcloud-introspection-rules.yml index 0782800d2..4c4f1126c 100644 --- a/ansible/overcloud-introspection-rules.yml +++ b/ansible/overcloud-introspection-rules.yml @@ -55,3 +55,23 @@ changed_when: False register: ipa_ramdisk_id environment: "{{ openstack_auth_env }}" + + roles: + - role: ironic-inspector-rules + os_openstacksdk_install_epel: "{{ dnf_install_epel }}" + os_openstacksdk_state: "latest" + ironic_inspector_venv: "{{ venv }}" + ironic_inspector_upper_constraints_file: "{{ openstacksdk_upper_constraints_file }}" + ironic_inspector_auth_type: "{{ openstack_auth_type }}" + ironic_inspector_auth: "{{ openstack_auth_system_scope }}" + ironic_inspector_cacert: "{{ openstack_cacert }}" + ironic_inspector_interface: "{{ openstack_interface }}" + ironic_inspector_rules: "{{ inspector_rules }}" + # These variables may be referenced in the introspection rules. + inspector_rule_var_ipmi_username: "{{ inspector_ipmi_username }}" + inspector_rule_var_ipmi_password: "{{ inspector_ipmi_password }}" + inspector_rule_var_redfish_username: "{{ inspector_redfish_username }}" + inspector_rule_var_redfish_password: "{{ inspector_redfish_password }}" + inspector_rule_var_lldp_switch_port_interface: "{{ inspector_lldp_switch_port_interface_default }}" + inspector_rule_var_deploy_kernel: "{{ ipa_kernel_id.stdout }}" + inspector_rule_var_deploy_ramdisk: "{{ ipa_ramdisk_id.stdout }}" diff --git a/ansible/roles/ironic-inspector-rules/defaults/main.yml b/ansible/roles/ironic-inspector-rules/defaults/main.yml index ee38abae1..fd36cc0cf 100644 --- a/ansible/roles/ironic-inspector-rules/defaults/main.yml +++ b/ansible/roles/ironic-inspector-rules/defaults/main.yml @@ -2,7 +2,7 @@ # Path to a directory in which to create a virtualenv. ironic_inspector_venv: -# Upper constraints file for installation of python-ironic-inspector-client. +# Upper constraints file for installation of python-ironicclient. ironic_inspector_upper_constraints_file: # Authentication type. diff --git a/ansible/roles/ironic-inspector-rules/library/os_ironic_inspector_rule.py b/ansible/roles/ironic-inspector-rules/library/os_ironic_inspector_rule.py index 5db8f8088..c84743a51 100644 --- a/ansible/roles/ironic-inspector-rules/library/os_ironic_inspector_rule.py +++ b/ansible/roles/ironic-inspector-rules/library/os_ironic_inspector_rule.py @@ -53,6 +53,10 @@ description: - List of actions to be taken when the conditions are met. required: true + sensitive: + description: + - Whether to mark the rule as sensitive in Ironic + required: false """ EXAMPLES = """ @@ -74,13 +78,13 @@ def _get_client(module, cloud): """Return an Ironic inspector client.""" - return cloud.baremetal_introspection + return cloud.baremetal def _ensure_rule_present(module, client): """Ensure that an inspector rule is present.""" if module.params['uuid']: - response = client.get('/rules/{}'.format(module.params['uuid'])) + response = client.get('/inspection_rules/{}'.format(module.params['uuid']), headers={'X-OpenStack-Ironic-API-Version': '1.96'}) if not response.ok: if response.status_code != 404: module.fail_json(msg="Failed retrieving Inspector rule %s: %s" @@ -88,7 +92,7 @@ def _ensure_rule_present(module, client): else: rule = response.json() # Check whether the rule differs from the request. - keys = ('conditions', 'actions', 'description') + keys = ('conditions', 'actions', 'description', 'sensitive') for key in keys: expected = module.params[key] if key == 'conditions': @@ -96,9 +100,10 @@ def _ensure_rule_present(module, client): # conditions that may not be in the requested rule. Apply # defaults to allow the comparison to succeed. expected = copy.deepcopy(expected) + if key == 'actions': + expected = copy.deepcopy(expected) for condition in expected: - condition.setdefault('invert', False) - condition.setdefault('multiple', 'any') + condition.setdefault('loop', []) if rule[key] != expected: break else: @@ -111,9 +116,10 @@ def _ensure_rule_present(module, client): "conditions": module.params['conditions'], "actions": module.params['actions'], "description": module.params['description'], + "sensitive": module.params['sensitive'], "uuid": module.params['uuid'], } - response = client.post("/rules", json=rule) + response = client.post("/inspection_rules", json=rule, headers={'X-OpenStack-Ironic-API-Version': '1.96'}) if not response.ok: module.fail_json(msg="Failed creating Inspector rule %s: %s" % (module.params['uuid'], response.text)) @@ -124,7 +130,7 @@ def _ensure_rule_absent(module, client): """Ensure that an inspector rule is absent.""" if not module.params['uuid']: module.fail_json(msg="UUID is required to ensure rules are absent") - response = client.delete("/rules/{}".format(module.params['uuid'])) + response = client.delete("/inspection_rules/{}".format(module.params['uuid']), headers={'X-OpenStack-Ironic-API-Version': '1.96'}) if not response.ok: # If the rule does not exist, no problem and no change. if response.status_code == 404: @@ -140,6 +146,7 @@ def main(): actions=dict(type='list', required=True), description=dict(required=False), uuid=dict(required=False), + sensitive=dict(type='bool', required=False, default=False), state=dict(required=False, default='present', choices=['present', 'absent']), ) diff --git a/ansible/roles/ironic-inspector-rules/tasks/main.yml b/ansible/roles/ironic-inspector-rules/tasks/main.yml index 93fbe7fcb..41a1aab7e 100644 --- a/ansible/roles/ironic-inspector-rules/tasks/main.yml +++ b/ansible/roles/ironic-inspector-rules/tasks/main.yml @@ -8,9 +8,12 @@ cacert: "{{ ironic_inspector_cacert | default(omit, true) }}" cloud: "{{ ironic_inspector_cloud | default(omit, true) }}" interface: "{{ ironic_inspector_interface | default(omit, true) }}" - conditions: "{{ item.conditions }}" - actions: "{{ item.actions }}" - description: "{{ item.description | default(omit) }}" - uuid: "{{ item.uuid | default(item.description | to_uuid) | default(omit) }}" + conditions: "{{ ironic_inspector_rules[item].conditions }}" + actions: "{{ ironic_inspector_rules[item].actions }}" + description: "{{ ironic_inspector_rules[item].description | default(omit) }}" + uuid: "{{ ironic_inspector_rules[item].uuid | default(ironic_inspector_rules[item].description | to_uuid) | default(omit) }}" + sensitive: "{{ ironic_inspector_rules[item].sensitive | default(omit) }}" state: present - with_items: "{{ ironic_inspector_rules }}" + loop_control: + label: "{{ ironic_inspector_rules[item].description }}" + with_items: "{{ range(0, ironic_inspector_rules | length) | list }}" diff --git a/ansible/roles/kolla-ansible/templates/kolla/globals.yml b/ansible/roles/kolla-ansible/templates/kolla/globals.yml index a1a01451d..ccc37cddf 100644 --- a/ansible/roles/kolla-ansible/templates/kolla/globals.yml +++ b/ansible/roles/kolla-ansible/templates/kolla/globals.yml @@ -403,7 +403,7 @@ ironic_dnsmasq_dhcp_ranges: {% endif %} {% endif %} {% if kolla_inspector_extra_kernel_options %} -ironic_inspector_kernel_cmdline_extras: +ironic_kernel_cmdline_extras: {{ kolla_inspector_extra_kernel_options | to_nice_yaml }} {% endif %} # PXE bootloader file for Ironic Inspector, relative to /var/lib/ironic/tftpboot. diff --git a/ansible/roles/kolla-bifrost/defaults/main.yml b/ansible/roles/kolla-bifrost/defaults/main.yml index ae2e5fa47..eff98ea8f 100644 --- a/ansible/roles/kolla-bifrost/defaults/main.yml +++ b/ansible/roles/kolla-bifrost/defaults/main.yml @@ -42,7 +42,7 @@ kolla_bifrost_dnsmasq_dns_servers: [] kolla_bifrost_domain: # List of of inspector processing plugins. -kolla_bifrost_inspector_processing_hooks: +kolla_bifrost_inspector_hooks: # Which MAC addresses to add as ports during introspection. One of 'all', # 'active' or 'pxe'. diff --git a/ansible/roles/kolla-bifrost/templates/kolla/config/bifrost/bifrost.yml b/ansible/roles/kolla-bifrost/templates/kolla/config/bifrost/bifrost.yml index 5269328fe..e1e671b67 100644 --- a/ansible/roles/kolla-bifrost/templates/kolla/config/bifrost/bifrost.yml +++ b/ansible/roles/kolla-bifrost/templates/kolla/config/bifrost/bifrost.yml @@ -28,9 +28,9 @@ dnsmasq_dns_servers: "{{ kolla_bifrost_dnsmasq_dns_servers | join(',') }}" domain: "{{ kolla_bifrost_domain }}" {% endif %} -{% if kolla_bifrost_inspector_processing_hooks %} +{% if kolla_bifrost_inspector_hooks %} # Comma-separated list of inspector processing plugins. -inspector_processing_hooks: "{{ kolla_bifrost_inspector_processing_hooks | join(',') }}" +inspector_hooks: "{{ kolla_bifrost_inspector_hooks | join(',') }}" {% endif %} {% if kolla_bifrost_inspector_port_addition %} diff --git a/ansible/roles/kolla-openstack/defaults/main.yml b/ansible/roles/kolla-openstack/defaults/main.yml index c326bd838..0fabde950 100644 --- a/ansible/roles/kolla-openstack/defaults/main.yml +++ b/ansible/roles/kolla-openstack/defaults/main.yml @@ -567,7 +567,9 @@ kolla_extra_ironic: # Ironic inspector configuration. # Comma-separated list of inspector processing plugins. -kolla_inspector_processing_hooks: + +# Comma-separated list of inspector processing plugins for built-in inspector +kolla_inspector_hooks: # Which MAC addresses to add as ports during introspection. One of 'all', # 'active' or 'pxe'. diff --git a/ansible/roles/kolla-openstack/templates/kolla/config/ironic.conf b/ansible/roles/kolla-openstack/templates/kolla/config/ironic.conf index cbb8ca683..3961eb631 100644 --- a/ansible/roles/kolla-openstack/templates/kolla/config/ironic.conf +++ b/ansible/roles/kolla-openstack/templates/kolla/config/ironic.conf @@ -1,4 +1,11 @@ [DEFAULT] +enabled_inspect_interfaces = redfish,no-inspect,agent +{% if kolla_inspector_enable_discovery | bool %} +# Setting default_inspect_interface is required for the inspection flow to +# continue correctly after the node creation. See: +# https://docs.openstack.org/ironic/latest/admin/inspection/discovery.html +default_inspect_interface = agent +{% endif %} {% if kolla_ironic_enabled_hardware_types %} enabled_hardware_types: {{ kolla_ironic_enabled_hardware_types | join(',') }} {% endif %} @@ -37,6 +44,31 @@ kernel_append_params = {{ kolla_ironic_pxe_append_params | join(' ') }} tftp_server = {{ hostvars[inventory_hostname].ansible_facts[api_interface | replace('-', '_')]['ipv4']['address'] }} {% endraw %} +[auto_discovery] +enabled = {{ kolla_inspector_enable_discovery }} +driver = {{ kolla_inspector_discovery_enroll_node_driver }} + +[inspector] +{% if kolla_inspector_enable_discovery | bool %} +# Under unmanaged inspection we understand in-band inspection where the boot +# configuration (iPXE scripts, DHCP options, etc) is not provided by the Bare +# Metal service. In this case, the node is simply set to boot from network and +# powered on. See: +# https://docs.openstack.org/ironic/latest/admin/inspection/managed.html#unmanaged-inspection +require_managed_boot = False +{% endif %} +{% if kolla_inspector_add_ports %} +add_ports = {{ kolla_inspector_add_ports }} +{% endif %} + +{% if kolla_inspector_keep_ports %} +keep_ports = {{ kolla_inspector_keep_ports }} +{% endif %} + +{% if kolla_inspector_hooks %} +hooks = {{ kolla_inspector_hooks | join(',') }} +{% endif %} + {% if kolla_extra_ironic %} ####################### # Extra configuration diff --git a/ansible/seed-introspection-rules.yml b/ansible/seed-introspection-rules.yml index ca92bdd13..edcb031bf 100644 --- a/ansible/seed-introspection-rules.yml +++ b/ansible/seed-introspection-rules.yml @@ -19,4 +19,4 @@ inspector_rule_var_lldp_switch_port_interface: "{{ kolla_bifrost_inspector_lldp_switch_port_interface }}" inspector_rule_var_deploy_kernel: "{{ kolla_bifrost_inspector_deploy_kernel }}" inspector_rule_var_deploy_ramdisk: "{{ kolla_bifrost_inspector_deploy_ramdisk }}" - when: kolla_enable_bifrost | bool and false # TODO(priteau): Re-enable with built-in inspection + when: kolla_enable_bifrost | bool diff --git a/dev/functions b/dev/functions index 4a627e2a9..907151f10 100644 --- a/dev/functions +++ b/dev/functions @@ -563,9 +563,9 @@ function overcloud_test_init { environment_setup if [[ ! -z "$UPPER_CONSTRAINTS_FILE" ]]; then - pip install python-openstackclient -c "$UPPER_CONSTRAINTS_FILE" + pip install python-openstackclient python-ironicclient -c "$UPPER_CONSTRAINTS_FILE" else - pip install python-openstackclient + pip install python-openstackclient python-ironicclient fi source "${KOLLA_CONFIG_PATH:-/etc/kolla}/admin-openrc.sh" diff --git a/doc/source/configuration/reference/bifrost.rst b/doc/source/configuration/reference/bifrost.rst index 4180dd3da..cbd3e738e 100644 --- a/doc/source/configuration/reference/bifrost.rst +++ b/doc/source/configuration/reference/bifrost.rst @@ -268,9 +268,9 @@ Ironic Inspector configuration The following options configure the Ironic Inspector service in the ``bifrost-deploy`` container. -``kolla_bifrost_inspector_processing_hooks`` +``kolla_bifrost_inspector_hooks`` List of of inspector processing plugins. Default is ``{{ - inspector_processing_hooks }}``, defined in + inspector_hooks }}``, defined in ``${KAYOBE_CONFIG_PATH}/inspector.yml``. ``kolla_bifrost_inspector_port_addition`` Which MAC addresses to add as ports during introspection. One of ``all``, diff --git a/etc/kayobe/bifrost.yml b/etc/kayobe/bifrost.yml index 8c5e9a501..4150e6600 100644 --- a/etc/kayobe/bifrost.yml +++ b/etc/kayobe/bifrost.yml @@ -90,7 +90,7 @@ # Ironic Inspector configuration. # List of of inspector processing plugins. -#kolla_bifrost_inspector_processing_hooks: +#kolla_bifrost_inspector_hooks: # Which MAC addresses to add as ports during introspection. One of 'all', # 'active' or 'pxe'. diff --git a/etc/kayobe/inspector.yml b/etc/kayobe/inspector.yml index 713751dfc..926316b71 100644 --- a/etc/kayobe/inspector.yml +++ b/etc/kayobe/inspector.yml @@ -31,32 +31,40 @@ #inspector_ipa_ramdisk_checksum_algorithm: ############################################################################### -# Ironic inspector processing configuration. +# Ironic inspector processing configuration for the inspector implementation +# built-in to Ironic. -# List of of default inspector processing plugins. -#inspector_processing_hooks_default: +# List of hooks to enable for inspection. Default is [$default_hooks, memory, +# boot-mode, cpu-capabilities, pci-devices, parse-lldp]. +#inspector_hooks_default: -# List of of additional inspector processing plugins. -#inspector_processing_hooks_extra: +# List of extra inspection hooks to enable. Default is an empty list. +#inspector_hooks_extra: -# List of of additional inspector processing plugins. -#inspector_processing_hooks: +# List of of additional inspector hooks to enable. Default is +# {{ inspector_hooks_default + inspector_hooks_extra }}. +#inspector_hooks: + +############################################################################### +# Common Ironic Inspector processing configuration. # Which MAC addresses to add as ports during introspection. One of 'all', -# 'active' or 'pxe'. +# 'active' or 'pxe'. Default is 'pxe'. #inspector_add_ports: # Which ports to keep after introspection. One of 'all', 'present', or 'added'. +# Default is 'added'. #inspector_keep_ports: -# Whether to enable discovery of nodes not managed by Ironic. +# Whether to enable discovery of nodes not managed by Ironic. Default is true. #inspector_enable_discovery: -# The Ironic driver with which to register newly discovered nodes. +# The Ironic driver with which to register newly discovered nodes. Default is +# 'ipmi'. #inspector_discovery_enroll_node_driver: ############################################################################### -# Ironic inspector configuration. +# Ironic inspector introspection rules configuration. # Ironic inspector option to enable IPMI rules. Set to 'True' by default. #inspector_rules_ipmi_enabled: @@ -90,9 +98,6 @@ # Redfish CA setting. Set to 'True' by default #inspector_rule_var_redfish_verify_ca: -############################################################################### -# Ironic inspector introspection rules configuration. - # Ironic inspector rule to set IPMI credentials. #inspector_rule_ipmi_credentials: @@ -102,9 +107,6 @@ # Ironic inspector rule to set deployment ramdisk. #inspector_rule_deploy_ramdisk: -# Ironic inspector rule to initialise root device hints. -#inspector_rule_root_hint_init: - # Ironic inspector rule to set serial root device hint. #inspector_rule_root_hint_serial: diff --git a/playbooks/kayobe-overcloud-base/run.yml b/playbooks/kayobe-overcloud-base/run.yml index cdc3828e2..76ecd8af6 100644 --- a/playbooks/kayobe-overcloud-base/run.yml +++ b/playbooks/kayobe-overcloud-base/run.yml @@ -41,7 +41,6 @@ cmd: dev/overcloud-test-baremetal.sh &> {{ logs_dir }}/ansible/overcloud-test-baremetal chdir: "{{ kayobe_src_dir }}" executable: /bin/bash - when: false # TODO(priteau): Re-enable with built-in inspection - name: Register dummy baremetal compute nodes shell: diff --git a/playbooks/kayobe-overcloud-upgrade-base/run.yml b/playbooks/kayobe-overcloud-upgrade-base/run.yml index 03d5e3e72..820536979 100644 --- a/playbooks/kayobe-overcloud-upgrade-base/run.yml +++ b/playbooks/kayobe-overcloud-upgrade-base/run.yml @@ -109,7 +109,6 @@ cmd: dev/overcloud-test-baremetal.sh &> {{ logs_dir }}/ansible/overcloud-test-bm-post-upgrade chdir: "{{ kayobe_src_dir }}" executable: /bin/bash - when: false # TODO(priteau): Re-enable with built-in inspection environment: KAYOBE_CONFIG_SOURCE_PATH: "{{ kayobe_config_src_dir }}" diff --git a/releasenotes/notes/adds-support-for-configuring-builtin-inspector-04ab4ea4f1a1c3c8.yaml b/releasenotes/notes/adds-support-for-configuring-builtin-inspector-04ab4ea4f1a1c3c8.yaml new file mode 100644 index 000000000..a721182c8 --- /dev/null +++ b/releasenotes/notes/adds-support-for-configuring-builtin-inspector-04ab4ea4f1a1c3c8.yaml @@ -0,0 +1,26 @@ +--- +upgrade: + - | + ``inspector_processing_hooks`` has been removed. A new variable named + ``inspector_hooks`` has been introduced to to replace it since the names of + the hooks differ between standalone and built-in implementations. See + :ironic-doc:`Ironic documentation ` for + more details. + - | + Support for standalone inspector has been removed. All Ironic nodes will + need to be migrated from the ``inspector`` inspect-interface to ``agent``. + It is recommended that you do this after upgrading, but you will need to + ensure that you add ``inspector`` and ``agent`` to + ``kolla_ironic_enabled_inspect_interfaces`` for the upgrade. Check that + ``kolla_ironic_default_inspect_interface`` is not set to ``inspector``. + See :ironic-doc:`Ironic documentation ` for + more details. + - | + The format of inspection rules has changed. Any custom rules will need + to be updated to the new format. See + :ironic-doc:`Ironic documentation ` + for more details. + - | + The format of the data output from ``kayobe baremetal compute introspection + data save`` and ``kayobe overcloud introspection data save`` has changed. + You may need to update any tooling that is using this data. diff --git a/requirements.yml b/requirements.yml index 2490a5bcb..68c92d3a2 100644 --- a/requirements.yml +++ b/requirements.yml @@ -22,7 +22,7 @@ collections: - name: stackhpc.network version: 1.0.0 - name: stackhpc.openstack - version: 0.2.2 + version: 0.6.0 roles: - src: ahuffman.resolv From ee2657d3ba99eb79a682d007013dad9c3b1c8ed3 Mon Sep 17 00:00:00 2001 From: Pierre Riteau Date: Fri, 14 Nov 2025 13:09:16 +0100 Subject: [PATCH 09/10] Fix comment in globals.yml Change-Id: I7611e4798d3dd27f4193f07e02e9e664229fd451 Signed-off-by: Pierre Riteau --- etc/kayobe/globals.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/etc/kayobe/globals.yml b/etc/kayobe/globals.yml index 13f340e57..498b5886b 100644 --- a/etc/kayobe/globals.yml +++ b/etc/kayobe/globals.yml @@ -51,7 +51,6 @@ # OS release. Valid options are "10-stream" when os_distribution is "centos", # "10" when os_distribution is "rocky", or "noble" when os_distribution is # "ubuntu". -# os_distribution is "ubuntu". #os_release: ############################################################################### From 72339426eaa4152d31a4a93de3e604bb9db1d5ef Mon Sep 17 00:00:00 2001 From: Pierre Riteau Date: Fri, 14 Nov 2025 13:32:58 +0100 Subject: [PATCH 10/10] [release] Fix release notes for 2025.2 Change-Id: I74a1a56525ec7d7ae36cca634b425e045dd6a42a Signed-off-by: Pierre Riteau --- ...-args-for-virtual-media-1446188235feaaac.yaml | 16 +++++++--------- .../notes/bug-2121588-ad6d8b33e3fcaff9.yaml | 2 +- ...on-algorithm-to-zstd-19-b3860e0a24ca824e.yaml | 2 +- ...x-baremetal-serial-venv-946b4b7dd191662b.yaml | 4 ++-- ...orking-dir-url-encoding-5f50d66547858e37.yaml | 3 +-- ...onic-inspection-network-6cd3977447492236.yaml | 2 +- ...t-centos-stream-9-image-d23c5a3f5c3a3914.yaml | 5 ----- 7 files changed, 13 insertions(+), 21 deletions(-) delete mode 100644 releasenotes/notes/use-latest-centos-stream-9-image-d23c5a3f5c3a3914.yaml diff --git a/releasenotes/notes/add-redfish-pxe-args-for-virtual-media-1446188235feaaac.yaml b/releasenotes/notes/add-redfish-pxe-args-for-virtual-media-1446188235feaaac.yaml index 24837912e..1f167ece2 100644 --- a/releasenotes/notes/add-redfish-pxe-args-for-virtual-media-1446188235feaaac.yaml +++ b/releasenotes/notes/add-redfish-pxe-args-for-virtual-media-1446188235feaaac.yaml @@ -1,12 +1,10 @@ --- features: - | - Adds support for Redfish virtual media and - PXE boot using a common set of variables. - Migration to using - ``kolla_ironic_kernel_append_params`` is - advised. - New boot variables are: - kolla_ironic_kernel_append_params, - kolla_ironic_kernel_append_params_default, - kolla_ironic_kernel_append_params_extra. + Adds support for Redfish virtual media and PXE boot using a common set of + variables. Migration to using ``kolla_ironic_kernel_append_params`` is + advised. New boot variables are: + + * ``kolla_ironic_kernel_append_params`` + * ``kolla_ironic_kernel_append_params_default`` + * ``kolla_ironic_kernel_append_params_extra`` diff --git a/releasenotes/notes/bug-2121588-ad6d8b33e3fcaff9.yaml b/releasenotes/notes/bug-2121588-ad6d8b33e3fcaff9.yaml index ac5424b7f..ff8b82e06 100644 --- a/releasenotes/notes/bug-2121588-ad6d8b33e3fcaff9.yaml +++ b/releasenotes/notes/bug-2121588-ad6d8b33e3fcaff9.yaml @@ -1,6 +1,6 @@ --- fixes: - | - Fixes CentOS Stream 9 seed and infra VMs not booting by switching to an + Fixes CentOS Stream seed and infra VMs not booting by switching to an EFI-compatible image. `LP#2121588 `__ diff --git a/releasenotes/notes/change-IPA-compression-algorithm-to-zstd-19-b3860e0a24ca824e.yaml b/releasenotes/notes/change-IPA-compression-algorithm-to-zstd-19-b3860e0a24ca824e.yaml index bf4576bb2..1942bd165 100644 --- a/releasenotes/notes/change-IPA-compression-algorithm-to-zstd-19-b3860e0a24ca824e.yaml +++ b/releasenotes/notes/change-IPA-compression-algorithm-to-zstd-19-b3860e0a24ca824e.yaml @@ -11,4 +11,4 @@ upgrade: default ``gzip`` to ``zstd``. The ``ipa_build_dib_env_default`` dictionary now includes ``DIB_IPA_COMPRESS_CMD`` set to ``zstd -19``. The default ``ipa_build_dib_host_packages_extra`` has been changed from - none to ``['zstd']``. \ No newline at end of file + none to ``['zstd']``. diff --git a/releasenotes/notes/fix-baremetal-serial-venv-946b4b7dd191662b.yaml b/releasenotes/notes/fix-baremetal-serial-venv-946b4b7dd191662b.yaml index 71e999ee6..eedc72012 100644 --- a/releasenotes/notes/fix-baremetal-serial-venv-946b4b7dd191662b.yaml +++ b/releasenotes/notes/fix-baremetal-serial-venv-946b4b7dd191662b.yaml @@ -1,5 +1,5 @@ --- fixes: - | - Call virtualenv as a Python module during baremetal compute serial console - setup to fix ``executable not found`` error on Rocky Linux. + Fixes ``executable not found`` errors on Rocky Linux by calling virtualenv + as a Python module during baremetal compute serial console setup. diff --git a/releasenotes/notes/fix-working-dir-url-encoding-5f50d66547858e37.yaml b/releasenotes/notes/fix-working-dir-url-encoding-5f50d66547858e37.yaml index a7ed09bd2..f5a4ebae0 100644 --- a/releasenotes/notes/fix-working-dir-url-encoding-5f50d66547858e37.yaml +++ b/releasenotes/notes/fix-working-dir-url-encoding-5f50d66547858e37.yaml @@ -1,7 +1,6 @@ --- fixes: - | - Fixes a issue where the working directory contains symbols such - as @. + Fixes an issue where the working directory contains symbols such as ``@``. The previous behaviour tries to load files with url encoded symbols. `LP#2129687 `__ diff --git a/releasenotes/notes/kolla-ironic-inspection-network-6cd3977447492236.yaml b/releasenotes/notes/kolla-ironic-inspection-network-6cd3977447492236.yaml index 04187c12f..605d473a8 100644 --- a/releasenotes/notes/kolla-ironic-inspection-network-6cd3977447492236.yaml +++ b/releasenotes/notes/kolla-ironic-inspection-network-6cd3977447492236.yaml @@ -3,4 +3,4 @@ features: - | Adds support for ``kolla_ironic_inspection_network`` which will be created in Neutron for Ironic Inspection purposes (defaults to using provisioning - network for backwards compatibility).. + network for backwards compatibility). diff --git a/releasenotes/notes/use-latest-centos-stream-9-image-d23c5a3f5c3a3914.yaml b/releasenotes/notes/use-latest-centos-stream-9-image-d23c5a3f5c3a3914.yaml deleted file mode 100644 index 82e8b0520..000000000 --- a/releasenotes/notes/use-latest-centos-stream-9-image-d23c5a3f5c3a3914.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -upgrade: - - | - Updates the default cloud image for CentOS Stream 9 deployments to use - ``CentOS-Stream-GenericCloud-9-latest.x86_64.qcow2``.