From 7af3b01f24edfde34e42640ee565a5a6bb66ce26 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Fri, 27 Mar 2020 01:11:36 +0000 Subject: [PATCH] Restore the ability to `kubectl apply --prune` without -n flag Before https://github.com/kubernetes/kubernetes/pull/83084, `kubectl apply --prune` can prune resources in all namespaces specified in config files. After that PR got merged, only a single namespace is considered for pruning. It is OK if namespace is explicitly specified by --namespace option, but what the PR does is use the default namespace (or from kubeconfig) if not overridden by command line flag. That breaks the existing usage of `kubectl apply --prune` without --namespace option. If --namespace is not used, there is no error, and no one notices this issue unless they actually check that pruning happens. This issue also prevents resources in multiple namespaces in config file from being pruned. kubectl 1.16 does not have this bug. Let's see the difference between kubectl 1.16 and kubectl 1.17. Suppose the following config file: ```yaml apiVersion: v1 kind: ConfigMap metadata: creationTimestamp: null name: foo namespace: a labels: pl: foo data: foo: bar --- apiVersion: v1 kind: ConfigMap metadata: creationTimestamp: null name: bar namespace: a labels: pl: foo data: foo: bar ``` Apply it with `kubectl apply -f file`. Then comment out ConfigMap foo in this file. kubectl 1.16 prunes ConfigMap foo with the following command: $ kubectl-1.16 apply -f file -l pl=foo --prune configmap/bar configured configmap/foo pruned But kubectl 1.17 does not prune ConfigMap foo with the same command: $ kubectl-1.17 apply -f file -l pl=foo --prune configmap/bar configured With this patch, kubectl once again can prune the resource as before. --- .../src/k8s.io/kubectl/pkg/cmd/apply/prune.go | 3 --- test/cmd/apply.sh | 24 +++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/apply/prune.go b/staging/src/k8s.io/kubectl/pkg/cmd/apply/prune.go index 48783705618..60b9d5ec64c 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/apply/prune.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/apply/prune.go @@ -77,9 +77,6 @@ func (p *pruner) pruneAll(o *ApplyOptions) error { } for n := range p.visitedNamespaces { - if len(o.Namespace) != 0 && n != o.Namespace { - continue - } for _, m := range namespacedRESTMappings { if err := p.prune(n, m); err != nil { return fmt.Errorf("error pruning namespaced object %v: %v", m.GroupVersionKind, err) diff --git a/test/cmd/apply.sh b/test/cmd/apply.sh index b1e47afaef7..f025c58ca69 100755 --- a/test/cmd/apply.sh +++ b/test/cmd/apply.sh @@ -223,6 +223,30 @@ __EOF__ # cleanup kubectl delete svc prune-svc 2>&1 "${kube_flags[@]:?}" + ## kubectl apply --prune can prune resources not in the defaulted namespace + # Pre-Condition: namespace nsb exists; no POD exists + kubectl create ns nsb + kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" '' + # apply a into namespace nsb + kubectl apply --namespace nsb -f hack/testdata/prune/a.yaml "${kube_flags[@]:?}" + kube::test::get_object_assert 'pods a -n nsb' "{{${id_field:?}}}" 'a' + # apply b with namespace + kubectl apply --namespace nsb -f hack/testdata/prune/b.yaml "${kube_flags[@]:?}" + kube::test::get_object_assert 'pods b -n nsb' "{{${id_field:?}}}" 'b' + # apply --prune must prune a + kubectl apply --prune --all -f hack/testdata/prune/b.yaml + # check wrong pod doesn't exist + output_message=$(! kubectl get pods a -n nsb 2>&1 "${kube_flags[@]:?}") + kube::test::if_has_string "${output_message}" 'pods "a" not found' + # check right pod exists + kube::test::get_object_assert 'pods b -n nsb' "{{${id_field:?}}}" 'b' + + # cleanup + kubectl delete ns nsb + + ## kubectl apply -n must fail if input file contains namespace other than the one given in -n + output_message=$(! kubectl apply -n foo -f hack/testdata/prune/b.yaml 2>&1 "${kube_flags[@]:?}") + kube::test::if_has_string "${output_message}" 'the namespace from the provided object "nsb" does not match the namespace "foo".' ## kubectl apply -f some.yml --force # Pre-condition: no service exists