// 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 }
// 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) }
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 }
// 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 }
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 }
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 }
// 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 }
// 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) } }
// 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} }, ) }
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 }
func imageref(name string) imageapi.DockerImageReference { ref, err := imageapi.ParseDockerImageReference(name) if err != nil { panic(err) } return ref }
// 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} }, ) }
// 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 }
// 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" }
// 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 }
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 }
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) } }
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 }
// 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 }
// 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 }
// 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 }
// 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 }
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} } } } }
// 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) }
// 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 }
// 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()) }
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 }
// 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} }