123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- /*
- Copyright 2016 The Kubernetes 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 garbagecollector
- import (
- "encoding/json"
- "fmt"
- "k8s.io/apimachinery/pkg/api/errors"
- "k8s.io/apimachinery/pkg/api/meta"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/runtime"
- "k8s.io/apimachinery/pkg/types"
- "k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly"
- )
- type objectForDeleteOwnerRefStrategicMergePatch struct {
- Metadata objectMetaForMergePatch `json:"metadata"`
- }
- type objectMetaForMergePatch struct {
- UID types.UID `json:"uid"`
- OwnerReferences []map[string]string `json:"ownerReferences"`
- }
- func deleteOwnerRefStrategicMergePatch(dependentUID types.UID, ownerUIDs ...types.UID) []byte {
- var pieces []map[string]string
- for _, ownerUID := range ownerUIDs {
- pieces = append(pieces, map[string]string{"$patch": "delete", "uid": string(ownerUID)})
- }
- patch := objectForDeleteOwnerRefStrategicMergePatch{
- Metadata: objectMetaForMergePatch{
- UID: dependentUID,
- OwnerReferences: pieces,
- },
- }
- patchBytes, err := json.Marshal(&patch)
- if err != nil {
- return []byte{}
- }
- return patchBytes
- }
- // getMetadata tries getting object metadata from local cache, and sends GET request to apiserver when
- // local cache is not available or not latest.
- func (gc *GarbageCollector) getMetadata(apiVersion, kind, namespace, name string) (metav1.Object, error) {
- apiResource, _, err := gc.apiResource(apiVersion, kind)
- if err != nil {
- return nil, err
- }
- gc.dependencyGraphBuilder.monitorLock.RLock()
- defer gc.dependencyGraphBuilder.monitorLock.RUnlock()
- m, ok := gc.dependencyGraphBuilder.monitors[apiResource]
- if !ok || m == nil {
- // If local cache doesn't exist for mapping.Resource, send a GET request to API server
- return gc.metadataClient.Resource(apiResource).Namespace(namespace).Get(name, metav1.GetOptions{})
- }
- key := name
- if len(namespace) != 0 {
- key = namespace + "/" + name
- }
- raw, exist, err := m.store.GetByKey(key)
- if err != nil {
- return nil, err
- }
- if !exist {
- // If local cache doesn't contain the object, send a GET request to API server
- return gc.metadataClient.Resource(apiResource).Namespace(namespace).Get(name, metav1.GetOptions{})
- }
- obj, ok := raw.(runtime.Object)
- if !ok {
- return nil, fmt.Errorf("expect a runtime.Object, got %v", raw)
- }
- return meta.Accessor(obj)
- }
- type objectForFinalizersPatch struct {
- ObjectMetaForFinalizersPatch `json:"metadata"`
- }
- // ObjectMetaForFinalizersPatch defines object meta struct for finalizers patch operation.
- type ObjectMetaForFinalizersPatch struct {
- ResourceVersion string `json:"resourceVersion"`
- Finalizers []string `json:"finalizers"`
- }
- type objectForPatch struct {
- ObjectMetaForPatch `json:"metadata"`
- }
- // ObjectMetaForPatch defines object meta struct for patch operation.
- type ObjectMetaForPatch struct {
- ResourceVersion string `json:"resourceVersion"`
- OwnerReferences []metav1.OwnerReference `json:"ownerReferences"`
- }
- // jsonMergePatchFunc defines the interface for functions that construct json merge patches that manipulate
- // owner reference array.
- type jsonMergePatchFunc func(*node) ([]byte, error)
- // patch tries strategic merge patch on item first, and if SMP is not supported, it fallbacks to JSON merge
- // patch.
- func (gc *GarbageCollector) patch(item *node, smp []byte, jmp jsonMergePatchFunc) (*metav1.PartialObjectMetadata, error) {
- smpResult, err := gc.patchObject(item.identity, smp, types.StrategicMergePatchType)
- if err == nil {
- return smpResult, nil
- }
- if !errors.IsUnsupportedMediaType(err) {
- return nil, err
- }
- // StrategicMergePatch is not supported, use JSON merge patch instead
- patch, err := jmp(item)
- if err != nil {
- return nil, err
- }
- return gc.patchObject(item.identity, patch, types.MergePatchType)
- }
- // Returns JSON merge patch that removes the ownerReferences matching ownerUIDs.
- func (gc *GarbageCollector) deleteOwnerRefJSONMergePatch(item *node, ownerUIDs ...types.UID) ([]byte, error) {
- accessor, err := gc.getMetadata(item.identity.APIVersion, item.identity.Kind, item.identity.Namespace, item.identity.Name)
- if err != nil {
- return nil, err
- }
- expectedObjectMeta := ObjectMetaForPatch{}
- expectedObjectMeta.ResourceVersion = accessor.GetResourceVersion()
- refs := accessor.GetOwnerReferences()
- for _, ref := range refs {
- var skip bool
- for _, ownerUID := range ownerUIDs {
- if ref.UID == ownerUID {
- skip = true
- break
- }
- }
- if !skip {
- expectedObjectMeta.OwnerReferences = append(expectedObjectMeta.OwnerReferences, ref)
- }
- }
- return json.Marshal(objectForPatch{expectedObjectMeta})
- }
- // Generate a patch that unsets the BlockOwnerDeletion field of all
- // ownerReferences of node.
- func (n *node) unblockOwnerReferencesStrategicMergePatch() ([]byte, error) {
- var dummy metaonly.MetadataOnlyObject
- var blockingRefs []metav1.OwnerReference
- falseVar := false
- for _, owner := range n.owners {
- if owner.BlockOwnerDeletion != nil && *owner.BlockOwnerDeletion {
- ref := owner
- ref.BlockOwnerDeletion = &falseVar
- blockingRefs = append(blockingRefs, ref)
- }
- }
- dummy.ObjectMeta.SetOwnerReferences(blockingRefs)
- dummy.ObjectMeta.UID = n.identity.UID
- return json.Marshal(dummy)
- }
- // Generate a JSON merge patch that unsets the BlockOwnerDeletion field of all
- // ownerReferences of node.
- func (gc *GarbageCollector) unblockOwnerReferencesJSONMergePatch(n *node) ([]byte, error) {
- accessor, err := gc.getMetadata(n.identity.APIVersion, n.identity.Kind, n.identity.Namespace, n.identity.Name)
- if err != nil {
- return nil, err
- }
- expectedObjectMeta := ObjectMetaForPatch{}
- expectedObjectMeta.ResourceVersion = accessor.GetResourceVersion()
- var expectedOwners []metav1.OwnerReference
- falseVar := false
- for _, owner := range n.owners {
- owner.BlockOwnerDeletion = &falseVar
- expectedOwners = append(expectedOwners, owner)
- }
- expectedObjectMeta.OwnerReferences = expectedOwners
- return json.Marshal(objectForPatch{expectedObjectMeta})
- }
|