Skip to content

Commit

Permalink
pinning operator digest plugin now supports konflux images with oci.i…
Browse files Browse the repository at this point in the history
…ndex

* STONEBLD-2986

Signed-off-by: Robert Cerven <[email protected]>
  • Loading branch information
rcerven committed Nov 22, 2024
1 parent 1c5927c commit 5207f06
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 8 deletions.
12 changes: 10 additions & 2 deletions atomic_reactor/plugins/pin_operator_digest.py
Original file line number Diff line number Diff line change
Expand Up @@ -602,9 +602,17 @@ def pin_digest(self, image):
if image.tag.startswith("sha256:"):
self.log.debug("%s looks like a digest, skipping query", image.tag)
return image
self.log.debug("Querying %s for manifest list digest", image.registry)

registry_client = self._get_registry_client(image.registry)
digest = registry_client.get_manifest_list_digest(image)

self.log.debug("Querying %s for manifest list digest", image.registry)
try:
digest = registry_client.get_manifest_list_digest(image)
except RuntimeError:
self.log.debug("manifest list not found trying image index")
self.log.debug("Querying %s for manifest index digest", image.registry)
digest = registry_client.get_manifest_index_digest(image)

return self._replace(image, tag=digest)

def replace_registry(self, image):
Expand Down
12 changes: 12 additions & 0 deletions atomic_reactor/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,18 @@ def get_manifest_list_digest(self, image):
digest_dict = get_checksums(io.BytesIO(response.content), ['sha256'])
return 'sha256:{}'.format(digest_dict['sha256sum'])

def get_manifest_index_digest(self, image):
"""Return manifest index digest for image
:param image:
:return:
"""
response = self.get_manifest_index(image)
if response is None:
raise RuntimeError('Unable to fetch oci.index for {}'.format(image.to_str()))
digest_dict = get_checksums(io.BytesIO(response.content), ['sha256'])
return 'sha256:{}'.format(digest_dict['sha256sum'])

def get_all_manifests(
self, image: ImageName, versions: Sequence[str] = ('v1', 'v2', 'v2_list', 'oci_index')
) -> Dict[str, requests.Response]:
Expand Down
63 changes: 57 additions & 6 deletions tests/plugins/test_pin_operator_digests.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ def mock_package_mapping_files(repo_replacements):
return repo_replacements


def mock_digest_query(image_digest_map):
def mock_digest_query(image_digest_map, manifest_list_raises=False, manifest_index_raises=False):

updated_map = {
ImageName.parse(pullspec).to_str(): digest
Expand All @@ -219,9 +219,23 @@ def mock_digest_query(image_digest_map):
def mocked_get_manifest_list_digest(image):
return updated_map[image.to_str()]

(flexmock(atomic_reactor.util.RegistryClient)
.should_receive('get_manifest_list_digest')
.replace_with(mocked_get_manifest_list_digest))
if manifest_list_raises:
(flexmock(atomic_reactor.util.RegistryClient)
.should_receive('get_manifest_list_digest')
.and_raise(RuntimeError, "Unable to fetch v2.manifest_list for"))
else:
(flexmock(atomic_reactor.util.RegistryClient)
.should_receive('get_manifest_list_digest')
.replace_with(mocked_get_manifest_list_digest))

if manifest_index_raises:
(flexmock(atomic_reactor.util.RegistryClient)
.should_receive('get_manifest_index_digest')
.and_raise(RuntimeError, "Unable to fetch oci.index for {}"))
else:
(flexmock(atomic_reactor.util.RegistryClient)
.should_receive('get_manifest_index_digest')
.replace_with(mocked_get_manifest_list_digest))


def mock_inspect_query(pullspec, labels, times=1):
Expand Down Expand Up @@ -424,9 +438,46 @@ def test_raise_error_if_csv_has_both_related_images_and_related_env_vars(
)
assert expected in str(exc_info.value)

@responses.activate
def test_raise_when_manifest_list_and_index_not_found(self, workflow, repo_dir):
pullspecs = [
'old-registry/ns/spam@sha256:4', # -> new-registry/new-ns/new-spam@sha256:4
'old-registry/ns/spam:1', # -> new-registry/new-ns/new-spam@sha256:4
]
replacement_pullspecs = {
'old-registry/ns/spam@sha256:4': 'new-registry/new-ns/new-spam@sha256:4',
'old-registry/ns/spam:1': 'new-registry/new-ns/new-spam@sha256:4',
}

mock_digest_query({
'old-registry/ns/spam:1': 'sha256:4',
}, manifest_list_raises=True, manifest_index_raises=True)

manifests_dir = repo_dir.joinpath(OPERATOR_MANIFESTS_DIR)
manifests_dir.mkdir()
mock_operator_csv(manifests_dir, 'csv.yaml', pullspecs)

user_config = get_user_config(OPERATOR_MANIFESTS_DIR)
site_config = get_site_config()

pull_registries = {'pull_registries': [
{'url': 'https://old-registry'},
]}

runner = mock_env(workflow, repo_dir, site_config=site_config,
add_to_config=pull_registries, user_config=user_config,
replacement_pullspecs=replacement_pullspecs)

with pytest.raises(PluginFailedException) as exc_info:
runner.run()

expected_error = "Unable to fetch oci.index for"
assert expected_error in str(exc_info.value)

@pytest.mark.parametrize('ocp_44', [True, False])
@pytest.mark.parametrize('manifest_list_raises', [True, False])
@responses.activate
def test_pin_operator_digest(self, ocp_44, workflow, repo_dir, caplog):
def test_pin_operator_digest(self, ocp_44, manifest_list_raises, workflow, repo_dir, caplog):
pullspecs = [
# registry.private.example.com: do not replace registry or repos
'registry.private.example.com/ns/foo@sha256:1', # -> no change
Expand Down Expand Up @@ -485,7 +536,7 @@ def test_pin_operator_digest(self, ocp_44, workflow, repo_dir, caplog):
'weird-registry/ns/bar:1': 'sha256:2',
'private-registry/ns/baz:1': 'sha256:3',
'old-registry/ns/spam:1': 'sha256:4',
})
}, manifest_list_raises=manifest_list_raises)
# there should be no queries for the pullspecs which already contain a digest

# images should be inspected after their digests are pinned
Expand Down

0 comments on commit 5207f06

Please sign in to comment.