de9995d5f0
Signed-off-by: Andrew Pilloud <andrewpilloud@igneoussystems.com>
157 lines
7.2 KiB
Go
157 lines
7.2 KiB
Go
package openshift
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/containers/image/docker/policyconfiguration"
|
|
"github.com/containers/image/docker/reference"
|
|
genericImage "github.com/containers/image/image"
|
|
"github.com/containers/image/transports"
|
|
"github.com/containers/image/types"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
func init() {
|
|
transports.Register(Transport)
|
|
}
|
|
|
|
// Transport is an ImageTransport for OpenShift registry-hosted images.
|
|
var Transport = openshiftTransport{}
|
|
|
|
type openshiftTransport struct{}
|
|
|
|
func (t openshiftTransport) Name() string {
|
|
return "atomic"
|
|
}
|
|
|
|
// ParseReference converts a string, which should not start with the ImageTransport.Name prefix, into an ImageReference.
|
|
func (t openshiftTransport) ParseReference(reference string) (types.ImageReference, error) {
|
|
return ParseReference(reference)
|
|
}
|
|
|
|
// Note that imageNameRegexp is namespace/stream:tag, this
|
|
// is HOSTNAME/namespace/stream:tag or parent prefixes.
|
|
// Keep this in sync with imageNameRegexp!
|
|
var scopeRegexp = regexp.MustCompile("^[^/]*(/[^:/]*(/[^:/]*(:[^:/]*)?)?)?$")
|
|
|
|
// ValidatePolicyConfigurationScope checks that scope is a valid name for a signature.PolicyTransportScopes keys
|
|
// (i.e. a valid PolicyConfigurationIdentity() or PolicyConfigurationNamespaces() return value).
|
|
// It is acceptable to allow an invalid value which will never be matched, it can "only" cause user confusion.
|
|
// scope passed to this function will not be "", that value is always allowed.
|
|
func (t openshiftTransport) ValidatePolicyConfigurationScope(scope string) error {
|
|
if scopeRegexp.FindStringIndex(scope) == nil {
|
|
return errors.Errorf("Invalid scope name %s", scope)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// openshiftReference is an ImageReference for OpenShift images.
|
|
type openshiftReference struct {
|
|
dockerReference reference.NamedTagged
|
|
namespace string // Computed from dockerReference in advance.
|
|
stream string // Computed from dockerReference in advance.
|
|
}
|
|
|
|
// ParseReference converts a string, which should not start with the ImageTransport.Name prefix, into an OpenShift ImageReference.
|
|
func ParseReference(ref string) (types.ImageReference, error) {
|
|
r, err := reference.ParseNormalizedNamed(ref)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to parse image reference %q", ref)
|
|
}
|
|
tagged, ok := r.(reference.NamedTagged)
|
|
if !ok {
|
|
return nil, errors.Errorf("invalid image reference %s, expected format: 'hostname/namespace/stream:tag'", ref)
|
|
}
|
|
return NewReference(tagged)
|
|
}
|
|
|
|
// NewReference returns an OpenShift reference for a reference.NamedTagged
|
|
func NewReference(dockerRef reference.NamedTagged) (types.ImageReference, error) {
|
|
r := strings.SplitN(reference.Path(dockerRef), "/", 3)
|
|
if len(r) != 2 {
|
|
return nil, errors.Errorf("invalid image reference: %s, expected format: 'hostname/namespace/stream:tag'",
|
|
reference.FamiliarString(dockerRef))
|
|
}
|
|
return openshiftReference{
|
|
namespace: r[0],
|
|
stream: r[1],
|
|
dockerReference: dockerRef,
|
|
}, nil
|
|
}
|
|
|
|
func (ref openshiftReference) Transport() types.ImageTransport {
|
|
return Transport
|
|
}
|
|
|
|
// StringWithinTransport returns a string representation of the reference, which MUST be such that
|
|
// reference.Transport().ParseReference(reference.StringWithinTransport()) returns an equivalent reference.
|
|
// NOTE: The returned string is not promised to be equal to the original input to ParseReference;
|
|
// e.g. default attribute values omitted by the user may be filled in in the return value, or vice versa.
|
|
// WARNING: Do not use the return value in the UI to describe an image, it does not contain the Transport().Name() prefix.
|
|
func (ref openshiftReference) StringWithinTransport() string {
|
|
return reference.FamiliarString(ref.dockerReference)
|
|
}
|
|
|
|
// DockerReference returns a Docker reference associated with this reference
|
|
// (fully explicit, i.e. !reference.IsNameOnly, but reflecting user intent,
|
|
// not e.g. after redirect or alias processing), or nil if unknown/not applicable.
|
|
func (ref openshiftReference) DockerReference() reference.Named {
|
|
return ref.dockerReference
|
|
}
|
|
|
|
// PolicyConfigurationIdentity returns a string representation of the reference, suitable for policy lookup.
|
|
// This MUST reflect user intent, not e.g. after processing of third-party redirects or aliases;
|
|
// The value SHOULD be fully explicit about its semantics, with no hidden defaults, AND canonical
|
|
// (i.e. various references with exactly the same semantics should return the same configuration identity)
|
|
// It is fine for the return value to be equal to StringWithinTransport(), and it is desirable but
|
|
// not required/guaranteed that it will be a valid input to Transport().ParseReference().
|
|
// Returns "" if configuration identities for these references are not supported.
|
|
func (ref openshiftReference) PolicyConfigurationIdentity() string {
|
|
res, err := policyconfiguration.DockerReferenceIdentity(ref.dockerReference)
|
|
if res == "" || err != nil { // Coverage: Should never happen, NewReference constructs a valid tagged reference.
|
|
panic(fmt.Sprintf("Internal inconsistency: policyconfiguration.DockerReferenceIdentity returned %#v, %v", res, err))
|
|
}
|
|
return res
|
|
}
|
|
|
|
// PolicyConfigurationNamespaces returns a list of other policy configuration namespaces to search
|
|
// for if explicit configuration for PolicyConfigurationIdentity() is not set. The list will be processed
|
|
// in order, terminating on first match, and an implicit "" is always checked at the end.
|
|
// It is STRONGLY recommended for the first element, if any, to be a prefix of PolicyConfigurationIdentity(),
|
|
// and each following element to be a prefix of the element preceding it.
|
|
func (ref openshiftReference) PolicyConfigurationNamespaces() []string {
|
|
return policyconfiguration.DockerReferenceNamespaces(ref.dockerReference)
|
|
}
|
|
|
|
// NewImage returns a types.Image for this reference, possibly specialized for this ImageTransport.
|
|
// The caller must call .Close() on the returned Image.
|
|
// NOTE: If any kind of signature verification should happen, build an UnparsedImage from the value returned by NewImageSource,
|
|
// verify that UnparsedImage, and convert it into a real Image via image.FromUnparsedImage.
|
|
func (ref openshiftReference) NewImage(ctx *types.SystemContext) (types.Image, error) {
|
|
src, err := newImageSource(ctx, ref, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return genericImage.FromSource(src)
|
|
}
|
|
|
|
// NewImageSource returns a types.ImageSource for this reference,
|
|
// asking the backend to use a manifest from requestedManifestMIMETypes if possible.
|
|
// nil requestedManifestMIMETypes means manifest.DefaultRequestedManifestMIMETypes.
|
|
// The caller must call .Close() on the returned ImageSource.
|
|
func (ref openshiftReference) NewImageSource(ctx *types.SystemContext, requestedManifestMIMETypes []string) (types.ImageSource, error) {
|
|
return newImageSource(ctx, ref, requestedManifestMIMETypes)
|
|
}
|
|
|
|
// NewImageDestination returns a types.ImageDestination for this reference.
|
|
// The caller must call .Close() on the returned ImageDestination.
|
|
func (ref openshiftReference) NewImageDestination(ctx *types.SystemContext) (types.ImageDestination, error) {
|
|
return newImageDestination(ctx, ref)
|
|
}
|
|
|
|
// DeleteImage deletes the named image from the registry, if supported.
|
|
func (ref openshiftReference) DeleteImage(ctx *types.SystemContext) error {
|
|
return errors.Errorf("Deleting images not implemented for atomic: images")
|
|
}
|