Example #1
0
def export_legacy_packages(packages, request_id, rebuilt_index_image,
                           cnr_token, organization):
    """
    Export packages to be backported and push them via OMPS.

    :param set packages: a set of strings representing the names of the packages to be exported.
    :param int request_id: the ID of the IIB build request.
    :param str rebuilt_index_image: the pull specification of the index image rebuilt by IIB.
    :param str cnr_token: the token required to push backported packages to the legacy
        app registry via OMPS.
    :param str organization: the organization name in the legacy app registry to which the
        backported packages should be pushed to.
    :raises IIBError: if the export of packages fails.
    """
    operator_versions = dict()
    with tempfile.TemporaryDirectory(prefix='iib-') as temp_dir:
        for package in packages:
            _opm_index_export(rebuilt_index_image, package, temp_dir)
            package_dir = os.path.join(temp_dir, package)
            _verify_package_info(package_dir, rebuilt_index_image)
            _zip_package(package_dir)
            omps_response = _push_package_manifest(package_dir, cnr_token,
                                                   organization)
            operator_versions[package] = omps_response.get('version')

    set_omps_operator_version(request_id, operator_versions)
    set_request_state(request_id, 'in_progress',
                      'Back ported packages successfully pushed to OMPS')
Example #2
0
def _overwrite_from_index(request_id,
                          output_pull_spec,
                          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 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.
    """
    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()
Example #3
0
def get_legacy_support_packages(bundles,
                                request_id,
                                ocp_version,
                                force_backport=False):
    """
    Get the packages that must be pushed to the legacy application registry.

    :param list<str> bundles: a list of strings representing the pull specifications of the bundles
        to add to the index image being built.
    :param int request_id: the ID of the IIB build request.
    :param str ocp_version: the OCP version that the index is intended for.
    :param bool force_backport: if True, backport legacy support is forced for every package
    :return: a set of packages that require legacy support
    :rtype: set
    """
    packages = set()
    if ocp_version != 'v4.5':
        log.info('Backport legacy support is disabled for %s', ocp_version)
        return packages
    if force_backport:
        set_request_state(request_id, 'in_progress',
                          'Backport legacy support will be forced')
    for bundle in bundles:
        labels = get_image_labels(bundle)
        if force_backport or ruamel.yaml.safe_load(
                labels.get('com.redhat.delivery.backport', 'false')):
            packages.add(
                labels['operators.operatorframework.io.bundle.package.v1'])

    return packages
Example #4
0
def test_set_request_state(mock_update_request):
    state = 'failed'
    state_reason = 'Ran out of gas'
    api_utils.set_request_state(3, state, state_reason)

    mock_update_request.assert_called_once()
    mock_update_request.call_args[0][1] == {
        'state': state,
        'state_reason': state_reason
    }
Example #5
0
def handle_rm_request(
    operators,
    binary_image,
    request_id,
    from_index,
    add_arches=None,
    overwrite_from_index=False,
    overwrite_from_index_token=None,
):
    """
    Coordinate the work needed to remove the input operators and rebuild the index image.

    :param list operators: a list of strings representing the name of the operators to
        remove from the index image.
    :param str binary_image: the pull specification of the container image where the opm binary
        gets copied from.
    :param int request_id: the ID of the IIB build request
    :param str from_index: the pull specification of the container image containing the index that
        the index image build will be based from.
    :param list add_arches: the list of arches to build in addition to the arches ``from_index`` is
        currently built for.
    :param bool overwrite_from_index: if True, overwrite the input ``from_index`` with the built
        index image.
    :param str overwrite_from_index_token: the token used for overwriting the input
        ``from_index`` image. This is required for non-privileged users to use
        ``overwrite_from_index``. The format of the token must be in the format "user:password".
    :raises IIBError: if the index image build fails.
    """
    _cleanup()
    prebuild_info = _prepare_request_for_build(binary_image, request_id,
                                               from_index, add_arches)

    with tempfile.TemporaryDirectory(prefix='iib-') as temp_dir:
        _opm_index_rm(temp_dir, operators, binary_image, from_index)

        arches = prebuild_info['arches']
        for arch in sorted(arches):
            _build_image(temp_dir, 'index.Dockerfile', request_id, arch)
            _push_image(request_id, arch)

    _verify_index_image(prebuild_info['from_index_resolved'], from_index)

    set_request_state(request_id, 'in_progress', 'Creating the manifest list')
    output_pull_spec = _create_and_push_manifest_list(request_id, arches)

    _finish_request_post_build(
        output_pull_spec,
        request_id,
        arches,
        from_index,
        overwrite_from_index,
        overwrite_from_index_token,
    )
Example #6
0
def failed_request_callback(context, exc, traceback, request_id):
    """
    Wrap set_request_state for task error callbacks.

    :param celery.app.task.Context context: the context of the task failure
    :param Exception exc: the exception that caused the task failure
    :param int request_id: the ID of the IIB request
    """
    if isinstance(exc, IIBError):
        msg = str(exc)
    else:
        msg = 'An unknown error occurred'

    set_request_state(request_id, 'failed', msg)
Example #7
0
def opm_create_empty_fbc(request_id, temp_dir, from_index_resolved, from_index,
                         binary_image, operators):
    """
    Create an empty FBC index image.

    This only produces the index.Dockerfile file and does not build the container image.

    :param int request_id: the ID of the IIB build request
    :param str temp_dir: the base directory to generate the database and index.Dockerfile in.
    :param str from_index_resolved: the resolved pull specification of the container image
        containing the index that the index image build will be based from.
    :param str from_index: the pull specification of the container image containing the index that
        the index image build will be based from.
    :param str binary_image: the pull specification of the container image where the opm binary
        gets copied from. This should point to a digest or stable tag.
    :param list operators: a list of strings representing the packages of the operators to be
        removed from the output index image.
    """
    # if from_index provided is FBC, get the hidden index db location
    if is_image_fbc(from_index_resolved):
        log.debug('%s provided is FBC index image', from_index)
        index_db_path = get_hidden_index_database(from_index=from_index,
                                                  base_dir=temp_dir)
    # if the from_index is SQLite based, get the default index db location
    else:
        from iib.workers.tasks.build import _get_index_database

        log.debug('%s provided is SQLite index image', from_index)
        index_db_path = _get_index_database(from_index=from_index,
                                            base_dir=temp_dir)

    # Remove all the operators from the index
    set_request_state(request_id, 'in_progress',
                      'Removing operators from index image')
    _opm_registry_rm(index_db_path=index_db_path,
                     operators=operators,
                     base_dir=temp_dir)

    # Migrate the index to FBC
    fbc_dir = opm_migrate(index_db=index_db_path, base_dir=temp_dir)

    opm_generate_dockerfile(
        fbc_dir=fbc_dir,
        base_dir=temp_dir,
        index_db=index_db_path,
        binary_image=binary_image,
        dockerfile_name='index.Dockerfile',
    )
Example #8
0
def get_legacy_support_packages(bundles, request_id, force_backport=False):
    """
    Get the packages that must be pushed to the legacy application registry.

    :param list<str> bundles: a list of strings representing the pull specifications of the bundles
        to add to the index image being built.
    :param int request_id: the ID of the IIB build request.
    :param bool force_backport: if True, backport legacy support is forced for every package
    :return: a set of packages that require legacy support
    :rtype: set
    """
    if force_backport:
        set_request_state(request_id, 'in_progress',
                          'Backport legacy support will be forced')
    packages = set()
    for bundle in bundles:
        labels = get_image_labels(bundle)
        if force_backport or labels.get('com.redhat.delivery.backport', False):
            packages.add(
                labels['operators.operatorframework.io.bundle.package.v1'])

    return packages
Example #9
0
def handle_merge_request(
    source_from_index,
    deprecation_list,
    request_id,
    binary_image=None,
    target_index=None,
    overwrite_target_index=False,
    overwrite_target_index_token=None,
    distribution_scope=None,
    binary_image_config=None,
):
    """
    Coordinate the work needed to merge old (N) index image with new (N+1) index image.

    :param str source_from_index: pull specification to be used as the base for building the new
        index image.
    :param str target_index: pull specification of content stage index image for the
        corresponding target index image.
    :param list deprecation_list: list of deprecated bundles for the target index image.
    :param int request_id: the ID of the IIB build request.
    :param str binary_image: the pull specification of the container image where the opm binary
        gets copied from.
    :param bool overwrite_target_index: if True, overwrite the input ``target_index`` with
        the built index image.
    :param str overwrite_target_index_token: the token used for overwriting the input
        ``target_index`` image. This is required for non-privileged users to use
        ``overwrite_target_index``. The format of the token must be in the format "user:password".
    :param str distribution_scope: the scope for distribution of the index image, defaults to
        ``None``.
    :raises IIBError: if the index image merge fails.
    """
    _cleanup()
    prebuild_info = _prepare_request_for_build(
        request_id,
        binary_image,
        overwrite_from_index_token=overwrite_target_index_token,
        source_from_index=source_from_index,
        target_index=target_index,
        distribution_scope=distribution_scope,
        binary_image_config=binary_image_config,
    )
    _update_index_image_build_state(request_id, prebuild_info)

    with tempfile.TemporaryDirectory(prefix='iib-') as temp_dir:
        set_request_state(request_id, 'in_progress',
                          'Getting bundles present in the index images')
        log.info('Getting bundles present in the source index image')
        source_index_bundles = _get_present_bundles(source_from_index,
                                                    temp_dir)

        target_index_bundles = []
        if target_index:
            log.info('Getting bundles present in the target index image')
            target_index_bundles = _get_present_bundles(target_index, temp_dir)

        arches = list(prebuild_info['arches'])
        arch = 'amd64' if 'amd64' in arches else arches[0]

        missing_bundles = _add_bundles_missing_in_source(
            source_index_bundles,
            target_index_bundles,
            temp_dir,
            prebuild_info['binary_image'],
            source_from_index,
            request_id,
            arch,
            prebuild_info['target_ocp_version'],
            overwrite_target_index_token,
            distribution_scope=prebuild_info['distribution_scope'],
        )

        set_request_state(request_id, 'in_progress',
                          'Deprecating bundles in the deprecation list')
        log.info('Deprecating bundles in the deprecation list')
        intermediate_bundles = source_index_bundles + missing_bundles
        deprecate_bundles = _get_bundles_from_deprecation_list(
            intermediate_bundles, deprecation_list)
        intermediate_image_name = _get_external_arch_pull_spec(
            request_id, arch, include_transport=False)

        if deprecate_bundles:
            _deprecate_bundles(
                deprecate_bundles,
                temp_dir,
                prebuild_info['binary_image'],
                intermediate_image_name,
                overwrite_target_index_token,
            )

        for arch in sorted(prebuild_info['arches']):
            _build_image(temp_dir, 'index.Dockerfile', request_id, arch)
            _push_image(request_id, arch)

    output_pull_spec = _create_and_push_manifest_list(request_id,
                                                      prebuild_info['arches'])
    _update_index_image_pull_spec(
        output_pull_spec,
        request_id,
        prebuild_info['arches'],
        target_index,
        overwrite_target_index,
        overwrite_target_index_token,
        prebuild_info['target_index_resolved'],
    )
    set_request_state(request_id, 'complete',
                      'The index image was successfully cleaned and updated.')
Example #10
0
def _prepare_request_for_build(binary_image,
                               request_id,
                               from_index=None,
                               add_arches=None,
                               bundles=None):
    """
    Prepare the request for the index image build.

    All information that was retrieved and/or calculated for the next steps in the build are
    returned as a dictionary.

    This function was created so that code didn't need to be duplicated for the ``add`` and ``rm``
    request types.

    :param str binary_image: the pull specification of the container image where the opm binary
        gets copied from.
    :param int request_id: the ID of the IIB build request
    :param str from_index: the pull specification of the container image containing the index that
        the index image build will be based from.
    :param list add_arches: the list of arches to build in addition to the arches ``from_index`` is
        currently built for; if ``from_index`` is ``None``, then this is used as the list of arches
        to build the index image for
    :param list bundles: the list of bundles to create the bundle mapping on the request
    :return: a dictionary with the keys: arches, binary_image_resolved, and from_index_resolved.
    :raises IIBError: if the container image resolution fails or the architectures couldn't be
        detected.
    """
    if bundles is None:
        bundles = []

    set_request_state(request_id, 'in_progress',
                      'Resolving the container images')

    if add_arches:
        arches = set(add_arches)
    else:
        arches = set()

    binary_image_resolved = _get_resolved_image(binary_image)
    binary_image_arches = _get_image_arches(binary_image_resolved)

    if from_index:
        from_index_resolved = _get_resolved_image(from_index)
        from_index_arches = _get_image_arches(from_index_resolved)
        arches = arches | from_index_arches
    else:
        from_index_resolved = None

    if not arches:
        raise IIBError('No arches were provided to build the index image')

    arches_str = ', '.join(sorted(arches))
    log.debug('Set to build the index image for the following arches: %s',
              arches_str)

    if not arches.issubset(binary_image_arches):
        raise IIBError(
            'The binary image is not available for the following arches: {}'.
            format(', '.join(sorted(arches - binary_image_arches))))

    bundle_mapping = {}
    for bundle in bundles:
        operator = get_image_label(
            bundle, 'operators.operatorframework.io.bundle.package.v1')
        if operator:
            bundle_mapping.setdefault(operator, []).append(bundle)

    payload = {
        'binary_image_resolved':
        binary_image_resolved,
        'state':
        'in_progress',
        'state_reason':
        f'Building the index image for the following arches: {arches_str}',
    }
    if bundle_mapping:
        payload['bundle_mapping'] = bundle_mapping
    if from_index_resolved:
        payload['from_index_resolved'] = from_index_resolved
    exc_msg = 'Failed setting the resolved images on the request'
    update_request(request_id, payload, exc_msg)

    return {
        'arches': arches,
        'binary_image_resolved': binary_image_resolved,
        'from_index_resolved': from_index_resolved,
    }
Example #11
0
File: build.py Project: lcarva/iib
def handle_add_request(
    bundles,
    binary_image,
    request_id,
    from_index=None,
    add_arches=None,
    cnr_token=None,
    organization=None,
    overwrite_from_index=False,
):
    """
    Coordinate the the work needed to build the index image with the input bundles.

    :param list bundles: a list of strings representing the pull specifications of the bundles to
        add to the index image being built.
    :param str binary_image: the pull specification of the image where the opm binary gets copied
        from.
    :param int request_id: the ID of the IIB build request
    :param str from_index: the pull specification of the image containing the index that the index
        image build will be based from.
    :param list add_arches: the list of arches to build in addition to the arches ``from_index`` is
        currently built for; if ``from_index`` is ``None``, then this is used as the list of arches
        to build the index image for
    :param str cnr_token: the token required to push backported packages to the legacy
        app registry via OMPS.
    :param str organization: organization name in the legacy app registry to which the backported
        packages should be pushed to.
    :param bool overwrite_from_index: if True, overwrite the input ``from_index`` with the built
        index image.
    :raises IIBError: if the index image build fails or legacy support is required and one of
        ``cnr_token`` or ``organization`` is not specified.
    """
    _verify_labels(bundles)

    log.info(
        'Checking if interacting with the legacy app registry is required')
    legacy_support_packages = get_legacy_support_packages(bundles)
    if legacy_support_packages:
        validate_legacy_params_and_config(legacy_support_packages, bundles,
                                          cnr_token, organization)

    _cleanup()
    prebuild_info = _prepare_request_for_build(binary_image, request_id,
                                               from_index, add_arches, bundles)

    with tempfile.TemporaryDirectory(prefix='iib-') as temp_dir:
        _opm_index_add(temp_dir, bundles,
                       prebuild_info['binary_image_resolved'], from_index)

        arches = prebuild_info['arches']
        for arch in sorted(arches):
            _build_image(temp_dir, request_id, arch)
            _push_image(request_id, arch)

    if from_index:
        _verify_index_image(prebuild_info['from_index_resolved'], from_index)

    set_request_state(request_id, 'in_progress', 'Creating the manifest list')
    output_pull_spec = _create_and_push_manifest_list(request_id, arches)

    if legacy_support_packages:
        export_legacy_packages(legacy_support_packages, request_id,
                               output_pull_spec, cnr_token, organization)

    _finish_request_post_build(output_pull_spec, request_id, arches,
                               from_index, overwrite_from_index)
Example #12
0
def handle_regenerate_bundle_request(from_bundle_image, organization,
                                     request_id):
    """
    Coordinate the work needed to regenerate the operator bundle image.

    :param str from_bundle_image: the pull specification of the bundle image to be regenerated.
    :param str organization: the name of the organization the bundle should be regenerated for.
    :param int request_id: the ID of the IIB build request
    :raises IIBError: if the regenerate bundle image build fails.
    """
    _cleanup()

    set_request_state(request_id, 'in_progress', 'Resolving from_bundle_image')
    from_bundle_image_resolved = _get_resolved_image(from_bundle_image)
    arches = _get_image_arches(from_bundle_image_resolved)
    if not arches:
        raise IIBError(
            f'No arches were found in the resolved from_bundle_image {from_bundle_image_resolved}'
        )

    arches_str = ', '.join(sorted(arches))
    log.debug(
        'Set to regenerate the bundle image for the following arches: %s',
        arches_str)

    payload = {
        'from_bundle_image_resolved':
        from_bundle_image_resolved,
        'state':
        'in_progress',
        'state_reason':
        f'Regenerating the bundle image for the following arches: {arches_str}',
    }
    exc_msg = 'Failed setting the resolved "from_bundle_image" on the request'
    update_request(request_id, payload, exc_msg=exc_msg)

    # Pull the from_bundle_image to ensure steps later on don't fail due to registry timeouts
    podman_pull(from_bundle_image_resolved)

    with tempfile.TemporaryDirectory(prefix='iib-') as temp_dir:
        manifests_path = os.path.join(temp_dir, 'manifests')
        _copy_files_from_image(from_bundle_image_resolved, '/manifests',
                               manifests_path)
        metadata_path = os.path.join(temp_dir, 'metadata')
        _copy_files_from_image(from_bundle_image_resolved, '/metadata',
                               metadata_path)
        labels = _adjust_operator_bundle(manifests_path, metadata_path,
                                         organization)

        with open(os.path.join(temp_dir, 'Dockerfile'), 'w') as dockerfile:
            dockerfile.write(
                textwrap.dedent(f"""\
                        FROM {from_bundle_image_resolved}
                        COPY ./manifests /manifests
                        COPY ./metadata /metadata
                    """))
            for name, value in labels.items():
                dockerfile.write(f'LABEL {name}={value}\n')

        for arch in sorted(arches):
            _build_image(temp_dir, 'Dockerfile', request_id, arch)
            _push_image(request_id, arch)

    set_request_state(request_id, 'in_progress', 'Creating the manifest list')
    output_pull_spec = _create_and_push_manifest_list(request_id, arches)

    conf = get_worker_config()
    if conf['iib_index_image_output_registry']:
        old_output_pull_spec = output_pull_spec
        output_pull_spec = output_pull_spec.replace(
            conf['iib_registry'], conf['iib_index_image_output_registry'], 1)
        log.info(
            'Changed the bundle_image pull specification from %s to %s',
            old_output_pull_spec,
            output_pull_spec,
        )

    payload = {
        'arches': list(arches),
        'bundle_image': output_pull_spec,
        'state': 'complete',
        'state_reason': 'The request completed successfully',
    }
    update_request(request_id,
                   payload,
                   exc_msg='Failed setting the bundle image on the request')
Example #13
0
def handle_rm_request(
    operators,
    request_id,
    from_index,
    binary_image=None,
    add_arches=None,
    overwrite_from_index=False,
    overwrite_from_index_token=None,
    distribution_scope=None,
    binary_image_config=None,
):
    """
    Coordinate the work needed to remove the input operators and rebuild the index image.

    :param list operators: a list of strings representing the name of the operators to
        remove from the index image.
    :param int request_id: the ID of the IIB build request
    :param str from_index: the pull specification of the container image containing the index that
        the index image build will be based from.
    :param str binary_image: the pull specification of the container image where the opm binary
        gets copied from.
    :param list add_arches: the list of arches to build in addition to the arches ``from_index`` is
        currently built for.
    :param bool overwrite_from_index: if True, overwrite the input ``from_index`` with the built
        index image.
    :param str overwrite_from_index_token: the token used for overwriting the input
        ``from_index`` image. This is required to use ``overwrite_from_index``.
        The format of the token must be in the format "user:password".
    :param str distribution_scope: the scope for distribution of the index image, defaults to
        ``None``.
    :param dict binary_image_config: the dict of config required to identify the appropriate
        ``binary_image`` to use.
    :raises IIBError: if the index image build fails.
    """
    _cleanup()
    prebuild_info = prepare_request_for_build(
        request_id,
        RequestConfigAddRm(
            _binary_image=binary_image,
            from_index=from_index,
            overwrite_from_index_token=overwrite_from_index_token,
            add_arches=add_arches,
            distribution_scope=distribution_scope,
            binary_image_config=binary_image_config,
        ),
    )
    _update_index_image_build_state(request_id, prebuild_info)

    from_index_resolved = prebuild_info['from_index_resolved']

    with tempfile.TemporaryDirectory(prefix='iib-') as temp_dir:
        _opm_index_rm(
            temp_dir,
            operators,
            prebuild_info['binary_image'],
            from_index_resolved,
            overwrite_from_index_token,
        )

        _add_label_to_index(
            'com.redhat.index.delivery.version',
            prebuild_info['ocp_version'],
            temp_dir,
            'index.Dockerfile',
        )

        _add_label_to_index(
            'com.redhat.index.delivery.distribution_scope',
            prebuild_info['distribution_scope'],
            temp_dir,
            'index.Dockerfile',
        )

        arches = prebuild_info['arches']
        for arch in sorted(arches):
            _build_image(temp_dir, 'index.Dockerfile', request_id, arch)
            _push_image(request_id, arch)

    set_request_state(request_id, 'in_progress', 'Creating the manifest list')
    output_pull_spec = _create_and_push_manifest_list(request_id, arches)

    _update_index_image_pull_spec(
        output_pull_spec,
        request_id,
        arches,
        from_index,
        overwrite_from_index,
        overwrite_from_index_token,
        from_index_resolved,
        add_or_rm=True,
    )
    set_request_state(
        request_id, 'complete',
        'The operator(s) were successfully removed from the index image')
Example #14
0
def handle_add_request(
    bundles,
    request_id,
    binary_image=None,
    from_index=None,
    add_arches=None,
    cnr_token=None,
    organization=None,
    force_backport=False,
    overwrite_from_index=False,
    overwrite_from_index_token=None,
    distribution_scope=None,
    greenwave_config=None,
    binary_image_config=None,
    deprecation_list=None,
):
    """
    Coordinate the the work needed to build the index image with the input bundles.

    :param list bundles: a list of strings representing the pull specifications of the bundles to
        add to the index image being built.
    :param int request_id: the ID of the IIB build request
    :param str binary_image: the pull specification of the container image where the opm binary
        gets copied from.
    :param str from_index: the pull specification of the container image containing the index that
        the index image build will be based from.
    :param list add_arches: the list of arches to build in addition to the arches ``from_index`` is
        currently built for; if ``from_index`` is ``None``, then this is used as the list of arches
        to build the index image for
    :param str cnr_token: the token required to push backported packages to the legacy
        app registry via OMPS.
    :param str organization: organization name in the legacy app registry to which the backported
        packages should be pushed to.
    :param bool force_backport: if True, always export packages to the legacy app registry via OMPS.
    :param bool overwrite_from_index: if True, overwrite the input ``from_index`` with the built
        index image.
    :param str overwrite_from_index_token: the token used for overwriting the input
        ``from_index`` image. This is required to use ``overwrite_from_index``.
        The format of the token must be in the format "user:password".
    :param str distribution_scope: the scope for distribution of the index image, defaults to
        ``None``.
    :param dict greenwave_config: the dict of config required to query Greenwave to gate bundles.
    :param dict binary_image_config: the dict of config required to identify the appropriate
        ``binary_image`` to use.
    :param list deprecation_list: list of deprecated bundles for the target index image. Defaults
        to ``None``.
    :raises IIBError: if the index image build fails or legacy support is required and one of
        ``cnr_token`` or ``organization`` is not specified.
    """
    _cleanup()
    # Resolve bundles to their digests
    set_request_state(request_id, 'in_progress', 'Resolving the bundles')
    resolved_bundles = get_resolved_bundles(bundles)

    verify_labels(resolved_bundles)

    # Check if Gating passes for all the bundles
    if greenwave_config:
        gate_bundles(resolved_bundles, greenwave_config)

    prebuild_info = prepare_request_for_build(
        request_id,
        RequestConfigAddRm(
            _binary_image=binary_image,
            from_index=from_index,
            overwrite_from_index_token=overwrite_from_index_token,
            add_arches=add_arches,
            bundles=bundles,
            distribution_scope=distribution_scope,
            binary_image_config=binary_image_config,
        ),
    )
    from_index_resolved = prebuild_info['from_index_resolved']

    log.info(
        'Checking if interacting with the legacy app registry is required')
    legacy_support_packages = get_legacy_support_packages(
        resolved_bundles,
        request_id,
        prebuild_info['ocp_version'],
        force_backport=force_backport)
    if legacy_support_packages:
        validate_legacy_params_and_config(legacy_support_packages,
                                          resolved_bundles, cnr_token,
                                          organization)

    _update_index_image_build_state(request_id, prebuild_info)
    present_bundles = []
    present_bundles_pull_spec = []
    with tempfile.TemporaryDirectory(prefix='iib-') as temp_dir:
        if from_index:
            msg = 'Checking if bundles are already present in index image'
            log.info(msg)
            set_request_state(request_id, 'in_progress', msg)

            with set_registry_token(overwrite_from_index_token,
                                    from_index_resolved):
                present_bundles, present_bundles_pull_spec = _get_present_bundles(
                    from_index_resolved, temp_dir)

            filtered_bundles = _get_missing_bundles(present_bundles,
                                                    resolved_bundles)
            excluded_bundles = [
                bundle for bundle in resolved_bundles
                if bundle not in filtered_bundles
            ]
            resolved_bundles = filtered_bundles

            if excluded_bundles:
                log.info(
                    'Following bundles are already present in the index image: %s',
                    ' '.join(excluded_bundles),
                )

        _opm_index_add(
            temp_dir,
            resolved_bundles,
            prebuild_info['binary_image_resolved'],
            from_index_resolved,
            overwrite_from_index_token,
            (prebuild_info['distribution_scope'] in ['dev', 'stage']),
        )

        deprecation_bundles = get_bundles_from_deprecation_list(
            present_bundles_pull_spec + resolved_bundles, deprecation_list
            or [])

        arches = prebuild_info['arches']
        if deprecation_bundles:
            # opm can only deprecate a bundle image on an existing index image. Build and
            # push a temporary index image to satisfy this requirement. Any arch will do.
            arch = sorted(arches)[0]
            log.info(
                'Building a temporary index image to satisfy the deprecation requirement'
            )
            _build_image(temp_dir, 'index.Dockerfile', request_id, arch)
            intermediate_image_name = _get_local_pull_spec(
                request_id, arch, include_transport=True)
            deprecate_bundles(
                deprecation_bundles,
                temp_dir,
                prebuild_info['binary_image'],
                intermediate_image_name,
                overwrite_from_index_token,
                # Use podman so opm can find the image locally
                container_tool='podman',
            )

        _add_label_to_index(
            'com.redhat.index.delivery.version',
            prebuild_info['ocp_version'],
            temp_dir,
            'index.Dockerfile',
        )

        _add_label_to_index(
            'com.redhat.index.delivery.distribution_scope',
            prebuild_info['distribution_scope'],
            temp_dir,
            'index.Dockerfile',
        )

        for arch in sorted(arches):
            _build_image(temp_dir, 'index.Dockerfile', request_id, arch)
            _push_image(request_id, arch)

        # If the container-tool podman is used in the opm commands above, opm will create temporary
        # files and directories without the write permission. This will cause the context manager
        # to fail to delete these files. Adjust the file modes to avoid this error.
        chmod_recursively(
            temp_dir,
            dir_mode=(stat.S_IRWXU | stat.S_IRWXG),
            file_mode=(stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP
                       | stat.S_IWGRP),
        )

    set_request_state(request_id, 'in_progress', 'Creating the manifest list')
    output_pull_spec = _create_and_push_manifest_list(request_id, arches)
    if legacy_support_packages:
        export_legacy_packages(legacy_support_packages, request_id,
                               output_pull_spec, cnr_token, organization)

    _update_index_image_pull_spec(
        output_pull_spec,
        request_id,
        arches,
        from_index,
        overwrite_from_index,
        overwrite_from_index_token,
        from_index_resolved,
        add_or_rm=True,
    )
    set_request_state(
        request_id, 'complete',
        'The operator bundle(s) were successfully added to the index image')
Example #15
0
def handle_add_request(
    bundles,
    request_id,
    binary_image=None,
    from_index=None,
    add_arches=None,
    cnr_token=None,
    organization=None,
    force_backport=False,
    overwrite_from_index=False,
    overwrite_from_index_token=None,
    distribution_scope=None,
    greenwave_config=None,
    binary_image_config=None,
    deprecation_list=None,
):
    """
    Coordinate the the work needed to build the index image with the input bundles.

    :param list bundles: a list of strings representing the pull specifications of the bundles to
        add to the index image being built.
    :param int request_id: the ID of the IIB build request
    :param str binary_image: the pull specification of the container image where the opm binary
        gets copied from.
    :param str from_index: the pull specification of the container image containing the index that
        the index image build will be based from.
    :param list add_arches: the list of arches to build in addition to the arches ``from_index`` is
        currently built for; if ``from_index`` is ``None``, then this is used as the list of arches
        to build the index image for
    :param str cnr_token: (deprecated) legacy support was disabled.
        the token required to push backported packages to the legacy app registry via OMPS.
    :param str organization: (deprecated) legacy support was disabled.
        organization name in the legacy app registry to which the backported packages
        should be pushed to.
    :param bool force_backport: (deprecated) legacy support was disabled.
        if True, always export packages to the legacy app registry via OMPS.
    :param bool overwrite_from_index: if True, overwrite the input ``from_index`` with the built
        index image.
    :param str overwrite_from_index_token: the token used for overwriting the input
        ``from_index`` image. This is required to use ``overwrite_from_index``.
        The format of the token must be in the format "user:password".
    :param str distribution_scope: the scope for distribution of the index image, defaults to
        ``None``.
    :param dict greenwave_config: the dict of config required to query Greenwave to gate bundles.
    :param dict binary_image_config: the dict of config required to identify the appropriate
        ``binary_image`` to use.
    :param list deprecation_list: list of deprecated bundles for the target index image. Defaults
        to ``None``.
    :raises IIBError: if the index image build fails.
    """
    _cleanup()
    # Resolve bundles to their digests
    set_request_state(request_id, 'in_progress', 'Resolving the bundles')
    resolved_bundles = get_resolved_bundles(bundles)

    verify_labels(resolved_bundles)

    # Check if Gating passes for all the bundles
    if greenwave_config:
        gate_bundles(resolved_bundles, greenwave_config)

    prebuild_info = prepare_request_for_build(
        request_id,
        RequestConfigAddRm(
            _binary_image=binary_image,
            from_index=from_index,
            overwrite_from_index_token=overwrite_from_index_token,
            add_arches=add_arches,
            bundles=bundles,
            distribution_scope=distribution_scope,
            binary_image_config=binary_image_config,
        ),
    )
    from_index_resolved = prebuild_info['from_index_resolved']

    if (cnr_token and organization) or force_backport:
        log.warning(
            "Legacy support is deprecated in IIB. "
            "cnr_token, organization and force_backport parameters will be ignored."
        )

    _update_index_image_build_state(request_id, prebuild_info)
    present_bundles = []
    present_bundles_pull_spec = []
    with tempfile.TemporaryDirectory(prefix='iib-') as temp_dir:
        if from_index:
            msg = 'Checking if bundles are already present in index image'
            log.info(msg)
            set_request_state(request_id, 'in_progress', msg)

            with set_registry_token(overwrite_from_index_token,
                                    from_index_resolved):
                present_bundles, present_bundles_pull_spec = _get_present_bundles(
                    from_index_resolved, temp_dir)

            filtered_bundles = _get_missing_bundles(present_bundles,
                                                    resolved_bundles)
            excluded_bundles = [
                bundle for bundle in resolved_bundles
                if bundle not in filtered_bundles
            ]
            resolved_bundles = filtered_bundles

            if excluded_bundles:
                log.info(
                    'Following bundles are already present in the index image: %s',
                    ' '.join(excluded_bundles),
                )

        _opm_index_add(
            temp_dir,
            resolved_bundles,
            prebuild_info['binary_image_resolved'],
            from_index_resolved,
            overwrite_from_index_token,
            (prebuild_info['distribution_scope'] in ['dev', 'stage']),
        )

        # Add the max ocp version property
        # We need to ensure that any bundle which has deprecated/removed API(s) in 1.22/ocp 4.9
        # will have this property to prevent users from upgrading clusters to 4.9 before upgrading
        # the operator installed to a version that is compatible with 4.9

        # Get the CSV name and version (not just the bundle path)
        db_path = temp_dir + "/database/index.db"
        port, rpc_proc = _serve_index_registry(db_path)

        raw_bundles = run_cmd(
            [
                'grpcurl', '-plaintext', f'localhost:{port}',
                'api.Registry/ListBundles'
            ],
            exc_msg='Failed to get bundle data from index image',
        )
        rpc_proc.kill()

        # Get bundle json for bundles in the request
        updated_bundles = list(
            filter(lambda b: b['bundlePath'] in resolved_bundles,
                   _get_bundle_json(raw_bundles)))

        for bundle in updated_bundles:
            if _requires_max_ocp_version(bundle['bundlePath']):
                log.info('adding property for %s', bundle['bundlePath'])
                max_openshift_version_property = {
                    'type': 'olm.maxOpenShiftVersion',
                    'value': '4.8',
                    'operatorbundle_name': bundle['csvName'],
                    'operatorbundle_version': bundle['version'],
                    'operatorbundle_path': bundle['bundlePath'],
                }
                _add_property_to_index(db_path, max_openshift_version_property)
                log.info('property added for %s', bundle['bundlePath'])

        deprecation_bundles = get_bundles_from_deprecation_list(
            present_bundles_pull_spec + resolved_bundles, deprecation_list
            or [])

        arches = prebuild_info['arches']
        if deprecation_bundles:
            # opm can only deprecate a bundle image on an existing index image. Build and
            # push a temporary index image to satisfy this requirement. Any arch will do.
            arch = sorted(arches)[0]
            log.info(
                'Building a temporary index image to satisfy the deprecation requirement'
            )
            _build_image(temp_dir, 'index.Dockerfile', request_id, arch)
            intermediate_image_name = _get_local_pull_spec(
                request_id, arch, include_transport=True)
            deprecate_bundles(
                deprecation_bundles,
                temp_dir,
                prebuild_info['binary_image'],
                intermediate_image_name,
                overwrite_from_index_token,
                # Use podman so opm can find the image locally
                container_tool='podman',
            )

        _add_label_to_index(
            'com.redhat.index.delivery.version',
            prebuild_info['ocp_version'],
            temp_dir,
            'index.Dockerfile',
        )

        _add_label_to_index(
            'com.redhat.index.delivery.distribution_scope',
            prebuild_info['distribution_scope'],
            temp_dir,
            'index.Dockerfile',
        )

        for arch in sorted(arches):
            _build_image(temp_dir, 'index.Dockerfile', request_id, arch)
            _push_image(request_id, arch)

        # If the container-tool podman is used in the opm commands above, opm will create temporary
        # files and directories without the write permission. This will cause the context manager
        # to fail to delete these files. Adjust the file modes to avoid this error.
        chmod_recursively(
            temp_dir,
            dir_mode=(stat.S_IRWXU | stat.S_IRWXG),
            file_mode=(stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP
                       | stat.S_IWGRP),
        )

    set_request_state(request_id, 'in_progress', 'Creating the manifest list')
    output_pull_spec = _create_and_push_manifest_list(request_id, arches)

    _update_index_image_pull_spec(
        output_pull_spec,
        request_id,
        arches,
        from_index,
        overwrite_from_index,
        overwrite_from_index_token,
        from_index_resolved,
        add_or_rm=True,
    )
    set_request_state(
        request_id, 'complete',
        'The operator bundle(s) were successfully added to the index image')
Example #16
0
def _add_bundles_missing_in_source(
    source_index_bundles,
    target_index_bundles,
    base_dir,
    binary_image,
    source_from_index,
    request_id,
    arch,
    ocp_version,
    overwrite_target_index_token=None,
    distribution_scope=None,
):
    """
    Rebuild index image with bundles missing from source image but present in target image.

    If no bundles are missing in the source index image, the index image is still rebuilt
    using the new binary image.

    :param list source_index_bundles: bundles present in the source index image.
    :param list target_index_bundles: bundles present in the target index image.
    :param str base_dir: base directory where operation files will be located.
    :param str binary_image: binary image to be used by the new index image.
    :param str source_from_index: index image, whose data will be contained in the new index image.
    :param int request_id: the ID of the IIB build request.
    :param str arch: the architecture to build this image for.
    :param str ocp_version: ocp version which will be added as a label to the image.
    :param str overwrite_target_index_token: the token used for overwriting the input
        ``source_from_index`` image. This is required for non-privileged users to use
        ``overwrite_target_index``. The format of the token must be in the format "user:password".
    :return: bundles which were added to the index image.
    :rtype: list
    """
    set_request_state(request_id, 'in_progress',
                      'Adding bundles missing in source index image')
    log.info(
        'Adding bundles from target index image which are missing from source index image'
    )
    missing_bundles = []
    source_bundle_digests = []
    source_bundle_csv_names = []
    target_bundle_digests = []

    for bundle in source_index_bundles:
        if '@sha256:' in bundle['bundlePath']:
            source_bundle_digests.append(
                bundle['bundlePath'].split('@sha256:')[-1])
            source_bundle_csv_names.append(bundle['csvName'])
        else:
            raise IIBError(
                f'Bundle {bundle["bundlePath"]} in the source index image is not defined via digest'
            )
    for bundle in target_index_bundles:
        if '@sha256:' in bundle['bundlePath']:
            target_bundle_digests.append(
                (bundle['bundlePath'].split('@sha256:')[-1], bundle))
        else:
            raise IIBError(
                f'Bundle {bundle["bundlePath"]} in the target index image is not defined via digest'
            )

    for target_bundle_digest, bundle in target_bundle_digests:
        if (target_bundle_digest not in source_bundle_digests
                and bundle['csvName'] not in source_bundle_csv_names):
            missing_bundles.append(bundle)

    missing_bundle_paths = [bundle['bundlePath'] for bundle in missing_bundles]
    if missing_bundle_paths:
        log.info('%s bundles are missing in the source index image.',
                 len(missing_bundle_paths))
    else:
        log.info(
            'No bundles are missing in the source index image. However, the index image is '
            'still being rebuilt with the new binary image.')

    _opm_index_add(
        base_dir,
        missing_bundle_paths,
        binary_image,
        source_from_index,
        overwrite_target_index_token,
    )
    _add_label_to_index('com.redhat.index.delivery.version', ocp_version,
                        base_dir, 'index.Dockerfile')
    _add_label_to_index(
        'com.redhat.index.delivery.distribution_scope',
        distribution_scope,
        base_dir,
        'index.Dockerfile',
    )
    _build_image(base_dir, 'index.Dockerfile', request_id, arch)
    _push_image(request_id, arch)
    _create_and_push_manifest_list(request_id, [arch])
    log.info('New index image created')

    return missing_bundles
Example #17
0
def _prepare_request_for_build(
    binary_image,
    request_id,
    from_index=None,
    overwrite_from_index_token=None,
    add_arches=None,
    bundles=None,
):
    """
    Prepare the request for the index image build.

    All information that was retrieved and/or calculated for the next steps in the build are
    returned as a dictionary.

    This function was created so that code didn't need to be duplicated for the ``add`` and ``rm``
    request types.

    :param str binary_image: the pull specification of the container image where the opm binary
        gets copied from.
    :param int request_id: the ID of the IIB build request
    :param str from_index: the pull specification of the container image containing the index that
        the index image build will be based from.
    :param str overwrite_from_index_token: the token used for overwriting the input
        ``from_index`` image. This is required for non-privileged users to use
        ``overwrite_from_index``. The format of the token must be in the format "user:password".
    :param list add_arches: the list of arches to build in addition to the arches ``from_index`` is
        currently built for; if ``from_index`` is ``None``, then this is used as the list of arches
        to build the index image for
    :param list bundles: the list of bundles to create the bundle mapping on the request
    :return: a dictionary with the keys: arches, binary_image_resolved, from_index_resolved, and
        ocp_version.
    :raises IIBError: if the container image resolution fails or the architectures couldn't be
        detected.
    """
    if bundles is None:
        bundles = []

    set_request_state(request_id, 'in_progress',
                      'Resolving the container images')

    if add_arches:
        arches = set(add_arches)
    else:
        arches = set()

    binary_image_resolved = _get_resolved_image(binary_image)
    binary_image_arches = _get_image_arches(binary_image_resolved)

    if from_index:
        with set_registry_token(overwrite_from_index_token, from_index):
            from_index_resolved = _get_resolved_image(from_index)
            from_index_arches = _get_image_arches(from_index_resolved)
            ocp_version = (get_image_label(
                from_index_resolved, 'com.redhat.index.delivery.version')
                           or 'v4.5')
        arches = arches | from_index_arches
    else:
        from_index_resolved = None
        ocp_version = 'v4.5'

    if not arches:
        raise IIBError('No arches were provided to build the index image')

    arches_str = ', '.join(sorted(arches))
    log.debug('Set to build the index image for the following arches: %s',
              arches_str)

    if not arches.issubset(binary_image_arches):
        raise IIBError(
            'The binary image is not available for the following arches: {}'.
            format(', '.join(sorted(arches - binary_image_arches))))

    bundle_mapping = {}
    for bundle in bundles:
        operator = get_image_label(
            bundle, 'operators.operatorframework.io.bundle.package.v1')
        if operator:
            bundle_mapping.setdefault(operator, []).append(bundle)

    return {
        'arches': arches,
        'binary_image_resolved': binary_image_resolved,
        'bundle_mapping': bundle_mapping,
        'from_index_resolved': from_index_resolved,
        'ocp_version': ocp_version,
    }
Example #18
0
def handle_merge_request(
    source_from_index,
    deprecation_list,
    request_id,
    binary_image=None,
    target_index=None,
    overwrite_target_index=False,
    overwrite_target_index_token=None,
    distribution_scope=None,
    binary_image_config=None,
    build_tags=None,
):
    """
    Coordinate the work needed to merge old (N) index image with new (N+1) index image.

    :param str source_from_index: pull specification to be used as the base for building the new
        index image.
    :param str target_index: pull specification of content stage index image for the
        corresponding target index image.
    :param list deprecation_list: list of deprecated bundles for the target index image.
    :param int request_id: the ID of the IIB build request.
    :param str binary_image: the pull specification of the container image where the opm binary
        gets copied from.
    :param bool overwrite_target_index: if True, overwrite the input ``target_index`` with
        the built index image.
    :param str overwrite_target_index_token: the token used for overwriting the input
        ``target_index`` image. This is required to use ``overwrite_target_index``.
        The format of the token must be in the format "user:password".
    :param str distribution_scope: the scope for distribution of the index image, defaults to
        ``None``.
    :param build_tags: list of extra tag to use for intermetdiate index image
    :raises IIBError: if the index image merge fails.
    """
    _cleanup()
    prebuild_info = prepare_request_for_build(
        request_id,
        RequestConfigMerge(
            _binary_image=binary_image,
            overwrite_target_index_token=overwrite_target_index_token,
            source_from_index=source_from_index,
            target_index=target_index,
            distribution_scope=distribution_scope,
            binary_image_config=binary_image_config,
        ),
    )
    _update_index_image_build_state(request_id, prebuild_info)
    source_from_index_resolved = prebuild_info['source_from_index_resolved']
    target_index_resolved = prebuild_info['target_index_resolved']
    dockerfile_name = 'index.Dockerfile'

    with tempfile.TemporaryDirectory(prefix='iib-') as temp_dir:
        with set_registry_token(overwrite_target_index_token, source_from_index):
            source_fbc = is_image_fbc(source_from_index_resolved)
            target_fbc = is_image_fbc(target_index_resolved)

        # do not remove - logging requested by stakeholders
        if source_fbc:
            log.info("Processing source index image as File-Based Catalog image")
        if target_fbc:
            log.info("Processing target index image as File-Based Catalog image")

        if source_fbc and not target_fbc:
            err_msg = (
                'Cannot merge source File-Based Catalog index image into target SQLite index image.'
            )
            log.error(err_msg)
            raise IIBError(err_msg)

        set_request_state(request_id, 'in_progress', 'Getting bundles present in the index images')
        log.info('Getting bundles present in the source index image')
        with set_registry_token(overwrite_target_index_token, source_from_index):
            source_index_bundles, source_index_bundles_pull_spec = _get_present_bundles(
                source_from_index_resolved, temp_dir
            )

            target_index_bundles = []
            if target_index:
                log.info('Getting bundles present in the target index image')
                target_index_bundles, _ = _get_present_bundles(target_index_resolved, temp_dir)

        arches = list(prebuild_info['arches'])
        arch = sorted(arches)[0]

        missing_bundles, invalid_version_bundles = _add_bundles_missing_in_source(
            source_index_bundles,
            target_index_bundles,
            temp_dir,
            prebuild_info['binary_image'],
            source_from_index_resolved,
            request_id,
            arch,
            prebuild_info['target_ocp_version'],
            overwrite_target_index_token,
            distribution_scope=prebuild_info['distribution_scope'],
        )

        missing_bundle_paths = [bundle['bundlePath'] for bundle in missing_bundles]
        if missing_bundle_paths:
            add_max_ocp_version_property(missing_bundle_paths, temp_dir)
        set_request_state(request_id, 'in_progress', 'Deprecating bundles in the deprecation list')
        log.info('Deprecating bundles in the deprecation list')
        intermediate_bundles = missing_bundle_paths + source_index_bundles_pull_spec
        deprecation_bundles = get_bundles_from_deprecation_list(
            intermediate_bundles, deprecation_list
        )
        # We do not need to pass the invalid_version_bundles through the
        # get_bundles_from_deprecation_list function because we already know
        # they are present in the newly created index.
        deprecation_bundles = deprecation_bundles + [
            bundle['bundlePath'] for bundle in invalid_version_bundles
        ]

        if deprecation_bundles:
            intermediate_image_name = _get_external_arch_pull_spec(
                request_id, arch, include_transport=False
            )

            # we can check if source index is FBC or not because intermediate_image
            # will be always the same type because it is built
            # from source index image in _add_bundles_missing_in_source()
            if source_fbc:
                deprecate_bundles_fbc(
                    bundles=deprecation_bundles,
                    base_dir=temp_dir,
                    binary_image=prebuild_info['binary_image'],
                    from_index=intermediate_image_name,
                )
            else:
                # opm can only deprecate a bundle image on an existing index image. Build and
                # push a temporary index image to satisfy this requirement. Any arch will do.
                # NOTE: we cannot use local builds because opm commands fails,
                # index image has to be pushed to registry
                _build_image(temp_dir, 'index.Dockerfile', request_id, arch)
                _push_image(request_id, arch)

                deprecate_bundles(
                    bundles=deprecation_bundles,
                    base_dir=temp_dir,
                    binary_image=prebuild_info['binary_image'],
                    from_index=intermediate_image_name,
                    overwrite_target_index_token=overwrite_target_index_token,
                )

        if target_fbc:
            index_db_file = os.path.join(temp_dir, get_worker_config()['temp_index_db_path'])
            # make sure FBC is generated right before build
            fbc_dir = opm_migrate(index_db=index_db_file, base_dir=temp_dir)
            if not source_fbc:
                # when source image is not FBC, but final image should be an FBC image
                # we have to generate Dockerfile for FBC (with hidden index.db)
                dockerfile_path = os.path.join(temp_dir, dockerfile_name)
                if os.path.isfile(dockerfile_path):
                    log.info('Removing previously generated dockerfile.')
                    os.remove(dockerfile_path)
                opm_generate_dockerfile(
                    fbc_dir=fbc_dir,
                    base_dir=temp_dir,
                    index_db=index_db_file,
                    binary_image=prebuild_info['binary_image'],
                    dockerfile_name=dockerfile_name,
                )

        _add_label_to_index(
            'com.redhat.index.delivery.version',
            prebuild_info['target_ocp_version'],
            temp_dir,
            dockerfile_name,
        )

        _add_label_to_index(
            'com.redhat.index.delivery.distribution_scope',
            prebuild_info['distribution_scope'],
            temp_dir,
            dockerfile_name,
        )

        for arch in sorted(prebuild_info['arches']):
            _build_image(temp_dir, dockerfile_name, request_id, arch)
            _push_image(request_id, arch)

        # If the container-tool podman is used in the opm commands above, opm will create temporary
        # files and directories without the write permission. This will cause the context manager
        # to fail to delete these files. Adjust the file modes to avoid this error.
        chmod_recursively(
            temp_dir,
            dir_mode=(stat.S_IRWXU | stat.S_IRWXG),
            file_mode=(stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP),
        )

    output_pull_spec = _create_and_push_manifest_list(
        request_id, prebuild_info['arches'], build_tags
    )
    _update_index_image_pull_spec(
        output_pull_spec,
        request_id,
        prebuild_info['arches'],
        target_index,
        overwrite_target_index,
        overwrite_target_index_token,
        target_index_resolved,
    )
    set_request_state(
        request_id, 'complete', 'The index image was successfully cleaned and updated.'
    )
Example #19
0
File: build.py Project: zanssa/iib
def handle_add_request(
    bundles,
    request_id,
    binary_image=None,
    from_index=None,
    add_arches=None,
    cnr_token=None,
    organization=None,
    force_backport=False,
    overwrite_from_index=False,
    overwrite_from_index_token=None,
    distribution_scope=None,
    greenwave_config=None,
    binary_image_config=None,
    deprecation_list=None,
    build_tags=None,
):
    """
    Coordinate the the work needed to build the index image with the input bundles.

    :param list bundles: a list of strings representing the pull specifications of the bundles to
        add to the index image being built.
    :param int request_id: the ID of the IIB build request
    :param str binary_image: the pull specification of the container image where the opm binary
        gets copied from.
    :param str from_index: the pull specification of the container image containing the index that
        the index image build will be based from.
    :param list add_arches: the list of arches to build in addition to the arches ``from_index`` is
        currently built for; if ``from_index`` is ``None``, then this is used as the list of arches
        to build the index image for
    :param str cnr_token: (deprecated) legacy support was disabled.
        the token required to push backported packages to the legacy app registry via OMPS.
    :param str organization: (deprecated) legacy support was disabled.
        organization name in the legacy app registry to which the backported packages
        should be pushed to.
    :param bool force_backport: (deprecated) legacy support was disabled.
        if True, always export packages to the legacy app registry via OMPS.
    :param bool overwrite_from_index: if True, overwrite the input ``from_index`` with the built
        index image.
    :param str overwrite_from_index_token: the token used for overwriting the input
        ``from_index`` image. This is required to use ``overwrite_from_index``.
        The format of the token must be in the format "user:password".
    :param str distribution_scope: the scope for distribution of the index image, defaults to
        ``None``.
    :param dict greenwave_config: the dict of config required to query Greenwave to gate bundles.
    :param dict binary_image_config: the dict of config required to identify the appropriate
        ``binary_image`` to use.
    :param list deprecation_list: list of deprecated bundles for the target index image. Defaults
        to ``None``.
    :param list build_tags: List of tags which will be applied to intermediate index images.
    :raises IIBError: if the index image build fails.
    """
    _cleanup()
    # Resolve bundles to their digests
    set_request_state(request_id, 'in_progress', 'Resolving the bundles')
    resolved_bundles = get_resolved_bundles(bundles)

    verify_labels(resolved_bundles)

    # Check if Gating passes for all the bundles
    if greenwave_config:
        gate_bundles(resolved_bundles, greenwave_config)

    prebuild_info = prepare_request_for_build(
        request_id,
        RequestConfigAddRm(
            _binary_image=binary_image,
            from_index=from_index,
            overwrite_from_index_token=overwrite_from_index_token,
            add_arches=add_arches,
            bundles=bundles,
            distribution_scope=distribution_scope,
            binary_image_config=binary_image_config,
        ),
    )
    from_index_resolved = prebuild_info['from_index_resolved']
    with set_registry_token(overwrite_from_index_token, from_index_resolved):
        is_fbc = is_image_fbc(from_index_resolved) if from_index else False
        if is_fbc:
            # logging requested by stakeholders do not delete
            log.info("Processing File-Based Catalog image")

    if (cnr_token and organization) or force_backport:
        log.warning(
            "Legacy support is deprecated in IIB. "
            "cnr_token, organization and force_backport parameters will be ignored."
        )

    _update_index_image_build_state(request_id, prebuild_info)
    present_bundles = []
    present_bundles_pull_spec = []
    with tempfile.TemporaryDirectory(prefix='iib-') as temp_dir:
        if from_index:
            msg = 'Checking if bundles are already present in index image'
            log.info(msg)
            set_request_state(request_id, 'in_progress', msg)

            with set_registry_token(overwrite_from_index_token, from_index_resolved):
                present_bundles, present_bundles_pull_spec = _get_present_bundles(
                    from_index_resolved, temp_dir
                )

            filtered_bundles = _get_missing_bundles(present_bundles, resolved_bundles)
            excluded_bundles = [
                bundle for bundle in resolved_bundles if bundle not in filtered_bundles
            ]
            resolved_bundles = filtered_bundles

            if excluded_bundles:
                log.info(
                    'Following bundles are already present in the index image: %s',
                    ' '.join(excluded_bundles),
                )

        if is_fbc:
            opm_registry_add_fbc(
                base_dir=temp_dir,
                bundles=resolved_bundles,
                binary_image=prebuild_info['binary_image_resolved'],
                from_index=from_index_resolved,
                overwrite_from_index_token=overwrite_from_index_token,
                overwrite_csv=(prebuild_info['distribution_scope'] in ['dev', 'stage']),
            )
        else:
            _opm_index_add(
                base_dir=temp_dir,
                bundles=resolved_bundles,
                binary_image=prebuild_info['binary_image_resolved'],
                from_index=from_index_resolved,
                overwrite_from_index_token=overwrite_from_index_token,
                overwrite_csv=(prebuild_info['distribution_scope'] in ['dev', 'stage']),
            )

        # Add the max ocp version property
        # We need to ensure that any bundle which has deprecated/removed API(s) in 1.22/ocp 4.9
        # will have this property to prevent users from upgrading clusters to 4.9 before upgrading
        # the operator installed to a version that is compatible with 4.9
        if resolved_bundles:
            add_max_ocp_version_property(resolved_bundles, temp_dir)

        deprecation_bundles = get_bundles_from_deprecation_list(
            present_bundles_pull_spec + resolved_bundles, deprecation_list or []
        )

        arches = prebuild_info['arches']
        if deprecation_bundles:
            if is_fbc:
                deprecate_bundles_fbc(
                    bundles=deprecation_bundles,
                    base_dir=temp_dir,
                    binary_image=prebuild_info['binary_image'],
                    from_index=from_index_resolved,
                )
            else:
                # opm can only deprecate a bundle image on an existing index image. Build and
                # push a temporary index image to satisfy this requirement. Any arch will do.
                arch = sorted(arches)[0]
                log.info('Building a temporary index image to satisfy the deprecation requirement')
                _build_image(temp_dir, 'index.Dockerfile', request_id, arch)
                _push_image(request_id, arch)
                intermediate_image_name = _get_external_arch_pull_spec(
                    request_id, arch, include_transport=False
                )
                deprecate_bundles(
                    bundles=deprecation_bundles,
                    base_dir=temp_dir,
                    binary_image=prebuild_info['binary_image'],
                    from_index=intermediate_image_name,
                    overwrite_target_index_token=overwrite_from_index_token,
                    # Use podman so opm can find the image locally
                    container_tool='podman',
                )

        _add_label_to_index(
            'com.redhat.index.delivery.version',
            prebuild_info['ocp_version'],
            temp_dir,
            'index.Dockerfile',
        )

        _add_label_to_index(
            'com.redhat.index.delivery.distribution_scope',
            prebuild_info['distribution_scope'],
            temp_dir,
            'index.Dockerfile',
        )

        if is_fbc:
            index_db_file = os.path.join(temp_dir, get_worker_config()['temp_index_db_path'])
            # make sure FBC is generated right before build
            opm_migrate(index_db=index_db_file, base_dir=temp_dir)

        for arch in sorted(arches):
            _build_image(temp_dir, 'index.Dockerfile', request_id, arch)
            _push_image(request_id, arch)

        # If the container-tool podman is used in the opm commands above, opm will create temporary
        # files and directories without the write permission. This will cause the context manager
        # to fail to delete these files. Adjust the file modes to avoid this error.
        chmod_recursively(
            temp_dir,
            dir_mode=(stat.S_IRWXU | stat.S_IRWXG),
            file_mode=(stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP),
        )

    set_request_state(request_id, 'in_progress', 'Creating the manifest list')
    output_pull_spec = _create_and_push_manifest_list(request_id, arches, build_tags)

    _update_index_image_pull_spec(
        output_pull_spec,
        request_id,
        arches,
        from_index,
        overwrite_from_index,
        overwrite_from_index_token,
        from_index_resolved,
        add_or_rm=True,
    )
    set_request_state(
        request_id, 'complete', 'The operator bundle(s) were successfully added to the index image'
    )
Example #20
0
def prepare_request_for_build(request_id, build_request_config):
    """Prepare the request for the index image build.

    All information that was retrieved and/or calculated for the next steps in the build are
    returned as a dictionary.
    This function was created so that code didn't need to be duplicated for the ``add`` and ``rm``
    request types.
    :param RequestConfig build_request_config: build request configuration
    :return: a dictionary with the keys: arches, binary_image_resolved, from_index_resolved, and
    ocp_version.
    :rtype: dict
    :raises IIBError: if the container image resolution fails or the architectures couldn't be
    detected.
    """
    bundles = None
    if hasattr(build_request_config, "bundles"):
        bundles = build_request_config.bundles

    if bundles is None:
        bundles = []

    set_request_state(request_id, 'in_progress', 'Resolving the container images')

    # Use v4.5 as default version
    index_info = get_all_index_images_info(
        build_request_config,
        [("from_index", "v4.5"), ("source_from_index", "v4.5"), ("target_index", "v4.6")],
    )
    arches = gather_index_image_arches(build_request_config, index_info)
    if not arches:
        raise IIBError('No arches were provided to build the index image')

    arches_str = ', '.join(sorted(arches))
    log.debug('Set to build the index image for the following arches: %s', arches_str)

    # Use the distribution_scope of the from_index as the resolved distribution scope for `Add`,
    # and 'Rm' requests, but use the distribution_scope of the target_index as the resolved
    # distribution scope for `merge-index-image` requests.
    resolved_distribution_scope = index_info['from_index']['resolved_distribution_scope']
    if (
        hasattr(build_request_config, "source_from_index")
        and build_request_config.source_from_index
    ):
        resolved_distribution_scope = index_info['target_index']['resolved_distribution_scope']

    distribution_scope = _validate_distribution_scope(
        resolved_distribution_scope, build_request_config.distribution_scope
    )

    binary_image = build_request_config.binary_image(index_info['from_index'], distribution_scope)

    binary_image_resolved = get_resolved_image(binary_image)
    binary_image_arches = get_image_arches(binary_image_resolved)

    if not arches.issubset(binary_image_arches):
        raise IIBError(
            'The binary image is not available for the following arches: {}'.format(
                ', '.join(sorted(arches - binary_image_arches))
            )
        )

    bundle_mapping = {}
    for bundle in bundles:
        operator = get_image_label(bundle, 'operators.operatorframework.io.bundle.package.v1')
        if operator:
            bundle_mapping.setdefault(operator, []).append(bundle)

    return {
        'arches': arches,
        'binary_image': binary_image,
        'binary_image_resolved': binary_image_resolved,
        'bundle_mapping': bundle_mapping,
        'from_index_resolved': index_info["from_index"]['resolved_from_index'],
        'ocp_version': index_info["from_index"]['ocp_version'],
        'distribution_scope': distribution_scope,
        'source_from_index_resolved': index_info['source_from_index']['resolved_from_index'],
        'source_ocp_version': index_info['source_from_index']['ocp_version'],
        'target_index_resolved': index_info['target_index']['resolved_from_index'],
        'target_ocp_version': index_info['target_index']['ocp_version'],
    }
Example #21
0
def handle_merge_request(
    source_from_index,
    deprecation_list,
    request_id,
    binary_image=None,
    target_index=None,
    overwrite_target_index=False,
    overwrite_target_index_token=None,
    distribution_scope=None,
    binary_image_config=None,
):
    """
    Coordinate the work needed to merge old (N) index image with new (N+1) index image.

    :param str source_from_index: pull specification to be used as the base for building the new
        index image.
    :param str target_index: pull specification of content stage index image for the
        corresponding target index image.
    :param list deprecation_list: list of deprecated bundles for the target index image.
    :param int request_id: the ID of the IIB build request.
    :param str binary_image: the pull specification of the container image where the opm binary
        gets copied from.
    :param bool overwrite_target_index: if True, overwrite the input ``target_index`` with
        the built index image.
    :param str overwrite_target_index_token: the token used for overwriting the input
        ``target_index`` image. This is required to use ``overwrite_target_index``.
        The format of the token must be in the format "user:password".
    :param str distribution_scope: the scope for distribution of the index image, defaults to
        ``None``.
    :raises IIBError: if the index image merge fails.
    """
    _cleanup()
    prebuild_info = prepare_request_for_build(
        request_id,
        RequestConfigMerge(
            _binary_image=binary_image,
            overwrite_target_index_token=overwrite_target_index_token,
            source_from_index=source_from_index,
            target_index=target_index,
            distribution_scope=distribution_scope,
            binary_image_config=binary_image_config,
        ),
    )
    _update_index_image_build_state(request_id, prebuild_info)
    source_from_index_resolved = prebuild_info['source_from_index_resolved']
    target_index_resolved = prebuild_info['target_index_resolved']

    with tempfile.TemporaryDirectory(prefix='iib-') as temp_dir:
        set_request_state(request_id, 'in_progress',
                          'Getting bundles present in the index images')
        log.info('Getting bundles present in the source index image')
        with set_registry_token(overwrite_target_index_token,
                                source_from_index):
            source_index_bundles, source_index_bundles_pull_spec = _get_present_bundles(
                source_from_index_resolved, temp_dir)

            target_index_bundles = []
            if target_index:
                log.info('Getting bundles present in the target index image')
                target_index_bundles, _ = _get_present_bundles(
                    target_index_resolved, temp_dir)

        arches = list(prebuild_info['arches'])
        arch = 'amd64' if 'amd64' in arches else arches[0]

        missing_bundles, invalid_version_bundles = _add_bundles_missing_in_source(
            source_index_bundles,
            target_index_bundles,
            temp_dir,
            prebuild_info['binary_image'],
            source_from_index_resolved,
            request_id,
            arch,
            prebuild_info['target_ocp_version'],
            overwrite_target_index_token,
            distribution_scope=prebuild_info['distribution_scope'],
        )

        set_request_state(request_id, 'in_progress',
                          'Deprecating bundles in the deprecation list')
        log.info('Deprecating bundles in the deprecation list')
        intermediate_bundles = [
            bundle['bundlePath'] for bundle in missing_bundles
        ] + source_index_bundles_pull_spec
        deprecation_bundles = get_bundles_from_deprecation_list(
            intermediate_bundles, deprecation_list)
        # We do not need to pass the invalid_version_bundles through the
        # get_bundles_from_deprecation_list function because we already know
        # they are present in the newly created index.
        deprecation_bundles = deprecation_bundles + [
            bundle['bundlePath'] for bundle in invalid_version_bundles
        ]
        intermediate_image_name = _get_external_arch_pull_spec(
            request_id, arch, include_transport=False)

        if deprecation_bundles:
            deprecate_bundles(
                deprecation_bundles,
                temp_dir,
                prebuild_info['binary_image'],
                intermediate_image_name,
                overwrite_target_index_token,
            )

        for arch in sorted(prebuild_info['arches']):
            _build_image(temp_dir, 'index.Dockerfile', request_id, arch)
            _push_image(request_id, arch)

        # If the container-tool podman is used in the opm commands above, opm will create temporary
        # files and directories without the write permission. This will cause the context manager
        # to fail to delete these files. Adjust the file modes to avoid this error.
        chmod_recursively(
            temp_dir,
            dir_mode=(stat.S_IRWXU | stat.S_IRWXG),
            file_mode=(stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP
                       | stat.S_IWGRP),
        )

    output_pull_spec = _create_and_push_manifest_list(request_id,
                                                      prebuild_info['arches'])
    _update_index_image_pull_spec(
        output_pull_spec,
        request_id,
        prebuild_info['arches'],
        target_index,
        overwrite_target_index,
        overwrite_target_index_token,
        target_index_resolved,
    )
    set_request_state(request_id, 'complete',
                      'The index image was successfully cleaned and updated.')
Example #22
0
def handle_add_request(
    bundles,
    binary_image,
    request_id,
    from_index=None,
    add_arches=None,
    cnr_token=None,
    organization=None,
    force_backport=False,
    overwrite_from_index=False,
    overwrite_from_index_token=None,
    greenwave_config=None,
):
    """
    Coordinate the the work needed to build the index image with the input bundles.

    :param list bundles: a list of strings representing the pull specifications of the bundles to
        add to the index image being built.
    :param str binary_image: the pull specification of the container image where the opm binary
        gets copied from.
    :param int request_id: the ID of the IIB build request
    :param str from_index: the pull specification of the container image containing the index that
        the index image build will be based from.
    :param list add_arches: the list of arches to build in addition to the arches ``from_index`` is
        currently built for; if ``from_index`` is ``None``, then this is used as the list of arches
        to build the index image for
    :param str cnr_token: the token required to push backported packages to the legacy
        app registry via OMPS.
    :param str organization: organization name in the legacy app registry to which the backported
        packages should be pushed to.
    :param bool force_backport: if True, always export packages to the legacy app registry via OMPS.
    :param bool overwrite_from_index: if True, overwrite the input ``from_index`` with the built
        index image.
    :param str overwrite_from_index_token: the token used for overwriting the input
        ``from_index`` image. This is required for non-privileged users to use
        ``overwrite_from_index``. The format of the token must be in the format "user:password".
    :param dict greenwave_config: the dict of config required to query Greenwave to gate bundles.
    :raises IIBError: if the index image build fails or legacy support is required and one of
        ``cnr_token`` or ``organization`` is not specified.
    """
    _cleanup()
    # Resolve bundles to their digests
    set_request_state(request_id, 'in_progress', 'Resolving the bundles')
    resolved_bundles = _get_resolved_bundles(bundles)

    _verify_labels(resolved_bundles)

    # Check if Gating passes for all the bundles
    if greenwave_config:
        gate_bundles(resolved_bundles, greenwave_config)

    prebuild_info = _prepare_request_for_build(binary_image, request_id,
                                               from_index,
                                               overwrite_from_index_token,
                                               add_arches, bundles)

    log.info(
        'Checking if interacting with the legacy app registry is required')
    legacy_support_packages = get_legacy_support_packages(
        resolved_bundles,
        request_id,
        prebuild_info['ocp_version'],
        force_backport=force_backport)
    if legacy_support_packages:
        validate_legacy_params_and_config(legacy_support_packages,
                                          resolved_bundles, cnr_token,
                                          organization)

    _update_index_image_build_state(request_id, prebuild_info)

    with tempfile.TemporaryDirectory(prefix='iib-') as temp_dir:
        _opm_index_add(
            temp_dir,
            resolved_bundles,
            prebuild_info['binary_image_resolved'],
            from_index,
            overwrite_from_index_token,
        )

        _add_ocp_label_to_index(
            prebuild_info['ocp_version'],
            temp_dir,
            'index.Dockerfile',
        )

        arches = prebuild_info['arches']
        for arch in sorted(arches):
            _build_image(temp_dir, 'index.Dockerfile', request_id, arch)
            _push_image(request_id, arch)

    if from_index:
        _verify_index_image(prebuild_info['from_index_resolved'], from_index,
                            overwrite_from_index_token)

    set_request_state(request_id, 'in_progress', 'Creating the manifest list')
    output_pull_spec = _create_and_push_manifest_list(request_id, arches)
    if legacy_support_packages:
        export_legacy_packages(legacy_support_packages, request_id,
                               output_pull_spec, cnr_token, organization)

    _update_index_image_pull_spec(
        output_pull_spec,
        request_id,
        arches,
        from_index,
        overwrite_from_index,
        overwrite_from_index_token,
    )
    set_request_state(
        request_id,
        'complete',
        'The operator bundle(s) were successfully added to the index image',
    )
Example #23
0
def _add_bundles_missing_in_source(
    source_index_bundles,
    target_index_bundles,
    base_dir,
    binary_image,
    source_from_index,
    request_id,
    arch,
    ocp_version,
    overwrite_target_index_token=None,
    distribution_scope=None,
):
    """
    Rebuild index image with bundles missing from source image but present in target image.

    If no bundles are missing in the source index image, the index image is still rebuilt
    using the new binary image.

    :param list source_index_bundles: bundles present in the source index image.
    :param list target_index_bundles: bundles present in the target index image.
    :param str base_dir: base directory where operation files will be located.
    :param str binary_image: binary image to be used by the new index image.
    :param str source_from_index: index image, whose data will be contained in the new index image.
    :param int request_id: the ID of the IIB build request.
    :param str arch: the architecture to build this image for.
    :param str ocp_version: ocp version which will be added as a label to the image.
    :param str overwrite_target_index_token: the token used for overwriting the input
        ``source_from_index`` image. This is required to use ``overwrite_target_index``.
        The format of the token must be in the format "user:password".
    :return: tuple where the first value is a list of bundles which were added to the index image
        and the second value is a list of bundles in the new index whose ocp_version range does not
        satisfy the ocp_version value of the target index.
    :rtype: tuple
    """
    set_request_state(request_id, 'in_progress',
                      'Adding bundles missing in source index image')
    log.info(
        'Adding bundles from target index image which are missing from source index image'
    )
    missing_bundles = []
    missing_bundle_paths = []
    # This list stores the bundles whose ocp_version range does not satisfy the ocp_version
    # of the target index
    invalid_bundles = []
    source_bundle_digests = []
    source_bundle_csv_names = []
    target_bundle_digests = []

    for bundle in source_index_bundles:
        if '@sha256:' in bundle['bundlePath']:
            source_bundle_digests.append(
                bundle['bundlePath'].split('@sha256:')[-1])
            source_bundle_csv_names.append(bundle['csvName'])
        else:
            raise IIBError(
                f'Bundle {bundle["bundlePath"]} in the source index image is not defined via digest'
            )
    for bundle in target_index_bundles:
        if '@sha256:' in bundle['bundlePath']:
            target_bundle_digests.append(
                (bundle['bundlePath'].split('@sha256:')[-1], bundle))
        else:
            raise IIBError(
                f'Bundle {bundle["bundlePath"]} in the target index image is not defined via digest'
            )

    for target_bundle_digest, bundle in target_bundle_digests:
        if (target_bundle_digest not in source_bundle_digests
                and bundle['csvName'] not in source_bundle_csv_names):
            missing_bundles.append(bundle)
            missing_bundle_paths.append(bundle['bundlePath'])

    for bundle in itertools.chain(missing_bundles, source_index_bundles):
        if not is_bundle_version_valid(bundle['bundlePath'], ocp_version):
            invalid_bundles.append(bundle)

    if invalid_bundles:
        log.info(
            '%s bundles have invalid version label and will be deprecated.',
            len(invalid_bundles))

    _opm_index_add(
        base_dir,
        missing_bundle_paths,
        binary_image,
        from_index=source_from_index,
        overwrite_from_index_token=overwrite_target_index_token,
        # Use podman until opm's default mechanism is more resilient:
        #   https://bugzilla.redhat.com/show_bug.cgi?id=1937097
        container_tool='podman',
    )
    _add_label_to_index('com.redhat.index.delivery.version', ocp_version,
                        base_dir, 'index.Dockerfile')
    _add_label_to_index(
        'com.redhat.index.delivery.distribution_scope',
        distribution_scope,
        base_dir,
        'index.Dockerfile',
    )
    _build_image(base_dir, 'index.Dockerfile', request_id, arch)
    _push_image(request_id, arch)
    _create_and_push_manifest_list(request_id, [arch])
    log.info('New index image created')

    return (missing_bundles, invalid_bundles)
Example #24
0
def handle_create_empty_index_request(
    from_index,
    request_id,
    output_fbc=False,
    binary_image=None,
    labels=None,
    binary_image_config=None,
):
    """Coordinate the the work needed to create the index image with labels.

    :param str from_index: the pull specification of the container image containing the index that
        the index image build will be based from.
    :param int request_id: the ID of the IIB build request
    :param bool output_fbc: specifies whether a File-based Catalog index image should be created
    :param str binary_image: the pull specification of the container image where the opm binary
        gets copied from.
    :param dict labels: the dict of labels required to be added to a new index image
    :param dict binary_image_config: the dict of config required to identify the appropriate
        ``binary_image`` to use.
    """
    _cleanup()
    prebuild_info = prepare_request_for_build(
        request_id,
        RequestConfigCreateIndexImage(
            _binary_image=binary_image,
            from_index=from_index,
            binary_image_config=binary_image_config,
        ),
    )
    from_index_resolved = prebuild_info['from_index_resolved']
    prebuild_info['labels'] = labels

    if not output_fbc and is_image_fbc(from_index_resolved):
        log.debug('%s is FBC index image', from_index_resolved)
        err_msg = 'Cannot create SQLite index image from File-Based Catalog index image'
        log.error(err_msg)
        raise IIBError(err_msg)

    _update_index_image_build_state(request_id, prebuild_info)

    with tempfile.TemporaryDirectory(prefix='iib-') as temp_dir:
        set_request_state(request_id, 'in_progress', 'Checking operators present in index image')

        operators = _get_present_operators(from_index_resolved, temp_dir)

        # if output_fbc parameter is true, create an empty FBC index image
        # else create empty SQLite index image
        if output_fbc:
            log.debug('Creating empty FBC index image from %s', from_index)
            opm_create_empty_fbc(
                request_id=request_id,
                temp_dir=temp_dir,
                from_index_resolved=from_index_resolved,
                from_index=from_index,
                binary_image=prebuild_info['binary_image'],
                operators=operators,
            )
        else:
            set_request_state(request_id, 'in_progress', 'Removing operators from index image')
            _opm_index_rm(temp_dir, operators, prebuild_info['binary_image'], from_index_resolved)

        set_request_state(
            request_id, 'in_progress', 'Getting and updating labels for new index image'
        )

        iib_labels = {
            'com.redhat.index.delivery.version': prebuild_info['ocp_version'],
            'com.redhat.index.delivery.distribution_scope': prebuild_info['distribution_scope'],
        }

        if labels:
            iib_labels.update(labels)
        for index_label, value in iib_labels.items():
            _add_label_to_index(index_label, value, temp_dir, 'index.Dockerfile')

        arches = prebuild_info['arches']

        for arch in sorted(arches):
            _build_image(temp_dir, 'index.Dockerfile', request_id, arch)
            _push_image(request_id, arch)

    set_request_state(request_id, 'in_progress', 'Creating the manifest list')
    output_pull_spec = _create_and_push_manifest_list(request_id, arches, [])

    _update_index_image_pull_spec(
        output_pull_spec=output_pull_spec,
        request_id=request_id,
        arches=arches,
        from_index=from_index,
        resolved_prebuild_from_index=from_index_resolved,
    )
    set_request_state(request_id, 'complete', 'The empty index image was successfully created')
Example #25
0
def handle_create_empty_index_request(from_index,
                                      request_id,
                                      binary_image=None,
                                      labels=None,
                                      binary_image_config=None):
    """Coordinate the the work needed to create the index image with labels.

    :param str from_index: the pull specification of the container image containing the index that
        the index image build will be based from.
    :param int request_id: the ID of the IIB build request
    :param str binary_image: the pull specification of the container image where the opm binary
        gets copied from.
    :param dict labels: the dict of labels required to be added to a new index image
    :param dict binary_image_config: the dict of config required to identify the appropriate
        ``binary_image`` to use.
    """
    _cleanup()

    prebuild_info = prepare_request_for_build(
        request_id,
        RequestConfigCreateIndexImage(
            _binary_image=binary_image,
            from_index=from_index,
            binary_image_config=binary_image_config,
        ),
    )
    from_index_resolved = prebuild_info['from_index_resolved']
    prebuild_info['labels'] = labels

    _update_index_image_build_state(request_id, prebuild_info)
    with tempfile.TemporaryDirectory(prefix='iib-') as temp_dir:
        set_request_state(request_id, 'in_progress',
                          'Checking operators present in index image')

        operators = _get_present_operators(from_index_resolved, temp_dir)
        set_request_state(request_id, 'in_progress',
                          'Removing operators from index image')

        _opm_index_rm(temp_dir, operators, prebuild_info['binary_image'],
                      from_index_resolved)

        set_request_state(request_id, 'in_progress',
                          'Getting and updating labels for new index image')

        iib_labels = {
            'com.redhat.index.delivery.version':
            prebuild_info['ocp_version'],
            'com.redhat.index.delivery.distribution_scope':
            prebuild_info['distribution_scope'],
        }

        iib_labels.update(labels)
        for index_label, value in iib_labels.items():
            _add_label_to_index(index_label, value, temp_dir,
                                'index.Dockerfile')

        arches = prebuild_info['arches']

        for arch in sorted(arches):
            _build_image(temp_dir, 'index.Dockerfile', request_id, arch)
            _push_image(request_id, arch)

    set_request_state(request_id, 'in_progress', 'Creating the manifest list')
    output_pull_spec = _create_and_push_manifest_list(request_id, arches)

    _update_index_image_pull_spec(
        output_pull_spec=output_pull_spec,
        request_id=request_id,
        arches=arches,
        from_index=from_index,
        resolved_prebuild_from_index=from_index_resolved,
    )
    set_request_state(request_id, 'complete',
                      'The empty index image was successfully created')