diff --git a/tripleo_common/image/kolla_builder.py b/tripleo_common/image/kolla_builder.py index 7c92fdde3..a0bec7358 100644 --- a/tripleo_common/image/kolla_builder.py +++ b/tripleo_common/image/kolla_builder.py @@ -20,6 +20,7 @@ import os import re import subprocess import sys +import tempfile import yaml from tripleo_common.image import base @@ -83,6 +84,57 @@ def build_service_filter(environment, roles_data): return containerized_services.intersection(enabled_services) +def container_images_prepare_multi(environment, roles_data): + """Perform multiple container image prepares and merge result + + Given the full heat environment and roles data, perform multiple image + prepare operations. The data to drive the multiple prepares is taken from + the ContainerImagePrepare parameter in the provided environment. If + push_destination is specified, uploads will be performed during the + preparation. + + :param environment: Heat environment for deployment + :param roles_data: Roles file data used to filter services + :returns: dict containing merged container image parameters from all + prepare operations + """ + + pd = environment.get('parameter_defaults', {}) + cip = pd.get('ContainerImagePrepare') + if not cip: + return + + env_params = {} + service_filter = build_service_filter(environment, roles_data) + + for cip_entry in cip: + mapping_args = cip_entry.get('set') + push_destination = cip_entry.get('push_destination') + pull_source = cip_entry.get('pull_source') + + prepare_data = container_images_prepare( + excludes=cip_entry.get('excludes'), + service_filter=service_filter, + pull_source=pull_source, + push_destination=push_destination, + mapping_args=mapping_args, + output_env_file='image_params', + output_images_file='upload_data', + tag_from_label=cip_entry.get('tag_from_label'), + ) + env_params.update(prepare_data['image_params']) + + if push_destination or pull_source: + with tempfile.NamedTemporaryFile(mode='w') as f: + yaml.safe_dump({ + 'container_images': prepare_data['upload_data'] + }, f) + uploader = image_uploader.ImageUploadManager( + [f.name], verbose=True) + uploader.upload() + return env_params + + def container_images_prepare_defaults(): """Return default dict for prepare substitutions diff --git a/tripleo_common/tests/image/test_kolla_builder.py b/tripleo_common/tests/image/test_kolla_builder.py index 3ab6c489d..1438aba81 100644 --- a/tripleo_common/tests/image/test_kolla_builder.py +++ b/tripleo_common/tests/image/test_kolla_builder.py @@ -649,3 +649,88 @@ class TestPrepare(base.TestCase): } ]) ) + + @mock.patch('tripleo_common.image.kolla_builder.container_images_prepare') + @mock.patch('tripleo_common.image.image_uploader.ImageUploadManager', + autospec=True) + def test_container_images_prepare_multi(self, mock_im, mock_cip): + mapping_args = { + 'namespace': 't', + 'name_prefix': '', + 'name_suffix': '', + 'tag': 'l', + } + env = { + 'parameter_defaults': { + 'ContainerImagePrepare': [{ + 'set': mapping_args, + 'tag_from_label': 'foo', + }, { + 'set': mapping_args, + 'tag_from_label': 'bar', + 'excludes': ['nova', 'neutron'], + 'push_destination': '192.0.2.1:8787' + }] + } + } + roles_data = [] + mock_cip.side_effect = [ + { + 'image_params': { + 'FooImage': 't/foo:latest', + 'BarImage': 't/bar:latest', + 'BazImage': 't/baz:latest', + 'BinkImage': 't/bink:latest' + }, + 'upload_data': [] + }, { + 'image_params': { + 'BarImage': 't/bar:1.0', + 'BazImage': 't/baz:1.0' + }, + 'upload_data': [{ + 'imagename': 't/bar:1.0', + 'push_destination': '192.0.2.1:8787' + }, { + 'imagename': 't/baz:1.0', + 'push_destination': '192.0.2.1:8787' + }] + }, + ] + + image_params = kb.container_images_prepare_multi(env, roles_data) + + mock_cip.assert_has_calls([ + mock.call( + excludes=None, + mapping_args=mapping_args, + output_env_file='image_params', + output_images_file='upload_data', + pull_source=None, + push_destination=None, + service_filter=set([]), + tag_from_label='foo' + ), + mock.call( + excludes=['nova', 'neutron'], + mapping_args=mapping_args, + output_env_file='image_params', + output_images_file='upload_data', + pull_source=None, + push_destination='192.0.2.1:8787', + service_filter=set([]), + tag_from_label='bar' + ) + ]) + + mock_im.assert_called_once() + + self.assertEqual( + { + 'BarImage': 't/bar:1.0', + 'BazImage': 't/baz:1.0', + 'BinkImage': 't/bink:latest', + 'FooImage': 't/foo:latest' + }, + image_params + )