python-tripleoclient/tripleoclient/tests/v2/container_image/test_tripleo_container_image.py
Kevin Carter 39c270006d Add tripleo container image hotfix command
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 <kecarter@redhat.com>
(cherry picked from commit 4967f4f6ee)
2020-07-06 12:09:52 -04:00

279 lines
9.6 KiB
Python

# Copyright 2016 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
import mock
import sys
from tripleoclient.tests import fakes
from tripleoclient.tests.v1.overcloud_deploy import fakes as deploy_fakes
from tripleoclient.v2 import tripleo_container_image as tcib
IMAGE_YAML = """---
container_images:
- image_source: "tripleo"
imagename: "test/keystone:tag"
"""
MOCK_WALK = [
("", ["base"], [],),
("/base", ["memcached", "openstack"], ["config.yaml", "test.doc"],),
("/base/memcached", [], ["memcached.yaml"],),
("/base/openstack", ["glance", "keystone", "neutron", "nova"], [],),
(
"/base/openstack/glance",
[],
["glance-registry.yaml", "glance-api.yaml"],
),
("/base/openstack/keystone", [], ["keystone.yaml"],),
("/base/openstack/neutron", ["api"], [],),
("/base/openstack/neutron/api", [], ["neutron-api.yml"],),
("/base/openstack/nova", [], [],),
]
if sys.version_info >= (3, 0):
MOCK_OPEN_PATH = "builtins.open"
else:
MOCK_OPEN_PATH = "tripleoclient.v2.tripleo_container_image.open"
class TestContainerImages(deploy_fakes.TestDeployOvercloud):
def setUp(self):
super(TestContainerImages, self).setUp()
self.app = fakes.FakeApp()
self.os_walk = mock.patch(
"os.walk", autospec=True, return_value=iter(MOCK_WALK)
)
self.os_walk.start()
self.addCleanup(self.os_walk.stop)
self.os_listdir = mock.patch(
"os.listdir", autospec=True, return_value=["config.yaml"]
)
self.os_listdir.start()
self.addCleanup(self.os_listdir.stop)
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.buildah_build_all = mock.patch(
"tripleo_common.image.builder.buildah.BuildahBuilder.build_all",
autospec=True,
)
self.mock_buildah = self.buildah_build_all.start()
self.addCleanup(self.buildah_build_all.stop)
self.cmd = tcib.Build(self.app, None)
def _take_action(self, parsed_args):
self.cmd.image_parents = {"keystone": "base"}
mock_open = mock.mock_open(read_data=IMAGE_YAML)
with mock.patch("os.path.isfile", autospec=True) as mock_isfile:
mock_isfile.return_value = True
with mock.patch("os.path.isdir", autospec=True) as mock_isdir:
mock_isdir.return_value = True
with mock.patch(MOCK_OPEN_PATH, mock_open):
with mock.patch(
"tripleoclient.v2.tripleo_container_image.Build"
".find_image",
autospec=True,
) as mock_find_image:
mock_find_image.return_value = {"tcib_option": "data"}
self.cmd.take_action(parsed_args)
def test_find_image(self):
mock_open = mock.mock_open(read_data='---\ntcib_option: "data"')
with mock.patch(MOCK_OPEN_PATH, mock_open):
image = self.cmd.find_image("keystone", "some/path", "base-image")
self.assertEqual(image, {"tcib_option": "data"})
def test_build_tree(self):
image = self.cmd.build_tree("some/path")
self.assertEqual(
image,
[
{
"base": [
"memcached",
{
"openstack": [
"glance",
"keystone",
{"neutron": ["api"]},
"nova",
]
},
]
}
],
)
def test_image_regex(self):
image = self.cmd.imagename_to_regex("test/centos-binary-keystone:tag")
self.assertEqual(image, "keystone")
image = self.cmd.imagename_to_regex("test/rhel-binary-keystone:tag")
self.assertEqual(image, "keystone")
image = self.cmd.imagename_to_regex("test/rhel-source-keystone:tag")
self.assertEqual(image, "keystone")
image = self.cmd.imagename_to_regex("test/rhel-rdo-keystone:tag")
self.assertEqual(image, "keystone")
image = self.cmd.imagename_to_regex("test/rhel-rhos-keystone:tag")
self.assertEqual(image, "keystone")
image = self.cmd.imagename_to_regex("test/other-keystone:tag")
self.assertEqual(image, "other-keystone")
def test_rectify_excludes(self):
self.cmd.identified_images = ["keystone", "nova", "glance"]
excludes = self.cmd.rectify_excludes(images_to_prepare=["glance"])
self.assertEqual(excludes, ["keystone", "nova"])
def test_image_build_yaml(self):
arglist = ["--config-file", "config.yaml"]
verifylist = [("config_file", "config.yaml")]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self._take_action(parsed_args=parsed_args)
assert self.mock_buildah.called
def test_image_build_with_skip_build(self):
arglist = ["--config-file", "config.yaml", "--skip-build"]
verifylist = [("config_file", "config.yaml"), ("skip_build", True)]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self._take_action(parsed_args=parsed_args)
assert not self.mock_buildah.called
def test_image_build_with_push(self):
arglist = ["--config-file", "config.yaml", "--push"]
verifylist = [("config_file", "config.yaml"), ("push", True)]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self._take_action(parsed_args=parsed_args)
assert self.mock_buildah.called
def test_image_build_with_volume(self):
arglist = ["--config-file", "config.yaml", "--volume", "bind/mount"]
verifylist = [
("config_file", "config.yaml"),
(
"volumes",
[
"/etc/yum.repos.d:/etc/yum.repos.d:z",
"/etc/pki/rpm-gpg:/etc/pki/rpm-gpg:z",
"bind/mount",
],
),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self._take_action(parsed_args=parsed_args)
assert self.mock_buildah.called
def test_image_build_with_exclude(self):
arglist = ["--exclude", "image1"]
verifylist = [
("excludes", ["image1"]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self._take_action(parsed_args=parsed_args)
assert self.mock_buildah.called
def test_image_build_failure_no_config_file(self):
arglist = ["--config-file", "not-a-file-config.yaml"]
verifylist = [
("config_file", "not-a-file-config.yaml"),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.assertRaises(IOError, self.cmd.take_action, parsed_args)
def test_image_build_failure_no_config_dir(self):
arglist = ["--config-path", "not-a-path"]
verifylist = [
("config_path", "not-a-path"),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
with mock.patch("os.path.isfile", autospec=True) as mock_isfile:
mock_isfile.return_value = True
self.assertRaises(IOError, self.cmd.take_action, parsed_args)
class TestContainerImagesHotfix(deploy_fakes.TestDeployOvercloud):
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 = tcib.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)
def test_image_hotfix_missing_args(self):
arglist = []
verifylist = []
self.assertRaises(
deploy_fakes.fakes.utils.ParserException,
self.check_parser,
self.cmd,
arglist,
verifylist,
)