Example #1
0
// FromStream generates an ImageRef from an OpenShift ImageStream
func (g *imageRefGenerator) FromStream(stream *imageapi.ImageStream, tag string) (*ImageRef, error) {
	imageRef := &ImageRef{
		Stream: stream,
	}

	if tagged := imageapi.LatestTaggedImage(stream, tag); tagged != nil {
		if ref, err := imageapi.ParseDockerImageReference(tagged.DockerImageReference); err == nil {
			imageRef.ResolvedReference = &ref
			imageRef.Reference = ref
		}
	}

	if pullSpec := stream.Status.DockerImageRepository; len(pullSpec) != 0 {
		ref, err := imageapi.ParseDockerImageReference(pullSpec)
		if err != nil {
			return nil, err
		}
		imageRef.Reference = ref
	}
	switch {
	case len(tag) > 0:
		imageRef.Reference.Tag = tag
	case len(tag) == 0 && len(imageRef.Reference.Tag) == 0:
		imageRef.Reference.Tag = imageapi.DefaultImageTag
	}

	return imageRef, nil
}
Example #2
0
// getImageReferenceForObjectReference returns corresponding docker image reference for the given object
// reference representing either an image stream image or image stream tag or docker image.
func (c *GenericImageStreamUsageComputer) getImageReferenceForObjectReference(
	namespace string,
	objRef *kapi.ObjectReference,
) (imageapi.DockerImageReference, error) {
	switch objRef.Kind {
	case "ImageStreamImage":
		nameParts := strings.Split(objRef.Name, "@")
		if len(nameParts) != 2 {
			return imageapi.DockerImageReference{}, fmt.Errorf("failed to parse name of imageStreamImage %q", objRef.Name)
		}
		res, err := imageapi.ParseDockerImageReference(objRef.Name)
		if err != nil {
			return imageapi.DockerImageReference{}, err
		}
		if res.Namespace == "" {
			res.Namespace = objRef.Namespace
		}
		if res.Namespace == "" {
			res.Namespace = namespace
		}
		return res, nil

	case "ImageStreamTag":
		// This is really fishy. An admission check can be easily worked around by setting a tag reference
		// to an ImageStreamTag with no or small image and then tagging a large image to the source tag.
		// TODO: Shall we refuse an ImageStreamTag set in the spec if the quota is set?
		nameParts := strings.Split(objRef.Name, ":")
		if len(nameParts) != 2 {
			return imageapi.DockerImageReference{}, fmt.Errorf("failed to parse name of imageStreamTag %q", objRef.Name)
		}

		ns := namespace
		if len(objRef.Namespace) > 0 {
			ns = objRef.Namespace
		}

		isName := nameParts[0]
		is, err := c.getImageStream(ns, isName)
		if err != nil {
			return imageapi.DockerImageReference{}, fmt.Errorf("failed to get imageStream for ImageStreamTag %s/%s: %v", ns, objRef.Name, err)
		}

		event := imageapi.LatestTaggedImage(is, nameParts[1])
		if event == nil || len(event.DockerImageReference) == 0 {
			return imageapi.DockerImageReference{}, fmt.Errorf("%q is not currently pointing to an image, cannot use it as the source of a tag", objRef.Name)
		}
		return imageapi.ParseDockerImageReference(event.DockerImageReference)

	case "DockerImage":
		managedByOS, ref := imageReferenceBelongsToInternalRegistry(objRef.Name)
		if !managedByOS {
			return imageapi.DockerImageReference{}, fmt.Errorf("DockerImage %s does not belong to internal registry", objRef.Name)
		}
		return ref, nil
	}

	return imageapi.DockerImageReference{}, fmt.Errorf("unsupported object reference kind %s", objRef.Kind)
}
Example #3
0
func ValidateImageStreamImport(isi *api.ImageStreamImport) field.ErrorList {
	specPath := field.NewPath("spec")
	imagesPath := specPath.Child("images")
	repoPath := specPath.Child("repository")

	errs := field.ErrorList{}
	for i, spec := range isi.Spec.Images {
		from := spec.From
		switch from.Kind {
		case "DockerImage":
			if spec.To != nil && len(spec.To.Name) == 0 {
				errs = append(errs, field.Invalid(imagesPath.Index(i).Child("to", "name"), spec.To.Name, "the name of the target tag must be specified"))
			}
			if len(spec.From.Name) == 0 {
				errs = append(errs, field.Required(imagesPath.Index(i).Child("from", "name"), ""))
			} else {
				if ref, err := api.ParseDockerImageReference(spec.From.Name); err != nil {
					errs = append(errs, field.Invalid(imagesPath.Index(i).Child("from", "name"), spec.From.Name, err.Error()))
				} else {
					if len(ref.ID) > 0 && spec.ImportPolicy.Scheduled {
						errs = append(errs, field.Invalid(imagesPath.Index(i).Child("from", "name"), spec.From.Name, "only tags can be scheduled for import"))
					}
				}
			}
		default:
			errs = append(errs, field.Invalid(imagesPath.Index(i).Child("from", "kind"), from.Kind, "only DockerImage is supported"))
		}
	}

	if spec := isi.Spec.Repository; spec != nil {
		from := spec.From
		switch from.Kind {
		case "DockerImage":
			if len(spec.From.Name) == 0 {
				errs = append(errs, field.Required(repoPath.Child("from", "name"), ""))
			} else {
				if ref, err := api.ParseDockerImageReference(from.Name); err != nil {
					errs = append(errs, field.Invalid(repoPath.Child("from", "name"), from.Name, err.Error()))
				} else {
					if len(ref.ID) > 0 || len(ref.Tag) > 0 {
						errs = append(errs, field.Invalid(repoPath.Child("from", "name"), from.Name, "you must specify an image repository, not a tag or ID"))
					}
				}
			}
		default:
			errs = append(errs, field.Invalid(repoPath.Child("from", "kind"), from.Kind, "only DockerImage is supported"))
		}
	}
	if len(isi.Spec.Images) == 0 && isi.Spec.Repository == nil {
		errs = append(errs, field.Invalid(imagesPath, nil, "you must specify at least one image or a repository import"))
	}

	errs = append(errs, validation.ValidateObjectMeta(&isi.ObjectMeta, true, ValidateImageStreamName, field.NewPath("metadata"))...)
	return errs
}
Example #4
0
// ValidateImageStream tests required fields for an ImageStream.
func ValidateImageStream(stream *api.ImageStream) field.ErrorList {
	result := validation.ValidateObjectMeta(&stream.ObjectMeta, true, ValidateImageStreamName, field.NewPath("metadata"))

	// Ensure we can generate a valid docker image repository from namespace/name
	if len(stream.Namespace+"/"+stream.Name) > reference.NameTotalLengthMax {
		result = append(result, field.Invalid(field.NewPath("metadata", "name"), stream.Name, fmt.Sprintf("'namespace/name' cannot be longer than %d characters", reference.NameTotalLengthMax)))
	}

	if stream.Spec.Tags == nil {
		stream.Spec.Tags = make(map[string]api.TagReference)
	}

	if len(stream.Spec.DockerImageRepository) != 0 {
		dockerImageRepositoryPath := field.NewPath("spec", "dockerImageRepository")
		if ref, err := api.ParseDockerImageReference(stream.Spec.DockerImageRepository); err != nil {
			result = append(result, field.Invalid(dockerImageRepositoryPath, stream.Spec.DockerImageRepository, err.Error()))
		} else {
			if len(ref.Tag) > 0 {
				result = append(result, field.Invalid(dockerImageRepositoryPath, stream.Spec.DockerImageRepository, "the repository name may not contain a tag"))
			}
			if len(ref.ID) > 0 {
				result = append(result, field.Invalid(dockerImageRepositoryPath, stream.Spec.DockerImageRepository, "the repository name may not contain an ID"))
			}
		}
	}
	for tag, tagRef := range stream.Spec.Tags {
		if tagRef.From != nil {
			switch tagRef.From.Kind {
			case "DockerImage":
				if ref, err := api.ParseDockerImageReference(tagRef.From.Name); err == nil && tagRef.ImportPolicy.Scheduled && len(ref.ID) > 0 {
					result = append(result, field.Invalid(field.NewPath("spec", "tags").Key(tag).Child("from", "name"), tagRef.From.Name, "only tags can be scheduled for import"))
				}
			case "ImageStreamImage", "ImageStreamTag":
				if tagRef.ImportPolicy.Scheduled {
					result = append(result, field.Invalid(field.NewPath("spec", "tags").Key(tag).Child("importPolicy", "scheduled"), tagRef.ImportPolicy.Scheduled, "only tags pointing to Docker repositories may be scheduled for background import"))
				}
			default:
				result = append(result, field.Invalid(field.NewPath("spec", "tags").Key(tag).Child("from", "kind"), tagRef.From.Kind, "valid values are 'DockerImage', 'ImageStreamImage', 'ImageStreamTag'"))
			}
		}
	}
	for tag, history := range stream.Status.Tags {
		for i, tagEvent := range history.Items {
			if len(tagEvent.DockerImageReference) == 0 {
				result = append(result, field.Required(field.NewPath("status", "tags").Key(tag).Child("items").Index(i).Child("dockerImageReference")))
			}
		}
	}

	return result
}
Example #5
0
func convert_v1_DeploymentTriggerImageChangeParams_To_api_DeploymentTriggerImageChangeParams(in *DeploymentTriggerImageChangeParams, out *newer.DeploymentTriggerImageChangeParams, s conversion.Scope) error {
	out.Automatic = in.Automatic
	out.ContainerNames = make([]string, len(in.ContainerNames))
	copy(out.ContainerNames, in.ContainerNames)
	out.LastTriggeredImage = in.LastTriggeredImage
	if err := s.Convert(&in.From, &out.From, 0); err != nil {
		return err
	}
	switch in.From.Kind {
	case "DockerImage":
		ref, err := imageapi.ParseDockerImageReference(in.From.Name)
		if err != nil {
			return err
		}
		out.Tag = ref.Tag
		ref.Tag, ref.ID = "", ""
		out.RepositoryName = ref.String()
	case "ImageStreamTag":
		name, tag, ok := imageapi.SplitImageStreamTag(in.From.Name)
		if !ok {
			return fmt.Errorf("ImageStreamTag object references must be in the form <name>:<tag>: %s", in.From.Name)
		}
		out.From.Kind = "ImageStream"
		out.From.Name = name
		out.Tag = tag
	}
	return nil
}
Example #6
0
func (o *TriggersOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command, args []string) error {
	cmdNamespace, explicit, err := f.DefaultNamespace()
	if err != nil {
		return err
	}

	if !cmd.Flags().Lookup("from-github").Changed {
		o.FromGitHub = nil
	}
	if !cmd.Flags().Lookup("from-webhook").Changed {
		o.FromWebHook = nil
	}
	if !cmd.Flags().Lookup("from-webhook-allow-env").Changed {
		o.FromWebHookAllowEnv = nil
	}

	if len(o.FromImage) > 0 {
		ref, err := imageapi.ParseDockerImageReference(o.FromImage)
		if err != nil {
			return fmt.Errorf("the value of --from-image does not appear to be a valid reference to an image: %v", err)
		}
		if len(ref.Registry) > 0 || len(ref.ID) > 0 {
			return fmt.Errorf("the value of --from-image must point to an image stream tag on this server")
		}
		if len(ref.Tag) == 0 {
			return fmt.Errorf("the value of --from-image must include the tag you wish to pull from")
		}
		o.FromImage = ref.NameString()
		o.FromImageNamespace = defaultNamespace(ref.Namespace, cmdNamespace)
	}

	count := o.count()
	o.Reset = count == 0 && (o.Auto || o.Manual)
	switch {
	case count == 0 && !o.Remove && !o.RemoveAll && !o.Auto && !o.Manual:
		o.PrintTable = true
	case !o.RemoveAll && !o.Auto && !o.Manual:
		o.Auto = true
	}

	mapper, typer := f.Object(false)
	o.Builder = resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), kapi.Codecs.UniversalDecoder()).
		ContinueOnError().
		NamespaceParam(cmdNamespace).DefaultNamespace().
		FilenameParam(explicit, false, o.Filenames...).
		SelectorParam(o.Selector).
		ResourceTypeOrNameArgs(o.All, args...).
		Flatten()

	output := kcmdutil.GetFlagString(cmd, "output")
	if len(output) != 0 {
		o.PrintObject = func(obj runtime.Object) error { return f.PrintObject(cmd, mapper, obj, o.Out) }
	}

	o.Encoder = f.JSONEncoder()
	o.ShortOutput = kcmdutil.GetFlagString(cmd, "output") == "name"
	o.Mapper = mapper

	return nil
}
Example #7
0
// setupBuildEnv injects human-friendly environment variables which provides
// useful information about the current build.
func setupBuildEnv(build *buildapi.Build, pod *kapi.Pod) error {
	vars := []kapi.EnvVar{}

	switch {
	case build.Spec.Source.Git != nil:
		vars = append(vars, kapi.EnvVar{Name: "SOURCE_URI", Value: build.Spec.Source.Git.URI})
		vars = append(vars, kapi.EnvVar{Name: "SOURCE_REF", Value: build.Spec.Source.Git.Ref})
	default:
		// Do nothing for unknown source types
	}

	if build.Spec.Output.To != nil {
		// output much always be a DockerImage type reference at this point.
		ref, err := imageapi.ParseDockerImageReference(build.Spec.Output.To.Name)
		if err != nil {
			return err
		}
		vars = append(vars, kapi.EnvVar{Name: "OUTPUT_REGISTRY", Value: ref.Registry})
		ref.Registry = ""
		vars = append(vars, kapi.EnvVar{Name: "OUTPUT_IMAGE", Value: ref.String()})
	}

	if len(pod.Spec.Containers) > 0 {
		pod.Spec.Containers[0].Env = append(pod.Spec.Containers[0].Env, vars...)
	}
	return nil
}
Example #8
0
// ResolveObjectReference converts a reference into an image API or returns an error. If the kind is not recognized
// this method will return an error to prevent references that may be images from being ignored.
func (c *imageResolutionCache) ResolveObjectReference(ref *kapi.ObjectReference, defaultNamespace string) (*rules.ImagePolicyAttributes, error) {
	switch ref.Kind {
	case "ImageStreamTag":
		ns := ref.Namespace
		if len(ns) == 0 {
			ns = defaultNamespace
		}
		name, tag, ok := imageapi.SplitImageStreamTag(ref.Name)
		if !ok {
			return &rules.ImagePolicyAttributes{IntegratedRegistry: true}, fmt.Errorf("references of kind ImageStreamTag must be of the form NAME:TAG")
		}
		return c.resolveImageStreamTag(ns, name, tag)

	case "ImageStreamImage":
		ns := ref.Namespace
		if len(ns) == 0 {
			ns = defaultNamespace
		}
		name, id, ok := imageapi.SplitImageStreamImage(ref.Name)
		if !ok {
			return &rules.ImagePolicyAttributes{IntegratedRegistry: true}, fmt.Errorf("references of kind ImageStreamImage must be of the form NAME@DIGEST")
		}
		return c.resolveImageStreamImage(ns, name, id)

	case "DockerImage":
		ref, err := imageapi.ParseDockerImageReference(ref.Name)
		if err != nil {
			return nil, err
		}
		return c.resolveImageReference(ref)

	default:
		return nil, fmt.Errorf("image policy does not allow image references of kind %q", ref.Kind)
	}
}
Example #9
0
// EnsureDockerRepositoryNode adds the named Docker repository tag reference to the graph if it does
// not already exist. If the reference is invalid, the Name field of the graph will be used directly.
func EnsureDockerRepositoryNode(g osgraph.MutableUniqueGraph, name, tag string) graph.Node {
	ref, err := imageapi.ParseDockerImageReference(name)
	if err == nil {
		if len(tag) != 0 {
			ref.Tag = tag
		}
		if len(ref.Tag) == 0 {
			ref.Tag = imageapi.DefaultImageTag
		}
		if len(ref.Registry) == 0 {
			ref.Registry = "docker.io"
		}
		if len(ref.Namespace) == 0 {
			ref.Namespace = imageapi.DockerDefaultNamespace
		}
	} else {
		ref = imageapi.DockerImageReference{Name: name}
	}

	return osgraph.EnsureUnique(g,
		DockerImageRepositoryNodeName(ref),
		func(node osgraph.Node) graph.Node {
			return &DockerImageRepositoryNode{node, ref}
		},
	)
}
Example #10
0
func validateOutput(output *buildapi.BuildOutput) fielderrors.ValidationErrorList {
	allErrs := fielderrors.ValidationErrorList{}

	// TODO: make part of a generic ValidateObjectReference method upstream.
	if output.To != nil {
		kind, name, namespace := output.To.Kind, output.To.Name, output.To.Namespace
		if len(kind) == 0 {
			kind = "ImageStream"
			output.To.Kind = kind
		}
		if kind != "ImageStream" {
			allErrs = append(allErrs, fielderrors.NewFieldInvalid("to.kind", kind, "the target of build output must be 'ImageStream'"))
		}
		if len(name) == 0 {
			allErrs = append(allErrs, fielderrors.NewFieldRequired("to.name"))
		} else if !util.IsDNS1123Subdomain(name) {
			allErrs = append(allErrs, fielderrors.NewFieldInvalid("to.name", name, "name must be a valid subdomain"))
		}
		if len(namespace) != 0 && !util.IsDNS1123Subdomain(namespace) {
			allErrs = append(allErrs, fielderrors.NewFieldInvalid("to.namespace", namespace, "namespace must be a valid subdomain"))
		}
	}

	allErrs = append(allErrs, validateSecretRef(output.PushSecret).Prefix("pushSecret")...)

	if len(output.DockerImageReference) != 0 {
		if _, err := imageapi.ParseDockerImageReference(output.DockerImageReference); err != nil {
			allErrs = append(allErrs, fielderrors.NewFieldInvalid("dockerImageReference", output.DockerImageReference, err.Error()))
		}
	}

	return allErrs
}
Example #11
0
func imageref(name string) imageapi.DockerImageReference {
	ref, err := imageapi.ParseDockerImageReference(name)
	if err != nil {
		panic(err)
	}
	return ref
}
Example #12
0
// DockerRepository adds the named Docker repository tag reference to the graph if it does
// not already exist. If the reference is invalid, the Name field of the graph will be
// used directly.
func DockerRepository(g MutableUniqueGraph, name, tag string) graph.Node {
	ref, err := image.ParseDockerImageReference(name)
	if err == nil {
		if len(tag) != 0 {
			ref.Tag = tag
		}
		if len(ref.Tag) == 0 {
			ref.Tag = image.DefaultImageTag
		}
		if len(ref.Registry) == 0 {
			ref.Registry = "docker.io"
		}
		if len(ref.Namespace) == 0 {
			ref.Namespace = image.DockerDefaultNamespace
		}
		// TODO: canonicalize
		name = ref.String()
	} else {
		ref = image.DockerImageReference{Name: name}
	}
	return EnsureUnique(g,
		UniqueName(fmt.Sprintf("%d|%s", DockerRepositoryGraphKind, name)),
		func(node Node) graph.Node {
			return &DockerImageRepositoryNode{node, ref}
		},
	)
}
Example #13
0
// ValidateImageStream tests required fields for an ImageStream.
func ValidateImageStream(stream *api.ImageStream) field.ErrorList {
	result := validation.ValidateObjectMeta(&stream.ObjectMeta, true, ValidateImageStreamName, field.NewPath("metadata"))

	// Ensure we can generate a valid docker image repository from namespace/name
	if len(stream.Namespace+"/"+stream.Name) > reference.NameTotalLengthMax {
		result = append(result, field.Invalid(field.NewPath("metadata", "name"), stream.Name, fmt.Sprintf("'namespace/name' cannot be longer than %d characters", reference.NameTotalLengthMax)))
	}

	if len(stream.Spec.DockerImageRepository) != 0 {
		dockerImageRepositoryPath := field.NewPath("spec", "dockerImageRepository")
		if ref, err := api.ParseDockerImageReference(stream.Spec.DockerImageRepository); err != nil {
			result = append(result, field.Invalid(dockerImageRepositoryPath, stream.Spec.DockerImageRepository, err.Error()))
		} else {
			if len(ref.Tag) > 0 {
				result = append(result, field.Invalid(dockerImageRepositoryPath, stream.Spec.DockerImageRepository, "the repository name may not contain a tag"))
			}
			if len(ref.ID) > 0 {
				result = append(result, field.Invalid(dockerImageRepositoryPath, stream.Spec.DockerImageRepository, "the repository name may not contain an ID"))
			}
		}
	}
	for tag, tagRef := range stream.Spec.Tags {
		path := field.NewPath("spec", "tags").Key(tag)
		result = append(result, ValidateImageStreamTagReference(tagRef, path)...)
	}
	for tag, history := range stream.Status.Tags {
		for i, tagEvent := range history.Items {
			if len(tagEvent.DockerImageReference) == 0 {
				result = append(result, field.Required(field.NewPath("status", "tags").Key(tag).Child("items").Index(i).Child("dockerImageReference"), ""))
			}
		}
	}

	return result
}
Example #14
0
// validImageStreamImage will cycle through the imageStream.Status.Tags.[]TagEvent.DockerImageReference and  determine whether an image with the hexadecimal image id
// associated with an ImageStreamImage reference in fact exists in a given ImageStream; on return, this method returns a true if does exist, and as well as the hexadecimal image
// id from the ImageStreamImage, as well as the appropriate message to add to the marker if the image was not found
func validImageStreamImage(imageNode *imagegraph.ImageStreamImageNode, imageStream *imageapi.ImageStream) (bool, string, string) {
	dockerImageReference, err := imageapi.ParseDockerImageReference(imageNode.Name)
	if err == nil {
		for _, tagEventList := range imageStream.Status.Tags {
			for _, tagEvent := range tagEventList.Items {
				if strings.Contains(tagEvent.DockerImageReference, dockerImageReference.ID) {
					return true, dockerImageReference.ID, ""
				}
			}
		}
	}

	// check the images stream to see if any import images are in flight or have failed
	annotation, ok := imageStream.Annotations[imageapi.DockerImageRepositoryCheckAnnotation]
	if !ok {
		return false, dockerImageReference.ID, "import the image with hexadecimal ID %s into the image stream %s"
	}

	if checkTime, err := time.Parse(time.RFC3339, annotation); err == nil {
		// this time based annotation is set by pkg/image/controller/controller.go whenever import/tag operations are performed; unless
		// in the midst of an import/tag operation, it stays set and serves as a timestamp for when the last operation occurred;
		// so we will check if the image stream has been updated "recently";
		// in case it is a slow link to the remote repo, see if if the check annotation occured within the last 5 minutes; if so, consider that as potentially "in progress"
		compareTime := checkTime.Add(5 * time.Minute)
		currentTime, _ := time.Parse(time.RFC3339, unversioned.Now().UTC().Format(time.RFC3339))
		if compareTime.Before(currentTime) {
			return false, dockerImageReference.ID, "import the image with hexadecimal ID %s into the image stream %s"
		}

		return false, dockerImageReference.ID, "a import of the image with hexadecimal ID %s into the image stream %s could be in progress; check again after a couple of minutes"

	}
	return false, dockerImageReference.ID, "an error occurred importing the image with hexadecimal ID %s into the image stream %s; inspect the images stream annotations for details"
}
Example #15
0
// ValidateImageStreamMapping tests required fields for an ImageStreamMapping.
func ValidateImageStreamMapping(mapping *api.ImageStreamMapping) field.ErrorList {
	result := validation.ValidateObjectMeta(&mapping.ObjectMeta, true, oapi.MinimalNameRequirements, field.NewPath("metadata"))

	hasRepository := len(mapping.DockerImageRepository) != 0
	hasName := len(mapping.Name) != 0
	switch {
	case hasRepository:
		if _, err := api.ParseDockerImageReference(mapping.DockerImageRepository); err != nil {
			result = append(result, field.Invalid(field.NewPath("dockerImageRepository"), mapping.DockerImageRepository, err.Error()))
		}
	case hasName:
	default:
		result = append(result, field.Required(field.NewPath("name"), ""))
		result = append(result, field.Required(field.NewPath("dockerImageRepository"), ""))
	}

	if ok, msg := validation.ValidateNamespaceName(mapping.Namespace, false); !ok {
		result = append(result, field.Invalid(field.NewPath("metadata", "namespace"), mapping.Namespace, msg))
	}
	if len(mapping.Tag) == 0 {
		result = append(result, field.Required(field.NewPath("tag"), ""))
	}
	if errs := validateImage(&mapping.Image, field.NewPath("image")); len(errs) != 0 {
		result = append(result, errs...)
	}
	return result
}
Example #16
0
func convert_v1_BuildOutput_To_api_BuildOutput(in *BuildOutput, out *newer.BuildOutput, s conversion.Scope) error {
	if err := s.DefaultConvert(in, out, conversion.IgnoreMissingFields); err != nil {
		return err
	}
	if in.To != nil && in.To.Kind == "ImageStreamTag" {
		name, tag, ok := imageapi.SplitImageStreamTag(in.To.Name)
		if !ok {
			return fmt.Errorf("ImageStreamTag object references must be in the form <name>:<tag>: %s", in.To.Name)
		}
		out.To.Kind = "ImageStream"
		out.To.Name = name
		out.Tag = tag
		return nil
	}
	if in.To != nil && in.To.Kind == "DockerImage" {
		out.To = nil
		if ref, err := imageapi.ParseDockerImageReference(in.To.Name); err == nil {
			out.Tag = ref.Tag
			ref.Tag = ""
			out.DockerImageReference = ref.String()
		} else {
			out.DockerImageReference = in.To.Name
		}
	}
	return nil
}
Example #17
0
func addPodSpecToGraph(g graph.Graph, spec *kapi.PodSpec, predecessor gonum.Node) {
	for j := range spec.Containers {
		container := spec.Containers[j]

		glog.V(4).Infof("Examining container image %q", container.Image)
		ref, err := imageapi.ParseDockerImageReference(container.Image)
		if err != nil {
			glog.V(2).Infof("Unable to parse DockerImageReference %q: %v - skipping", container.Image, err)
			continue
		}

		if len(ref.ID) == 0 {
			// ignore not managed images
			continue
		}

		imageNode := imagegraph.FindImage(g, ref.ID)
		if imageNode == nil {
			glog.V(1).Infof("Unable to find image %q in the graph", ref.ID)
			continue
		}

		glog.V(4).Infof("Adding edge from %v to %v", predecessor, imageNode)
		g.AddEdge(predecessor, imageNode, PodImageEdgeKind)
	}
}
Example #18
0
func validateToImageReference(reference *kapi.ObjectReference) fielderrors.ValidationErrorList {
	allErrs := fielderrors.ValidationErrorList{}
	kind, name, namespace := reference.Kind, reference.Name, reference.Namespace
	switch kind {
	case "ImageStreamTag":
		if len(name) == 0 {
			allErrs = append(allErrs, fielderrors.NewFieldRequired("name"))
		} else if _, _, ok := imageapi.SplitImageStreamTag(name); !ok {
			allErrs = append(allErrs, fielderrors.NewFieldInvalid("name", name, "ImageStreamTag object references must be in the form <name>:<tag>"))
		}
		if len(namespace) != 0 && !kvalidation.IsDNS1123Subdomain(namespace) {
			allErrs = append(allErrs, fielderrors.NewFieldInvalid("namespace", namespace, "namespace must be a valid subdomain"))
		}

	case "DockerImage":
		if len(namespace) != 0 {
			allErrs = append(allErrs, fielderrors.NewFieldInvalid("namespace", namespace, "namespace is not valid when used with a 'DockerImage'"))
		}
		if _, err := imageapi.ParseDockerImageReference(name); err != nil {
			allErrs = append(allErrs, fielderrors.NewFieldInvalid("name", name, fmt.Sprintf("name is not a valid Docker pull specification: %v", err)))
		}
	case "":
		allErrs = append(allErrs, fielderrors.NewFieldRequired("kind"))
	default:
		allErrs = append(allErrs, fielderrors.NewFieldInvalid("kind", kind, "the target of build output must be an 'ImageStreamTag' or 'DockerImage'"))

	}
	return allErrs
}
Example #19
0
// imageReferenceBelongsToInternalRegistry returns true if the given docker image reference refers to an
// image in an internal registry.
func imageReferenceBelongsToInternalRegistry(dockerImageReference string) (bool, imageapi.DockerImageReference) {
	ref, err := imageapi.ParseDockerImageReference(dockerImageReference)
	if err != nil || len(ref.Registry) == 0 || len(ref.Namespace) == 0 || len(ref.Name) == 0 {
		return false, ref
	}
	return internalRegistryNames.Has(ref.Registry), ref
}
Example #20
0
// addOutputEnvVars adds env variables that provide information about the output
// target for the build
func addOutputEnvVars(buildOutput *kapi.ObjectReference, output *[]kapi.EnvVar) error {
	if buildOutput == nil {
		return nil
	}

	// output must always be a DockerImage type reference at this point.
	if buildOutput.Kind != "DockerImage" {
		return fmt.Errorf("invalid build output kind %s, must be DockerImage", buildOutput.Kind)
	}
	ref, err := imageapi.ParseDockerImageReference(buildOutput.Name)
	if err != nil {
		return err
	}
	registry := ref.Registry
	ref.Registry = ""
	image := ref.String()

	outputVars := []kapi.EnvVar{
		{Name: "OUTPUT_REGISTRY", Value: registry},
		{Name: "OUTPUT_IMAGE", Value: image},
	}

	*output = append(*output, outputVars...)
	return nil
}
// identifyCandidateRepositories returns a map of remote repositories referenced by this image stream.
func identifyCandidateRepositories(is *imageapi.ImageStream, localRegistry string, primary bool) map[string]*imageapi.DockerImageReference {
	// identify the canonical location of referenced registries to search
	search := make(map[string]*imageapi.DockerImageReference)
	for _, tagEvent := range is.Status.Tags {
		var candidates []imageapi.TagEvent
		if primary {
			if len(tagEvent.Items) == 0 {
				continue
			}
			candidates = tagEvent.Items[:1]
		} else {
			if len(tagEvent.Items) <= 1 {
				continue
			}
			candidates = tagEvent.Items[1:]
		}
		for _, event := range candidates {
			ref, err := imageapi.ParseDockerImageReference(event.DockerImageReference)
			if err != nil {
				continue
			}
			// skip anything that matches the innate registry
			// TODO: there may be a better way to make this determination
			if len(localRegistry) != 0 && localRegistry == ref.Registry {
				continue
			}
			ref = ref.DockerClientDefaults()
			search[ref.AsRepository().Exact()] = &ref
		}
	}
	return search
}
Example #22
0
// MapReference transforms the provided Docker image reference if any mapping matches the
// input. If the reference cannot be parsed, it will not be modified.
func (m ImageReferenceMappings) MapReference(in string) string {
	ref, err := imageapi.ParseDockerImageReference(in)
	if err != nil {
		return in
	}
	registry := ref.DockerClientDefaults().Registry
	name := ref.RepositoryName()
	for _, mapping := range m {
		if len(mapping.FromRegistry) > 0 && mapping.FromRegistry != registry {
			continue
		}
		if len(mapping.FromName) > 0 && mapping.FromName != name {
			continue
		}
		if len(mapping.ToRegistry) > 0 {
			ref.Registry = mapping.ToRegistry
		}
		if len(mapping.ToName) > 0 {
			ref.Namespace = ""
			ref.Name = mapping.ToName
		}
		return ref.Exact()
	}
	return in
}
Example #23
0
// Edges are added to the graph from each predecessor (pod or replication
// controller) to the images specified by the pod spec's list of containers, as
// long as the image is managed by OpenShift.
func addPodSpecToGraph(g graph.Graph, spec *kapi.PodSpec, predecessor gonum.Node) {
	for j := range spec.Containers {
		container := spec.Containers[j]

		glog.V(4).Infof("Examining container image %q", container.Image)

		ref, err := imageapi.ParseDockerImageReference(container.Image)
		if err != nil {
			util.HandleError(fmt.Errorf("unable to parse DockerImageReference %q: %v", container.Image, err))
			continue
		}

		if len(ref.ID) == 0 {
			glog.V(4).Infof("%q has no image ID", container.Image)
			continue
		}

		imageNode := imagegraph.FindImage(g, ref.ID)
		if imageNode == nil {
			glog.Infof("Unable to find image %q in the graph", ref.ID)
			continue
		}

		glog.V(4).Infof("Adding edge from pod to image")
		g.AddEdge(predecessor, imageNode, ReferencedImageEdgeKind)
	}
}
// Search searches in the Docker registry for images that match terms
func (r DockerRegistrySearcher) Search(terms ...string) (ComponentMatches, error) {
	componentMatches := ComponentMatches{}
	for _, term := range terms {
		ref, err := imageapi.ParseDockerImageReference(term)
		if err != nil {
			return nil, err
		}

		glog.V(4).Infof("checking Docker registry for %q, allow-insecure=%v", ref.String(), r.AllowInsecure)
		connection, err := r.Client.Connect(ref.Registry, r.AllowInsecure)
		if err != nil {
			if dockerregistry.IsRegistryNotFound(err) {
				return nil, ErrNoMatch{value: term}
			}
			return nil, fmt.Errorf("can't connect to %q: %v", ref.Registry, err)
		}

		image, err := connection.ImageByTag(ref.Namespace, ref.Name, ref.Tag)
		if err != nil {
			if dockerregistry.IsNotFound(err) {
				if dockerregistry.IsTagNotFound(err) {
					glog.V(4).Infof("tag not found: %v", err)
				}
				continue
			}
			return nil, fmt.Errorf("can't connect to %q: %v", ref.Registry, err)
		}

		if len(ref.Tag) == 0 {
			ref.Tag = imageapi.DefaultImageTag
		}
		if len(ref.Registry) == 0 {
			ref.Registry = "Docker Hub"
		}
		glog.V(4).Infof("found image: %#v", image)

		dockerImage := &imageapi.DockerImage{}
		if err = kapi.Scheme.Convert(&image.Image, dockerImage); err != nil {
			return nil, err
		}

		match := &ComponentMatch{
			Value:       term,
			Argument:    fmt.Sprintf("--docker-image=%q", term),
			Name:        term,
			Description: descriptionFor(dockerImage, term, ref.Registry, ref.Tag),
			Score:       0,
			Image:       dockerImage,
			ImageTag:    ref.Tag,
			Insecure:    r.AllowInsecure,
			Meta:        map[string]string{"registry": ref.Registry},
		}
		glog.V(2).Infof("Adding %s as component match for %q with score %v", match.Description, term, match.Score)
		componentMatches = append(componentMatches, match)
	}

	return componentMatches, nil
}
Example #25
0
func SetDefaults_ImageImportSpec(obj *ImageImportSpec) {
	if obj.To == nil {
		if ref, err := newer.ParseDockerImageReference(obj.From.Name); err == nil {
			if len(ref.Tag) > 0 {
				obj.To = &v1.LocalObjectReference{Name: ref.Tag}
			}
		}
	}
}
Example #26
0
// AddImageStreamImageRefEdge ensures that a directed edge exists between an ImageStreamImage Node and the IS it references
func AddImageStreamImageRefEdge(g osgraph.MutableUniqueGraph, node *imagegraph.ImageStreamImageNode) {
	dockImgRef, _ := imageapi.ParseDockerImageReference(node.Name)
	imageStream := &imageapi.ImageStream{}
	imageStream.Namespace = node.Namespace
	imageStream.Name = dockImgRef.Name

	imageStreamNode := imagegraph.FindOrCreateSyntheticImageStreamNode(g, imageStream)
	g.AddEdge(node, imageStreamNode, ReferencedImageStreamImageGraphEdgeKind)
}
Example #27
0
// FromName generates an ImageRef from a given name
func (g *imageRefGenerator) FromName(name string) (*ImageRef, error) {
	ref, err := imageapi.ParseDockerImageReference(name)
	if err != nil {
		return nil, err
	}
	return &ImageRef{
		DockerImageReference: ref,
	}, nil
}
Example #28
0
// addBuildParameters checks if a Image is set to replace the default base image.
// If that's the case then change the Dockerfile to make the build with the given image.
// Also append the environment variables and labels in the Dockerfile.
func (d *DockerBuilder) addBuildParameters(dir string) error {
	dockerfilePath := filepath.Join(dir, "Dockerfile")
	if d.build.Spec.Strategy.DockerStrategy != nil && len(d.build.Spec.Source.ContextDir) > 0 {
		dockerfilePath = filepath.Join(dir, d.build.Spec.Source.ContextDir, "Dockerfile")
	}

	f, err := os.Open(dockerfilePath)
	if err != nil {
		return err
	}

	// Parse the Dockerfile.
	node, err := parser.Parse(f)
	if err != nil {
		return err
	}

	// Update base image if build strategy specifies the From field.
	if d.build.Spec.Strategy.DockerStrategy.From != nil && d.build.Spec.Strategy.DockerStrategy.From.Kind == "DockerImage" {
		// Reduce the name to a minimal canonical form for the daemon
		name := d.build.Spec.Strategy.DockerStrategy.From.Name
		if ref, err := imageapi.ParseDockerImageReference(name); err == nil {
			name = ref.DaemonMinimal().String()
		}
		err := replaceLastFrom(node, name)
		if err != nil {
			return err
		}
	}

	// Append build info as environment variables.
	err = appendEnv(node, d.buildInfo())
	if err != nil {
		return err
	}

	// Append build labels.
	err = appendLabel(node, d.buildLabels(dir))
	if err != nil {
		return err
	}

	// Insert environment variables defined in the build strategy.
	err = insertEnvAfterFrom(node, d.build.Spec.Strategy.DockerStrategy.Env)
	if err != nil {
		return err
	}

	instructions := dockerfile.ParseTreeToDockerfile(node)

	// Overwrite the Dockerfile.
	fi, err := f.Stat()
	if err != nil {
		return err
	}
	return ioutil.WriteFile(dockerfilePath, instructions, fi.Mode())
}
Example #29
0
func ValidateImageStreamImport(isi *api.ImageStreamImport) fielderrors.ValidationErrorList {
	errs := fielderrors.ValidationErrorList{}
	for i, spec := range isi.Spec.Images {
		from := spec.From
		switch from.Kind {
		case "DockerImage":
			if spec.To != nil && len(spec.To.Name) == 0 {
				errs = append(errs, fielderrors.ValidationErrorList{fielderrors.NewFieldInvalid("to.name", spec.To.Name, "the name of the target tag must be specified")}.PrefixIndex(i)...)
			}
			if len(spec.From.Name) == 0 {
				errs = append(errs, fielderrors.ValidationErrorList{fielderrors.NewFieldRequired("from.name")}.PrefixIndex(i)...)
			} else {
				if _, err := api.ParseDockerImageReference(spec.From.Name); err != nil {
					errs = append(errs, fielderrors.ValidationErrorList{fielderrors.NewFieldInvalid("from.name", spec.From.Name, err.Error())}.PrefixIndex(i)...)
				}
			}
		default:
			errs = append(errs, fielderrors.ValidationErrorList{fielderrors.NewFieldInvalid("from.kind", from.Kind, "only DockerImage is supported")}.PrefixIndex(i)...)
		}
	}
	errs = errs.Prefix("spec.images")

	if spec := isi.Spec.Repository; spec != nil {
		from := spec.From
		switch from.Kind {
		case "DockerImage":
			if len(spec.From.Name) == 0 {
				errs = append(errs, fielderrors.NewFieldRequired("spec.repository.from.name"))
			} else {
				if _, err := api.ParseDockerImageReference(spec.From.Name); err != nil {
					errs = append(errs, fielderrors.NewFieldInvalid("spec.repository.from.name", spec.From.Name, err.Error()))
				}
			}
		default:
			errs = append(errs, fielderrors.NewFieldInvalid("spec.repository.from.kind", from.Kind, "only DockerImage is supported"))
		}
	}
	if len(isi.Spec.Images) == 0 && isi.Spec.Repository == nil {
		errs = append(errs, fielderrors.NewFieldInvalid("spec.images", nil, "you must specify at least one image or a repository import"))
	}

	errs = append(errs, validation.ValidateObjectMeta(&isi.ObjectMeta, true, ValidateImageStreamName).Prefix("metadata")...)
	return errs
}
Example #30
0
// Resolve will attempt to find an imagestream with a name that matches the passed in value
func (r ImageStreamResolver) Resolve(value string) (*ComponentMatch, error) {
	ref, err := imageapi.ParseDockerImageReference(value)
	if err != nil || len(ref.Registry) != 0 {
		return nil, fmt.Errorf("image repositories must be of the form [<namespace>/]<name>[:<tag>|@<digest>]")
	}
	namespaces := r.Namespaces
	if len(ref.Namespace) != 0 {
		namespaces = []string{ref.Namespace}
	}
	searchTag := ref.Tag
	if len(searchTag) == 0 {
		searchTag = imageapi.DefaultImageTag
	}
	for _, namespace := range namespaces {
		glog.V(4).Infof("checking ImageStream %s/%s with ref %q", namespace, ref.Name, searchTag)
		repo, err := r.Client.ImageStreams(namespace).Get(ref.Name)
		if err != nil {
			if errors.IsNotFound(err) || errors.IsForbidden(err) {
				continue
			}
			return nil, err
		}
		ref.Namespace = namespace
		latest := imageapi.LatestTaggedImage(repo, searchTag)
		if latest == nil {
			// continue searching in the next namespace
			glog.V(2).Infof("no image recorded for %s/%s:%s", repo.Namespace, repo.Name, searchTag)
			continue
		}
		imageStreamImage, err := r.ImageStreamImages.ImageStreamImages(namespace).Get(ref.Name, latest.Image)
		if err != nil {
			if errors.IsNotFound(err) {
				// continue searching in the next namespace
				glog.V(2).Infof("tag %q is set, but image %q has been removed", searchTag, latest.Image)
				continue
			}
			return nil, err
		}
		imageData := imageStreamImage.Image

		ref.Registry = ""
		return &ComponentMatch{
			Value:       ref.String(),
			Argument:    fmt.Sprintf("--image=%q", ref.String()),
			Name:        ref.Name,
			Description: fmt.Sprintf("Image repository %s (tag %q) in project %s, tracks %q", repo.Name, searchTag, repo.Namespace, repo.Status.DockerImageRepository),
			Builder:     IsBuilderImage(&imageData.DockerImageMetadata),
			Score:       0,

			ImageStream: repo,
			Image:       &imageData.DockerImageMetadata,
			ImageTag:    searchTag,
		}, nil
	}
	return nil, ErrNoMatch{value: value}
}