diff --git a/go.mod b/go.mod index 7c64585c48..3e618eb198 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/onsi/ginkgo v1.12.0 // indirect github.com/onsi/gomega v1.9.0 // indirect github.com/opencontainers/go-digest v1.0.0-rc1 // indirect - github.com/opencontainers/image-spec v1.0.1 // indirect + github.com/opencontainers/image-spec v1.0.1 github.com/sirupsen/logrus v1.6.0 // indirect github.com/spf13/cobra v1.0.0 github.com/vdemeester/k8s-pkg-credentialprovider v1.18.1-0.20201019120933-f1d16962a4db diff --git a/pkg/v1/v1util/index.go b/pkg/v1/v1util/index.go new file mode 100644 index 0000000000..bf6d5cc915 --- /dev/null +++ b/pkg/v1/v1util/index.go @@ -0,0 +1,38 @@ +// Copyright 2018 Google LLC All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1util + +import ( + "fmt" + + v1 "github.com/google/go-containerregistry/pkg/v1" +) + +// FindManifests given a v1.ImageIndex, find the manifests that fit the matcher +func FindManifests(index v1.ImageIndex, matcher ManifestMatcher) ([]v1.Descriptor, error) { + // get the actual manifest list + indexManifest, err := index.IndexManifest() + if err != nil { + return nil, fmt.Errorf("unable to get raw index: %v", err) + } + manifests := []v1.Descriptor{} + // try to get the root of our image + for _, manifest := range indexManifest.Manifests { + if matcher(manifest) { + manifests = append(manifests, manifest) + } + } + return manifests, nil +} diff --git a/pkg/v1/v1util/matcher.go b/pkg/v1/v1util/matcher.go new file mode 100644 index 0000000000..051ca62450 --- /dev/null +++ b/pkg/v1/v1util/matcher.go @@ -0,0 +1,77 @@ +// Copyright 2020 Google LLC All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1util + +import ( + v1 "github.com/google/go-containerregistry/pkg/v1" + imagespec "github.com/opencontainers/image-spec/specs-go/v1" +) + +// ManifestMatcher function that is given a v1.Descriptor, and returns whether or +// not it matches a given rule. Can match on anything it wants in the Descriptor. +type ManifestMatcher func(desc v1.Descriptor) bool + +// NameMatcher returns a ManifestMatcher that matches on the name tag in +// github.com/opencontainers/image-spec/specs-go/v1.AnnotationRefName +func NameMatcher(name string) ManifestMatcher { + return AnnotationMatcher(imagespec.AnnotationRefName, name) +} + +// AnnotationMatcher returns a ManifestMatcher that matches based on the provided annotation +func AnnotationMatcher(key, value string) ManifestMatcher { + return func(desc v1.Descriptor) bool { + if desc.Annotations == nil { + return false + } + if aValue, ok := desc.Annotations[key]; ok && aValue == value { + return true + } + return false + } +} + +// PlatformMatcher returns a ManifestMatcher that matches on the provided platform. +// Ignores any descriptors that do not have a platform. +func PlatformMatcher(platform v1.Platform) ManifestMatcher { + return func(desc v1.Descriptor) bool { + if desc.Platform == nil { + return false + } + return platformEqual(*desc.Platform, platform) + } +} + +// MediaTypeMatcher returns a ManifestMatcher that matches based on one of the provided media types +func MediaTypeMatcher(mediaTypes []string) ManifestMatcher { + mts := map[string]bool{} + for _, media := range mediaTypes { + mts[media] = true + } + return func(desc v1.Descriptor) bool { + if desc.MediaType == "" { + return false + } + if _, ok := mts[string(desc.MediaType)]; ok { + return true + } + return false + } +} + +// platformEqual return if two v1.Platform are functionally equivalent. +func platformEqual(a, b v1.Platform) bool { + // ignoring the Platform.Features and Platform.OSFeatures for now + return a.OS == b.OS && a.Architecture == b.Architecture && a.Variant == b.Variant && a.OSVersion == b.OSVersion +}