k8s.io/kubernetes@v1.29.3/pkg/controller/garbagecollector/patch.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package garbagecollector 18 19 import ( 20 "context" 21 "encoding/json" 22 "fmt" 23 24 "k8s.io/apimachinery/pkg/api/errors" 25 "k8s.io/apimachinery/pkg/api/meta" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/runtime" 28 "k8s.io/apimachinery/pkg/types" 29 "k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly" 30 ) 31 32 // getMetadata tries getting object metadata from local cache, and sends GET request to apiserver when 33 // local cache is not available or not latest. 34 func (gc *GarbageCollector) getMetadata(apiVersion, kind, namespace, name string) (metav1.Object, error) { 35 apiResource, _, err := gc.apiResource(apiVersion, kind) 36 if err != nil { 37 return nil, err 38 } 39 gc.dependencyGraphBuilder.monitorLock.RLock() 40 defer gc.dependencyGraphBuilder.monitorLock.RUnlock() 41 m, ok := gc.dependencyGraphBuilder.monitors[apiResource] 42 if !ok || m == nil { 43 // If local cache doesn't exist for mapping.Resource, send a GET request to API server 44 return gc.metadataClient.Resource(apiResource).Namespace(namespace).Get(context.TODO(), name, metav1.GetOptions{}) 45 } 46 key := name 47 if len(namespace) != 0 { 48 key = namespace + "/" + name 49 } 50 raw, exist, err := m.store.GetByKey(key) 51 if err != nil { 52 return nil, err 53 } 54 if !exist { 55 // If local cache doesn't contain the object, send a GET request to API server 56 return gc.metadataClient.Resource(apiResource).Namespace(namespace).Get(context.TODO(), name, metav1.GetOptions{}) 57 } 58 obj, ok := raw.(runtime.Object) 59 if !ok { 60 return nil, fmt.Errorf("expect a runtime.Object, got %v", raw) 61 } 62 return meta.Accessor(obj) 63 } 64 65 type objectForFinalizersPatch struct { 66 ObjectMetaForFinalizersPatch `json:"metadata"` 67 } 68 69 // ObjectMetaForFinalizersPatch defines object meta struct for finalizers patch operation. 70 type ObjectMetaForFinalizersPatch struct { 71 ResourceVersion string `json:"resourceVersion"` 72 Finalizers []string `json:"finalizers"` 73 } 74 75 type objectForPatch struct { 76 ObjectMetaForPatch `json:"metadata"` 77 } 78 79 // ObjectMetaForPatch defines object meta struct for patch operation. 80 type ObjectMetaForPatch struct { 81 ResourceVersion string `json:"resourceVersion"` 82 OwnerReferences []metav1.OwnerReference `json:"ownerReferences"` 83 } 84 85 // jsonMergePatchFunc defines the interface for functions that construct json merge patches that manipulate 86 // owner reference array. 87 type jsonMergePatchFunc func(*node) ([]byte, error) 88 89 // patch tries strategic merge patch on item first, and if SMP is not supported, it fallbacks to JSON merge 90 // patch. 91 func (gc *GarbageCollector) patch(item *node, smp []byte, jmp jsonMergePatchFunc) (*metav1.PartialObjectMetadata, error) { 92 smpResult, err := gc.patchObject(item.identity, smp, types.StrategicMergePatchType) 93 if err == nil { 94 return smpResult, nil 95 } 96 if !errors.IsUnsupportedMediaType(err) { 97 return nil, err 98 } 99 // StrategicMergePatch is not supported, use JSON merge patch instead 100 patch, err := jmp(item) 101 if err != nil { 102 return nil, err 103 } 104 return gc.patchObject(item.identity, patch, types.MergePatchType) 105 } 106 107 // Returns JSON merge patch that removes the ownerReferences matching ownerUIDs. 108 func (gc *GarbageCollector) deleteOwnerRefJSONMergePatch(item *node, ownerUIDs ...types.UID) ([]byte, error) { 109 accessor, err := gc.getMetadata(item.identity.APIVersion, item.identity.Kind, item.identity.Namespace, item.identity.Name) 110 if err != nil { 111 return nil, err 112 } 113 expectedObjectMeta := ObjectMetaForPatch{} 114 expectedObjectMeta.ResourceVersion = accessor.GetResourceVersion() 115 refs := accessor.GetOwnerReferences() 116 for _, ref := range refs { 117 var skip bool 118 for _, ownerUID := range ownerUIDs { 119 if ref.UID == ownerUID { 120 skip = true 121 break 122 } 123 } 124 if !skip { 125 expectedObjectMeta.OwnerReferences = append(expectedObjectMeta.OwnerReferences, ref) 126 } 127 } 128 return json.Marshal(objectForPatch{expectedObjectMeta}) 129 } 130 131 // Generate a patch that unsets the BlockOwnerDeletion field of all 132 // ownerReferences of node. 133 func (n *node) unblockOwnerReferencesStrategicMergePatch() ([]byte, error) { 134 var dummy metaonly.MetadataOnlyObject 135 var blockingRefs []metav1.OwnerReference 136 falseVar := false 137 for _, owner := range n.owners { 138 if owner.BlockOwnerDeletion != nil && *owner.BlockOwnerDeletion { 139 ref := owner 140 ref.BlockOwnerDeletion = &falseVar 141 blockingRefs = append(blockingRefs, ref) 142 } 143 } 144 dummy.ObjectMeta.SetOwnerReferences(blockingRefs) 145 dummy.ObjectMeta.UID = n.identity.UID 146 return json.Marshal(dummy) 147 } 148 149 // Generate a JSON merge patch that unsets the BlockOwnerDeletion field of all 150 // ownerReferences of node. 151 func (gc *GarbageCollector) unblockOwnerReferencesJSONMergePatch(n *node) ([]byte, error) { 152 accessor, err := gc.getMetadata(n.identity.APIVersion, n.identity.Kind, n.identity.Namespace, n.identity.Name) 153 if err != nil { 154 return nil, err 155 } 156 expectedObjectMeta := ObjectMetaForPatch{} 157 expectedObjectMeta.ResourceVersion = accessor.GetResourceVersion() 158 var expectedOwners []metav1.OwnerReference 159 falseVar := false 160 for _, owner := range n.owners { 161 owner.BlockOwnerDeletion = &falseVar 162 expectedOwners = append(expectedOwners, owner) 163 } 164 expectedObjectMeta.OwnerReferences = expectedOwners 165 return json.Marshal(objectForPatch{expectedObjectMeta}) 166 }