From c35f112a14d5e5bd49bd49429179b49b5ae0da40 Mon Sep 17 00:00:00 2001 From: Pierre Riteau Date: Fri, 26 Nov 2021 09:28:00 +0100 Subject: [PATCH] Build overcloud host image directly with DIB As a first step towards supporting multiple overcloud disk images, this change introduces a new command to build a disk image directly with DIB: `kayobe overcloud host image build`. It also disables building a root disk image during Bifrost bootstrap if overcloud_dib_build_host_images is set to true. Change-Id: I93d242889e225b4e60254f6b9cc5eeb457294ac8 Story: 2002098 Task: 41693 --- ansible/group_vars/all/overcloud-dib | 54 +++++++++++++++++++ ansible/overcloud-host-image-build.yml | 51 ++++++++++++++++++ .../templates/kolla/config/bifrost/dib.yml | 7 +++ ansible/seed-ipa-build.yml | 4 +- dev/functions | 12 +++++ etc/kayobe/overcloud-dib.yml | 50 +++++++++++++++++ kayobe/cli/commands.py | 25 +++++++++ kayobe/tests/unit/cli/test_commands.py | 44 +++++++++++++++ playbooks/kayobe-seed-base/overrides.yml.j2 | 5 +- roles/kayobe-diagnostics/files/get_logs.sh | 6 +++ setup.cfg | 3 ++ 11 files changed, 258 insertions(+), 3 deletions(-) create mode 100644 ansible/group_vars/all/overcloud-dib create mode 100644 ansible/overcloud-host-image-build.yml create mode 100644 etc/kayobe/overcloud-dib.yml diff --git a/ansible/group_vars/all/overcloud-dib b/ansible/group_vars/all/overcloud-dib new file mode 100644 index 000000000..0f8d76f5b --- /dev/null +++ b/ansible/group_vars/all/overcloud-dib @@ -0,0 +1,54 @@ +--- +# Overcloud host disk image configuration. + +############################################################################### +# Diskimage-builder configuration for overcloud host disk images. + +# Whether to build host disk images with DIB directly instead of through +# Bifrost. Setting it to true disables Bifrost image build and allows images to +# be built with the `kayobe overcloud host image build` command. Default value +# is False. This will change in a future release. +overcloud_dib_build_host_images: False + +# DIB base OS element. Default is {{ os_distribution }}. +overcloud_dib_os_element: "{{ os_distribution }}" + +# DIB image OS release. Default is {{ os_release }}. +overcloud_dib_os_release: "{{ os_release }}" + +# List of default DIB elements. Default is ["centos", "cloud-init-datasources", +# "disable-selinux", "enable-serial-console", "vm"] when +# overcloud_dib_os_element is "centos", or ["ubuntu", "cloud-init-datasources", +# "enable-serial-console", "vm"] when overcloud_dib_os_element is "ubuntu". +overcloud_dib_elements_default: + - "{{ overcloud_dib_os_element }}" + - "cloud-init-datasources" + - "{% if overcloud_dib_os_element == 'centos' %}disable-selinux{% endif %}" + - "enable-serial-console" + - "vm" + +# List of additional DIB elements. Default is none. +overcloud_dib_elements_extra: [] + +# List of DIB elements. Default is a combination of +# overcloud_dib_elements_default and overcloud_dib_elements_extra. +overcloud_dib_elements: "{{ overcloud_dib_elements_default | select | list + overcloud_dib_elements_extra }}" + +# DIB default environment variables. Default is +# {"DIB_BOOTLOADER_DEFAULT_CMDLINE": "nofb nomodeset gfxpayload=text +# net.ifnames=1", "DIB_CLOUD_INIT_DATASOURCES": "ConfigDrive", "DIB_RELEASE": +# "{{ overcloud_dib_os_release }}"}. +overcloud_dib_env_vars_default: + DIB_BOOTLOADER_DEFAULT_CMDLINE: "nofb nomodeset gfxpayload=text net.ifnames=1" + DIB_CLOUD_INIT_DATASOURCES: "ConfigDrive" + DIB_RELEASE: "{{ overcloud_dib_os_release }}" + +# DIB additional environment variables. Default is none. +overcloud_dib_env_vars_extra: {} + +# DIB environment variables. Default is combination of +# overcloud_dib_env_vars_default and overcloud_dib_env_vars_extra. +overcloud_dib_env_vars: "{{ overcloud_dib_env_vars_default | combine(overcloud_dib_env_vars_extra) }}" + +# List of DIB packages to install. Default is to install no extra packages. +overcloud_dib_packages: [] diff --git a/ansible/overcloud-host-image-build.yml b/ansible/overcloud-host-image-build.yml new file mode 100644 index 000000000..1855607cc --- /dev/null +++ b/ansible/overcloud-host-image-build.yml @@ -0,0 +1,51 @@ +--- +# Build and install a overcloud host disk image for the seed host's ironic +# service. + +- name: Ensure overcloud host disk image is built and installed + hosts: seed + tags: + - overcloud-host-image-build + vars: + overcloud_host_image_name: "deployment_image" + overcloud_host_disk_images: + - "{{ overcloud_host_image_name }}.qcow2" + overcloud_host_image_force_rebuild: False + tasks: + - block: + - name: Ensure overcloud host disk image is built + include_role: + name: stackhpc.os-images + vars: + os_images_venv: "{{ virtualenv_path }}/overcloud-host-image-dib" + os_images_package_state: latest + os_images_upper_constraints_file: "{{ pip_upper_constraints_file }}" + os_images_cache: "{{ image_cache_path }}" + os_images_common: "" + os_images_list: + - name: "{{ overcloud_host_image_name }}" + elements: "{{ overcloud_dib_elements }}" + env: "{{ overcloud_dib_env_vars }}" + packages: "{{ overcloud_dib_packages }}" + type: qcow2 + os_images_upload: False + os_images_force_rebuild: "{{ overcloud_host_image_force_rebuild }}" + + - name: Ensure overcloud host disk image is copied onto seed + copy: + src: "{{ image_cache_path }}/{{ overcloud_host_image_name }}/{{ item }}" + dest: "/etc/kolla/bifrost/{{ item }}" + remote_src: True + with_items: "{{ overcloud_host_disk_images }}" + become: True + + - name: Copy overcloud host disk image into /httpboot + command: > + docker exec bifrost_deploy + bash -c 'ansible -vvvv target + -i /bifrost/playbooks/inventory/target + -m copy + -a "src=/etc/bifrost/{{ item }} dest=/httpboot/{{ item }}" + -e "ansible_python_interpreter=/var/lib/kolla/venv/bin/python"' + with_items: "{{ overcloud_host_disk_images }}" + when: overcloud_dib_build_host_images | bool diff --git a/ansible/roles/kolla-bifrost/templates/kolla/config/bifrost/dib.yml b/ansible/roles/kolla-bifrost/templates/kolla/config/bifrost/dib.yml index e3456414f..a4fe0522b 100644 --- a/ansible/roles/kolla-bifrost/templates/kolla/config/bifrost/dib.yml +++ b/ansible/roles/kolla-bifrost/templates/kolla/config/bifrost/dib.yml @@ -1,4 +1,5 @@ --- +{% if not overcloud_dib_build_host_images | bool %} # Diskimage-builder element for base OS. dib_os_element: "{{ kolla_bifrost_dib_os_element }}" @@ -13,3 +14,9 @@ dib_elements: "{{ (kolla_bifrost_dib_elements + [kolla_bifrost_dib_init_element] # List of DIB image packages. dib_packages: "{{ kolla_bifrost_dib_packages | join(',') }}" +{% else %} +# Stop building overcloud host image using Bifrost. This needs to be defined +# here to override the default true value set in kolla-ansible in +# ansible/roles/bifrost/templates/dib.yml.j2. +create_image_via_dib: False +{% endif %} diff --git a/ansible/seed-ipa-build.yml b/ansible/seed-ipa-build.yml index 05297f332..1145bf819 100644 --- a/ansible/seed-ipa-build.yml +++ b/ansible/seed-ipa-build.yml @@ -53,8 +53,8 @@ - name: Copy Ironic Python Agent images into /httpboot command: > docker exec bifrost_deploy - bash -c 'export OS_CLOUD=bifrost && - ansible -vvvv target -i /bifrost/playbooks/inventory/target + bash -c 'ansible -vvvv target + -i /bifrost/playbooks/inventory/target -m copy -a "src=/etc/bifrost/{{ item }} dest=/httpboot/{{ item }}" -e "ansible_python_interpreter=/var/lib/kolla/venv/bin/python"' diff --git a/dev/functions b/dev/functions index 90bfe3c94..0e9940238 100644 --- a/dev/functions +++ b/dev/functions @@ -219,6 +219,11 @@ function is_ironic_enabled { [[ $ironic_enabled =~ ^true$ ]] } +function is_overcloud_host_image_built_by_dib { + overcloud_dib_build_host_images=$(kayobe configuration dump --host controllers[0] --var-name overcloud_dib_build_host_images) + [[ $overcloud_dib_build_host_images =~ ^true$ ]] +} + function environment_setup { # NOTE: Virtualenv's activate script references an unbound variable. set +u @@ -316,6 +321,13 @@ function seed_deploy { else echo "Not building seed deployment images" fi + + if is_overcloud_host_image_built_by_dib; then + echo "Building overcloud host images" + run_kayobe overcloud host image build + else + echo "Not building overcloud host images" + fi } function seed_upgrade { diff --git a/etc/kayobe/overcloud-dib.yml b/etc/kayobe/overcloud-dib.yml new file mode 100644 index 000000000..41bce702a --- /dev/null +++ b/etc/kayobe/overcloud-dib.yml @@ -0,0 +1,50 @@ +--- +# Overcloud host disk image configuration. + +############################################################################### +# Diskimage-builder configuration for overcloud host disk images. + +# Whether to build host disk images with DIB directly instead of through +# Bifrost. Setting it to true disables Bifrost image build and allows images to +# be built with the `kayobe overcloud host image build` command. Default value +# is False. This will change in a future release. +#overcloud_dib_build_host_images: + +# DIB base OS element. Default is {{ os_distribution }}. +#overcloud_dib_os_element: + +# DIB image OS release. Default is {{ os_release }}. +#overcloud_dib_os_release: + +# List of default DIB elements. Default is ["centos", "cloud-init-datasources", +# "disable-selinux", "enable-serial-console", "vm"] when +# overcloud_dib_os_element is "centos", or ["ubuntu", "cloud-init-datasources", +# "enable-serial-console", "vm"] when overcloud_dib_os_element is "ubuntu". +#overcloud_dib_elements_default: + +# List of additional DIB elements. Default is none. +#overcloud_dib_elements_extra: + +# List of DIB elements. Default is a combination of +# overcloud_dib_elements_default and overcloud_dib_elements_extra. +#overcloud_dib_elements: + +# DIB default environment variables. Default is +# {"DIB_BOOTLOADER_DEFAULT_CMDLINE": "nofb nomodeset gfxpayload=text +# net.ifnames=1", "DIB_CLOUD_INIT_DATASOURCES": "ConfigDrive", "DIB_RELEASE": +# "{{ overcloud_dib_os_release }}"}. +#overcloud_dib_env_vars_default: + +# DIB additional environment variables. Default is none. +#overcloud_dib_env_vars_extra: + +# DIB environment variables. Default is combination of +# overcloud_dib_env_vars_default and overcloud_dib_env_vars_extra. +#overcloud_dib_env_vars: + +# List of DIB packages to install. Default is to install no extra packages. +#overcloud_dib_packages: + +############################################################################### +# 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 066f8e666..b992bc6e3 100644 --- a/kayobe/cli/commands.py +++ b/kayobe/cli/commands.py @@ -1762,6 +1762,31 @@ class OvercloudDeploymentImageBuild(KayobeAnsibleMixin, VaultMixin, Command): extra_vars=extra_vars) +class OvercloudHostImageBuild(KayobeAnsibleMixin, VaultMixin, Command): + """Build overcloud host disk images. + + Builds host disk images using Diskimage Builder (DIB) for use when + provisioning the overcloud hosts. + """ + + def get_parser(self, prog_name): + parser = super(OvercloudHostImageBuild, self).get_parser( + prog_name) + group = parser.add_argument_group("Host Image Build") + group.add_argument("--force-rebuild", action="store_true", + help="whether to force rebuilding the images") + return parser + + def take_action(self, parsed_args): + self.app.LOG.debug("Building overcloud host disk images") + playbooks = _build_playbook_list("overcloud-host-image-build") + extra_vars = {} + if parsed_args.force_rebuild: + extra_vars["overcloud_host_image_force_rebuild"] = True + self.run_kayobe_playbooks(parsed_args, playbooks, + extra_vars=extra_vars) + + class OvercloudPostConfigure(KayobeAnsibleMixin, VaultMixin, Command): """Perform post-deployment configuration. diff --git a/kayobe/tests/unit/cli/test_commands.py b/kayobe/tests/unit/cli/test_commands.py index f40144f4a..73bb7656a 100644 --- a/kayobe/tests/unit/cli/test_commands.py +++ b/kayobe/tests/unit/cli/test_commands.py @@ -2000,6 +2000,50 @@ class TestCase(unittest.TestCase): ] self.assertEqual(expected_calls, mock_run.call_args_list) + @mock.patch.object(commands.KayobeAnsibleMixin, + "run_kayobe_playbooks") + def test_overcloud_host_image_build(self, mock_run): + command = commands.OvercloudHostImageBuild(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", "overcloud-host-image-build.yml"), + ], + extra_vars={}, + ), + ] + self.assertEqual(expected_calls, mock_run.call_args_list) + + @mock.patch.object(commands.KayobeAnsibleMixin, + "run_kayobe_playbooks") + def test_overcloud_host_image_build_force_rebuild(self, mock_run): + command = commands.OvercloudHostImageBuild(TestApp(), []) + parser = command.get_parser("test") + parsed_args = parser.parse_args(["--force-rebuild"]) + + result = command.run(parsed_args) + self.assertEqual(0, result) + + expected_calls = [ + mock.call( + mock.ANY, + [ + utils.get_data_files_path( + "ansible", "overcloud-host-image-build.yml"), + ], + extra_vars={"overcloud_host_image_force_rebuild": True}, + ), + ] + self.assertEqual(expected_calls, mock_run.call_args_list) + @mock.patch.object(commands.KayobeAnsibleMixin, "run_kayobe_playbooks") def test_overcloud_deployment_image_build(self, mock_run): diff --git a/playbooks/kayobe-seed-base/overrides.yml.j2 b/playbooks/kayobe-seed-base/overrides.yml.j2 index 0881ebff6..5c9c948c2 100644 --- a/playbooks/kayobe-seed-base/overrides.yml.j2 +++ b/playbooks/kayobe-seed-base/overrides.yml.j2 @@ -35,4 +35,7 @@ aio_bridge_ports: # Build seed deployment images (IPA) with extra-hardware element ipa_build_images: true ipa_build_dib_elements_extra: - - "extra-hardware" \ No newline at end of file + - "extra-hardware" + +# Build overcloud host image +overcloud_dib_build_host_images: true diff --git a/roles/kayobe-diagnostics/files/get_logs.sh b/roles/kayobe-diagnostics/files/get_logs.sh index d07f8680a..539d41a11 100644 --- a/roles/kayobe-diagnostics/files/get_logs.sh +++ b/roles/kayobe-diagnostics/files/get_logs.sh @@ -102,6 +102,12 @@ copy_logs() { cp /opt/kayobe/images/ipa/ipa.stderr /opt/kayobe/images/ipa/ipa.stdout ${LOG_DIR}/kayobe/ fi + # Overcloud host image build logs + if [[ -f /opt/kayobe/images/deployment_image/deployment_image.stderr ]] || [[ -f /opt/kayobe/images/deployment_image/deployment_image.stdout ]]; then + mkdir -p ${LOG_DIR}/kayobe + cp /opt/kayobe/images/deployment_image/deployment_image.stderr /opt/kayobe/images/deployment_image/deployment_image.stdout ${LOG_DIR}/kayobe/ + fi + # Rename files to .txt; this is so that when displayed via # logs.openstack.org clicking results in the browser shows the # files, rather than trying to send it to another app or make you diff --git a/setup.cfg b/setup.cfg index 209fdc604..766398d35 100644 --- a/setup.cfg +++ b/setup.cfg @@ -61,6 +61,7 @@ kayobe.cli= overcloud_facts_gather = kayobe.cli.commands:OvercloudFactsGather overcloud_hardware_inspect = kayobe.cli.commands:OvercloudHardwareInspect overcloud_host_configure = kayobe.cli.commands:OvercloudHostConfigure + overcloud_host_image_build = kayobe.cli.commands:OvercloudHostImageBuild overcloud_host_package_update = kayobe.cli.commands:OvercloudHostPackageUpdate overcloud_host_command_run = kayobe.cli.commands:OvercloudHostCommandRun overcloud_host_upgrade = kayobe.cli.commands:OvercloudHostUpgrade @@ -148,6 +149,8 @@ kayobe.cli.overcloud_hardware_inspect = hooks = kayobe.cli.commands:HookDispatcher kayobe.cli.overcloud_host_configure = hooks = kayobe.cli.commands:HookDispatcher +kayobe.cli.overcloud_host_image_build = + hooks = kayobe.cli.commands:HookDispatcher kayobe.cli.overcloud_host_package_update = hooks = kayobe.cli.commands:HookDispatcher kayobe.cli.overcloud_host_command_run =