// Create registers a new image (if it doesn't exist) and updates the specified ImageStream's tags. func (s *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { if err := rest.BeforeCreate(Strategy, ctx, obj); err != nil { return nil, err } mapping := obj.(*api.ImageStreamMapping) stream, err := s.findStreamForMapping(ctx, mapping) if err != nil { return nil, err } image := mapping.Image tag := mapping.Tag if len(tag) == 0 { tag = api.DefaultImageTag } if err := s.imageRegistry.CreateImage(ctx, &image); err != nil && !errors.IsAlreadyExists(err) { return nil, err } next := api.TagEvent{ Created: util.Now(), DockerImageReference: image.DockerImageReference, Image: image.Name, } if !api.AddTagEventToImageStream(stream, tag, next) { // nothing actually changed return &kapi.Status{Status: kapi.StatusSuccess}, nil } api.UpdateTrackingTags(stream, tag, next) if _, err := s.imageStreamRegistry.UpdateImageStreamStatus(ctx, stream); err != nil { return nil, err } return &kapi.Status{Status: kapi.StatusSuccess}, nil }
// Create registers a new image (if it doesn't exist) and updates the // specified ImageStream's tags. If attempts to update the ImageStream fail // with a resource conflict, the update will be retried if the newer // ImageStream has no tag diffs from the previous state. If tag diffs are // detected, the conflict error is returned. func (s *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { if err := rest.BeforeCreate(Strategy, ctx, obj); err != nil { return nil, err } mapping := obj.(*api.ImageStreamMapping) stream, err := s.findStreamForMapping(ctx, mapping) if err != nil { return nil, err } image := mapping.Image tag := mapping.Tag if len(tag) == 0 { tag = api.DefaultImageTag } if err := s.imageRegistry.CreateImage(ctx, &image); err != nil && !errors.IsAlreadyExists(err) { return nil, err } next := api.TagEvent{ Created: unversioned.Now(), DockerImageReference: image.DockerImageReference, Image: image.Name, } err = wait.ExponentialBackoff(wait.Backoff{Steps: maxRetriesOnConflict}, func() (bool, error) { lastEvent := api.LatestTaggedImage(stream, tag) next.Generation = stream.Generation if !api.AddTagEventToImageStream(stream, tag, next) { // nothing actually changed return true, nil } api.UpdateTrackingTags(stream, tag, next) _, err := s.imageStreamRegistry.UpdateImageStreamStatus(ctx, stream) if err == nil { return true, nil } if !errors.IsConflict(err) { return false, err } // If the update conflicts, get the latest stream and check for tag // updates. If the latest tag hasn't changed, retry. latestStream, findLatestErr := s.findStreamForMapping(ctx, mapping) if findLatestErr != nil { return false, findLatestErr } // no previous tag if lastEvent == nil { // The tag hasn't changed, so try again with the updated stream. stream = latestStream return false, nil } // check for tag change newerEvent := api.LatestTaggedImage(latestStream, tag) // generation and creation time differences are ignored lastEvent.Generation = newerEvent.Generation lastEvent.Created = newerEvent.Created if kapi.Semantic.DeepEqual(lastEvent, newerEvent) { // The tag hasn't changed, so try again with the updated stream. stream = latestStream return false, nil } // The tag changed, so return the conflict error back to the client. return false, err }) if err != nil { return nil, err } return &unversioned.Status{Status: unversioned.StatusSuccess}, nil }