Signed-off-by: Antonio Murdaca <runcom@redhat.com>
This commit is contained in:
Antonio Murdaca
2016-09-13 10:12:39 +02:00
parent d6be447ce9
commit 3980ac5894
5 changed files with 76 additions and 118 deletions

View File

@@ -9,6 +9,7 @@ import (
"io"
"io/ioutil"
"net/http"
"net/url"
"strings"
"time"
@@ -21,7 +22,8 @@ import (
// openshiftClient is configuration for dealing with a single image stream, for reading or writing.
type openshiftClient struct {
ref openshiftReference
ref openshiftReference
baseURL *url.URL
// Values from Kubernetes configuration
httpClient *http.Client
bearerToken string // "" if not used
@@ -51,9 +53,7 @@ func newOpenshiftClient(ref openshiftReference) (*openshiftClient, error) {
return nil, err
}
logrus.Debugf("URL: %#v", *baseURL)
if *baseURL != *ref.baseURL {
return nil, fmt.Errorf("Unexpected baseURL mismatch: default %#v, reference %#v", *baseURL, *ref.baseURL)
}
if httpClient == nil {
httpClient = http.DefaultClient
}
@@ -61,6 +61,7 @@ func newOpenshiftClient(ref openshiftReference) (*openshiftClient, error) {
return &openshiftClient{
ref: ref,
baseURL: baseURL,
httpClient: httpClient,
bearerToken: restConfig.BearerToken,
username: restConfig.Username,
@@ -70,7 +71,7 @@ func newOpenshiftClient(ref openshiftReference) (*openshiftClient, error) {
// doRequest performs a correctly authenticated request to a specified path, and returns response body or an error object.
func (c *openshiftClient) doRequest(method, path string, requestBody []byte) ([]byte, error) {
url := *c.ref.baseURL
url := *c.baseURL
url.Path = path
var requestBodyReader io.Reader
if requestBody != nil {
@@ -153,19 +154,7 @@ func (c *openshiftClient) convertDockerImageReference(ref string) (string, error
if len(parts) != 2 {
return "", fmt.Errorf("Invalid format of docker reference %s: missing '/'", ref)
}
// Sanity check that the reference is at least plausibly similar, i.e. uses the hard-coded port we expect.
if !strings.HasSuffix(parts[0], ":5000") {
return "", fmt.Errorf("Invalid format of docker reference %s: expecting port 5000", ref)
}
return c.dockerRegistryHostPart() + "/" + parts[1], nil
}
// dockerRegistryHostPart returns the host:port of the embedded Docker Registry API endpoint
// FIXME: There seems to be no way to discover the correct:host port using the API, so hard-code our knowledge
// about how the OpenShift Atomic Registry is configured, per examples/atomic-registry/run.sh:
// -p OPENSHIFT_OAUTH_PROVIDER_URL=https://${INSTALL_HOST}:8443,COCKPIT_KUBE_URL=https://${INSTALL_HOST},REGISTRY_HOST=${INSTALL_HOST}:5000
func (c *openshiftClient) dockerRegistryHostPart() string {
return strings.SplitN(c.ref.baseURL.Host, ":", 2)[0] + ":5000"
return c.ref.dockerReference.Hostname() + "/" + parts[1], nil
}
type openshiftImageSource struct {
@@ -261,7 +250,7 @@ func (s *openshiftImageSource) ensureImageIsResolved() error {
}
var te *tagEvent
for _, tag := range is.Status.Tags {
if tag.Tag != s.client.ref.tag {
if tag.Tag != s.client.ref.dockerReference.Tag() {
continue
}
if len(tag.Items) > 0 {
@@ -308,7 +297,7 @@ func newImageDestination(ctx *types.SystemContext, ref openshiftReference) (type
// FIXME: Should this always use a digest, not a tag? Uploading to Docker by tag requires the tag _inside_ the manifest to match,
// i.e. a single signed image cannot be available under multiple tags. But with types.ImageDestination, we don't know
// the manifest digest at this point.
dockerRefString := fmt.Sprintf("//%s/%s/%s:%s", client.dockerRegistryHostPart(), client.ref.namespace, client.ref.stream, client.ref.tag)
dockerRefString := fmt.Sprintf("//%s/%s/%s:%s", client.ref.dockerReference.Hostname(), client.ref.namespace, client.ref.stream, client.ref.dockerReference.Tag())
dockerRef, err := docker.ParseReference(dockerRefString)
if err != nil {
return nil, err
@@ -370,7 +359,7 @@ func (d *openshiftImageDestination) PutManifest(m []byte) error {
}
d.imageStreamImageName = manifestDigest
// FIXME: We can't do what respositorymiddleware.go does because we don't know the internal address. Does any of this matter?
dockerImageReference := fmt.Sprintf("%s/%s/%s@%s", d.client.dockerRegistryHostPart(), d.client.ref.namespace, d.client.ref.stream, manifestDigest)
dockerImageReference := fmt.Sprintf("%s/%s/%s@%s", d.client.ref.dockerReference.Hostname(), d.client.ref.namespace, d.client.ref.stream, manifestDigest)
ism := imageStreamMapping{
typeMeta: typeMeta{
Kind: "ImageStreamMapping",
@@ -387,7 +376,7 @@ func (d *openshiftImageDestination) PutManifest(m []byte) error {
DockerImageReference: dockerImageReference,
DockerImageManifest: string(m),
},
Tag: d.client.ref.tag,
Tag: d.client.ref.dockerReference.Tag(),
}
body, err := json.Marshal(ism)
if err != nil {

View File

@@ -3,10 +3,9 @@ package openshift
import (
"errors"
"fmt"
"net/url"
"regexp"
"strings"
"github.com/Sirupsen/logrus"
"github.com/containers/image/docker/policyconfiguration"
"github.com/containers/image/types"
"github.com/docker/docker/reference"
@@ -44,67 +43,33 @@ func (t openshiftTransport) ValidatePolicyConfigurationScope(scope string) error
// 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.
dockerReference reference.NamedTagged
namespace string // Computed from dockerReference in advance.
stream string // Computed from dockerReference in advance.
}
// 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()
func ParseReference(ref string) (types.ImageReference, error) {
r, err := reference.ParseNamed(ref)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to parse image reference %q, %v", ref, 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
tagged, ok := r.(reference.NamedTagged)
if !ok {
return nil, fmt.Errorf("invalid image reference %s, %#v", ref, r)
}
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])
return NewReference(tagged)
}
// 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
// NewReference returns an OpenShift reference for a reference.NamedTagged
func NewReference(dockerRef reference.NamedTagged) (types.ImageReference, error) {
r := strings.SplitN(dockerRef.RemoteName(), "/", 3)
if len(r) != 2 {
return nil, fmt.Errorf("invalid image reference %s", dockerRef.String())
}
dockerRef, err = reference.WithTag(dockerRef, tag)
if err != nil {
return nil, err
}
return openshiftReference{
baseURL: baseURL,
namespace: namespace,
stream: stream,
tag: tag,
namespace: r[0],
stream: r[1],
dockerReference: dockerRef,
}, nil
}
@@ -119,7 +84,7 @@ func (ref openshiftReference) Transport() types.ImageTransport {
// 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)
return ref.dockerReference.String()
}
// DockerReference returns a Docker reference associated with this reference

View File

@@ -15,18 +15,22 @@
package v1
const (
// MediaTypeDescriptor specifies the mediaType for a content descriptor.
// MediaTypeDescriptor specifies the media type for a content descriptor.
MediaTypeDescriptor = "application/vnd.oci.descriptor.v1+json"
// MediaTypeImageManifest specifies the mediaType for an image manifest.
// MediaTypeImageManifest specifies the media type for an image manifest.
MediaTypeImageManifest = "application/vnd.oci.image.manifest.v1+json"
// MediaTypeImageManifestList specifies the mediaType for an image manifest list.
// MediaTypeImageManifestList specifies the media type for an image manifest list.
MediaTypeImageManifestList = "application/vnd.oci.image.manifest.list.v1+json"
// MediaTypeImageLayer is the mediaType used for layers referenced by the manifest.
// MediaTypeImageLayer is the media type used for layers referenced by the manifest.
MediaTypeImageLayer = "application/vnd.oci.image.layer.tar+gzip"
// MediaTypeImageConfig specifies the mediaType for the image configuration.
// MediaTypeImageLayerNonDistributable is the media type for layers referenced by
// the manifest but with distribution restrictions.
MediaTypeImageLayerNonDistributable = "application/vnd.oci.image.layer.nondistributable.tar+gzip"
// MediaTypeImageConfig specifies the media type for the image configuration.
MediaTypeImageConfig = "application/vnd.oci.image.config.v1+json"
)