... | ... |
@@ -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, |