def _get_image_arches(pull_spec): """ Get the architectures this image was built for. :param str pull_spec: the pull specification to a v2 manifest list :return: a set of architectures of the container images contained in the manifest list :rtype: set :raises IIBError: if the pull specification is not a v2 manifest list """ log.debug('Get the available arches for %s', pull_spec) skopeo_raw = skopeo_inspect(f'docker://{pull_spec}', '--raw') arches = set() if skopeo_raw.get( 'mediaType' ) == 'application/vnd.docker.distribution.manifest.list.v2+json': for manifest in skopeo_raw['manifests']: arches.add(manifest['platform']['architecture']) elif skopeo_raw.get( 'mediaType' ) == 'application/vnd.docker.distribution.manifest.v2+json': skopeo_out = skopeo_inspect(f'docker://{pull_spec}', '--config') arches.add(skopeo_out['architecture']) else: raise IIBError( f'The pull specification of {pull_spec} is neither a v2 manifest list nor a v2 manifest' ) return arches
def _push_image(request_id, arch): """ Push the single arch container image to the configured registry. :param int request_id: the ID of the IIB build request :param str arch: the architecture of the container image to push :raises IIBError: if the push fails """ source = _get_local_pull_spec(request_id, arch) destination = _get_external_arch_pull_spec(request_id, arch, include_transport=True) log.info('Pushing the container image %s to %s', source, destination) run_cmd( ['podman', 'push', '-q', source, destination], exc_msg= f'Failed to push the container image to {destination} for the arch {arch}', ) log.debug( f'Verifying that {destination} was pushed as a v2 manifest due to RHBZ#1810768' ) skopeo_raw = skopeo_inspect(destination, '--raw') if skopeo_raw['schemaVersion'] != 2: log.warning( 'The manifest for %s ended up using schema version 1 due to RHBZ#1810768. Manually ' 'fixing it with skopeo.', destination, ) exc_msg = f'Failed to fix the manifest schema version on {destination}' _skopeo_copy(destination, destination, exc_msg=exc_msg)
def test_skopeo_inspect(mock_run_cmd): mock_run_cmd.return_value = '{"Name": "some-image"}' image = 'docker://some-image:latest' rv = utils.skopeo_inspect(image) assert rv == {"Name": "some-image"} skopeo_args = mock_run_cmd.call_args[0][0] expected = ['skopeo', '--command-timeout', '300s', 'inspect', image] assert skopeo_args == expected
def test_skopeo_inspect_cache(mock_run_cmd, moc_dpr_get): mock_run_cmd.return_value = '{"Name": "some-image-cache"}' image = 'docker://some-image-cache@sha256:129bfb6af3e03997eb_not_real_sha_c7c18d89b40d97' rv_expected = {'Name': 'some-image-cache'} moc_dpr_get.return_value = rv_expected rv = utils.skopeo_inspect(image) assert rv == rv_expected assert mock_run_cmd.called is False assert mock_run_cmd.call_args is None
def test_skopeo_inspect_no_cache(mock_run_cmd, moc_dpr_get): mock_run_cmd.return_value = '{"Name": "some-image-cache"}' image = 'docker://some-image-no-cache:tag' rv_expected = {"Name": "some-image-cache"} rv = utils.skopeo_inspect(image) assert rv == rv_expected assert mock_run_cmd.called is True assert moc_dpr_get.called is False skopeo_args = mock_run_cmd.call_args[0][0] args_expected = ['skopeo', '--command-timeout', '300s', 'inspect', image] assert skopeo_args == args_expected
def _get_resolved_image(pull_spec): """ Get the pull specification of the container image using its digest. :param str pull_spec: the pull specification of the container image to resolve :return: the resolved pull specification :rtype: str """ log.debug('Resolving %s', pull_spec) skopeo_output = skopeo_inspect(f'docker://{pull_spec}') pull_spec_resolved = f'{skopeo_output["Name"]}@{skopeo_output["Digest"]}' log.debug('%s resolved to %s', pull_spec, pull_spec_resolved) return pull_spec_resolved
def _get_resolved_image(pull_spec): """ Get the pull specification of the container image using its digest. :param str pull_spec: the pull specification of the container image to resolve :return: the resolved pull specification :rtype: str """ log.debug('Resolving %s', pull_spec) name = _get_container_image_name(pull_spec) skopeo_output = skopeo_inspect(f'docker://{pull_spec}', '--raw', return_json=False) digest = hashlib.sha256(skopeo_output.encode('utf-8')).hexdigest() pull_spec_resolved = f'{name}@sha256:{digest}' log.debug('%s resolved to %s', pull_spec, pull_spec_resolved) return pull_spec_resolved
def _get_resolved_bundles(bundles): """ Get the pull specification of the bundle images using their digests. Determine if the pull spec refers to a manifest list. If so, simply use the digest of the first item in the manifest list. If not a manifest list, it must be a v2s2 image manifest and should be used as it is. :param list bundles: the list of bundle images to be resolved. :return: the list of bundle images resolved to their digests. :rtype: list :raises IIBError: if unable to resolve a bundle image. """ log.info('Resolving bundles %s', ', '.join(bundles)) resolved_bundles = set() for bundle_pull_spec in bundles: skopeo_raw = skopeo_inspect(f'docker://{bundle_pull_spec}', '--raw') if (skopeo_raw.get('mediaType') == 'application/vnd.docker.distribution.manifest.list.v2+json'): # Get the digest of the first item in the manifest list digest = skopeo_raw['manifests'][0]['digest'] if '@' in bundle_pull_spec: repo = bundle_pull_spec.split('@', 1)[0] else: repo = bundle_pull_spec.rsplit(':', 1)[0] resolved_bundles.add(f'{repo}@{digest}') elif (skopeo_raw.get('mediaType') == 'application/vnd.docker.distribution.manifest.v2+json' and skopeo_raw.get('schemaVersion') == 2): resolved_bundles.add(_get_resolved_image(bundle_pull_spec)) else: error_msg = ( f'The pull specification of {bundle_pull_spec} is neither ' f'a v2 manifest list nor a v2s2 manifest. Type {skopeo_raw.get("mediaType")}' f' and schema version {skopeo_raw.get("schemaVersion")} is not supported by IIB.' ) raise IIBError(error_msg) return list(resolved_bundles)
def test_rasise_exception_on_none_mediatype_skopeo_inspect(mock_run_cmd): mock_run_cmd.return_value = '{"Name": "some-image"}' image = 'docker://some-image:latest' with pytest.raises(IIBError, match='mediaType not found'): utils.skopeo_inspect(image, '--raw', require_media_type=True)