Don't assume default tag exists in container repo
When no tag is set for an entry in ContainerImagePrepare, the default tag from container-images/container_image_prepare_defaults.yaml will be assumed, which is typically current-tripleo, or a release version such as 16.0. In most cases, this tag will exist. However, when using a satellite with a content view that has been filtered on tags, it likely won't exist since content views are often used with container image versions that are not the latest. In the case where no tag is set in the entry in ContainerImagePrepare, and the default tag does not exist in the container repo, the latest tag from the repo will be assumed instead. Change-Id: I985ef22c340c4071866c8c51bf303a6f4ee7713c Closes-Bug: #1886547 Signed-off-by: James Slagle <jslagle@redhat.com>
This commit is contained in:
parent
733caa908e
commit
0c4de9c771
@ -17,6 +17,7 @@ parameter_defaults:
|
||||
name_prefix: centos-binary-
|
||||
name_suffix: ''
|
||||
tag: current-tripleo
|
||||
default_tag: True
|
||||
rhel_containers: false
|
||||
|
||||
# Substitute neutron images based on driver. Can be 'other', 'ovn' or
|
||||
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
fixes:
|
||||
- When the default tag doesn't exist in the container repo during container
|
||||
image prepare, and a tag wasn't set in the actual input for
|
||||
ContainerImagePrepare, the latest tag from the repo will be used instead of
|
||||
failing with a not found error.
|
@ -717,19 +717,24 @@ class BaseImageUploader(object):
|
||||
wait=tenacity.wait_random_exponential(multiplier=1, max=10),
|
||||
stop=tenacity.stop_after_attempt(5)
|
||||
)
|
||||
def _inspect(cls, image_url, session=None):
|
||||
def _inspect(cls, image_url, session=None, default_tag=False):
|
||||
image, tag = cls._image_tag_from_url(image_url)
|
||||
parts = {
|
||||
'image': image,
|
||||
'tag': tag
|
||||
}
|
||||
|
||||
manifest_url = cls._build_url(
|
||||
image_url, CALL_MANIFEST % parts
|
||||
)
|
||||
tags_url = cls._build_url(
|
||||
image_url, CALL_TAGS % parts
|
||||
)
|
||||
tags_r = RegistrySessionHelper.get(session, tags_url, timeout=30)
|
||||
tags = tags_r.json()['tags']
|
||||
if default_tag and tag not in tags:
|
||||
parts['tag'] = tags[-1]
|
||||
|
||||
manifest_url = cls._build_url(
|
||||
image_url, CALL_MANIFEST % parts
|
||||
)
|
||||
manifest_headers = {'Accept': MEDIA_MANIFEST_V2}
|
||||
|
||||
try:
|
||||
@ -746,8 +751,6 @@ class BaseImageUploader(object):
|
||||
else:
|
||||
raise
|
||||
|
||||
tags_r = RegistrySessionHelper.get(session, tags_url, timeout=30)
|
||||
|
||||
manifest_str = cls._get_response_text(manifest_r)
|
||||
|
||||
if 'Docker-Content-Digest' in manifest_r.headers:
|
||||
@ -781,8 +784,6 @@ class BaseImageUploader(object):
|
||||
)
|
||||
config = config_r.json()
|
||||
|
||||
tags = tags_r.json()['tags']
|
||||
|
||||
image, tag = cls._image_tag_from_url(image_url)
|
||||
name = '%s%s' % (image_url.netloc, image)
|
||||
created = config['created']
|
||||
@ -932,7 +933,8 @@ class BaseImageUploader(object):
|
||||
)
|
||||
return tag_label
|
||||
|
||||
def discover_image_tags(self, images, tag_from_label=None):
|
||||
def discover_image_tags(self, images, tag_from_label=None,
|
||||
default_tag=False):
|
||||
image_urls = [self._image_to_url(i) for i in images]
|
||||
|
||||
# prime self.insecure_registries by testing every image
|
||||
@ -941,7 +943,8 @@ class BaseImageUploader(object):
|
||||
|
||||
discover_args = []
|
||||
for image in images:
|
||||
discover_args.append((self, image, tag_from_label))
|
||||
discover_args.append((self, image, tag_from_label,
|
||||
default_tag))
|
||||
|
||||
versioned_images = {}
|
||||
with futures.ThreadPoolExecutor(max_workers=16) as p:
|
||||
@ -2379,10 +2382,10 @@ class PythonImageUploader(BaseImageUploader):
|
||||
return image, manifest, config_str
|
||||
|
||||
@classmethod
|
||||
def _inspect(cls, image_url, session=None):
|
||||
def _inspect(cls, image_url, session=None, default_tag=False):
|
||||
if image_url.scheme == 'docker':
|
||||
return super(PythonImageUploader, cls)._inspect(
|
||||
image_url, session=session)
|
||||
image_url, session=session, default_tag=default_tag)
|
||||
if image_url.scheme != 'containers-storage':
|
||||
raise ImageUploaderException('Inspect not implemented for %s' %
|
||||
image_url.geturl())
|
||||
@ -2543,7 +2546,7 @@ def upload_task(args):
|
||||
|
||||
|
||||
def discover_tag_from_inspect(args):
|
||||
self, image, tag_from_label = args
|
||||
self, image, tag_from_label, default_tag = args
|
||||
image_url = self._image_to_url(image)
|
||||
username, password = self.credentials_for_registry(image_url.netloc)
|
||||
try:
|
||||
@ -2556,7 +2559,7 @@ def discover_tag_from_inspect(args):
|
||||
'missing registry credentials or the provided '
|
||||
'container or namespace does not exist. %s' % e)
|
||||
raise
|
||||
i = self._inspect(image_url, session=session)
|
||||
i = self._inspect(image_url, session=session, default_tag=default_tag)
|
||||
session.close()
|
||||
if ':' in image_url.path:
|
||||
# break out the tag from the url to be the fallback tag
|
||||
|
@ -328,10 +328,14 @@ def container_images_prepare(template_file=DEFAULT_TEMPLATE_FILE,
|
||||
)
|
||||
uploader = manager.uploader('python')
|
||||
images = [i.get('imagename', '') for i in result]
|
||||
if result:
|
||||
default_tag = result[0].get('default_tag', False)
|
||||
else:
|
||||
default_tag = False
|
||||
|
||||
if tag_from_label:
|
||||
image_version_tags = uploader.discover_image_tags(
|
||||
images, tag_from_label)
|
||||
images, tag_from_label, default_tag)
|
||||
for entry in result:
|
||||
imagename = entry.get('imagename', '')
|
||||
image_no_tag = imagename.rpartition(':')[0]
|
||||
@ -436,6 +440,12 @@ class KollaImageBuilder(base.BaseImageManager):
|
||||
hyphenated appropriately.
|
||||
'''
|
||||
mapping = dict(kwargs)
|
||||
# set a flag to record whether the default tag is used or not. the
|
||||
# logic here is that if the tag key is not already in mapping then it
|
||||
# wil be added during the template render, so default_tag is set to
|
||||
# True.
|
||||
mapping['default_tag'] = 'tag' not in mapping
|
||||
|
||||
if CONTAINER_IMAGES_DEFAULTS is None:
|
||||
return
|
||||
for k, v in CONTAINER_IMAGES_DEFAULTS.items():
|
||||
|
@ -527,12 +527,12 @@ class TestBaseImageUploader(base.TestCase):
|
||||
self.assertRaises(
|
||||
ImageUploaderException,
|
||||
image_uploader.discover_tag_from_inspect,
|
||||
(self.uploader, 'docker.io/t/foo', 'rdo_version')
|
||||
(self.uploader, 'docker.io/t/foo', 'rdo_version', False)
|
||||
)
|
||||
self.assertRaises(
|
||||
requests.exceptions.HTTPError,
|
||||
image_uploader.discover_tag_from_inspect,
|
||||
(self.uploader, 'docker.io/t/foo', 'rdo_version')
|
||||
(self.uploader, 'docker.io/t/foo', 'rdo_version', False)
|
||||
)
|
||||
|
||||
@mock.patch('tripleo_common.image.image_uploader.'
|
||||
@ -554,63 +554,65 @@ class TestBaseImageUploader(base.TestCase):
|
||||
self.assertEqual(
|
||||
('docker.io/t/foo', 'a'),
|
||||
image_uploader.discover_tag_from_inspect(
|
||||
(self.uploader, 'docker.io/t/foo', 'rdo_version'))
|
||||
(self.uploader, 'docker.io/t/foo', 'rdo_version', False))
|
||||
)
|
||||
|
||||
# templated labels -> tag
|
||||
self.assertEqual(
|
||||
('docker.io/t/foo', '1.0.0-20180125'),
|
||||
image_uploader.discover_tag_from_inspect(
|
||||
(self.uploader, 'docker.io/t/foo', '{release}-{version}'))
|
||||
(self.uploader, 'docker.io/t/foo', '{release}-{version}',
|
||||
False))
|
||||
)
|
||||
|
||||
# simple label -> tag with fallback
|
||||
self.assertEqual(
|
||||
('docker.io/t/foo', 'a'),
|
||||
image_uploader.discover_tag_from_inspect(
|
||||
(self.uploader, 'docker.io/t/foo:a', 'bar'))
|
||||
(self.uploader, 'docker.io/t/foo:a', 'bar', False))
|
||||
)
|
||||
|
||||
# templated labels -> tag with fallback
|
||||
self.assertEqual(
|
||||
('docker.io/t/foo', 'a'),
|
||||
image_uploader.discover_tag_from_inspect(
|
||||
(self.uploader, 'docker.io/t/foo:a', '{releases}-{versions}'))
|
||||
(self.uploader, 'docker.io/t/foo:a', '{releases}-{versions}',
|
||||
False))
|
||||
)
|
||||
|
||||
# Invalid template
|
||||
self.assertRaises(
|
||||
ImageUploaderException,
|
||||
image_uploader.discover_tag_from_inspect,
|
||||
(self.uploader, 'docker.io/t/foo', '{release}-{version')
|
||||
(self.uploader, 'docker.io/t/foo', '{release}-{version', False)
|
||||
)
|
||||
|
||||
# Missing label in template
|
||||
self.assertRaises(
|
||||
ImageUploaderException,
|
||||
image_uploader.discover_tag_from_inspect,
|
||||
(self.uploader, 'docker.io/t/foo', '{releases}-{version}')
|
||||
(self.uploader, 'docker.io/t/foo', '{releases}-{version}', False)
|
||||
)
|
||||
|
||||
# no tag_from_label specified
|
||||
self.assertRaises(
|
||||
ImageUploaderException,
|
||||
image_uploader.discover_tag_from_inspect,
|
||||
(self.uploader, 'docker.io/t/foo', None)
|
||||
(self.uploader, 'docker.io/t/foo', None, False)
|
||||
)
|
||||
|
||||
# missing RepoTags entry
|
||||
self.assertRaises(
|
||||
ImageUploaderException,
|
||||
image_uploader.discover_tag_from_inspect,
|
||||
(self.uploader, 'docker.io/t/foo', 'build_version')
|
||||
(self.uploader, 'docker.io/t/foo', 'build_version', False)
|
||||
)
|
||||
|
||||
# missing Labels entry
|
||||
self.assertRaises(
|
||||
ImageUploaderException,
|
||||
image_uploader.discover_tag_from_inspect,
|
||||
(self.uploader, 'docker.io/t/foo', 'version')
|
||||
(self.uploader, 'docker.io/t/foo', 'version', False)
|
||||
)
|
||||
|
||||
# inspect call failed
|
||||
@ -618,7 +620,7 @@ class TestBaseImageUploader(base.TestCase):
|
||||
self.assertRaises(
|
||||
ImageUploaderException,
|
||||
image_uploader.discover_tag_from_inspect,
|
||||
(self.uploader, 'docker.io/t/foo', 'rdo_version')
|
||||
(self.uploader, 'docker.io/t/foo', 'rdo_version', False)
|
||||
)
|
||||
|
||||
# handle auth issues
|
||||
@ -632,12 +634,12 @@ class TestBaseImageUploader(base.TestCase):
|
||||
self.assertRaises(
|
||||
ImageUploaderException,
|
||||
image_uploader.discover_tag_from_inspect,
|
||||
(self.uploader, 'docker.io/t/foo', 'rdo_version')
|
||||
(self.uploader, 'docker.io/t/foo', 'rdo_version', False)
|
||||
)
|
||||
self.assertRaises(
|
||||
requests.exceptions.HTTPError,
|
||||
image_uploader.discover_tag_from_inspect,
|
||||
(self.uploader, 'docker.io/t/foo', 'rdo_version')
|
||||
(self.uploader, 'docker.io/t/foo', 'rdo_version', False)
|
||||
)
|
||||
|
||||
@mock.patch('concurrent.futures.ThreadPoolExecutor')
|
||||
@ -665,9 +667,9 @@ class TestBaseImageUploader(base.TestCase):
|
||||
mock_map.assert_called_once_with(
|
||||
image_uploader.discover_tag_from_inspect,
|
||||
[
|
||||
(self.uploader, 'docker.io/t/foo', 'rdo_release'),
|
||||
(self.uploader, 'docker.io/t/bar', 'rdo_release'),
|
||||
(self.uploader, 'docker.io/t/baz', 'rdo_release')
|
||||
(self.uploader, 'docker.io/t/foo', 'rdo_release', False),
|
||||
(self.uploader, 'docker.io/t/bar', 'rdo_release', False),
|
||||
(self.uploader, 'docker.io/t/baz', 'rdo_release', False)
|
||||
])
|
||||
|
||||
@mock.patch('tripleo_common.image.image_uploader.'
|
||||
|
@ -241,6 +241,7 @@ class TestKollaImageBuilderTemplate(base.TestCase):
|
||||
'name_suffix': '',
|
||||
'rhel_containers': False,
|
||||
'neutron_driver': 'ovn',
|
||||
'default_tag': True,
|
||||
}
|
||||
for key in (
|
||||
'namespace',
|
||||
@ -277,6 +278,7 @@ class TestKollaImageBuilderTemplate(base.TestCase):
|
||||
'ceph_tag': 'latest',
|
||||
'name_prefix': 'prefix-',
|
||||
'name_suffix': '-suffix',
|
||||
'default_tag': False,
|
||||
'tag': 'master',
|
||||
'rhel_containers': False,
|
||||
'neutron_driver': 'ovn',
|
||||
|
Loading…
Reference in New Issue
Block a user