mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			457 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			457 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
Copyright 2017 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 history
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"fmt"
 | 
						|
	"hash/fnv"
 | 
						|
	"sort"
 | 
						|
	"strconv"
 | 
						|
 | 
						|
	apps "k8s.io/api/apps/v1"
 | 
						|
	appsinformers "k8s.io/client-go/informers/apps/v1"
 | 
						|
	clientset "k8s.io/client-go/kubernetes"
 | 
						|
	appslisters "k8s.io/client-go/listers/apps/v1"
 | 
						|
	hashutil "k8s.io/kubernetes/pkg/util/hash"
 | 
						|
 | 
						|
	apiequality "k8s.io/apimachinery/pkg/api/equality"
 | 
						|
	"k8s.io/apimachinery/pkg/api/errors"
 | 
						|
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						|
	"k8s.io/apimachinery/pkg/labels"
 | 
						|
	"k8s.io/apimachinery/pkg/runtime"
 | 
						|
	"k8s.io/apimachinery/pkg/types"
 | 
						|
 | 
						|
	"k8s.io/apimachinery/pkg/runtime/schema"
 | 
						|
	"k8s.io/apimachinery/pkg/util/rand"
 | 
						|
	"k8s.io/client-go/tools/cache"
 | 
						|
	"k8s.io/client-go/util/retry"
 | 
						|
)
 | 
						|
 | 
						|
// ControllerRevisionHashLabel is the label used to indicate the hash value of a ControllerRevision's Data.
 | 
						|
const ControllerRevisionHashLabel = "controller.kubernetes.io/hash"
 | 
						|
 | 
						|
// ControllerRevisionName returns the Name for a ControllerRevision in the form prefix-hash. If the length
 | 
						|
// of prefix is greater than 223 bytes, it is truncated to allow for a name that is no larger than 253 bytes.
 | 
						|
func ControllerRevisionName(prefix string, hash uint32) string {
 | 
						|
	if len(prefix) > 223 {
 | 
						|
		prefix = prefix[:223]
 | 
						|
	}
 | 
						|
 | 
						|
	return fmt.Sprintf("%s-%s", prefix, rand.SafeEncodeString(strconv.FormatInt(int64(hash), 10)))
 | 
						|
}
 | 
						|
 | 
						|
// NewControllerRevision returns a ControllerRevision with a ControllerRef pointing to parent and indicating that
 | 
						|
// parent is of parentKind. The ControllerRevision has labels matching template labels, contains Data equal to data, and
 | 
						|
// has a Revision equal to revision. The collisionCount is used when creating the name of the ControllerRevision
 | 
						|
// so the name is likely unique. If the returned error is nil, the returned ControllerRevision is valid. If the
 | 
						|
// returned error is not nil, the returned ControllerRevision is invalid for use.
 | 
						|
func NewControllerRevision(parent metav1.Object,
 | 
						|
	parentKind schema.GroupVersionKind,
 | 
						|
	templateLabels map[string]string,
 | 
						|
	data runtime.RawExtension,
 | 
						|
	revision int64,
 | 
						|
	collisionCount *int32) (*apps.ControllerRevision, error) {
 | 
						|
	labelMap := make(map[string]string)
 | 
						|
	for k, v := range templateLabels {
 | 
						|
		labelMap[k] = v
 | 
						|
	}
 | 
						|
	blockOwnerDeletion := true
 | 
						|
	isController := true
 | 
						|
	cr := &apps.ControllerRevision{
 | 
						|
		ObjectMeta: metav1.ObjectMeta{
 | 
						|
			Labels: labelMap,
 | 
						|
			OwnerReferences: []metav1.OwnerReference{
 | 
						|
				{
 | 
						|
					APIVersion:         parentKind.GroupVersion().String(),
 | 
						|
					Kind:               parentKind.Kind,
 | 
						|
					Name:               parent.GetName(),
 | 
						|
					UID:                parent.GetUID(),
 | 
						|
					BlockOwnerDeletion: &blockOwnerDeletion,
 | 
						|
					Controller:         &isController,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		Data:     data,
 | 
						|
		Revision: revision,
 | 
						|
	}
 | 
						|
	hash := HashControllerRevision(cr, collisionCount)
 | 
						|
	cr.Name = ControllerRevisionName(parent.GetName(), hash)
 | 
						|
	cr.Labels[ControllerRevisionHashLabel] = strconv.FormatInt(int64(hash), 10)
 | 
						|
	return cr, nil
 | 
						|
}
 | 
						|
 | 
						|
// HashControllerRevision hashes the contents of revision's Data using FNV hashing. If probe is not nil, the byte value
 | 
						|
// of probe is added written to the hash as well.
 | 
						|
func HashControllerRevision(revision *apps.ControllerRevision, probe *int32) uint32 {
 | 
						|
	hf := fnv.New32()
 | 
						|
	if len(revision.Data.Raw) > 0 {
 | 
						|
		hf.Write(revision.Data.Raw)
 | 
						|
	}
 | 
						|
	if revision.Data.Object != nil {
 | 
						|
		hashutil.DeepHashObject(hf, revision.Data.Object)
 | 
						|
	}
 | 
						|
	if probe != nil {
 | 
						|
		hf.Write([]byte(strconv.FormatInt(int64(*probe), 10)))
 | 
						|
	}
 | 
						|
	return hf.Sum32()
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
// SortControllerRevisions sorts revisions by their Revision.
 | 
						|
func SortControllerRevisions(revisions []*apps.ControllerRevision) {
 | 
						|
	sort.Sort(byRevision(revisions))
 | 
						|
}
 | 
						|
 | 
						|
// EqualRevision returns true if lhs and rhs are either both nil, or both point to non-nil ControllerRevisions that
 | 
						|
// contain semantically equivalent data. Otherwise this method returns false.
 | 
						|
func EqualRevision(lhs *apps.ControllerRevision, rhs *apps.ControllerRevision) bool {
 | 
						|
	var lhsHash, rhsHash *uint32
 | 
						|
	if lhs == nil || rhs == nil {
 | 
						|
		return lhs == rhs
 | 
						|
	}
 | 
						|
	if hs, found := lhs.Labels[ControllerRevisionHashLabel]; found {
 | 
						|
		hash, err := strconv.ParseInt(hs, 10, 32)
 | 
						|
		if err == nil {
 | 
						|
			lhsHash = new(uint32)
 | 
						|
			*lhsHash = uint32(hash)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if hs, found := rhs.Labels[ControllerRevisionHashLabel]; found {
 | 
						|
		hash, err := strconv.ParseInt(hs, 10, 32)
 | 
						|
		if err == nil {
 | 
						|
			rhsHash = new(uint32)
 | 
						|
			*rhsHash = uint32(hash)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if lhsHash != nil && rhsHash != nil && *lhsHash != *rhsHash {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
	return bytes.Equal(lhs.Data.Raw, rhs.Data.Raw) && apiequality.Semantic.DeepEqual(lhs.Data.Object, rhs.Data.Object)
 | 
						|
}
 | 
						|
 | 
						|
// FindEqualRevisions returns all ControllerRevisions in revisions that are equal to needle using EqualRevision as the
 | 
						|
// equality test. The returned slice preserves the order of revisions.
 | 
						|
func FindEqualRevisions(revisions []*apps.ControllerRevision, needle *apps.ControllerRevision) []*apps.ControllerRevision {
 | 
						|
	var eq []*apps.ControllerRevision
 | 
						|
	for i := range revisions {
 | 
						|
		if EqualRevision(revisions[i], needle) {
 | 
						|
			eq = append(eq, revisions[i])
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return eq
 | 
						|
}
 | 
						|
 | 
						|
// byRevision implements sort.Interface to allow ControllerRevisions to be sorted by Revision.
 | 
						|
type byRevision []*apps.ControllerRevision
 | 
						|
 | 
						|
func (br byRevision) Len() int {
 | 
						|
	return len(br)
 | 
						|
}
 | 
						|
 | 
						|
func (br byRevision) Less(i, j int) bool {
 | 
						|
	return br[i].Revision < br[j].Revision
 | 
						|
}
 | 
						|
 | 
						|
func (br byRevision) Swap(i, j int) {
 | 
						|
	br[i], br[j] = br[j], br[i]
 | 
						|
}
 | 
						|
 | 
						|
// Interface provides an interface allowing for management of a Controller's history as realized by recorded
 | 
						|
// ControllerRevisions. An instance of Interface can be retrieved from NewHistory. Implementations must treat all
 | 
						|
// pointer parameters as "in" parameter, and they must not be mutated.
 | 
						|
type Interface interface {
 | 
						|
	// ListControllerRevisions lists all ControllerRevisions matching selector and owned by parent or no other
 | 
						|
	// controller. If the returned error is nil the returned slice of ControllerRevisions is valid. If the
 | 
						|
	// returned error is not nil, the returned slice is not valid.
 | 
						|
	ListControllerRevisions(parent metav1.Object, selector labels.Selector) ([]*apps.ControllerRevision, error)
 | 
						|
	// CreateControllerRevision attempts to create the revision as owned by parent via a ControllerRef. If name
 | 
						|
	// collision occurs, collisionCount (incremented each time collision occurs except for the first time) is
 | 
						|
	// added to the hash of the revision and it is renamed using ControllerRevisionName. Implementations may
 | 
						|
	// cease to attempt to retry creation after some number of attempts and return an error. If the returned
 | 
						|
	// error is not nil, creation failed. If the returned error is nil, the returned ControllerRevision has been
 | 
						|
	// created.
 | 
						|
	// Callers must make sure that collisionCount is not nil. An error is returned if it is.
 | 
						|
	CreateControllerRevision(parent metav1.Object, revision *apps.ControllerRevision, collisionCount *int32) (*apps.ControllerRevision, error)
 | 
						|
	// DeleteControllerRevision attempts to delete revision. If the returned error is not nil, deletion has failed.
 | 
						|
	DeleteControllerRevision(revision *apps.ControllerRevision) error
 | 
						|
	// UpdateControllerRevision updates revision such that its Revision is equal to newRevision. Implementations
 | 
						|
	// may retry on conflict. If the returned error is nil, the update was successful and returned ControllerRevision
 | 
						|
	// is valid. If the returned error is not nil, the update failed and the returned ControllerRevision is invalid.
 | 
						|
	UpdateControllerRevision(revision *apps.ControllerRevision, newRevision int64) (*apps.ControllerRevision, error)
 | 
						|
	// AdoptControllerRevision attempts to adopt revision by adding a ControllerRef indicating that the parent
 | 
						|
	// Object of parentKind is the owner of revision. If revision is already owned, an error is returned. If the
 | 
						|
	// resource patch fails, an error is returned. If no error is returned, the returned ControllerRevision is
 | 
						|
	// valid.
 | 
						|
	AdoptControllerRevision(parent metav1.Object, parentKind schema.GroupVersionKind, revision *apps.ControllerRevision) (*apps.ControllerRevision, error)
 | 
						|
	// ReleaseControllerRevision attempts to release parent's ownership of revision by removing parent from the
 | 
						|
	// OwnerReferences of revision. If an error is returned, parent remains the owner of revision. If no error is
 | 
						|
	// returned, the returned ControllerRevision is valid.
 | 
						|
	ReleaseControllerRevision(parent metav1.Object, revision *apps.ControllerRevision) (*apps.ControllerRevision, error)
 | 
						|
}
 | 
						|
 | 
						|
// NewHistory returns an instance of Interface that uses client to communicate with the API Server and lister to list
 | 
						|
// ControllerRevisions. This method should be used to create an Interface for all scenarios other than testing.
 | 
						|
func NewHistory(client clientset.Interface, lister appslisters.ControllerRevisionLister) Interface {
 | 
						|
	return &realHistory{client, lister}
 | 
						|
}
 | 
						|
 | 
						|
// NewFakeHistory returns an instance of Interface that uses informer to create, update, list, and delete
 | 
						|
// ControllerRevisions. This method should be used to create an Interface for testing purposes.
 | 
						|
func NewFakeHistory(informer appsinformers.ControllerRevisionInformer) Interface {
 | 
						|
	return &fakeHistory{informer.Informer().GetIndexer(), informer.Lister()}
 | 
						|
}
 | 
						|
 | 
						|
type realHistory struct {
 | 
						|
	client clientset.Interface
 | 
						|
	lister appslisters.ControllerRevisionLister
 | 
						|
}
 | 
						|
 | 
						|
func (rh *realHistory) ListControllerRevisions(parent metav1.Object, selector labels.Selector) ([]*apps.ControllerRevision, error) {
 | 
						|
	// List all revisions in the namespace that match the selector
 | 
						|
	history, err := rh.lister.ControllerRevisions(parent.GetNamespace()).List(selector)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	var owned []*apps.ControllerRevision
 | 
						|
	for i := range history {
 | 
						|
		ref := metav1.GetControllerOf(history[i])
 | 
						|
		if ref == nil || ref.UID == parent.GetUID() {
 | 
						|
			owned = append(owned, history[i])
 | 
						|
		}
 | 
						|
 | 
						|
	}
 | 
						|
	return owned, err
 | 
						|
}
 | 
						|
 | 
						|
func (rh *realHistory) CreateControllerRevision(parent metav1.Object, revision *apps.ControllerRevision, collisionCount *int32) (*apps.ControllerRevision, error) {
 | 
						|
	if collisionCount == nil {
 | 
						|
		return nil, fmt.Errorf("collisionCount should not be nil")
 | 
						|
	}
 | 
						|
 | 
						|
	// Clone the input
 | 
						|
	clone := revision.DeepCopy()
 | 
						|
 | 
						|
	// Continue to attempt to create the revision updating the name with a new hash on each iteration
 | 
						|
	for {
 | 
						|
		hash := HashControllerRevision(revision, collisionCount)
 | 
						|
		// Update the revisions name and labels
 | 
						|
		clone.Name = ControllerRevisionName(parent.GetName(), hash)
 | 
						|
		created, err := rh.client.AppsV1().ControllerRevisions(parent.GetNamespace()).Create(clone)
 | 
						|
		if errors.IsAlreadyExists(err) {
 | 
						|
			*collisionCount++
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		return created, err
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (rh *realHistory) UpdateControllerRevision(revision *apps.ControllerRevision, newRevision int64) (*apps.ControllerRevision, error) {
 | 
						|
	clone := revision.DeepCopy()
 | 
						|
	err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
 | 
						|
		if clone.Revision == newRevision {
 | 
						|
			return nil
 | 
						|
		}
 | 
						|
		clone.Revision = newRevision
 | 
						|
		updated, updateErr := rh.client.AppsV1().ControllerRevisions(clone.Namespace).Update(clone)
 | 
						|
		if updateErr == nil {
 | 
						|
			return nil
 | 
						|
		}
 | 
						|
		if updated != nil {
 | 
						|
			clone = updated
 | 
						|
		}
 | 
						|
		if updated, err := rh.lister.ControllerRevisions(clone.Namespace).Get(clone.Name); err == nil {
 | 
						|
			// make a copy so we don't mutate the shared cache
 | 
						|
			clone = updated.DeepCopy()
 | 
						|
		}
 | 
						|
		return updateErr
 | 
						|
	})
 | 
						|
	return clone, err
 | 
						|
}
 | 
						|
 | 
						|
func (rh *realHistory) DeleteControllerRevision(revision *apps.ControllerRevision) error {
 | 
						|
	return rh.client.AppsV1().ControllerRevisions(revision.Namespace).Delete(revision.Name, nil)
 | 
						|
}
 | 
						|
 | 
						|
func (rh *realHistory) AdoptControllerRevision(parent metav1.Object, parentKind schema.GroupVersionKind, revision *apps.ControllerRevision) (*apps.ControllerRevision, error) {
 | 
						|
	// Return an error if the parent does not own the revision
 | 
						|
	if owner := metav1.GetControllerOf(revision); owner != nil {
 | 
						|
		return nil, fmt.Errorf("attempt to adopt revision owned by %v", owner)
 | 
						|
	}
 | 
						|
	// Use strategic merge patch to add an owner reference indicating a controller ref
 | 
						|
	return rh.client.AppsV1().ControllerRevisions(parent.GetNamespace()).Patch(revision.GetName(),
 | 
						|
		types.StrategicMergePatchType, []byte(fmt.Sprintf(
 | 
						|
			`{"metadata":{"ownerReferences":[{"apiVersion":"%s","kind":"%s","name":"%s","uid":"%s","controller":true,"blockOwnerDeletion":true}],"uid":"%s"}}`,
 | 
						|
			parentKind.GroupVersion().String(), parentKind.Kind,
 | 
						|
			parent.GetName(), parent.GetUID(), revision.UID)))
 | 
						|
}
 | 
						|
 | 
						|
func (rh *realHistory) ReleaseControllerRevision(parent metav1.Object, revision *apps.ControllerRevision) (*apps.ControllerRevision, error) {
 | 
						|
	// Use strategic merge patch to add an owner reference indicating a controller ref
 | 
						|
	released, err := rh.client.AppsV1().ControllerRevisions(revision.GetNamespace()).Patch(revision.GetName(),
 | 
						|
		types.StrategicMergePatchType,
 | 
						|
		[]byte(fmt.Sprintf(`{"metadata":{"ownerReferences":[{"$patch":"delete","uid":"%s"}],"uid":"%s"}}`, parent.GetUID(), revision.UID)))
 | 
						|
 | 
						|
	if err != nil {
 | 
						|
		if errors.IsNotFound(err) {
 | 
						|
			// We ignore deleted revisions
 | 
						|
			return nil, nil
 | 
						|
		}
 | 
						|
		if errors.IsInvalid(err) {
 | 
						|
			// We ignore cases where the parent no longer owns the revision or where the revision has no
 | 
						|
			// owner.
 | 
						|
			return nil, nil
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return released, err
 | 
						|
}
 | 
						|
 | 
						|
type fakeHistory struct {
 | 
						|
	indexer cache.Indexer
 | 
						|
	lister  appslisters.ControllerRevisionLister
 | 
						|
}
 | 
						|
 | 
						|
func (fh *fakeHistory) ListControllerRevisions(parent metav1.Object, selector labels.Selector) ([]*apps.ControllerRevision, error) {
 | 
						|
	history, err := fh.lister.ControllerRevisions(parent.GetNamespace()).List(selector)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	var owned []*apps.ControllerRevision
 | 
						|
	for i := range history {
 | 
						|
		ref := metav1.GetControllerOf(history[i])
 | 
						|
		if ref == nil || ref.UID == parent.GetUID() {
 | 
						|
			owned = append(owned, history[i])
 | 
						|
		}
 | 
						|
 | 
						|
	}
 | 
						|
	return owned, err
 | 
						|
}
 | 
						|
 | 
						|
func (fh *fakeHistory) addRevision(revision *apps.ControllerRevision) (*apps.ControllerRevision, error) {
 | 
						|
	key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(revision)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	obj, found, err := fh.indexer.GetByKey(key)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	if found {
 | 
						|
		foundRevision := obj.(*apps.ControllerRevision)
 | 
						|
		return foundRevision, errors.NewAlreadyExists(apps.Resource("controllerrevision"), revision.Name)
 | 
						|
	}
 | 
						|
	return revision, fh.indexer.Update(revision)
 | 
						|
}
 | 
						|
 | 
						|
func (fh *fakeHistory) CreateControllerRevision(parent metav1.Object, revision *apps.ControllerRevision, collisionCount *int32) (*apps.ControllerRevision, error) {
 | 
						|
	if collisionCount == nil {
 | 
						|
		return nil, fmt.Errorf("collisionCount should not be nil")
 | 
						|
	}
 | 
						|
 | 
						|
	// Clone the input
 | 
						|
	clone := revision.DeepCopy()
 | 
						|
	clone.Namespace = parent.GetNamespace()
 | 
						|
 | 
						|
	// Continue to attempt to create the revision updating the name with a new hash on each iteration
 | 
						|
	for {
 | 
						|
		hash := HashControllerRevision(revision, collisionCount)
 | 
						|
		// Update the revisions name and labels
 | 
						|
		clone.Name = ControllerRevisionName(parent.GetName(), hash)
 | 
						|
		created, err := fh.addRevision(clone)
 | 
						|
		if errors.IsAlreadyExists(err) {
 | 
						|
			*collisionCount++
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		return created, err
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (fh *fakeHistory) DeleteControllerRevision(revision *apps.ControllerRevision) error {
 | 
						|
	key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(revision)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	obj, found, err := fh.indexer.GetByKey(key)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if !found {
 | 
						|
		return errors.NewNotFound(apps.Resource("controllerrevisions"), revision.Name)
 | 
						|
	}
 | 
						|
	return fh.indexer.Delete(obj)
 | 
						|
}
 | 
						|
 | 
						|
func (fh *fakeHistory) UpdateControllerRevision(revision *apps.ControllerRevision, newRevision int64) (*apps.ControllerRevision, error) {
 | 
						|
	clone := revision.DeepCopy()
 | 
						|
	clone.Revision = newRevision
 | 
						|
	return clone, fh.indexer.Update(clone)
 | 
						|
}
 | 
						|
 | 
						|
func (fh *fakeHistory) AdoptControllerRevision(parent metav1.Object, parentKind schema.GroupVersionKind, revision *apps.ControllerRevision) (*apps.ControllerRevision, error) {
 | 
						|
	blockOwnerDeletion := true
 | 
						|
	isController := true
 | 
						|
	if owner := metav1.GetControllerOf(revision); owner != nil {
 | 
						|
		return nil, fmt.Errorf("attempt to adopt revision owned by %v", owner)
 | 
						|
	}
 | 
						|
	key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(revision)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	_, found, err := fh.indexer.GetByKey(key)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	if !found {
 | 
						|
		return nil, errors.NewNotFound(apps.Resource("controllerrevisions"), revision.Name)
 | 
						|
	}
 | 
						|
	clone := revision.DeepCopy()
 | 
						|
	clone.OwnerReferences = append(clone.OwnerReferences, metav1.OwnerReference{
 | 
						|
		APIVersion:         parentKind.GroupVersion().String(),
 | 
						|
		Kind:               parentKind.Kind,
 | 
						|
		Name:               parent.GetName(),
 | 
						|
		UID:                parent.GetUID(),
 | 
						|
		BlockOwnerDeletion: &blockOwnerDeletion,
 | 
						|
		Controller:         &isController,
 | 
						|
	})
 | 
						|
	return clone, fh.indexer.Update(clone)
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
func (fh *fakeHistory) ReleaseControllerRevision(parent metav1.Object, revision *apps.ControllerRevision) (*apps.ControllerRevision, error) {
 | 
						|
	key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(revision)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	_, found, err := fh.indexer.GetByKey(key)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	if !found {
 | 
						|
		return nil, nil
 | 
						|
	}
 | 
						|
	clone := revision.DeepCopy()
 | 
						|
	refs := clone.OwnerReferences
 | 
						|
	clone.OwnerReferences = nil
 | 
						|
	for i := range refs {
 | 
						|
		if refs[i].UID != parent.GetUID() {
 | 
						|
			clone.OwnerReferences = append(clone.OwnerReferences, refs[i])
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return clone, fh.indexer.Update(clone)
 | 
						|
}
 |