# Copyright 2015 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 fixtures import mock import os import requests import shutil import six import sys import tempfile import uuid import yaml from osc_lib import exceptions as oscexc from six.moves.urllib import parse from tripleo_common.image import kolla_builder from tripleoclient import constants from tripleoclient.tests.v1.test_plugin import TestPluginV1 from tripleoclient.v1 import container_image class TestContainerImageUpload(TestPluginV1): def setUp(self): super(TestContainerImageUpload, self).setUp() # Get the command object to test self.cmd = container_image.UploadImage(self.app, None) @mock.patch('tripleo_common.utils.locks.processlock.' 'ProcessLock') @mock.patch('sys.exit') @mock.patch('tripleo_common.image.image_uploader.ImageUploadManager') def test_container_image_upload_noargs(self, mock_manager, exit_mock, mock_lock): arglist = [] verifylist = [] mock_lockobj = mock.MagicMock() mock_lock.return_value = mock_lockobj parsed_args = self.check_parser(self.cmd, arglist, verifylist) self.cmd.take_action(parsed_args) # argparse will complain that --config-file is missing and exit with 2 exit_mock.assert_called_with(2) @mock.patch('tripleo_common.utils.locks.processlock.' 'ProcessLock') @mock.patch('tripleo_common.image.image_uploader.ImageUploadManager') def test_container_image_upload_conf_files(self, mock_manager, mock_lock): arglist = [ '--config-file', '/tmp/foo.yaml', '--config-file', '/tmp/bar.yaml' ] verifylist = [] mock_lockobj = mock.MagicMock() mock_lock.return_value = mock_lockobj parsed_args = self.check_parser(self.cmd, arglist, verifylist) self.cmd.take_action(parsed_args) mock_manager.assert_called_once_with( ['/tmp/foo.yaml', '/tmp/bar.yaml'], cleanup='full', lock=mock_lockobj) mock_manager.return_value.upload.assert_called_once_with() class TestContainerImagePush(TestPluginV1): def setUp(self): super(TestContainerImagePush, self).setUp() lock = mock.patch('tripleo_common.utils.locks.processlock.ProcessLock') self.mock_lock = lock.start() self.addCleanup(lock.stop) self.cmd = container_image.TripleOContainerImagePush(self.app, None) @mock.patch('tripleo_common.image.image_uploader.get_undercloud_registry', return_value='uc.ctlplane.somedomain') @mock.patch('tripleo_common.image.image_uploader.UploadTask') @mock.patch('tripleo_common.image.image_uploader.ImageUploadManager') def test_take_action(self, mock_manager, mock_task, mock_get_uc_registry): arglist = ['docker.io/namespace/foo'] verifylist = [('image_to_push', 'docker.io/namespace/foo')] parsed_args = self.check_parser(self.cmd, arglist, verifylist) # mock manager object mock_mgr = mock.Mock() mock_manager.return_value = mock_mgr # mock uploader object mock_uploader = mock.Mock() mock_mgr.uploader.return_value = mock_uploader # mock return session object from uploader.authenticate mock_session = mock.Mock() mock_uploader.authenticate.return_value = mock_session # mock upload task mock_uploadtask = mock.Mock() mock_task.return_value = mock_uploadtask # mock add upload task action mock_add_upload = mock.Mock() data = [] mock_add_upload.return_value = data mock_uploader.add_upload_task = mock_add_upload # mock run tasks action mock_run_tasks = mock.Mock() mock_uploader.run_tasks = mock_run_tasks self.cmd.take_action(parsed_args) mock_task.assert_called_once_with( image_name='namespace/foo', pull_source='docker.io', push_destination='uc.ctlplane.somedomain', append_tag=parsed_args.append_tag, modify_role=None, modify_vars=None, cleanup=False, multi_arch=parsed_args.multi_arch) mock_add_upload.assert_called_once_with(mock_uploadtask) mock_run_tasks.assert_called_once() @mock.patch('tripleo_common.image.image_uploader.get_undercloud_registry', return_value='uc.ctlplane.somedomain') @mock.patch('tripleo_common.image.image_uploader.UploadTask') @mock.patch('tripleo_common.image.image_uploader.ImageUploadManager') def test_take_action_local(self, mock_manager, mock_task, mock_get_uc_registry): arglist = ['docker.io/namespace/foo', '--local'] verifylist = [('image_to_push', 'docker.io/namespace/foo'), ('local', True)] parsed_args = self.check_parser(self.cmd, arglist, verifylist) # mock manager object mock_mgr = mock.Mock() mock_manager.return_value = mock_mgr # mock uploader object mock_uploader = mock.Mock() mock_mgr.uploader.return_value = mock_uploader # mock return session object from uploader.authenticate mock_session = mock.Mock() mock_uploader.authenticate.return_value = mock_session # mock upload task mock_uploadtask = mock.Mock() mock_task.return_value = mock_uploadtask # mock add upload task action mock_add_upload = mock.Mock() data = [] mock_add_upload.return_value = data mock_uploader.add_upload_task = mock_add_upload # mock run tasks action mock_run_tasks = mock.Mock() mock_uploader.run_tasks = mock_run_tasks self.cmd.take_action(parsed_args) mock_task.assert_called_once_with( image_name='containers-storage:docker.io/namespace/foo', pull_source=None, push_destination='uc.ctlplane.somedomain', append_tag=parsed_args.append_tag, modify_role=None, modify_vars=None, cleanup=False, multi_arch=parsed_args.multi_arch) mock_add_upload.assert_called_once_with(mock_uploadtask) mock_run_tasks.assert_called_once() @mock.patch('tripleo_common.image.image_uploader.get_undercloud_registry', return_value='uc.ctlplane.somedomain') @mock.patch('tripleo_common.image.image_uploader.UploadTask') @mock.patch('tripleo_common.image.image_uploader.ImageUploadManager') def test_take_action_local_path(self, mock_manager, mock_task, mock_get_uc_registry): arglist = ['containers-storage:docker.io/namespace/foo'] verifylist = [('image_to_push', 'containers-storage:docker.io/namespace/foo')] parsed_args = self.check_parser(self.cmd, arglist, verifylist) # mock manager object mock_mgr = mock.Mock() mock_manager.return_value = mock_mgr # mock uploader object mock_uploader = mock.Mock() mock_mgr.uploader.return_value = mock_uploader # mock return session object from uploader.authenticate mock_session = mock.Mock() mock_uploader.authenticate.return_value = mock_session # mock upload task mock_uploadtask = mock.Mock() mock_task.return_value = mock_uploadtask # mock add upload task action mock_add_upload = mock.Mock() data = [] mock_add_upload.return_value = data mock_uploader.add_upload_task = mock_add_upload # mock run tasks action mock_run_tasks = mock.Mock() mock_uploader.run_tasks = mock_run_tasks self.cmd.take_action(parsed_args) mock_task.assert_called_once_with( image_name='containers-storage:docker.io/namespace/foo', pull_source=None, push_destination='uc.ctlplane.somedomain', append_tag=parsed_args.append_tag, modify_role=None, modify_vars=None, cleanup=False, multi_arch=parsed_args.multi_arch) mock_add_upload.assert_called_once_with(mock_uploadtask) mock_run_tasks.assert_called_once() @mock.patch('tripleo_common.image.image_uploader.get_undercloud_registry', return_value='uc.ctlplane.somedomain') @mock.patch('tripleo_common.image.image_uploader.UploadTask') @mock.patch('tripleo_common.image.image_uploader.ImageUploadManager') def test_take_action_oserror(self, mock_manager, mock_task, mock_get_uc_registry): arglist = ['docker.io/namespace/foo'] verifylist = [('image_to_push', 'docker.io/namespace/foo')] parsed_args = self.check_parser(self.cmd, arglist, verifylist) # mock manager object mock_mgr = mock.Mock() mock_manager.return_value = mock_mgr # mock uploader object mock_uploader = mock.Mock() mock_mgr.uploader.return_value = mock_uploader # mock return session object from uploader.authenticate mock_session = mock.Mock() mock_uploader.authenticate.return_value = mock_session # mock upload task mock_uploadtask = mock.Mock() mock_task.return_value = mock_uploadtask # mock add upload task action mock_add_upload = mock.Mock() data = [] mock_add_upload.return_value = data mock_uploader.add_upload_task = mock_add_upload # mock run tasks action mock_run_tasks = mock.Mock() mock_run_tasks.side_effect = OSError('Fail') mock_uploader.run_tasks = mock_run_tasks self.assertRaises(oscexc.CommandError, self.cmd.take_action, parsed_args) @mock.patch('tripleo_common.image.image_uploader.get_undercloud_registry', return_value='uc.ctlplane.somedomain') @mock.patch('tripleo_common.image.image_uploader.UploadTask') @mock.patch('tripleo_common.image.image_uploader.ImageUploadManager') def test_take_action_all_options(self, mock_manager, mock_task, mock_get_uc_registry): arglist = ['--registry-url', '127.0.0.1:8787', '--append-tag', 'test', '--source-username', 'sourceuser', '--source-password', 'sourcepassword', '--username', 'user', '--password', 'password', '--dry-run', '--multi-arch', '--cleanup', 'docker.io/namespace/foo:tag'] verifylist = [('registry_url', '127.0.0.1:8787'), ('append_tag', 'test'), ('username', 'user'), ('password', 'password'), ('dry_run', True), ('multi_arch', True), ('cleanup', True), ('image_to_push', 'docker.io/namespace/foo:tag')] parsed_args = self.check_parser(self.cmd, arglist, verifylist) # mock manager object mock_mgr = mock.Mock() mock_manager.return_value = mock_mgr # mock uploader object mock_uploader = mock.Mock() mock_mgr.uploader.return_value = mock_uploader # mock return session object from uploader.authenticate mock_session = mock.Mock() mock_uploader.authenticate.return_value = mock_session # mock upload task mock_uploadtask = mock.Mock() mock_task.return_value = mock_uploadtask # mock add upload task action mock_add_upload = mock.Mock() data = [] mock_add_upload.return_value = data mock_uploader.add_upload_task = mock_add_upload # mock run tasks action mock_run_tasks = mock.Mock() mock_uploader.run_tasks = mock_run_tasks self.cmd.take_action(parsed_args) source_url = parse.urlparse("docker://docker.io/namespace/foo:tag") registry_url = parse.urlparse("docker://127.0.0.1:8787") auth_calls = [mock.call(source_url, parsed_args.source_username, parsed_args.source_password), mock.call(registry_url, parsed_args.username, parsed_args.password)] mock_uploader.authenticate.assert_has_calls(auth_calls) mock_task.assert_not_called() mock_add_upload.assert_not_called() mock_run_tasks.assert_not_called() class TestContainerImageDelete(TestPluginV1): def setUp(self): super(TestContainerImageDelete, self).setUp() lock = mock.patch('tripleo_common.utils.locks.processlock.ProcessLock') self.mock_lock = lock.start() self.addCleanup(lock.stop) self.cmd = container_image.TripleOContainerImageDelete(self.app, None) @mock.patch('tripleo_common.image.image_uploader.get_undercloud_registry', return_value='uc.ctlplane.somedomain') @mock.patch('tripleo_common.image.image_uploader.ImageUploadManager') def test_oserror(self, mock_manager, mock_get_uc_registry): arglist = ['-y', 'foo'] verifylist = [('yes', True), ('image_to_delete', 'foo')] parsed_args = self.check_parser(self.cmd, arglist, verifylist) # mock manager object mock_mgr = mock.Mock() mock_manager.return_value = mock_mgr # mock uploader object mock_uploader = mock.Mock() mock_mgr.uploader.return_value = mock_uploader # mock return url object from uploader._image_to_url mock_url = mock.Mock() mock_url.geturl.return_value = 'munged-reg-url' mock_uploader._image_to_url.return_value = mock_url # mock return session object from uploader.authenticate mock_session = mock.Mock() mock_uploader.authenticate.return_value = mock_session mock_uploader.delete.side_effect = OSError('Errno 13') self.assertRaises(oscexc.CommandError, self.cmd.take_action, parsed_args) mock_uploader.delete.assert_called_once_with('foo', session=mock_session) class TestContainerImageList(TestPluginV1): def setUp(self): super(TestContainerImageList, self).setUp() lock = mock.patch('tripleo_common.utils.locks.processlock.ProcessLock') self.mock_lock = lock.start() self.addCleanup(lock.stop) self.cmd = container_image.TripleOContainerImageList(self.app, None) @mock.patch('tripleo_common.image.image_uploader.get_undercloud_registry', return_value='uc.ctlplane.somedomain') @mock.patch('tripleo_common.image.image_uploader.ImageUploadManager') def test_take_action(self, mock_manager, mock_get_uc_registry): arglist = [] verifylist = [] mock_manager.return_value.uploader.return_value.list.return_value = \ ['a', 'b'] parsed_args = self.check_parser(self.cmd, arglist, verifylist) rv = self.cmd.take_action(parsed_args) actual = (('Image Name',), [('a',), ('b',)]) self.assertEqual(actual, rv) @mock.patch('tripleo_common.image.image_uploader.get_undercloud_registry', return_value='uc.ctlplane.somedomain') @mock.patch('tripleo_common.image.image_uploader.ImageUploadManager') def test_take_action_auth(self, mock_manager, mock_get_uc_registry): # check arg parsing items arglist = ['--registry-url', 'reg-url', '--username', 'foo', '--password', 'bar'] verifylist = [('registry_url', 'reg-url'), ('username', 'foo'), ('password', 'bar')] parsed_args = self.check_parser(self.cmd, arglist, verifylist) # mock manager object mock_mgr = mock.Mock() mock_manager.return_value = mock_mgr # mock uploader object mock_uploader = mock.Mock() mock_mgr.uploader.return_value = mock_uploader # mock return url object from uploader._image_to_url mock_url = mock.Mock() mock_url.geturl.return_value = 'munged-reg-url' mock_uploader._image_to_url.return_value = mock_url # mock return session object from uploader.authenticate mock_session = mock.Mock() mock_uploader.authenticate.return_value = mock_session # mock image list function mock_uploader.list.return_value = ['a', 'b'] rv = self.cmd.take_action(parsed_args) # check various functions are called with expected inputs mock_mgr.uploader.assert_called_with('python') mock_uploader._image_to_url.assert_called_with('reg-url') mock_uploader.authenticate.assert_called_with(mock_url, 'foo', 'bar') mock_uploader.list.assert_called_with('munged-reg-url', session=mock_session) # check data format for lister actual = (('Image Name',), [('a',), ('b',)]) self.assertEqual(actual, rv) class TestContainerImageShow(TestPluginV1): def setUp(self): super(TestContainerImageShow, self).setUp() lock = mock.patch('tripleo_common.utils.locks.processlock.ProcessLock') self.mock_lock = lock.start() self.addCleanup(lock.stop) self.cmd = container_image.TripleOContainerImageShow(self.app, None) @mock.patch('tripleoclient.v1.container_image.TripleOContainerImageShow.' 'format_image_inspect') @mock.patch('tripleo_common.image.image_uploader.ImageUploadManager') def test_take_action(self, mock_manager, mock_formatter): arglist = ['foo'] verifylist = [('image_to_inspect', 'foo')] parsed_args = self.check_parser(self.cmd, arglist, verifylist) # mock manager object mock_mgr = mock.Mock() mock_manager.return_value = mock_mgr # mock uploader object mock_uploader = mock.Mock() mock_mgr.uploader.return_value = mock_uploader # mock return url object from uploader._image_to_url mock_url = mock.Mock() mock_url.geturl.return_value = 'munged-reg-url' mock_uploader._image_to_url.return_value = mock_url # mock return session object from uploader.authenticate mock_session = mock.Mock() mock_uploader.authenticate.return_value = mock_session mock_inspect = mock.Mock() data = {'Name': 'a', 'Layers': 'b'} mock_inspect.return_value = data mock_uploader.inspect = mock_inspect # mock format image inspect formatted_data = (['Name', 'Layers'], ['a', 'b']) mock_formatter.return_value = formatted_data rv = self.cmd.take_action(parsed_args) mock_formatter.assert_called_once_with(data) self.assertEqual(formatted_data, rv) def test_format_image_inspect(self): test_data = {'Name': 'foo', 'Layers': 'bar'} self.assertEqual(self.cmd.format_image_inspect(test_data), (['Name', 'Layers'], ['foo', 'bar'])) class TestContainerImagePrepare(TestPluginV1): def setUp(self): super(TestContainerImagePrepare, self).setUp() # Get the command object to test self.cmd = container_image.PrepareImageFiles(self.app, None) kolla_builder.DEFAULT_TEMPLATE_FILE = os.path.join( '/tmp/overcloud_containers.yaml.j2' ) self.roles_yaml = ''' - name: EnabledRole CountDefault: 1 ServicesDefault: - OS::TripleO::Services::AodhEvaluator - name: RoleDisabledViaRolesData CountDefault: 0 ServicesDefault: - OS::TripleO::Services::AodhApi - name: RoleDisabledViaEnvironment CountDefault: 1 ServicesDefault: - OS::TripleO::Services::Disabled - name: RoleOverwrittenViaEnvironment CountDefault: 1 ServicesDefault: - OS::TripleO::Services::Overwritten ''' @mock.patch('tripleo_common.image.kolla_builder.' 'container_images_prepare_defaults', create=True) @mock.patch('tripleo_common.image.kolla_builder.' 'container_images_prepare', create=True) @mock.patch('requests.get') @mock.patch('tripleo_common.image.kolla_builder.' 'build_service_filter') def test_container_image_prepare_noargs(self, mock_bsf, mock_get, mock_cip, mock_cipd): mock_bsf.return_value = None mock_cipd.return_value = { 'neutron_driver': 'ovn', 'name_suffix': '', 'tag': 'latest', 'namespace': 'docker.io/tripleomaster', 'name_prefix': 'centos-binary-' } arglist = [] verifylist = [] mock_cip.return_value = {'container_images.yaml': {}} parsed_args = self.check_parser(self.cmd, arglist, verifylist) self.cmd.take_action(parsed_args) mock_cip.assert_called_with( excludes=[], includes=[], mapping_args={ 'neutron_driver': 'ovn', 'name_suffix': '', 'tag': 'latest', 'namespace': 'docker.io/tripleomaster', 'name_prefix': 'centos-binary-' }, output_env_file=None, output_images_file='container_images.yaml', push_destination=None, service_filter=None, tag_from_label=None, modify_role=None, modify_vars=None, append_tag=None, template_file=kolla_builder.DEFAULT_TEMPLATE_FILE ) @mock.patch('tripleoclient.utils.fetch_roles_file') @mock.patch('tripleo_common.image.kolla_builder.' 'container_images_prepare_defaults', create=True) @mock.patch('tripleo_common.image.kolla_builder.' 'container_images_prepare', create=True) @mock.patch('heatclient.common.template_utils.' 'process_multiple_environments_and_files') @mock.patch('tripleo_common.image.kolla_builder.' 'build_service_filter') @mock.patch('requests.get') def test_container_image_prepare(self, mock_get, mock_bsf, pmef, mock_cip, mock_cipd, mock_roles): temp = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, temp) images_file = os.path.join(temp, 'overcloud_containers.yaml') env_file = os.path.join(temp, 'containers_env.yaml') tmpl_file = os.path.join(temp, 'overcloud_containers.yaml.j2') aodh_file = os.path.join(temp, 'docker', 'services', 'aodh.yaml') roles_file = os.path.join(temp, 'roles_data.yaml') with open(roles_file, 'w') as f: f.write(self.roles_yaml) modify_vars_file = os.path.join(temp, 'modify_vars.yaml') with open(modify_vars_file, 'w') as f: f.write('foo: bar') mock_get.side_effect = requests.exceptions.SSLError('ouch') mock_bsf.return_value = set(['OS::TripleO::Services::AodhEvaluator']) resource_registry = { 'parameter_defaults': { 'NeutronMechanismDrivers': 'ovn', }, 'resource_registry': { 'OS::TripleO::Services::AodhEvaluator': aodh_file, 'OS::TripleO::Services::AodhApi': aodh_file } } pmef.return_value = None, resource_registry arglist = [ '--template-file', tmpl_file, '--tag', 'passed-ci', '--namespace', '192.0.2.0:8787/t', '--prefix', 'os-', '--suffix', 'foo', '--output-images-file', images_file, '--output-env-file', env_file, '--set', 'ceph_namespace=myceph', '--set', 'ceph_image=mydaemon', '--set', 'ceph_tag=mytag', '-e', 'environment/docker-ha.yaml', '--roles-file', roles_file, '--modify-role', 'foo-role', '--modify-vars', modify_vars_file ] self.cmd.app.command_options = arglist verifylist = [] mock_cip.return_value = {images_file: [{ 'imagename': '192.0.2.0:8787/t/os-aodh-apifoo:passed-ci', }, { 'imagename': '192.0.2.0:8787/t/os-aodh-evaluatorfoo:passed-ci', }], env_file: { 'DockerAodhApiImage': '192.0.2.0:8787/t/os-aodh-apifoo:passed-ci', 'DockerAodhConfigImage': '192.0.2.0:8787/t/os-aodh-apifoo:passed-ci', 'DockerAodhEvaluatorImage': '192.0.2.0:8787/t/os-aodh-evaluatorfoo:passed-ci', 'DockerInsecureRegistryAddress': ['192.0.2.0:8787'] } } parsed_args = self.check_parser(self.cmd, arglist, verifylist) self.cmd.take_action(parsed_args) pmef.assert_called_once_with(['environment/docker-ha.yaml'], env_path_is_object=mock.ANY, object_request=mock.ANY) mock_cip.assert_called_once_with( excludes=[], includes=[], mapping_args={ 'namespace': '192.0.2.0:8787/t', 'name_suffix': 'foo', 'ceph_tag': 'mytag', 'ceph_image': 'mydaemon', 'tag': 'passed-ci', 'neutron_driver': 'ovn', 'ceph_namespace': 'myceph', 'name_prefix': 'os-' }, output_env_file=env_file, output_images_file=images_file, push_destination=None, service_filter=set([ 'OS::TripleO::Services::AodhEvaluator', ]), tag_from_label=None, modify_role='foo-role', modify_vars={'foo': 'bar'}, append_tag=mock.ANY, template_file=tmpl_file ) ci_data = { 'container_images': [{ 'imagename': '192.0.2.0:8787/t/os-aodh-apifoo:passed-ci', }, { 'imagename': '192.0.2.0:8787/t/os-aodh-evaluatorfoo:passed-ci', }] } env_data = { 'parameter_defaults': { 'DockerAodhApiImage': '192.0.2.0:8787/t/os-aodh-apifoo:passed-ci', 'DockerAodhConfigImage': '192.0.2.0:8787/t/os-aodh-apifoo:passed-ci', 'DockerAodhEvaluatorImage': '192.0.2.0:8787/t/os-aodh-evaluatorfoo:passed-ci', 'DockerInsecureRegistryAddress': ['192.0.2.0:8787'] } } with open(images_file) as f: self.assertEqual(ci_data, yaml.safe_load(f)) with open(env_file) as f: self.assertEqual(env_data, yaml.safe_load(f)) class TestTripleoImagePrepare(TestPluginV1): def setUp(self): super(TestTripleoImagePrepare, self).setUp() # Get the command object to test self.cmd = container_image.TripleOImagePrepare(self.app, None) self.cmd.app_args = mock.Mock() self.cmd.app_args.verbose_level = 3 self.temp_dir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, self.temp_dir) self.prepare_default_file = os.path.join( self.temp_dir, 'prepare_env.yaml') default_param = kolla_builder.CONTAINER_IMAGE_PREPARE_PARAM self.default_env = { 'parameter_defaults': { 'ContainerImagePrepare': default_param } } with open(self.prepare_default_file, 'w') as f: yaml.safe_dump(self.default_env, f) self.roles_yaml = ''' - name: EnabledRole CountDefault: 1 ServicesDefault: - OS::TripleO::Services::AodhEvaluator - name: RoleDisabledViaRolesData CountDefault: 0 ServicesDefault: - OS::TripleO::Services::AodhApi - name: RoleDisabledViaEnvironment CountDefault: 1 ServicesDefault: - OS::TripleO::Services::Disabled - name: RoleOverwrittenViaEnvironment CountDefault: 1 ServicesDefault: - OS::TripleO::Services::Overwritten ''' self.roles_data_file = os.path.join( self.temp_dir, 'roles_data.yaml') with open(self.roles_data_file, 'w') as f: f.write(self.roles_yaml) @mock.patch('tripleoclient.utils.run_ansible_playbook', autospec=True) def test_tripleo_container_image_prepare(self, mock_playbook): env_file = os.path.join(self.temp_dir, 'containers_env.yaml') arglist = [ '--environment-file', self.prepare_default_file, '--roles-file', self.roles_data_file, '--output-env-file', env_file ] verifylist = [] self.app.command_options = [ 'tripleo', 'container', 'image', 'prepare' ] + arglist parsed_args = self.check_parser(self.cmd, arglist, verifylist) self.cmd.take_action(parsed_args) e_vars = {'roles_file': self.roles_data_file, 'environment_directories': [mock.ANY], 'environment_files': [self.temp_dir + '/prepare_env.yaml'], 'cleanup': 'full', 'dry_run': False, 'log_file': 'container_image_prepare.log', 'debug': True, 'output_env_file': self.temp_dir + '/containers_env.yaml'} mock_playbook.assert_called_with( extra_vars=e_vars, inventory='localhost,', playbook='cli-container-image-prepare.yaml', playbook_dir='/usr/share/ansible/tripleo-playbooks', verbosity=3, workdir=mock.ANY) @mock.patch('tripleoclient.utils.rel_or_abs_path') @mock.patch('tripleoclient.utils.run_ansible_playbook', autospec=True) def test_tripleo_container_image_prepare_paths(self, mock_playbook, mock_path): arglist = ['-e', 'foo.yaml', '-e', '/bar.yaml', '--environment-directory', 'foo', '--environment-directory', '/bar', '-r', 'foo.yaml'] verifylist = [] self.app.command_options = [ 'tripleo', 'container', 'image', 'prepare' ] + arglist mock_path.return_value = ('/usr/share/openstack-tripleo-heat-templates' '/foo.yaml') parsed_args = self.check_parser(self.cmd, arglist, verifylist) self.cmd.take_action(parsed_args) e_vars = {'roles_file': ('/usr/share/' 'openstack-tripleo-heat-templates/foo.yaml'), 'environment_directories': [ os.path.expanduser(constants.DEFAULT_ENV_DIRECTORY), os.getcwd() + '/foo', '/bar' ], 'environment_files': [ os.getcwd() + '/foo.yaml', '/bar.yaml' ], 'cleanup': 'full', 'dry_run': False, 'log_file': 'container_image_prepare.log', 'debug': True} mock_playbook.assert_called_with( extra_vars=e_vars, inventory='localhost,', playbook='cli-container-image-prepare.yaml', playbook_dir='/usr/share/ansible/tripleo-playbooks', verbosity=3, workdir=mock.ANY) class TestTripleoImagePrepareDefault(TestPluginV1): def setUp(self): super(TestTripleoImagePrepareDefault, self).setUp() # Get the command object to test self.cmd = container_image.TripleOImagePrepareDefault(self.app, None) def test_prepare_default(self): arglist = [] verifylist = [] self.app.command_options = [ 'tripleo', 'container', 'image', 'prepare', 'default' ] + arglist self.cmd.app.stdout = six.StringIO() cmd = container_image.TripleOImagePrepareDefault(self.app, None) parsed_args = self.check_parser(cmd, arglist, verifylist) cmd.take_action(parsed_args) result = self.app.stdout.getvalue() expected_param = kolla_builder.CONTAINER_IMAGE_PREPARE_PARAM expected = { 'parameter_defaults': { 'ContainerImagePrepare': expected_param } } self.assertEqual(expected, yaml.safe_load(result)) def test_prepare_default_local_registry(self): temp = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, temp) env_file = os.path.join(temp, 'containers_env.yaml') arglist = ['--local-push-destination', '--output-env-file', env_file] verifylist = [] self.app.command_options = [ 'tripleo', 'container', 'image', 'prepare', 'default' ] + arglist cmd = container_image.TripleOImagePrepareDefault(self.app, None) parsed_args = self.check_parser(cmd, arglist, verifylist) cmd.take_action(parsed_args) with open(env_file) as f: result = yaml.safe_load(f) self.assertEqual( True, result['parameter_defaults']['ContainerImagePrepare'] [0]['push_destination'] ) def test_prepare_default_registyr_login(self): temp = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, temp) env_file = os.path.join(temp, 'containers_env.yaml') arglist = ['--enable-registry-login', '--output-env-file', env_file] verifylist = [] self.app.command_options = [ 'tripleo', 'container', 'image', 'prepare', 'default' ] + arglist cmd = container_image.TripleOImagePrepareDefault(self.app, None) parsed_args = self.check_parser(cmd, arglist, verifylist) cmd.take_action(parsed_args) with open(env_file) as f: result = yaml.safe_load(f) self.assertEqual( True, result['parameter_defaults']['ContainerImageRegistryLogin'] ) class TestContainerImageBuild(TestPluginV1): def setUp(self): super(TestContainerImageBuild, self).setUp() # Get the command object to test self.cmd = container_image.BuildImage(self.app, None) self.cmd.app.stdout = six.StringIO() self.uuid = str(uuid.uuid4()) self.temp_dir = os.path.join(self.useFixture( fixtures.TempDir()).join()) self.temp_dir_uuid = os.path.join(self.temp_dir, self.uuid) # Default conf file self.default_kolla_conf = os.path.join( sys.prefix, 'share', 'tripleo-common', 'container-images', 'tripleo_kolla_config_overrides.conf') @mock.patch('sys.exit') @mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder', autospec=True) @mock.patch('os.makedirs') def test_container_image_build_noargs(self, mock_mkdirs, mock_builder, exit_mock): arglist = [] verifylist = [] mock_builder.return_value.build_images.return_value = 'done' parsed_args = self.check_parser(self.cmd, arglist, verifylist) f, path = tempfile.mkstemp(dir=self.temp_dir) with mock.patch('tempfile.mkstemp') as mock_mkstemp: mock_mkstemp.return_value = f, path self.cmd.take_action(parsed_args) # argparse will complain that --config-file is missing and exit with 2 exit_mock.assert_called_with(2) @mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder', autospec=True) @mock.patch('uuid.uuid4') def test_container_image_build(self, mock_uuid, mock_builder): arglist = [ '--config-file', '/tmp/foo.yaml', '--config-file', '/tmp/bar.yaml', '--work-dir', self.temp_dir, '--kolla-config-file', '/tmp/kolla.conf' ] verifylist = [] mock_builder.return_value.build_images.return_value = 'done' mock_uuid.return_value = self.uuid parsed_args = self.check_parser(self.cmd, arglist, verifylist) f, path = tempfile.mkstemp(dir=self.temp_dir) with mock.patch('tempfile.mkstemp') as mock_mkstemp: with mock.patch('os.chdir'): mock_mkstemp.return_value = f, path self.cmd.take_action(parsed_args) mock_builder.assert_called_once_with([ '/tmp/foo.yaml', '/tmp/bar.yaml']) mock_builder.return_value.build_images.assert_called_once_with([ self.default_kolla_conf, '/tmp/kolla.conf', path ], [], False, self.temp_dir_uuid) @mock.patch('os.chdir') @mock.patch('os.fdopen', autospec=True) @mock.patch('tempfile.mkstemp') @mock.patch( 'tripleoclient.utils.get_from_cfg') @mock.patch( 'tripleoclient.utils.getboolean_from_cfg') @mock.patch('tripleo_common.image.builder.buildah.BuildahBuilder', autospec=True) @mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder', autospec=True) @mock.patch('tripleoclient.utils.get_read_config') @mock.patch('os.remove') def test_container_image_build_with_buildah(self, mock_remove, mock_read_conf, mock_builder, mock_buildah, mock_kolla_boolean_cfg, mock_kolla_cfg, mock_mkstemp, mock_fdopen, mock_chdir): arglist = [ '--config-file', '/tmp/bar.yaml', '--kolla-config-file', '/tmp/kolla.conf', '--use-buildah', '--work-dir', self.temp_dir, ] parsed_args = self.check_parser(self.cmd, arglist, []) deps = '{"base": ["qrouterd"]}' mock_builder.return_value.build_images.return_value = deps mock_mkstemp.return_value = (1, '/tmp/whatever_file') mock_bb = mock.MagicMock() mock_bb.build_all = mock.MagicMock() mock_buildah.return_value = mock_bb self.cmd.take_action(parsed_args) cfg_files = list(parsed_args.kolla_config_files) cfg_files.append('/tmp/whatever_file') mock_read_conf.assert_any_call(cfg_files) cfg_calls = [ mock.call(mock_read_conf.return_value, 'base'), mock.call(mock_read_conf.return_value, 'type'), mock.call(mock_read_conf.return_value, 'tag'), mock.call(mock_read_conf.return_value, 'namespace'), mock.call(mock_read_conf.return_value, 'registry'), ] cfg_boolean_calls = [ mock.call(mock_read_conf.return_value, 'push'), ] mock_kolla_cfg.assert_has_calls(cfg_calls) mock_kolla_boolean_cfg.assert_has_calls(cfg_boolean_calls) mock_bb.build_all.assert_called_once() @mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder', autospec=True) @mock.patch('uuid.uuid4') def test_container_image_build_with_exclude(self, mock_uuid, mock_builder): arglist = [ '--config-file', '/tmp/foo.yaml', '--config-file', '/tmp/bar.yaml', '--kolla-config-file', '/tmp/kolla.conf', '--work-dir', '/tmp/testing', '--exclude', 'foo', '--exclude', 'bar' ] verifylist = [] mock_builder.return_value.build_images.return_value = 'done' mock_uuid.return_value = '123' parsed_args = self.check_parser(self.cmd, arglist, verifylist) f, path = tempfile.mkstemp(dir=self.temp_dir) with mock.patch('tempfile.mkdtemp') as mock_mkd: mock_mkd.return_value = '/tmp/testing' with mock.patch('tempfile.mkstemp') as mock_mkstemp: with mock.patch('os.chdir'): mock_mkstemp.return_value = f, path self.cmd.take_action(parsed_args) mock_builder.assert_called_once_with([ '/tmp/foo.yaml', '/tmp/bar.yaml']) mock_builder.return_value.build_images.assert_called_once_with([ self.default_kolla_conf, '/tmp/kolla.conf', path ], ['foo', 'bar'], False, '/tmp/testing/123') @mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder', autospec=True) @mock.patch('os.remove') def test_container_image_build_list_images(self, mock_remove, mock_builder): arglist = [ '--list-images', '--config-file', '/tmp/bar.yaml', '--work-dir', '/tmp/testing', '--kolla-config-file', '/tmp/kolla.conf' ] parsed_args = self.check_parser(self.cmd, arglist, []) deps = '{"base": ["qrouterd"]}' mock_builder.return_value.build_images.return_value = deps f, path = tempfile.mkstemp(dir=self.temp_dir) with mock.patch('tempfile.mkstemp') as mock_mkstemp: mock_mkstemp.return_value = f, path self.cmd.take_action(parsed_args) with open(path, 'r') as conf_file: self.assertEqual( conf_file.readlines(), ['[DEFAULT]\n', 'list_dependencies=true']) self.assertEqual('- base\n- qrouterd\n', self.cmd.app.stdout.getvalue()) @mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder', autospec=True) @mock.patch('os.remove') @mock.patch('os.makedirs') def test_container_image_build_list_deps(self, mock_mkdirs, mock_remove, mock_builder): arglist = [ '--config-file', '/tmp/bar.yaml', '--kolla-config-file', '/tmp/kolla.conf', '--list-dependencies', ] parsed_args = self.check_parser(self.cmd, arglist, []) deps = '{"base": ["qrouterd"]}' mock_builder.return_value.build_images.return_value = deps f, path = tempfile.mkstemp(dir=self.temp_dir) with mock.patch('tempfile.mkstemp') as mock_mkstemp: mock_mkstemp.return_value = f, path self.cmd.take_action(parsed_args) with open(path, 'r') as conf_file: self.assertEqual( conf_file.readlines(), ['[DEFAULT]\n', 'list_dependencies=true']) self.assertEqual('base:\n- qrouterd\n', self.cmd.app.stdout.getvalue()) def test_images_from_deps(self): deps = yaml.safe_load('''base: - qdrouterd - cron - ceph-base: - ceph-osd - ceph-rgw - ceph-mon - cephfs-fuse - ceph-mds - redis - etcd - kubernetes-entrypoint - kolla-toolbox - telegraf - openstack-base: - swift-base: - swift-proxy-server - swift-account - swift-container - swift-object-expirer - swift-rsyncd - swift-object''') images_yaml = '''- base - qdrouterd - cron - ceph-base - ceph-osd - ceph-rgw - ceph-mon - cephfs-fuse - ceph-mds - redis - etcd - kubernetes-entrypoint - kolla-toolbox - telegraf - openstack-base - swift-base - swift-proxy-server - swift-account - swift-container - swift-object-expirer - swift-rsyncd - swift-object ''' images = [] self.cmd.images_from_deps(images, deps) self.assertEqual(yaml.safe_load(images_yaml), images)