Browse code

Bug 1371511 - add namespace awareness to oadm prune commands

Maciej Szulik authored on 2016/10/07 01:24:33
Showing 5 changed files
... ...
@@ -84,6 +84,14 @@ func (o *PruneBuildsOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command,
84 84
 		return kcmdutil.UsageError(cmd, "no arguments are allowed to this command")
85 85
 	}
86 86
 
87
+	namespace := kapi.NamespaceAll
88
+	if cmd.Flags().Lookup("namespace").Changed {
89
+		var err error
90
+		namespace, _, err = f.DefaultNamespace()
91
+		if err != nil {
92
+			return err
93
+		}
94
+	}
87 95
 	o.Out = out
88 96
 
89 97
 	osClient, _, err := f.Clients()
... ...
@@ -92,7 +100,7 @@ func (o *PruneBuildsOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command,
92 92
 	}
93 93
 	o.Client = osClient
94 94
 
95
-	buildConfigList, err := osClient.BuildConfigs(kapi.NamespaceAll).List(kapi.ListOptions{})
95
+	buildConfigList, err := osClient.BuildConfigs(namespace).List(kapi.ListOptions{})
96 96
 	if err != nil {
97 97
 		return err
98 98
 	}
... ...
@@ -101,7 +109,7 @@ func (o *PruneBuildsOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command,
101 101
 		buildConfigs = append(buildConfigs, &buildConfigList.Items[i])
102 102
 	}
103 103
 
104
-	buildList, err := osClient.Builds(kapi.NamespaceAll).List(kapi.ListOptions{})
104
+	buildList, err := osClient.Builds(namespace).List(kapi.ListOptions{})
105 105
 	if err != nil {
106 106
 		return err
107 107
 	}
... ...
@@ -85,6 +85,14 @@ func (o *PruneDeploymentsOptions) Complete(f *clientcmd.Factory, cmd *cobra.Comm
85 85
 		return kcmdutil.UsageError(cmd, "no arguments are allowed to this command")
86 86
 	}
87 87
 
88
+	namespace := kapi.NamespaceAll
89
+	if cmd.Flags().Lookup("namespace").Changed {
90
+		var err error
91
+		namespace, _, err = f.DefaultNamespace()
92
+		if err != nil {
93
+			return err
94
+		}
95
+	}
88 96
 	o.Out = out
89 97
 
90 98
 	osClient, kClient, err := f.Clients()
... ...
@@ -93,7 +101,7 @@ func (o *PruneDeploymentsOptions) Complete(f *clientcmd.Factory, cmd *cobra.Comm
93 93
 	}
94 94
 	o.Client = kClient
95 95
 
96
-	deploymentConfigList, err := osClient.DeploymentConfigs(kapi.NamespaceAll).List(kapi.ListOptions{})
96
+	deploymentConfigList, err := osClient.DeploymentConfigs(namespace).List(kapi.ListOptions{})
97 97
 	if err != nil {
98 98
 		return err
99 99
 	}
... ...
@@ -102,7 +110,7 @@ func (o *PruneDeploymentsOptions) Complete(f *clientcmd.Factory, cmd *cobra.Comm
102 102
 		deploymentConfigs = append(deploymentConfigs, &deploymentConfigList.Items[i])
103 103
 	}
104 104
 
105
-	deploymentList, err := kClient.ReplicationControllers(kapi.NamespaceAll).List(kapi.ListOptions{})
105
+	deploymentList, err := kClient.ReplicationControllers(namespace).List(kapi.ListOptions{})
106 106
 	if err != nil {
107 107
 		return err
108 108
 	}
... ...
@@ -124,7 +124,14 @@ func (o *PruneImagesOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command,
124 124
 	if !cmd.Flags().Lookup("prune-over-size-limit").Changed {
125 125
 		o.PruneOverSizeLimit = nil
126 126
 	}
127
-
127
+	namespace := kapi.NamespaceAll
128
+	if cmd.Flags().Lookup("namespace").Changed {
129
+		var err error
130
+		namespace, _, err = f.DefaultNamespace()
131
+		if err != nil {
132
+			return err
133
+		}
134
+	}
128 135
 	o.Out = out
129 136
 
130 137
 	osClient, kClient, registryClient, err := getClients(f, o.CABundle)
... ...
@@ -138,41 +145,41 @@ func (o *PruneImagesOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command,
138 138
 		return err
139 139
 	}
140 140
 
141
-	allStreams, err := osClient.ImageStreams(kapi.NamespaceAll).List(kapi.ListOptions{})
141
+	allStreams, err := osClient.ImageStreams(namespace).List(kapi.ListOptions{})
142 142
 	if err != nil {
143 143
 		return err
144 144
 	}
145 145
 
146
-	allPods, err := kClient.Pods(kapi.NamespaceAll).List(kapi.ListOptions{})
146
+	allPods, err := kClient.Pods(namespace).List(kapi.ListOptions{})
147 147
 	if err != nil {
148 148
 		return err
149 149
 	}
150 150
 
151
-	allRCs, err := kClient.ReplicationControllers(kapi.NamespaceAll).List(kapi.ListOptions{})
151
+	allRCs, err := kClient.ReplicationControllers(namespace).List(kapi.ListOptions{})
152 152
 	if err != nil {
153 153
 		return err
154 154
 	}
155 155
 
156
-	allBCs, err := osClient.BuildConfigs(kapi.NamespaceAll).List(kapi.ListOptions{})
156
+	allBCs, err := osClient.BuildConfigs(namespace).List(kapi.ListOptions{})
157 157
 	// We need to tolerate 'not found' errors for buildConfigs since they may be disabled in Atomic
158 158
 	err = oserrors.TolerateNotFoundError(err)
159 159
 	if err != nil {
160 160
 		return err
161 161
 	}
162 162
 
163
-	allBuilds, err := osClient.Builds(kapi.NamespaceAll).List(kapi.ListOptions{})
163
+	allBuilds, err := osClient.Builds(namespace).List(kapi.ListOptions{})
164 164
 	// We need to tolerate 'not found' errors for builds since they may be disabled in Atomic
165 165
 	err = oserrors.TolerateNotFoundError(err)
166 166
 	if err != nil {
167 167
 		return err
168 168
 	}
169 169
 
170
-	allDCs, err := osClient.DeploymentConfigs(kapi.NamespaceAll).List(kapi.ListOptions{})
170
+	allDCs, err := osClient.DeploymentConfigs(namespace).List(kapi.ListOptions{})
171 171
 	if err != nil {
172 172
 		return err
173 173
 	}
174 174
 
175
-	limitRangesList, err := kClient.LimitRanges(kapi.NamespaceAll).List(kapi.ListOptions{})
175
+	limitRangesList, err := kClient.LimitRanges(namespace).List(kapi.ListOptions{})
176 176
 	if err != nil {
177 177
 		return err
178 178
 	}
... ...
@@ -203,6 +210,9 @@ func (o *PruneImagesOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command,
203 203
 		RegistryClient:     registryClient,
204 204
 		RegistryURL:        o.RegistryUrlOverride,
205 205
 	}
206
+	if namespace != kapi.NamespaceAll {
207
+		options.Namespace = namespace
208
+	}
206 209
 
207 210
 	o.Pruner = prune.NewPruner(options)
208 211
 
... ...
@@ -54,6 +54,7 @@ type pruneAlgorithm struct {
54 54
 	keepYoungerThan    time.Duration
55 55
 	keepTagRevisions   int
56 56
 	pruneOverSizeLimit bool
57
+	namespace          string
57 58
 }
58 59
 
59 60
 // ImageDeleter knows how to remove images from OpenShift.
... ...
@@ -102,6 +103,8 @@ type PrunerOptions struct {
102 102
 	// PruneOverSizeLimit indicates that images exceeding defined limits (openshift.io/Image)
103 103
 	// will be considered as candidates for pruning.
104 104
 	PruneOverSizeLimit *bool
105
+	// Namespace to be pruned, if specified it should never remove Images.
106
+	Namespace string
105 107
 	// Images is the entire list of images in OpenShift. An image must be in this
106 108
 	// list to be a candidate for pruning.
107 109
 	Images *imageapi.ImageList
... ...
@@ -256,6 +259,7 @@ func NewPruner(options PrunerOptions) Pruner {
256 256
 	if options.PruneOverSizeLimit != nil {
257 257
 		algorithm.pruneOverSizeLimit = *options.PruneOverSizeLimit
258 258
 	}
259
+	algorithm.namespace = options.Namespace
259 260
 
260 261
 	addImagesToGraph(g, options.Images, algorithm)
261 262
 	addImageStreamsToGraph(g, options.Streams, options.LimitRanges, algorithm)
... ...
@@ -819,12 +823,16 @@ func (p *pruner) Prune(
819 819
 	}
820 820
 
821 821
 	prunableImageNodes, prunableImageIDs := calculatePrunableImages(p.g, imageNodes)
822
-	graphWithoutPrunableImages := subgraphWithoutPrunableImages(p.g, prunableImageIDs)
823
-	prunableComponents := calculatePrunableImageComponents(graphWithoutPrunableImages)
824 822
 
825 823
 	errs := []error{}
826
-
827 824
 	errs = append(errs, pruneStreams(p.g, prunableImageNodes, streamPruner)...)
825
+	// if namespace is specified prune only ImageStreams and nothing more
826
+	if len(p.algorithm.namespace) > 0 {
827
+		return kerrors.NewAggregate(errs)
828
+	}
829
+
830
+	graphWithoutPrunableImages := subgraphWithoutPrunableImages(p.g, prunableImageIDs)
831
+	prunableComponents := calculatePrunableImageComponents(graphWithoutPrunableImages)
828 832
 	errs = append(errs, pruneImageComponents(p.g, p.registryClient, registryURL, prunableComponents, layerLinkPruner)...)
829 833
 	errs = append(errs, pruneBlobs(p.g, p.registryClient, registryURL, prunableComponents, blobPruner)...)
830 834
 	errs = append(errs, pruneManifests(p.g, p.registryClient, registryURL, prunableImageNodes, manifestPruner)...)
... ...
@@ -418,6 +418,7 @@ func TestImagePruning(t *testing.T) {
418 418
 	tests := map[string]struct {
419 419
 		pruneOverSizeLimit         *bool
420 420
 		registryURLs               []string
421
+		namespace                  string
421 422
 		images                     imageapi.ImageList
422 423
 		pods                       kapi.PodList
423 424
 		streams                    imageapi.ImageStreamList
... ...
@@ -870,6 +871,28 @@ func TestImagePruning(t *testing.T) {
870 870
 			expectedImageDeletions: []string{},
871 871
 			expectedStreamUpdates:  []string{},
872 872
 		},
873
+		"image exceeding limits with namespace specified": {
874
+			pruneOverSizeLimit: newBool(true),
875
+			namespace:          "foo",
876
+			images: imageList(
877
+				unmanagedImage("id", "otherregistry/foo/bar@id", false, "", ""),
878
+				sizedImage("id2", registryURL+"/foo/bar@id2", 100, nil),
879
+				sizedImage("id3", registryURL+"/foo/bar@id3", 200, nil),
880
+			),
881
+			streams: streamList(
882
+				stream(registryURL, "foo", "bar", tags(
883
+					tag("latest",
884
+						tagEvent("id", "otherregistry/foo/bar@id"),
885
+						tagEvent("id2", registryURL+"/foo/bar@id2"),
886
+						tagEvent("id3", registryURL+"/foo/bar@id3"),
887
+					),
888
+				)),
889
+			),
890
+			limits: map[string][]*kapi.LimitRange{
891
+				"foo": limitList(100, 200),
892
+			},
893
+			expectedStreamUpdates: []string{"foo/bar|id3"},
894
+		},
873 895
 	}
874 896
 
875 897
 	for name, test := range tests {
... ...
@@ -879,6 +902,7 @@ func TestImagePruning(t *testing.T) {
879 879
 		}
880 880
 
881 881
 		options := PrunerOptions{
882
+			Namespace:   test.namespace,
882 883
 			Images:      &test.images,
883 884
 			Streams:     &test.streams,
884 885
 			Pods:        &test.pods,