diff --git a/doc/source/commands.rst b/doc/source/commands.rst index b671d97df..ac6ec0666 100644 --- a/doc/source/commands.rst +++ b/doc/source/commands.rst @@ -12,9 +12,6 @@ Container Commands .. autoprogram-cliff:: openstack.tripleoclient.v2 :command: tripleo container * -.. autoprogram-cliff:: openstack.tripleoclient.v2 - :command: overcloud container image [!prep]* - =================== Undercloud Commands =================== diff --git a/releasenotes/notes/remove-overcloud-container-commands-fe7185ee87aeda3a.yaml b/releasenotes/notes/remove-overcloud-container-commands-fe7185ee87aeda3a.yaml new file mode 100644 index 000000000..7b36558b7 --- /dev/null +++ b/releasenotes/notes/remove-overcloud-container-commands-fe7185ee87aeda3a.yaml @@ -0,0 +1,7 @@ +--- +upgrade: + - | + Removed `overcloud container image upload`, `overcloud container image build`, + `overcloud container image prepare` and `overcloud container image tag` + commands as the `tripleo container` command replaced those in Train and + they no longer work. diff --git a/setup.cfg b/setup.cfg index 58acb1f16..4981c9fee 100644 --- a/setup.cfg +++ b/setup.cfg @@ -44,10 +44,6 @@ openstack.tripleoclient.v2 = overcloud_cell_export = tripleoclient.v1.overcloud_cell:ExportCell overcloud_ceph_deploy = tripleoclient.v2.overcloud_ceph:OvercloudCephDeploy overcloud_config_download = tripleoclient.v1.overcloud_config:DownloadConfig - overcloud_container_image_upload = tripleoclient.v1.container_image:UploadImage - overcloud_container_image_build = tripleoclient.v1.container_image:BuildImage - overcloud_container_image_prepare = tripleoclient.v1.container_image:PrepareImageFiles - overcloud_container_image_tag_discover = tripleoclient.v1.container_image:DiscoverImageTag overcloud_delete = tripleoclient.v2.overcloud_delete:DeleteOvercloud overcloud_credentials = tripleoclient.v1.overcloud_credentials:OvercloudCredentials overcloud_deploy = tripleoclient.v1.overcloud_deploy:DeployOvercloud diff --git a/tripleoclient/tests/v1/test_container_image.py b/tripleoclient/tests/v1/test_container_image.py index 0499ee59f..efa8478b4 100644 --- a/tripleoclient/tests/v1/test_container_image.py +++ b/tripleoclient/tests/v1/test_container_image.py @@ -13,76 +13,20 @@ # under the License. # -import fixtures from io import StringIO import os -import requests import shutil -import sys import tempfile from urllib import parse -import uuid import yaml from unittest import mock from osc_lib import exceptions as oscexc 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() @@ -535,345 +479,6 @@ class TestContainerImageShow(TestPluginV1): (['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): @@ -949,279 +554,3 @@ class TestTripleoImagePrepareDefault(TestPluginV1): 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 = 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) diff --git a/tripleoclient/v1/container_image.py b/tripleoclient/v1/container_image.py index e3a7abb2a..a73f82739 100644 --- a/tripleoclient/v1/container_image.py +++ b/tripleoclient/v1/container_image.py @@ -17,21 +17,15 @@ import copy import datetime import errno from io import StringIO -import json import logging import os import shutil -import sys -import tempfile -import time -import uuid from osc_lib import exceptions as oscexc from osc_lib.i18n import _ from urllib import parse import yaml -from tripleo_common.image.builder import buildah from tripleo_common.image import image_uploader from tripleo_common.image import kolla_builder from tripleo_common.utils.locks import processlock @@ -56,501 +50,6 @@ def build_env_file(params, command_options): return f.getvalue() -class UploadImage(command.Command): - """Push overcloud container images to registries.""" - - auth_required = False - log = logging.getLogger(__name__ + ".UploadImage") - - def get_parser(self, prog_name): - parser = super(UploadImage, self).get_parser(prog_name) - parser.add_argument( - "--config-file", - dest="config_files", - metavar='', - default=[], - action="append", - required=True, - help=_("YAML config file specifying the image build. May be " - "specified multiple times. Order is preserved, and later " - "files will override some options in previous files. " - "Other options will append."), - ) - parser.add_argument( - "--cleanup", - dest="cleanup", - metavar='', - default=image_uploader.CLEANUP_FULL, - help=_("Cleanup behavior for local images left after upload. " - "The default 'full' will attempt to delete all local " - "images. 'partial' will leave images required for " - "deployment on this host. 'none' will do no cleanup.") - ) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)" % parsed_args) - if parsed_args.cleanup not in image_uploader.CLEANUP: - raise oscexc.CommandError('--cleanup must be one of: %s' % - ', '.join(image_uploader.CLEANUP)) - lock = processlock.ProcessLock() - uploader = image_uploader.ImageUploadManager( - parsed_args.config_files, cleanup=parsed_args.cleanup, lock=lock) - try: - uploader.upload() - except KeyboardInterrupt: # ctrl-c - self.log.warning('Upload was interrupted by ctrl-c.') - - -class BuildImage(command.Command): - """Build overcloud container images with kolla-build.""" - - auth_required = False - log = logging.getLogger(__name__ + ".BuildImage") - - @staticmethod - def images_from_deps(images, dep): - '''Builds a list from the dependencies depth-first. ''' - if isinstance(dep, list): - for v in dep: - BuildImage.images_from_deps(images, v) - elif isinstance(dep, dict): - for k, v in dep.items(): - images.append(k) - BuildImage.images_from_deps(images, v) - else: - images.append(dep) - - def get_parser(self, prog_name): - default_kolla_conf = os.path.join( - sys.prefix, 'share', 'tripleo-common', 'container-images', - 'tripleo_kolla_config_overrides.conf') - parser = super(BuildImage, self).get_parser(prog_name) - parser.add_argument( - "--config-file", - dest="config_files", - metavar='', - default=[], - action="append", - help=_("YAML config file specifying the images to build. May be " - "specified multiple times. Order is preserved, and later " - "files will override some options in previous files. " - "Other options will append. If not specified, the default " - "set of containers will be built."), - ) - parser.add_argument( - "--kolla-config-file", - dest="kolla_config_files", - metavar='', - default=[default_kolla_conf], - action="append", - required=True, - help=_("Path to a Kolla config file to use. Multiple config files " - "can be specified, with values in later files taking " - "precedence. By default, tripleo kolla conf file {conf} " - "is added.").format(conf=default_kolla_conf), - ) - parser.add_argument( - '--list-images', - dest='list_images', - action='store_true', - default=False, - help=_('Show the images which would be built instead of ' - 'building them.') - ) - parser.add_argument( - '--list-dependencies', - dest='list_dependencies', - action='store_true', - default=False, - help=_('Show the image build dependencies instead of ' - 'building them.') - ) - parser.add_argument( - "--exclude", - dest="excludes", - metavar='', - default=[], - action="append", - help=_("Name of a container to match against the list of " - "containers to be built to skip. Can be specified multiple " - "times."), - ) - parser.add_argument( - '--use-buildah', - dest='use_buildah', - action='store_true', - default=False, - help=_('Use Buildah instead of Docker to build the images ' - 'with Kolla.') - ) - parser.add_argument( - "--work-dir", - dest="work_dir", - default='/tmp/container-builds', - metavar='', - help=_("TripleO container builds directory, storing configs and " - "logs for each image and its dependencies.") - ) - parser.add_argument( - "--build-timeout", - dest="build_timeout", - default=None, - type=int, - metavar="", - help=_("Build timeout in seconds.") - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)" % parsed_args) - self.log.warning('This command is deprecated. Please use "openstack ' - 'tripleo container image build" instead.') - - fd, path = tempfile.mkstemp(prefix='kolla_conf_') - with os.fdopen(fd, 'w') as tmp: - tmp.write('[DEFAULT]\n') - if parsed_args.list_images or parsed_args.list_dependencies: - tmp.write('list_dependencies=true') - kolla_config_files = list(parsed_args.kolla_config_files) - kolla_config_files.append(path) - # Generate an unique work directory so we can keep configs and logs - # each time we run the command; they'll be stored in work_dir. - kolla_work_dir = os.path.join(parsed_args.work_dir, str(uuid.uuid4())) - - # Make sure the unique work directory exists - if not os.path.exists(kolla_work_dir): - self.log.debug("Creating container builds " - "workspace in: %s" % kolla_work_dir) - os.makedirs(kolla_work_dir) - - builder = kolla_builder.KollaImageBuilder(parsed_args.config_files) - result = builder.build_images(kolla_config_files, - parsed_args.excludes, - parsed_args.use_buildah, - kolla_work_dir) - - if parsed_args.use_buildah: - deps = json.loads(result) - kolla_cfg = utils.get_read_config(kolla_config_files) - bb = buildah.BuildahBuilder( - kolla_work_dir, deps, - utils.get_from_cfg(kolla_cfg, "base"), - utils.get_from_cfg(kolla_cfg, "type"), - utils.get_from_cfg(kolla_cfg, "tag"), - utils.get_from_cfg(kolla_cfg, "namespace"), - utils.get_from_cfg(kolla_cfg, "registry"), - utils.getboolean_from_cfg(kolla_cfg, "push"), - parsed_args.build_timeout, - self.app.options.debug) - bb.build_all() - elif parsed_args.list_dependencies: - deps = json.loads(result) - yaml.safe_dump( - deps, - self.app.stdout, - indent=2, - default_flow_style=False - ) - elif parsed_args.list_images: - deps = json.loads(result) - images = [] - BuildImage.images_from_deps(images, deps) - yaml.safe_dump( - images, - self.app.stdout, - default_flow_style=False - ) - elif result: - self.app.stdout.write(result) - - -class PrepareImageFiles(command.Command): - """Generate files defining the images, tags and registry.""" - - auth_required = False - log = logging.getLogger(__name__ + ".PrepareImageFiles") - - def get_parser(self, prog_name): - parser = super(PrepareImageFiles, self).get_parser(prog_name) - try: - roles_file = utils.rel_or_abs_path( - constants.OVERCLOUD_ROLES_FILE, - constants.TRIPLEO_HEAT_TEMPLATES) - except exceptions.DeploymentError: - roles_file = None - defaults = kolla_builder.container_images_prepare_defaults() - - parser.add_argument( - "--template-file", - dest="template_file", - default=kolla_builder.DEFAULT_TEMPLATE_FILE, - metavar='', - help=_("YAML template file which the images config file will be " - "built from.\n" - "Default: %s") % kolla_builder.DEFAULT_TEMPLATE_FILE, - ) - parser.add_argument( - "--push-destination", - dest="push_destination", - metavar='', - help=_("Location of image registry to push images to. " - "If specified, a push_destination will be set for every " - "image entry."), - ) - parser.add_argument( - "--tag", - dest="tag", - default=defaults['tag'], - metavar='', - help=_("Override the default tag substitution. " - "If --tag-from-label is specified, " - "start discovery with this tag.\n" - "Default: %s") % defaults['tag'], - ) - parser.add_argument( - "--tag-from-label", - dest="tag_from_label", - metavar='', - help=_("Use the value of the specified label(s) to discover the " - "tag. Labels can be combined in a template format, " - "for example: {version}-{release}"), - ) - parser.add_argument( - "--namespace", - dest="namespace", - default=defaults['namespace'], - metavar='', - help=_("Override the default namespace substitution.\n" - "Default: %s") % defaults['namespace'], - ) - parser.add_argument( - "--prefix", - dest="prefix", - default=defaults['name_prefix'], - metavar='', - help=_("Override the default name prefix substitution.\n" - "Default: %s") % defaults['name_prefix'], - ) - parser.add_argument( - "--suffix", - dest="suffix", - default=defaults['name_suffix'], - metavar='', - help=_("Override the default name suffix substitution.\n" - "Default: %s") % defaults['name_suffix'], - ) - parser.add_argument( - '--set', - metavar='', - action='append', - help=_('Set the value of a variable in the template, even if it ' - 'has no dedicated argument such as "--suffix".') - ) - parser.add_argument( - "--exclude", - dest="excludes", - metavar='', - default=[], - action="append", - help=_("Pattern to match against resulting imagename entries to " - "exclude from the final output. Can be specified multiple " - "times."), - ) - parser.add_argument( - "--include", - dest="includes", - metavar='', - default=[], - action="append", - help=_("Pattern to match against resulting imagename entries to " - "include in final output. Can be specified multiple " - "times, entries not matching any --include will be " - "excluded. --exclude is ignored if --include is used."), - ) - parser.add_argument( - "--output-images-file", - dest="output_images_file", - metavar='', - help=_("File to write resulting image entries to, as well as " - "stdout. Any existing file will be overwritten."), - ) - parser.add_argument( - '--environment-file', '-e', metavar='', - action='append', dest='environment_files', - help=_('Environment files specifying which services are ' - 'containerized. Entries will be filtered to only contain ' - 'images used by containerized services. (Can be specified ' - 'more than once.)') - ) - parser.add_argument( - '--environment-directory', metavar='', - action='append', dest='environment_directories', - default=[os.path.expanduser(constants.DEFAULT_ENV_DIRECTORY)], - help=_('Environment file directories that are automatically ' - 'added to the update command. Entries will be filtered ' - 'to only contain images used by containerized services. ' - 'Can be specified more than once. Files in directories are ' - 'loaded in ascending sort order.') - ) - parser.add_argument( - "--output-env-file", - dest="output_env_file", - metavar='', - help=_("File to write heat environment file which specifies all " - "image parameters. Any existing file will be overwritten."), - ) - parser.add_argument( - '--roles-file', '-r', dest='roles_file', - default=roles_file, - help=_( - 'Roles file, overrides the default %s in the t-h-t templates ' - 'directory used for deployment. May be an ' - 'absolute path or the path relative to the templates dir.' - ) % constants.OVERCLOUD_ROLES_FILE - ) - parser.add_argument( - '--modify-role', - dest='modify_role', - help=_('Name of ansible role to run between every image upload ' - 'pull and push.') - ) - parser.add_argument( - '--modify-vars', - dest='modify_vars', - help=_('Ansible variable file containing variables to use when ' - 'invoking the role --modify-role.') - ) - return parser - - def parse_set_values(self, subs, set_values): - if not set_values: - return - for s in set_values: - try: - (n, v) = s.split(('='), 1) - subs[n] = v - except ValueError: - msg = _('Malformed --set(%s). ' - 'Use the variable=value format.') % s - raise oscexc.CommandError(msg) - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)" % parsed_args) - self.log.warning("[DEPRECATED] This command has been deprecated and " - "replaced by the 'openstack tripleo container image " - "prepare' command.") - - roles_data = utils.fetch_roles_file(parsed_args.roles_file) or set() - - env = utils.build_prepare_env( - parsed_args.environment_files, - parsed_args.environment_directories - ) - - if roles_data: - service_filter = kolla_builder.build_service_filter( - env, roles_data) - else: - service_filter = None - mapping_args = { - 'tag': parsed_args.tag, - 'namespace': parsed_args.namespace, - 'name_prefix': parsed_args.prefix, - 'name_suffix': parsed_args.suffix, - } - self.parse_set_values(mapping_args, parsed_args.set) - pd = env.get('parameter_defaults', {}) - kolla_builder.set_neutron_driver(pd, mapping_args) - - output_images_file = (parsed_args.output_images_file - or 'container_images.yaml') - modify_role = None - modify_vars = None - append_tag = None - if parsed_args.modify_role: - modify_role = parsed_args.modify_role - append_tag = time.strftime('-modified-%Y%m%d%H%M%S') - if parsed_args.modify_vars: - with open(parsed_args.modify_vars) as m: - modify_vars = yaml.safe_load(m.read()) - - prepare_data = kolla_builder.container_images_prepare( - excludes=parsed_args.excludes, - includes=parsed_args.includes, - service_filter=service_filter, - push_destination=parsed_args.push_destination, - mapping_args=mapping_args, - output_env_file=parsed_args.output_env_file, - output_images_file=output_images_file, - tag_from_label=parsed_args.tag_from_label, - modify_role=modify_role, - modify_vars=modify_vars, - append_tag=append_tag, - template_file=parsed_args.template_file - ) - if parsed_args.output_env_file: - params = prepare_data[parsed_args.output_env_file] - output_env_file_expanded = os.path.expanduser( - parsed_args.output_env_file) - if os.path.exists(output_env_file_expanded): - self.log.warning("Output env file exists, " - "moving it to backup.") - shutil.move(output_env_file_expanded, - output_env_file_expanded + ".backup") - utils.safe_write(output_env_file_expanded, - build_env_file(params, self.app.command_options)) - - result = prepare_data[output_images_file] - result_str = yaml.safe_dump({'container_images': result}, - default_flow_style=False) - sys.stdout.write(result_str) - - if parsed_args.output_images_file: - utils.safe_write(parsed_args.output_images_file, result_str) - - -class DiscoverImageTag(command.Command): - """Discover the versioned tag for an image.""" - - auth_required = False - log = logging.getLogger(__name__ + ".DiscoverImageTag") - - def get_parser(self, prog_name): - parser = super(DiscoverImageTag, self).get_parser(prog_name) - parser.add_argument( - "--image", - dest="image", - metavar='', - required=True, - help=_("Fully qualified name of the image to discover the tag for " - "(Including registry and stable tag)."), - ) - parser.add_argument( - "--tag-from-label", - dest="tag_from_label", - metavar='', - help=_("Use the value of the specified label(s) to discover the " - "tag. Labels can be combined in a template format, " - "for example: {version}-{release}"), - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)" % parsed_args) - self.log.warning("[DEPRECATED] This command has been deprecated and " - "replaced by the 'openstack tripleo container image " - "prepare' command.") - - lock = processlock.ProcessLock() - uploader = image_uploader.ImageUploadManager([], lock=lock) - print(uploader.discover_image_tag( - image=parsed_args.image, - tag_from_label=parsed_args.tag_from_label - )) - - class TripleOContainerImagePush(command.Command): """Push specified image to registry."""