Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pinning operator digest plugin now supports konflux images with oci.index #2131

Merged
merged 1 commit into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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