Implement helm.sh/resource-deletion-policy annotation to override deletion cascade per resource

Signed-off-by: Danil Grigorev <danil.grigorev@suse.com>
pull/12917/head
Danil Grigorev 2 years ago
parent 833bbfa31a
commit 769742a4f8
No known key found for this signature in database
GPG Key ID: 7C96CE1776C81090

@ -484,7 +484,15 @@ func rdelete(c *Client, resources ResourceList, propagation metav1.DeletionPropa
mtx := sync.Mutex{}
err := perform(resources, func(info *resource.Info) error {
c.Log("Starting delete for %q %s", info.Name, info.Mapping.GroupVersionKind.Kind)
err := deleteResource(info, propagation)
propagationPolicy := propagation
if annotations, err := metadataAccessor.Annotations(info.Object); err != nil {
c.Log("Unable to get annotations on %q, err: %s", info.Name, err)
errs = append(errs, err)
} else if annotations != nil && annotations[ResourceDeletionPolicyAnno] != "" {
propagationPolicy = selectDeletionPolicy(annotations[ResourceDeletionPolicyAnno], propagation)
}
err := deleteResource(info, propagationPolicy)
if err == nil || apierrors.IsNotFound(err) {
if err != nil {
c.Log("Ignoring delete failure for %q %s: %v", info.Name, info.Mapping.GroupVersionKind, err)

@ -213,6 +213,93 @@ func TestUpdate(t *testing.T) {
}
}
func TestDelete(t *testing.T) {
listA := newPodList("starfish", "otter", "squid", "jellyfish")
listA.Items[0].Annotations = map[string]string{
ResourceDeletionPolicyAnno: "foreground",
}
listA.Items[1].Annotations = map[string]string{
ResourceDeletionPolicyAnno: "orphan",
}
listA.Items[2].Annotations = map[string]string{
ResourceDeletionPolicyAnno: "background",
}
listA.Items[3].Annotations = map[string]string{
ResourceDeletionPolicyAnno: "oops",
}
var actions []string
c := newTestClient(t)
c.Factory.(*cmdtesting.TestFactory).UnstructuredClient = &fake.RESTClient{
NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
p, m := req.URL.Path, req.Method
b, err := io.ReadAll(req.Body)
if err != nil {
t.Fatal(err)
}
req.Body.Close()
actions = append(actions, p+":"+m)
t.Logf("got request %s %s", p, m)
switch {
case p == "/namespaces/default/pods/jellyfish" && m == "DELETE" && string(b) == "{\"propagationPolicy\":\"Background\"}\n":
return newResponse(200, &listA.Items[3])
case p == "/namespaces/default/pods/squid" && m == "DELETE" && string(b) == "{\"propagationPolicy\":\"Background\"}\n":
return newResponse(200, &listA.Items[2])
case p == "/namespaces/default/pods/otter" && m == "DELETE" && string(b) == "{\"propagationPolicy\":\"Orphan\"}\n":
return newResponse(200, &listA.Items[1])
case p == "/namespaces/default/pods/starfish" && m == "DELETE" && string(b) == "{\"propagationPolicy\":\"Foreground\"}\n":
return newResponse(200, &listA.Items[0])
default:
t.Fatalf("unexpected request: %s %s", req.Method, req.URL.Path)
return nil, nil
}
}),
}
first, err := c.Build(objBody(&listA), false)
if err != nil {
t.Fatal(err)
}
result, errs := c.Delete(first)
if len(errs) > 0 {
t.Fatal(errs)
}
if len(result.Created) != 0 {
t.Errorf("expected 0 resource created, got %d", len(result.Created))
}
if len(result.Updated) != 0 {
t.Errorf("expected 0 resource updated, got %d", len(result.Updated))
}
if len(result.Deleted) != 4 {
t.Errorf("expected 4 resource deleted, got %d", len(result.Deleted))
}
expectedActions := []string{
"/namespaces/default/pods/squid:DELETE",
"/namespaces/default/pods/starfish:DELETE",
"/namespaces/default/pods/otter:DELETE",
"/namespaces/default/pods/jellyfish:DELETE",
}
if len(expectedActions) != len(actions) {
t.Fatalf("unexpected number of requests, expected %d, got %d", len(expectedActions), len(actions))
}
for _, v := range expectedActions {
found := false
for _, action := range actions {
if action == v {
found = true
}
}
if !found {
t.Errorf("expected %s request got %#v", v, actions)
}
}
}
func TestBuild(t *testing.T) {
tests := []struct {
name string

@ -0,0 +1,40 @@
/*
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"
import (
"strings"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
const ResourceDeletionPolicyAnno = "helm.sh/resource-deletion-policy"
// selectDeletionPolicy allows to select an override deleteion policy per resource,
// based on ResourceDeletionPolicyAnno.
func selectDeletionPolicy(policyAnnotation string, defualt v1.DeletionPropagation) v1.DeletionPropagation {
switch policyAnnotation {
case strings.ToLower(string(v1.DeletePropagationBackground)):
return v1.DeletePropagationBackground
case strings.ToLower(string(v1.DeletePropagationForeground)):
return v1.DeletePropagationForeground
case strings.ToLower(string(v1.DeletePropagationOrphan)):
return v1.DeletePropagationOrphan
default:
return defualt
}
}
Loading…
Cancel
Save