diff --git a/contrib/completions/bash/oc b/contrib/completions/bash/oc index 77544f278c2f..e3e0027d878d 100644 --- a/contrib/completions/bash/oc +++ b/contrib/completions/bash/oc @@ -12053,6 +12053,8 @@ _oc_import-image() flags+=("--all") local_nonpersistent_flags+=("--all") + flags+=("--allow-missing-template-keys") + local_nonpersistent_flags+=("--allow-missing-template-keys") flags+=("--confirm") local_nonpersistent_flags+=("--confirm") flags+=("--dry-run") @@ -12061,10 +12063,17 @@ _oc_import-image() local_nonpersistent_flags+=("--from=") flags+=("--insecure") local_nonpersistent_flags+=("--insecure") + flags+=("--output=") + two_word_flags+=("-o") + local_nonpersistent_flags+=("--output=") flags+=("--reference-policy=") local_nonpersistent_flags+=("--reference-policy=") flags+=("--scheduled") local_nonpersistent_flags+=("--scheduled") + flags+=("--template=") + flags_with_completion+=("--template") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--template=") flags+=("--as=") flags+=("--as-group=") flags+=("--cache-dir=") diff --git a/contrib/completions/zsh/oc b/contrib/completions/zsh/oc index e80cdd3b25ca..0bd90fc59af6 100644 --- a/contrib/completions/zsh/oc +++ b/contrib/completions/zsh/oc @@ -12195,6 +12195,8 @@ _oc_import-image() flags+=("--all") local_nonpersistent_flags+=("--all") + flags+=("--allow-missing-template-keys") + local_nonpersistent_flags+=("--allow-missing-template-keys") flags+=("--confirm") local_nonpersistent_flags+=("--confirm") flags+=("--dry-run") @@ -12203,10 +12205,17 @@ _oc_import-image() local_nonpersistent_flags+=("--from=") flags+=("--insecure") local_nonpersistent_flags+=("--insecure") + flags+=("--output=") + two_word_flags+=("-o") + local_nonpersistent_flags+=("--output=") flags+=("--reference-policy=") local_nonpersistent_flags+=("--reference-policy=") flags+=("--scheduled") local_nonpersistent_flags+=("--scheduled") + flags+=("--template=") + flags_with_completion+=("--template") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--template=") flags+=("--as=") flags+=("--as-group=") flags+=("--cache-dir=") diff --git a/hack/import-restrictions.json b/hack/import-restrictions.json index 6d43677a7d5d..fe515bfe1dd8 100644 --- a/hack/import-restrictions.json +++ b/hack/import-restrictions.json @@ -476,9 +476,9 @@ "github.com/openshift/origin/pkg/authorization/generated", "github.com/openshift/origin/pkg/build/apis/build/v1", "github.com/openshift/origin/pkg/build/generated", - "github.com/openshift/origin/pkg/image/apis/image/v1", + "github.com/openshift/origin/pkg/image/apis/image/v1", "github.com/openshift/origin/pkg/image/generated", - "github.com/openshift/origin/pkg/image/util", + "github.com/openshift/origin/pkg/image/util", "github.com/openshift/origin/pkg/network/generated", "github.com/openshift/origin/pkg/oauth/generated", "github.com/openshift/origin/pkg/project/generated", diff --git a/pkg/oc/cli/importimage/importimage.go b/pkg/oc/cli/importimage/importimage.go index f1132fc6681e..256e1b2bcbeb 100644 --- a/pkg/oc/cli/importimage/importimage.go +++ b/pkg/oc/cli/importimage/importimage.go @@ -6,18 +6,19 @@ import ( "github.com/spf13/cobra" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/sets" "k8s.io/kubernetes/pkg/api/legacyscheme" - kapi "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/kubectl/cmd/templates" kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/kubectl/genericclioptions" + "k8s.io/kubernetes/pkg/kubectl/genericclioptions/printers" - imageapiv1 "github.com/openshift/api/image/v1" + imagev1 "github.com/openshift/api/image/v1" + imagev1client "github.com/openshift/client-go/image/clientset/versioned/typed/image/v1" imageapi "github.com/openshift/origin/pkg/image/apis/image" - imageclientinternal "github.com/openshift/origin/pkg/image/generated/internalclientset" - imageclient "github.com/openshift/origin/pkg/image/generated/internalclientset/typed/image/internalversion" "github.com/openshift/origin/pkg/oc/cli/tag" "github.com/openshift/origin/pkg/oc/lib/describe" ) @@ -43,6 +44,10 @@ var ( // ImageImportOptions contains all the necessary information to perform an import. type ImportImageOptions struct { + PrintFlags *genericclioptions.PrintFlags + + ToPrinter func(string) (printers.ResourcePrinter, error) + // user set values From string Confirm bool @@ -61,14 +66,15 @@ type ImportImageOptions struct { ReferencePolicy string // helpers - imageClient imageclient.ImageInterface - isClient imageclient.ImageStreamInterface + imageClient imagev1client.ImageV1Interface + isClient imagev1client.ImageStreamInterface genericclioptions.IOStreams } func NewImportImageOptions(name string, streams genericclioptions.IOStreams) *ImportImageOptions { return &ImportImageOptions{ + PrintFlags: genericclioptions.NewPrintFlags("imported"), IOStreams: streams, ReferencePolicy: tag.SourceReferencePolicy, } @@ -85,10 +91,13 @@ func NewCmdImportImage(fullName string, f kcmdutil.Factory, streams genericcliop Example: fmt.Sprintf(importImageExample, fullName), Run: func(cmd *cobra.Command, args []string) { kcmdutil.CheckErr(o.Complete(f, cmd, args)) - kcmdutil.CheckErr(o.Validate(cmd)) + kcmdutil.CheckErr(o.Validate()) kcmdutil.CheckErr(o.Run()) }, } + + o.PrintFlags.AddFlags(cmd) + cmd.Flags().StringVar(&o.From, "from", o.From, "A Docker image repository to import images from") cmd.Flags().BoolVar(&o.Confirm, "confirm", o.Confirm, "If true, allow the image stream import location to be set or changed") cmd.Flags().BoolVar(&o.All, "all", o.All, "If true, import all tags from the provided source on creation or if --from is specified") @@ -112,34 +121,35 @@ func (o *ImportImageOptions) Complete(f kcmdutil.Factory, cmd *cobra.Command, ar o.ReferencePolicy = "" } - namespace, _, err := f.ToRawKubeConfigLoader().Namespace() + clientConfig, err := f.ToRESTConfig() if err != nil { return err } - o.Namespace = namespace - clientConfig, err := f.ToRESTConfig() + o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace() if err != nil { return err } - client, err := imageclientinternal.NewForConfig(clientConfig) + + o.imageClient, err = imagev1client.NewForConfig(clientConfig) if err != nil { return err } - o.imageClient = client.Image() - o.isClient = client.Image().ImageStreams(namespace) + o.isClient = o.imageClient.ImageStreams(o.Namespace) - return nil -} + o.ToPrinter = func(operation string) (printers.ResourcePrinter, error) { + o.PrintFlags.NamePrintFlags.Operation = operation -// Validate ensures that a ImportImageOptions is valid and can be used to execute -// an import. -func (o *ImportImageOptions) Validate(cmd *cobra.Command) error { - if len(o.Target) == 0 { - return kcmdutil.UsageErrorf(cmd, "you must specify the name of an image stream") + // We assume that the (dry run) message has already been added (if need be) + // by the caller of this method. + return o.PrintFlags.ToPrinter() } + return o.parseImageReference() +} + +func (o *ImportImageOptions) parseImageReference() error { targetRef, err := imageapi.ParseDockerImageReference(o.Target) switch { case err != nil: @@ -159,6 +169,16 @@ func (o *ImportImageOptions) Validate(cmd *cobra.Command) error { return nil } +// Validate ensures that a ImportImageOptions is valid and can be used to execute +// an import. +func (o *ImportImageOptions) Validate() error { + if len(o.Target) == 0 { + return fmt.Errorf("you must specify the name of an image stream") + } + + return nil +} + // Run contains all the necessary functionality for the OpenShift cli import-image command. func (o *ImportImageOptions) Run() error { stream, isi, err := o.createImageImport() @@ -171,37 +191,47 @@ func (o *ImportImageOptions) Run() error { return err } + message := "imported" + if wasError(result) { + message = "imported with errors" + } + if o.DryRun { - if wasError(result) { - fmt.Fprintf(o.ErrOut, "The dry-run import completed with errors.\n\n") - } else { - fmt.Fprint(o.Out, "The dry-run import completed successfully.\n\n") - } - } else { - if wasError(result) { - fmt.Fprintf(o.ErrOut, "The import completed with errors.\n\n") - } else { - fmt.Fprint(o.Out, "The import completed successfully.\n\n") - } + message = fmt.Sprintf("%s (dry run)", message) } + message = fmt.Sprintf("%s\n\n", message) if result.Status.Import != nil { + + // TODO: remove once we have external describers + internalResult := &imageapi.ImageStreamImport{} + if legacyscheme.Scheme.Convert(result, internalResult, nil); err != nil { + return fmt.Errorf("unable to convert *v1.Image to internal object: %v", err) + } + // TODO: dry-run doesn't return an image stream, so we have to display partial results - info, err := describe.DescribeImageStream(result.Status.Import) + info, err := describe.DescribeImageStream(internalResult.Status.Import) if err != nil { return err } - fmt.Fprintln(o.Out, info) + + message += fmt.Sprintln(info) } if repo := result.Status.Repository; repo != nil { for _, image := range repo.Images { if image.Image != nil { - info, err := describe.DescribeImage(image.Image, imageapi.JoinImageStreamTag(stream.Name, image.Tag)) + // TODO: remove once we have external describers + var internalImage imageapi.Image + if legacyscheme.Scheme.Convert(image.Image, &internalImage, nil); err != nil { + return fmt.Errorf("unable to convert *v1.Image to internal object: %v", err) + } + + info, err := describe.DescribeImage(&internalImage, imageapi.JoinImageStreamTag(stream.Name, image.Tag)) if err != nil { fmt.Fprintf(o.ErrOut, "error: tag %s failed: %v\n", image.Tag, err) } else { - fmt.Fprintln(o.Out, info) + message += fmt.Sprintln(info) } } else { fmt.Fprintf(o.ErrOut, "error: repository tag %s failed: %v\n", image.Tag, image.Status.Message) @@ -211,11 +241,17 @@ func (o *ImportImageOptions) Run() error { for _, image := range result.Status.Images { if image.Image != nil { - info, err := describe.DescribeImage(image.Image, imageapi.JoinImageStreamTag(stream.Name, image.Tag)) + // TODO: remove once we have external describers + var internalImage imageapi.Image + if legacyscheme.Scheme.Convert(image.Image, &internalImage, nil); err != nil { + return fmt.Errorf("unable to convert *v1.Image to internal object: %v", err) + } + + info, err := describe.DescribeImage(&internalImage, imageapi.JoinImageStreamTag(stream.Name, image.Tag)) if err != nil { fmt.Fprintf(o.ErrOut, "error: tag %s failed: %v\n", image.Tag, err) } else { - fmt.Fprintln(o.Out, info) + message += fmt.Sprintln(info) } } else { fmt.Fprintf(o.ErrOut, "error: tag %s failed: %v\n", image.Tag, image.Status.Message) @@ -223,12 +259,18 @@ func (o *ImportImageOptions) Run() error { } if r := result.Status.Repository; r != nil && len(r.AdditionalTags) > 0 { - fmt.Fprintf(o.Out, "\ninfo: The remote repository contained %d additional tags which were not imported: %s\n", len(r.AdditionalTags), strings.Join(r.AdditionalTags, ", ")) + message += fmt.Sprintf("\ninfo: The remote repository contained %d additional tags which were not imported: %s\n", len(r.AdditionalTags), strings.Join(r.AdditionalTags, ", ")) } - return nil + + printer, err := o.ToPrinter(message) + if err != nil { + return err + } + + return printer.PrintObj(stream, o.Out) } -func wasError(isi *imageapi.ImageStreamImport) bool { +func wasError(isi *imagev1.ImageStreamImport) bool { for _, image := range isi.Status.Images { if image.Status.Status == metav1.StatusFailure { return true @@ -249,8 +291,8 @@ func (e importError) Error() string { return fmt.Sprintf("unable to import image: %s", e.annotation) } -func (o *ImportImageOptions) createImageImport() (*imageapi.ImageStream, *imageapi.ImageStreamImport, error) { - var isi *imageapi.ImageStreamImport +func (o *ImportImageOptions) createImageImport() (*imagev1.ImageStream, *imagev1.ImageStreamImport, error) { + var isi *imagev1.ImageStreamImport stream, err := o.isClient.Get(o.Name, metav1.GetOptions{}) // no stream, try creating one if err != nil { @@ -261,18 +303,6 @@ func (o *ImportImageOptions) createImageImport() (*imageapi.ImageStream, *imagea return nil, nil, fmt.Errorf("no image stream named %q exists, pass --confirm to create and import", o.Name) } stream, isi = o.newImageStream() - // ensure defaulting is applied by round trip converting - // TODO: convert to using versioned types. - external, err := legacyscheme.Scheme.ConvertToVersion(stream, imageapiv1.SchemeGroupVersion) - if err != nil { - return nil, nil, err - } - legacyscheme.Scheme.Default(external) - internal, err := legacyscheme.Scheme.ConvertToVersion(external, imageapi.GroupVersion) - if err != nil { - return nil, nil, err - } - stream = internal.(*imageapi.ImageStream) return stream, isi, nil } @@ -290,10 +320,15 @@ func (o *ImportImageOptions) createImageImport() (*imageapi.ImageStream, *imagea } } + // this is ok because we know exactly how we want to be serialized + if stream.GetObjectKind().GroupVersionKind().Empty() { + stream.GetObjectKind().SetGroupVersionKind(imagev1.SchemeGroupVersion.WithKind("ImageStream")) + } + return stream, isi, nil } -func (o *ImportImageOptions) importAll(stream *imageapi.ImageStream) (*imageapi.ImageStreamImport, error) { +func (o *ImportImageOptions) importAll(stream *imagev1.ImageStream) (*imagev1.ImageStreamImport, error) { from := o.From // update ImageStream appropriately if len(from) == 0 { @@ -301,9 +336,9 @@ func (o *ImportImageOptions) importAll(stream *imageapi.ImageStream) (*imageapi. from = stream.Spec.DockerImageRepository } else { tags := make(map[string]string) - for name, tag := range stream.Spec.Tags { + for _, tag := range stream.Spec.Tags { if tag.From != nil && tag.From.Kind == "DockerImage" { - tags[name] = tag.From.Name + tags[tag.Name] = tag.From.Name } } if len(tags) == 0 { @@ -326,11 +361,12 @@ func (o *ImportImageOptions) importAll(stream *imageapi.ImageStream) (*imageapi. return o.newImageStreamImportAll(stream, from), nil } -func (o *ImportImageOptions) importTag(stream *imageapi.ImageStream) (*imageapi.ImageStreamImport, error) { +func (o *ImportImageOptions) importTag(stream *imagev1.ImageStream) (*imagev1.ImageStreamImport, error) { from := o.From tag := o.Tag + // follow any referential tags to the destination - finalTag, existing, multiple, err := imageapi.FollowTagReference(stream, tag) + finalTag, existing, multiple, err := followTagReferenceV1(stream, tag) switch err { case imageapi.ErrInvalidReference: return nil, fmt.Errorf("tag %q points to an invalid imagestreamtag", tag) @@ -348,8 +384,8 @@ func (o *ImportImageOptions) importTag(stream *imageapi.ImageStream) (*imageapi. if len(from) == 0 { return nil, fmt.Errorf("the tag %q does not exist on the image stream - choose an existing tag to import or use the 'tag' command to create a new tag", tag) } - existing = &imageapi.TagReference{ - From: &kapi.ObjectReference{ + existing = &imagev1.TagReference{ + From: &corev1.ObjectReference{ Kind: "DockerImage", Name: from, }, @@ -384,39 +420,55 @@ func (o *ImportImageOptions) importTag(stream *imageapi.ImageStream) (*imageapi. existing.Generation = &zero } - stream.Spec.Tags[tag] = *existing + + tagFound := false + for i := range stream.Spec.Tags { + if stream.Spec.Tags[i].Name == tag { + stream.Spec.Tags[i] = *existing + tagFound = true + break + } + } + + if !tagFound { + stream.Spec.Tags = append(stream.Spec.Tags, *existing) + } // and create accompanying ImageStreamImport return o.newImageStreamImportTags(stream, map[string]string{tag: from}), nil } -func (o *ImportImageOptions) newImageStream() (*imageapi.ImageStream, *imageapi.ImageStreamImport) { +func (o *ImportImageOptions) newImageStream() (*imagev1.ImageStream, *imagev1.ImageStreamImport) { from := o.From tag := o.Tag if len(from) == 0 { from = o.Target } var ( - stream *imageapi.ImageStream - isi *imageapi.ImageStreamImport + stream *imagev1.ImageStream + isi *imagev1.ImageStreamImport ) // create new ImageStream and accompanying ImageStreamImport // TODO: this should be removed along with the legacy path, we don't need to // create the IS in the new path, the import mechanism will do that for us, // this is only for the legacy path that we need to create the IS. if o.All { - stream = &imageapi.ImageStream{ + stream = &imagev1.ImageStream{ + // this is ok because we know exactly how we want to be serialized + TypeMeta: metav1.TypeMeta{APIVersion: imagev1.SchemeGroupVersion.String(), Kind: "ImageStream"}, ObjectMeta: metav1.ObjectMeta{Name: o.Name}, - Spec: imageapi.ImageStreamSpec{DockerImageRepository: from}, + Spec: imagev1.ImageStreamSpec{DockerImageRepository: from}, } isi = o.newImageStreamImportAll(stream, from) } else { - stream = &imageapi.ImageStream{ + stream = &imagev1.ImageStream{ + // this is ok because we know exactly how we want to be serialized + TypeMeta: metav1.TypeMeta{APIVersion: imagev1.SchemeGroupVersion.String(), Kind: "ImageStream"}, ObjectMeta: metav1.ObjectMeta{Name: o.Name}, - Spec: imageapi.ImageStreamSpec{ - Tags: map[string]imageapi.TagReference{ - tag: { - From: &kapi.ObjectReference{ + Spec: imagev1.ImageStreamSpec{ + Tags: []imagev1.TagReference{ + { + From: &corev1.ObjectReference{ Kind: "DockerImage", Name: from, }, @@ -431,28 +483,28 @@ func (o *ImportImageOptions) newImageStream() (*imageapi.ImageStream, *imageapi. return stream, isi } -func (o *ImportImageOptions) getReferencePolicy() imageapi.TagReferencePolicy { - ref := imageapi.TagReferencePolicy{} +func (o *ImportImageOptions) getReferencePolicy() imagev1.TagReferencePolicy { + ref := imagev1.TagReferencePolicy{} if len(o.ReferencePolicy) == 0 { return ref } switch o.ReferencePolicy { case tag.SourceReferencePolicy: - ref.Type = imageapi.SourceTagReferencePolicy + ref.Type = imagev1.SourceTagReferencePolicy case tag.LocalReferencePolicy: - ref.Type = imageapi.LocalTagReferencePolicy + ref.Type = imagev1.LocalTagReferencePolicy } return ref } -func (o *ImportImageOptions) newImageStreamImport(stream *imageapi.ImageStream) (*imageapi.ImageStreamImport, bool) { - isi := &imageapi.ImageStreamImport{ +func (o *ImportImageOptions) newImageStreamImport(stream *imagev1.ImageStream) (*imagev1.ImageStreamImport, bool) { + isi := &imagev1.ImageStreamImport{ ObjectMeta: metav1.ObjectMeta{ Name: stream.Name, Namespace: o.Namespace, ResourceVersion: stream.ResourceVersion, }, - Spec: imageapi.ImageStreamImportSpec{Import: !o.DryRun}, + Spec: imagev1.ImageStreamImportSpec{Import: !o.DryRun}, } insecureAnnotation := stream.Annotations[imageapi.InsecureRepositoryAnnotation] insecure := insecureAnnotation == "true" @@ -464,14 +516,14 @@ func (o *ImportImageOptions) newImageStreamImport(stream *imageapi.ImageStream) return isi, insecure } -func (o *ImportImageOptions) newImageStreamImportAll(stream *imageapi.ImageStream, from string) *imageapi.ImageStreamImport { +func (o *ImportImageOptions) newImageStreamImportAll(stream *imagev1.ImageStream, from string) *imagev1.ImageStreamImport { isi, insecure := o.newImageStreamImport(stream) - isi.Spec.Repository = &imageapi.RepositoryImportSpec{ - From: kapi.ObjectReference{ + isi.Spec.Repository = &imagev1.RepositoryImportSpec{ + From: corev1.ObjectReference{ Kind: "DockerImage", Name: from, }, - ImportPolicy: imageapi.TagImportPolicy{ + ImportPolicy: imagev1.TagImportPolicy{ Insecure: insecure, Scheduled: o.Scheduled, }, @@ -481,23 +533,33 @@ func (o *ImportImageOptions) newImageStreamImportAll(stream *imageapi.ImageStrea return isi } -func (o *ImportImageOptions) newImageStreamImportTags(stream *imageapi.ImageStream, tags map[string]string) *imageapi.ImageStreamImport { +func (o *ImportImageOptions) newImageStreamImportTags(stream *imagev1.ImageStream, tags map[string]string) *imagev1.ImageStreamImport { isi, streamInsecure := o.newImageStreamImport(stream) for tag, from := range tags { insecure := streamInsecure scheduled := o.Scheduled - oldTag, ok := stream.Spec.Tags[tag] - if ok { + + oldTagFound := false + var oldTag imagev1.TagReference + for _, t := range stream.Spec.Tags { + if t.Name == tag { + oldTag = t + oldTagFound = true + break + } + } + + if oldTagFound { insecure = insecure || oldTag.ImportPolicy.Insecure scheduled = scheduled || oldTag.ImportPolicy.Scheduled } - isi.Spec.Images = append(isi.Spec.Images, imageapi.ImageImportSpec{ - From: kapi.ObjectReference{ + isi.Spec.Images = append(isi.Spec.Images, imagev1.ImageImportSpec{ + From: corev1.ObjectReference{ Kind: "DockerImage", Name: from, }, - To: &kapi.LocalObjectReference{Name: tag}, - ImportPolicy: imageapi.TagImportPolicy{ + To: &corev1.LocalObjectReference{Name: tag}, + ImportPolicy: imagev1.TagImportPolicy{ Insecure: insecure, Scheduled: scheduled, }, @@ -506,3 +568,59 @@ func (o *ImportImageOptions) newImageStreamImportTags(stream *imageapi.ImageStre } return isi } + +// followTagReferenceV1 walks through the defined tags on a stream, following any referential tags in the stream. +// Will return multiple if the tag had at least reference, and ref and finalTag will be the last tag seen. +// If an invalid reference is found, err will be returned. +func followTagReferenceV1(stream *imagev1.ImageStream, tag string) (finalTag string, ref *imagev1.TagReference, multiple bool, err error) { + seen := sets.NewString() + for { + if seen.Has(tag) { + // circular reference + return tag, nil, multiple, imageapi.ErrCircularReference + } + seen.Insert(tag) + + tagRefFound := false + var tagRef imagev1.TagReference + for _, t := range stream.Spec.Tags { + if t.Name == tag { + tagRef = t + tagRefFound = true + break + } + } + + if !tagRefFound { + // no tag at the end of the rainbow + return tag, nil, multiple, imageapi.ErrNotFoundReference + } + if tagRef.From == nil || tagRef.From.Kind != "ImageStreamTag" { + // terminating tag + return tag, &tagRef, multiple, nil + } + + if tagRef.From.Namespace != "" && tagRef.From.Namespace != stream.ObjectMeta.Namespace { + return tag, nil, multiple, imageapi.ErrCrossImageStreamReference + } + + // The reference needs to be followed with two format patterns: + // a) sameis:sometag and b) sometag + if strings.Contains(tagRef.From.Name, ":") { + name, tagref, ok := imageapi.SplitImageStreamTag(tagRef.From.Name) + if !ok { + return tag, nil, multiple, imageapi.ErrInvalidReference + } + if name != stream.ObjectMeta.Name { + // anotheris:sometag - this should not happen. + return tag, nil, multiple, imageapi.ErrCrossImageStreamReference + } + // sameis:sometag - follow the reference as sometag + tag = tagref + } else { + // sometag - follow the reference + tag = tagRef.From.Name + } + multiple = true + } +} diff --git a/pkg/oc/cli/importimage/importimage_test.go b/pkg/oc/cli/importimage/importimage_test.go index 4ff94a4cf887..dd99cee22a30 100644 --- a/pkg/oc/cli/importimage/importimage_test.go +++ b/pkg/oc/cli/importimage/importimage_test.go @@ -4,14 +4,13 @@ import ( "strings" "testing" - "github.com/spf13/cobra" - + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - kapi "k8s.io/kubernetes/pkg/apis/core" kapihelper "k8s.io/kubernetes/pkg/apis/core/helper" - imageapi "github.com/openshift/origin/pkg/image/apis/image" - imagefake "github.com/openshift/origin/pkg/image/generated/internalclientset/fake" + imagev1 "github.com/openshift/api/image/v1" + imagefake "github.com/openshift/client-go/image/clientset/versioned/fake" + internalimageapi "github.com/openshift/origin/pkg/image/apis/image" "github.com/openshift/origin/pkg/oc/cli/tag" ) @@ -19,15 +18,15 @@ func TestCreateImageImport(t *testing.T) { testCases := map[string]struct { name string from string - stream *imageapi.ImageStream + stream *imagev1.ImageStream all bool confirm bool scheduled bool insecure *bool referencePolicy string err string - expectedImages []imageapi.ImageImportSpec - expectedRepository *imageapi.RepositoryImportSpec + expectedImages []imagev1.ImageImportSpec + expectedRepository *imagev1.RepositoryImportSpec }{ "import from non-existing": { name: "nonexisting", @@ -36,40 +35,40 @@ func TestCreateImageImport(t *testing.T) { "confirmed import from non-existing": { name: "nonexisting", confirm: true, - expectedImages: []imageapi.ImageImportSpec{{ - From: kapi.ObjectReference{Kind: "DockerImage", Name: "nonexisting"}, - To: &kapi.LocalObjectReference{Name: "latest"}, + expectedImages: []imagev1.ImageImportSpec{{ + From: corev1.ObjectReference{Kind: "DockerImage", Name: "nonexisting"}, + To: &corev1.LocalObjectReference{Name: "latest"}, }}, }, "confirmed import all from non-existing": { name: "nonexisting", all: true, confirm: true, - expectedRepository: &imageapi.RepositoryImportSpec{ - From: kapi.ObjectReference{Kind: "DockerImage", Name: "nonexisting"}, + expectedRepository: &imagev1.RepositoryImportSpec{ + From: corev1.ObjectReference{Kind: "DockerImage", Name: "nonexisting"}, }, }, "import from .spec.dockerImageRepository": { name: "testis", - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{Name: "testis", Namespace: "other"}, - Spec: imageapi.ImageStreamSpec{ + Spec: imagev1.ImageStreamSpec{ DockerImageRepository: "repo.com/somens/someimage", - Tags: make(map[string]imageapi.TagReference), + Tags: []imagev1.TagReference{}, }, }, - expectedImages: []imageapi.ImageImportSpec{{ - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage"}, - To: &kapi.LocalObjectReference{Name: "latest"}, + expectedImages: []imagev1.ImageImportSpec{{ + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage"}, + To: &corev1.LocalObjectReference{Name: "latest"}, }}, }, "import from .spec.dockerImageRepository non-existing tag": { name: "testis:nonexisting", - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{Name: "testis", Namespace: "other"}, - Spec: imageapi.ImageStreamSpec{ + Spec: imagev1.ImageStreamSpec{ DockerImageRepository: "repo.com/somens/someimage", - Tags: make(map[string]imageapi.TagReference), + Tags: []imagev1.TagReference{}, }, }, err: `"nonexisting" does not exist on the image stream`, @@ -77,15 +76,15 @@ func TestCreateImageImport(t *testing.T) { "import all from .spec.dockerImageRepository": { name: "testis", all: true, - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{Name: "testis", Namespace: "other"}, - Spec: imageapi.ImageStreamSpec{ + Spec: imagev1.ImageStreamSpec{ DockerImageRepository: "repo.com/somens/someimage", - Tags: make(map[string]imageapi.TagReference), + Tags: []imagev1.TagReference{}, }, }, - expectedRepository: &imageapi.RepositoryImportSpec{ - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage"}, + expectedRepository: &imagev1.RepositoryImportSpec{ + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage"}, }, }, "import all from .spec.dockerImageRepository with different from": { @@ -93,11 +92,11 @@ func TestCreateImageImport(t *testing.T) { from: "totally_different_spec", all: true, err: "different import spec", - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{Name: "testis", Namespace: "other"}, - Spec: imageapi.ImageStreamSpec{ + Spec: imagev1.ImageStreamSpec{ DockerImageRepository: "repo.com/somens/someimage", - Tags: make(map[string]imageapi.TagReference), + Tags: []imagev1.TagReference{}, }, }, }, @@ -106,66 +105,66 @@ func TestCreateImageImport(t *testing.T) { from: "totally/different/spec", all: true, confirm: true, - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{Name: "testis", Namespace: "other"}, - Spec: imageapi.ImageStreamSpec{ + Spec: imagev1.ImageStreamSpec{ DockerImageRepository: "repo.com/somens/someimage", - Tags: make(map[string]imageapi.TagReference), + Tags: []imagev1.TagReference{}, }, }, - expectedRepository: &imageapi.RepositoryImportSpec{ - From: kapi.ObjectReference{Kind: "DockerImage", Name: "totally/different/spec"}, + expectedRepository: &imagev1.RepositoryImportSpec{ + From: corev1.ObjectReference{Kind: "DockerImage", Name: "totally/different/spec"}, }, }, "import all from .spec.tags": { name: "testis", all: true, - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{Name: "testis", Namespace: "other"}, - Spec: imageapi.ImageStreamSpec{ - Tags: map[string]imageapi.TagReference{ - "latest": {From: &kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:latest"}}, - "other": {From: &kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:other"}}, + Spec: imagev1.ImageStreamSpec{ + Tags: []imagev1.TagReference{ + {Name: "latest", From: &corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:latest"}}, + {Name: "other", From: &corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:other"}}, }, }, }, - expectedImages: []imageapi.ImageImportSpec{ + expectedImages: []imagev1.ImageImportSpec{ { - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:latest"}, - To: &kapi.LocalObjectReference{Name: "latest"}, + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:latest"}, + To: &corev1.LocalObjectReference{Name: "latest"}, }, { - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:other"}, - To: &kapi.LocalObjectReference{Name: "other"}, + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:other"}, + To: &corev1.LocalObjectReference{Name: "other"}, }, }, }, "import all from .spec.tags with insecure annotation": { name: "testis", all: true, - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{ Name: "testis", Namespace: "other", - Annotations: map[string]string{imageapi.InsecureRepositoryAnnotation: "true"}, + Annotations: map[string]string{internalimageapi.InsecureRepositoryAnnotation: "true"}, }, - Spec: imageapi.ImageStreamSpec{ - Tags: map[string]imageapi.TagReference{ - "latest": {From: &kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:latest"}}, - "other": {From: &kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:other"}}, + Spec: imagev1.ImageStreamSpec{ + Tags: []imagev1.TagReference{ + {Name: "latest", From: &corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:latest"}}, + {Name: "other", From: &corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:other"}}, }, }, }, - expectedImages: []imageapi.ImageImportSpec{ + expectedImages: []imagev1.ImageImportSpec{ { - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:latest"}, - To: &kapi.LocalObjectReference{Name: "latest"}, - ImportPolicy: imageapi.TagImportPolicy{Insecure: true}, + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:latest"}, + To: &corev1.LocalObjectReference{Name: "latest"}, + ImportPolicy: imagev1.TagImportPolicy{Insecure: true}, }, { - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:other"}, - To: &kapi.LocalObjectReference{Name: "other"}, - ImportPolicy: imageapi.TagImportPolicy{Insecure: true}, + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:other"}, + To: &corev1.LocalObjectReference{Name: "other"}, + ImportPolicy: imagev1.TagImportPolicy{Insecure: true}, }, }, }, @@ -173,25 +172,25 @@ func TestCreateImageImport(t *testing.T) { name: "testis", all: true, insecure: newBool(true), - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{Name: "testis", Namespace: "other"}, - Spec: imageapi.ImageStreamSpec{ - Tags: map[string]imageapi.TagReference{ - "latest": {From: &kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:latest"}}, - "other": {From: &kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:other"}}, + Spec: imagev1.ImageStreamSpec{ + Tags: []imagev1.TagReference{ + {Name: "latest", From: &corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:latest"}}, + {Name: "other", From: &corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:other"}}, }, }, }, - expectedImages: []imageapi.ImageImportSpec{ + expectedImages: []imagev1.ImageImportSpec{ { - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:latest"}, - To: &kapi.LocalObjectReference{Name: "latest"}, - ImportPolicy: imageapi.TagImportPolicy{Insecure: true}, + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:latest"}, + To: &corev1.LocalObjectReference{Name: "latest"}, + ImportPolicy: imagev1.TagImportPolicy{Insecure: true}, }, { - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:other"}, - To: &kapi.LocalObjectReference{Name: "other"}, - ImportPolicy: imageapi.TagImportPolicy{Insecure: true}, + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:other"}, + To: &corev1.LocalObjectReference{Name: "other"}, + ImportPolicy: imagev1.TagImportPolicy{Insecure: true}, }, }, }, @@ -199,11 +198,11 @@ func TestCreateImageImport(t *testing.T) { name: "testis", all: true, err: "does not have tags pointing to external docker images", - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{Name: "testis", Namespace: "other"}, - Spec: imageapi.ImageStreamSpec{ - Tags: map[string]imageapi.TagReference{ - "latest": {From: &kapi.ObjectReference{Kind: "ImageStreamTag", Name: "otheris:latest"}}, + Spec: imagev1.ImageStreamSpec{ + Tags: []imagev1.TagReference{ + {Name: "latest", From: &corev1.ObjectReference{Kind: "ImageStreamTag", Name: "otheris:latest"}}, }, }, }, @@ -211,112 +210,114 @@ func TestCreateImageImport(t *testing.T) { "empty image stream": { name: "testis", err: "the tag \"latest\" does not exist on the image stream - choose an existing tag to import or use the 'tag' command to create a new tag", - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{Name: "testis", Namespace: "other"}, }, }, "import latest tag": { name: "testis:latest", - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{ Name: "testis", Namespace: "other", }, - Spec: imageapi.ImageStreamSpec{ - Tags: map[string]imageapi.TagReference{ - "latest": {From: &kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:latest"}}, + Spec: imagev1.ImageStreamSpec{ + Tags: []imagev1.TagReference{ + {Name: "latest", From: &corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:latest"}}, }, }, }, - expectedImages: []imageapi.ImageImportSpec{{ - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:latest"}, - To: &kapi.LocalObjectReference{Name: "latest"}, + expectedImages: []imagev1.ImageImportSpec{{ + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:latest"}, + To: &corev1.LocalObjectReference{Name: "latest"}, }}, }, "import existing tag": { name: "testis:existing", - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{ Name: "testis", Namespace: "other", }, - Spec: imageapi.ImageStreamSpec{ - Tags: map[string]imageapi.TagReference{ - "existing": {From: &kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:latest"}}, + Spec: imagev1.ImageStreamSpec{ + Tags: []imagev1.TagReference{ + {Name: "existing", From: &corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:latest"}}, }, }, }, - expectedImages: []imageapi.ImageImportSpec{{ - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:latest"}, - To: &kapi.LocalObjectReference{Name: "existing"}, + expectedImages: []imagev1.ImageImportSpec{{ + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:latest"}, + To: &corev1.LocalObjectReference{Name: "existing"}, }}, }, "import non-existing tag": { name: "testis:latest", err: "does not exist on the image stream", - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{ Name: "testis", Namespace: "other", }, - Spec: imageapi.ImageStreamSpec{ - Tags: map[string]imageapi.TagReference{ - "nonlatest": {From: &kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:latest"}}, + Spec: imagev1.ImageStreamSpec{ + Tags: []imagev1.TagReference{ + {Name: "nonlatest", From: &corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:latest"}}, }, }, }, }, "import tag from .spec.tags": { name: "testis:mytag", - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{ Name: "testis", Namespace: "other", }, - Spec: imageapi.ImageStreamSpec{ - Tags: map[string]imageapi.TagReference{ - "mytag": { - From: &kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, + Spec: imagev1.ImageStreamSpec{ + Tags: []imagev1.TagReference{ + { + Name: "mytag", + From: &corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, }, }, }, }, - expectedImages: []imageapi.ImageImportSpec{{ - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, - To: &kapi.LocalObjectReference{Name: "mytag"}, + expectedImages: []imagev1.ImageImportSpec{{ + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, + To: &corev1.LocalObjectReference{Name: "mytag"}, }}, }, "use tag aliases": { name: "testis:mytag", - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{ Name: "testis", Namespace: "other", }, - Spec: imageapi.ImageStreamSpec{ - Tags: map[string]imageapi.TagReference{ - "mytag": {From: &kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}}, - "other1": {From: &kapi.ObjectReference{Kind: "ImageStreamTag", Name: "testis:mytag"}}, - "other2": {From: &kapi.ObjectReference{Kind: "ImageStreamTag", Name: "mytag"}}, + Spec: imagev1.ImageStreamSpec{ + Tags: []imagev1.TagReference{ + {Name: "mytag", From: &corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}}, + {Name: "other1", From: &corev1.ObjectReference{Kind: "ImageStreamTag", Name: "testis:mytag"}}, + {Name: "other2", From: &corev1.ObjectReference{Kind: "ImageStreamTag", Name: "mytag"}}, }, }, }, - expectedImages: []imageapi.ImageImportSpec{{ - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, - To: &kapi.LocalObjectReference{Name: "mytag"}, + expectedImages: []imagev1.ImageImportSpec{{ + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, + To: &corev1.LocalObjectReference{Name: "mytag"}, }}, }, "import tag from alias of cross-image-stream": { name: "testis:mytag", - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{ Name: "testis", Namespace: "other", }, - Spec: imageapi.ImageStreamSpec{ - Tags: map[string]imageapi.TagReference{ - "mytag": { - From: &kapi.ObjectReference{Kind: "ImageStreamTag", Name: "otherimage:mytag"}, + Spec: imagev1.ImageStreamSpec{ + Tags: []imagev1.TagReference{ + { + Name: "mytag", + From: &corev1.ObjectReference{Kind: "ImageStreamTag", Name: "otherimage:mytag"}, }, }, }, @@ -325,15 +326,16 @@ func TestCreateImageImport(t *testing.T) { }, "import tag from alias of circular reference": { name: "testis:mytag", - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{ Name: "testis", Namespace: "other", }, - Spec: imageapi.ImageStreamSpec{ - Tags: map[string]imageapi.TagReference{ - "mytag": { - From: &kapi.ObjectReference{Kind: "ImageStreamTag", Name: "mytag"}, + Spec: imagev1.ImageStreamSpec{ + Tags: []imagev1.TagReference{ + { + Name: "mytag", + From: &corev1.ObjectReference{Kind: "ImageStreamTag", Name: "mytag"}, }, }, }, @@ -342,15 +344,16 @@ func TestCreateImageImport(t *testing.T) { }, "import tag from non existing alias": { name: "testis:mytag", - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{ Name: "testis", Namespace: "other", }, - Spec: imageapi.ImageStreamSpec{ - Tags: map[string]imageapi.TagReference{ - "mytag": { - From: &kapi.ObjectReference{Kind: "ImageStreamTag", Name: "nonexisting"}, + Spec: imagev1.ImageStreamSpec{ + Tags: []imagev1.TagReference{ + { + Name: "mytag", + From: &corev1.ObjectReference{Kind: "ImageStreamTag", Name: "nonexisting"}, }, }, }, @@ -359,85 +362,86 @@ func TestCreateImageImport(t *testing.T) { }, "use insecure annotation": { name: "testis", - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{ Name: "testis", Namespace: "other", - Annotations: map[string]string{imageapi.InsecureRepositoryAnnotation: "true"}, + Annotations: map[string]string{internalimageapi.InsecureRepositoryAnnotation: "true"}, }, - Spec: imageapi.ImageStreamSpec{ + Spec: imagev1.ImageStreamSpec{ DockerImageRepository: "repo.com/somens/someimage", - Tags: make(map[string]imageapi.TagReference), + Tags: []imagev1.TagReference{}, }, }, - expectedImages: []imageapi.ImageImportSpec{{ - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage"}, - To: &kapi.LocalObjectReference{Name: "latest"}, - ImportPolicy: imageapi.TagImportPolicy{Insecure: true}, + expectedImages: []imagev1.ImageImportSpec{{ + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage"}, + To: &corev1.LocalObjectReference{Name: "latest"}, + ImportPolicy: imagev1.TagImportPolicy{Insecure: true}, }}, }, "insecure flag overrides insecure annotation": { name: "testis", insecure: newBool(false), - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{ Name: "testis", Namespace: "other", - Annotations: map[string]string{imageapi.InsecureRepositoryAnnotation: "true"}, + Annotations: map[string]string{internalimageapi.InsecureRepositoryAnnotation: "true"}, }, - Spec: imageapi.ImageStreamSpec{ + Spec: imagev1.ImageStreamSpec{ DockerImageRepository: "repo.com/somens/someimage", - Tags: make(map[string]imageapi.TagReference), + Tags: []imagev1.TagReference{}, }, }, - expectedImages: []imageapi.ImageImportSpec{{ - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage"}, - To: &kapi.LocalObjectReference{Name: "latest"}, - ImportPolicy: imageapi.TagImportPolicy{Insecure: false}, + expectedImages: []imagev1.ImageImportSpec{{ + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage"}, + To: &corev1.LocalObjectReference{Name: "latest"}, + ImportPolicy: imagev1.TagImportPolicy{Insecure: false}, }}, }, "import tag setting referencePolicy": { name: "testis:mytag", referencePolicy: tag.LocalReferencePolicy, - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{Name: "testis", Namespace: "other"}, - Spec: imageapi.ImageStreamSpec{ - Tags: map[string]imageapi.TagReference{ - "mytag": { - From: &kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, + Spec: imagev1.ImageStreamSpec{ + Tags: []imagev1.TagReference{ + { + Name: "mytag", + From: &corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, }, }, }, }, - expectedImages: []imageapi.ImageImportSpec{{ - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, - To: &kapi.LocalObjectReference{Name: "mytag"}, - ReferencePolicy: imageapi.TagReferencePolicy{Type: imageapi.LocalTagReferencePolicy}, + expectedImages: []imagev1.ImageImportSpec{{ + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, + To: &corev1.LocalObjectReference{Name: "mytag"}, + ReferencePolicy: imagev1.TagReferencePolicy{Type: imagev1.LocalTagReferencePolicy}, }}, }, "import all from .spec.tags setting referencePolicy": { name: "testis", all: true, referencePolicy: tag.LocalReferencePolicy, - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{Name: "testis", Namespace: "other"}, - Spec: imageapi.ImageStreamSpec{ - Tags: map[string]imageapi.TagReference{ - "mytag": {From: &kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}}, - "other": {From: &kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:other"}}, + Spec: imagev1.ImageStreamSpec{ + Tags: []imagev1.TagReference{ + {Name: "mytag", From: &corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}}, + {Name: "other", From: &corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:other"}}, }, }, }, - expectedImages: []imageapi.ImageImportSpec{ + expectedImages: []imagev1.ImageImportSpec{ { - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, - To: &kapi.LocalObjectReference{Name: "mytag"}, - ReferencePolicy: imageapi.TagReferencePolicy{Type: imageapi.LocalTagReferencePolicy}, + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, + To: &corev1.LocalObjectReference{Name: "mytag"}, + ReferencePolicy: imagev1.TagReferencePolicy{Type: imagev1.LocalTagReferencePolicy}, }, { - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:other"}, - To: &kapi.LocalObjectReference{Name: "other"}, - ReferencePolicy: imageapi.TagReferencePolicy{Type: imageapi.LocalTagReferencePolicy}, + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:other"}, + To: &corev1.LocalObjectReference{Name: "other"}, + ReferencePolicy: imagev1.TagReferencePolicy{Type: imagev1.LocalTagReferencePolicy}, }, }, }, @@ -445,80 +449,82 @@ func TestCreateImageImport(t *testing.T) { name: "testis", all: true, referencePolicy: tag.LocalReferencePolicy, - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{Name: "testis", Namespace: "other"}, - Spec: imageapi.ImageStreamSpec{ + Spec: imagev1.ImageStreamSpec{ DockerImageRepository: "repo.com/somens/someimage", - Tags: make(map[string]imageapi.TagReference), + Tags: []imagev1.TagReference{}, }, }, - expectedRepository: &imageapi.RepositoryImportSpec{ - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage"}, - ReferencePolicy: imageapi.TagReferencePolicy{Type: imageapi.LocalTagReferencePolicy}, + expectedRepository: &imagev1.RepositoryImportSpec{ + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage"}, + ReferencePolicy: imagev1.TagReferencePolicy{Type: imagev1.LocalTagReferencePolicy}, }, }, "import tag setting scheduled": { name: "testis:mytag", scheduled: true, - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{Name: "testis", Namespace: "other"}, - Spec: imageapi.ImageStreamSpec{ - Tags: map[string]imageapi.TagReference{ - "mytag": { - From: &kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, + Spec: imagev1.ImageStreamSpec{ + Tags: []imagev1.TagReference{ + { + Name: "mytag", + From: &corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, }, }, }, }, - expectedImages: []imageapi.ImageImportSpec{{ - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, - To: &kapi.LocalObjectReference{Name: "mytag"}, - ImportPolicy: imageapi.TagImportPolicy{Scheduled: true}, + expectedImages: []imagev1.ImageImportSpec{{ + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, + To: &corev1.LocalObjectReference{Name: "mytag"}, + ImportPolicy: imagev1.TagImportPolicy{Scheduled: true}, }}, }, "import already scheduled tag without setting scheduled": { name: "testis:mytag", scheduled: false, - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{Name: "testis", Namespace: "other"}, - Spec: imageapi.ImageStreamSpec{ - Tags: map[string]imageapi.TagReference{ - "mytag": { - From: &kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, - ImportPolicy: imageapi.TagImportPolicy{Scheduled: true}, + Spec: imagev1.ImageStreamSpec{ + Tags: []imagev1.TagReference{ + { + Name: "mytag", + From: &corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, + ImportPolicy: imagev1.TagImportPolicy{Scheduled: true}, }, }, }, }, - expectedImages: []imageapi.ImageImportSpec{{ - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, - To: &kapi.LocalObjectReference{Name: "mytag"}, - ImportPolicy: imageapi.TagImportPolicy{Scheduled: true}, + expectedImages: []imagev1.ImageImportSpec{{ + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, + To: &corev1.LocalObjectReference{Name: "mytag"}, + ImportPolicy: imagev1.TagImportPolicy{Scheduled: true}, }}, }, "import all from .spec.tags setting scheduled": { name: "testis", all: true, scheduled: true, - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{Name: "testis", Namespace: "other"}, - Spec: imageapi.ImageStreamSpec{ - Tags: map[string]imageapi.TagReference{ - "mytag": {From: &kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}}, - "other": {From: &kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:other"}}, + Spec: imagev1.ImageStreamSpec{ + Tags: []imagev1.TagReference{ + {Name: "mytag", From: &corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}}, + {Name: "other", From: &corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:other"}}, }, }, }, - expectedImages: []imageapi.ImageImportSpec{ + expectedImages: []imagev1.ImageImportSpec{ { - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, - To: &kapi.LocalObjectReference{Name: "mytag"}, - ImportPolicy: imageapi.TagImportPolicy{Scheduled: true}, + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, + To: &corev1.LocalObjectReference{Name: "mytag"}, + ImportPolicy: imagev1.TagImportPolicy{Scheduled: true}, }, { - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:other"}, - To: &kapi.LocalObjectReference{Name: "other"}, - ImportPolicy: imageapi.TagImportPolicy{Scheduled: true}, + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:other"}, + To: &corev1.LocalObjectReference{Name: "other"}, + ImportPolicy: imagev1.TagImportPolicy{Scheduled: true}, }, }, }, @@ -526,28 +532,29 @@ func TestCreateImageImport(t *testing.T) { name: "testis", all: true, scheduled: false, - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{Name: "testis", Namespace: "other"}, - Spec: imageapi.ImageStreamSpec{ - Tags: map[string]imageapi.TagReference{ - "mytag": { - From: &kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, - ImportPolicy: imageapi.TagImportPolicy{Scheduled: true}, + Spec: imagev1.ImageStreamSpec{ + Tags: []imagev1.TagReference{ + { + Name: "mytag", + From: &corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, + ImportPolicy: imagev1.TagImportPolicy{Scheduled: true}, }, - "other": {From: &kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:other"}}, + {Name: "other", From: &corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:other"}}, }, }, }, - expectedImages: []imageapi.ImageImportSpec{ + expectedImages: []imagev1.ImageImportSpec{ { - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, - To: &kapi.LocalObjectReference{Name: "mytag"}, - ImportPolicy: imageapi.TagImportPolicy{Scheduled: true}, + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:mytag"}, + To: &corev1.LocalObjectReference{Name: "mytag"}, + ImportPolicy: imagev1.TagImportPolicy{Scheduled: true}, }, { - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:other"}, - To: &kapi.LocalObjectReference{Name: "other"}, - ImportPolicy: imageapi.TagImportPolicy{Scheduled: false}, + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage:other"}, + To: &corev1.LocalObjectReference{Name: "other"}, + ImportPolicy: imagev1.TagImportPolicy{Scheduled: false}, }, }, }, @@ -555,16 +562,16 @@ func TestCreateImageImport(t *testing.T) { name: "testis", all: true, scheduled: true, - stream: &imageapi.ImageStream{ + stream: &imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{Name: "testis", Namespace: "other"}, - Spec: imageapi.ImageStreamSpec{ + Spec: imagev1.ImageStreamSpec{ DockerImageRepository: "repo.com/somens/someimage", - Tags: make(map[string]imageapi.TagReference), + Tags: []imagev1.TagReference{}, }, }, - expectedRepository: &imageapi.RepositoryImportSpec{ - From: kapi.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage"}, - ImportPolicy: imageapi.TagImportPolicy{Scheduled: true}, + expectedRepository: &imagev1.RepositoryImportSpec{ + From: corev1.ObjectReference{Kind: "DockerImage", Name: "repo.com/somens/someimage"}, + ImportPolicy: imagev1.TagImportPolicy{Scheduled: true}, }, }, } @@ -591,9 +598,9 @@ func TestCreateImageImport(t *testing.T) { o.InsecureFlagProvided = true } - // we need to run Validate, because it sets appropriate Name and Tag - if err := o.Validate(&cobra.Command{}); err != nil { - t.Errorf("%s: unexpected error: %v", name, err) + if err := o.parseImageReference(); err != nil { + t.Errorf("unexpected error: %v", err) + continue } _, isi, err := o.createImageImport() @@ -623,17 +630,17 @@ func TestCreateImageImport(t *testing.T) { func TestWasError(t *testing.T) { testCases := map[string]struct { - isi *imageapi.ImageStreamImport + isi *imagev1.ImageStreamImport expected bool }{ "no error": { - isi: &imageapi.ImageStreamImport{}, + isi: &imagev1.ImageStreamImport{}, expected: false, }, "error importing images": { - isi: &imageapi.ImageStreamImport{ - Status: imageapi.ImageStreamImportStatus{ - Images: []imageapi.ImageImportStatus{ + isi: &imagev1.ImageStreamImport{ + Status: imagev1.ImageStreamImportStatus{ + Images: []imagev1.ImageImportStatus{ {Status: metav1.Status{Status: metav1.StatusFailure}}, }, }, @@ -641,9 +648,9 @@ func TestWasError(t *testing.T) { expected: true, }, "error importing repository": { - isi: &imageapi.ImageStreamImport{ - Status: imageapi.ImageStreamImportStatus{ - Repository: &imageapi.RepositoryImportStatus{ + isi: &imagev1.ImageStreamImport{ + Status: imagev1.ImageStreamImportStatus{ + Repository: &imagev1.RepositoryImportStatus{ Status: metav1.Status{Status: metav1.StatusFailure}, }, }, @@ -659,7 +666,7 @@ func TestWasError(t *testing.T) { } } -func listEqual(actual, expected []imageapi.ImageImportSpec) bool { +func listEqual(actual, expected []imagev1.ImageImportSpec) bool { if len(actual) != len(expected) { return false } diff --git a/test/cmd/images.sh b/test/cmd/images.sh index e7f2b843bc63..4bae8b7de48f 100755 --- a/test/cmd/images.sh +++ b/test/cmd/images.sh @@ -315,7 +315,7 @@ os::test::junit::declare_suite_start "cmd/images${IMAGES_TESTS_POSTFIX:-}/import os::cmd::expect_success 'oc new-project import-images' os::cmd::expect_success 'oc create secret docker-registry dummy-secret1 --docker-server=docker.io --docker-username=dummy1 --docker-password=dummy1 --docker-email==dummy1@example.com' os::cmd::expect_success 'oc create secret docker-registry dummy-secret2 --docker-server=docker.io --docker-username=dummy2 --docker-password=dummy2 --docker-email==dummy2@example.com' -os::cmd::expect_success_and_text 'oc import-image example --from=openshift/hello-openshift --confirm' 'The import completed successfully' +os::cmd::expect_success_and_text 'oc import-image example --from=openshift/hello-openshift --confirm' 'imagestream.image.openshift.io/example imported' os::cmd::expect_success 'oc delete project import-images' echo "import public images with fake secret ok" os::test::junit::declare_suite_end