From c52058c882b4de3b3d8c025ed0ac83a50f4343eb Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Tue, 25 Aug 2026 16:33:59 +0100 Subject: [PATCH 01/19] Tolerate missing image IDs when updating deployment images We want the image IDs to be set when they are unset instead of erroring with missing dictionary key. Closes-Bug: #2165045 Change-Id: I07ea72bbc17b6a86a0f9eee138640f22409d5205 Signed-off-by: Will Szumski --- ansible/roles/ipa-images/tasks/set-driver-info.yml | 4 ++-- .../notes/tolerate-missing-image-ids-2a6a46b7cb74fca5.yaml | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 releasenotes/notes/tolerate-missing-image-ids-2a6a46b7cb74fca5.yaml diff --git a/ansible/roles/ipa-images/tasks/set-driver-info.yml b/ansible/roles/ipa-images/tasks/set-driver-info.yml index 6ddcbc89e..b416438f3 100644 --- a/ansible/roles/ipa-images/tasks/set-driver-info.yml +++ b/ansible/roles/ipa-images/tasks/set-driver-info.yml @@ -64,6 +64,6 @@ --driver-info deploy_ramdisk={{ ipa_images_ramdisk_uuid }} with_items: "{{ ipa_images_ironic_nodes }}" when: - item["driver_info"].deploy_kernel != ipa_images_kernel_uuid or - item["driver_info"].deploy_ramdisk != ipa_images_ramdisk_uuid + item["driver_info"].deploy_kernel | default("UNSET") != ipa_images_kernel_uuid or + item["driver_info"].deploy_ramdisk | default("UNSET") != ipa_images_ramdisk_uuid environment: "{{ ipa_images_ironic_openstack_auth_env }}" diff --git a/releasenotes/notes/tolerate-missing-image-ids-2a6a46b7cb74fca5.yaml b/releasenotes/notes/tolerate-missing-image-ids-2a6a46b7cb74fca5.yaml new file mode 100644 index 000000000..793b25e1b --- /dev/null +++ b/releasenotes/notes/tolerate-missing-image-ids-2a6a46b7cb74fca5.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Fixes deployment image updates failing when an Ironic node is missing + deployment image IDs. `LP#2165045 + `__ From a4b8f9d75089663e943fe957da1cf79c42110534 Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Fri, 3 Jul 2026 09:45:51 +0100 Subject: [PATCH 02/19] Update Docker storage driver default Set docker_storage_driver to use an undefined default in inventory so Docker runtime behavior is used unless explicitly overridden. Update container engine reference docs and example config comments to describe the runtime-default storage driver behavior, while keeping docker as the default container engine. Add an upgrade release note covering fresh-install vs upgraded-install behavior and the containerd image store transition. Change-Id: If6aa1edd520c8e6c224b00b8c537b0456316c55a Signed-off-by: Will Szumski --- .../inventory/group_vars/all/container-engine | 5 +++-- doc/source/configuration/reference/hosts.rst | 7 ++++--- etc/kayobe/container-engine.yml | 3 ++- ...-driver-runtime-default-271e86e7162984cb.yaml | 13 +++++++++++++ .../tests/test_host_configure.py | 16 +++++++++++++--- 5 files changed, 35 insertions(+), 9 deletions(-) create mode 100644 releasenotes/notes/docker-storage-driver-runtime-default-271e86e7162984cb.yaml diff --git a/ansible/inventory/group_vars/all/container-engine b/ansible/inventory/group_vars/all/container-engine index 29f7b3106..4e4982bdf 100644 --- a/ansible/inventory/group_vars/all/container-engine +++ b/ansible/inventory/group_vars/all/container-engine @@ -12,8 +12,9 @@ container_engine_volumes_path: "{{ podman_volumes_path if container_engine == 'p ############################################################################### # Docker configuration. -# Name of the docker storage driver. Default is 'overlay2'. -docker_storage_driver: overlay2 +# Name of the docker storage driver. Default is "", which defers to the +# Docker runtime default. +docker_storage_driver: "" # URL of docker registry docker_registry: diff --git a/doc/source/configuration/reference/hosts.rst b/doc/source/configuration/reference/hosts.rst index 292934d9e..02364e142 100644 --- a/doc/source/configuration/reference/hosts.rst +++ b/doc/source/configuration/reference/hosts.rst @@ -1253,9 +1253,10 @@ insecure (HTTP) registry, set ``podman_registry_insecure`` to ``true``. Docker ------ -The ``docker_storage_driver`` variable sets the Docker storage driver, and by -default the ``overlay2`` driver is used. See :ref:`configuration-hosts-lvm` for -information about configuring LVM for Docker. +The ``docker_storage_driver`` variable sets the Docker storage driver. By +default it is unset, which defers to Docker's runtime default. See +:ref:`configuration-hosts-lvm` for information about configuring LVM for +Docker. If using an insecure (HTTP) registry, set ``docker_registry_insecure`` to ``true``. diff --git a/etc/kayobe/container-engine.yml b/etc/kayobe/container-engine.yml index 48ea969b3..ffe1d4943 100644 --- a/etc/kayobe/container-engine.yml +++ b/etc/kayobe/container-engine.yml @@ -12,7 +12,8 @@ ############################################################################### # Docker configuration. -# Name of the docker storage driver. Default is 'overlay2'. +# Name of the docker storage driver. Default is "", which defers to the +# Docker runtime default. #docker_storage_driver: # URL of docker registry diff --git a/releasenotes/notes/docker-storage-driver-runtime-default-271e86e7162984cb.yaml b/releasenotes/notes/docker-storage-driver-runtime-default-271e86e7162984cb.yaml new file mode 100644 index 000000000..814b32299 --- /dev/null +++ b/releasenotes/notes/docker-storage-driver-runtime-default-271e86e7162984cb.yaml @@ -0,0 +1,13 @@ +--- +upgrade: + - | + ``docker_storage_driver`` is now unset by default, which defers to the + Docker runtime default storage backend. + + On fresh installations of Docker Engine 29.0 and later, Docker uses the + containerd image store by default. On existing installations upgraded from + earlier Docker versions, Docker continues using the legacy graph drivers + (including ``overlay2``) until the containerd image store is explicitly + enabled. See the Docker `containerd image store + `__ documentation for + details. diff --git a/roles/host-configure-test-harness/tests/test_host_configure.py b/roles/host-configure-test-harness/tests/test_host_configure.py index 5c03a28cd..a5f7a1be0 100644 --- a/roles/host-configure-test-harness/tests/test_host_configure.py +++ b/roles/host-configure-test-harness/tests/test_host_configure.py @@ -190,10 +190,20 @@ def test_cloud_init_is_disabled(host): assert host.file("/etc/cloud/cloud-init.disabled").exists -def test_docker_storage_driver_is_overlay2(host): +def test_docker_storage_driver_is_configured(host): with host.sudo("stack"): - info = host.check_output("docker info") - assert "overlay2" in info + driver_status_json = host.check_output( + "docker info --format '{{json .DriverStatus}}'") + + driver_status = json.loads(driver_status_json) + status_map = { + entry[0]: entry[1] + for entry in driver_status + if isinstance(entry, list) and len(entry) == 2 + } + + driver_type = status_map.get("driver-type", "") + assert driver_type.startswith("io.containerd.snapshotter.") @pytest.mark.parametrize('user', ['kolla', 'stack']) From 1aec029a29dfbd813e25fcc354a520e622cef237 Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Mon, 21 Sep 2026 16:51:51 +0000 Subject: [PATCH 03/19] Skip etc-hosts fixup on hosts not mapped to kolla The overcloud-etc-hosts-fixup playbook ran against all overcloud hosts unconditionally, including those not mapped through to the generated kolla-ansible inventory. This caused it to fail during overcloud host upgrade on such hosts. Skip the tasks on hosts that are not in the kolla_mapped_overcloud_host_True dynamic group, computed the same way as in kolla-ansible.yml. Since this playbook can run standalone via overcloud-host-upgrade.yml without kolla-ansible.yml having run first, the group_by task that creates the group is duplicated here. Closes-Bug: #2167869 Co-Authored-By: Claude Sonnet 5 Change-Id: Ie52edc45f6968dbba41dbc0c93f228994b48bef8 Signed-off-by: Will Szumski --- ansible/overcloud-etc-hosts-fixup.yml | 15 +++++++++++++-- ...ts-fixup-non-kolla-hosts-c42c9b50067d5155.yaml | 9 +++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 releasenotes/notes/fix-etc-hosts-fixup-non-kolla-hosts-c42c9b50067d5155.yaml diff --git a/ansible/overcloud-etc-hosts-fixup.yml b/ansible/overcloud-etc-hosts-fixup.yml index aed231139..6c10a69fe 100644 --- a/ansible/overcloud-etc-hosts-fixup.yml +++ b/ansible/overcloud-etc-hosts-fixup.yml @@ -7,8 +7,19 @@ # which it is listening. As a workaround, we remove the stale entries from # /etc/hosts. See https://github.com/stackhpc/kayobe/issues/14. -- name: Ensure overcloud hosts' /etc/hosts does not contain incorrect IPs +- name: Collect hosts to map through to kolla-ansible hosts: overcloud + gather_facts: false + tags: + - etc-hosts-fixup + tasks: + - name: Group by kolla_overcloud_inventory_pass_through_enabled + ansible.builtin.group_by: + key: "kolla_mapped_overcloud_host_{{ kolla_overcloud_inventory_pass_through_enabled }}" + changed_when: false + +- name: Ensure overcloud hosts' /etc/hosts does not contain incorrect IPs + hosts: kolla_mapped_overcloud_host_True max_fail_percentage: >- {{ overcloud_etc_hosts_fixup_max_fail_percentage | default(kayobe_max_fail_percentage) | @@ -28,7 +39,7 @@ become: True - name: Ensure rabbitmq containers' /etc/hosts does not contain incorrect IPs - hosts: overcloud + hosts: kolla_mapped_overcloud_host_True max_fail_percentage: >- {{ overcloud_etc_hosts_fixup_max_fail_percentage | default(kayobe_max_fail_percentage) | diff --git a/releasenotes/notes/fix-etc-hosts-fixup-non-kolla-hosts-c42c9b50067d5155.yaml b/releasenotes/notes/fix-etc-hosts-fixup-non-kolla-hosts-c42c9b50067d5155.yaml new file mode 100644 index 000000000..e31ea7f49 --- /dev/null +++ b/releasenotes/notes/fix-etc-hosts-fixup-non-kolla-hosts-c42c9b50067d5155.yaml @@ -0,0 +1,9 @@ +--- +fixes: + - | + Fixes a bug where ``ansible/overcloud-etc-hosts-fixup.yml``, run as part + of ``kayobe overcloud host upgrade``, attempted to run on all overcloud + hosts, including those that are not mapped through to the generated + kolla-ansible inventory. It is now skipped on hosts that are not mapped + through to kolla-ansible. + `LP#2167869 `__ From 0d2d7c85be37468a0cf9358be4fbe78231ad34bf Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Mon, 21 Sep 2026 16:44:30 +0000 Subject: [PATCH 04/19] Respect custom ansible.cfg for Galaxy installs Kayobe installs its Galaxy role and collection dependencies by invoking ansible-galaxy directly. These subprocesses did not have ANSIBLE_CONFIG set, so a custom ansible.cfg in the Kayobe configuration path was ignored. In particular, a custom Galaxy server list (server_list) was not used and the default public Galaxy server was contacted instead. Set ANSIBLE_CONFIG for the ansible-galaxy invocations when a custom ansible.cfg exists in the configuration path. This matches the behaviour of ansible-playbook runs. Generated-By: opencode deepseek-v4-pro Change-Id: Ia9d7282e28509eadf41efeff534a179bedc64e57 Signed-off-by: Will Szumski --- kayobe/ansible.py | 30 +++- kayobe/tests/unit/test_ansible.py | 133 +++++++++++++----- kayobe/tests/unit/test_utils.py | 31 +++- kayobe/utils.py | 27 +++- ...laxy-use-ansible-cfg-d34b1f4c3e1a2b7c.yaml | 9 ++ 5 files changed, 186 insertions(+), 44 deletions(-) create mode 100644 releasenotes/notes/galaxy-use-ansible-cfg-d34b1f4c3e1a2b7c.yaml diff --git a/kayobe/ansible.py b/kayobe/ansible.py index 406076a47..bc411c35b 100644 --- a/kayobe/ansible.py +++ b/kayobe/ansible.py @@ -634,6 +634,24 @@ def config_dump(parsed_args, host=None, hosts=None, var_name=None, shutil.rmtree(dump_dir) +def _get_galaxy_environment(parsed_args): + """Return an environment dict for running ansible-galaxy commands. + + This ensures that a custom Ansible configuration file in the Kayobe + configuration path, if present, is used by ansible-galaxy. Without this, + galaxy server configuration such as a custom server list would be ignored + when installing roles and collections. + + :param parsed_args: Parsed command line arguments. + """ + env = os.environ.copy() + # If a custom Ansible configuration file exists, use it. + ansible_cfg_path = os.path.join(parsed_args.config_path, "ansible.cfg") + if utils.is_readable_file(ansible_cfg_path)["result"]: + env.setdefault("ANSIBLE_CONFIG", ansible_cfg_path) + return env + + def install_galaxy_roles(parsed_args, force=False): """Install Ansible Galaxy role dependencies. @@ -643,10 +661,12 @@ def install_galaxy_roles(parsed_args, force=False): :param parsed_args: Parsed command line arguments. :param force: Whether to force reinstallation of roles. """ + env = _get_galaxy_environment(parsed_args) LOG.info("Installing galaxy role dependencies from kayobe") requirements = utils.get_data_files_path("requirements.yml") roles_destination = utils.get_data_files_path('ansible', 'roles') - utils.galaxy_role_install(requirements, roles_destination, force=force) + utils.galaxy_role_install(requirements, roles_destination, force=force, + env=env) # Check for requirements in kayobe configuration. kc_reqs_path = os.path.join(parsed_args.config_path, @@ -669,7 +689,8 @@ def install_galaxy_roles(parsed_args, force=False): (parsed_args.config_path, str(e))) # Install roles from kayobe-config. - utils.galaxy_role_install(kc_reqs_path, kc_roles_path, force=force) + utils.galaxy_role_install(kc_reqs_path, kc_roles_path, force=force, + env=env) def install_galaxy_collections(parsed_args, force=False): @@ -681,12 +702,13 @@ def install_galaxy_collections(parsed_args, force=False): :param parsed_args: Parsed command line arguments. :param force: Whether to force reinstallation of roles. """ + env = _get_galaxy_environment(parsed_args) LOG.info("Installing galaxy collection dependencies from kayobe") requirements = utils.get_data_files_path("requirements.yml") collections_destination = utils.get_data_files_path('ansible', 'collections') utils.galaxy_collection_install(requirements, collections_destination, - force=force) + force=force, env=env) # Check for requirements in kayobe configuration. kc_reqs_path = os.path.join(parsed_args.config_path, @@ -711,7 +733,7 @@ def install_galaxy_collections(parsed_args, force=False): # Install collections from kayobe-config. utils.galaxy_collection_install(kc_reqs_path, kc_collections_path, - force=force) + force=force, env=env) def prune_galaxy_roles(parsed_args): diff --git a/kayobe/tests/unit/test_ansible.py b/kayobe/tests/unit/test_ansible.py index 9e7500b86..198f85fad 100644 --- a/kayobe/tests/unit/test_ansible.py +++ b/kayobe/tests/unit/test_ansible.py @@ -837,6 +837,47 @@ def test_config_dump_vaulted(self, mock_mkdtemp, mock_run, mock_listdir, mock.call(os.path.join(dump_dir, "host2.yml")), ]) + @mock.patch.object(utils, 'is_readable_file', autospec=True) + def test_get_galaxy_environment_ansible_cfg(self, mock_is_readable): + parser = argparse.ArgumentParser() + ansible.add_args(parser) + parsed_args = parser.parse_args([]) + mock_is_readable.return_value = {"result": True} + + with mock.patch.dict(os.environ, {}, clear=True): + env = ansible._get_galaxy_environment(parsed_args) + + self.assertEqual(env["ANSIBLE_CONFIG"], "/etc/kayobe/ansible.cfg") + mock_is_readable.assert_called_once_with("/etc/kayobe/ansible.cfg") + + @mock.patch.object(utils, 'is_readable_file', autospec=True) + def test_get_galaxy_environment_no_ansible_cfg(self, mock_is_readable): + parser = argparse.ArgumentParser() + ansible.add_args(parser) + parsed_args = parser.parse_args([]) + mock_is_readable.return_value = {"result": False} + + with mock.patch.dict(os.environ, {}, clear=True): + env = ansible._get_galaxy_environment(parsed_args) + + self.assertNotIn("ANSIBLE_CONFIG", env) + mock_is_readable.assert_called_once_with("/etc/kayobe/ansible.cfg") + + @mock.patch.object(utils, 'is_readable_file', autospec=True) + def test_get_galaxy_environment_existing_ansible_cfg( + self, mock_is_readable): + parser = argparse.ArgumentParser() + ansible.add_args(parser) + parsed_args = parser.parse_args([]) + mock_is_readable.return_value = {"result": True} + + with mock.patch.dict( + os.environ, {"ANSIBLE_CONFIG": "/path/to/ansible.cfg"}): + env = ansible._get_galaxy_environment(parsed_args) + + self.assertEqual(env["ANSIBLE_CONFIG"], "/path/to/ansible.cfg") + mock_is_readable.assert_called_once_with("/etc/kayobe/ansible.cfg") + @mock.patch.object(utils, 'galaxy_role_install', autospec=True) @mock.patch.object(utils, 'is_readable_file', autospec=True) @mock.patch.object(os, 'makedirs', autospec=True) @@ -849,11 +890,14 @@ def test_install_galaxy_roles(self, mock_mkdirs, mock_is_readable, ansible.install_galaxy_roles(parsed_args) - mock_install.assert_called_once_with(utils.get_data_files_path( - "requirements.yml"), utils.get_data_files_path( - "ansible", "roles"), force=False) - mock_is_readable.assert_called_once_with( - "/etc/kayobe/ansible/requirements.yml") + mock_install.assert_called_once_with( + utils.get_data_files_path("requirements.yml"), + utils.get_data_files_path("ansible", "roles"), + force=False, env=mock.ANY) + mock_is_readable.assert_has_calls([ + mock.call("/etc/kayobe/ansible.cfg"), + mock.call("/etc/kayobe/ansible/requirements.yml"), + ]) self.assertFalse(mock_mkdirs.called) @mock.patch.object(utils, 'galaxy_role_install', autospec=True) @@ -871,12 +915,15 @@ def test_install_galaxy_roles_with_kayobe_config( expected_calls = [ mock.call(utils.get_data_files_path("requirements.yml"), utils.get_data_files_path("ansible", "roles"), - force=False), + force=False, env=mock.ANY), mock.call("/etc/kayobe/ansible/requirements.yml", - "/etc/kayobe/ansible/roles", force=False)] + "/etc/kayobe/ansible/roles", + force=False, env=mock.ANY)] self.assertListEqual(expected_calls, mock_install.call_args_list) - mock_is_readable.assert_called_once_with( - "/etc/kayobe/ansible/requirements.yml") + mock_is_readable.assert_has_calls([ + mock.call("/etc/kayobe/ansible.cfg"), + mock.call("/etc/kayobe/ansible/requirements.yml"), + ]) mock_mkdirs.assert_called_once_with("/etc/kayobe/ansible/roles") @mock.patch.object(utils, 'galaxy_role_install', autospec=True) @@ -894,12 +941,15 @@ def test_install_galaxy_roles_with_kayobe_config_forced( expected_calls = [ mock.call(utils.get_data_files_path("requirements.yml"), utils.get_data_files_path("ansible", "roles"), - force=True), + force=True, env=mock.ANY), mock.call("/etc/kayobe/ansible/requirements.yml", - "/etc/kayobe/ansible/roles", force=True)] + "/etc/kayobe/ansible/roles", + force=True, env=mock.ANY)] self.assertListEqual(expected_calls, mock_install.call_args_list) - mock_is_readable.assert_called_once_with( - "/etc/kayobe/ansible/requirements.yml") + mock_is_readable.assert_has_calls([ + mock.call("/etc/kayobe/ansible.cfg"), + mock.call("/etc/kayobe/ansible/requirements.yml"), + ]) mock_mkdirs.assert_called_once_with("/etc/kayobe/ansible/roles") @mock.patch.object(utils, 'galaxy_role_install', autospec=True) @@ -916,11 +966,14 @@ def test_install_galaxy_roles_with_kayobe_config_mkdirs_failure( self.assertRaises(exception.Error, ansible.install_galaxy_roles, parsed_args) - mock_install.assert_called_once_with(utils.get_data_files_path( - "requirements.yml"), utils.get_data_files_path("ansible", "roles"), - force=False) - mock_is_readable.assert_called_once_with( - "/etc/kayobe/ansible/requirements.yml") + mock_install.assert_called_once_with( + utils.get_data_files_path("requirements.yml"), + utils.get_data_files_path("ansible", "roles"), + force=False, env=mock.ANY) + mock_is_readable.assert_has_calls([ + mock.call("/etc/kayobe/ansible.cfg"), + mock.call("/etc/kayobe/ansible/requirements.yml"), + ]) mock_mkdirs.assert_called_once_with("/etc/kayobe/ansible/roles") @mock.patch.object(utils, 'galaxy_collection_install', autospec=True) @@ -935,11 +988,14 @@ def test_install_galaxy_collections(self, mock_mkdirs, mock_is_readable, ansible.install_galaxy_collections(parsed_args) - mock_install.assert_called_once_with(utils.get_data_files_path( - "requirements.yml"), utils.get_data_files_path( - "ansible", "collections"), force=False) - mock_is_readable.assert_called_once_with( - "/etc/kayobe/ansible/requirements.yml") + mock_install.assert_called_once_with( + utils.get_data_files_path("requirements.yml"), + utils.get_data_files_path("ansible", "collections"), + force=False, env=mock.ANY) + mock_is_readable.assert_has_calls([ + mock.call("/etc/kayobe/ansible.cfg"), + mock.call("/etc/kayobe/ansible/requirements.yml"), + ]) self.assertFalse(mock_mkdirs.called) @mock.patch.object(utils, 'galaxy_collection_install', autospec=True) @@ -957,12 +1013,15 @@ def test_install_galaxy_collections_with_kayobe_config( expected_calls = [ mock.call(utils.get_data_files_path("requirements.yml"), utils.get_data_files_path("ansible", "collections"), - force=False), + force=False, env=mock.ANY), mock.call("/etc/kayobe/ansible/requirements.yml", - "/etc/kayobe/ansible/collections", force=False)] + "/etc/kayobe/ansible/collections", + force=False, env=mock.ANY)] self.assertListEqual(expected_calls, mock_install.call_args_list) - mock_is_readable.assert_called_once_with( - "/etc/kayobe/ansible/requirements.yml") + mock_is_readable.assert_has_calls([ + mock.call("/etc/kayobe/ansible.cfg"), + mock.call("/etc/kayobe/ansible/requirements.yml"), + ]) mock_mkdirs.assert_called_once_with("/etc/kayobe/ansible/collections") @mock.patch.object(utils, 'galaxy_collection_install', autospec=True) @@ -980,12 +1039,15 @@ def test_install_galaxy_collections_with_kayobe_config_forced( expected_calls = [ mock.call(utils.get_data_files_path("requirements.yml"), utils.get_data_files_path("ansible", "collections"), - force=True), + force=True, env=mock.ANY), mock.call("/etc/kayobe/ansible/requirements.yml", - "/etc/kayobe/ansible/collections", force=True)] + "/etc/kayobe/ansible/collections", + force=True, env=mock.ANY)] self.assertListEqual(expected_calls, mock_install.call_args_list) - mock_is_readable.assert_called_once_with( - "/etc/kayobe/ansible/requirements.yml") + mock_is_readable.assert_has_calls([ + mock.call("/etc/kayobe/ansible.cfg"), + mock.call("/etc/kayobe/ansible/requirements.yml"), + ]) mock_mkdirs.assert_called_once_with("/etc/kayobe/ansible/collections") @mock.patch.object(utils, 'galaxy_collection_install', autospec=True) @@ -1004,9 +1066,12 @@ def test_install_galaxy_collections_with_kayobe_config_mkdirs_failure( mock_install.assert_called_once_with( utils.get_data_files_path("requirements.yml"), - utils.get_data_files_path("ansible", "collections"), force=False) - mock_is_readable.assert_called_once_with( - "/etc/kayobe/ansible/requirements.yml") + utils.get_data_files_path("ansible", "collections"), + force=False, env=mock.ANY) + mock_is_readable.assert_has_calls([ + mock.call("/etc/kayobe/ansible.cfg"), + mock.call("/etc/kayobe/ansible/requirements.yml"), + ]) mock_mkdirs.assert_called_once_with("/etc/kayobe/ansible/collections") @mock.patch.object(utils, 'galaxy_remove', autospec=True) diff --git a/kayobe/tests/unit/test_utils.py b/kayobe/tests/unit/test_utils.py index 736678e9f..fc9abc871 100644 --- a/kayobe/tests/unit/test_utils.py +++ b/kayobe/tests/unit/test_utils.py @@ -34,7 +34,18 @@ def test_galaxy_role_install(self, mock_run): utils.galaxy_role_install("/path/to/role/file", "/path/to/roles") mock_run.assert_called_once_with(["ansible-galaxy", "role", "install", "--roles-path", "/path/to/roles", - "--role-file", "/path/to/role/file"]) + "--role-file", "/path/to/role/file"], + env=None) + + @mock.patch.object(utils, "run_command") + def test_galaxy_role_install_env(self, mock_run): + env = {"ANSIBLE_CONFIG": "/etc/kayobe/ansible.cfg"} + utils.galaxy_role_install("/path/to/role/file", "/path/to/roles", + env=env) + mock_run.assert_called_once_with(["ansible-galaxy", "role", "install", + "--roles-path", "/path/to/roles", + "--role-file", "/path/to/role/file"], + env=env) @mock.patch.object(utils, "run_command") def test_galaxy_role_install_failure(self, mock_run): @@ -57,6 +68,24 @@ def test_galaxy_collection_install(self, mock_read, mock_run): "/path/to/collection/file"], env=env) + @mock.patch.object(utils, "run_command") + @mock.patch.object(utils, "read_yaml_file") + def test_galaxy_collection_install_env(self, mock_read, mock_run): + mock_read.return_value = {"collections": []} + env = {"ANSIBLE_CONFIG": "/etc/kayobe/ansible.cfg"} + utils.galaxy_collection_install("/path/to/collection/file", + "/path/to/collections", env=env) + expected_env = { + 'ANSIBLE_COLLECTIONS_SCAN_SYS_PATH': 'False', + 'ANSIBLE_CONFIG': '/etc/kayobe/ansible.cfg', + } + mock_run.assert_called_once_with(["ansible-galaxy", "collection", + "install", "--collections-path", + "/path/to/collections", + "--requirements-file", + "/path/to/collection/file"], + env=expected_env) + @mock.patch.object(utils, "run_command") @mock.patch.object(utils, "read_yaml_file") def test_galaxy_collection_install_failure(self, mock_read, mock_run): diff --git a/kayobe/utils.py b/kayobe/utils.py index 14cbf6637..248851658 100644 --- a/kayobe/utils.py +++ b/kayobe/utils.py @@ -102,15 +102,22 @@ def _get_base_path(): return os.path.join(os.path.dirname(os.path.realpath(__file__)), "..") -def galaxy_role_install(role_file, roles_path, force=False): - """Install Ansible roles via Ansible Galaxy.""" +def galaxy_role_install(role_file, roles_path, force=False, env=None): + """Install Ansible roles via Ansible Galaxy. + + :param role_file: Path to a file containing role requirements. + :param roles_path: Path to a directory in which to install roles. + :param force: Whether to force reinstallation of roles. + :param env: Optional environment dict to use when invoking + ansible-galaxy. If None, the current environment is inherited. + """ cmd = ["ansible-galaxy", "role", "install"] cmd += ["--roles-path", roles_path] cmd += ["--role-file", role_file] if force: cmd += ["--force"] try: - run_command(cmd) + run_command(cmd, env=env) except subprocess.CalledProcessError as e: LOG.error("Failed to install Ansible roles from %s via Ansible " "Galaxy: returncode %d", role_file, e.returncode) @@ -118,7 +125,17 @@ def galaxy_role_install(role_file, roles_path, force=False): def galaxy_collection_install(requirements_file, collections_path, - force=False): + force=False, env=None): + """Install Ansible collections via Ansible Galaxy. + + :param requirements_file: Path to a file containing collection + requirements. + :param collections_path: Path to a directory in which to install + collections. + :param force: Whether to force reinstallation of collections. + :param env: Optional environment dict to use when invoking + ansible-galaxy. If None, the current environment is inherited. + """ requirements = read_yaml_file(requirements_file) if not isinstance(requirements, dict): # Handle legacy role list format, which causes the command to fail. @@ -131,7 +148,7 @@ def galaxy_collection_install(requirements_file, collections_path, # kayobe requirements.yml. "ANSIBLE_COLLECTIONS_SCAN_SYS_PATH": "False", } - env = env_defaults | os.environ + env = env_defaults | (env if env is not None else os.environ) if force: cmd += ["--force"] try: diff --git a/releasenotes/notes/galaxy-use-ansible-cfg-d34b1f4c3e1a2b7c.yaml b/releasenotes/notes/galaxy-use-ansible-cfg-d34b1f4c3e1a2b7c.yaml new file mode 100644 index 000000000..64997535a --- /dev/null +++ b/releasenotes/notes/galaxy-use-ansible-cfg-d34b1f4c3e1a2b7c.yaml @@ -0,0 +1,9 @@ +--- +fixes: + - | + Fixes installation of Ansible roles and collections during ``kayobe + control host bootstrap`` to respect a custom ``ansible.cfg`` in the Kayobe + configuration path. Previously the ``ansible-galaxy`` commands were run + without ``ANSIBLE_CONFIG`` set, so configuration such as a custom Galaxy + server list (``server_list``) was ignored and the default public Galaxy + server was used instead. From 14da58dbae82e37742b7bb2d34667b80e76e2fe9 Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Tue, 22 Sep 2026 08:51:59 +0000 Subject: [PATCH 05/19] Set ANSIBLE_CONFIG for kolla-ansible collections The kolla-ansible role installs its Ansible collection dependencies by invoking ansible-galaxy directly. These subprocesses did not reliably pick up a custom ansible.cfg from the parent ansible-playbook, because Ansible runs tasks with the working directory set to the playbook directory, where the custom ansible.cfg is not discoverable. As a result, a custom Galaxy server list (server_list) was ignored and the default public Galaxy server was contacted instead. Set ANSIBLE_CONFIG explicitly for these tasks, preferring the Kolla Ansible ansible.cfg ($KAYOBE_CONFIG_PATH/kolla/ansible.cfg), falling back to the Kayobe ansible.cfg ($KAYOBE_CONFIG_PATH/ansible.cfg), and finally to the existing ANSIBLE_CONFIG environment variable. Generated-By: opencode deepseek-v4-pro Change-Id: I17b5731a96f1932208d5c30d47de0d3612ea3164 Signed-off-by: Will Szumski --- ansible/roles/kolla-ansible/defaults/main.yml | 11 +++++++++++ ansible/roles/kolla-ansible/tasks/install.yml | 11 +++++++++++ ...-collections-use-ansible-cfg-6c1ba8a6e480fc8f.yaml | 9 +++++++++ 3 files changed, 31 insertions(+) create mode 100644 releasenotes/notes/kolla-ansible-collections-use-ansible-cfg-6c1ba8a6e480fc8f.yaml diff --git a/ansible/roles/kolla-ansible/defaults/main.yml b/ansible/roles/kolla-ansible/defaults/main.yml index ad5b08b89..c9adef0f4 100644 --- a/ansible/roles/kolla-ansible/defaults/main.yml +++ b/ansible/roles/kolla-ansible/defaults/main.yml @@ -39,6 +39,17 @@ kolla_ansible_core_requirements_yml: "{{ kolla_ansible_venv }}/share/kolla-ansib # If None, custom collections are not installed. kolla_ansible_custom_requirements_paths: +# Path to the Ansible configuration file used when installing Ansible +# collections for Kolla Ansible. Kayobe supports a Kolla Ansible-specific +# configuration file at $KAYOBE_CONFIG_PATH/kolla/ansible.cfg, falling back +# to $KAYOBE_CONFIG_PATH/ansible.cfg. If neither exists, the value of the +# ANSIBLE_CONFIG environment variable is used. +kolla_ansible_ansible_config: >- + {%- set config_path = kayobe_config_path | default('/etc/kayobe') -%} + {%- set kolla_config = config_path ~ '/kolla/ansible.cfg' -%} + {%- set kayobe_config = config_path ~ '/ansible.cfg' -%} + {{ kolla_config if kolla_config is file else (kayobe_config if kayobe_config is file else lookup('env', 'ANSIBLE_CONFIG')) }} + # Virtualenv directory where Kolla-ansible's ansible modules will execute # remotely on the target nodes. If None, no virtualenv will be used. kolla_ansible_target_venv: diff --git a/ansible/roles/kolla-ansible/tasks/install.yml b/ansible/roles/kolla-ansible/tasks/install.yml index a271b7bf4..4411b975b 100644 --- a/ansible/roles/kolla-ansible/tasks/install.yml +++ b/ansible/roles/kolla-ansible/tasks/install.yml @@ -128,6 +128,11 @@ ANSIBLE_COLLECTIONS_SCAN_SYS_PATH: "False" # NOTE(wszumski): Don't use path configured for kayobe ANSIBLE_COLLECTIONS_PATH: '' + # NOTE(wszumski): Set the Ansible configuration file explicitly. The + # ansible-galaxy subprocess does not reliably pick up a custom Galaxy + # server list otherwise, since it is run from a different working + # directory to the parent ansible-playbook. + ANSIBLE_CONFIG: "{{ kolla_ansible_ansible_config }}" when: not kolla_ansible_venv_ansible - name: Ensure Ansible collections are installed @@ -142,6 +147,9 @@ ANSIBLE_COLLECTIONS_SCAN_SYS_PATH: "False" # NOTE(wszumski): Don't use path configured for kayobe ANSIBLE_COLLECTIONS_PATH: '' + # NOTE(wszumski): Set the Ansible configuration file explicitly. See the + # comment on the core collections task above. + ANSIBLE_CONFIG: "{{ kolla_ansible_ansible_config }}" - name: Check for custom Ansible collections requirements files stat: @@ -165,6 +173,9 @@ ANSIBLE_COLLECTIONS_SCAN_SYS_PATH: "False" # NOTE(wszumski): Don't use path configured for kayobe ANSIBLE_COLLECTIONS_PATH: '' + # NOTE(wszumski): Set the Ansible configuration file explicitly. See the + # comment on the core collections task above. + ANSIBLE_CONFIG: "{{ kolla_ansible_ansible_config }}" when: - kolla_ansible_custom_requirements_paths is not none - item.stat.exists diff --git a/releasenotes/notes/kolla-ansible-collections-use-ansible-cfg-6c1ba8a6e480fc8f.yaml b/releasenotes/notes/kolla-ansible-collections-use-ansible-cfg-6c1ba8a6e480fc8f.yaml new file mode 100644 index 000000000..5ab7cf4dc --- /dev/null +++ b/releasenotes/notes/kolla-ansible-collections-use-ansible-cfg-6c1ba8a6e480fc8f.yaml @@ -0,0 +1,9 @@ +--- +fixes: + - | + Fixes installation of Kolla Ansible collection dependencies during + ``kayobe control host bootstrap`` to respect a custom ``ansible.cfg`` in + the Kayobe configuration path. Previously the ``ansible-galaxy`` commands + run by the ``kolla-ansible`` role did not set ``ANSIBLE_CONFIG``, so + configuration such as a custom Galaxy server list (``server_list``) was + ignored and the default public Galaxy server was used instead. From f2e9cfc1b63455bf966ea7a234c177e763bf0e2b Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Mon, 21 Sep 2026 15:46:45 +0000 Subject: [PATCH 06/19] CI: Use OpenDev Galaxy mirror Prefer the site's OpenDev Ansible Galaxy mirror in CI, falling back to the public Galaxy server. This speeds up and stabilises role and collection installs in CI. Select the mirror using the zuul_site_mirror_fqdn variable. The tox jobs render a CI-only ansible.cfg from a template in a pre-run playbook and point ANSIBLE_CONFIG at it. It is deliberately not named ansible.cfg so that it is not auto-discovered by Ansible when running tox locally. The CI-injected ansible.cfg used by the deployment jobs is updated too. Generated-By: opencode deepseek-v4-pro Change-Id: I4c91889dc97510a128205731b1efc20d23c053c9 Signed-off-by: Will Szumski --- playbooks/kayobe-base/pre.yml | 22 ++++++++++++++++++++++ playbooks/kayobe-tox/ansible-ci.cfg.j2 | 14 ++++++++++++++ playbooks/kayobe-tox/pre.yml | 8 ++++++++ tox.ini | 1 + zuul.d/jobs.yaml | 21 +++++++++++++++++++-- 5 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 playbooks/kayobe-tox/ansible-ci.cfg.j2 create mode 100644 playbooks/kayobe-tox/pre.yml diff --git a/playbooks/kayobe-base/pre.yml b/playbooks/kayobe-base/pre.yml index a8be2b19c..5168b990f 100644 --- a/playbooks/kayobe-base/pre.yml +++ b/playbooks/kayobe-base/pre.yml @@ -22,6 +22,17 @@ # https://github.com/ansible/ansible/issues/81777 pipelining = False retries = 3 + + [galaxy] + # Prefer the site's OpenDev Ansible Galaxy mirror, falling back to the + # public Galaxy server. + server_list = opendev, galaxy + + [galaxy_server.opendev] + url = https://{{ zuul_site_mirror_fqdn }}:4448/api/ + + [galaxy_server.galaxy] + url = https://galaxy.ansible.com/ ansible_cfg_kolla: | [defaults] # Ensure that facts are referenced via ansible_facts.. @@ -43,6 +54,17 @@ # https://github.com/ansible/ansible/issues/81777 pipelining = False retries = 3 + + [galaxy] + # Prefer the site's OpenDev Ansible Galaxy mirror, falling back to the + # public Galaxy server. + server_list = opendev, galaxy + + [galaxy_server.opendev] + url = https://{{ zuul_site_mirror_fqdn }}:4448/api/ + + [galaxy_server.galaxy] + url = https://galaxy.ansible.com/ roles: - role: kayobe-diagnostics kayobe_diagnostics_phase: "pre" diff --git a/playbooks/kayobe-tox/ansible-ci.cfg.j2 b/playbooks/kayobe-tox/ansible-ci.cfg.j2 new file mode 100644 index 000000000..5bfa402a3 --- /dev/null +++ b/playbooks/kayobe-tox/ansible-ci.cfg.j2 @@ -0,0 +1,14 @@ +# CI-only Ansible configuration. This file is intentionally not named +# ansible.cfg so that it is not auto-discovered by Ansible on a developer's +# machine. CI renders it from this template via a Zuul pre-run playbook, then +# points ANSIBLE_CONFIG at it for the tox jobs. +[galaxy] +# Prefer the site's OpenDev Ansible Galaxy mirror, falling back to the public +# Galaxy server. This speeds up and stabilises role/collection installs in CI. +server_list = opendev, galaxy + +[galaxy_server.opendev] +url = https://{{ zuul_site_mirror_fqdn }}:4448/api/ + +[galaxy_server.galaxy] +url = https://galaxy.ansible.com/ diff --git a/playbooks/kayobe-tox/pre.yml b/playbooks/kayobe-tox/pre.yml new file mode 100644 index 000000000..cb4b100ee --- /dev/null +++ b/playbooks/kayobe-tox/pre.yml @@ -0,0 +1,8 @@ +--- +- hosts: all + gather_facts: true + tasks: + - name: Render CI ansible.cfg using the site mirror + template: + src: ansible-ci.cfg.j2 + dest: "{{ ansible_env.PWD }}/ansible-ci.cfg" diff --git a/tox.ini b/tox.ini index 86f549130..582a843cd 100644 --- a/tox.ini +++ b/tox.ini @@ -6,6 +6,7 @@ envlist = py3,pep8 usedevelop = True passenv = HOME + ANSIBLE_CONFIG allowlist_externals = bash make diff --git a/zuul.d/jobs.yaml b/zuul.d/jobs.yaml index 8250d1bfc..4146477d9 100644 --- a/zuul.d/jobs.yaml +++ b/zuul.d/jobs.yaml @@ -4,11 +4,17 @@ description: | Tox job that checks Ansible playbook syntax. parent: openstack-tox - pre-run: playbooks/kayobe-tox-ansible-syntax/pre.yml + pre-run: + - playbooks/kayobe-tox/pre.yml + - playbooks/kayobe-tox-ansible-syntax/pre.yml required-projects: - name: openstack/ansible-collection-kolla vars: tox_envlist: ansible-syntax + # Use the site's OpenDev Galaxy mirror for role/collection installs. + # A pre-run playbook renders ansible-ci.cfg from a template. + tox_environment: + ANSIBLE_CONFIG: "{{ ansible_env.PWD ~ '/ansible-ci.cfg' }}" ansible_collection_kolla_src_dir: "{{ ansible_env.PWD ~ '/' ~ zuul.projects['opendev.org/openstack/ansible-collection-kolla'].src_dir }}" kayobe_src_dir: "{{ ansible_env.PWD ~ '/' ~ zuul.projects['opendev.org/openstack/kayobe'].src_dir }}" irrelevant-files: @@ -26,9 +32,14 @@ description: | Tox job that runs native Ansible role tests. parent: openstack-tox-with-sudo + pre-run: playbooks/kayobe-tox/pre.yml timeout: 3600 vars: tox_envlist: ansible + # Use the site's OpenDev Galaxy mirror for role/collection installs. + # A pre-run playbook renders ansible-ci.cfg from a template. + tox_environment: + ANSIBLE_CONFIG: "{{ ansible_env.PWD ~ '/ansible-ci.cfg' }}" required-projects: - name: openstack/requirements irrelevant-files: @@ -46,12 +57,18 @@ description: | Tox job that runs molecule-based Ansible role tests. parent: openstack-tox-with-sudo - pre-run: playbooks/kayobe-tox-molecule/pre.yml + pre-run: + - playbooks/kayobe-tox/pre.yml + - playbooks/kayobe-tox-molecule/pre.yml timeout: 3600 required-projects: - openstack/requirements vars: tox_envlist: molecule + # Use the site's OpenDev Galaxy mirror for role/collection installs. + # A pre-run playbook renders ansible-ci.cfg from a template. + tox_environment: + ANSIBLE_CONFIG: "{{ ansible_env.PWD ~ '/ansible-ci.cfg' }}" irrelevant-files: - ^.*\.rst$ - ^doc/.* From e4ab4eba193ae5a00cafd353371da08295084802 Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Mon, 21 Sep 2026 12:51:12 +0000 Subject: [PATCH 07/19] Remove Swift support Kolla Ansible has dropped support for Swift [1], so remove the corresponding support from Kayobe, including the swift-rings and swift-block-devices roles and associated integrations and CI scripts. [1] https://review.opendev.org/c/openstack/kolla-ansible/+/945113 Change-Id: Ied168ab752519f464c9863ef6f1cd1486530546e Signed-off-by: Will Szumski --- ansible/inventory/group_vars/all/controllers | 1 - ansible/inventory/group_vars/all/kolla | 7 - ansible/inventory/group_vars/all/network | 6 - ansible/inventory/group_vars/all/storage | 15 +- ansible/inventory/group_vars/all/swift | 67 --------- ansible/kolla-ansible.yml | 8 -- ansible/overcloud-host-configure.yml | 1 - .../kolla-ansible-host-vars/tests/test.yml | 8 -- ansible/roles/kolla-ansible/defaults/main.yml | 1 - .../kolla-ansible/templates/kolla/globals.yml | 30 +--- .../roles/kolla-ansible/tests/test-extras.yml | 4 - .../roles/kolla-openstack/defaults/main.yml | 21 --- .../molecule/default/tests/test_default.py | 3 +- .../molecule/enable-everything/molecule.yml | 1 - .../swift-block-devices/defaults/main.yml | 11 -- .../roles/swift-block-devices/tasks/main.yml | 73 ---------- .../roles/swift-block-devices/tests/main.yml | 13 -- .../tests/test-bootstrapped.yml | 69 ---------- .../tests/test-invalid-format.yml | 24 ---- .../swift-block-devices/tests/test-mount.yml | 61 --------- ansible/roles/swift-rings/defaults/main.yml | 49 ------- .../swift-rings/files/swift-ring-builder.py | 128 ------------------ ansible/roles/swift-rings/tasks/main.yml | 68 ---------- .../swift-rings/templates/swift-ring.yml.j2 | 21 --- ansible/roles/swift-rings/vars/main.yml | 6 - ansible/swift-block-devices.yml | 15 -- ansible/swift-rings.yml | 35 ----- dev/dev-vagrant.yml | 3 - dev/functions | 2 - .../configuration/reference/kolla-ansible.rst | 7 +- .../configuration/reference/network.rst | 11 -- .../scenarios/all-in-one/overcloud.rst | 6 - doc/source/deployment.rst | 12 -- etc/kayobe/networks.yml | 6 - etc/kayobe/storage.yml | 5 - etc/kayobe/swift.yml | 65 --------- kayobe/cli/commands.py | 9 -- kayobe/tests/unit/cli/test_commands.py | 20 --- ...remove-swift-support-7edf979aef2a1414.yaml | 7 + setup.cfg | 3 - 40 files changed, 11 insertions(+), 891 deletions(-) delete mode 100644 ansible/inventory/group_vars/all/swift delete mode 100644 ansible/roles/swift-block-devices/defaults/main.yml delete mode 100644 ansible/roles/swift-block-devices/tasks/main.yml delete mode 100644 ansible/roles/swift-block-devices/tests/main.yml delete mode 100644 ansible/roles/swift-block-devices/tests/test-bootstrapped.yml delete mode 100644 ansible/roles/swift-block-devices/tests/test-invalid-format.yml delete mode 100644 ansible/roles/swift-block-devices/tests/test-mount.yml delete mode 100644 ansible/roles/swift-rings/defaults/main.yml delete mode 100644 ansible/roles/swift-rings/files/swift-ring-builder.py delete mode 100644 ansible/roles/swift-rings/tasks/main.yml delete mode 100644 ansible/roles/swift-rings/templates/swift-ring.yml.j2 delete mode 100644 ansible/roles/swift-rings/vars/main.yml delete mode 100644 ansible/swift-block-devices.yml delete mode 100644 ansible/swift-rings.yml delete mode 100644 etc/kayobe/swift.yml create mode 100644 releasenotes/notes/remove-swift-support-7edf979aef2a1414.yaml diff --git a/ansible/inventory/group_vars/all/controllers b/ansible/inventory/group_vars/all/controllers index ead2f1104..a0cffca4b 100644 --- a/ansible/inventory/group_vars/all/controllers +++ b/ansible/inventory/group_vars/all/controllers @@ -44,7 +44,6 @@ controller_default_network_interfaces: > inspection_net_name, internal_net_name, storage_net_name, - swift_storage_net_name, cleaning_net_name] | select | unique | list }} # List of extra networks to which controller nodes are attached. diff --git a/ansible/inventory/group_vars/all/kolla b/ansible/inventory/group_vars/all/kolla index 6a104abf1..e21f89767 100644 --- a/ansible/inventory/group_vars/all/kolla +++ b/ansible/inventory/group_vars/all/kolla @@ -244,8 +244,6 @@ overcloud_container_image_regex_map: enabled: "{{ kolla_enable_redis | bool }}" - regex: ^skyline enabled: "{{ kolla_enable_skyline | bool }}" - - regex: ^swift - enabled: "{{ kolla_enable_swift | bool }}" - regex: ^tacker enabled: "{{ kolla_enable_tacker | bool }}" - regex: ^tgtd @@ -405,8 +403,6 @@ kolla_overcloud_inventory_pass_through_host_vars_default: - "kolla_api_interface" - "kolla_storage_interface" - "kolla_cluster_interface" - - "kolla_swift_storage_interface" - - "kolla_swift_replication_interface" - "kolla_provision_interface" - "kolla_inspector_dnsmasq_interface" - "kolla_dns_interface" @@ -437,8 +433,6 @@ kolla_overcloud_inventory_pass_through_host_vars_map_default: kolla_api_interface: "api_interface" kolla_storage_interface: "storage_interface" kolla_cluster_interface: "cluster_interface" - kolla_swift_storage_interface: "swift_storage_interface" - kolla_swift_replication_interface: "swift_replication_interface" kolla_provision_interface: "provision_interface" kolla_inspector_dnsmasq_interface: "ironic_dnsmasq_interface" kolla_dns_interface: "dns_interface" @@ -580,7 +574,6 @@ kolla_enable_prometheus: "no" kolla_enable_qdrouterd: "no" kolla_enable_redis: "no" kolla_enable_skyline: "no" -kolla_enable_swift: "no" kolla_enable_tacker: "no" kolla_enable_trove: "no" kolla_enable_valkey: "no" diff --git a/ansible/inventory/group_vars/all/network b/ansible/inventory/group_vars/all/network index 61f1529cd..402eb44f8 100644 --- a/ansible/inventory/group_vars/all/network +++ b/ansible/inventory/group_vars/all/network @@ -43,12 +43,6 @@ storage_net_name: 'storage_net' # Name of the network used to carry storage management traffic. storage_mgmt_net_name: 'storage_mgmt_net' -# Name of the network used to carry swift storage data traffic. -swift_storage_net_name: "{{ storage_net_name }}" - -# Name of the network used to carry swift storage replication traffic. -swift_storage_replication_net_name: "{{ storage_mgmt_net_name }}" - # Name of the network used to perform hardware introspection on the bare metal # workload hosts. inspection_net_name: "{{ 'inspection_net' if kolla_enable_ironic | bool else None }}" diff --git a/ansible/inventory/group_vars/all/storage b/ansible/inventory/group_vars/all/storage index df4a55d6e..fce656df8 100644 --- a/ansible/inventory/group_vars/all/storage +++ b/ansible/inventory/group_vars/all/storage @@ -13,11 +13,7 @@ storage_bootstrap_user: "{{ 'cloud-user' if os_distribution == 'centos' else os_ # List of networks to which storage nodes are attached. storage_network_interfaces: > {{ (storage_default_network_interfaces + - storage_extra_network_interfaces + - ([swift_storage_net_name] - if storage_needs_swift_network else []) + - ([swift_storage_replication_net_name] - if storage_needs_swift_replication_network else [])) | select | unique | list }} + storage_extra_network_interfaces) | select | unique | list }} # List of default networks to which storage nodes are attached. storage_default_network_interfaces: > @@ -29,15 +25,6 @@ storage_default_network_interfaces: > # List of extra networks to which storage nodes are attached. storage_extra_network_interfaces: [] -# Whether this host requires access to Swift networks. -storage_needs_swift_network: >- - {{ kolla_enable_swift | bool and - inventory_hostname in query('inventory_hostnames', swift_hosts) }} - -storage_needs_swift_replication_network: >- - {{ kolla_enable_swift | bool and - inventory_hostname in query('inventory_hostnames', swift_hosts) }} - ############################################################################### # Storage node BIOS configuration. diff --git a/ansible/inventory/group_vars/all/swift b/ansible/inventory/group_vars/all/swift deleted file mode 100644 index bd509434b..000000000 --- a/ansible/inventory/group_vars/all/swift +++ /dev/null @@ -1,67 +0,0 @@ ---- -############################################################################### -# OpenStack Swift configuration. - -# Short name of the kolla container image used to build rings. Default is the -# swift=object image. -swift_ring_build_image_name: swift-object - -# Full name of the kolla container image used to build rings. -swift_ring_build_image: "{{ kolla_docker_registry ~ '/' if kolla_docker_registry else '' }}{{ kolla_docker_namespace }}/{{ swift_ring_build_image_name }}:{{ openstack_release }}-{{ kolla_base_distro }}-{{ kolla_base_distro_version }}" - -# Ansible host pattern matching hosts on which Swift object storage services -# are deployed. The default is to use hosts in the 'storage' group. -swift_hosts: "storage" - -# Name of the host used to build Swift rings. Default is the first host of -# 'swift_hosts'. -swift_ring_build_host: "{{ query('inventory_hostnames', swift_hosts)[0] }}" - -# ID of the Swift region for this host. Default is 1. -swift_region: 1 - -# ID of the Swift zone. This can be set to different values for different hosts -# to place them in different zones. Default is 0. -swift_zone: 0 - -# Base-2 logarithm of the number of partitions. -# i.e. num_partitions=2^. Default is 10. -swift_part_power: 10 - -# Object replication count. Default is the smaller of the number of Swift -# hosts, or 3. -swift_replication_count: "{{ [query('inventory_hostnames', swift_hosts) | length, 3] | min }}" - -# Minimum time in hours between moving a given partition. Default is 1. -swift_min_part_hours: 1 - -# Ports on which Swift services listen. Default is: -# object: 6000 -# account: 6001 -# container: 6002 -swift_service_ports: - object: 6000 - account: 6001 - container: 6002 - -# List of block devices to use for Swift. Each item is a dict with the -# following items: -# - 'device': Block device path. Required. -# - 'fs_label': Name of the label used to create the file system on the device. -# Optional. Default is to use the basename of the device. -# - 'services': List of services that will use this block device. Optional. -# Default is 'swift_block_device_default_services'. Allowed items are -# 'account', 'container', and 'object'. -# - 'weight': Weight of the block device. Optional. Default is -# 'swift_block_device_default_weight'. -swift_block_devices: [] - -# Default weight to assign to block devices in the ring. Default is 100. -swift_block_device_default_weight: 100 - -# Default list of services to assign block devices to. Allowed items are -# 'account', 'container', and 'object'. Default value is all of these. -swift_block_device_default_services: - - account - - container - - object diff --git a/ansible/kolla-ansible.yml b/ansible/kolla-ansible.yml index 07514a63d..7542f1a79 100644 --- a/ansible/kolla-ansible.yml +++ b/ansible/kolla-ansible.yml @@ -204,14 +204,6 @@ description: "Cluster network" network: "{{ storage_mgmt_net_name }}" required: False - - var_name: "kolla_swift_storage_interface" - description: "Swift storage network" - network: "{{ swift_storage_net_name }}" - required: False - - var_name: "kolla_swift_replication_interface" - description: "Swift storage replication network" - network: "{{ swift_storage_replication_net_name }}" - required: False - var_name: "kolla_provision_interface" description: "Bare metal provisioning network" network: "{{ provision_wl_net_name }}" diff --git a/ansible/overcloud-host-configure.yml b/ansible/overcloud-host-configure.yml index e485720b6..568899655 100644 --- a/ansible/overcloud-host-configure.yml +++ b/ansible/overcloud-host-configure.yml @@ -31,6 +31,5 @@ - import_playbook: "kolla-target-venv.yml" - import_playbook: "container-engine.yml" - import_playbook: "apparmor-libvirt.yml" -- import_playbook: "swift-block-devices.yml" - import_playbook: "compute-libvirt-host.yml" - import_playbook: "vgpu.yml" diff --git a/ansible/roles/kolla-ansible-host-vars/tests/test.yml b/ansible/roles/kolla-ansible-host-vars/tests/test.yml index 4ff5d56ef..d211e9424 100644 --- a/ansible/roles/kolla-ansible-host-vars/tests/test.yml +++ b/ansible/roles/kolla-ansible-host-vars/tests/test.yml @@ -20,8 +20,6 @@ kolla_provision_interface: "eth8" kolla_inspector_dnsmasq_interface: "eth9" kolla_tunnel_interface: "eth10" - kolla_swift_storage_interface: "eth13" - kolla_swift_replication_interface: "eth14" - name: Add a compute host to the inventory add_host: @@ -61,8 +59,6 @@ - "kolla_api_interface" - "kolla_storage_interface" - "kolla_cluster_interface" - - "kolla_swift_storage_interface" - - "kolla_swift_replication_interface" - "kolla_provision_interface" - "kolla_inspector_dnsmasq_interface" - "kolla_dns_interface" @@ -76,8 +72,6 @@ kolla_api_interface: "api_interface" kolla_storage_interface: "storage_interface" kolla_cluster_interface: "cluster_interface" - kolla_swift_storage_interface: "swift_storage_interface" - kolla_swift_replication_interface: "swift_replication_interface" kolla_provision_interface: "provision_interface" kolla_inspector_dnsmasq_interface: "ironic_dnsmasq_interface" kolla_dns_interface: "dns_interface" @@ -120,8 +114,6 @@ api_interface: "eth2" storage_interface: "eth3" cluster_interface: "eth4" - swift_storage_interface: "eth13" - swift_replication_interface: "eth14" provision_interface: "eth8" ironic_dnsmasq_interface: "eth9" dns_interface: "eth5" diff --git a/ansible/roles/kolla-ansible/defaults/main.yml b/ansible/roles/kolla-ansible/defaults/main.yml index ad5b08b89..4172d0f77 100644 --- a/ansible/roles/kolla-ansible/defaults/main.yml +++ b/ansible/roles/kolla-ansible/defaults/main.yml @@ -243,7 +243,6 @@ kolla_openstack_logging_debug: #kolla_enable_neutron_agent_ha: #kolla_enable_neutron_vpnaas: #kolla_enable_prometheus: -#kolla_enable_swift: #kolla_enable_watcher: ####################### diff --git a/ansible/roles/kolla-ansible/templates/kolla/globals.yml b/ansible/roles/kolla-ansible/templates/kolla/globals.yml index ce4dd1f76..ddd18b2b7 100644 --- a/ansible/roles/kolla-ansible/templates/kolla/globals.yml +++ b/ansible/roles/kolla-ansible/templates/kolla/globals.yml @@ -109,8 +109,6 @@ docker_registry_username: "{{ kolla_docker_registry_username }}" #api_address_family: "{% raw %}{{ network_address_family }}{% endraw %}" #storage_address_family: "{% raw %}{{ network_address_family }}{% endraw %}" #cluster_address_family: "{% raw %}{{ network_address_family }}{% endraw %}" -#swift_storage_address_family: "{% raw %}{{ storage_address_family }}{% endraw %}" -#swift_replication_address_family: "{% raw %}{{ swift_storage_address_family }}{% endraw %}" #migration_address_family: "{% raw %}{{ network_address_family }}{% endraw %}" #tunnel_address_family: "{% raw %}{{ network_address_family }}{% endraw %}" #octavia_network_address_family: "{% raw %}{{ api_address_family }}{% endraw %}" @@ -284,7 +282,6 @@ enable_{{ feature_flag }}: {{ hostvars[inventory_hostname]['kolla_enable_' ~ fea # Configure image backend. #glance_backend_ceph: "no" #glance_backend_file: "yes" -#glance_backend_swift: "no" #glance_backend_vmware: "no" #enable_glance_image_cache: "no" # Configure glance upgrade option. @@ -324,7 +321,7 @@ enable_{{ feature_flag }}: {{ hostvars[inventory_hostname]['kolla_enable_' ~ fea # Valid options are [ '', redis, etcd ] #cinder_coordination_backend: "{% raw %}{{ 'redis' if enable_redis|bool else 'etcd' if enable_etcd|bool else '' }}{% endraw %}" -# Valid options are [ nfs, swift, ceph ] +# Valid options are [ nfs, ceph, s3 ] #cinder_backup_driver: "ceph" #cinder_backup_share: "" #cinder_backup_mount_options_nfs: "" @@ -431,31 +428,6 @@ ironic_kernel_cmdline_extras: #hnas_evs_ip: #hnas_file_system_name: -################################ -# Swift - Object Storage Options -################################ -# Swift expects block devices to be available for storage. Two types of storage -# are supported: 1 - storage device with a special partition name and filesystem -# label, 2 - unpartitioned disk with a filesystem. The label of this filesystem -# is used to detect the disk which Swift will be using. - -# Swift support two matching modes, valid options are [ prefix, strict ] -#swift_devices_match_mode: "strict" - -# This parameter defines matching pattern: if "strict" mode was selected, -# for swift_devices_match_mode then swift_device_name should specify the name of -# the special swift partition for example: "KOLLA_SWIFT_DATA", if "prefix" mode was -# selected then swift_devices_name should specify a pattern which would match to -# filesystems' labels prepared for swift. -#swift_devices_name: "KOLLA_SWIFT_DATA" - -# Configure swift upgrade option, due to currently kolla support -# two upgrade ways for swift: legacy_upgrade and rolling_upgrade -# The variable "swift_enable_rolling_upgrade: yes" is meaning rolling_upgrade -# were enabled and opposite -# Rolling upgrade were enable by default -#swift_enable_rolling_upgrade: "yes" - ################################### # VMware - OpenStack VMware support ################################### diff --git a/ansible/roles/kolla-ansible/tests/test-extras.yml b/ansible/roles/kolla-ansible/tests/test-extras.yml index 6b10ae794..e3c8f784e 100644 --- a/ansible/roles/kolla-ansible/tests/test-extras.yml +++ b/ansible/roles/kolla-ansible/tests/test-extras.yml @@ -196,7 +196,6 @@ kolla_enable_osprofiler: True kolla_enable_prometheus: True kolla_enable_skyline: True - kolla_enable_swift: True kolla_enable_tacker: True kolla_enable_trove: True kolla_enable_watcher: True @@ -306,7 +305,6 @@ #enable_osprofiler: True #enable_prometheus: True #enable_skyline: True - #enable_swift: True #enable_tacker: True #enable_trove: True #enable_watcher: True @@ -334,8 +332,6 @@ - kolla_external_vip_interface - storage_interface - cluster_interface - - swift_storage_interface - - swift_replication_interface - provision_interface - ironic_dnsmasq_interface - dns_interface diff --git a/ansible/roles/kolla-openstack/defaults/main.yml b/ansible/roles/kolla-openstack/defaults/main.yml index b87b54566..3b63e766d 100644 --- a/ansible/roles/kolla-openstack/defaults/main.yml +++ b/ansible/roles/kolla-openstack/defaults/main.yml @@ -146,8 +146,6 @@ kolla_openstack_custom_config_include_globs_default: glob: placement/** - enabled: '{{ kolla_enable_prometheus | bool }}' glob: prometheus/** - - enabled: '{{ kolla_enable_swift | bool }}' - glob: swift/** - enabled: '{{ kolla_enable_watcher | bool }}' glob: watcher.conf - enabled: '{{ kolla_enable_watcher | bool }}' @@ -215,12 +213,6 @@ kolla_openstack_custom_config_rules_default: - glob: ironic/ironic-agent.kernel strategy: copy priority: 1000 - - glob: swift/*.builder - strategy: copy - priority: 1000 - - glob: swift/*.ring.gz - strategy: copy - priority: 1000 - glob: '**/*.pem' strategy: copy priority: 1000 @@ -608,13 +600,6 @@ kolla_inspector_ipa_ramdisk_path: # kolla_inspector_ipa_ramdisk_path is set. kolla_inspector_ipa_host: -# Whether to enable the Swift introspection data store. -kolla_inspector_enable_swift: - -# Dict of authentication parameters for accessing the Swift introspection data -# store. -kolla_inspector_swift_auth: {} - # Deprecated: # Free form extra configuration to append to ironic-inspector.conf. kolla_extra_inspector: @@ -794,12 +779,6 @@ kolla_extra_placement: # Whether to enable Prometheus. kolla_enable_prometheus: false -############################################################################### -# Swift configuration. - -# Whether to enable swift. -kolla_enable_swift: false - ############################################################################### # Watcher configuration. diff --git a/ansible/roles/kolla-openstack/molecule/default/tests/test_default.py b/ansible/roles/kolla-openstack/molecule/default/tests/test_default.py index 086841cfe..1c3e2f3d1 100644 --- a/ansible/roles/kolla-openstack/molecule/default/tests/test_default.py +++ b/ansible/roles/kolla-openstack/molecule/default/tests/test_default.py @@ -46,8 +46,7 @@ 'masakari', 'neutron', 'nova', - 'prometheus', - 'swift']) + 'prometheus']) def test_service_config_directory_absent(host, path): path = os.path.join('/etc/kolla/config', path) utils.test_path_absent(host, path) diff --git a/ansible/roles/kolla-openstack/molecule/enable-everything/molecule.yml b/ansible/roles/kolla-openstack/molecule/enable-everything/molecule.yml index 6bd7da34d..5b1e38736 100644 --- a/ansible/roles/kolla-openstack/molecule/enable-everything/molecule.yml +++ b/ansible/roles/kolla-openstack/molecule/enable-everything/molecule.yml @@ -135,7 +135,6 @@ provisioner: [extra-placement.conf] foo=bar kolla_enable_prometheus: true - kolla_enable_swift: true kolla_enable_telegraf: true kolla_enable_watcher: true lint: diff --git a/ansible/roles/swift-block-devices/defaults/main.yml b/ansible/roles/swift-block-devices/defaults/main.yml deleted file mode 100644 index 55c0f0562..000000000 --- a/ansible/roles/swift-block-devices/defaults/main.yml +++ /dev/null @@ -1,11 +0,0 @@ ---- -# Label used to create partitions. This is used by kolla-ansible to determine -# which disks to mount. -swift_block_devices_part_label: KOLLA_SWIFT_DATA - -# List of block devices to use for Swift. Each item is a dict with the -# following items: -# - 'device': Block device path. Required. -# - 'fs_label': Name of the label used to create the file system on the device. -# Optional. Default is to use the basename of the device. -swift_block_devices: [] diff --git a/ansible/roles/swift-block-devices/tasks/main.yml b/ansible/roles/swift-block-devices/tasks/main.yml deleted file mode 100644 index 1da9979fa..000000000 --- a/ansible/roles/swift-block-devices/tasks/main.yml +++ /dev/null @@ -1,73 +0,0 @@ ---- -- name: Fail if swift_block_devices is not in the expected format - fail: - msg: >- - Device {{ device_index }} in swift_block_devices is in an invalid format. - Items should be a dict, containing at least a 'device' field. - with_items: "{{ swift_block_devices }}" - when: item is not mapping or 'device' not in item - loop_control: - index_var: device_index - -- name: Ensure required packages are installed - package: - name: - - parted - - xfsprogs - state: present - cache_valid_time: "{{ apt_cache_valid_time if ansible_facts.os_family == 'Debian' else omit }}" - update_cache: "{{ True if ansible_facts.os_family == 'Debian' else omit }}" - become: True - when: swift_block_devices | length > 0 - -- name: Check the presence of a partition on the Swift block devices - become: True - parted: - device: "{{ item.device }}" - with_items: "{{ swift_block_devices }}" - loop_control: - label: "{{ item.device }}" - register: swift_disk_info - -- name: Fail if the Swift block devices have already a partition - fail: - msg: > - The physical disk {{ item.item.device }} already has a partition. - Ensure that each disk in 'swift_block_devices' does not have any - partitions. - with_items: "{{ swift_disk_info.results }}" - when: - - item.partitions | length > 0 - - item.partitions.0.name != swift_block_devices_part_label - loop_control: - label: "{{ item.item.device }}" - -- name: Ensure partitions exist for Swift block device - become: True - parted: - device: "{{ item.item.device }}" - number: 1 - label: gpt - name: "{{ swift_block_devices_part_label }}" - state: present - with_items: "{{ swift_disk_info.results }}" - when: item.partitions | length == 0 - loop_control: - label: "{{ item.item.device }}" - -- name: Ensure Swift XFS file systems exist - become: true - filesystem: - dev: "{{ partition_name }}" - force: true - fstype: xfs - opts: "-L {{ fs_label }}" - with_items: "{{ swift_disk_info.results }}" - when: item.partitions | length == 0 - loop_control: - label: "{{ device }}" - index_var: index - vars: - device: "{{ item.item.device }}" - partition_name: "{{ device }}{% if device.startswith('/dev/loop') %}p{% endif %}1" - fs_label: "{{ item.item.fs_label | default(device | basename) }}" diff --git a/ansible/roles/swift-block-devices/tests/main.yml b/ansible/roles/swift-block-devices/tests/main.yml deleted file mode 100644 index 853028045..000000000 --- a/ansible/roles/swift-block-devices/tests/main.yml +++ /dev/null @@ -1,13 +0,0 @@ ---- -- import_playbook: test-invalid-format.yml -- import_playbook: test-mount.yml -- import_playbook: test-bootstrapped.yml - -- hosts: localhost - connection: local - tasks: - - name: Fail if any tests failed - fail: - msg: > - Test failures: {{ test_failures }} - when: test_failures is defined diff --git a/ansible/roles/swift-block-devices/tests/test-bootstrapped.yml b/ansible/roles/swift-block-devices/tests/test-bootstrapped.yml deleted file mode 100644 index 577b19ab7..000000000 --- a/ansible/roles/swift-block-devices/tests/test-bootstrapped.yml +++ /dev/null @@ -1,69 +0,0 @@ ---- -# Test case with one device that has already been partitioned. - -- hosts: localhost - connection: local - tasks: - - name: Allocate a temporary file for a fake device - tempfile: - register: tempfile - - - name: Allocate a fake device file - command: fallocate -l 350M {{ tempfile.path }} - - - name: Find a free loopback device - command: losetup -f - register: loopback - become: true - - - name: Create a loopback device - command: losetup {{ loopback.stdout }} {{ tempfile.path }} - become: true - - - name: Add a partition - become: True - parted: - device: "{{ loopback.stdout }}" - number: 1 - label: gpt - name: KOLLA_SWIFT_DATA - state: present - - - block: - - name: Test the swift-block-devices role - include_role: - name: ../../swift-block-devices - vars: - swift_block_devices: - - device: "{{ loopback.stdout }}" - apt_cache_valid_time: 3600 - - - name: Get name of fake partition - parted: - device: "{{ loopback.stdout }}" - register: "disk_info" - become: True - - - name: Validate number of partition - assert: - that: disk_info.partitions | length == 1 - msg: > - Number of partitions is not correct. - - - name: Validate partition label is present - assert: - that: "disk_info.partitions.0.name == 'KOLLA_SWIFT_DATA'" - msg: > - Name of partition is not correct. - - always: - - name: Remove the fake file - file: - name: "{{ loopback.stdout }}" - state: absent - become: true - - rescue: - - name: Flag that a failure occurred - set_fact: - test_failures: "{{ test_failures | default(0) | int + 1 }}" diff --git a/ansible/roles/swift-block-devices/tests/test-invalid-format.yml b/ansible/roles/swift-block-devices/tests/test-invalid-format.yml deleted file mode 100644 index 22df7be5e..000000000 --- a/ansible/roles/swift-block-devices/tests/test-invalid-format.yml +++ /dev/null @@ -1,24 +0,0 @@ ---- -# Test case with swift_block_devices in an invalid format. - -- hosts: localhost - connection: local - tasks: - - block: - - name: Test the swift-block-devices role - include_role: - name: ../../swift-block-devices - vars: - swift_block_devices: - - /dev/fake - apt_cache_valid_time: 3600 - - rescue: - - name: Flag that the error was raised - set_fact: - raised_error: true - - - name: Flag that a failure occurred - set_fact: - test_failures: "{{ test_failures | default(0) | int + 1 }}" - when: raised_error is not defined diff --git a/ansible/roles/swift-block-devices/tests/test-mount.yml b/ansible/roles/swift-block-devices/tests/test-mount.yml deleted file mode 100644 index 5489160d9..000000000 --- a/ansible/roles/swift-block-devices/tests/test-mount.yml +++ /dev/null @@ -1,61 +0,0 @@ ---- -# Test case with one device that has not yet been tagged by kayobe with the -# kolla-ansible bootstrap label. - -- hosts: localhost - connection: local - tasks: - - name: Allocate a temporary file for a fake device - tempfile: - register: tempfile - - - name: Allocate a fake device file - command: fallocate -l 350M {{ tempfile.path }} - - - name: Find a free loopback device - command: losetup -f - register: loopback - become: true - - - name: Create a loopback device - command: losetup {{ loopback.stdout }} {{ tempfile.path }} - become: true - - - block: - - name: Test the swift-block-devices role - include_role: - name: ../../swift-block-devices - vars: - swift_block_devices: - - device: "{{ loopback.stdout }}" - apt_cache_valid_time: 3600 - - - name: Get name of fake partition - parted: - device: "{{ loopback.stdout }}" - register: "disk_info" - become: True - - - name: Validate number of partition - assert: - that: disk_info.partitions | length == 1 - msg: > - Number of partitions is not correct. - - - name: Validate partition label is present - assert: - that: "disk_info.partitions.0.name == 'KOLLA_SWIFT_DATA'" - msg: > - Name of partition is not correct. - - always: - - name: Remove the fake file - file: - name: "{{ loopback.stdout }}" - state: absent - become: true - - rescue: - - name: Flag that a failure occurred - set_fact: - test_failures: "{{ test_failures | default(0) | int + 1 }}" diff --git a/ansible/roles/swift-rings/defaults/main.yml b/ansible/roles/swift-rings/defaults/main.yml deleted file mode 100644 index 32ae7dea4..000000000 --- a/ansible/roles/swift-rings/defaults/main.yml +++ /dev/null @@ -1,49 +0,0 @@ ---- -# Host on which to build Swift rings. -swift_ring_build_host: - -# Path to Kayobe cnnfigutation for Swift. -swift_config_path: - -# Path in the container in which to build rings. -swift_container_build_path: /tmp/swift-rings - -# Path on the build host in which to store ring files temporarily. -swift_ring_build_path: /tmp/swift-rings - -# Docker image to use to build rings. -swift_ring_build_image: - -# Base-2 logarithm of the number of partitions. -# i.e. num_partitions=2^. -swift_part_power: - -# Object replication count. -swift_replication_count: - -# Minimum time in hours between moving a given partition. -swift_min_part_hours: - -# List of configuration items for each host. Each item is a dict containing the -# following fields: -# - host: hostname -# - region: Swift region -# - zone: Swift zone -# - ip: storage network IP address -# - ports: dict of ports for the storage network -# - replication_ip: replication network IP address -# - replication_ports: dict of ports for the replication network -# - block_devices: list of block devices to use for Swift. Each item is a dict with the -# following items: -# - 'device': Block device path. Required. -# - 'fs_label': Name of the label used to create the file system on the device. -# Optional. Default is to use the basename of the device. -# - 'services': List of services that will use this block device. Optional. -# Default is 'block_device_default_services' for this host. -# - 'weight': Weight of the block device. Optional. Default is -# 'block_device_default_weight' for this host. -# - 'block_device_default_services': default list of services to assign block -# devices on this host to. -# - 'block_device_default_weight': default weight to assign to block devices on -# this host. -swift_host_config: [] diff --git a/ansible/roles/swift-rings/files/swift-ring-builder.py b/ansible/roles/swift-rings/files/swift-ring-builder.py deleted file mode 100644 index 274bd2a07..000000000 --- a/ansible/roles/swift-rings/files/swift-ring-builder.py +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/env python3 - -""" -Script to build a Swift ring from a declarative YAML configuration. This has -been built via a script to avoid repeated 'docker exec' commands which could -take a long time. - -Usage: - -python swift-ring-builder.py - -Example: - -python swift-ring-builder.py /path/to/config.yml /path/to/builds object - -Example configuration format: - ---- -part_power: 10 -replication_count: 3 -min_part_hours: 1 -hosts: - - host: swift1 - region: 1 - zone: 1 - ip: 10.0.0.1 - port: 6001 - replication_ip: 10.1.0.1 - replication_port: 6001 - devices: - - device: /dev/sdb - weight: 100 - - device: /dev/sdc - weight: 100 -""" -import subprocess -import sys - -import yaml - - -class RingBuilder(object): - """Helper class for building Swift rings.""" - - def __init__(self, build_path, service_name): - self.build_path = build_path - self.service_name = service_name - - def get_base_command(self): - return [ - 'swift-ring-builder', - '%s/%s.builder' % (self.build_path, self.service_name), - ] - - def create(self, part_power, replication_count, min_part_hours): - cmd = self.get_base_command() - cmd += [ - 'create', - "{}".format(part_power), - "{}".format(replication_count), - "{}".format(min_part_hours), - ] - try: - subprocess.check_call(cmd) - except subprocess.CalledProcessError: - print("Failed to create %s ring" % self.service_name) - sys.exit(1) - - def add_device(self, host, device): - cmd = self.get_base_command() - cmd += [ - 'add', - '--region', "{}".format(host['region']), - '--zone', "{}".format(host['zone']), - '--ip', host['ip'], - '--port', "{}".format(host['port']), - '--replication-ip', host['replication_ip'], - '--replication-port', "{}".format(host['replication_port']), - '--device', device['device'], - '--weight', "{}".format(device['weight']), - ] - try: - subprocess.check_call(cmd) - except subprocess.CalledProcessError: - print("Failed to add device %s on host %s to %s ring" % - (host['host'], device['device'], self.service_name)) - sys.exit(1) - - def rebalance(self): - cmd = self.get_base_command() - cmd += [ - 'rebalance', - ] - try: - subprocess.check_call(cmd) - except subprocess.CalledProcessError: - print("Failed to rebalance %s ring" % self.service_name) - sys.exit(1) - - -def build_rings(config, build_path, service_name): - builder = RingBuilder(build_path, service_name) - builder.create(config['part_power'], config['replication_count'], - config['min_part_hours']) - for host in config['hosts']: - devices = host['devices'] - # If no devices are present for this host, this will be None. - if devices is None: - continue - for device in devices: - builder.add_device(host, device) - builder.rebalance() - - -def main(): - if len(sys.argv) != 4: - raise Exception("Usage: {0} " - "") - config_path = sys.argv[1] - build_path = sys.argv[2] - service_name = sys.argv[3] - with open(config_path) as f: - config = yaml.safe_load(f) - build_rings(config, build_path, service_name) - - -if __name__ == "__main__": - main() diff --git a/ansible/roles/swift-rings/tasks/main.yml b/ansible/roles/swift-rings/tasks/main.yml deleted file mode 100644 index aa6f5e6fb..000000000 --- a/ansible/roles/swift-rings/tasks/main.yml +++ /dev/null @@ -1,68 +0,0 @@ ---- -# We generate a configuration file and execute a python script in a container -# that builds a ring based on the config file contents. Doing it this way -# avoids a large task loop with docker container for each step, which would be -# quite slow. - -# Execute the following commands on the ring build host. -- block: - - name: Ensure Swift ring build directory exists - file: - path: "{{ swift_ring_build_path }}" - state: directory - - - name: Ensure Swift ring builder script exists - copy: - src: swift-ring-builder.py - dest: "{{ swift_ring_build_path }}" - register: copy_result - - - name: Ensure Swift ring builder configuration exists - template: - src: swift-ring.yml.j2 - dest: "{{ swift_ring_build_path }}/{{ service_name }}-ring.yml" - with_items: "{{ swift_service_names }}" - loop_control: - loop_var: service_name - - - name: Ensure Swift rings exist - kayobe_container: - cleanup: true - command: >- - python3 {{ swift_container_build_path }}/swift-ring-builder.py - {{ swift_container_build_path }}/{{ item }}-ring.yml - {{ swift_container_build_path }} - {{ item }} - detach: false - image: "{{ swift_ring_build_image }}" - name: "swift_{{ item }}_ring_builder" - user: "{{ copy_result.uid }}:{{ copy_result.gid }}" - volumes: - - "{{ swift_ring_build_path }}/:{{ swift_container_build_path }}/" - with_items: "{{ swift_service_names }}" - become: "{{ container_engine == 'podman' }}" - - - name: Ensure Swift ring files are copied - fetch: - src: "{{ swift_ring_build_path }}/{{ item[0] }}.{{ item[1] }}" - dest: "{{ swift_config_path }}/{{ item[0] }}.{{ item[1] }}" - flat: true - mode: 0644 - with_nested: - - "{{ swift_service_names }}" - - - ring.gz - - builder - become: true - - always: - - name: Remove Swift ring build directory from build host - file: - path: "{{ swift_ring_build_path }}" - state: absent - become: true - - delegate_to: "{{ swift_ring_build_host }}" - vars: - # NOTE: Without this, the seed's ansible_host variable will not be - # respected when using delegate_to. - ansible_host: "{{ hostvars[swift_ring_build_host].ansible_host | default(swift_ring_build_host) }}" diff --git a/ansible/roles/swift-rings/templates/swift-ring.yml.j2 b/ansible/roles/swift-rings/templates/swift-ring.yml.j2 deleted file mode 100644 index 08aecc646..000000000 --- a/ansible/roles/swift-rings/templates/swift-ring.yml.j2 +++ /dev/null @@ -1,21 +0,0 @@ ---- -part_power: {{ swift_part_power }} -replication_count: {{ swift_replication_count }} -min_part_hours: {{ swift_min_part_hours }} -hosts: -{% for host_config in swift_host_config %} - - host: {{ host_config.host }} - region: {{ host_config.region }} - zone: {{ host_config.zone }} - ip: {{ host_config.ip }} - port: {{ host_config.ports[service_name] }} - replication_ip: {{ host_config.replication_ip }} - replication_port: {{ host_config.replication_ports[service_name] }} - devices: -{% for device in host_config.block_devices %} -{% if service_name in (device.services | default(host_config.block_device_default_services)) %} - - device: {{ device.fs_label | default(device.device | basename) }} - weight: {{ device.weight | default(host_config.block_device_default_weight) }} -{% endif %} -{% endfor %} -{% endfor %} diff --git a/ansible/roles/swift-rings/vars/main.yml b/ansible/roles/swift-rings/vars/main.yml deleted file mode 100644 index c6b67fbc8..000000000 --- a/ansible/roles/swift-rings/vars/main.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -# List of names of Swift services. -swift_service_names: - - object - - account - - container diff --git a/ansible/swift-block-devices.yml b/ansible/swift-block-devices.yml deleted file mode 100644 index 306a13d1b..000000000 --- a/ansible/swift-block-devices.yml +++ /dev/null @@ -1,15 +0,0 @@ ---- -- name: Ensure Swift block devices are prepared - hosts: "{{ swift_hosts }}" - max_fail_percentage: >- - {{ swift_block_devices_max_fail_percentage | - default(kayobe_max_fail_percentage) | - default(100) }} - vars: - swift_hosts: storage - tags: - - swift - - swift-block-devices - roles: - - role: swift-block-devices - when: kolla_enable_swift | bool diff --git a/ansible/swift-rings.yml b/ansible/swift-rings.yml deleted file mode 100644 index 56a17c9ac..000000000 --- a/ansible/swift-rings.yml +++ /dev/null @@ -1,35 +0,0 @@ ---- -- name: Ensure swift ring files exist - hosts: localhost - tags: - - swift - - swift-rings - tasks: - - name: Initialise a fact about swift hosts - set_fact: - swift_host_config: [] - - - name: Update a fact about Swift hosts - set_fact: - swift_host_config: "{{ swift_host_config + [swift_host] }}" - vars: - swift_host: - host: "{{ host }}" - region: "{{ hostvars[host]['swift_region'] }}" - zone: "{{ hostvars[host]['swift_zone'] }}" - ip: "{{ swift_storage_net_name | net_ip(inventory_hostname=host) }}" - ports: "{{ hostvars[host]['swift_service_ports'] }}" - replication_ip: "{{ swift_storage_replication_net_name | net_ip(inventory_hostname=host) }}" - replication_ports: "{{ hostvars[host]['swift_service_ports'] }}" - block_devices: "{{ hostvars[host]['swift_block_devices'] }}" - block_device_default_services: "{{ hostvars[host]['swift_block_device_default_services'] }}" - block_device_default_weight: "{{ hostvars[host]['swift_block_device_default_weight'] }}" - with_inventory_hostnames: "{{ swift_hosts }}" - loop_control: - loop_var: host - - - include_role: - name: swift-rings - vars: - swift_config_path: "{{ kayobe_env_config_path }}/kolla/config/swift" - when: kolla_enable_swift | bool diff --git a/dev/dev-vagrant.yml b/dev/dev-vagrant.yml index de676b86b..241e21a0f 100644 --- a/dev/dev-vagrant.yml +++ b/dev/dev-vagrant.yml @@ -17,9 +17,6 @@ kayobe_ansible_user: vagrant # Set an interface name for LLDP discovery. inspector_lldp_switch_port_interface_default: eth0 -# Disable swift. -kolla_enable_swift: False - # Map all networks to the all-in-one network. oob_oc_net_name: aio provision_oc_net_name: aio diff --git a/dev/functions b/dev/functions index 4c0ebb47d..4664c7710 100644 --- a/dev/functions +++ b/dev/functions @@ -1022,8 +1022,6 @@ function configure_iptables { # bridge, breth1. sudo iptables -A FORWARD -i breth1 -j ACCEPT || true - # agent ramdisk gets instance image from swift - sudo iptables -I INPUT -d $INTERNAL_VIP -p tcp --dport ${SWIFT_DEFAULT_BIND_PORT:-8080} -j ACCEPT || true sudo iptables -I INPUT -d $INTERNAL_VIP -p tcp --dport $GLANCE_SERVICE_PORT -j ACCEPT || true sudo iptables -I INPUT -d $HOST_IP -p tcp --dport $IRONIC_HTTP_PORT -j ACCEPT || true diff --git a/doc/source/configuration/reference/kolla-ansible.rst b/doc/source/configuration/reference/kolla-ansible.rst index ea2f6e85e..35f3f32a7 100644 --- a/doc/source/configuration/reference/kolla-ansible.rst +++ b/doc/source/configuration/reference/kolla-ansible.rst @@ -554,8 +554,6 @@ defined for a host, it is ignored. - "kolla_api_interface" - "kolla_storage_interface" - "kolla_cluster_interface" - - "kolla_swift_storage_interface" - - "kolla_swift_replication_interface" - "kolla_provision_interface" - "kolla_inspector_dnsmasq_interface" - "kolla_dns_interface" @@ -581,8 +579,6 @@ defined for a host, it is ignored. kolla_api_interface: "api_interface" kolla_storage_interface: "storage_interface" kolla_cluster_interface: "cluster_interface" - kolla_swift_storage_interface: "swift_storage_interface" - kolla_swift_replication_interface: "swift_replication_interface" kolla_provision_interface: "provision_interface" kolla_inspector_dnsmasq_interface: "ironic_dnsmasq_interface" kolla_dns_interface: "dns_interface" @@ -741,7 +737,7 @@ A common task is enabling a new OpenStack service. This may be done via the :caption: ``$KAYOBE_CONFIG_PATH/kolla.yml`` --- - kolla_enable_swift: true + kolla_enable_barbican: true Note that in some cases additional configuration may be required to successfully deploy a service - check the :kolla-ansible-doc:`Kolla Ansible @@ -828,7 +824,6 @@ which files are supported. ``placement.conf`` Placement configuration. ``placement/*`` Extended Placement configuration. ``prometheus/*`` Prometheus configuration. - ``swift/*`` Extended swift configuration. ``watcher.conf`` Watcher configuration. ``watcher/*`` Extended Watcher configuration. =============================== ======================================================= diff --git a/doc/source/configuration/reference/network.rst b/doc/source/configuration/reference/network.rst index 32d259557..27caeb72a 100644 --- a/doc/source/configuration/reference/network.rst +++ b/doc/source/configuration/reference/network.rst @@ -914,12 +914,6 @@ Storage network (``storage_net_name``) Name of the network used to carry storage data traffic. Storage management network (``storage_mgmt_net_name``) Name of the network used to carry storage management traffic. -Swift storage network (``swift_storage_net_name``) - Name of the network used to carry Swift storage data traffic. - Defaults to the storage network (``storage_net_name``). -Swift storage replication network (``swift_storage_replication_net_name``) - Name of the network used to carry storage management traffic. - Defaults to the storage management network (``storage_mgmt_net_name``) Workload inspection network (``inspection_net_name``) Name of the network used to perform hardware introspection on the bare metal workload hosts. @@ -956,8 +950,6 @@ To configure network roles in a system with two networks, ``example1`` and - example2 storage_net_name: example2 storage_mgmt_net_name: example2 - swift_storage_net_name: example2 - swift_replication_net_name: example2 inspection_net_name: example2 cleaning_net_name: example2 @@ -1323,9 +1315,6 @@ By default, the storage hosts are attached to the following networks: * storage network * storage management network -In addition, if Swift is enabled, they can also be attached to the Swift -management and replication networks. - Virtualised Compute Hosts ------------------------- diff --git a/doc/source/configuration/scenarios/all-in-one/overcloud.rst b/doc/source/configuration/scenarios/all-in-one/overcloud.rst index 431b0d587..ed8b01bd8 100644 --- a/doc/source/configuration/scenarios/all-in-one/overcloud.rst +++ b/doc/source/configuration/scenarios/all-in-one/overcloud.rst @@ -152,12 +152,6 @@ the name of the default controller networks to ``aio``: #storage_mgmt_net_name: storage_mgmt_net_name: aio - # Name of the network used to carry swift storage data traffic. - #swift_storage_net_name: - - # Name of the network used to carry swift storage replication traffic. - #swift_storage_replication_net_name: - # Name of the network used to perform hardware introspection on the bare metal # workload hosts. #inspection_net_name: diff --git a/doc/source/deployment.rst b/doc/source/deployment.rst index f9d079291..aa7ce5947 100644 --- a/doc/source/deployment.rst +++ b/doc/source/deployment.rst @@ -726,18 +726,6 @@ rebuilding images, use the ``--force-rebuild`` argument. See :ref:`here ` for information on how to configure the IPA image build process. -Building Swift Rings --------------------- - -.. note:: - - This section can be skipped if Swift is not in use. - -Swift uses ring files to control placement of data across a cluster. These -files can be generated automatically using the following command:: - - (kayobe) $ kayobe overcloud swift rings generate - Deploying Containerised Services -------------------------------- diff --git a/etc/kayobe/networks.yml b/etc/kayobe/networks.yml index a2b1093c5..f8e4f6331 100644 --- a/etc/kayobe/networks.yml +++ b/etc/kayobe/networks.yml @@ -42,12 +42,6 @@ # Name of the network used to carry storage management traffic. #storage_mgmt_net_name: -# Name of the network used to carry swift storage data traffic. -#swift_storage_net_name: - -# Name of the network used to carry swift storage replication traffic. -#swift_storage_replication_net_name: - # Name of the network used to perform hardware introspection on the bare metal # workload hosts. #inspection_net_name: diff --git a/etc/kayobe/storage.yml b/etc/kayobe/storage.yml index b71b1a9f6..c4651f54f 100644 --- a/etc/kayobe/storage.yml +++ b/etc/kayobe/storage.yml @@ -19,11 +19,6 @@ # List of extra networks to which storage nodes are attached. #storage_extra_network_interfaces: -# Whether this host requires access to Swift networks. -#storage_needs_swift_network: - -#storage_needs_swift_replication_network: - ############################################################################### # Storage node BIOS configuration. diff --git a/etc/kayobe/swift.yml b/etc/kayobe/swift.yml deleted file mode 100644 index c8812b068..000000000 --- a/etc/kayobe/swift.yml +++ /dev/null @@ -1,65 +0,0 @@ ---- -############################################################################### -# OpenStack Swift configuration. - -# Short name of the kolla container image used to build rings. Default is the -# swift=object image. -#swift_ring_build_image_name: - -# Full name of the kolla container image used to build rings. -#swift_ring_build_image: - -# Ansible host pattern matching hosts on which Swift object storage services -# are deployed. The default is to use hosts in the 'storage' group. -#swift_hosts: - -# Name of the host used to build Swift rings. Default is the first host of -# 'swift_hosts'. -#swift_ring_build_host: - -# ID of the Swift region for this host. Default is 1. -#swift_region: - -# ID of the Swift zone. This can be set to different values for different hosts -# to place them in different zones. Default is 0. -#swift_zone: - -# Base-2 logarithm of the number of partitions. -# i.e. num_partitions=2^. Default is 10. -#swift_part_power: - -# Object replication count. Default is the smaller of the number of Swift -# hosts, or 3. -#swift_replication_count: - -# Minimum time in hours between moving a given partition. Default is 1. -#swift_min_part_hours: - -# Ports on which Swift services listen. Default is: -# object: 6000 -# account: 6001 -# container: 6002 -#swift_service_ports: - -# List of block devices to use for Swift. Each item is a dict with the -# following items: -# - 'device': Block device path. Required. -# - 'fs_label': Name of the label used to create the file system on the device. -# Optional. Default is to use the basename of the device. -# - 'services': List of services that will use this block device. Optional. -# Default is 'swift_block_device_default_services'. Allowed items are -# 'account', 'container', and 'object'. -# - 'weight': Weight of the block device. Optional. Default is -# 'swift_block_device_default_weight'. -#swift_block_devices: - -# Default weight to assign to block devices in the ring. Default is 100. -#swift_block_device_default_weight: - -# Default list of services to assign block devices to. Allowed items are -# 'account', 'container', and 'object'. Default value is all of these. -#swift_block_device_default_services: - -############################################################################### -# Dummy variable to allow Ansible to accept this file. -workaround_ansible_issue_8743: yes diff --git a/kayobe/cli/commands.py b/kayobe/cli/commands.py index d6f4a9c47..49e0dccd4 100644 --- a/kayobe/cli/commands.py +++ b/kayobe/cli/commands.py @@ -2225,15 +2225,6 @@ def take_action(self, parsed_args): self.run_kayobe_playbooks(parsed_args, playbooks) -class OvercloudSwiftRingsGenerate(KayobeAnsibleMixin, VaultMixin, Command): - """Generate Swift rings.""" - - def take_action(self, parsed_args): - self.app.LOG.debug("Generating Swift rings") - playbooks = _build_playbook_list("swift-rings") - self.run_kayobe_playbooks(parsed_args, playbooks) - - class NetworkConnectivityCheck(KayobeAnsibleMixin, VaultMixin, Command): """Check network connectivity between hosts in the control plane. diff --git a/kayobe/tests/unit/cli/test_commands.py b/kayobe/tests/unit/cli/test_commands.py index 8cda090b0..a92c33cce 100644 --- a/kayobe/tests/unit/cli/test_commands.py +++ b/kayobe/tests/unit/cli/test_commands.py @@ -2410,26 +2410,6 @@ def test_overcloud_post_configure(self, mock_run): ] self.assertListEqual(expected_calls, mock_run.call_args_list) - @mock.patch.object(commands.KayobeAnsibleMixin, - "run_kayobe_playbooks") - def test_overcloud_swift_rings_generate(self, mock_run): - command = commands.OvercloudSwiftRingsGenerate(TestApp(), []) - parser = command.get_parser("test") - parsed_args = parser.parse_args([]) - - result = command.run(parsed_args) - self.assertEqual(0, result) - - expected_calls = [ - mock.call( - mock.ANY, - [ - utils.get_data_files_path("ansible", "swift-rings.yml"), - ], - ), - ] - self.assertListEqual(expected_calls, mock_run.call_args_list) - @mock.patch.object(commands.KayobeAnsibleMixin, "run_kayobe_playbooks") def test_baremetal_compute_register(self, mock_run): diff --git a/releasenotes/notes/remove-swift-support-7edf979aef2a1414.yaml b/releasenotes/notes/remove-swift-support-7edf979aef2a1414.yaml new file mode 100644 index 000000000..35cf2a17e --- /dev/null +++ b/releasenotes/notes/remove-swift-support-7edf979aef2a1414.yaml @@ -0,0 +1,7 @@ +--- +upgrade: + - | + Support for deploying Swift has been removed, following its removal from + Kolla Ansible. This includes the ``kayobe overcloud swift rings generate`` + command, the ``swift-rings`` and ``swift-block-devices`` roles, and the + associated ``swift`` inventory and configuration variables. diff --git a/setup.cfg b/setup.cfg index f4094b93c..a96bf711e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -88,7 +88,6 @@ kayobe.cli= overcloud_service_reconfigure = kayobe.cli.commands:OvercloudServiceReconfigure overcloud_service_stop = kayobe.cli.commands:OvercloudServiceStop overcloud_service_upgrade = kayobe.cli.commands:OvercloudServiceUpgrade - overcloud_swift_rings_generate = kayobe.cli.commands:OvercloudSwiftRingsGenerate physical_network_configure = kayobe.cli.commands:PhysicalNetworkConfigure playbook_run = kayobe.cli.commands:PlaybookRun seed_container_image_build = kayobe.cli.commands:SeedContainerImageBuild @@ -213,8 +212,6 @@ kayobe.cli.overcloud_service_stop = hooks = kayobe.cli.commands:HookDispatcher kayobe.cli.overcloud_service_upgrade = hooks = kayobe.cli.commands:HookDispatcher -kayobe.cli.overcloud_swift_rings_generate = - hooks = kayobe.cli.commands:HookDispatcher kayobe.cli.overcloud_passwords_view = hooks = kayobe.cli.commands:HookDispatcher kayobe.cli.physical_network_configure = From 1ca3389ffdd71a6252d0e347c7bc730534d05896 Mon Sep 17 00:00:00 2001 From: Thomas Sell Date: Mon, 28 Sep 2026 13:45:05 +0200 Subject: [PATCH 08/19] Fix Dell OS9 switch config indentation Closes-Bug: #2168744 Related-Change: I961c71a3bcde1511604f34cc8caf5e8648d5bcb3 Change-Id: I822820ac0fd87221c4d24557b82de70e954e4a50 Signed-off-by: Thomas Sell --- ansible/roles/dell-switch/templates/dellos9-config.j2 | 4 +--- releasenotes/notes/bug-2168744-d0872c5d71c4e76f.yaml | 5 +++++ 2 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 releasenotes/notes/bug-2168744-d0872c5d71c4e76f.yaml diff --git a/ansible/roles/dell-switch/templates/dellos9-config.j2 b/ansible/roles/dell-switch/templates/dellos9-config.j2 index 6108e9a0d..422116269 100644 --- a/ansible/roles/dell-switch/templates/dellos9-config.j2 +++ b/ansible/roles/dell-switch/templates/dellos9-config.j2 @@ -10,14 +10,13 @@ {% for interface, config in dell_switch_interface_config.items() %} {% if 'vlan' not in interface %} - interface {{ interface }} +interface {{ interface }} {% if config.description is defined %} description "{{ config.description }}" {% endif %} {% for line in config.config %} {{ line }} {% endfor %} - exit {% endif %} {% endfor %} @@ -30,6 +29,5 @@ interface {{ interface }} {% for line in config.config %} {{ line }} {% endfor %} - exit {% endif %} {% endfor %} diff --git a/releasenotes/notes/bug-2168744-d0872c5d71c4e76f.yaml b/releasenotes/notes/bug-2168744-d0872c5d71c4e76f.yaml new file mode 100644 index 000000000..710a55461 --- /dev/null +++ b/releasenotes/notes/bug-2168744-d0872c5d71c4e76f.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + Fixes Dell OS9 switch config. + `LP#2168744 `__ From c8229e4a0b9a015e690e0021710132c518721a40 Mon Sep 17 00:00:00 2001 From: Thomas Sell Date: Fri, 25 Sep 2026 15:16:04 +0200 Subject: [PATCH 09/19] Fix Dell OS10 switch config indentation Closes-Bug: #2168529 Change-Id: I961c71a3bcde1511604f34cc8caf5e8648d5bcb3 Signed-off-by: Thomas Sell --- .../dell-switch/templates/dellos10-config.j2 | 21 ++++++++++++++++--- .../notes/bug-2168529-b206bb5ace7090b3.yaml | 7 +++++++ 2 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 releasenotes/notes/bug-2168529-b206bb5ace7090b3.yaml diff --git a/ansible/roles/dell-switch/templates/dellos10-config.j2 b/ansible/roles/dell-switch/templates/dellos10-config.j2 index 7904f89c6..0fcbec176 100644 --- a/ansible/roles/dell-switch/templates/dellos10-config.j2 +++ b/ansible/roles/dell-switch/templates/dellos10-config.j2 @@ -4,13 +4,28 @@ {{ line }} {% endfor %} +{# Configure VLAN interfaces first as others might depend on them. #} + {% for interface, config in dell_switch_interface_config.items() %} +{% if 'vlan' in interface %} interface {{ interface }} {% if config.description is defined %} -description "{{ config.description }}" + description "{{ config.description }}" {% endif %} {% for line in config.config %} -{{ line }} + {{ line }} +{% endfor %} +{% endif %} +{% endfor %} + +{% for interface, config in dell_switch_interface_config.items() %} +{% if 'vlan' not in interface %} +interface {{ interface }} +{% if config.description is defined %} + description "{{ config.description }}" +{% endif %} +{% for line in config.config %} + {{ line }} {% endfor %} -exit +{% endif %} {% endfor %} diff --git a/releasenotes/notes/bug-2168529-b206bb5ace7090b3.yaml b/releasenotes/notes/bug-2168529-b206bb5ace7090b3.yaml new file mode 100644 index 000000000..4ebe5e7fd --- /dev/null +++ b/releasenotes/notes/bug-2168529-b206bb5ace7090b3.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + Fixes Dell OS10 switch config. Also makes sure that VLAN interfaces are + defined first as others might depend on them. + + `LP#2168529 `__ From df758eef25730bd3c8a7f6dfbaed414c8f0c479d Mon Sep 17 00:00:00 2001 From: Thomas Sell Date: Fri, 25 Sep 2026 19:49:19 +0200 Subject: [PATCH 10/19] Fix Dell OS10 switch port changed status with whitespaces Closes-Bug: #2168557 Related-Change: I70e39d10c592639d0ae20080459babd6cdf5980a Change-Id: Ib793160210ab6c08bf3f3ea4514de83df2573acc Signed-off-by: Thomas Sell --- ansible/roles/dell-switch/templates/dellos10-config.j2 | 4 ++-- releasenotes/notes/bug-2168557-2a1748c41ec3b28f.yaml | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 releasenotes/notes/bug-2168557-2a1748c41ec3b28f.yaml diff --git a/ansible/roles/dell-switch/templates/dellos10-config.j2 b/ansible/roles/dell-switch/templates/dellos10-config.j2 index 0fcbec176..1aa4b212d 100644 --- a/ansible/roles/dell-switch/templates/dellos10-config.j2 +++ b/ansible/roles/dell-switch/templates/dellos10-config.j2 @@ -10,7 +10,7 @@ {% if 'vlan' in interface %} interface {{ interface }} {% if config.description is defined %} - description "{{ config.description }}" + description {{ ('"' ~ config.description ~ '"') if ' ' in config.description else config.description }} {% endif %} {% for line in config.config %} {{ line }} @@ -22,7 +22,7 @@ interface {{ interface }} {% if 'vlan' not in interface %} interface {{ interface }} {% if config.description is defined %} - description "{{ config.description }}" + description {{ ('"' ~ config.description ~ '"') if ' ' in config.description else config.description }} {% endif %} {% for line in config.config %} {{ line }} diff --git a/releasenotes/notes/bug-2168557-2a1748c41ec3b28f.yaml b/releasenotes/notes/bug-2168557-2a1748c41ec3b28f.yaml new file mode 100644 index 000000000..230656d40 --- /dev/null +++ b/releasenotes/notes/bug-2168557-2a1748c41ec3b28f.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Fixes regression causing DellOS10 switch config tasks to always change + description strings if there are not whitespace characters. + `LP#2168557 `__ From b321ba30d5a2d523e109285b92813951888b1599 Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Mon, 21 Sep 2026 16:44:36 +0000 Subject: [PATCH 11/19] Wait for firewalld to be ready before configuring Starting the firewalld service does not guarantee that its D-Bus interface is available. The firewalld Ansible module decides whether to use online or offline (on-disk only) operations when it is imported. If the first zone is created before the interface is ready, it is written to disk only and is not loaded into the running daemon. Assigning an interface to that zone later then fails with INVALID_ZONE. Wait until firewalld can be queried before creating zones. Closes-Bug: #2167866 Generated-By: opencode deepseek-v4-pro Change-Id: I40ec20cd9831f5c8e4fa4b05ca247f5bf1682a31 Signed-off-by: Will Szumski --- ansible/roles/firewalld/tasks/enabled.yml | 17 +++++++++++++++++ .../firewalld-wait-ready-7a1c2d9e4f6b8a30.yaml | 9 +++++++++ 2 files changed, 26 insertions(+) create mode 100644 releasenotes/notes/firewalld-wait-ready-7a1c2d9e4f6b8a30.yaml diff --git a/ansible/roles/firewalld/tasks/enabled.yml b/ansible/roles/firewalld/tasks/enabled.yml index 1ab86bcd6..4428c8b27 100644 --- a/ansible/roles/firewalld/tasks/enabled.yml +++ b/ansible/roles/firewalld/tasks/enabled.yml @@ -13,6 +13,23 @@ state: started become: true +# NOTE: The firewalld Ansible module decides whether to use online or offline +# (on-disk only) operations when it is imported, based on whether the firewalld +# D-Bus interface is available. Starting the service does not guarantee that +# the interface is ready yet, so if the first zone is created too early it is +# written to disk only and is not loaded into the running daemon. A subsequent +# attempt to assign an interface to that zone then fails with +# 'INVALID_ZONE'. Wait until firewalld can be queried before configuring it. +- name: Wait for firewalld to be ready + command: + cmd: firewall-cmd --state + register: firewalld_state + until: firewalld_state.rc == 0 + retries: 30 + delay: 1 + changed_when: false + become: true + - block: - name: Get firewalld current default zone command: diff --git a/releasenotes/notes/firewalld-wait-ready-7a1c2d9e4f6b8a30.yaml b/releasenotes/notes/firewalld-wait-ready-7a1c2d9e4f6b8a30.yaml new file mode 100644 index 000000000..76b0bcba0 --- /dev/null +++ b/releasenotes/notes/firewalld-wait-ready-7a1c2d9e4f6b8a30.yaml @@ -0,0 +1,9 @@ +--- +fixes: + - | + Fixes a race when configuring firewalld that could cause host + configuration to fail with ``INVALID_ZONE`` for a zone that was created + while firewalld was still starting up. The firewalld role now waits until + the firewalld D-Bus interface is ready before creating zones, ensuring + that they are applied to the running daemon rather than only to the + on-disk configuration. From f15aed133236739e99cf2384863e058570ccbf40 Mon Sep 17 00:00:00 2001 From: Pierre Riteau Date: Mon, 28 Sep 2026 20:24:58 +0200 Subject: [PATCH 12/19] Remove extra line break in release note Change-Id: I4defaad596922113f472134c3ef1a24ea38cf057 Signed-off-by: Pierre Riteau --- releasenotes/notes/bug-2168529-b206bb5ace7090b3.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/releasenotes/notes/bug-2168529-b206bb5ace7090b3.yaml b/releasenotes/notes/bug-2168529-b206bb5ace7090b3.yaml index 4ebe5e7fd..d06aaa964 100644 --- a/releasenotes/notes/bug-2168529-b206bb5ace7090b3.yaml +++ b/releasenotes/notes/bug-2168529-b206bb5ace7090b3.yaml @@ -3,5 +3,4 @@ fixes: - | Fixes Dell OS10 switch config. Also makes sure that VLAN interfaces are defined first as others might depend on them. - `LP#2168529 `__ From 94b04e458f8cf462f1d582db6fe593d1fb00ae01 Mon Sep 17 00:00:00 2001 From: Pierre Riteau Date: Mon, 28 Sep 2026 22:15:53 +0200 Subject: [PATCH 13/19] Revert "CI: Make Ubuntu overcloud upgrade job periodic" This reverts commit 72eab43b3f142837e646f62934346324c239f775. Change-Id: I93c09c222ecac9ac1f43d35c9d1c4d9b88fd7121 Signed-off-by: Pierre Riteau --- zuul.d/project.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml index 70b618334..b10876f99 100644 --- a/zuul.d/project.yaml +++ b/zuul.d/project.yaml @@ -29,6 +29,7 @@ - kayobe-overcloud-ubuntu-noble - kayobe-overcloud-ubuntu-noble-podman - kayobe-overcloud-upgrade-rocky10 + - kayobe-overcloud-upgrade-ubuntu-noble - kayobe-seed-rocky10 - kayobe-seed-rocky10-podman - kayobe-seed-ubuntu-noble @@ -57,6 +58,7 @@ - kayobe-overcloud-ubuntu-noble - kayobe-overcloud-ubuntu-noble-podman - kayobe-overcloud-upgrade-rocky10 + - kayobe-overcloud-upgrade-ubuntu-noble - kayobe-seed-rocky10 - kayobe-seed-rocky10-podman - kayobe-seed-ubuntu-noble @@ -89,6 +91,3 @@ - kayobe-seed-vm-rocky10-q35 - kayobe-seed-vm-ubuntu-noble-cloud-image - kayobe-seed-vm-ubuntu-noble-q35 - periodic: - jobs: - - kayobe-overcloud-upgrade-ubuntu-noble From 503a914a02984d8c54208c9c286213e789a7dca1 Mon Sep 17 00:00:00 2001 From: Pierre Riteau Date: Mon, 28 Sep 2026 23:13:15 +0200 Subject: [PATCH 14/19] Revert "CI: Skip previous release testing for Ubuntu" This reverts commit 2f33a2812e75cee27160df27404ac88036945a58. Change-Id: Id5b5567bd53aa2a7117cc0d19598d1710e819179 Signed-off-by: Pierre Riteau --- playbooks/kayobe-overcloud-upgrade-base/run.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/playbooks/kayobe-overcloud-upgrade-base/run.yml b/playbooks/kayobe-overcloud-upgrade-base/run.yml index 318432e67..123d5686b 100644 --- a/playbooks/kayobe-overcloud-upgrade-base/run.yml +++ b/playbooks/kayobe-overcloud-upgrade-base/run.yml @@ -76,14 +76,12 @@ cmd: dev/overcloud-test-vm.sh &> {{ logs_dir }}/ansible/overcloud-test-vm-pre-upgrade chdir: "{{ previous_kayobe_src_dir }}" executable: /bin/bash - when: ansible_facts.os_family != 'Debian' - name: Perform testing of the baremetal machines in the overcloud prior to upgrade shell: cmd: dev/overcloud-test-baremetal.sh &> {{ logs_dir }}/ansible/overcloud-test-bm-pre-upgrade chdir: "{{ previous_kayobe_src_dir }}" executable: /bin/bash - when: ansible_facts.os_family != 'Debian' # Upgrade Kayobe, and use it to perform an upgrade of the control plane. From 36086e164c1938028c46d60773e86dcb5566e661 Mon Sep 17 00:00:00 2001 From: Thomas Sell Date: Fri, 25 Sep 2026 16:11:06 +0200 Subject: [PATCH 15/19] Fix Dell switch config task changed status Closes-Bug: #2168538 Change-Id: Id5e822c9df9fa60345a40647e0a97763d4fda233 Signed-off-by: Thomas Sell --- ansible/roles/dell-switch/handlers/main.yml | 15 +++++++++++++++ ansible/roles/dell-switch/tasks/main.yml | 6 +++--- .../notes/bug-2168538-2c528e265fe6ce6c.yaml | 7 +++++++ 3 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 ansible/roles/dell-switch/handlers/main.yml create mode 100644 releasenotes/notes/bug-2168538-2c528e265fe6ce6c.yaml diff --git a/ansible/roles/dell-switch/handlers/main.yml b/ansible/roles/dell-switch/handlers/main.yml new file mode 100644 index 000000000..cb37f2201 --- /dev/null +++ b/ansible/roles/dell-switch/handlers/main.yml @@ -0,0 +1,15 @@ +--- +- name: Save DellOS6 running-config to startup-config + dellemc.os6.os6_config: # noqa fqcn[canonical] + save: true + when: dell_switch_save | bool + +- name: Save DellOS9 running-config to startup-config + dellemc.os9.os9_config: # noqa fqcn[canonical] + save: true + when: dell_switch_save | bool + +- name: Save DellOS10 running-config to startup-config + dellemc.os10.os10_config: # noqa fqcn[canonical] + save: true + when: dell_switch_save | bool diff --git a/ansible/roles/dell-switch/tasks/main.yml b/ansible/roles/dell-switch/tasks/main.yml index 2f7620ee8..c9f7aa86d 100644 --- a/ansible/roles/dell-switch/tasks/main.yml +++ b/ansible/roles/dell-switch/tasks/main.yml @@ -2,17 +2,17 @@ - name: Ensure DellOS6 switches are configured dellemc.os6.os6_config: # noqa fqcn[canonical] src: "../templates/dellos6-config.j2" - save: "{{ dell_switch_save | bool }}" + notify: Save DellOS6 running-config to startup-config when: dell_switch_type == 'dellos6' - name: Ensure DellOS9 switches are configured dellemc.os9.os9_config: # noqa fqcn[canonical] src: "../templates/dellos9-config.j2" - save: "{{ dell_switch_save | bool }}" + notify: Save DellOS9 running-config to startup-config when: dell_switch_type == 'dellos9' - name: Ensure DellOS10 switches are configured dellemc.os10.os10_config: # noqa fqcn[canonical] src: "../templates/dellos10-config.j2" - save: "{{ dell_switch_save | bool }}" + notify: Save DellOS10 running-config to startup-config when: dell_switch_type == 'dellos10' diff --git a/releasenotes/notes/bug-2168538-2c528e265fe6ce6c.yaml b/releasenotes/notes/bug-2168538-2c528e265fe6ce6c.yaml new file mode 100644 index 000000000..78b8ca0f6 --- /dev/null +++ b/releasenotes/notes/bug-2168538-2c528e265fe6ce6c.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + Fixes Dell switch configuration tasks always reporting as ``changed`` when + saving switch configuration was enabled. Switch configuration is now saved + only when changes have been made. + `LP#2168538 `__ From ee6d553444ea59ef5a2892e35a78572327b8822d Mon Sep 17 00:00:00 2001 From: Pierre Riteau Date: Tue, 29 Sep 2026 14:29:46 +0200 Subject: [PATCH 16/19] Bump community.docker to 5.3.0 Change-Id: I20e816b1828d0673f82e065a656d919e2439545b Signed-off-by: Pierre Riteau --- requirements.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.yml b/requirements.yml index 17ce80ed9..5565ead34 100644 --- a/requirements.yml +++ b/requirements.yml @@ -4,7 +4,7 @@ collections: type: git version: master - name: community.docker - version: 5.2.0 + version: 5.3.0 - name: community.network version: 5.1.0 - name: dellemc.enterprise_sonic From db16de58e3d133bdd172322b92acd8efe3600bd9 Mon Sep 17 00:00:00 2001 From: Bartosz Bezak Date: Tue, 22 Sep 2026 14:19:07 +0200 Subject: [PATCH 17/19] Add support for Cisco NX-OS switches Change-Id: I29197e80e9fd5e990f20a74f4a63dbfb24df968b Signed-off-by: Bartosz Bezak --- ansible/physical-network.yml | 17 ++++++ ansible/roles/cisco-nxos-switch/README.md | 59 +++++++++++++++++++ .../roles/cisco-nxos-switch/defaults/main.yml | 11 ++++ .../roles/cisco-nxos-switch/tasks/main.yml | 6 ++ .../templates/cisco-nxos-config.j2 | 16 +++++ .../reference/physical-network.rst | 39 ++++++++++++ ...-nxos-switch-support-6ef2c747d24e5197.yaml | 6 ++ requirements.yml | 2 + 8 files changed, 156 insertions(+) create mode 100644 ansible/roles/cisco-nxos-switch/README.md create mode 100644 ansible/roles/cisco-nxos-switch/defaults/main.yml create mode 100644 ansible/roles/cisco-nxos-switch/tasks/main.yml create mode 100644 ansible/roles/cisco-nxos-switch/templates/cisco-nxos-config.j2 create mode 100644 releasenotes/notes/add-cisco-nxos-switch-support-6ef2c747d24e5197.yaml diff --git a/ansible/physical-network.yml b/ansible/physical-network.yml index 8891a62c5..c9e411f11 100644 --- a/ansible/physical-network.yml +++ b/ansible/physical-network.yml @@ -29,6 +29,7 @@ # List of supported values for the 'switch_type' variable. supported_switch_types: - arista + - cisco-nxos - dellos6 - dellos9 - dellos10 @@ -126,6 +127,22 @@ arista_switch_config: "{{ switch_config }}" arista_switch_interface_config: "{{ switch_interface_config }}" +- name: Ensure Cisco NX-OS physical switches are configured + hosts: switches_of_type_cisco-nxos:&switches_in_display_mode_False + gather_facts: no + max_fail_percentage: >- + {{ physical_network_max_fail_percentage | + default(kayobe_max_fail_percentage) | + default(100) }} + roles: + - role: ssh-known-host + when: not switch_skip_keyscan | bool + + - role: cisco-nxos-switch + cisco_nxos_switch_config: "{{ switch_config }}" + cisco_nxos_switch_interface_config: "{{ switch_interface_config }}" + cisco_nxos_switch_save: "{{ switch_config_save }}" + - name: Ensure DellOS physical switches are configured hosts: switches_of_type_dellos6:switches_of_type_dellos9:switches_of_type_dellos10:&switches_in_display_mode_False gather_facts: no diff --git a/ansible/roles/cisco-nxos-switch/README.md b/ansible/roles/cisco-nxos-switch/README.md new file mode 100644 index 000000000..e51f59cdd --- /dev/null +++ b/ansible/roles/cisco-nxos-switch/README.md @@ -0,0 +1,59 @@ +Cisco NX-OS Switch +================== + +This role configures Cisco NX-OS switches using the `cisco.nxos.nxos_config` +Ansible module. It allows global and per-interface configuration commands to +be applied to the switch. + +Requirements +------------ + +The switches should be configured to allow SSH access. + +The `cisco.nxos` Ansible collection must be installed. + +Role Variables +-------------- + +`cisco_nxos_switch_config` is a list of configuration lines to apply to the +switch, and defaults to an empty list. + +`cisco_nxos_switch_interface_config` is a dict mapping switch interface names +to configuration dicts, and defaults to an empty dict. Each dict contains: + +- `description` - an optional description to apply to the interface. +- `config` - a list of per-interface configuration commands. + +`cisco_nxos_switch_save` controls whether the running configuration is saved +to the startup configuration when they differ, including any previously unsaved +changes. Defaults to `false`. + +Dependencies +------------ + +None + +Example Playbook +---------------- + +The following playbook configures hosts in the `cisco-nxos-switches` group. +It assumes host variables for each switch holding the host and SSH credentials. +It enables LLDP and configures an Ethernet interface as a switchport. + + --- + - name: Ensure Cisco NX-OS switches are configured + hosts: cisco-nxos-switches + gather_facts: no + vars: + ansible_connection: ansible.netcommon.network_cli + ansible_network_os: cisco.nxos.nxos + roles: + - role: cisco-nxos-switch + cisco_nxos_switch_config: + - "feature lldp" + cisco_nxos_switch_interface_config: + Ethernet1/1: + description: server-1 + config: + - "switchport" + - "switchport mode access" diff --git a/ansible/roles/cisco-nxos-switch/defaults/main.yml b/ansible/roles/cisco-nxos-switch/defaults/main.yml new file mode 100644 index 000000000..8356cac5a --- /dev/null +++ b/ansible/roles/cisco-nxos-switch/defaults/main.yml @@ -0,0 +1,11 @@ +--- +# List of configuration lines to apply to the switch. +cisco_nxos_switch_config: [] + +# Interface configuration. Dict mapping switch interface names to configuration +# dicts. Each dict contains an optional 'description' item and a 'config' item +# which should contain a list of per-interface configuration. +cisco_nxos_switch_interface_config: {} + +# Whether to save the configuration. +cisco_nxos_switch_save: false diff --git a/ansible/roles/cisco-nxos-switch/tasks/main.yml b/ansible/roles/cisco-nxos-switch/tasks/main.yml new file mode 100644 index 000000000..beb5cd07b --- /dev/null +++ b/ansible/roles/cisco-nxos-switch/tasks/main.yml @@ -0,0 +1,6 @@ +--- +- name: Ensure Cisco NX-OS switches are configured + cisco.nxos.nxos_config: + content: "{{ lookup('template', 'cisco-nxos-config.j2') }}" + save_when: >- + {{ cisco_nxos_switch_save | bool | ternary('modified', 'never') }} diff --git a/ansible/roles/cisco-nxos-switch/templates/cisco-nxos-config.j2 b/ansible/roles/cisco-nxos-switch/templates/cisco-nxos-config.j2 new file mode 100644 index 000000000..d219991f9 --- /dev/null +++ b/ansible/roles/cisco-nxos-switch/templates/cisco-nxos-config.j2 @@ -0,0 +1,16 @@ +#jinja2: trim_blocks: True,lstrip_blocks: True + +{% for line in cisco_nxos_switch_config %} +{{ line }} +{% endfor %} + +{% for interface, config in cisco_nxos_switch_interface_config.items() %} +interface {{ interface }} +{% if config.description is defined %} + description {{ config.description }} +{% endif %} +{% for line in config.config %} + {{ line }} +{% endfor %} +! +{% endfor %} diff --git a/doc/source/configuration/reference/physical-network.rst b/doc/source/configuration/reference/physical-network.rst index ff00a60c8..2cd3815bf 100644 --- a/doc/source/configuration/reference/physical-network.rst +++ b/doc/source/configuration/reference/physical-network.rst @@ -15,6 +15,7 @@ configure`` command. See :ref:`physical-network` for details. The following switch operating systems are currently supported: * Arista EOS +* Cisco NX-OS * Cumulus Linux (via `Network Command Line Utility (NCLU) `__) * Cumulus Linux (via `NVIDIA User Experience command line utility (NVUE) @@ -213,6 +214,44 @@ modules. * ``ansible_become`` should be ``true``. * ``ansible_become_method`` should be ``enable``. +Cisco NX-OS +----------- + +Configuration for these devices is applied using the ``cisco-nxos-switch`` +Ansible role in Kayobe. The role configures Cisco NX-OS switches using the +``cisco.nxos.nxos_config`` Ansible module. + +``switch_type`` should be set to ``cisco-nxos``. + +``switch_config_save`` may be set to ``true`` to save the running configuration +to the startup configuration when they differ, including any previously unsaved +changes. + +* ``ansible_host`` is the hostname or IP address. Optional. +* ``ansible_user`` is the SSH username. +* ``ansible_ssh_pass`` is the SSH password, if using password authentication. +* ``ansible_connection`` should be ``ansible.netcommon.network_cli``. +* ``ansible_network_os`` should be ``cisco.nxos.nxos``. + +The SSH user must have permission to configure the switch. + +For example, the following host variables enable LLDP and configure a +switchport: + +.. code-block:: yaml + + switch_type: cisco-nxos + ansible_connection: ansible.netcommon.network_cli + ansible_network_os: cisco.nxos.nxos + switch_config: + - "feature lldp" + switch_interface_config: + Ethernet1/1: + description: server-1 + config: + - "switchport" + - "switchport mode access" + Cumulus Linux (with NCLU) ------------------------- diff --git a/releasenotes/notes/add-cisco-nxos-switch-support-6ef2c747d24e5197.yaml b/releasenotes/notes/add-cisco-nxos-switch-support-6ef2c747d24e5197.yaml new file mode 100644 index 000000000..7886998b7 --- /dev/null +++ b/releasenotes/notes/add-cisco-nxos-switch-support-6ef2c747d24e5197.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Adds support for configuring Cisco NX-OS switches with + ``kayobe physical network configure``. Set ``switch_type`` to + ``cisco-nxos`` to use this support. diff --git a/requirements.yml b/requirements.yml index 17ce80ed9..19873e98b 100644 --- a/requirements.yml +++ b/requirements.yml @@ -3,6 +3,8 @@ collections: - name: https://opendev.org/openstack/ansible-collection-kolla type: git version: master + - name: cisco.nxos + version: 13.0.0 - name: community.docker version: 5.2.0 - name: community.network From a3716f95b63295904fecd9788768f302e8329a73 Mon Sep 17 00:00:00 2001 From: Pierre Riteau Date: Wed, 30 Sep 2026 08:13:59 +0200 Subject: [PATCH 18/19] Add support for AlliedWare Plus switches Change-Id: I2095a27a1a386d88f8e1a8c665074fbd6652ab67 Signed-off-by: Pierre Riteau --- ansible/physical-network.yml | 17 ++++ .../roles/alliedware-plus-switch/README.md | 79 +++++++++++++++++++ .../alliedware-plus-switch/defaults/main.yml | 11 +++ .../alliedware-plus-switch/tasks/main.yml | 6 ++ .../templates/alliedware-plus-config.j2 | 15 ++++ .../reference/physical-network.rst | 23 ++++++ ...liedware-plus-switch-75625ad2e5d61241.yaml | 5 ++ requirements.yml | 2 + 8 files changed, 158 insertions(+) create mode 100644 ansible/roles/alliedware-plus-switch/README.md create mode 100644 ansible/roles/alliedware-plus-switch/defaults/main.yml create mode 100644 ansible/roles/alliedware-plus-switch/tasks/main.yml create mode 100644 ansible/roles/alliedware-plus-switch/templates/alliedware-plus-config.j2 create mode 100644 releasenotes/notes/alliedware-plus-switch-75625ad2e5d61241.yaml diff --git a/ansible/physical-network.yml b/ansible/physical-network.yml index 8891a62c5..292776eae 100644 --- a/ansible/physical-network.yml +++ b/ansible/physical-network.yml @@ -28,6 +28,7 @@ physical_network_display: False # List of supported values for the 'switch_type' variable. supported_switch_types: + - alliedware-plus - arista - dellos6 - dellos9 @@ -109,6 +110,22 @@ debug: var: switch_interface_config +- name: Ensure AlliedWare Plus physical switches are configured + hosts: switches_of_type_alliedware-plus:&switches_in_display_mode_False + gather_facts: no + max_fail_percentage: >- + {{ physical_network_max_fail_percentage | + default(kayobe_max_fail_percentage) | + default(100) }} + roles: + - role: ssh-known-host + when: not switch_skip_keyscan | bool + + - role: alliedware-plus-switch + alliedware_plus_switch_config: "{{ switch_config }}" + alliedware_plus_switch_interface_config: "{{ switch_interface_config }}" + alliedware_plus_switch_save: "{{ switch_config_save }}" + - name: Ensure Arista physical switches are configured hosts: switches_of_type_arista:&switches_in_display_mode_False gather_facts: no diff --git a/ansible/roles/alliedware-plus-switch/README.md b/ansible/roles/alliedware-plus-switch/README.md new file mode 100644 index 000000000..4b5290336 --- /dev/null +++ b/ansible/roles/alliedware-plus-switch/README.md @@ -0,0 +1,79 @@ +AlliedWare Plus Switch +====================== + +This role configures AlliedWare Plus switches using the +`alliedtelesis.awplus.awplus_config` Ansible module. It provides a fairly +minimal abstraction of the configuration interface provided by the +`awplus_config` module, allowing for application of arbitrary switch +configuration options. + +Requirements +------------ + +The switches should be configured to allow SSH access. + +The `alliedtelesis.awplus` Ansible collection must be installed. + +Role Variables +-------------- + +`alliedware_plus_switch_config` is a list of configuration lines to apply to +the switch, and defaults to an empty list. + +`alliedware_plus_switch_interface_config` contains interface configuration. It +is a dict mapping switch interface names to configuration dicts, and defaults +to an empty dict. Each dict may contain the following items: + +- `description` - an optional description to apply to the interface. +- `config` - a list of per-interface configuration commands. + +`alliedware_plus_switch_save` controls whether the running configuration is +saved to the startup configuration when they differ, including any previously +unsaved changes. Defaults to `false`. + +Dependencies +------------ + +None + +Example Playbook +---------------- + +The following playbook configures hosts in the `alliedware-plus-switches` +group. It assumes host variables for each switch holding the host and SSH +credentials. + + --- + - name: Ensure AlliedWare Plus switches are configured + hosts: alliedware-plus-switches + gather_facts: no + vars: + ansible_connection: ansible.netcommon.network_cli + ansible_network_os: alliedtelesis.awplus.awplus + roles: + - role: alliedware-plus-switch + alliedware_plus_switch_config: + - "vlan database" + - " vlan 1000,1001 state enable" + alliedware_plus_switch_interface_config: + port1.0.1: + description: server-1 + config: + - "no shutdown" + - "switchport" + - "switchport mode trunk" + - "switchport trunk native vlan 1000" + - "switchport trunk allowed vlan add 1001" + port1.0.2: + description: server-2 + config: + - "no shutdown" + - "switchport" + - "switchport mode trunk" + - "switchport trunk native vlan 1000" + - "switchport trunk allowed vlan add 1001" + +Author Information +------------------ + +- Pierre Riteau () diff --git a/ansible/roles/alliedware-plus-switch/defaults/main.yml b/ansible/roles/alliedware-plus-switch/defaults/main.yml new file mode 100644 index 000000000..3a1e6556c --- /dev/null +++ b/ansible/roles/alliedware-plus-switch/defaults/main.yml @@ -0,0 +1,11 @@ +--- +# List of configuration lines to apply to the switch. +alliedware_plus_switch_config: [] + +# Interface configuration. Dict mapping switch interface names to configuration +# dicts. Each dict contains an optional 'description' item and a 'config' item +# which should contain a list of per-interface configuration. +alliedware_plus_switch_interface_config: {} + +# Whether to save the configuration. +alliedware_plus_switch_save: false diff --git a/ansible/roles/alliedware-plus-switch/tasks/main.yml b/ansible/roles/alliedware-plus-switch/tasks/main.yml new file mode 100644 index 000000000..ceb0d434c --- /dev/null +++ b/ansible/roles/alliedware-plus-switch/tasks/main.yml @@ -0,0 +1,6 @@ +--- +- name: Ensure AlliedWare Plus switches are configured + alliedtelesis.awplus.awplus_config: + lines: "{{ lookup('template', 'alliedware-plus-config.j2') }}" + save_when: >- + {{ alliedware_plus_switch_save | bool | ternary('modified', 'never') }} diff --git a/ansible/roles/alliedware-plus-switch/templates/alliedware-plus-config.j2 b/ansible/roles/alliedware-plus-switch/templates/alliedware-plus-config.j2 new file mode 100644 index 000000000..e1138bb9e --- /dev/null +++ b/ansible/roles/alliedware-plus-switch/templates/alliedware-plus-config.j2 @@ -0,0 +1,15 @@ +#jinja2: trim_blocks: True,lstrip_blocks: True + +{% for line in alliedware_plus_switch_config %} +{{ line }} +{% endfor %} + +{% for interface, config in alliedware_plus_switch_interface_config.items() %} +interface {{ interface }} +{% if config.description is defined %} + description {{ config.description }} +{% endif %} +{% for line in config.config %} + {{ line }} +{% endfor %} +{% endfor %} diff --git a/doc/source/configuration/reference/physical-network.rst b/doc/source/configuration/reference/physical-network.rst index ff00a60c8..5b586f318 100644 --- a/doc/source/configuration/reference/physical-network.rst +++ b/doc/source/configuration/reference/physical-network.rst @@ -14,6 +14,7 @@ configure`` command. See :ref:`physical-network` for details. The following switch operating systems are currently supported: +* AlliedWare Plus * Arista EOS * Cumulus Linux (via `Network Command Line Utility (NCLU) `__) @@ -196,6 +197,28 @@ hosts file on the Ansible control host will need to be populated manually. Device-specific Configuration Variables ======================================= +AlliedWare Plus +--------------- + +Configuration for these devices is applied using the ``alliedware-plus-switch`` +Ansible role in Kayobe. The role configures AlliedWare Plus switches using the +``alliedtelesis.awplus`` Ansible modules. + +``switch_type`` should be set to ``alliedware-plus``. + + +``switch_config_save`` may be set to ``true`` to save the running configuration +to the startup configuration when they differ, including any previously unsaved +changes. + +* ``ansible_host`` is the hostname or IP address. Optional. +* ``ansible_user`` is the SSH username. +* ``ansible_ssh_pass`` is the SSH password. +* ``ansible_connection`` should be ``ansible.netcommon.network_cli``. +* ``ansible_network_os`` should be ``alliedtelesis.awplus.awplus``. +* ``ansible_become`` should be ``true``. +* ``ansible_become_method`` should be ``enable``. + Arista EOS ---------- diff --git a/releasenotes/notes/alliedware-plus-switch-75625ad2e5d61241.yaml b/releasenotes/notes/alliedware-plus-switch-75625ad2e5d61241.yaml new file mode 100644 index 000000000..1dd97cd60 --- /dev/null +++ b/releasenotes/notes/alliedware-plus-switch-75625ad2e5d61241.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Adds support for configuration of AlliedWare Plus switches. This is + integrated with the ``kayobe physical network configure`` command. diff --git a/requirements.yml b/requirements.yml index 17ce80ed9..ccb4b2db7 100644 --- a/requirements.yml +++ b/requirements.yml @@ -1,5 +1,7 @@ --- collections: + - name: alliedtelesis.awplus + version: 1.3.0 - name: https://opendev.org/openstack/ansible-collection-kolla type: git version: master From f2335651930b6baf8e97a2841cdfcb441c87b7af Mon Sep 17 00:00:00 2001 From: Pierre Riteau Date: Thu, 1 Oct 2026 10:49:23 +0200 Subject: [PATCH 19/19] Synchronise network configuration variables Change-Id: I4af7b41aa4abcd118274b1233bfd028fbc7a25f3 Signed-off-by: Pierre Riteau --- ansible/inventory/group_vars/all/network | 8 +++++--- etc/kayobe/networks.yml | 8 +++++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/ansible/inventory/group_vars/all/network b/ansible/inventory/group_vars/all/network index 402eb44f8..f5500bf91 100644 --- a/ansible/inventory/group_vars/all/network +++ b/ansible/inventory/group_vars/all/network @@ -1,12 +1,14 @@ --- +# Kayobe network configuration. + ############################################################################### # Network role to network name mappings. # Name of the network used for admin access to the overcloud admin_oc_net_name: "{{ provision_oc_net_name }}" -# Name of the network used by the overcloud hosts to manage the bare metal -# compute hosts via their out-of-band management controllers. +# Name of the network used by the seed to manage the bare metal overcloud +# hosts via their out-of-band management controllers. oob_oc_net_name: 'oob_oc_net' # Name of the network used by the seed to provision the bare metal overcloud @@ -52,7 +54,7 @@ inspection_net_name: "{{ 'inspection_net' if kolla_enable_ironic | bool else Non cleaning_net_name: "{{ provision_wl_net_name }}" ############################################################################### -# Network interface naming conventions. +# Network virtual patch link configuration. # Suffix for Open vSwitch bridge names. network_bridge_suffix_ovs: '-ovs' diff --git a/etc/kayobe/networks.yml b/etc/kayobe/networks.yml index f8e4f6331..a7fe9b77a 100644 --- a/etc/kayobe/networks.yml +++ b/etc/kayobe/networks.yml @@ -2,7 +2,7 @@ # Kayobe network configuration. ############################################################################### -# Network role to network mappings. +# Network role to network name mappings. # Name of the network used for admin access to the overcloud #admin_oc_net_name: @@ -105,6 +105,12 @@ # 'name' items. These tables will be added to /etc/iproute2/rt_tables. #network_route_tables: +############################################################################### +# Systemd-networkd configuration. + +# Prefix for systemd-networkd configuration file names. +#networkd_prefix: + ############################################################################### # Network connectivity check configuration.