From 9744e9f619d3c1d8ddbe3af59e7d70d81c05dc5a Mon Sep 17 00:00:00 2001 From: Dong Gang Date: Mon, 2 Mar 2020 14:23:35 +0800 Subject: [PATCH 1/3] fix(helm): respect resource policy on ungrade Don't delete a resource on upgrade if it is annotated with helm.io/resource-policy=keep. This can cause data loss for users if the annotation is ignored(e.g. for a PVC) Close #7677 Signed-off-by: Dong Gang --- pkg/kube/client.go | 16 ++++++++++++++++ pkg/kube/resource_policy.go | 26 ++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 pkg/kube/resource_policy.go diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 31dabcc5d..04f247c93 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -21,6 +21,7 @@ import ( "encoding/json" "fmt" "io" + "k8s.io/apimachinery/pkg/api/meta" "strings" "sync" "time" @@ -50,6 +51,8 @@ import ( // ErrNoObjectsVisited indicates that during a visit operation, no matching objects were found. var ErrNoObjectsVisited = errors.New("no objects visited") +var metadataAccessor = meta.NewAccessor() + // Client represents a client capable of communicating with the Kubernetes API. type Client struct { Factory Factory @@ -210,6 +213,19 @@ func (c *Client) Update(original, target ResourceList, force bool) (*Result, err for _, info := range original.Difference(target) { c.Log("Deleting %q in %s...", info.Name, info.Namespace) + + if err := info.Get(); err != nil { + c.Log("Unable to get obj %q, err: %s", info.Name, err) + } + annotations, err := metadataAccessor.Annotations(info.Object) + if err != nil { + c.Log("Unable to get annotations on %q, err: %s", info.Name, err) + } + if annotations != nil && annotations[ResourcePolicyAnno] == KeepPolicy { + c.Log("Skipping delete of %q due to annotation [%s=%s]", info.Name, ResourcePolicyAnno, KeepPolicy) + continue + } + res.Deleted = append(res.Deleted, info) if err := deleteResource(info); err != nil { if apierrors.IsNotFound(err) { diff --git a/pkg/kube/resource_policy.go b/pkg/kube/resource_policy.go new file mode 100644 index 000000000..5f391eb50 --- /dev/null +++ b/pkg/kube/resource_policy.go @@ -0,0 +1,26 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package kube // import "helm.sh/helm/v3/pkg/kube" + +// ResourcePolicyAnno is the annotation name for a resource policy +const ResourcePolicyAnno = "helm.sh/resource-policy" + +// KeepPolicy is the resource policy type for keep +// +// This resource policy type allows resources to skip being deleted +// during an uninstallRelease action. +const KeepPolicy = "keep" From c45869c4ad8f46140f6aea0d673aa7892f3eefad Mon Sep 17 00:00:00 2001 From: Dong Gang Date: Mon, 2 Mar 2020 14:47:54 +0800 Subject: [PATCH 2/3] fix(helm): polish goimport Signed-off-by: Dong Gang --- pkg/kube/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 04f247c93..b761c6d12 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -21,7 +21,6 @@ import ( "encoding/json" "fmt" "io" - "k8s.io/apimachinery/pkg/api/meta" "strings" "sync" "time" @@ -34,6 +33,7 @@ import ( apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/runtime" From 69d9722edaea6f54194d6ab508142d3f4eb2be14 Mon Sep 17 00:00:00 2001 From: Dong Gang Date: Mon, 2 Mar 2020 14:55:53 +0800 Subject: [PATCH 3/3] test(helm): fix client update error Signed-off-by: Dong Gang --- pkg/kube/client_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/kube/client_test.go b/pkg/kube/client_test.go index 9e7581d00..aa081423c 100644 --- a/pkg/kube/client_test.go +++ b/pkg/kube/client_test.go @@ -147,6 +147,8 @@ func TestUpdate(t *testing.T) { return newResponse(200, &listB.Items[1]) case p == "/namespaces/default/pods/squid" && m == "DELETE": return newResponse(200, &listB.Items[1]) + case p == "/namespaces/default/pods/squid" && m == "GET": + return newResponse(200, &listB.Items[2]) default: t.Fatalf("unexpected request: %s %s", req.Method, req.URL.Path) return nil, nil @@ -184,6 +186,7 @@ func TestUpdate(t *testing.T) { "/namespaces/default/pods/otter:GET", "/namespaces/default/pods/dolphin:GET", "/namespaces/default/pods:POST", + "/namespaces/default/pods/squid:GET", "/namespaces/default/pods/squid:DELETE", } if len(expectedActions) != len(actions) {