Skip to content

Commit 72c9740

Browse files
Merge pull request #19611 from legionus/way-how-to-break-cluster
Add option to ignore image reference errors
2 parents a3d35f9 + 8b5afa1 commit 72c9740

File tree

5 files changed

+85
-32
lines changed

5 files changed

+85
-32
lines changed

contrib/completions/bash/oc

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

contrib/completions/zsh/oc

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/oc/admin/prune/imageprune/prune.go

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ type PrunerOptions struct {
160160
RegistryClient *http.Client
161161
// RegistryURL is the URL of the integrated Docker registry.
162162
RegistryURL *url.URL
163+
// IgnoreInvalidRefs indicates that all invalid references should be ignored.
164+
IgnoreInvalidRefs bool
163165
}
164166

165167
// Pruner knows how to prune istags, images, layers and image configs.
@@ -173,10 +175,11 @@ type Pruner interface {
173175

174176
// pruner is an object that knows how to prune a data set
175177
type pruner struct {
176-
g genericgraph.Graph
177-
algorithm pruneAlgorithm
178-
registryClient *http.Client
179-
registryURL *url.URL
178+
g genericgraph.Graph
179+
algorithm pruneAlgorithm
180+
registryClient *http.Client
181+
registryURL *url.URL
182+
ignoreInvalidRefs bool
180183
}
181184

182185
var _ Pruner = &pruner{}
@@ -253,9 +256,10 @@ func NewPruner(options PrunerOptions) (Pruner, kerrors.Aggregate) {
253256
algorithm.namespace = options.Namespace
254257

255258
p := &pruner{
256-
algorithm: algorithm,
257-
registryClient: options.RegistryClient,
258-
registryURL: options.RegistryURL,
259+
algorithm: algorithm,
260+
registryClient: options.RegistryClient,
261+
registryURL: options.RegistryURL,
262+
ignoreInvalidRefs: options.IgnoreInvalidRefs,
259263
}
260264

261265
if err := p.buildGraph(options); err != nil {
@@ -493,8 +497,10 @@ func (p *pruner) addPodSpecToGraph(referrer *kapi.ObjectReference, spec *kapi.Po
493497

494498
ref, err := imageapi.ParseDockerImageReference(container.Image)
495499
if err != nil {
496-
glog.V(4).Infof("Unable to parse DockerImageReference %q of %s: %v - skipping", container.Image, getKindName(referrer), err)
497-
errs = append(errs, newErrBadReferenceToImage(container.Image, referrer, err.Error()))
500+
glog.Warningf("Unable to parse DockerImageReference %q of %s: %v - skipping", container.Image, getKindName(referrer), err)
501+
if !p.ignoreInvalidRefs {
502+
errs = append(errs, newErrBadReferenceToImage(container.Image, referrer, err.Error()))
503+
}
498504
continue
499505
}
500506

@@ -662,6 +668,25 @@ func (p *pruner) addBuildsToGraph(builds *buildapi.BuildList) []error {
662668
return errs
663669
}
664670

671+
// resolveISTagName parses and tries to find it in the graph. If the parsing fails,
672+
// an error is returned. If the istag cannot be found, nil is returned.
673+
func (p *pruner) resolveISTagName(g genericgraph.Graph, referrer *kapi.ObjectReference, istagName string) (*imagegraph.ImageStreamTagNode, error) {
674+
name, tag, err := imageapi.ParseImageStreamTagName(istagName)
675+
if err != nil {
676+
if p.ignoreInvalidRefs {
677+
glog.Warningf("Failed to parse ImageStreamTag name %q: %v", istagName, err)
678+
return nil, nil
679+
}
680+
return nil, newErrBadReferenceTo("ImageStreamTag", istagName, referrer, err.Error())
681+
}
682+
node := g.Find(imagegraph.ImageStreamTagNodeName(makeISTag(referrer.Namespace, name, tag)))
683+
if istNode, ok := node.(*imagegraph.ImageStreamTagNode); ok {
684+
return istNode, nil
685+
}
686+
687+
return nil, nil
688+
}
689+
665690
// addBuildStrategyImageReferencesToGraph ads references from the build strategy's parent node to the image
666691
// the build strategy references.
667692
//
@@ -687,23 +712,27 @@ func (p *pruner) addBuildStrategyImageReferencesToGraph(referrer *kapi.ObjectRef
687712
}
688713
ref, err := imageapi.ParseDockerImageReference(from.Name)
689714
if err != nil {
690-
msg := fmt.Sprintf("failed to parse DockerImage name %q of %s: %v", from.Name, getKindName(referrer), err)
691-
glog.V(4).Infof(msg)
692-
return []error{newErrBadReferenceToImage(from.Name, referrer, err.Error())}
715+
glog.Warningf("Failed to parse DockerImage name %q of %s: %v", from.Name, getKindName(referrer), err)
716+
if !p.ignoreInvalidRefs {
717+
return []error{newErrBadReferenceToImage(from.Name, referrer, err.Error())}
718+
}
719+
return nil
693720
}
694721
imageID = ref.ID
695722

696723
case "ImageStreamImage":
697724
_, id, err := imageapi.ParseImageStreamImageName(from.Name)
698725
if err != nil {
699-
msg := fmt.Sprintf("failed to parse ImageStreamImage name %q of %s: %v", from.Name, getKindName(referrer), err)
700-
glog.V(4).Infof(msg)
701-
return []error{newErrBadReferenceTo("ImageStreamImage", from.Name, referrer, err.Error())}
726+
glog.Warningf("Failed to parse ImageStreamImage name %q of %s: %v", from.Name, getKindName(referrer), err)
727+
if !p.ignoreInvalidRefs {
728+
return []error{newErrBadReferenceTo("ImageStreamImage", from.Name, referrer, err.Error())}
729+
}
730+
return nil
702731
}
703732
imageID = id
704733

705734
case "ImageStreamTag":
706-
istNode, err := resolveISTagName(p.g, referrer, from.Name)
735+
istNode, err := p.resolveISTagName(p.g, referrer, from.Name)
707736
if err != nil {
708737
glog.V(4).Infof(err.Error())
709738
return []error{err}
@@ -1332,18 +1361,3 @@ func makeISTag(namespace, name, tag string) *imageapi.ImageStreamTag {
13321361
func makeISTagWithStream(is *imageapi.ImageStream, tag string) *imageapi.ImageStreamTag {
13331362
return makeISTag(is.Namespace, is.Name, tag)
13341363
}
1335-
1336-
// resolveISTagName parses ImageStreamTag's name and tries to find it in the graph. If the parsing fails,
1337-
// an error is returned. If the istag cannot be found, nil is returned.
1338-
func resolveISTagName(g genericgraph.Graph, referrer *kapi.ObjectReference, istagName string) (*imagegraph.ImageStreamTagNode, error) {
1339-
name, tag, err := imageapi.ParseImageStreamTagName(istagName)
1340-
if err != nil {
1341-
return nil, newErrBadReferenceTo("ImageStreamTag", istagName, referrer, err.Error())
1342-
}
1343-
node := g.Find(imagegraph.ImageStreamTagNodeName(makeISTag(referrer.Namespace, name, tag)))
1344-
if istNode, ok := node.(*imagegraph.ImageStreamTagNode); ok {
1345-
return istNode, nil
1346-
}
1347-
1348-
return nil, nil
1349-
}

pkg/oc/admin/prune/imageprune/prune_test.go

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ func TestImagePruning(t *testing.T) {
4848
pruneOverSizeLimit *bool
4949
allImages *bool
5050
pruneRegistry *bool
51+
ignoreInvalidRefs *bool
5152
keepTagRevisions *int
5253
namespace string
5354
images imageapi.ImageList
@@ -851,6 +852,34 @@ func TestImagePruning(t *testing.T) {
851852
expectedStreamUpdates: []string{"foo/bar|sha256:0000000000000000000000000000000000000000000000000000000000000003"},
852853
},
853854

855+
{
856+
name: "build with ignored bad image reference",
857+
pruneOverSizeLimit: newBool(true),
858+
ignoreInvalidRefs: newBool(true),
859+
images: testutil.ImageList(
860+
testutil.UnmanagedImage("sha256:0000000000000000000000000000000000000000000000000000000000000000", "otherregistry/foo/bar@sha256:0000000000000000000000000000000000000000000000000000000000000000", false, "", ""),
861+
testutil.SizedImage("sha256:0000000000000000000000000000000000000000000000000000000000000002", registryHost+"/foo/bar@sha256:0000000000000000000000000000000000000000000000000000000000000002", 100, nil),
862+
testutil.SizedImage("sha256:0000000000000000000000000000000000000000000000000000000000000003", registryHost+"/foo/bar@sha256:0000000000000000000000000000000000000000000000000000000000000003", 200, nil),
863+
),
864+
streams: testutil.StreamList(
865+
testutil.Stream(registryHost, "foo", "bar", testutil.Tags(
866+
testutil.Tag("latest",
867+
testutil.TagEvent("sha256:0000000000000000000000000000000000000000000000000000000000000000", "otherregistry/foo/bar@sha256:0000000000000000000000000000000000000000000000000000000000000000"),
868+
testutil.TagEvent("sha256:0000000000000000000000000000000000000000000000000000000000000002", registryHost+"/foo/bar@sha256:0000000000000000000000000000000000000000000000000000000000000002"),
869+
testutil.TagEvent("sha256:0000000000000000000000000000000000000000000000000000000000000003", registryHost+"/foo/bar@sha256:0000000000000000000000000000000000000000000000000000000000000003"),
870+
),
871+
)),
872+
),
873+
builds: testutil.BuildList(
874+
testutil.Build("foo", "build1", "source", "DockerImage", "foo", registryHost+"/foo/bar@sha256:many-zeros-and-3"),
875+
),
876+
limits: map[string][]*kapi.LimitRange{
877+
"foo": testutil.LimitList(100, 200),
878+
},
879+
expectedImageDeletions: []string{"sha256:0000000000000000000000000000000000000000000000000000000000000003"},
880+
expectedStreamUpdates: []string{"foo/bar|sha256:0000000000000000000000000000000000000000000000000000000000000003"},
881+
},
882+
854883
{
855884
name: "build with bad image reference",
856885
builds: testutil.BuildList(testutil.Build("foo", "build1", "source", "DockerImage", "foo", registryHost+"/foo/bar@invalid-digest")),
@@ -908,14 +937,17 @@ func TestImagePruning(t *testing.T) {
908937
if test.pruneRegistry != nil {
909938
options.PruneRegistry = test.pruneRegistry
910939
}
940+
if test.ignoreInvalidRefs != nil {
941+
options.IgnoreInvalidRefs = *test.ignoreInvalidRefs
942+
}
911943
p, err := NewPruner(options)
912944
if err != nil {
913945
if len(test.expectedErrorString) > 0 {
914946
if a, e := err.Error(), test.expectedErrorString; a != e {
915947
t.Fatalf("got unexpected error: %q != %q", a, e)
916948
}
917949
} else {
918-
t.Fatalf("got unexpected error: %v", test.expectedErrorString)
950+
t.Fatalf("got unexpected error: %v", err)
919951
}
920952
return
921953
} else if len(test.expectedErrorString) > 0 {

pkg/oc/admin/prune/images.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ type PruneImagesOptions struct {
119119
Namespace string
120120
ForceInsecure bool
121121
PruneRegistry *bool
122+
IgnoreInvalidRefs bool
122123

123124
ClientConfig *restclient.Config
124125
AppsClient appsclient.AppsInterface
@@ -166,6 +167,7 @@ func NewCmdPruneImages(f *clientcmd.Factory, parentName, name string, out io.Wri
166167
cmd.Flags().StringVar(&opts.RegistryUrlOverride, "registry-url", opts.RegistryUrlOverride, "The address to use when contacting the registry, instead of using the default value. This is useful if you can't resolve or reach the registry (e.g.; the default is a cluster-internal URL) but you do have an alternative route that works. Particular transport protocol can be enforced using '<scheme>://' prefix.")
167168
cmd.Flags().BoolVar(&opts.ForceInsecure, "force-insecure", opts.ForceInsecure, "If true, allow an insecure connection to the docker registry that is hosted via HTTP or has an invalid HTTPS certificate. Whenever possible, use --certificate-authority instead of this dangerous option.")
168169
cmd.Flags().BoolVar(opts.PruneRegistry, "prune-registry", *opts.PruneRegistry, "If false, the prune operation will clean up image API objects, but the none of the associated content in the registry is removed. Note, if only image API objects are cleaned up through use of this flag, the only means for subsequently cleaning up registry data corresponding to those image API objects is to employ the 'hard prune' administrative task.")
170+
cmd.Flags().BoolVar(&opts.IgnoreInvalidRefs, "ignore-invalid-refs", opts.IgnoreInvalidRefs, "If true, the pruning process will ignore all errors while parsing image references. This means that the pruning process will ignore the intended connection between the object and the referenced image. As a result an image may be incorrectly deleted as unused.")
169171

170172
return cmd
171173
}
@@ -388,6 +390,7 @@ func (o PruneImagesOptions) Run() error {
388390
RegistryClient: registryClient,
389391
RegistryURL: registryURL,
390392
PruneRegistry: o.PruneRegistry,
393+
IgnoreInvalidRefs: o.IgnoreInvalidRefs,
391394
}
392395
if o.Namespace != metav1.NamespaceAll {
393396
options.Namespace = o.Namespace

0 commit comments

Comments
 (0)