From 795f7c274f5119b880b2445eed798cbc0389cb95 Mon Sep 17 00:00:00 2001 From: Kevin Carter Date: Tue, 26 May 2020 12:14:01 -0500 Subject: [PATCH] Add tripleo container image hotfix command Note: this patch has been reworked to work for the stable/queens branch. This change adds a CLI command to invoke hotfixes via the TripleO modify image role. This CLI command will ensure a uniform experience for operators when needing to apply a hotfixes to containers. Change-Id: I364fb42a41b4cb4ae076f07704c72c6ea442a198 Signed-off-by: Kevin Carter (cherry picked from commit 182892b1f5d4068621c31b13e9e9c9f04edddb46) --- setup.cfg | 1 + .../overcloud_image/test_container_image.py | 43 ++++++++++ tripleoclient/v1/container_image.py | 82 +++++++++++++++++++ 3 files changed, 126 insertions(+) diff --git a/setup.cfg b/setup.cfg index 60a0de640..e3d9429f5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -103,6 +103,7 @@ openstack.tripleoclient.v1 = overcloud_execute = tripleoclient.v1.overcloud_execute:RemoteExecute overcloud_generate_fencing = tripleoclient.v1.overcloud_parameters:GenerateFencingParameters undercloud_deploy = tripleoclient.v1.undercloud_deploy:DeployUndercloud + tripleo_container_image_hotfix = tripleoclient.v1.container_image:HotFix undercloud_install = tripleoclient.v1.undercloud:InstallUndercloud undercloud_upgrade = tripleoclient.v1.undercloud:UpgradeUndercloud undercloud_backup = tripleoclient.v1.undercloud_backup:BackupUndercloud diff --git a/tripleoclient/tests/v1/overcloud_image/test_container_image.py b/tripleoclient/tests/v1/overcloud_image/test_container_image.py index 3c25fad5f..3f7990d16 100644 --- a/tripleoclient/tests/v1/overcloud_image/test_container_image.py +++ b/tripleoclient/tests/v1/overcloud_image/test_container_image.py @@ -631,3 +631,46 @@ class TestContainerImageBuild(TestPluginV1): images = [] self.cmd.images_from_deps(images, deps) self.assertEqual(yaml.safe_load(images_yaml), images) + + +class TestContainerImagesHotfix(TestPluginV1): + def setUp(self): + super(TestContainerImagesHotfix, self).setUp() + self.run_ansible_playbook = mock.patch( + "tripleoclient.utils.run_ansible_playbook", autospec=True + ) + self.run_ansible_playbook.start() + self.addCleanup(self.run_ansible_playbook.stop) + self.cmd = container_image.HotFix(self.app, None) + + def _take_action(self, parsed_args): + with mock.patch("os.path.isfile", autospec=True) as mock_isfile: + mock_isfile.return_value = True + self.cmd.take_action(parsed_args) + + def test_image_hotfix(self): + arglist = ["--image", "container1", "--rpms-path", "/opt"] + verifylist = [ + ("images", ["container1"]), + ("rpms_path", "/opt"), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + self._take_action(parsed_args=parsed_args) + + def test_image_hotfix_multi_image(self): + arglist = [ + "--image", + "container1", + "--image", + "container2", + "--rpms-path", + "/opt", + ] + verifylist = [ + ("images", ["container1", "container2"]), + ("rpms_path", "/opt"), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + self._take_action(parsed_args=parsed_args) diff --git a/tripleoclient/v1/container_image.py b/tripleoclient/v1/container_image.py index b86ea2221..b1b9cb733 100644 --- a/tripleoclient/v1/container_image.py +++ b/tripleoclient/v1/container_image.py @@ -17,6 +17,7 @@ import datetime import json import logging import os +import shutil import sys import tempfile @@ -481,3 +482,84 @@ class DiscoverImageTag(command.Command): image=parsed_args.image, tag_from_label=parsed_args.tag_from_label )) + + +class HotFix(command.Command): + """Hotfix tripleo container images with Ansible.""" + + def get_parser(self, prog_name): + parser = super(HotFix, self).get_parser(prog_name) + parser.add_argument( + "--image", + dest="images", + metavar="", + default=[], + action="append", + required=True, + help=_( + "Fully qualified reference to the source image to be " + "modified. Can be specified multiple times (one per " + "image) (default: %(default)s)." + ), + ) + parser.add_argument( + "--rpms-path", + dest="rpms_path", + metavar="", + required=True, + help=_("Path containing RPMs to install (default: %(default)s)."), + ) + parser.add_argument( + "--tag", + dest="tag", + metavar="", + default="latest", + help=_("Image hotfix tag (default: %(default)s)"), + ) + return parser + + def take_action(self, parsed_args): + tmp_modify_dir = tempfile.mkdtemp() + tasks = list() + try: + for image in parsed_args.images: + tasks.append( + { + "name": "include ansible-role-tripleo-modify-image", + "import_role": {"name": "tripleo-modify-image"}, + "vars": { + "container_build_tool": "docker", + "tasks_from": "rpm_install.yml", + "source_image": image, + "rpms_path": parsed_args.rpms_path, + "modified_append_tag": "-{}".format( + parsed_args.tag + ), + "modify_dir_path": tmp_modify_dir, + }, + } + ) + + playbook = os.path.join(tmp_modify_dir, + "tripleo-hotfix-playbook.yaml") + playdata = { + "name": "Generate hotfixs", + "connection": "local", + "hosts": "localhost", + "gather_facts": False, + "tasks": tasks, + } + + with open(playbook, "w") as f: + yaml.safe_dump( + [playdata], f, default_flow_style=False, width=4096 + ) + + utils.run_ansible_playbook( + logger=self.log, + workdir=tmp_modify_dir, + playbook=playbook, + inventory="localhost" + ) + finally: + shutil.rmtree(tmp_modify_dir)