// tagsChanged updates stream.Status.Tags based on the old and new image stream. // if the old stream is nil, all tags are considered additions. func (s Strategy) tagsChanged(old, stream *api.ImageStream) fielderrors.ValidationErrorList { var errs fielderrors.ValidationErrorList oldTags := map[string]api.TagReference{} if old != nil && old.Spec.Tags != nil { oldTags = old.Spec.Tags } for tag, tagRef := range stream.Spec.Tags { if oldRef, ok := oldTags[tag]; ok && !tagRefChanged(oldRef, tagRef, stream.Namespace) { continue } if tagRef.From == nil { continue } if tagRef.From.Kind == "DockerImage" && len(tagRef.From.Name) > 0 { if tagRef.Reference { event, err := tagReferenceToTagEvent(stream, tagRef, "") if err != nil { errs = append(errs, fielderrors.NewFieldInvalid(fmt.Sprintf("spec.tags[%s].from", tag), tagRef.From, err.Error())) continue } api.AddTagEventToImageStream(stream, tag, *event) } continue } tagRefStreamName, tagOrID, err := parseFromReference(stream, tagRef.From) if err != nil { errs = append(errs, fielderrors.NewFieldInvalid(fmt.Sprintf("spec.tags[%s].from.name", tag), tagRef.From.Name, "must be of the form <tag>, <repo>:<tag>, <id>, or <repo>@<id>")) continue } streamRef := stream streamRefNamespace := tagRef.From.Namespace if len(streamRefNamespace) == 0 { streamRefNamespace = stream.Namespace } if streamRefNamespace != stream.Namespace || tagRefStreamName != stream.Name { obj, err := s.ImageStreamGetter.Get(kapi.WithNamespace(kapi.NewContext(), streamRefNamespace), tagRefStreamName) if err != nil { if kerrors.IsNotFound(err) { errs = append(errs, fielderrors.NewFieldNotFound(fmt.Sprintf("spec.tags[%s].from.name", tag), tagRef.From.Name)) } else { errs = append(errs, fielderrors.NewFieldInvalid(fmt.Sprintf("spec.tags[%s].from.name", tag), tagRef.From.Name, fmt.Sprintf("unable to retrieve image stream: %v", err))) } continue } streamRef = obj.(*api.ImageStream) } event, err := tagReferenceToTagEvent(streamRef, tagRef, tagOrID) if err != nil { errs = append(errs, fielderrors.NewFieldInvalid(fmt.Sprintf("spec.tags[%s].from.name", tag), tagRef.From.Name, fmt.Sprintf("error generating tag event: %v", err))) continue } if event == nil { // referenced tag or ID doesn't exist, which is ok continue } api.AddTagEventToImageStream(stream, tag, *event) } if old != nil { api.UpdateChangedTrackingTags(stream, old) } // use a consistent timestamp on creation if old == nil && !stream.CreationTimestamp.IsZero() { for tag, list := range stream.Status.Tags { for _, event := range list.Items { event.Created = stream.CreationTimestamp } stream.Status.Tags[tag] = list } } return errs }
// tagsChanged updates stream.Status.Tags based on the old and new image stream. // if the old stream is nil, all tags are considered additions. func (s Strategy) tagsChanged(old, stream *api.ImageStream) field.ErrorList { internalRegistry, hasInternalRegistry := s.defaultRegistry.DefaultRegistry() var errs field.ErrorList oldTags := map[string]api.TagReference{} if old != nil && old.Spec.Tags != nil { oldTags = old.Spec.Tags } for tag, tagRef := range stream.Spec.Tags { if oldRef, ok := oldTags[tag]; ok && !tagRefChanged(oldRef, tagRef, stream.Namespace) { continue } if tagRef.From == nil { continue } glog.V(5).Infof("Detected changed tag %s in %s/%s", tag, stream.Namespace, stream.Name) generation := stream.Generation tagRef.Generation = &generation fromPath := field.NewPath("spec", "tags").Key(tag).Child("from") if tagRef.From.Kind == "DockerImage" && len(tagRef.From.Name) > 0 { if tagRef.Reference { event, err := tagReferenceToTagEvent(stream, tagRef, "") if err != nil { errs = append(errs, field.Invalid(fromPath, tagRef.From, err.Error())) continue } stream.Spec.Tags[tag] = tagRef api.AddTagEventToImageStream(stream, tag, *event) } continue } tagRefStreamName, tagOrID, err := parseFromReference(stream, tagRef.From) if err != nil { errs = append(errs, field.Invalid(fromPath.Child("name"), tagRef.From.Name, "must be of the form <tag>, <repo>:<tag>, <id>, or <repo>@<id>")) continue } streamRef := stream streamRefNamespace := tagRef.From.Namespace if len(streamRefNamespace) == 0 { streamRefNamespace = stream.Namespace } if streamRefNamespace != stream.Namespace || tagRefStreamName != stream.Name { obj, err := s.ImageStreamGetter.Get(kapi.WithNamespace(kapi.NewContext(), streamRefNamespace), tagRefStreamName) if err != nil { if kerrors.IsNotFound(err) { errs = append(errs, field.NotFound(fromPath.Child("name"), tagRef.From.Name)) } else { errs = append(errs, field.Invalid(fromPath.Child("name"), tagRef.From.Name, fmt.Sprintf("unable to retrieve image stream: %v", err))) } continue } streamRef = obj.(*api.ImageStream) } event, err := tagReferenceToTagEvent(streamRef, tagRef, tagOrID) if err != nil { errs = append(errs, field.Invalid(fromPath.Child("name"), tagRef.From.Name, fmt.Sprintf("error generating tag event: %v", err))) continue } if event == nil { // referenced tag or ID doesn't exist, which is ok continue } // if this is not a reference tag, and the tag points to the internal registry for the other namespace, alter it to // point to this stream so that pulls happen from this stream in the future. if !tagRef.Reference { if ref, err := api.ParseDockerImageReference(event.DockerImageReference); err == nil { if hasInternalRegistry && ref.Registry == internalRegistry && ref.Namespace == streamRef.Namespace && ref.Name == streamRef.Name { ref.Namespace = stream.Namespace ref.Name = stream.Name event.DockerImageReference = ref.Exact() } } } stream.Spec.Tags[tag] = tagRef api.AddTagEventToImageStream(stream, tag, *event) } api.UpdateChangedTrackingTags(stream, old) // use a consistent timestamp on creation if old == nil && !stream.CreationTimestamp.IsZero() { for tag, list := range stream.Status.Tags { for _, event := range list.Items { event.Created = stream.CreationTimestamp } stream.Status.Tags[tag] = list } } return errs }