...

Source file src/k8s.io/kubernetes/pkg/controller/garbagecollector/patch.go

Documentation: k8s.io/kubernetes/pkg/controller/garbagecollector

     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  }
   167  

View as plain text