From 22cf08e882b7094832025c6ba66781c528294df1 Mon Sep 17 00:00:00 2001 From: Mark Goddard Date: Thu, 10 May 2018 14:16:27 +0000 Subject: [PATCH] Support forcing rebuild of deployment images It is hard to know when disk images need to be rebuilt, and the stackhpc.os-images role simply checks for the presence of the DIB output directory to indicate that an image exists. In some cases, we may wish to force the rebuilding of a deployment (IPA) image, when we know there are changes to apply. This change adds a --force-rebuild argument to the following commands: kayobe seed deployment image build kayobe overcloud deployment image build Change-Id: I580811a4f621df9445ef32773ca66bcf303dad9b --- ansible/overcloud-ipa-build.yml | 38 +++++++----- ansible/seed-ipa-build.yml | 7 +++ doc/source/deployment.rst | 11 ++++ kayobe/cli/commands.py | 28 ++++++++- kayobe/tests/unit/cli/test_commands.py | 84 ++++++++++++++++++++++++++ 5 files changed, 151 insertions(+), 17 deletions(-) diff --git a/ansible/overcloud-ipa-build.yml b/ansible/overcloud-ipa-build.yml index a63d1d2a8..8dd2855fc 100644 --- a/ansible/overcloud-ipa-build.yml +++ b/ansible/overcloud-ipa-build.yml @@ -20,20 +20,28 @@ - ipa-build vars: ipa_image_name: "ipa" + ipa_image_force_rebuild: false tasks: - - name: Ensure Ironic Python Agent images are built - include_role: - name: stackhpc.os-images - vars: - os_images_venv: "{{ virtualenv_path }}/ipa-build-dib" - os_images_cache: "{{ image_cache_path }}" - os_images_common: "" - os_images_list: - - name: "{{ ipa_image_name }}" - elements: "{{ ipa_build_dib_elements }}" - env: "{{ ipa_build_dib_env }}" - # Avoid needing to install qemu-img for qcow2 image. - type: raw - os_images_git_elements: "{{ ipa_build_dib_git_elements }}" - os_images_upload: False + - block: + - name: Ensure existing Ironic Python Agent images are removed (force rebuild) + file: + path: "{{ image_cache_path }}/{{ ipa_image_name }}" + state: absent + when: ipa_image_force_rebuild | bool + + - name: Ensure Ironic Python Agent images are built + include_role: + name: stackhpc.os-images + vars: + os_images_venv: "{{ virtualenv_path }}/ipa-build-dib" + os_images_cache: "{{ image_cache_path }}" + os_images_common: "" + os_images_list: + - name: "{{ ipa_image_name }}" + elements: "{{ ipa_build_dib_elements }}" + env: "{{ ipa_build_dib_env }}" + # Avoid needing to install qemu-img for qcow2 image. + type: raw + os_images_git_elements: "{{ ipa_build_dib_git_elements }}" + os_images_upload: False when: ipa_build_images | bool diff --git a/ansible/seed-ipa-build.yml b/ansible/seed-ipa-build.yml index ab44c9910..bddacab5e 100644 --- a/ansible/seed-ipa-build.yml +++ b/ansible/seed-ipa-build.yml @@ -11,8 +11,15 @@ ipa_images: - "{{ ipa_image_name }}.vmlinuz" - "{{ ipa_image_name }}.initramfs" + ipa_image_force_rebuild: false tasks: - block: + - name: Ensure existing Ironic Python Agent images are removed (force rebuild) + file: + path: "{{ image_cache_path }}/{{ ipa_image_name }}" + state: absent + when: ipa_image_force_rebuild | bool + - name: Ensure Ironic Python Agent images are built include_role: name: stackhpc.os-images diff --git a/doc/source/deployment.rst b/doc/source/deployment.rst index 29f03b5ad..6b3f37bb5 100644 --- a/doc/source/deployment.rst +++ b/doc/source/deployment.rst @@ -164,6 +164,9 @@ should be set to ``True``. To build images locally:: (kayobe) $ kayobe seed deployment image build +If images have been built previously, they will not be rebuilt. To force +rebuilding images, use the ``--force-rebuild`` argument. + Accessing the Seed via SSH (Optional) ------------------------------------- @@ -333,6 +336,11 @@ Building Deployment Images It is possible to use prebuilt deployment images. In this case, this step can be skipped. +.. note:: + + Deployment images are only required for the overcloud when Ironic is in use. + Otherwise, this step can be skipped. + It is possible to use prebuilt deployment images from the `OpenStack hosted tarballs `_ or another source. In some cases it may be necessary to build images locally either to @@ -342,6 +350,9 @@ should be set to ``True``. To build images locally:: (kayobe) $ kayobe overcloud deployment image build +If images have been built previously, they will not be rebuilt. To force +rebuilding images, use the ``--force-rebuild`` argument. + Deploying Containerised Services -------------------------------- diff --git a/kayobe/cli/commands.py b/kayobe/cli/commands.py index aece7d52c..1e8ca4818 100644 --- a/kayobe/cli/commands.py +++ b/kayobe/cli/commands.py @@ -514,10 +514,22 @@ class SeedDeploymentImageBuild(KayobeAnsibleMixin, VaultMixin, Command): (DIB) for use when provisioning and inspecting the overcloud hosts. """ + def get_parser(self, prog_name): + parser = super(SeedDeploymentImageBuild, self).get_parser( + prog_name) + group = parser.add_argument_group("Deployment 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 seed deployment images") playbooks = _build_playbook_list("seed-ipa-build") - self.run_kayobe_playbooks(parsed_args, playbooks) + extra_vars = {} + if parsed_args.force_rebuild: + extra_vars["ipa_image_force_rebuild"] = True + self.run_kayobe_playbooks(parsed_args, playbooks, + extra_vars=extra_vars) class OvercloudInventoryDiscover(KayobeAnsibleMixin, VaultMixin, Command): @@ -1073,10 +1085,22 @@ class OvercloudContainerImageBuild(KayobeAnsibleMixin, VaultMixin, Command): class OvercloudDeploymentImageBuild(KayobeAnsibleMixin, VaultMixin, Command): """Build the overcloud deployment kernel and ramdisk images.""" + def get_parser(self, prog_name): + parser = super(OvercloudDeploymentImageBuild, self).get_parser( + prog_name) + group = parser.add_argument_group("Deployment 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 deployment images") playbooks = _build_playbook_list("overcloud-ipa-build") - self.run_kayobe_playbooks(parsed_args, playbooks) + extra_vars = {} + if parsed_args.force_rebuild: + extra_vars["ipa_image_force_rebuild"] = True + self.run_kayobe_playbooks(parsed_args, playbooks, + extra_vars=extra_vars) class OvercloudPostConfigure(KayobeAnsibleMixin, VaultMixin, Command): diff --git a/kayobe/tests/unit/cli/test_commands.py b/kayobe/tests/unit/cli/test_commands.py index 161fe3f00..acd29c0b3 100644 --- a/kayobe/tests/unit/cli/test_commands.py +++ b/kayobe/tests/unit/cli/test_commands.py @@ -387,6 +387,48 @@ class TestCase(unittest.TestCase): ] self.assertEqual(expected_calls, mock_run.call_args_list) + @mock.patch.object(commands.KayobeAnsibleMixin, + "run_kayobe_playbooks") + def test_seed_deployment_image_build(self, mock_run): + command = commands.SeedDeploymentImageBuild(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, + [ + "ansible/seed-ipa-build.yml", + ], + extra_vars={}, + ), + ] + self.assertEqual(expected_calls, mock_run.call_args_list) + + @mock.patch.object(commands.KayobeAnsibleMixin, + "run_kayobe_playbooks") + def test_seed_deployment_image_build_force_rebuild(self, mock_run): + command = commands.SeedDeploymentImageBuild(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, + [ + "ansible/seed-ipa-build.yml", + ], + extra_vars={"ipa_image_force_rebuild": True}, + ), + ] + self.assertEqual(expected_calls, mock_run.call_args_list) + @mock.patch.object(commands.KayobeAnsibleMixin, "run_kayobe_playbooks") @mock.patch.object(commands.KollaAnsibleMixin, @@ -674,6 +716,48 @@ class TestCase(unittest.TestCase): ] 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): + command = commands.OvercloudDeploymentImageBuild(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, + [ + "ansible/overcloud-ipa-build.yml", + ], + extra_vars={}, + ), + ] + self.assertEqual(expected_calls, mock_run.call_args_list) + + @mock.patch.object(commands.KayobeAnsibleMixin, + "run_kayobe_playbooks") + def test_overcloud_deployment_image_build_force_rebuild(self, mock_run): + command = commands.OvercloudDeploymentImageBuild(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, + [ + "ansible/overcloud-ipa-build.yml", + ], + extra_vars={"ipa_image_force_rebuild": True}, + ), + ] + self.assertEqual(expected_calls, mock_run.call_args_list) + @mock.patch.object(commands.KayobeAnsibleMixin, "run_kayobe_playbooks") def test_overcloud_post_configure(self, mock_run):