@@ -20,6 +20,7 @@ import (
2020 kerrors "k8s.io/apimachinery/pkg/util/errors"
2121 "k8s.io/apimachinery/pkg/util/sets"
2222 kapi "k8s.io/kubernetes/pkg/api"
23+ "k8s.io/kubernetes/pkg/client/retry"
2324
2425 "github.com/openshift/origin/pkg/api/graph"
2526 kubegraph "github.com/openshift/origin/pkg/api/kubegraph/nodes"
@@ -71,9 +72,11 @@ type ImageDeleter interface {
7172
7273// ImageStreamDeleter knows how to remove an image reference from an image stream.
7374type ImageStreamDeleter interface {
74- // DeleteImageStream removes all references to the image from the image
75+ // GetImageStream returns a fresh copy of an image stream.
76+ GetImageStream (stream * imageapi.ImageStream ) (* imageapi.ImageStream , error )
77+ // UpdateImageStream removes all references to the image from the image
7578 // stream's status.tags. The updated image stream is returned.
76- DeleteImageStream (stream * imageapi.ImageStream , image * imageapi.Image , updatedTags []string ) (* imageapi.ImageStream , error )
79+ UpdateImageStream (stream * imageapi.ImageStream , image * imageapi.Image , updatedTags []string ) (* imageapi.ImageStream , error )
7780}
7881
7982// BlobDeleter knows how to delete a blob from the Docker registry.
@@ -671,7 +674,7 @@ func calculatePrunableImageComponents(g graph.Graph) []*imagegraph.ImageComponen
671674}
672675
673676// pruneStreams removes references from all image streams' status.tags entries
674- // to prunable images, invoking streamPruner.DeleteImageStream for each updated
677+ // to prunable images, invoking streamPruner.UpdateImageStream for each updated
675678// stream.
676679func pruneStreams (g graph.Graph , imageNodes []* imagegraph.ImageNode , streamPruner ImageStreamDeleter ) []error {
677680 errs := []error {}
@@ -684,43 +687,49 @@ func pruneStreams(g graph.Graph, imageNodes []*imagegraph.ImageNode, streamPrune
684687 continue
685688 }
686689
687- stream := streamNode .ImageStream
688- updatedTags := sets .NewString ()
690+ if err := retry .RetryOnConflict (retry .DefaultRetry , func () error {
691+ stream , err := streamPruner .GetImageStream (streamNode .ImageStream )
692+ if err != nil {
693+ return err
694+ }
695+ updatedTags := sets .NewString ()
689696
690- glog .V (4 ).Infof ("Checking if ImageStream %s has references to image %s in status.tags" , getName (stream ), imageNode .Image .Name )
697+ glog .V (4 ).Infof ("Checking if ImageStream %s has references to image %s in status.tags" , getName (stream ), imageNode .Image .Name )
691698
692- for tag , history := range stream .Status .Tags {
693- glog .V (4 ).Infof ("Checking tag %q" , tag )
699+ for tag , history := range stream .Status .Tags {
700+ glog .V (4 ).Infof ("Checking tag %q" , tag )
694701
695- newHistory := imageapi.TagEventList {}
702+ newHistory := imageapi.TagEventList {}
696703
697- for i , tagEvent := range history .Items {
698- glog .V (4 ).Infof ("Checking tag event %d with image %q" , i , tagEvent .Image )
704+ for i , tagEvent := range history .Items {
705+ glog .V (4 ).Infof ("Checking tag event %d with image %q" , i , tagEvent .Image )
699706
700- if tagEvent .Image != imageNode .Image .Name {
701- glog .V (4 ).Infof ("Tag event doesn't match deleted image - keeping" )
702- newHistory .Items = append (newHistory .Items , tagEvent )
707+ if tagEvent .Image != imageNode .Image .Name {
708+ glog .V (4 ).Infof ("Tag event doesn't match deleted image - keeping" )
709+ newHistory .Items = append (newHistory .Items , tagEvent )
710+ } else {
711+ glog .V (4 ).Infof ("Tag event matches deleted image - removing reference" )
712+ updatedTags .Insert (tag )
713+ }
714+ }
715+ if len (newHistory .Items ) == 0 {
716+ glog .V (4 ).Infof ("Removing tag %q from status.tags of ImageStream %s" , tag , getName (stream ))
717+ delete (stream .Status .Tags , tag )
703718 } else {
704- glog .V (4 ).Infof ("Tag event matches deleted image - removing reference" )
705- updatedTags .Insert (tag )
719+ stream .Status .Tags [tag ] = newHistory
706720 }
707721 }
708- if len (newHistory .Items ) == 0 {
709- glog .V (4 ).Infof ("Removing tag %q from status.tags of ImageStream %s" , tag , getName (stream ))
710- delete (stream .Status .Tags , tag )
711- } else {
712- stream .Status .Tags [tag ] = newHistory
713- }
714- }
715722
716- updatedStream , err := streamPruner .DeleteImageStream (stream , imageNode .Image , updatedTags .List ())
717- if err != nil {
723+ updatedStream , err := streamPruner .UpdateImageStream (stream , imageNode .Image , updatedTags .List ())
724+ if err == nil {
725+ streamNode .ImageStream = updatedStream
726+ }
727+ return err
728+ }); err != nil {
718729 errs = append (errs , fmt .Errorf ("error removing image %s from stream %s: %v" ,
719- imageNode .Image .Name , getName (stream ), err ))
730+ imageNode .Image .Name , getName (streamNode . ImageStream ), err ))
720731 continue
721732 }
722-
723- streamNode .ImageStream = updatedStream
724733 }
725734 }
726735 glog .V (4 ).Infof ("Done removing pruned image references from streams" )
@@ -922,7 +931,11 @@ func NewImageStreamDeleter(streams client.ImageStreamsNamespacer) ImageStreamDel
922931 }
923932}
924933
925- func (p * imageStreamDeleter ) DeleteImageStream (stream * imageapi.ImageStream , image * imageapi.Image , updatedTags []string ) (* imageapi.ImageStream , error ) {
934+ func (p * imageStreamDeleter ) GetImageStream (stream * imageapi.ImageStream ) (* imageapi.ImageStream , error ) {
935+ return p .streams .ImageStreams (stream .Namespace ).Get (stream .Name , metav1.GetOptions {})
936+ }
937+
938+ func (p * imageStreamDeleter ) UpdateImageStream (stream * imageapi.ImageStream , image * imageapi.Image , updatedTags []string ) (* imageapi.ImageStream , error ) {
926939 glog .V (4 ).Infof ("Updating ImageStream %s" , getName (stream ))
927940 is , err := p .streams .ImageStreams (stream .Namespace ).UpdateStatus (stream )
928941 if err == nil {
0 commit comments