170 lines
7.5 KiB
Go
170 lines
7.5 KiB
Go
|
package openshift
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"net/url"
|
||
|
"regexp"
|
||
|
|
||
|
"github.com/Sirupsen/logrus"
|
||
|
"github.com/containers/image/docker/policyconfiguration"
|
||
|
"github.com/containers/image/types"
|
||
|
"github.com/docker/docker/reference"
|
||
|
)
|
||
|
|
||
|
// Transport is an ImageTransport for directory paths.
|
||
|
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 fmt.Errorf("Invalid scope name %s", scope)
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// openshiftReference is an ImageReference for OpenShift images.
|
||
|
type openshiftReference struct {
|
||
|
baseURL *url.URL
|
||
|
namespace string
|
||
|
stream string
|
||
|
tag string
|
||
|
dockerReference reference.Named // Computed from the above in advance, so that later references can not fail.
|
||
|
}
|
||
|
|
||
|
// FIXME: Is imageName like this a good way to refer to OpenShift images?
|
||
|
// Keep this in sync with scopeRegexp!
|
||
|
var imageNameRegexp = regexp.MustCompile("^([^:/]*)/([^:/]*):([^:/]*)$")
|
||
|
|
||
|
// ParseReference converts a string, which should not start with the ImageTransport.Name prefix, into an OpenShift ImageReference.
|
||
|
func ParseReference(reference string) (types.ImageReference, error) {
|
||
|
// Overall, this is modelled on openshift/origin/pkg/cmd/util/clientcmd.New().ClientConfig() and openshift/origin/pkg/client.
|
||
|
cmdConfig := defaultClientConfig()
|
||
|
logrus.Debugf("cmdConfig: %#v", cmdConfig)
|
||
|
restConfig, err := cmdConfig.ClientConfig()
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
// REMOVED: SetOpenShiftDefaults (values are not overridable in config files, so hard-coded these defaults.)
|
||
|
logrus.Debugf("restConfig: %#v", restConfig)
|
||
|
baseURL, _, err := restClientFor(restConfig)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
logrus.Debugf("URL: %#v", *baseURL)
|
||
|
|
||
|
m := imageNameRegexp.FindStringSubmatch(reference)
|
||
|
if m == nil || len(m) != 4 {
|
||
|
return nil, fmt.Errorf("Invalid image reference %s, %#v", reference, m)
|
||
|
}
|
||
|
|
||
|
return NewReference(baseURL, m[1], m[2], m[3])
|
||
|
}
|
||
|
|
||
|
// NewReference returns an OpenShift reference for a base URL, namespace, stream and tag.
|
||
|
func NewReference(baseURL *url.URL, namespace, stream, tag string) (types.ImageReference, error) {
|
||
|
// Precompute also dockerReference so that later references can not fail.
|
||
|
//
|
||
|
// This discards ref.baseURL.Path, which is unexpected for a “base URL”;
|
||
|
// but openshiftClient.doRequest actually completely overrides url.Path
|
||
|
// (and defaultServerURL rejects non-trivial Path values), so it is OK for
|
||
|
// us to ignore it as well.
|
||
|
//
|
||
|
// FIXME: This is, strictly speaking, a namespace conflict with images placed in a Docker registry running on the same host.
|
||
|
// Do we need to do something else, perhaps disambiguate (port number?) or namespace Docker and OpenShift separately?
|
||
|
dockerRef, err := reference.WithName(fmt.Sprintf("%s/%s/%s", baseURL.Host, namespace, stream))
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
dockerRef, err = reference.WithTag(dockerRef, tag)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return openshiftReference{
|
||
|
baseURL: baseURL,
|
||
|
namespace: namespace,
|
||
|
stream: stream,
|
||
|
tag: tag,
|
||
|
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 fmt.Sprintf("%s/%s:%s", ref.namespace, ref.stream, ref.tag)
|
||
|
}
|
||
|
|
||
|
// 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.
|
||
|
func (ref openshiftReference) NewImage(certPath string, tlsVerify bool) (types.Image, error) {
|
||
|
return nil, errors.New("Full Image support not implemented for atomic: image names")
|
||
|
}
|
||
|
|
||
|
// NewImageSource returns a types.ImageSource for this reference.
|
||
|
func (ref openshiftReference) NewImageSource(certPath string, tlsVerify bool) (types.ImageSource, error) {
|
||
|
return newImageSource(ref, certPath, tlsVerify)
|
||
|
}
|
||
|
|
||
|
// NewImageDestination returns a types.ImageDestination for this reference.
|
||
|
func (ref openshiftReference) NewImageDestination(certPath string, tlsVerify bool) (types.ImageDestination, error) {
|
||
|
return newImageDestination(ref, certPath, tlsVerify)
|
||
|
}
|