def find_in_data(self, data):
     return ImageName.parse(chain_get(data, self.path))
Beispiel #2
0
def _adjust_operator_bundle(manifests_path, metadata_path, organization=None):
    """
    Apply modifications to the operator manifests at the given location.

    For any container image pull spec found in the Operator CSV files, replace floating
    tags with pinned digests, e.g. `image:latest` becomes `image@sha256:...`.

    If spec.relatedImages is not set, it will be set with the pinned digests. If it is set but
    there are also RELATED_IMAGE_* environment variables set, an exception will be raised.

    This method relies on the OperatorManifest class to properly identify and apply the
    modifications as needed.

    :param str manifests_path: the full path to the directory containing the operator manifests.
    :param str metadata_path: the full path to the directory containing the bundle metadata files.
    :param str organization: the organization this bundle is for. If no organization is provided,
        no custom behavior will be applied.
    :raises IIBError: if the operator manifest has invalid entries
    :return: a dictionary of labels to set on the bundle
    :rtype: dict
    """
    package_name, labels = _apply_package_name_suffix(metadata_path,
                                                      organization)

    operator_manifest = OperatorManifest.from_directory(manifests_path)
    found_pullspecs = set()
    operator_csvs = []
    for operator_csv in operator_manifest.files:
        if operator_csv.has_related_images():
            csv_file_name = os.path.basename(operator_csv.path)
            if operator_csv.has_related_image_envs():
                raise IIBError(
                    f'The ClusterServiceVersion file {csv_file_name} has entries in '
                    'spec.relatedImages and one or more containers have RELATED_IMAGE_* '
                    'environment variables set. This is not allowed for bundles regenerated with '
                    'IIB.')
            log.debug(
                'Skipping pinning since the ClusterServiceVersion file %s has entries in '
                'spec.relatedImages',
                csv_file_name,
            )
            continue

        operator_csvs.append(operator_csv)

        for pullspec in operator_csv.get_pullspecs():
            found_pullspecs.add(pullspec)

    conf = get_worker_config()
    registry_replacements = (conf['iib_organization_customizations'].get(
        organization, {}).get('registry_replacements', {}))

    # Resolve pull specs to container image digests
    replacement_pullspecs = {}
    for pullspec in found_pullspecs:
        replacement_needed = False
        if ':' not in ImageName.parse(pullspec).tag:
            replacement_needed = True

        # Always resolve the image to make sure it's valid
        resolved_image = ImageName.parse(_get_resolved_image(
            pullspec.to_str()))

        if registry_replacements.get(resolved_image.registry):
            replacement_needed = True
            resolved_image.registry = registry_replacements[
                resolved_image.registry]

        if replacement_needed:
            log.debug(
                '%s will be replaced with %s',
                pullspec,
                resolved_image.to_str(),
            )
            replacement_pullspecs[pullspec] = resolved_image

    # Apply modifications to the operator bundle image metadata
    for operator_csv in operator_csvs:
        csv_file_name = os.path.basename(operator_csv.path)
        log.info('Replacing the pull specifications on %s', csv_file_name)
        operator_csv.replace_pullspecs_everywhere(replacement_pullspecs)

        log.info('Setting spec.relatedImages on %s', csv_file_name)
        operator_csv.set_related_images()

        operator_csv.dump()

    if organization:
        _adjust_csv_annotations(operator_manifest.files, package_name,
                                organization)

    return labels
 def __init__(self, name, value, replace, path):
     self._name = name
     self._value = ImageName.parse(value)
     self._replace = ImageName.parse(replace)
     self._path = path
Beispiel #4
0
def _overwrite_from_index(
    request_id,
    output_pull_spec,
    from_index,
    resolved_prebuild_from_index,
    overwrite_from_index_token=None,
):
    """
    Overwrite the ``from_index`` image.

    :param int request_id: the ID of the request this index image is for.
    :param str output_pull_spec: the pull specification of the manifest list for the index image
        that IIB built.
    :param str from_index: the pull specification of the image to overwrite.
    :param str resolved_prebuild_from_index: resolved index image before starting the build.
    :param str overwrite_from_index_token: the user supplied token to use when overwriting the
        ``from_index`` image. If this is not set, IIB's configured credentials will be used.
    :raises IIBError: if one of the skopeo commands fails or if the index image has changed
        since IIB build started.
    """
    _verify_index_image(resolved_prebuild_from_index, from_index,
                        overwrite_from_index_token)

    state_reason = f'Overwriting the index image {from_index} with {output_pull_spec}'
    log.info(state_reason)
    set_request_state(request_id, 'in_progress', state_reason)

    new_index_src = f'docker://{output_pull_spec}'
    temp_dir = None
    try:
        if overwrite_from_index_token:
            output_pull_spec_registry = ImageName.parse(
                output_pull_spec).registry
            from_index_registry = ImageName.parse(from_index).registry
            # If the registries are the same and `overwrite_from_index_token` was supplied, that
            # means that IIB's token will likely not have access to read the `from_index` image.
            # This means IIB must first export the manifest list and all the manifests locally and
            # then overwrite the `from_index` image with the exported version using the user
            # supplied token.
            #
            # When a newer version of buildah is available in RHEL 8, then that can be used instead
            # of the manifest-tool to create the manifest list locally which means this workaround
            # can be removed.
            if output_pull_spec_registry == from_index_registry:
                temp_dir = tempfile.TemporaryDirectory(prefix='iib-')
                new_index_src = f'oci:{temp_dir.name}'
                log.info(
                    'The registry used by IIB (%s) is also the registry where from_index (%s) will '
                    'be overwritten using the user supplied token. Will perform a workaround which '
                    'will cause the manifest digests to change but the content is the same.',
                    output_pull_spec_registry,
                    from_index_registry,
                )
                exc_msg = f'Failed to export {output_pull_spec} to the OCI format'
                _skopeo_copy(f'docker://{output_pull_spec}',
                             new_index_src,
                             copy_all=True,
                             exc_msg=exc_msg)

        exc_msg = f'Failed to overwrite the input from_index container image of {from_index}'
        with set_registry_token(overwrite_from_index_token, from_index):
            _skopeo_copy(new_index_src,
                         f'docker://{from_index}',
                         copy_all=True,
                         exc_msg=exc_msg)
    finally:
        if temp_dir:
            temp_dir.cleanup()