예제 #1
0
// RunImportImage contains all the necessary functionality for the OpenShift cli import-image command.
func RunImportImage(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args []string) error {
	if len(args) == 0 || len(args[0]) == 0 {
		return cmdutil.UsageError(cmd, "you must specify the name of an image stream.")
	}

	streamName := args[0]
	namespace, _, err := f.DefaultNamespace()
	if err != nil {
		return err
	}

	osClient, _, err := f.Clients()
	if err != nil {
		return err
	}

	imageStreamClient := osClient.ImageStreams(namespace)
	stream, err := imageStreamClient.Get(streamName)
	if err != nil {
		return err
	}

	if len(stream.Spec.DockerImageRepository) == 0 {
		return errors.New("only image streams with spec.dockerImageRepository set may have images imported")
	}

	if stream.Annotations == nil {
		stream.Annotations = make(map[string]string)
	}
	stream.Annotations[imageapi.DockerImageRepositoryCheckAnnotation] = ""

	updatedStream, err := imageStreamClient.Update(stream)
	if err != nil {
		return err
	}

	resourceVersion := updatedStream.ResourceVersion

	fmt.Fprintln(cmd.Out(), "Waiting for the import to complete, CTRL+C to stop waiting.")

	updatedStream, err = waitForImport(imageStreamClient, stream.Name, resourceVersion)
	if err != nil {
		return fmt.Errorf("unable to determine if the import completed successfully - please run 'oc describe -n %s imagestream/%s' to see if the tags were updated as expected: %v", stream.Namespace, stream.Name, err)
	}

	fmt.Fprintln(cmd.Out(), "The import completed successfully.\n")

	d := describe.ImageStreamDescriber{osClient}
	info, err := d.Describe(updatedStream.Namespace, updatedStream.Name)
	if err != nil {
		return err
	}

	fmt.Fprintln(out, info)
	return nil
}
예제 #2
0
// RunImportImage contains all the necessary functionality for the OpenShift cli import-image command.
func RunImportImage(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args []string) error {
	if len(args) == 0 || len(args[0]) == 0 {
		return cmdutil.UsageError(cmd, "you must specify the name of an image stream")
	}

	streamName := args[0]
	namespace, _, err := f.DefaultNamespace()
	if err != nil {
		return err
	}

	osClient, _, err := f.Clients()
	if err != nil {
		return err
	}

	from := cmdutil.GetFlagString(cmd, "from")
	confirm := cmdutil.GetFlagBool(cmd, "confirm")

	imageStreamClient := osClient.ImageStreams(namespace)
	stream, err := imageStreamClient.Get(streamName)
	if err != nil {
		if len(from) == 0 || !errors.IsNotFound(err) {
			return err
		}
		if !confirm {
			return fmt.Errorf("the image stream does not exist, pass --confirm to create")
		}
		stream = &imageapi.ImageStream{
			ObjectMeta: kapi.ObjectMeta{Name: streamName},
			Spec:       imageapi.ImageStreamSpec{DockerImageRepository: from},
		}
	} else {
		if len(stream.Spec.DockerImageRepository) == 0 {
			if len(from) == 0 {
				return fmt.Errorf("only image streams with spec.dockerImageRepository set may have images imported")
			}
			if !confirm {
				return fmt.Errorf("the image stream already has an import repository set, pass --confirm to update")
			}
			stream.Spec.DockerImageRepository = from
		} else {
			if len(from) != 0 {
				if from != stream.Spec.DockerImageRepository {
					if !confirm {
						return fmt.Errorf("the image stream has a different import spec %q, pass --confirm to update", stream.Spec.DockerImageRepository)
					}
				}
			}
		}
	}

	if stream.Annotations != nil {
		delete(stream.Annotations, imageapi.DockerImageRepositoryCheckAnnotation)
	}

	if stream.CreationTimestamp.IsZero() {
		stream, err = imageStreamClient.Create(stream)
	} else {
		stream, err = imageStreamClient.Update(stream)
	}
	if err != nil {
		return err
	}

	resourceVersion := stream.ResourceVersion

	fmt.Fprintln(cmd.Out(), "Waiting for the import to complete, CTRL+C to stop waiting.")

	stream, err = waitForImport(imageStreamClient, stream.Name, resourceVersion)
	if err != nil {
		return fmt.Errorf("unable to determine if the import completed successfully - please run 'oc describe -n %s imagestream/%s' to see if the tags were updated as expected: %v", stream.Namespace, stream.Name, err)
	}

	fmt.Fprint(cmd.Out(), "The import completed successfully.", "\n\n")

	d := describe.ImageStreamDescriber{Interface: osClient}
	info, err := d.Describe(stream.Namespace, stream.Name)
	if err != nil {
		return err
	}

	fmt.Fprintln(out, info)
	return nil
}
예제 #3
0
// RunImportImage contains all the necessary functionality for the OpenShift cli import-image command.
func RunImportImage(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args []string) error {
	if len(args) == 0 || len(args[0]) == 0 {
		return cmdutil.UsageError(cmd, "you must specify the name of an image stream")
	}

	target := args[0]
	namespace, _, err := f.DefaultNamespace()
	if err != nil {
		return err
	}

	osClient, _, err := f.Clients()
	if err != nil {
		return err
	}

	insecure := cmdutil.GetFlagBool(cmd, "insecure")
	from := cmdutil.GetFlagString(cmd, "from")
	confirm := cmdutil.GetFlagBool(cmd, "confirm")
	all := cmdutil.GetFlagBool(cmd, "all")

	targetRef, err := imageapi.ParseDockerImageReference(target)
	switch {
	case err != nil:
		return fmt.Errorf("the image name must be a valid Docker image pull spec or reference to an image stream (e.g. myregistry/myteam/image:tag)")
	case len(targetRef.ID) > 0:
		return fmt.Errorf("to import images by ID, use the 'tag' command")
	case len(targetRef.Tag) != 0 && all:
		// error out
		return fmt.Errorf("cannot specify a tag %q as well as --all", target)
	case len(targetRef.Tag) == 0 && !all:
		// apply the default tag
		targetRef.Tag = imageapi.DefaultImageTag
	}
	name := targetRef.Name
	tag := targetRef.Tag

	imageStreamClient := osClient.ImageStreams(namespace)
	stream, err := imageStreamClient.Get(name)
	if err != nil {
		if !errors.IsNotFound(err) {
			return err
		}

		// the stream is new
		if !confirm {
			return fmt.Errorf("no image stream named %q exists, pass --confirm to create and import", name)
		}
		if len(from) == 0 {
			from = target
		}
		if all {
			stream = &imageapi.ImageStream{
				ObjectMeta: kapi.ObjectMeta{Name: name},
				Spec:       imageapi.ImageStreamSpec{DockerImageRepository: from},
			}
		} else {
			stream = &imageapi.ImageStream{
				ObjectMeta: kapi.ObjectMeta{Name: name},
				Spec: imageapi.ImageStreamSpec{
					Tags: map[string]imageapi.TagReference{
						tag: {
							From: &kapi.ObjectReference{
								Kind: "DockerImage",
								Name: from,
							},
						},
					},
				},
			}
		}

	} else {
		// the stream already exists
		if len(stream.Spec.DockerImageRepository) == 0 && len(stream.Spec.Tags) == 0 {
			return fmt.Errorf("image stream has not defined anything to import")
		}

		if all {
			// importing a whole repository
			if len(from) == 0 {
				from = target
			}
			if from != stream.Spec.DockerImageRepository {
				if !confirm {
					if len(stream.Spec.DockerImageRepository) == 0 {
						return fmt.Errorf("the image stream does not currently import an entire Docker repository, pass --confirm to update")
					}
					return fmt.Errorf("the image stream has a different import spec %q, pass --confirm to update", stream.Spec.DockerImageRepository)
				}
				stream.Spec.DockerImageRepository = from
			}

		} else {
			// importing a single tag

			// follow any referential tags to the destination
			finalTag, existing, ok, multiple := imageapi.FollowTagReference(stream, tag)
			if !ok && multiple {
				return fmt.Errorf("tag %q on the image stream is a reference to %q, which does not exist", tag, finalTag)
			}

			if ok {
				// disallow changing an existing tag
				if existing.From == nil || existing.From.Kind != "DockerImage" {
					return fmt.Errorf("tag %q already exists - you must use the 'tag' command if you want to change the source to %q", tag, from)
				}
				if len(from) != 0 && from != existing.From.Name {
					if multiple {
						return fmt.Errorf("the tag %q points to the tag %q which points to %q - use the 'tag' command if you want to change the source to %q", tag, finalTag, existing.From.Name, from)
					}
					return fmt.Errorf("the tag %q points to %q - use the 'tag' command if you want to change the source to %q", tag, existing.From.Name, from)
				}

				// set the target item to import
				from = existing.From.Name
				if multiple {
					tag = finalTag
				}

				// clear the legacy annotation
				delete(existing.Annotations, imageapi.DockerImageRepositoryCheckAnnotation)
				// reset the generation
				zero := int64(0)
				existing.Generation = &zero

			} else {
				// create a new tag
				if len(from) == 0 {
					from = target
				}
				existing = &imageapi.TagReference{
					From: &kapi.ObjectReference{
						Kind: "DockerImage",
						Name: from,
					},
				}
			}
			stream.Spec.Tags[tag] = *existing
		}
	}

	if len(from) == 0 {
		// catch programmer error
		return fmt.Errorf("unexpected error, from is empty")
	}

	// Attempt the new, direct import path
	isi := &imageapi.ImageStreamImport{
		ObjectMeta: kapi.ObjectMeta{
			Name:            stream.Name,
			Namespace:       namespace,
			ResourceVersion: stream.ResourceVersion,
		},
		Spec: imageapi.ImageStreamImportSpec{Import: true},
	}
	if all {
		isi.Spec.Repository = &imageapi.RepositoryImportSpec{
			From: kapi.ObjectReference{
				Kind: "DockerImage",
				Name: from,
			},
			ImportPolicy: imageapi.TagImportPolicy{Insecure: insecure},
		}
	} else {
		isi.Spec.Images = append(isi.Spec.Images, imageapi.ImageImportSpec{
			From: kapi.ObjectReference{
				Kind: "DockerImage",
				Name: from,
			},
			To:           &kapi.LocalObjectReference{Name: tag},
			ImportPolicy: imageapi.TagImportPolicy{Insecure: insecure},
		})
	}

	// TODO: add dry-run
	_, err = imageStreamClient.Import(isi)
	switch {
	case err == client.ErrImageStreamImportUnsupported:
	case err != nil:
		return err
	default:
		fmt.Fprint(cmd.Out(), "The import completed successfully.\n\n")

		// optimization, use the image stream returned by the call
		d := describe.ImageStreamDescriber{Interface: osClient}
		info, err := d.Describe(namespace, stream.Name)
		if err != nil {
			return err
		}

		fmt.Fprintln(out, info)
		return nil
	}

	// Legacy path, remove when support for older importers is removed
	delete(stream.Annotations, imageapi.DockerImageRepositoryCheckAnnotation)
	if insecure {
		if stream.Annotations == nil {
			stream.Annotations = make(map[string]string)
		}
		stream.Annotations[imageapi.InsecureRepositoryAnnotation] = "true"
	}

	if stream.CreationTimestamp.IsZero() {
		stream, err = imageStreamClient.Create(stream)
	} else {
		stream, err = imageStreamClient.Update(stream)
	}
	if err != nil {
		return err
	}

	resourceVersion := stream.ResourceVersion

	fmt.Fprintln(cmd.Out(), "Importing (ctrl+c to stop waiting) ...")

	updatedStream, err := waitForImport(imageStreamClient, stream.Name, resourceVersion)
	if err != nil {
		if _, ok := err.(importError); ok {
			return err
		}
		return fmt.Errorf("unable to determine if the import completed successfully - please run 'oc describe -n %s imagestream/%s' to see if the tags were updated as expected: %v", stream.Namespace, stream.Name, err)
	}

	fmt.Fprint(cmd.Out(), "The import completed successfully.\n\n")

	d := describe.ImageStreamDescriber{Interface: osClient}
	info, err := d.Describe(updatedStream.Namespace, updatedStream.Name)
	if err != nil {
		return err
	}

	fmt.Fprintln(out, info)
	return nil
}
예제 #4
0
// Run contains all the necessary functionality for the OpenShift cli import-image command.
func (o *ImportImageOptions) Run() error {
	// TODO: add dry-run
	stream, isi, err := o.createImageImport()
	if err != nil {
		return err
	}

	// Attempt the new, direct import path
	result, err := o.isClient.Import(isi)
	switch {
	case err == client.ErrImageStreamImportUnsupported:
	case err != nil:
		return err
	default:
		fmt.Fprint(o.out, "The import completed successfully.\n\n")

		// optimization, use the image stream returned by the call
		d := describe.ImageStreamDescriber{Interface: o.osClient}
		info, err := d.Describe(o.Namespace, stream.Name, kctl.DescriberSettings{})
		if err != nil {
			return err
		}

		fmt.Fprintln(o.out, info)

		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, ", "))
		}
		return nil
	}

	// Legacy path, remove when support for older importers is removed
	delete(stream.Annotations, imageapi.DockerImageRepositoryCheckAnnotation)
	if o.Insecure != nil && *o.Insecure {
		if stream.Annotations == nil {
			stream.Annotations = make(map[string]string)
		}
		stream.Annotations[imageapi.InsecureRepositoryAnnotation] = "true"
	}

	if stream.CreationTimestamp.IsZero() {
		stream, err = o.isClient.Create(stream)
	} else {
		stream, err = o.isClient.Update(stream)
	}
	if err != nil {
		return err
	}

	fmt.Fprintln(o.out, "Importing (ctrl+c to stop waiting) ...")

	resourceVersion := stream.ResourceVersion
	updatedStream, err := o.waitForImport(resourceVersion)
	if err != nil {
		if _, ok := err.(importError); ok {
			return err
		}
		return fmt.Errorf("unable to determine if the import completed successfully - please run 'oc describe -n %s imagestream/%s' to see if the tags were updated as expected: %v", stream.Namespace, stream.Name, err)
	}

	fmt.Fprint(o.out, "The import completed successfully.\n\n")

	d := describe.ImageStreamDescriber{Interface: o.osClient}
	info, err := d.Describe(updatedStream.Namespace, updatedStream.Name, kctl.DescriberSettings{})
	if err != nil {
		return err
	}

	fmt.Fprintln(o.out, info)
	return nil
}