Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

CFE-783: A variety of changes needed for correct operation with multi architecture catalogs #611

Merged

Conversation

jchunkins
Copy link
Contributor

@jchunkins jchunkins commented Apr 19, 2023

Description

This change brings support for processing multi and single architecture catalog images within oc mirror.

TL;DR: The first item in the manifest list has its FBC catalog extracted, which is then processed as needed and then “reinserted” (i.e. added as a new layer) into each image referenced in the manifest list. In other words, the images are modified with the same updated FBC content. The binaries within each architecture catalog are unmodified.

ociimage

To understand the changes in this PR, we need to discuss OCI layouts, which is a on disk representation of image references. The OCI layout specification shares similar concepts with the docker image v2s2 specification in that they both define manifests (i.e. a JSON document) that describe a single image or a list of images (i.e. a fat manifest). The primary difference between the two standards is the mediaType which indicates the standard being used (you can see the compatibility matrix for details). Essentially, OCI attempts to keep backwards compatibility with docker, and adds its own enhancements (e.g. annotations). These manifests can be pushed/pulled to/from a remote docker registry in either format, and can be converted from one type to another if desired. In the diagram above, you can see that manifest lists and image manifests are the entities that can be moved into and out of a OCI layout on a file system.

An OCI layout consists of an index.json file that acts as the entry point for discovering what images are stored within the layout on the disk. This index.json file can reference any number of single or multi architecture images, however oc mirror only references a single image at a time in a given OCI layout. The image stored in the OCI layout can be either a single architecture image (i.e. an image manifest) or a multi architecture image (i.e. a manifest list). A manifest list image is a logical grouping of an architecture specific image manifests stored in an array. This arrangement allows a single digest reference to represent all of the architecture specific images, and tools such as skopeo or podman can automatically pull an image that matches the platform that the tool is being executed on. An individual architecture specific image is referred to as an image manifest. A image manifest has references to a config JSON file that describes detailed layer history, the platform the image runs on and runtime information necessary to start an image. A image manifest, also has references to one or more layers, which are just tar files, which could be compressed or uncompressed. As you can see in the above diagram, all of these internal references are by digest, which is a hash computed by taking a sha256sum of the manifest or tar file. Note that the digest of the config file itself is referred to as the "image id" whereas an image digest is hash of the image manifest itself.

An example of a OCI layout on disk looks like this:

/path/to/oci/layout
├── blobs
│   └── sha256
│       ├── 01c6d5dcde3e9f2de758d794a77974600fe5e0b7a8c2ce2833eede2e8b25e7e5
│       └── ...
├── index.json
└── oci-layout

The index.json will have references to manifests and tar files that reside in the blobs/sha256 directory. Technically the index.json file is its own form of manifest list, but it is important to note that the index.json file itself has no representation in a docker registry. Tools such as skopeo will generate a OCI layout using what I call "manifest list indirection" where the manifest list resides in the blobs directory and the index.json references this manifest list by its digest. However some tools will set the media type of the index.json to indicate that its a manifest list and not use this "indirection" (i.e. the index.json directly refers to the image manifests and includes the platform information directly). This PR handles both of these scenarios, and ensures that the appropriate images are processed.

OCI layouts are stored in the oc mirror workspace under <oc-mirror-workspace>/src/catalogs/<repoPath>/layout. A diagram of this workspace looks like this:

	/tmp/cwd/oc-mirror-workspace
	├── results-1675904745
	└── src
		├── catalogs
		│   └── icr.io                                                                              ─┐
		│       └── cpopen                                                                           ├─ catalog path (one per catalog)
		│           └── ibm-zcon-zosconnect-catalog                                                  │
		│               └── sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76 ─┘
		│                   ├── include-config.gob         <—— this represents v1alpha2.IncludeConfig for associated with index/index.json
		│                   ├── index                      <—— this represents a decl config for "single architecture image" image
		│                   │   │                              which was selected (note all images store the same content)
		│                   │   └── index.json             <—— Declarative Config
		│                   └── layout                     <—— OCI layout is capable of holding “manifest list” and “single architecture" images
		│                       ├── blobs
		│                       │   └── sha256
		│                       │       ├── 01c6d5dcde3e9f2de758d794a77974600fe5e0b7a8c2ce2833eede2e8b25e7e5
		│                       │       ├── 1cd0595314a53d179ddaf68761c9f40c4d9d1bcd3f692d1c005938dac2993db6
		│                       │       ├── 1ff4ea896d6b958aa060e04eb090f70c563ad0650e6b362c1a1d67582acb3b8e
		│                       │       ├── 25d123725cf91c20b497ca9dae8e0a6e8dedd8fe64f83757f3b41f6ac447eac0
		│                       │       ├── 2d55550cefe39606cc933a2ed1d242b3fd9a72d85e92a2c6b52b9623a6f4fe6a
		│                       │       ├── 34e12aa195bcd8366fbab95a242e8214ae959259bd0a1119c28d124f5799f502
		│                       │       ├── 49a32e2e950732d5a638d5486968dcc3096f940a94811cfec99bd5a4f9e1ad49
		│                       │       ├── 561bc8bee264b124ba5673e73ad36589abbecf0b15fb845ed9aab4e640989fbc
		│                       │       ├── 6672e188b9c3f7274b7ebf4498b34f951bc20ea86a8d72367eab363f1722d2ed
		│                       │       ├── 7062267a99d0149e4129843a9e3257b882920fb8554ec2068a264b37539768bc
		│                       │       ├── ae475359a3fb8fe5e3dff0626f0c788b94340416eb5c453339abc884ac86b671
		│                       │       ├── b2dd6105dc025aa5c5e8b75e0b2d8a390951369801d049fc0de2586917a42772
		│                       │       ├── c03c8f94bb495320bbe862bc69349dbdf9f2a29b83d5b344b3930890aaf89d7d
		│                       │       ├── dc1b9846d7994450e74b9cde2e621f8c1d98cdf1debd591db291785dd3fc6446
		│                       │       └── f89d6e2463fc5fff8bba9e568ec28a6030076dbc412bd52dff6dbf2b5897a59d
		│                       ├── index.json
		│                       └── oci-layout
		├── charts
		├── publish
		│   └── .metadata.json
		├── release-signatures
		└── v2

At a high level, this PR allows oc mirror traverse the OCI layout to pick an image for processing depending on what's stored in the layout:

  • for a single image manifest, we can use this image directly
  • for a manifest list, we choose the first image is the list. We can do this because the catalog content is identical in all images.

Once an image is chosen, the declarative config (i.e. the JSON/YAML files that represent the OLM catalog) is extracted from the image for processing. The existing code which performed this extraction was done incorrectly, and this PR addresses this issue. When an OCI image is referenced in the ImageSetConfiguration, and the --use-oci-feature is set, this declarative config is placed into <current working directory>/olm_artifacts/<repo>/<config folder> which acts as a temporary location to store the extracted data. After the catalog is processed, the content is written to <oc-mirror-workspace>/src/catalogs/<repoPath>/index. This catalog content is then added to ALL image manifests that are stored within the OCI layout by adding new layers that represent the updated catalog content. This is handled within the ImageBuilder, which has been modified to handle image updates for both single and multi arch images. Other changes within the PR relate to properly handling file paths and docker reference parsing.

Also, to be clear, additional images defined in the ImageSetConfiguration, and related images found within the catalog itself are already capable of mirroring single and multi platform images already because the "oc image mirror" codebase knows how to do this already. This PR is primarily focused on making catalog image handling multi architecture "aware".

User Stories

  • As a user I want to perform a "mirror to mirror" operation using manifest list and single image docker references in the operators portion of the ImageSetConfiguration
  • As a user I want to perform a "mirror to disk" operation using manifest list and single image docker references in the operators portion of the ImageSetConfiguration
  • As a user I want to perform a "oci layout to mirror" operation using an oci reference in the operator portion of the ImageSetConfiguration. The content of the OCI layout can contain either a manifest list or a single image manifest

Acceptance Criteria

  • All mirror operations following the user stories should complete successfully, resulting in the catalog being pushed to its remote repository along with any related images or additional images (if any are supplied in the ImageSetConfiguration).

Functional Changes

pkg/cli/mirror/fbc_operators.go

  • remove findFBCConfig & replace with extractDeclarativeConfigFromImage This is necessary because the layer processing did not handle whiteout files. Switched to go-containerregistry which handles this correctly.
  • modify getManifest so that it is fat manifest aware, and returns the first manifest in the list, or for single images, returns that manifest
  • Removed functions that are no longer necessary: GetCatalogConfigPath, getConfigPathFromConfigLayer, UntarLayers

pkg/cli/mirror/create.go

  • make createOlmArtifactsForOCI manifest list aware and discovers the first image in the list, or for single images, uses that image directly
  • calls replacement function extractDeclarativeConfigFromImage
  • stores full path to the artifact in a map so this path does not need to be recalculated later
  • strip protocol from ctlg.OCIFBCPath when constructing a layoutPath

pkg/cli/mirror/options.go

  • add operatorCatalogToFullArtifactPath map[string]string which stores temporary paths to declarative config directory
    • key: OCI URI (e.g. oci://foo which originates with v1alpha2.Operator.Catalog)
    • value: /olm_artifacts//

pkg/cli/mirror/operator.go

  • initialize operatorCatalogToFullArtifactPath
  • make use of operatorCatalogToFullArtifactPath map to obtain the full path to the olm_artifacts directory and its contents and remove getOperatorCatalogRef() since it is no longer necessary
  • make writeLayout() use the image config file to discover the platform when adding images, otherwise fall back to linux/amd64

pkg/image/image.go

  • replace getManifest with getFirstDigestFromPath which now gets the first digest for manifest lists, or the image digest for single image
  • change logging behavior in ParseReference() when path does not exist and invalidate the ID in that case.
  • in ParseReference, make sure that the docker reference uses lower case values for "name" and "namespace" which is required to make valid docker references. This covers the case where a OCI filepath uses uppercase letters in its path.

pkg/cli/mirror/catalog_images.go

  • in rebuildCatalogs, make sure that the catalog source docker reference uses lower case values for "name" and namespace" which is required to make valid docker references. This covers the case where a OCI filepath uses uppercase letters in its path.

pkg/image/builder/image_builder.go

  • make image builder handle single arch and multi arch images

Non-functional Changes

pkg/cli/mirror/mirror.go

  • removed redundant AsRespoitory() call since RepositoryName() already does this
  • use constant for olm_artifacts directory
  • operatorCatalogToFullArtifactPath

pkg/cli/options.go

  • use constant for workspace

all files

  • add documentation and change formatting for long function signatures
  • if any file used deprecated io/ioutil, replace with io or os package as necessary
  • update unit tests as necessary (the bulk of the files are related to new test cases)

Test Changes

internal/testutils/testutils.go

  • update and create new functions for creating single/multiarch images
  • created *WithURL function variants to allow pre-existing registry in tests because the defaults server won't allow external calls while debugging

pkg/image/builder/image_builder_test.go

  • update test cases for image builder

Fixes # (CFE-783)

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

  • Test With Docker (mirror to mirror)
    • Use a ImageSetConfiguration which points to a "fat manifest" catalog:
    kind: ImageSetConfiguration
    apiVersion: mirror.openshift.io/v1alpha2
    storageConfig:
      local:
        path: /tmp/localstorage
    mirror:
      operators:
      - catalog: icr.io/cpopen/ibm-zcon-zosconnect-catalog@sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76
    • Start a local docker registry to act as the destination
    docker run -d -p 5000:5000 --name registry registry:2
    
    • Run oc mirror like this (no errors should occur):
    oc mirror -c "/path/to/ImageSetConfiguration.yml" --dest-skip-tls --dest-use-http docker://localhost:5000
    
    • Throw away your local docker registry
    docker stop registry
    docker rm registry
    
  • Test With Docker (mirror to disk)
    • Use a ImageSetConfiguration which points to a "fat manifest" catalog:
    kind: ImageSetConfiguration
    apiVersion: mirror.openshift.io/v1alpha2
    storageConfig:
      local:
        path: /tmp/localstorage
    mirror:
      operators:
      - catalog: icr.io/cpopen/ibm-zcon-zosconnect-catalog@sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76
    • Run oc mirror like this (no errors should occur):
    oc mirror -c "/path/to/ImageSetConfiguration.yml" file://tmp/mirrortodisktest
    
  • Test With OCI
    • Pull a docker "fat manifest" image into a location on the file system:
    skopeo copy --all --format v2s2 docker://icr.io/cpopen/ibm-zcon-zosconnect-catalog@sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76 oci:///Users/jhunkins/temp/ocmirror
    
    • Use a ImageSetConfiguration which points to this newly downloaded image like this:
    kind: ImageSetConfiguration
    apiVersion: mirror.openshift.io/v1alpha2
    storageConfig:
      local:
        path: /tmp/localstorage
    mirror:
      operators:
      - catalog: oci:///Users/jhunkins/temp/ocmirror
    • Start a local docker registry to act as the destination
    docker run -d -p 5000:5000 --name registry registry:2
    
    • Run oc mirror like this (no errors should occur):
    oc mirror -c "/path/to/ImageSetConfiguration.yml" --use-oci-feature --oci-insecure-signature-policy --dest-skip-tls --dest-use-http docker://localhost:5000
    
    • Throw away your local docker registry
    docker stop registry
    docker rm registry
    

Test Configuration:

  • Firmware version:
  • Hardware:
  • Toolchain:
  • SDK:

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

@jchunkins jchunkins changed the title A variety of changes needed for correct operation WIP A variety of changes needed for correct operation with multi architecture catalogs Apr 19, 2023
@openshift-ci openshift-ci bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Apr 19, 2023
@jchunkins jchunkins changed the title WIP A variety of changes needed for correct operation with multi architecture catalogs CFE-783: A variety of changes needed for correct operation with multi architecture catalogs Apr 20, 2023
@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Apr 20, 2023
@openshift-ci-robot
Copy link

openshift-ci-robot commented Apr 20, 2023

@jchunkins: This pull request references CFE-783 which is a valid jira issue.

In response to this:

Description

Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.

Functional Changes

pkg/cli/mirror/fbc_operators.go

  • remove findFBCConfig & replace with extractDeclarativeConfigFromImage This is necessary because the layer processing did not handle whiteout files. Switched to go-containerregistry which handles this correctly.
  • modify getManifest so that it is fat manifest aware, and returns the first manifest in the list, or for single images, returns that manifest
  • Removed functions that are no longer necessary: GetCatalogConfigPath, getConfigPathFromConfigLayer, UntarLayers

pkg/cli/mirror/create.go

  • make createOlmArtifactsForOCI manifest list aware and discovers the first image in the list, or for single images, uses that image directly
  • calls replacement function extractDeclarativeConfigFromImage
  • stores full path to the artifact in a map so this path does not need to be recalculated later

pkg/cli/mirror/operator.go

  • make use of operatorCatalogToFullArtifactPath map to obtain the full path to the olm_artifacts directory and its contents and remove getOperatorCatalogRef() since it is no longer necessary
  • make writeLayout() use the image config file to discover the platform when adding images, otherwise fall back to linux/amd64

pkg/cli/mirror/options.go

  • add operatorCatalogToFullArtifactPath map[string]string

pkg/image/image.go

  • replace getManifest with getFirstDigestFromPath which now gets the first digest for manifest lists, or the image digest for single image
  • change logging behavior in ParseReference() when path does not exist and invalidate the ID in that case.

Non-functional Changes

pkg/cli/mirror/mirror.go

  • removed redundant AsRespoitory() call since RepositoryName() already does this
  • use constant for olm_artifacts directory

pkg/cli/options.go

  • use constant for workspace

all files

  • add documentation and change formatting for long function signatures
  • if any file used deprecated io/ioutil, replace with io or os package as necessary
  • update unit tests as necessary (the bulk of the files are related to new test cases)

Fixes # (issue)

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

  • Test A
  • Test B

Test Configuration:

  • Firmware version:
  • Hardware:
  • Toolchain:
  • SDK:

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@openshift-ci openshift-ci bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Apr 20, 2023
@jchunkins jchunkins changed the title CFE-783: A variety of changes needed for correct operation with multi architecture catalogs WIP CFE-783: A variety of changes needed for correct operation with multi architecture catalogs Apr 20, 2023
@openshift-ci openshift-ci bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Apr 20, 2023
@jchunkins jchunkins changed the title WIP CFE-783: A variety of changes needed for correct operation with multi architecture catalogs WIP: CFE-783: A variety of changes needed for correct operation with multi architecture catalogs Apr 20, 2023
@openshift-ci-robot
Copy link

openshift-ci-robot commented Apr 21, 2023

@jchunkins: This pull request references CFE-783 which is a valid jira issue.

In response to this:

Description

Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.

Functional Changes

pkg/cli/mirror/fbc_operators.go

  • remove findFBCConfig & replace with extractDeclarativeConfigFromImage This is necessary because the layer processing did not handle whiteout files. Switched to go-containerregistry which handles this correctly.
  • modify getManifest so that it is fat manifest aware, and returns the first manifest in the list, or for single images, returns that manifest
  • Removed functions that are no longer necessary: GetCatalogConfigPath, getConfigPathFromConfigLayer, UntarLayers

pkg/cli/mirror/create.go

  • make createOlmArtifactsForOCI manifest list aware and discovers the first image in the list, or for single images, uses that image directly
  • calls replacement function extractDeclarativeConfigFromImage
  • stores full path to the artifact in a map so this path does not need to be recalculated later
  • strip protocol from ctlg.OCIFBCPath when constructing a layoutPath

pkg/cli/mirror/options.go

  • add operatorCatalogToFullArtifactPath map[string]string which stores temporary paths to declarative config directory
  • key: OCI URI (e.g. oci://foo which originates with v1alpha2.Operator.Catalog)
  • value: /olm_artifacts//

pkg/cli/mirror/operator.go

  • initialize operatorCatalogToFullArtifactPath
  • make use of operatorCatalogToFullArtifactPath map to obtain the full path to the olm_artifacts directory and its contents and remove getOperatorCatalogRef() since it is no longer necessary
  • make writeLayout() use the image config file to discover the platform when adding images, otherwise fall back to linux/amd64

pkg/image/image.go

  • replace getManifest with getFirstDigestFromPath which now gets the first digest for manifest lists, or the image digest for single image
  • change logging behavior in ParseReference() when path does not exist and invalidate the ID in that case.
  • in ParseReference, make sure that the docker reference uses lower case values for "name" and "namespace" which is required to make valid docker references. This covers the case where a OCI filepath uses uppercase letters in its path.

pkg/cli/mirror/catalog_images.go

  • in rebuildCatalogs, make sure that the catalog source docker reference uses lower case values for "name" and namespace" which is required to make valid docker references. This covers the case where a OCI filepath uses uppercase letters in its path.

pkg/image/builder/image_builder.go

  • make image builder handle single arch and multi arch images

Non-functional Changes

pkg/cli/mirror/mirror.go

  • removed redundant AsRespoitory() call since RepositoryName() already does this
  • use constant for olm_artifacts directory
  • operatorCatalogToFullArtifactPath

pkg/cli/options.go

  • use constant for workspace

all files

  • add documentation and change formatting for long function signatures
  • if any file used deprecated io/ioutil, replace with io or os package as necessary
  • update unit tests as necessary (the bulk of the files are related to new test cases)

Test Changes

internal/testutils/testutils.go

  • update and create new functions for creating single/multiarch images
  • created *WithURL function variants to allow pre-existing registry in tests because the defaults server won't allow external calls while debugging

pkg/image/builder/image_builder_test.go

  • update test cases for image builder

Fixes # (issue)

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

  • Test A
  • Test B

Test Configuration:

  • Firmware version:
  • Hardware:
  • Toolchain:
  • SDK:

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@openshift-ci-robot
Copy link

openshift-ci-robot commented Apr 21, 2023

@jchunkins: This pull request references CFE-783 which is a valid jira issue.

In response to this:

Description

Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.

Functional Changes

pkg/cli/mirror/fbc_operators.go

  • remove findFBCConfig & replace with extractDeclarativeConfigFromImage This is necessary because the layer processing did not handle whiteout files. Switched to go-containerregistry which handles this correctly.
  • modify getManifest so that it is fat manifest aware, and returns the first manifest in the list, or for single images, returns that manifest
  • Removed functions that are no longer necessary: GetCatalogConfigPath, getConfigPathFromConfigLayer, UntarLayers

pkg/cli/mirror/create.go

  • make createOlmArtifactsForOCI manifest list aware and discovers the first image in the list, or for single images, uses that image directly
  • calls replacement function extractDeclarativeConfigFromImage
  • stores full path to the artifact in a map so this path does not need to be recalculated later
  • strip protocol from ctlg.OCIFBCPath when constructing a layoutPath

pkg/cli/mirror/options.go

  • add operatorCatalogToFullArtifactPath map[string]string which stores temporary paths to declarative config directory
  • key: OCI URI (e.g. oci://foo which originates with v1alpha2.Operator.Catalog)
  • value: /olm_artifacts//

pkg/cli/mirror/operator.go

  • initialize operatorCatalogToFullArtifactPath
  • make use of operatorCatalogToFullArtifactPath map to obtain the full path to the olm_artifacts directory and its contents and remove getOperatorCatalogRef() since it is no longer necessary
  • make writeLayout() use the image config file to discover the platform when adding images, otherwise fall back to linux/amd64

pkg/image/image.go

  • replace getManifest with getFirstDigestFromPath which now gets the first digest for manifest lists, or the image digest for single image
  • change logging behavior in ParseReference() when path does not exist and invalidate the ID in that case.
  • in ParseReference, make sure that the docker reference uses lower case values for "name" and "namespace" which is required to make valid docker references. This covers the case where a OCI filepath uses uppercase letters in its path.

pkg/cli/mirror/catalog_images.go

  • in rebuildCatalogs, make sure that the catalog source docker reference uses lower case values for "name" and namespace" which is required to make valid docker references. This covers the case where a OCI filepath uses uppercase letters in its path.

pkg/image/builder/image_builder.go

  • make image builder handle single arch and multi arch images

Non-functional Changes

pkg/cli/mirror/mirror.go

  • removed redundant AsRespoitory() call since RepositoryName() already does this
  • use constant for olm_artifacts directory
  • operatorCatalogToFullArtifactPath

pkg/cli/options.go

  • use constant for workspace

all files

  • add documentation and change formatting for long function signatures
  • if any file used deprecated io/ioutil, replace with io or os package as necessary
  • update unit tests as necessary (the bulk of the files are related to new test cases)

Test Changes

internal/testutils/testutils.go

  • update and create new functions for creating single/multiarch images
  • created *WithURL function variants to allow pre-existing registry in tests because the defaults server won't allow external calls while debugging

pkg/image/builder/image_builder_test.go

  • update test cases for image builder

Fixes # (CFE-783)

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

  • Test A
  • Test B

Test Configuration:

  • Firmware version:
  • Hardware:
  • Toolchain:
  • SDK:

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

1 similar comment
@openshift-ci-robot
Copy link

openshift-ci-robot commented Apr 21, 2023

@jchunkins: This pull request references CFE-783 which is a valid jira issue.

In response to this:

Description

Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.

Functional Changes

pkg/cli/mirror/fbc_operators.go

  • remove findFBCConfig & replace with extractDeclarativeConfigFromImage This is necessary because the layer processing did not handle whiteout files. Switched to go-containerregistry which handles this correctly.
  • modify getManifest so that it is fat manifest aware, and returns the first manifest in the list, or for single images, returns that manifest
  • Removed functions that are no longer necessary: GetCatalogConfigPath, getConfigPathFromConfigLayer, UntarLayers

pkg/cli/mirror/create.go

  • make createOlmArtifactsForOCI manifest list aware and discovers the first image in the list, or for single images, uses that image directly
  • calls replacement function extractDeclarativeConfigFromImage
  • stores full path to the artifact in a map so this path does not need to be recalculated later
  • strip protocol from ctlg.OCIFBCPath when constructing a layoutPath

pkg/cli/mirror/options.go

  • add operatorCatalogToFullArtifactPath map[string]string which stores temporary paths to declarative config directory
  • key: OCI URI (e.g. oci://foo which originates with v1alpha2.Operator.Catalog)
  • value: /olm_artifacts//

pkg/cli/mirror/operator.go

  • initialize operatorCatalogToFullArtifactPath
  • make use of operatorCatalogToFullArtifactPath map to obtain the full path to the olm_artifacts directory and its contents and remove getOperatorCatalogRef() since it is no longer necessary
  • make writeLayout() use the image config file to discover the platform when adding images, otherwise fall back to linux/amd64

pkg/image/image.go

  • replace getManifest with getFirstDigestFromPath which now gets the first digest for manifest lists, or the image digest for single image
  • change logging behavior in ParseReference() when path does not exist and invalidate the ID in that case.
  • in ParseReference, make sure that the docker reference uses lower case values for "name" and "namespace" which is required to make valid docker references. This covers the case where a OCI filepath uses uppercase letters in its path.

pkg/cli/mirror/catalog_images.go

  • in rebuildCatalogs, make sure that the catalog source docker reference uses lower case values for "name" and namespace" which is required to make valid docker references. This covers the case where a OCI filepath uses uppercase letters in its path.

pkg/image/builder/image_builder.go

  • make image builder handle single arch and multi arch images

Non-functional Changes

pkg/cli/mirror/mirror.go

  • removed redundant AsRespoitory() call since RepositoryName() already does this
  • use constant for olm_artifacts directory
  • operatorCatalogToFullArtifactPath

pkg/cli/options.go

  • use constant for workspace

all files

  • add documentation and change formatting for long function signatures
  • if any file used deprecated io/ioutil, replace with io or os package as necessary
  • update unit tests as necessary (the bulk of the files are related to new test cases)

Test Changes

internal/testutils/testutils.go

  • update and create new functions for creating single/multiarch images
  • created *WithURL function variants to allow pre-existing registry in tests because the defaults server won't allow external calls while debugging

pkg/image/builder/image_builder_test.go

  • update test cases for image builder

Fixes # (CFE-783)

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

  • Test A
  • Test B

Test Configuration:

  • Firmware version:
  • Hardware:
  • Toolchain:
  • SDK:

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@openshift-ci-robot
Copy link

openshift-ci-robot commented Apr 21, 2023

@jchunkins: This pull request references CFE-783 which is a valid jira issue.

In response to this:

Description

Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.

Functional Changes

pkg/cli/mirror/fbc_operators.go

  • remove findFBCConfig & replace with extractDeclarativeConfigFromImage This is necessary because the layer processing did not handle whiteout files. Switched to go-containerregistry which handles this correctly.
  • modify getManifest so that it is fat manifest aware, and returns the first manifest in the list, or for single images, returns that manifest
  • Removed functions that are no longer necessary: GetCatalogConfigPath, getConfigPathFromConfigLayer, UntarLayers

pkg/cli/mirror/create.go

  • make createOlmArtifactsForOCI manifest list aware and discovers the first image in the list, or for single images, uses that image directly
  • calls replacement function extractDeclarativeConfigFromImage
  • stores full path to the artifact in a map so this path does not need to be recalculated later
  • strip protocol from ctlg.OCIFBCPath when constructing a layoutPath

pkg/cli/mirror/options.go

  • add operatorCatalogToFullArtifactPath map[string]string which stores temporary paths to declarative config directory
  • key: OCI URI (e.g. oci://foo which originates with v1alpha2.Operator.Catalog)
  • value: /olm_artifacts//

pkg/cli/mirror/operator.go

  • initialize operatorCatalogToFullArtifactPath
  • make use of operatorCatalogToFullArtifactPath map to obtain the full path to the olm_artifacts directory and its contents and remove getOperatorCatalogRef() since it is no longer necessary
  • make writeLayout() use the image config file to discover the platform when adding images, otherwise fall back to linux/amd64

pkg/image/image.go

  • replace getManifest with getFirstDigestFromPath which now gets the first digest for manifest lists, or the image digest for single image
  • change logging behavior in ParseReference() when path does not exist and invalidate the ID in that case.
  • in ParseReference, make sure that the docker reference uses lower case values for "name" and "namespace" which is required to make valid docker references. This covers the case where a OCI filepath uses uppercase letters in its path.

pkg/cli/mirror/catalog_images.go

  • in rebuildCatalogs, make sure that the catalog source docker reference uses lower case values for "name" and namespace" which is required to make valid docker references. This covers the case where a OCI filepath uses uppercase letters in its path.

pkg/image/builder/image_builder.go

  • make image builder handle single arch and multi arch images

Non-functional Changes

pkg/cli/mirror/mirror.go

  • removed redundant AsRespoitory() call since RepositoryName() already does this
  • use constant for olm_artifacts directory
  • operatorCatalogToFullArtifactPath

pkg/cli/options.go

  • use constant for workspace

all files

  • add documentation and change formatting for long function signatures
  • if any file used deprecated io/ioutil, replace with io or os package as necessary
  • update unit tests as necessary (the bulk of the files are related to new test cases)

Test Changes

internal/testutils/testutils.go

  • update and create new functions for creating single/multiarch images
  • created *WithURL function variants to allow pre-existing registry in tests because the defaults server won't allow external calls while debugging

pkg/image/builder/image_builder_test.go

  • update test cases for image builder

Fixes # (CFE-783)

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

  • Test With Docker (mirror to mirror)
  • Use a ImageSetConfiguration which points to a "fat manifest" catalog:
kind: ImageSetConfiguration
apiVersion: mirror.openshift.io/v1alpha2
storageConfig:
  local:
    path: /tmp/localstorage
mirror:
  operators:
  - catalog: icr.io/cpopen/ibm-zcon-zosconnect-catalog@sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76
  • Start a local docker registry to act as the destination
docker run -d -p 5000:5000 --name registry registry:2
  • Run oc mirror like this (no errors should occur):
oc mirror -c "/path/to/ImageSetConfiguration.yml" --dest-skip-tls --dest-use-http docker://localhost:5000
  • Throw away your local docker registry
docker stop registry
docker rm registry
  • Test With Docker (mirror to disk)
  • Use a ImageSetConfiguration which points to a "fat manifest" catalog:
kind: ImageSetConfiguration
apiVersion: mirror.openshift.io/v1alpha2
storageConfig:
  local:
    path: /tmp/localstorage
mirror:
  operators:
  - catalog: icr.io/cpopen/ibm-zcon-zosconnect-catalog@sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76
  • Run oc mirror like this (no errors should occur):
oc mirror -c "/path/to/ImageSetConfiguration.yml" file://tmp/mirrortodisktest
  • Test With OCI
  • Pull a docker "fat manifest" image into a location on the file system:
skopeo copy --all --format v2s2 docker://icr.io/cpopen/ibm-zcon-zosconnect-catalog@sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76 oci:///Users/jhunkins/temp/ocmirror
  • Use a ImageSetConfiguration which points to this newly downloaded image like this:
kind: ImageSetConfiguration
apiVersion: mirror.openshift.io/v1alpha2
storageConfig:
  local:
    path: /tmp/localstorage
mirror:
  operators:
  - catalog: oci:///Users/jhunkins/temp/ocmirror
  • Start a local docker registry to act as the destination
docker run -d -p 5000:5000 --name registry registry:2
  • Run oc mirror like this (no errors should occur):
oc mirror -c "/path/to/ImageSetConfiguration.yml" --use-oci-feature --oci-insecure-signature-policy --dest-skip-tls --dest-use-http docker://localhost:5000
  • Throw away your local docker registry
docker stop registry
docker rm registry

Test Configuration:

  • Firmware version:
  • Hardware:
  • Toolchain:
  • SDK:

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@openshift-ci-robot
Copy link

openshift-ci-robot commented Apr 22, 2023

@jchunkins: This pull request references CFE-783 which is a valid jira issue.

In response to this:

Description

This change brings support for processing multi and single architecture catalog images within oc mirror.

ociimage

To understand the changes in this PR, we need to discuss OCI layouts, which is a on disk representation of image references. The OCI layout specification shares similar concepts with the docker image v2s2 specification in that they both define manifests (i.e. a JSON document) that describe a single image or a list of images (i.e. a fat manifest). The primary difference between the two standards is the mediaType which indicates the standard being used (you can see the compatibility matrix for details). Essentially, OCI attempts to keep backwards compatibility with docker, and adds its own enhancements (e.g. annotations). These manifests can be pushed/pulled to/from a remote docker registry in either format, and can be converted from one type to another if desired. In the diagram above, you can see that manifest lists and image manifests are the entities that can be moved into and out of a OCI layout on a file system.

An OCI layout consists of an index.json file that acts as the entry point for discovering what images are stored within the layout on the disk. This index.json file can reference any number of single or multi architecture images, however oc mirror only references a single image at a time in a given OCI layout. The image stored in the OCI layout can be either a single architecture image (i.e. an image manifest) or a multi architecture image (i.e. a manifest list). A manifest list image has a list of references to architecture specific image manifests. A image manifest itself has references to a config JSON file, as well as references to one or more layers, which are just tar files, which could be compressed or uncompressed. As you can see in the above diagram, all of these internal references are by digest, which is a hash computed by taking a sha256sum of the manifest or tar file. Note that the digest of the config file itself is referred to as the "image id" whereas an image digest is hash of the image manifest itself.

An example of a OCI layout on disk looks like this:

/path/to/oci/layout
├── blobs
│   └── sha256
│       ├── 01c6d5dcde3e9f2de758d794a77974600fe5e0b7a8c2ce2833eede2e8b25e7e5
│       └── ...
├── index.json
└── oci-layout

The index.json will have references to manifests and tar files that reside in the blobs/sha256 directory. Technically the index.json file is its own form of manifest list, but it is important to note that the index.json file itself has no representation in a docker registry. Tools such as skopeo will generate a OCI layout using what I call "manifest list indirection" where the manifest list resides in the blobs directory and the index.json references this manifest list by its digest. However some tools will set the media type of the index.json to indicate that its a manifest list and not use this "indirection" (i.e. the index.json directly refers to the image manifests and includes the platform information directly). This PR knows how to handle both of these scenarios.

Functional Changes

pkg/cli/mirror/fbc_operators.go

  • remove findFBCConfig & replace with extractDeclarativeConfigFromImage This is necessary because the layer processing did not handle whiteout files. Switched to go-containerregistry which handles this correctly.
  • modify getManifest so that it is fat manifest aware, and returns the first manifest in the list, or for single images, returns that manifest
  • Removed functions that are no longer necessary: GetCatalogConfigPath, getConfigPathFromConfigLayer, UntarLayers

pkg/cli/mirror/create.go

  • make createOlmArtifactsForOCI manifest list aware and discovers the first image in the list, or for single images, uses that image directly
  • calls replacement function extractDeclarativeConfigFromImage
  • stores full path to the artifact in a map so this path does not need to be recalculated later
  • strip protocol from ctlg.OCIFBCPath when constructing a layoutPath

pkg/cli/mirror/options.go

  • add operatorCatalogToFullArtifactPath map[string]string which stores temporary paths to declarative config directory
  • key: OCI URI (e.g. oci://foo which originates with v1alpha2.Operator.Catalog)
  • value: /olm_artifacts//

pkg/cli/mirror/operator.go

  • initialize operatorCatalogToFullArtifactPath
  • make use of operatorCatalogToFullArtifactPath map to obtain the full path to the olm_artifacts directory and its contents and remove getOperatorCatalogRef() since it is no longer necessary
  • make writeLayout() use the image config file to discover the platform when adding images, otherwise fall back to linux/amd64

pkg/image/image.go

  • replace getManifest with getFirstDigestFromPath which now gets the first digest for manifest lists, or the image digest for single image
  • change logging behavior in ParseReference() when path does not exist and invalidate the ID in that case.
  • in ParseReference, make sure that the docker reference uses lower case values for "name" and "namespace" which is required to make valid docker references. This covers the case where a OCI filepath uses uppercase letters in its path.

pkg/cli/mirror/catalog_images.go

  • in rebuildCatalogs, make sure that the catalog source docker reference uses lower case values for "name" and namespace" which is required to make valid docker references. This covers the case where a OCI filepath uses uppercase letters in its path.

pkg/image/builder/image_builder.go

  • make image builder handle single arch and multi arch images

Non-functional Changes

pkg/cli/mirror/mirror.go

  • removed redundant AsRespoitory() call since RepositoryName() already does this
  • use constant for olm_artifacts directory
  • operatorCatalogToFullArtifactPath

pkg/cli/options.go

  • use constant for workspace

all files

  • add documentation and change formatting for long function signatures
  • if any file used deprecated io/ioutil, replace with io or os package as necessary
  • update unit tests as necessary (the bulk of the files are related to new test cases)

Test Changes

internal/testutils/testutils.go

  • update and create new functions for creating single/multiarch images
  • created *WithURL function variants to allow pre-existing registry in tests because the defaults server won't allow external calls while debugging

pkg/image/builder/image_builder_test.go

  • update test cases for image builder

Fixes # (CFE-783)

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

  • Test With Docker (mirror to mirror)
  • Use a ImageSetConfiguration which points to a "fat manifest" catalog:
kind: ImageSetConfiguration
apiVersion: mirror.openshift.io/v1alpha2
storageConfig:
  local:
    path: /tmp/localstorage
mirror:
  operators:
  - catalog: icr.io/cpopen/ibm-zcon-zosconnect-catalog@sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76
  • Start a local docker registry to act as the destination
docker run -d -p 5000:5000 --name registry registry:2
  • Run oc mirror like this (no errors should occur):
oc mirror -c "/path/to/ImageSetConfiguration.yml" --dest-skip-tls --dest-use-http docker://localhost:5000
  • Throw away your local docker registry
docker stop registry
docker rm registry
  • Test With Docker (mirror to disk)
  • Use a ImageSetConfiguration which points to a "fat manifest" catalog:
kind: ImageSetConfiguration
apiVersion: mirror.openshift.io/v1alpha2
storageConfig:
  local:
    path: /tmp/localstorage
mirror:
  operators:
  - catalog: icr.io/cpopen/ibm-zcon-zosconnect-catalog@sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76
  • Run oc mirror like this (no errors should occur):
oc mirror -c "/path/to/ImageSetConfiguration.yml" file://tmp/mirrortodisktest
  • Test With OCI
  • Pull a docker "fat manifest" image into a location on the file system:
skopeo copy --all --format v2s2 docker://icr.io/cpopen/ibm-zcon-zosconnect-catalog@sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76 oci:///Users/jhunkins/temp/ocmirror
  • Use a ImageSetConfiguration which points to this newly downloaded image like this:
kind: ImageSetConfiguration
apiVersion: mirror.openshift.io/v1alpha2
storageConfig:
  local:
    path: /tmp/localstorage
mirror:
  operators:
  - catalog: oci:///Users/jhunkins/temp/ocmirror
  • Start a local docker registry to act as the destination
docker run -d -p 5000:5000 --name registry registry:2
  • Run oc mirror like this (no errors should occur):
oc mirror -c "/path/to/ImageSetConfiguration.yml" --use-oci-feature --oci-insecure-signature-policy --dest-skip-tls --dest-use-http docker://localhost:5000
  • Throw away your local docker registry
docker stop registry
docker rm registry

Test Configuration:

  • Firmware version:
  • Hardware:
  • Toolchain:
  • SDK:

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@openshift-ci-robot
Copy link

openshift-ci-robot commented Apr 22, 2023

@jchunkins: This pull request references CFE-783 which is a valid jira issue.

In response to this:

Description

This change brings support for processing multi and single architecture catalog images within oc mirror.

ociimage

To understand the changes in this PR, we need to discuss OCI layouts, which is a on disk representation of image references. The OCI layout specification shares similar concepts with the docker image v2s2 specification in that they both define manifests (i.e. a JSON document) that describe a single image or a list of images (i.e. a fat manifest). The primary difference between the two standards is the mediaType which indicates the standard being used (you can see the compatibility matrix for details). Essentially, OCI attempts to keep backwards compatibility with docker, and adds its own enhancements (e.g. annotations). These manifests can be pushed/pulled to/from a remote docker registry in either format, and can be converted from one type to another if desired. In the diagram above, you can see that manifest lists and image manifests are the entities that can be moved into and out of a OCI layout on a file system.

An OCI layout consists of an index.json file that acts as the entry point for discovering what images are stored within the layout on the disk. This index.json file can reference any number of single or multi architecture images, however oc mirror only references a single image at a time in a given OCI layout. The image stored in the OCI layout can be either a single architecture image (i.e. an image manifest) or a multi architecture image (i.e. a manifest list). A manifest list image is a logical grouping of an architecture specific image manifests stored in an array. This arrangement allows a single digest reference to represent all of the architecture specific images, and tools such as skopeo or podman can automatically pull an image that matches the platform that the tool is being executed on. An individual architecture specific image is referred to as an image manifest. A image manifest has references to a config JSON file that describes detailed layer history, the platform the image runs on and runtime information necessary to start an image. A image manifest, also has references to one or more layers, which are just tar files, which could be compressed or uncompressed. As you can see in the above diagram, all of these internal references are by digest, which is a hash computed by taking a sha256sum of the manifest or tar file. Note that the digest of the config file itself is referred to as the "image id" whereas an image digest is hash of the image manifest itself.

An example of a OCI layout on disk looks like this:

/path/to/oci/layout
├── blobs
│   └── sha256
│       ├── 01c6d5dcde3e9f2de758d794a77974600fe5e0b7a8c2ce2833eede2e8b25e7e5
│       └── ...
├── index.json
└── oci-layout

The index.json will have references to manifests and tar files that reside in the blobs/sha256 directory. Technically the index.json file is its own form of manifest list, but it is important to note that the index.json file itself has no representation in a docker registry. Tools such as skopeo will generate a OCI layout using what I call "manifest list indirection" where the manifest list resides in the blobs directory and the index.json references this manifest list by its digest. However some tools will set the media type of the index.json to indicate that its a manifest list and not use this "indirection" (i.e. the index.json directly refers to the image manifests and includes the platform information directly). This PR handles both of these scenarios, and ensures that the appropriate images are processed.

OCI layouts are stored in the oc mirror workspace under <oc-mirror-workspace>/src/catalogs/<repoPath>/layout. A diagram of this workspace looks like this:

  /tmp/cwd/oc-mirror-workspace
  ├── results-1675904745
  └── src
  	├── catalogs
  	│   └── icr.io                                                                              ─┐
  	│       └── cpopen                                                                           ├─ catalog path (one per catalog)
  	│           └── ibm-zcon-zosconnect-catalog                                                  │
  	│               └── sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76 ─┘
  	│                   ├── include-config.gob         <—— this represents v1alpha2.IncludeConfig for associated with index/index.json
  	│                   ├── index                      <—— this represents a decl config for "single architecture image" image
  	│                   │   │                              (i.e. no multi arch use case)
  	│                   │   └── index.json             <—— Declarative Config
  	│                   └── layout                     <—— OCI layout is capable of holding “manifest list” and “single architecture" images
  	│                       ├── blobs
  	│                       │   └── sha256
  	│                       │       ├── 01c6d5dcde3e9f2de758d794a77974600fe5e0b7a8c2ce2833eede2e8b25e7e5
  	│                       │       ├── 1cd0595314a53d179ddaf68761c9f40c4d9d1bcd3f692d1c005938dac2993db6
  	│                       │       ├── 1ff4ea896d6b958aa060e04eb090f70c563ad0650e6b362c1a1d67582acb3b8e
  	│                       │       ├── 25d123725cf91c20b497ca9dae8e0a6e8dedd8fe64f83757f3b41f6ac447eac0
  	│                       │       ├── 2d55550cefe39606cc933a2ed1d242b3fd9a72d85e92a2c6b52b9623a6f4fe6a
  	│                       │       ├── 34e12aa195bcd8366fbab95a242e8214ae959259bd0a1119c28d124f5799f502
  	│                       │       ├── 49a32e2e950732d5a638d5486968dcc3096f940a94811cfec99bd5a4f9e1ad49
  	│                       │       ├── 561bc8bee264b124ba5673e73ad36589abbecf0b15fb845ed9aab4e640989fbc
  	│                       │       ├── 6672e188b9c3f7274b7ebf4498b34f951bc20ea86a8d72367eab363f1722d2ed
  	│                       │       ├── 7062267a99d0149e4129843a9e3257b882920fb8554ec2068a264b37539768bc
  	│                       │       ├── ae475359a3fb8fe5e3dff0626f0c788b94340416eb5c453339abc884ac86b671
  	│                       │       ├── b2dd6105dc025aa5c5e8b75e0b2d8a390951369801d049fc0de2586917a42772
  	│                       │       ├── c03c8f94bb495320bbe862bc69349dbdf9f2a29b83d5b344b3930890aaf89d7d
  	│                       │       ├── dc1b9846d7994450e74b9cde2e621f8c1d98cdf1debd591db291785dd3fc6446
  	│                       │       └── f89d6e2463fc5fff8bba9e568ec28a6030076dbc412bd52dff6dbf2b5897a59d
  	│                       ├── index.json
  	│                       └── oci-layout
  	├── charts
  	├── publish
  	│   └── .metadata.json
  	├── release-signatures
  	└── v2

At a high level, this PR allows oc mirror traverse the OCI layout to pick an image for processing depending on what's stored in the layout:

  • for a single image manifest, we can use this image directly
  • for a manifest list, we choose the first image is the list

Once an image is chosen, the declarative config (i.e. the JSON/YAML files that represent the OLM catalog) is extracted from the image for processing. The existing code which performed this extraction was done incorrectly, and this PR addresses this issue. When an OCI image is the referenced in the ISC, and the --use-oci-feature is set, this declarative config is placed into <current working directory>/olm_artifacts/<repo>/<config folder> which acts as a temporary location to store the extracted data. After the catalog is processed, the content is written to <oc-mirror-workspace>/src/catalogs/<repoPath>/index, and then ALL image manifests that are stored within the OCI layout are updated with new layers that represent the updated catalog content. This is handled within the ImageBuilder, which has been modified to handle image updates for both single and multi arch images. Other changes within the PR relate to properly handling file paths and docker reference parsing.

Functional Changes

pkg/cli/mirror/fbc_operators.go

  • remove findFBCConfig & replace with extractDeclarativeConfigFromImage This is necessary because the layer processing did not handle whiteout files. Switched to go-containerregistry which handles this correctly.
  • modify getManifest so that it is fat manifest aware, and returns the first manifest in the list, or for single images, returns that manifest
  • Removed functions that are no longer necessary: GetCatalogConfigPath, getConfigPathFromConfigLayer, UntarLayers

pkg/cli/mirror/create.go

  • make createOlmArtifactsForOCI manifest list aware and discovers the first image in the list, or for single images, uses that image directly
  • calls replacement function extractDeclarativeConfigFromImage
  • stores full path to the artifact in a map so this path does not need to be recalculated later
  • strip protocol from ctlg.OCIFBCPath when constructing a layoutPath

pkg/cli/mirror/options.go

  • add operatorCatalogToFullArtifactPath map[string]string which stores temporary paths to declarative config directory
  • key: OCI URI (e.g. oci://foo which originates with v1alpha2.Operator.Catalog)
  • value: /olm_artifacts//

pkg/cli/mirror/operator.go

  • initialize operatorCatalogToFullArtifactPath
  • make use of operatorCatalogToFullArtifactPath map to obtain the full path to the olm_artifacts directory and its contents and remove getOperatorCatalogRef() since it is no longer necessary
  • make writeLayout() use the image config file to discover the platform when adding images, otherwise fall back to linux/amd64

pkg/image/image.go

  • replace getManifest with getFirstDigestFromPath which now gets the first digest for manifest lists, or the image digest for single image
  • change logging behavior in ParseReference() when path does not exist and invalidate the ID in that case.
  • in ParseReference, make sure that the docker reference uses lower case values for "name" and "namespace" which is required to make valid docker references. This covers the case where a OCI filepath uses uppercase letters in its path.

pkg/cli/mirror/catalog_images.go

  • in rebuildCatalogs, make sure that the catalog source docker reference uses lower case values for "name" and namespace" which is required to make valid docker references. This covers the case where a OCI filepath uses uppercase letters in its path.

pkg/image/builder/image_builder.go

  • make image builder handle single arch and multi arch images

Non-functional Changes

pkg/cli/mirror/mirror.go

  • removed redundant AsRespoitory() call since RepositoryName() already does this
  • use constant for olm_artifacts directory
  • operatorCatalogToFullArtifactPath

pkg/cli/options.go

  • use constant for workspace

all files

  • add documentation and change formatting for long function signatures
  • if any file used deprecated io/ioutil, replace with io or os package as necessary
  • update unit tests as necessary (the bulk of the files are related to new test cases)

Test Changes

internal/testutils/testutils.go

  • update and create new functions for creating single/multiarch images
  • created *WithURL function variants to allow pre-existing registry in tests because the defaults server won't allow external calls while debugging

pkg/image/builder/image_builder_test.go

  • update test cases for image builder

Fixes # (CFE-783)

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

  • Test With Docker (mirror to mirror)
  • Use a ImageSetConfiguration which points to a "fat manifest" catalog:
kind: ImageSetConfiguration
apiVersion: mirror.openshift.io/v1alpha2
storageConfig:
  local:
    path: /tmp/localstorage
mirror:
  operators:
  - catalog: icr.io/cpopen/ibm-zcon-zosconnect-catalog@sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76
  • Start a local docker registry to act as the destination
docker run -d -p 5000:5000 --name registry registry:2
  • Run oc mirror like this (no errors should occur):
oc mirror -c "/path/to/ImageSetConfiguration.yml" --dest-skip-tls --dest-use-http docker://localhost:5000
  • Throw away your local docker registry
docker stop registry
docker rm registry
  • Test With Docker (mirror to disk)
  • Use a ImageSetConfiguration which points to a "fat manifest" catalog:
kind: ImageSetConfiguration
apiVersion: mirror.openshift.io/v1alpha2
storageConfig:
  local:
    path: /tmp/localstorage
mirror:
  operators:
  - catalog: icr.io/cpopen/ibm-zcon-zosconnect-catalog@sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76
  • Run oc mirror like this (no errors should occur):
oc mirror -c "/path/to/ImageSetConfiguration.yml" file://tmp/mirrortodisktest
  • Test With OCI
  • Pull a docker "fat manifest" image into a location on the file system:
skopeo copy --all --format v2s2 docker://icr.io/cpopen/ibm-zcon-zosconnect-catalog@sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76 oci:///Users/jhunkins/temp/ocmirror
  • Use a ImageSetConfiguration which points to this newly downloaded image like this:
kind: ImageSetConfiguration
apiVersion: mirror.openshift.io/v1alpha2
storageConfig:
  local:
    path: /tmp/localstorage
mirror:
  operators:
  - catalog: oci:///Users/jhunkins/temp/ocmirror
  • Start a local docker registry to act as the destination
docker run -d -p 5000:5000 --name registry registry:2
  • Run oc mirror like this (no errors should occur):
oc mirror -c "/path/to/ImageSetConfiguration.yml" --use-oci-feature --oci-insecure-signature-policy --dest-skip-tls --dest-use-http docker://localhost:5000
  • Throw away your local docker registry
docker stop registry
docker rm registry

Test Configuration:

  • Firmware version:
  • Hardware:
  • Toolchain:
  • SDK:

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@openshift-ci-robot
Copy link

openshift-ci-robot commented Apr 22, 2023

@jchunkins: This pull request references CFE-783 which is a valid jira issue.

In response to this:

Description

This change brings support for processing multi and single architecture catalog images within oc mirror.

ociimage

To understand the changes in this PR, we need to discuss OCI layouts, which is a on disk representation of image references. The OCI layout specification shares similar concepts with the docker image v2s2 specification in that they both define manifests (i.e. a JSON document) that describe a single image or a list of images (i.e. a fat manifest). The primary difference between the two standards is the mediaType which indicates the standard being used (you can see the compatibility matrix for details). Essentially, OCI attempts to keep backwards compatibility with docker, and adds its own enhancements (e.g. annotations). These manifests can be pushed/pulled to/from a remote docker registry in either format, and can be converted from one type to another if desired. In the diagram above, you can see that manifest lists and image manifests are the entities that can be moved into and out of a OCI layout on a file system.

An OCI layout consists of an index.json file that acts as the entry point for discovering what images are stored within the layout on the disk. This index.json file can reference any number of single or multi architecture images, however oc mirror only references a single image at a time in a given OCI layout. The image stored in the OCI layout can be either a single architecture image (i.e. an image manifest) or a multi architecture image (i.e. a manifest list). A manifest list image is a logical grouping of an architecture specific image manifests stored in an array. This arrangement allows a single digest reference to represent all of the architecture specific images, and tools such as skopeo or podman can automatically pull an image that matches the platform that the tool is being executed on. An individual architecture specific image is referred to as an image manifest. A image manifest has references to a config JSON file that describes detailed layer history, the platform the image runs on and runtime information necessary to start an image. A image manifest, also has references to one or more layers, which are just tar files, which could be compressed or uncompressed. As you can see in the above diagram, all of these internal references are by digest, which is a hash computed by taking a sha256sum of the manifest or tar file. Note that the digest of the config file itself is referred to as the "image id" whereas an image digest is hash of the image manifest itself.

An example of a OCI layout on disk looks like this:

/path/to/oci/layout
├── blobs
│   └── sha256
│       ├── 01c6d5dcde3e9f2de758d794a77974600fe5e0b7a8c2ce2833eede2e8b25e7e5
│       └── ...
├── index.json
└── oci-layout

The index.json will have references to manifests and tar files that reside in the blobs/sha256 directory. Technically the index.json file is its own form of manifest list, but it is important to note that the index.json file itself has no representation in a docker registry. Tools such as skopeo will generate a OCI layout using what I call "manifest list indirection" where the manifest list resides in the blobs directory and the index.json references this manifest list by its digest. However some tools will set the media type of the index.json to indicate that its a manifest list and not use this "indirection" (i.e. the index.json directly refers to the image manifests and includes the platform information directly). This PR handles both of these scenarios, and ensures that the appropriate images are processed.

OCI layouts are stored in the oc mirror workspace under <oc-mirror-workspace>/src/catalogs/<repoPath>/layout. A diagram of this workspace looks like this:

  /tmp/cwd/oc-mirror-workspace
  ├── results-1675904745
  └── src
  	├── catalogs
  	│   └── icr.io                                                                              ─┐
  	│       └── cpopen                                                                           ├─ catalog path (one per catalog)
  	│           └── ibm-zcon-zosconnect-catalog                                                  │
  	│               └── sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76 ─┘
  	│                   ├── include-config.gob         <—— this represents v1alpha2.IncludeConfig for associated with index/index.json
  	│                   ├── index                      <—— this represents a decl config for "single architecture image" image
  	│                   │   │                              which was selected (note all images store the same content)
  	│                   │   └── index.json             <—— Declarative Config
  	│                   └── layout                     <—— OCI layout is capable of holding “manifest list” and “single architecture" images
  	│                       ├── blobs
  	│                       │   └── sha256
  	│                       │       ├── 01c6d5dcde3e9f2de758d794a77974600fe5e0b7a8c2ce2833eede2e8b25e7e5
  	│                       │       ├── 1cd0595314a53d179ddaf68761c9f40c4d9d1bcd3f692d1c005938dac2993db6
  	│                       │       ├── 1ff4ea896d6b958aa060e04eb090f70c563ad0650e6b362c1a1d67582acb3b8e
  	│                       │       ├── 25d123725cf91c20b497ca9dae8e0a6e8dedd8fe64f83757f3b41f6ac447eac0
  	│                       │       ├── 2d55550cefe39606cc933a2ed1d242b3fd9a72d85e92a2c6b52b9623a6f4fe6a
  	│                       │       ├── 34e12aa195bcd8366fbab95a242e8214ae959259bd0a1119c28d124f5799f502
  	│                       │       ├── 49a32e2e950732d5a638d5486968dcc3096f940a94811cfec99bd5a4f9e1ad49
  	│                       │       ├── 561bc8bee264b124ba5673e73ad36589abbecf0b15fb845ed9aab4e640989fbc
  	│                       │       ├── 6672e188b9c3f7274b7ebf4498b34f951bc20ea86a8d72367eab363f1722d2ed
  	│                       │       ├── 7062267a99d0149e4129843a9e3257b882920fb8554ec2068a264b37539768bc
  	│                       │       ├── ae475359a3fb8fe5e3dff0626f0c788b94340416eb5c453339abc884ac86b671
  	│                       │       ├── b2dd6105dc025aa5c5e8b75e0b2d8a390951369801d049fc0de2586917a42772
  	│                       │       ├── c03c8f94bb495320bbe862bc69349dbdf9f2a29b83d5b344b3930890aaf89d7d
  	│                       │       ├── dc1b9846d7994450e74b9cde2e621f8c1d98cdf1debd591db291785dd3fc6446
  	│                       │       └── f89d6e2463fc5fff8bba9e568ec28a6030076dbc412bd52dff6dbf2b5897a59d
  	│                       ├── index.json
  	│                       └── oci-layout
  	├── charts
  	├── publish
  	│   └── .metadata.json
  	├── release-signatures
  	└── v2

At a high level, this PR allows oc mirror traverse the OCI layout to pick an image for processing depending on what's stored in the layout:

  • for a single image manifest, we can use this image directly
  • for a manifest list, we choose the first image is the list

Once an image is chosen, the declarative config (i.e. the JSON/YAML files that represent the OLM catalog) is extracted from the image for processing. The existing code which performed this extraction was done incorrectly, and this PR addresses this issue. When an OCI image is the referenced in the ISC, and the --use-oci-feature is set, this declarative config is placed into <current working directory>/olm_artifacts/<repo>/<config folder> which acts as a temporary location to store the extracted data. After the catalog is processed, the content is written to <oc-mirror-workspace>/src/catalogs/<repoPath>/index, and then ALL image manifests that are stored within the OCI layout are updated with new layers that represent the updated catalog content. This is handled within the ImageBuilder, which has been modified to handle image updates for both single and multi arch images. Other changes within the PR relate to properly handling file paths and docker reference parsing.

Functional Changes

pkg/cli/mirror/fbc_operators.go

  • remove findFBCConfig & replace with extractDeclarativeConfigFromImage This is necessary because the layer processing did not handle whiteout files. Switched to go-containerregistry which handles this correctly.
  • modify getManifest so that it is fat manifest aware, and returns the first manifest in the list, or for single images, returns that manifest
  • Removed functions that are no longer necessary: GetCatalogConfigPath, getConfigPathFromConfigLayer, UntarLayers

pkg/cli/mirror/create.go

  • make createOlmArtifactsForOCI manifest list aware and discovers the first image in the list, or for single images, uses that image directly
  • calls replacement function extractDeclarativeConfigFromImage
  • stores full path to the artifact in a map so this path does not need to be recalculated later
  • strip protocol from ctlg.OCIFBCPath when constructing a layoutPath

pkg/cli/mirror/options.go

  • add operatorCatalogToFullArtifactPath map[string]string which stores temporary paths to declarative config directory
  • key: OCI URI (e.g. oci://foo which originates with v1alpha2.Operator.Catalog)
  • value: /olm_artifacts//

pkg/cli/mirror/operator.go

  • initialize operatorCatalogToFullArtifactPath
  • make use of operatorCatalogToFullArtifactPath map to obtain the full path to the olm_artifacts directory and its contents and remove getOperatorCatalogRef() since it is no longer necessary
  • make writeLayout() use the image config file to discover the platform when adding images, otherwise fall back to linux/amd64

pkg/image/image.go

  • replace getManifest with getFirstDigestFromPath which now gets the first digest for manifest lists, or the image digest for single image
  • change logging behavior in ParseReference() when path does not exist and invalidate the ID in that case.
  • in ParseReference, make sure that the docker reference uses lower case values for "name" and "namespace" which is required to make valid docker references. This covers the case where a OCI filepath uses uppercase letters in its path.

pkg/cli/mirror/catalog_images.go

  • in rebuildCatalogs, make sure that the catalog source docker reference uses lower case values for "name" and namespace" which is required to make valid docker references. This covers the case where a OCI filepath uses uppercase letters in its path.

pkg/image/builder/image_builder.go

  • make image builder handle single arch and multi arch images

Non-functional Changes

pkg/cli/mirror/mirror.go

  • removed redundant AsRespoitory() call since RepositoryName() already does this
  • use constant for olm_artifacts directory
  • operatorCatalogToFullArtifactPath

pkg/cli/options.go

  • use constant for workspace

all files

  • add documentation and change formatting for long function signatures
  • if any file used deprecated io/ioutil, replace with io or os package as necessary
  • update unit tests as necessary (the bulk of the files are related to new test cases)

Test Changes

internal/testutils/testutils.go

  • update and create new functions for creating single/multiarch images
  • created *WithURL function variants to allow pre-existing registry in tests because the defaults server won't allow external calls while debugging

pkg/image/builder/image_builder_test.go

  • update test cases for image builder

Fixes # (CFE-783)

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

  • Test With Docker (mirror to mirror)
  • Use a ImageSetConfiguration which points to a "fat manifest" catalog:
kind: ImageSetConfiguration
apiVersion: mirror.openshift.io/v1alpha2
storageConfig:
  local:
    path: /tmp/localstorage
mirror:
  operators:
  - catalog: icr.io/cpopen/ibm-zcon-zosconnect-catalog@sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76
  • Start a local docker registry to act as the destination
docker run -d -p 5000:5000 --name registry registry:2
  • Run oc mirror like this (no errors should occur):
oc mirror -c "/path/to/ImageSetConfiguration.yml" --dest-skip-tls --dest-use-http docker://localhost:5000
  • Throw away your local docker registry
docker stop registry
docker rm registry
  • Test With Docker (mirror to disk)
  • Use a ImageSetConfiguration which points to a "fat manifest" catalog:
kind: ImageSetConfiguration
apiVersion: mirror.openshift.io/v1alpha2
storageConfig:
  local:
    path: /tmp/localstorage
mirror:
  operators:
  - catalog: icr.io/cpopen/ibm-zcon-zosconnect-catalog@sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76
  • Run oc mirror like this (no errors should occur):
oc mirror -c "/path/to/ImageSetConfiguration.yml" file://tmp/mirrortodisktest
  • Test With OCI
  • Pull a docker "fat manifest" image into a location on the file system:
skopeo copy --all --format v2s2 docker://icr.io/cpopen/ibm-zcon-zosconnect-catalog@sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76 oci:///Users/jhunkins/temp/ocmirror
  • Use a ImageSetConfiguration which points to this newly downloaded image like this:
kind: ImageSetConfiguration
apiVersion: mirror.openshift.io/v1alpha2
storageConfig:
  local:
    path: /tmp/localstorage
mirror:
  operators:
  - catalog: oci:///Users/jhunkins/temp/ocmirror
  • Start a local docker registry to act as the destination
docker run -d -p 5000:5000 --name registry registry:2
  • Run oc mirror like this (no errors should occur):
oc mirror -c "/path/to/ImageSetConfiguration.yml" --use-oci-feature --oci-insecure-signature-policy --dest-skip-tls --dest-use-http docker://localhost:5000
  • Throw away your local docker registry
docker stop registry
docker rm registry

Test Configuration:

  • Firmware version:
  • Hardware:
  • Toolchain:
  • SDK:

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@openshift-ci-robot
Copy link

openshift-ci-robot commented Apr 22, 2023

@jchunkins: This pull request references CFE-783 which is a valid jira issue.

In response to this:

Description

This change brings support for processing multi and single architecture catalog images within oc mirror.

ociimage

To understand the changes in this PR, we need to discuss OCI layouts, which is a on disk representation of image references. The OCI layout specification shares similar concepts with the docker image v2s2 specification in that they both define manifests (i.e. a JSON document) that describe a single image or a list of images (i.e. a fat manifest). The primary difference between the two standards is the mediaType which indicates the standard being used (you can see the compatibility matrix for details). Essentially, OCI attempts to keep backwards compatibility with docker, and adds its own enhancements (e.g. annotations). These manifests can be pushed/pulled to/from a remote docker registry in either format, and can be converted from one type to another if desired. In the diagram above, you can see that manifest lists and image manifests are the entities that can be moved into and out of a OCI layout on a file system.

An OCI layout consists of an index.json file that acts as the entry point for discovering what images are stored within the layout on the disk. This index.json file can reference any number of single or multi architecture images, however oc mirror only references a single image at a time in a given OCI layout. The image stored in the OCI layout can be either a single architecture image (i.e. an image manifest) or a multi architecture image (i.e. a manifest list). A manifest list image is a logical grouping of an architecture specific image manifests stored in an array. This arrangement allows a single digest reference to represent all of the architecture specific images, and tools such as skopeo or podman can automatically pull an image that matches the platform that the tool is being executed on. An individual architecture specific image is referred to as an image manifest. A image manifest has references to a config JSON file that describes detailed layer history, the platform the image runs on and runtime information necessary to start an image. A image manifest, also has references to one or more layers, which are just tar files, which could be compressed or uncompressed. As you can see in the above diagram, all of these internal references are by digest, which is a hash computed by taking a sha256sum of the manifest or tar file. Note that the digest of the config file itself is referred to as the "image id" whereas an image digest is hash of the image manifest itself.

An example of a OCI layout on disk looks like this:

/path/to/oci/layout
├── blobs
│   └── sha256
│       ├── 01c6d5dcde3e9f2de758d794a77974600fe5e0b7a8c2ce2833eede2e8b25e7e5
│       └── ...
├── index.json
└── oci-layout

The index.json will have references to manifests and tar files that reside in the blobs/sha256 directory. Technically the index.json file is its own form of manifest list, but it is important to note that the index.json file itself has no representation in a docker registry. Tools such as skopeo will generate a OCI layout using what I call "manifest list indirection" where the manifest list resides in the blobs directory and the index.json references this manifest list by its digest. However some tools will set the media type of the index.json to indicate that its a manifest list and not use this "indirection" (i.e. the index.json directly refers to the image manifests and includes the platform information directly). This PR handles both of these scenarios, and ensures that the appropriate images are processed.

OCI layouts are stored in the oc mirror workspace under <oc-mirror-workspace>/src/catalogs/<repoPath>/layout. A diagram of this workspace looks like this:

  /tmp/cwd/oc-mirror-workspace
  ├── results-1675904745
  └── src
  	├── catalogs
  	│   └── icr.io                                                                              ─┐
  	│       └── cpopen                                                                           ├─ catalog path (one per catalog)
  	│           └── ibm-zcon-zosconnect-catalog                                                  │
  	│               └── sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76 ─┘
  	│                   ├── include-config.gob         <—— this represents v1alpha2.IncludeConfig for associated with index/index.json
  	│                   ├── index                      <—— this represents a decl config for "single architecture image" image
  	│                   │   │                              which was selected (note all images store the same content)
  	│                   │   └── index.json             <—— Declarative Config
  	│                   └── layout                     <—— OCI layout is capable of holding “manifest list” and “single architecture" images
  	│                       ├── blobs
  	│                       │   └── sha256
  	│                       │       ├── 01c6d5dcde3e9f2de758d794a77974600fe5e0b7a8c2ce2833eede2e8b25e7e5
  	│                       │       ├── 1cd0595314a53d179ddaf68761c9f40c4d9d1bcd3f692d1c005938dac2993db6
  	│                       │       ├── 1ff4ea896d6b958aa060e04eb090f70c563ad0650e6b362c1a1d67582acb3b8e
  	│                       │       ├── 25d123725cf91c20b497ca9dae8e0a6e8dedd8fe64f83757f3b41f6ac447eac0
  	│                       │       ├── 2d55550cefe39606cc933a2ed1d242b3fd9a72d85e92a2c6b52b9623a6f4fe6a
  	│                       │       ├── 34e12aa195bcd8366fbab95a242e8214ae959259bd0a1119c28d124f5799f502
  	│                       │       ├── 49a32e2e950732d5a638d5486968dcc3096f940a94811cfec99bd5a4f9e1ad49
  	│                       │       ├── 561bc8bee264b124ba5673e73ad36589abbecf0b15fb845ed9aab4e640989fbc
  	│                       │       ├── 6672e188b9c3f7274b7ebf4498b34f951bc20ea86a8d72367eab363f1722d2ed
  	│                       │       ├── 7062267a99d0149e4129843a9e3257b882920fb8554ec2068a264b37539768bc
  	│                       │       ├── ae475359a3fb8fe5e3dff0626f0c788b94340416eb5c453339abc884ac86b671
  	│                       │       ├── b2dd6105dc025aa5c5e8b75e0b2d8a390951369801d049fc0de2586917a42772
  	│                       │       ├── c03c8f94bb495320bbe862bc69349dbdf9f2a29b83d5b344b3930890aaf89d7d
  	│                       │       ├── dc1b9846d7994450e74b9cde2e621f8c1d98cdf1debd591db291785dd3fc6446
  	│                       │       └── f89d6e2463fc5fff8bba9e568ec28a6030076dbc412bd52dff6dbf2b5897a59d
  	│                       ├── index.json
  	│                       └── oci-layout
  	├── charts
  	├── publish
  	│   └── .metadata.json
  	├── release-signatures
  	└── v2

At a high level, this PR allows oc mirror traverse the OCI layout to pick an image for processing depending on what's stored in the layout:

  • for a single image manifest, we can use this image directly
  • for a manifest list, we choose the first image is the list. We can do this because the catalog content is identical in all images.

Once an image is chosen, the declarative config (i.e. the JSON/YAML files that represent the OLM catalog) is extracted from the image for processing. The existing code which performed this extraction was done incorrectly, and this PR addresses this issue. When an OCI image is referenced in the ImageSetConfiguration, and the --use-oci-feature is set, this declarative config is placed into <current working directory>/olm_artifacts/<repo>/<config folder> which acts as a temporary location to store the extracted data. After the catalog is processed, the content is written to <oc-mirror-workspace>/src/catalogs/<repoPath>/index. This catalog content is then added to ALL image manifests that are stored within the OCI layout by adding new layers that represent the updated catalog content. This is handled within the ImageBuilder, which has been modified to handle image updates for both single and multi arch images. Other changes within the PR relate to properly handling file paths and docker reference parsing.

Also, to be clear, additional images defined in the ImageSetConfiguration, and related images found within the catalog itself are already capable of mirroring single and multi platform images already because the "oc image mirror" codebase knows how to do this already. This PR is primarily focused on making catalog image handling multi architecture "aware".

User Stories

  • As a user I want to perform a "mirror to mirror" operation using manifest list and single image docker references in the operators portion of the ImageSetConfiguration
  • As a user I want to perform a "mirror to disk" operation using manifest list and single image docker references in the operators portion of the ImageSetConfiguration
  • As a user I want to perform a "oci layout to mirror" operation using an oci reference in the operator portion of the ImageSetConfiguration. The content of the OCI layout can contain either a manifest list or a single image manifest

Acceptance Criteria

  • All mirror operations following the user stories should complete successfully, resulting in the catalog being pushed to its remote repository along with any related images or additional images (if any are supplied in the ImageSetConfiguration).

Functional Changes

pkg/cli/mirror/fbc_operators.go

  • remove findFBCConfig & replace with extractDeclarativeConfigFromImage This is necessary because the layer processing did not handle whiteout files. Switched to go-containerregistry which handles this correctly.
  • modify getManifest so that it is fat manifest aware, and returns the first manifest in the list, or for single images, returns that manifest
  • Removed functions that are no longer necessary: GetCatalogConfigPath, getConfigPathFromConfigLayer, UntarLayers

pkg/cli/mirror/create.go

  • make createOlmArtifactsForOCI manifest list aware and discovers the first image in the list, or for single images, uses that image directly
  • calls replacement function extractDeclarativeConfigFromImage
  • stores full path to the artifact in a map so this path does not need to be recalculated later
  • strip protocol from ctlg.OCIFBCPath when constructing a layoutPath

pkg/cli/mirror/options.go

  • add operatorCatalogToFullArtifactPath map[string]string which stores temporary paths to declarative config directory
  • key: OCI URI (e.g. oci://foo which originates with v1alpha2.Operator.Catalog)
  • value: /olm_artifacts//

pkg/cli/mirror/operator.go

  • initialize operatorCatalogToFullArtifactPath
  • make use of operatorCatalogToFullArtifactPath map to obtain the full path to the olm_artifacts directory and its contents and remove getOperatorCatalogRef() since it is no longer necessary
  • make writeLayout() use the image config file to discover the platform when adding images, otherwise fall back to linux/amd64

pkg/image/image.go

  • replace getManifest with getFirstDigestFromPath which now gets the first digest for manifest lists, or the image digest for single image
  • change logging behavior in ParseReference() when path does not exist and invalidate the ID in that case.
  • in ParseReference, make sure that the docker reference uses lower case values for "name" and "namespace" which is required to make valid docker references. This covers the case where a OCI filepath uses uppercase letters in its path.

pkg/cli/mirror/catalog_images.go

  • in rebuildCatalogs, make sure that the catalog source docker reference uses lower case values for "name" and namespace" which is required to make valid docker references. This covers the case where a OCI filepath uses uppercase letters in its path.

pkg/image/builder/image_builder.go

  • make image builder handle single arch and multi arch images

Non-functional Changes

pkg/cli/mirror/mirror.go

  • removed redundant AsRespoitory() call since RepositoryName() already does this
  • use constant for olm_artifacts directory
  • operatorCatalogToFullArtifactPath

pkg/cli/options.go

  • use constant for workspace

all files

  • add documentation and change formatting for long function signatures
  • if any file used deprecated io/ioutil, replace with io or os package as necessary
  • update unit tests as necessary (the bulk of the files are related to new test cases)

Test Changes

internal/testutils/testutils.go

  • update and create new functions for creating single/multiarch images
  • created *WithURL function variants to allow pre-existing registry in tests because the defaults server won't allow external calls while debugging

pkg/image/builder/image_builder_test.go

  • update test cases for image builder

Fixes # (CFE-783)

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

  • Test With Docker (mirror to mirror)
  • Use a ImageSetConfiguration which points to a "fat manifest" catalog:
kind: ImageSetConfiguration
apiVersion: mirror.openshift.io/v1alpha2
storageConfig:
  local:
    path: /tmp/localstorage
mirror:
  operators:
  - catalog: icr.io/cpopen/ibm-zcon-zosconnect-catalog@sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76
  • Start a local docker registry to act as the destination
docker run -d -p 5000:5000 --name registry registry:2
  • Run oc mirror like this (no errors should occur):
oc mirror -c "/path/to/ImageSetConfiguration.yml" --dest-skip-tls --dest-use-http docker://localhost:5000
  • Throw away your local docker registry
docker stop registry
docker rm registry
  • Test With Docker (mirror to disk)
  • Use a ImageSetConfiguration which points to a "fat manifest" catalog:
kind: ImageSetConfiguration
apiVersion: mirror.openshift.io/v1alpha2
storageConfig:
  local:
    path: /tmp/localstorage
mirror:
  operators:
  - catalog: icr.io/cpopen/ibm-zcon-zosconnect-catalog@sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76
  • Run oc mirror like this (no errors should occur):
oc mirror -c "/path/to/ImageSetConfiguration.yml" file://tmp/mirrortodisktest
  • Test With OCI
  • Pull a docker "fat manifest" image into a location on the file system:
skopeo copy --all --format v2s2 docker://icr.io/cpopen/ibm-zcon-zosconnect-catalog@sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76 oci:///Users/jhunkins/temp/ocmirror
  • Use a ImageSetConfiguration which points to this newly downloaded image like this:
kind: ImageSetConfiguration
apiVersion: mirror.openshift.io/v1alpha2
storageConfig:
  local:
    path: /tmp/localstorage
mirror:
  operators:
  - catalog: oci:///Users/jhunkins/temp/ocmirror
  • Start a local docker registry to act as the destination
docker run -d -p 5000:5000 --name registry registry:2
  • Run oc mirror like this (no errors should occur):
oc mirror -c "/path/to/ImageSetConfiguration.yml" --use-oci-feature --oci-insecure-signature-policy --dest-skip-tls --dest-use-http docker://localhost:5000
  • Throw away your local docker registry
docker stop registry
docker rm registry

Test Configuration:

  • Firmware version:
  • Hardware:
  • Toolchain:
  • SDK:

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@openshift-ci-robot
Copy link

openshift-ci-robot commented Apr 24, 2023

@jchunkins: This pull request references CFE-783 which is a valid jira issue.

In response to this:

Description

This change brings support for processing multi and single architecture catalog images within oc mirror.

TL;DR: The first item in the manifest list has its FBC catalog extracted, which is then processed as needed and then “reinserted” (i.e. added as a new layer) into each image referenced in the manifest list. In other words, the images are modified with the same updated FBC content. The binaries within each architecture catalog are unmodified.

ociimage

To understand the changes in this PR, we need to discuss OCI layouts, which is a on disk representation of image references. The OCI layout specification shares similar concepts with the docker image v2s2 specification in that they both define manifests (i.e. a JSON document) that describe a single image or a list of images (i.e. a fat manifest). The primary difference between the two standards is the mediaType which indicates the standard being used (you can see the compatibility matrix for details). Essentially, OCI attempts to keep backwards compatibility with docker, and adds its own enhancements (e.g. annotations). These manifests can be pushed/pulled to/from a remote docker registry in either format, and can be converted from one type to another if desired. In the diagram above, you can see that manifest lists and image manifests are the entities that can be moved into and out of a OCI layout on a file system.

An OCI layout consists of an index.json file that acts as the entry point for discovering what images are stored within the layout on the disk. This index.json file can reference any number of single or multi architecture images, however oc mirror only references a single image at a time in a given OCI layout. The image stored in the OCI layout can be either a single architecture image (i.e. an image manifest) or a multi architecture image (i.e. a manifest list). A manifest list image is a logical grouping of an architecture specific image manifests stored in an array. This arrangement allows a single digest reference to represent all of the architecture specific images, and tools such as skopeo or podman can automatically pull an image that matches the platform that the tool is being executed on. An individual architecture specific image is referred to as an image manifest. A image manifest has references to a config JSON file that describes detailed layer history, the platform the image runs on and runtime information necessary to start an image. A image manifest, also has references to one or more layers, which are just tar files, which could be compressed or uncompressed. As you can see in the above diagram, all of these internal references are by digest, which is a hash computed by taking a sha256sum of the manifest or tar file. Note that the digest of the config file itself is referred to as the "image id" whereas an image digest is hash of the image manifest itself.

An example of a OCI layout on disk looks like this:

/path/to/oci/layout
├── blobs
│   └── sha256
│       ├── 01c6d5dcde3e9f2de758d794a77974600fe5e0b7a8c2ce2833eede2e8b25e7e5
│       └── ...
├── index.json
└── oci-layout

The index.json will have references to manifests and tar files that reside in the blobs/sha256 directory. Technically the index.json file is its own form of manifest list, but it is important to note that the index.json file itself has no representation in a docker registry. Tools such as skopeo will generate a OCI layout using what I call "manifest list indirection" where the manifest list resides in the blobs directory and the index.json references this manifest list by its digest. However some tools will set the media type of the index.json to indicate that its a manifest list and not use this "indirection" (i.e. the index.json directly refers to the image manifests and includes the platform information directly). This PR handles both of these scenarios, and ensures that the appropriate images are processed.

OCI layouts are stored in the oc mirror workspace under <oc-mirror-workspace>/src/catalogs/<repoPath>/layout. A diagram of this workspace looks like this:

  /tmp/cwd/oc-mirror-workspace
  ├── results-1675904745
  └── src
  	├── catalogs
  	│   └── icr.io                                                                              ─┐
  	│       └── cpopen                                                                           ├─ catalog path (one per catalog)
  	│           └── ibm-zcon-zosconnect-catalog                                                  │
  	│               └── sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76 ─┘
  	│                   ├── include-config.gob         <—— this represents v1alpha2.IncludeConfig for associated with index/index.json
  	│                   ├── index                      <—— this represents a decl config for "single architecture image" image
  	│                   │   │                              which was selected (note all images store the same content)
  	│                   │   └── index.json             <—— Declarative Config
  	│                   └── layout                     <—— OCI layout is capable of holding “manifest list” and “single architecture" images
  	│                       ├── blobs
  	│                       │   └── sha256
  	│                       │       ├── 01c6d5dcde3e9f2de758d794a77974600fe5e0b7a8c2ce2833eede2e8b25e7e5
  	│                       │       ├── 1cd0595314a53d179ddaf68761c9f40c4d9d1bcd3f692d1c005938dac2993db6
  	│                       │       ├── 1ff4ea896d6b958aa060e04eb090f70c563ad0650e6b362c1a1d67582acb3b8e
  	│                       │       ├── 25d123725cf91c20b497ca9dae8e0a6e8dedd8fe64f83757f3b41f6ac447eac0
  	│                       │       ├── 2d55550cefe39606cc933a2ed1d242b3fd9a72d85e92a2c6b52b9623a6f4fe6a
  	│                       │       ├── 34e12aa195bcd8366fbab95a242e8214ae959259bd0a1119c28d124f5799f502
  	│                       │       ├── 49a32e2e950732d5a638d5486968dcc3096f940a94811cfec99bd5a4f9e1ad49
  	│                       │       ├── 561bc8bee264b124ba5673e73ad36589abbecf0b15fb845ed9aab4e640989fbc
  	│                       │       ├── 6672e188b9c3f7274b7ebf4498b34f951bc20ea86a8d72367eab363f1722d2ed
  	│                       │       ├── 7062267a99d0149e4129843a9e3257b882920fb8554ec2068a264b37539768bc
  	│                       │       ├── ae475359a3fb8fe5e3dff0626f0c788b94340416eb5c453339abc884ac86b671
  	│                       │       ├── b2dd6105dc025aa5c5e8b75e0b2d8a390951369801d049fc0de2586917a42772
  	│                       │       ├── c03c8f94bb495320bbe862bc69349dbdf9f2a29b83d5b344b3930890aaf89d7d
  	│                       │       ├── dc1b9846d7994450e74b9cde2e621f8c1d98cdf1debd591db291785dd3fc6446
  	│                       │       └── f89d6e2463fc5fff8bba9e568ec28a6030076dbc412bd52dff6dbf2b5897a59d
  	│                       ├── index.json
  	│                       └── oci-layout
  	├── charts
  	├── publish
  	│   └── .metadata.json
  	├── release-signatures
  	└── v2

At a high level, this PR allows oc mirror traverse the OCI layout to pick an image for processing depending on what's stored in the layout:

  • for a single image manifest, we can use this image directly
  • for a manifest list, we choose the first image is the list. We can do this because the catalog content is identical in all images.

Once an image is chosen, the declarative config (i.e. the JSON/YAML files that represent the OLM catalog) is extracted from the image for processing. The existing code which performed this extraction was done incorrectly, and this PR addresses this issue. When an OCI image is referenced in the ImageSetConfiguration, and the --use-oci-feature is set, this declarative config is placed into <current working directory>/olm_artifacts/<repo>/<config folder> which acts as a temporary location to store the extracted data. After the catalog is processed, the content is written to <oc-mirror-workspace>/src/catalogs/<repoPath>/index. This catalog content is then added to ALL image manifests that are stored within the OCI layout by adding new layers that represent the updated catalog content. This is handled within the ImageBuilder, which has been modified to handle image updates for both single and multi arch images. Other changes within the PR relate to properly handling file paths and docker reference parsing.

Also, to be clear, additional images defined in the ImageSetConfiguration, and related images found within the catalog itself are already capable of mirroring single and multi platform images already because the "oc image mirror" codebase knows how to do this already. This PR is primarily focused on making catalog image handling multi architecture "aware".

User Stories

  • As a user I want to perform a "mirror to mirror" operation using manifest list and single image docker references in the operators portion of the ImageSetConfiguration
  • As a user I want to perform a "mirror to disk" operation using manifest list and single image docker references in the operators portion of the ImageSetConfiguration
  • As a user I want to perform a "oci layout to mirror" operation using an oci reference in the operator portion of the ImageSetConfiguration. The content of the OCI layout can contain either a manifest list or a single image manifest

Acceptance Criteria

  • All mirror operations following the user stories should complete successfully, resulting in the catalog being pushed to its remote repository along with any related images or additional images (if any are supplied in the ImageSetConfiguration).

Functional Changes

pkg/cli/mirror/fbc_operators.go

  • remove findFBCConfig & replace with extractDeclarativeConfigFromImage This is necessary because the layer processing did not handle whiteout files. Switched to go-containerregistry which handles this correctly.
  • modify getManifest so that it is fat manifest aware, and returns the first manifest in the list, or for single images, returns that manifest
  • Removed functions that are no longer necessary: GetCatalogConfigPath, getConfigPathFromConfigLayer, UntarLayers

pkg/cli/mirror/create.go

  • make createOlmArtifactsForOCI manifest list aware and discovers the first image in the list, or for single images, uses that image directly
  • calls replacement function extractDeclarativeConfigFromImage
  • stores full path to the artifact in a map so this path does not need to be recalculated later
  • strip protocol from ctlg.OCIFBCPath when constructing a layoutPath

pkg/cli/mirror/options.go

  • add operatorCatalogToFullArtifactPath map[string]string which stores temporary paths to declarative config directory
  • key: OCI URI (e.g. oci://foo which originates with v1alpha2.Operator.Catalog)
  • value: /olm_artifacts//

pkg/cli/mirror/operator.go

  • initialize operatorCatalogToFullArtifactPath
  • make use of operatorCatalogToFullArtifactPath map to obtain the full path to the olm_artifacts directory and its contents and remove getOperatorCatalogRef() since it is no longer necessary
  • make writeLayout() use the image config file to discover the platform when adding images, otherwise fall back to linux/amd64

pkg/image/image.go

  • replace getManifest with getFirstDigestFromPath which now gets the first digest for manifest lists, or the image digest for single image
  • change logging behavior in ParseReference() when path does not exist and invalidate the ID in that case.
  • in ParseReference, make sure that the docker reference uses lower case values for "name" and "namespace" which is required to make valid docker references. This covers the case where a OCI filepath uses uppercase letters in its path.

pkg/cli/mirror/catalog_images.go

  • in rebuildCatalogs, make sure that the catalog source docker reference uses lower case values for "name" and namespace" which is required to make valid docker references. This covers the case where a OCI filepath uses uppercase letters in its path.

pkg/image/builder/image_builder.go

  • make image builder handle single arch and multi arch images

Non-functional Changes

pkg/cli/mirror/mirror.go

  • removed redundant AsRespoitory() call since RepositoryName() already does this
  • use constant for olm_artifacts directory
  • operatorCatalogToFullArtifactPath

pkg/cli/options.go

  • use constant for workspace

all files

  • add documentation and change formatting for long function signatures
  • if any file used deprecated io/ioutil, replace with io or os package as necessary
  • update unit tests as necessary (the bulk of the files are related to new test cases)

Test Changes

internal/testutils/testutils.go

  • update and create new functions for creating single/multiarch images
  • created *WithURL function variants to allow pre-existing registry in tests because the defaults server won't allow external calls while debugging

pkg/image/builder/image_builder_test.go

  • update test cases for image builder

Fixes # (CFE-783)

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

  • Test With Docker (mirror to mirror)
  • Use a ImageSetConfiguration which points to a "fat manifest" catalog:
kind: ImageSetConfiguration
apiVersion: mirror.openshift.io/v1alpha2
storageConfig:
  local:
    path: /tmp/localstorage
mirror:
  operators:
  - catalog: icr.io/cpopen/ibm-zcon-zosconnect-catalog@sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76
  • Start a local docker registry to act as the destination
docker run -d -p 5000:5000 --name registry registry:2
  • Run oc mirror like this (no errors should occur):
oc mirror -c "/path/to/ImageSetConfiguration.yml" --dest-skip-tls --dest-use-http docker://localhost:5000
  • Throw away your local docker registry
docker stop registry
docker rm registry
  • Test With Docker (mirror to disk)
  • Use a ImageSetConfiguration which points to a "fat manifest" catalog:
kind: ImageSetConfiguration
apiVersion: mirror.openshift.io/v1alpha2
storageConfig:
  local:
    path: /tmp/localstorage
mirror:
  operators:
  - catalog: icr.io/cpopen/ibm-zcon-zosconnect-catalog@sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76
  • Run oc mirror like this (no errors should occur):
oc mirror -c "/path/to/ImageSetConfiguration.yml" file://tmp/mirrortodisktest
  • Test With OCI
  • Pull a docker "fat manifest" image into a location on the file system:
skopeo copy --all --format v2s2 docker://icr.io/cpopen/ibm-zcon-zosconnect-catalog@sha256:6f02ecef46020bcd21bdd24a01f435023d5fc3943972ef0d9769d5276e178e76 oci:///Users/jhunkins/temp/ocmirror
  • Use a ImageSetConfiguration which points to this newly downloaded image like this:
kind: ImageSetConfiguration
apiVersion: mirror.openshift.io/v1alpha2
storageConfig:
  local:
    path: /tmp/localstorage
mirror:
  operators:
  - catalog: oci:///Users/jhunkins/temp/ocmirror
  • Start a local docker registry to act as the destination
docker run -d -p 5000:5000 --name registry registry:2
  • Run oc mirror like this (no errors should occur):
oc mirror -c "/path/to/ImageSetConfiguration.yml" --use-oci-feature --oci-insecure-signature-policy --dest-skip-tls --dest-use-http docker://localhost:5000
  • Throw away your local docker registry
docker stop registry
docker rm registry

Test Configuration:

  • Firmware version:
  • Hardware:
  • Toolchain:
  • SDK:

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@openshift-merge-robot openshift-merge-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Apr 25, 2023
Copy link
Contributor

@sherine-k sherine-k left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi John,
Thank you for an overall great job explaining and commenting on the code to make this improvement easy.
I have one question overall, and moving on to some testing. @zhouying7780 will also be helping us out

pkg/image/image.go Outdated Show resolved Hide resolved
pkg/image/image.go Outdated Show resolved Hide resolved
@jchunkins jchunkins force-pushed the CFE-760-manifest-list-minimal branch from 8059d85 to d22ba27 Compare April 27, 2023 20:29
@openshift-merge-robot openshift-merge-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Apr 27, 2023
@sherine-k
Copy link
Contributor

/retest

Functional Changes

pkg/cli/mirror/fbc_operators.go

- remove findFBCConfig & replace with extractDeclarativeConfigFromImage
This is necessary because the layer processing did not handle whiteout
files. Switched to go-containerregistry which handles this correctly.
- modify getManifest so that it is fat manifest aware, and returns the
first manifest in the list, or for single images, returns that manifest
- Removed functions that are no longer necessary:
GetCatalogConfigPath, getConfigPathFromConfigLayer, UntarLayers

pkg/cli/mirror/create.go

- make createOlmArtifactsForOCI manifest list aware and discovers the
first image in the list, or for single images, uses that image directly
- calls replacement function extractDeclarativeConfigFromImage
- stores full path to the artifact in a map so this path does not need
to be recalculated later

pkg/cli/mirror/operator.go

- make use of operatorCatalogToFullArtifactPath map to obtain the full
path to the olm_artifacts directory and its contents and remove
getOperatorCatalogRef() since it is no longer necessary
- make writeLayout() use the image config file to discover the platform
when adding images, otherwise fall back to linux/amd64

pkg/cli/mirror/options.go

- add operatorCatalogToFullArtifactPath map[string]string

pkg/image/image.go

- replace getManifest with getFirstDigestFromPath which now gets the
first digest for manifest lists, or the image digest for single image
- change logging behavior in ParseReference() when path does not exist
and invalidate the ID in that case.

Non-functional Changes

pkg/cli/mirror/mirror.go

- removed redundant AsRespoitory() call since RepositoryName() already
does this
- use constant for olm_artifacts directory

pkg/cli/options.go

- use constant for workspace

all files
- add documentation and change formatting for long function signatures
- if any file used deprecated io/ioutil, replace with io or os package
as necessary
- update unit tests as necessary (the bulk of the files are related to
new test cases)
- The original PR had concerns about using latest tag, so did not bring
this change over, therefore this test case had to be reverted too.
This commit brings over the remaining changes needed for correct
manifest list handling.

internal/testutils/testutils.go

- update and create new functions for creating single/multiarch images
- created *WithURL function variants to allow pre-existing registry in
tests because the defaults server won't allow external calls while
debugging

pkg/cli/mirror/catalog_images.go

- in rebuildCatalogs, make sure that the catalog source docker
reference uses lower case values for "name" and "namespace" which
is required to make valid docker references. This covers the case where
a OCI filepath uses uppercase letters in its path.

pkg/cli/mirror/create.go

- add missing call to strip protocol from ctlg.OCIFBCPath when
constructing a layoutPath

pkg/cli/mirror/mirror.go

- add missing initialization of operatorCatalogToFullArtifactPath

pkg/image/image.go

- in ParseReference, make sure that the docker reference uses lower case
values for "name" and "namespace" which is required to make valid docker
references. This covers the case where a OCI filepath uses uppercase
letters in its path.

pkg/image/builder/image_builder.go

- make image builder handle single arch and multi arch images

pkg/image/builder/image_builder_test.go

- update test cases for image builder

update go modules and vendoring
- make function return error when number of manifests > 1
- do basic checks to ensure digest is valid before returning
- return image digest instead of config hash
- adjust documentation
When copying the OCI layout, make sure we only copy files/folders that
are part of the OCI layout specification.

The bug resulted because the copy destination was inside the
source directory, which lead to an infinite circular copy operation when
using the github.com/otiai10/copy package. This fix avoids this
because it copies only the OCI layout files/folders and ignores others.
- based on review, make inner function processImageIndex into a method
of ImageBuilder
- add/update documentation
@jchunkins jchunkins force-pushed the CFE-760-manifest-list-minimal branch from fee0a75 to 269e67c Compare June 5, 2023 21:12
@jchunkins
Copy link
Contributor Author

@sherine-k I performed another rebase from main to make sure everything is in sync, and then did a line by line comparison of the files in jchunkins:CFE-760-manifest-list-minimal against the backup of the branch before the rebase happened, and as far as I can see everything is accounted for. Specifically the validateMapping function in this PR is using getImageList.

Please let me know if there was something else that does not seem correct.

@sherine-k
Copy link
Contributor

/lgtm
Thanks @jchunkins !

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Jun 6, 2023
@sherine-k
Copy link
Contributor

/payload 4.14 nightly informing

@openshift-ci
Copy link

openshift-ci bot commented Jun 6, 2023

@sherine-k: trigger 55 job(s) of type informing for the nightly release of OCP 4.14

  • periodic-ci-openshift-release-master-nightly-4.14-e2e-alibaba-ovn
  • periodic-ci-openshift-release-master-nightly-4.14-console-aws
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-aws-csi
  • periodic-ci-openshift-release-master-ci-4.14-e2e-aws-ovn
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-aws-ovn-fips
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-aws-ovn-single-node
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-aws-ovn-single-node-serial
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-aws-sdn
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-aws-sdn-cgroupsv2
  • periodic-ci-openshift-release-master-ci-4.14-e2e-aws-sdn-techpreview
  • periodic-ci-openshift-release-master-ci-4.14-e2e-aws-sdn-techpreview-serial
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-aws-ovn-upi
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-azure-csi
  • periodic-ci-openshift-release-master-ci-4.14-e2e-azure-ovn
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-azure-sdn
  • periodic-ci-openshift-release-master-ci-4.14-e2e-azure-sdn-techpreview
  • periodic-ci-openshift-release-master-ci-4.14-e2e-azure-sdn-techpreview-serial
  • periodic-ci-openshift-release-master-ci-4.14-e2e-azure-sdn-upgrade
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-azure-deploy-cnv
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-azure-upgrade-cnv
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-aws-driver-toolkit
  • periodic-ci-openshift-release-master-ci-4.14-e2e-gcp-ovn
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-gcp-ovn-csi
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-gcp-ovn-rt
  • periodic-ci-openshift-release-master-ci-4.14-upgrade-from-stable-4.13-e2e-gcp-ovn-upgrade
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-gcp-sdn
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-gcp-sdn-serial
  • periodic-ci-openshift-release-master-ci-4.14-e2e-gcp-sdn-techpreview
  • periodic-ci-openshift-release-master-ci-4.14-e2e-gcp-sdn-techpreview-serial
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-gcp-sdn-upgrade
  • periodic-ci-openshift-release-master-ci-4.14-upgrade-from-stable-4.13-e2e-gcp-sdn-upgrade
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-metal-ipi-ovn-dualstack
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-metal-ipi-sdn-bm-upgrade
  • periodic-ci-openshift-release-master-nightly-4.14-upgrade-from-stable-4.13-e2e-metal-ipi-sdn-bm-upgrade
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-metal-ipi-sdn-serial-ipv4
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-metal-ipi-sdn-serial-virtualmedia-bond
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-metal-ipi-serial-ovn-ipv6
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-metal-ipi-serial-ovn-dualstack
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-metal-ipi-upgrade-ovn-ipv6
  • periodic-ci-openshift-release-master-nightly-4.14-upgrade-from-stable-4.13-e2e-metal-ipi-upgrade-ovn-ipv6
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-metal-ovn-assisted
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-ovirt-csi
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-ovirt-sdn
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-aws-ovn-proxy
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-metal-ovn-single-node-live-iso
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-aws-sdn-upgrade
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-telco5g
  • periodic-ci-openshift-release-master-nightly-4.14-upgrade-from-stable-4.13-e2e-aws-sdn-upgrade
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-vsphere-ovn-csi
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-vsphere-ovn-serial
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-vsphere-ovn-techpreview
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-vsphere-ovn-techpreview-serial
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-vsphere-ovn-upi
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-vsphere-ovn-upi-serial
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-vsphere-sdn

See details on https://pr-payload-tests.ci.openshift.org/runs/ci/f6cb7370-0474-11ee-999e-3debd10eddbe-0

@dgoodwin
Copy link

dgoodwin commented Jun 8, 2023

/payload 4.14 nightly blocking

In general blocking is probably the better signal for pre-merge testing. (expensive, but worth if it we're worried this might cause regressions)

Hoping to return to this in one of the next batches.

@openshift-ci
Copy link

openshift-ci bot commented Jun 8, 2023

@dgoodwin: trigger 7 job(s) of type blocking for the nightly release of OCP 4.14

  • periodic-ci-openshift-release-master-nightly-4.14-e2e-aws-sdn-upgrade
  • periodic-ci-openshift-release-master-ci-4.14-e2e-azure-ovn-upgrade
  • periodic-ci-openshift-release-master-ci-4.14-upgrade-from-stable-4.13-e2e-gcp-ovn-rt-upgrade
  • periodic-ci-openshift-release-master-ci-4.14-e2e-aws-ovn-upgrade
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-aws-sdn-serial
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-metal-ipi-ovn-ipv6
  • periodic-ci-openshift-release-master-nightly-4.14-e2e-metal-ipi-sdn-bm

See details on https://pr-payload-tests.ci.openshift.org/runs/ci/c4047590-05ff-11ee-970a-891597cb4abb-0

@sherine-k
Copy link
Contributor

Hi @dgoodwin
Those fails are almost positively not related to this PR, especially since the failing tests don't use oc-mirror at all.
Should we rerun them?
Should we re-ask for the merge after they pass?
Or is this all covered by the queue process in another way?

@deepsm007
Copy link

/label jira/valid-bug

@openshift-ci openshift-ci bot added the jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. label Jun 12, 2023
@openshift-ci
Copy link

openshift-ci bot commented Jun 12, 2023

@jchunkins: all tests passed!

Full PR test history. Your PR dashboard.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here.

@openshift-merge-robot openshift-merge-robot merged commit 2445f2c into openshift:main Jun 12, 2023
5 checks passed
lmzuccarelli pushed a commit to lmzuccarelli/oc-mirror that referenced this pull request Jun 29, 2023
… architecture catalogs (openshift#611)

* A variety of changes needed for correct operation

Functional Changes

pkg/cli/mirror/fbc_operators.go

- remove findFBCConfig & replace with extractDeclarativeConfigFromImage
This is necessary because the layer processing did not handle whiteout
files. Switched to go-containerregistry which handles this correctly.
- modify getManifest so that it is fat manifest aware, and returns the
first manifest in the list, or for single images, returns that manifest
- Removed functions that are no longer necessary:
GetCatalogConfigPath, getConfigPathFromConfigLayer, UntarLayers

pkg/cli/mirror/create.go

- make createOlmArtifactsForOCI manifest list aware and discovers the
first image in the list, or for single images, uses that image directly
- calls replacement function extractDeclarativeConfigFromImage
- stores full path to the artifact in a map so this path does not need
to be recalculated later

pkg/cli/mirror/operator.go

- make use of operatorCatalogToFullArtifactPath map to obtain the full
path to the olm_artifacts directory and its contents and remove
getOperatorCatalogRef() since it is no longer necessary
- make writeLayout() use the image config file to discover the platform
when adding images, otherwise fall back to linux/amd64

pkg/cli/mirror/options.go

- add operatorCatalogToFullArtifactPath map[string]string

pkg/image/image.go

- replace getManifest with getFirstDigestFromPath which now gets the
first digest for manifest lists, or the image digest for single image
- change logging behavior in ParseReference() when path does not exist
and invalidate the ID in that case.

Non-functional Changes

pkg/cli/mirror/mirror.go

- removed redundant AsRespoitory() call since RepositoryName() already
does this
- use constant for olm_artifacts directory

pkg/cli/options.go

- use constant for workspace

all files
- add documentation and change formatting for long function signatures
- if any file used deprecated io/ioutil, replace with io or os package
as necessary
- update unit tests as necessary (the bulk of the files are related to
new test cases)

* reverted test case result

- The original PR had concerns about using latest tag, so did not bring
this change over, therefore this test case had to be reverted too.

* bring over remaining changes

This commit brings over the remaining changes needed for correct
manifest list handling.

internal/testutils/testutils.go

- update and create new functions for creating single/multiarch images
- created *WithURL function variants to allow pre-existing registry in
tests because the defaults server won't allow external calls while
debugging

pkg/cli/mirror/catalog_images.go

- in rebuildCatalogs, make sure that the catalog source docker
reference uses lower case values for "name" and "namespace" which
is required to make valid docker references. This covers the case where
a OCI filepath uses uppercase letters in its path.

pkg/cli/mirror/create.go

- add missing call to strip protocol from ctlg.OCIFBCPath when
constructing a layoutPath

pkg/cli/mirror/mirror.go

- add missing initialization of operatorCatalogToFullArtifactPath

pkg/image/image.go

- in ParseReference, make sure that the docker reference uses lower case
values for "name" and "namespace" which is required to make valid docker
references. This covers the case where a OCI filepath uses uppercase
letters in its path.

pkg/image/builder/image_builder.go

- make image builder handle single arch and multi arch images

pkg/image/builder/image_builder_test.go

- update test cases for image builder

update go modules and vendoring

* fix test case error message

* Change getFirstDigestFromPath based on feedback

- make function return error when number of manifests > 1
- do basic checks to ensure digest is valid before returning
- return image digest instead of config hash
- adjust documentation

* fix test case

* fix uninitialized error

* fix test case after rebase

* Fix OCPBUGS-13198

When copying the OCI layout, make sure we only copy files/folders that
are part of the OCI layout specification.

The bug resulted because the copy destination was inside the
source directory, which lead to an infinite circular copy operation when
using the github.com/otiai10/copy package. This fix avoids this
because it copies only the OCI layout files/folders and ignores others.

* refactor inner function to standalone per feedback

* refactor processImageIndex to be a method

- based on review, make inner function processImageIndex into a method
of ImageBuilder
- add/update documentation

* remove unused getManifest func and test case
openshift-merge-robot pushed a commit that referenced this pull request Jul 19, 2023
… operation with multi… (#661)

* CFE-783: A variety of changes needed for correct operation with multi architecture catalogs (#611)

* A variety of changes needed for correct operation

Functional Changes

pkg/cli/mirror/fbc_operators.go

- remove findFBCConfig & replace with extractDeclarativeConfigFromImage
This is necessary because the layer processing did not handle whiteout
files. Switched to go-containerregistry which handles this correctly.
- modify getManifest so that it is fat manifest aware, and returns the
first manifest in the list, or for single images, returns that manifest
- Removed functions that are no longer necessary:
GetCatalogConfigPath, getConfigPathFromConfigLayer, UntarLayers

pkg/cli/mirror/create.go

- make createOlmArtifactsForOCI manifest list aware and discovers the
first image in the list, or for single images, uses that image directly
- calls replacement function extractDeclarativeConfigFromImage
- stores full path to the artifact in a map so this path does not need
to be recalculated later

pkg/cli/mirror/operator.go

- make use of operatorCatalogToFullArtifactPath map to obtain the full
path to the olm_artifacts directory and its contents and remove
getOperatorCatalogRef() since it is no longer necessary
- make writeLayout() use the image config file to discover the platform
when adding images, otherwise fall back to linux/amd64

pkg/cli/mirror/options.go

- add operatorCatalogToFullArtifactPath map[string]string

pkg/image/image.go

- replace getManifest with getFirstDigestFromPath which now gets the
first digest for manifest lists, or the image digest for single image
- change logging behavior in ParseReference() when path does not exist
and invalidate the ID in that case.

Non-functional Changes

pkg/cli/mirror/mirror.go

- removed redundant AsRespoitory() call since RepositoryName() already
does this
- use constant for olm_artifacts directory

pkg/cli/options.go

- use constant for workspace

all files
- add documentation and change formatting for long function signatures
- if any file used deprecated io/ioutil, replace with io or os package
as necessary
- update unit tests as necessary (the bulk of the files are related to
new test cases)

* reverted test case result

- The original PR had concerns about using latest tag, so did not bring
this change over, therefore this test case had to be reverted too.

* bring over remaining changes

This commit brings over the remaining changes needed for correct
manifest list handling.

internal/testutils/testutils.go

- update and create new functions for creating single/multiarch images
- created *WithURL function variants to allow pre-existing registry in
tests because the defaults server won't allow external calls while
debugging

pkg/cli/mirror/catalog_images.go

- in rebuildCatalogs, make sure that the catalog source docker
reference uses lower case values for "name" and "namespace" which
is required to make valid docker references. This covers the case where
a OCI filepath uses uppercase letters in its path.

pkg/cli/mirror/create.go

- add missing call to strip protocol from ctlg.OCIFBCPath when
constructing a layoutPath

pkg/cli/mirror/mirror.go

- add missing initialization of operatorCatalogToFullArtifactPath

pkg/image/image.go

- in ParseReference, make sure that the docker reference uses lower case
values for "name" and "namespace" which is required to make valid docker
references. This covers the case where a OCI filepath uses uppercase
letters in its path.

pkg/image/builder/image_builder.go

- make image builder handle single arch and multi arch images

pkg/image/builder/image_builder_test.go

- update test cases for image builder

update go modules and vendoring

* fix test case error message

* Change getFirstDigestFromPath based on feedback

- make function return error when number of manifests > 1
- do basic checks to ensure digest is valid before returning
- return image digest instead of config hash
- adjust documentation

* fix test case

* fix uninitialized error

* fix test case after rebase

* Fix OCPBUGS-13198

When copying the OCI layout, make sure we only copy files/folders that
are part of the OCI layout specification.

The bug resulted because the copy destination was inside the
source directory, which lead to an infinite circular copy operation when
using the github.com/otiai10/copy package. This fix avoids this
because it copies only the OCI layout files/folders and ignores others.

* refactor inner function to standalone per feedback

* refactor processImageIndex to be a method

- based on review, make inner function processImageIndex into a method
of ImageBuilder
- add/update documentation

* remove unused getManifest func and test case

* OCPBUGS-13762: make addRelatedImageToMapping multithreaded (#638)

* fix for OCPBUGS-13762

- make execution of addRelatedImageToMapping multi threaded
- make addRelatedImageToMapping take a sync.Map to support concurrency
- convert sync.Map back to image.TypedImageMapping after processing
- fix bug so that we actually use the mirror value if we found one

* add missing checkin for test case

* run make tidy

---------

Co-authored-by: John Hunkins <jhunkins@us.ibm.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged. qe-approved Signifies that QE has signed off on this PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet