Define the interface for multi arch image prepare

If the `AdditionalArchitectures` parameter has entries then the
container image prepare will prepare images for all architectures
instead of just the default one. A new boolean field `multi_arch` can
also be set in `ContainerImagePrepare` entries to determine the multi
arch behaviour for images in that entry. If any entry sets a
`multi_arch` value then `AdditionalArchitectures` is ignored.

This change defines the interface for supporting multi-arch prepare
operations, a later change in this series will implement the support.

Blueprint: multiarch-support
Change-Id: Ia7b33ab6bec0fabc8632e58807e749b6e2a8c9a3
This commit is contained in:
Steve Baker 2019-05-03 14:11:54 -06:00
parent 3d593a4b3f
commit 08ae3286c7
5 changed files with 63 additions and 22 deletions

View File

@ -0,0 +1,9 @@
---
features:
- |
If the `AdditionalArchitectures` parameter has entries then the container
image prepare will prepare images for all architectures instead of just
the default one. A new boolean field `multi_arch` can also be set in
`ContainerImagePrepare` entries to determine the multi arch behaviour for
images in that entry. If any entry sets a `multi_arch` value then
`AdditionalArchitectures` is ignored.

View File

@ -109,7 +109,8 @@ class ImageUploadManager(BaseImageManager):
def __init__(self, config_files=None,
dry_run=False, cleanup=CLEANUP_FULL,
mirrors=None, registry_credentials=None):
mirrors=None, registry_credentials=None,
multi_arch=False):
if config_files is None:
config_files = []
super(ImageUploadManager, self).__init__(config_files)
@ -126,6 +127,7 @@ class ImageUploadManager(BaseImageManager):
self.validate_registry_credentials(registry_credentials)
for uploader in self.uploaders.values():
uploader.registry_credentials = registry_credentials
self.multi_arch = multi_arch
def validate_registry_credentials(self, creds_data):
if not isinstance(creds_data, dict):
@ -189,12 +191,13 @@ class ImageUploadManager(BaseImageManager):
append_tag = item.get('modify_append_tag')
modify_role = item.get('modify_role')
modify_vars = item.get('modify_vars')
multi_arch = item.get('multi_arch', self.multi_arch)
uploader = self.uploader(uploader)
task = UploadTask(
image_name, pull_source, push_destination,
append_tag, modify_role, modify_vars, self.dry_run,
self.cleanup)
self.cleanup, multi_arch)
uploader.add_upload_task(task)
for uploader in self.uploaders.values():
@ -1645,7 +1648,8 @@ class PythonImageUploader(BaseImageUploader):
class UploadTask(object):
def __init__(self, image_name, pull_source, push_destination,
append_tag, modify_role, modify_vars, dry_run, cleanup):
append_tag, modify_role, modify_vars, dry_run, cleanup,
multi_arch):
self.image_name = image_name
self.pull_source = pull_source
self.push_destination = push_destination
@ -1654,6 +1658,7 @@ class UploadTask(object):
self.modify_vars = modify_vars
self.dry_run = dry_run
self.cleanup = cleanup
self.multi_arch = multi_arch
if ':' in image_name:
image = image_name.rpartition(':')[0]

View File

@ -151,6 +151,7 @@ def container_images_prepare_multi(environment, roles_data, dry_run=False,
mirrors['docker.io'] = mirror
creds = pd.get('ContainerImageRegistryCredentials')
multi_arch = len(pd.get('AdditionalArchitectures', []))
env_params = {}
service_filter = build_service_filter(environment, roles_data)
@ -172,6 +173,10 @@ def container_images_prepare_multi(environment, roles_data, dry_run=False,
modify_append_tag = cip_entry.get('modify_append_tag',
time.strftime(
'-modified-%Y%m%d%H%M%S'))
if multi_arch and 'multi_arch' in cip_entry:
# individual entry sets multi_arch,
# so set global multi_arch to False
multi_arch = False
prepare_data = container_images_prepare(
excludes=cip_entry.get('excludes'),
@ -188,7 +193,8 @@ def container_images_prepare_multi(environment, roles_data, dry_run=False,
modify_vars=modify_vars,
modify_only_with_labels=modify_only_with_labels,
mirrors=mirrors,
registry_credentials=creds
registry_credentials=creds,
multi_arch=multi_arch
)
env_params.update(prepare_data['image_params'])
@ -202,7 +208,8 @@ def container_images_prepare_multi(environment, roles_data, dry_run=False,
dry_run=dry_run,
cleanup=cleanup,
mirrors=mirrors,
registry_credentials=creds
registry_credentials=creds,
multi_arch=multi_arch
)
uploader.upload()
return env_params
@ -225,7 +232,8 @@ def container_images_prepare(template_file=DEFAULT_TEMPLATE_FILE,
output_images_file=None, tag_from_label=None,
append_tag=None, modify_role=None,
modify_vars=None, modify_only_with_labels=None,
mirrors=None, registry_credentials=None):
mirrors=None, registry_credentials=None,
multi_arch=False):
"""Perform container image preparation
:param template_file: path to Jinja2 file containing all image entries
@ -257,6 +265,8 @@ def container_images_prepare(template_file=DEFAULT_TEMPLATE_FILE,
The value is a single-entry dict where the
username is the key and the password is the
value.
:param multi_arch: boolean whether to prepare every architecture of
each image
:returns: dict with entries for the supplied output_env_file or
output_images_file
"""
@ -287,7 +297,10 @@ def container_images_prepare(template_file=DEFAULT_TEMPLATE_FILE,
filter=ffunc, **mapping_args)
manager = image_uploader.ImageUploadManager(
mirrors=mirrors, registry_credentials=registry_credentials)
mirrors=mirrors,
registry_credentials=registry_credentials,
multi_arch=multi_arch
)
uploader = manager.uploader('python')
images = [i.get('imagename', '') for i in result]

View File

@ -857,7 +857,8 @@ class TestSkopeoImageUploader(base.TestCase):
None,
None,
False,
'full')
'full',
False)
)
)
mock_popen.assert_called_once_with([
@ -921,7 +922,8 @@ class TestSkopeoImageUploader(base.TestCase):
'add-foo-plugin',
{'foo_version': '1.0.1'},
False,
'partial')
'partial',
False)
)
)
@ -981,7 +983,7 @@ class TestSkopeoImageUploader(base.TestCase):
self.uploader.upload_image, image_uploader.UploadTask(
image + ':' + tag, None, push_destination,
append_tag, 'add-foo-plugin', {'foo_version': '1.0.1'},
False, 'full')
False, 'full', False)
)
mock_copy.assert_called_once_with(
@ -1009,7 +1011,8 @@ class TestSkopeoImageUploader(base.TestCase):
'add-foo-plugin',
{'foo_version': '1.0.1'},
True,
'full')
'full',
False)
)
mock_ansible.assert_not_called()
@ -1039,7 +1042,8 @@ class TestSkopeoImageUploader(base.TestCase):
'add-foo-plugin',
{'foo_version': '1.0.1'},
False,
'full')
'full',
False)
)
mock_ansible.assert_not_called()
@ -1149,7 +1153,8 @@ class TestPythonImageUploader(base.TestCase):
modify_role=None,
modify_vars=None,
dry_run=False,
cleanup='full'
cleanup='full',
multi_arch=False
)
self.assertEqual(
@ -1241,7 +1246,8 @@ class TestPythonImageUploader(base.TestCase):
modify_role=None,
modify_vars=None,
dry_run=False,
cleanup='full'
cleanup='full',
multi_arch=False
)
self.assertEqual(
@ -1307,7 +1313,8 @@ class TestPythonImageUploader(base.TestCase):
modify_role=None,
modify_vars=None,
dry_run=False,
cleanup='full'
cleanup='full',
multi_arch=False
)
self.assertEqual(
@ -1372,7 +1379,8 @@ class TestPythonImageUploader(base.TestCase):
modify_role=None,
modify_vars=None,
dry_run=False,
cleanup='full'
cleanup='full',
multi_arch=False
)
self.assertEqual(
@ -1471,7 +1479,8 @@ class TestPythonImageUploader(base.TestCase):
modify_role='add-foo-plugin',
modify_vars={'foo_version': '1.0.1'},
dry_run=False,
cleanup='full'
cleanup='full',
multi_arch=False
)
source_url = urlparse(

View File

@ -1104,7 +1104,8 @@ class TestPrepare(base.TestCase):
},
registry_credentials={
'docker.io': {'my_username': 'my_password'}
}
},
multi_arch=False
),
mock.call(
excludes=['nova', 'neutron'],
@ -1125,7 +1126,8 @@ class TestPrepare(base.TestCase):
},
registry_credentials={
'docker.io': {'my_username': 'my_password'}
}
},
multi_arch=False
)
])
@ -1211,7 +1213,8 @@ class TestPrepare(base.TestCase):
modify_only_with_labels=None,
modify_vars=None,
mirrors={},
registry_credentials=None
registry_credentials=None,
multi_arch=False
),
mock.call(
excludes=['nova', 'neutron'],
@ -1228,12 +1231,14 @@ class TestPrepare(base.TestCase):
modify_only_with_labels=['kolla_version'],
modify_vars={'foo_version': '1.0.1'},
mirrors={},
registry_credentials=None
registry_credentials=None,
multi_arch=False
)
])
mock_im.assert_called_once_with(mock.ANY, dry_run=True, cleanup='full',
mirrors={}, registry_credentials=None)
mirrors={}, registry_credentials=None,
multi_arch=False)
self.assertEqual(
{