2016-06-10 19:28:42 -04:00
/ *
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 controller
import (
2021-04-22 14:14:52 -04:00
"context"
2019-10-09 21:44:54 -04:00
"encoding/json"
2016-06-10 19:28:42 -04:00
"fmt"
2017-03-10 20:13:51 -05:00
"sync"
2016-06-10 19:28:42 -04:00
2018-02-14 13:35:38 -05:00
apps "k8s.io/api/apps/v1"
2019-10-09 21:44:54 -04:00
v1 "k8s.io/api/core/v1"
2017-01-13 12:48:50 -05:00
"k8s.io/apimachinery/pkg/api/errors"
2017-01-11 09:09:48 -05:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema"
2019-10-09 21:44:54 -04:00
"k8s.io/apimachinery/pkg/types"
2017-02-16 11:53:34 -05:00
utilerrors "k8s.io/apimachinery/pkg/util/errors"
2020-04-17 15:25:06 -04:00
"k8s.io/klog/v2"
2016-06-10 19:28:42 -04:00
)
2017-05-24 10:52:36 -04:00
type BaseControllerRefManager struct {
Controller metav1 . Object
Selector labels . Selector
2017-03-10 20:13:51 -05:00
canAdoptErr error
canAdoptOnce sync . Once
2021-04-22 14:14:52 -04:00
CanAdoptFunc func ( ctx context . Context ) error
2017-03-10 20:13:51 -05:00
}
2021-04-22 14:14:52 -04:00
func ( m * BaseControllerRefManager ) CanAdopt ( ctx context . Context ) error {
2017-03-10 20:13:51 -05:00
m . canAdoptOnce . Do ( func ( ) {
2017-05-24 10:52:36 -04:00
if m . CanAdoptFunc != nil {
2021-04-22 14:14:52 -04:00
m . canAdoptErr = m . CanAdoptFunc ( ctx )
2017-03-10 20:13:51 -05:00
}
} )
return m . canAdoptErr
2017-02-16 11:53:34 -05:00
}
2017-05-24 10:52:36 -04:00
// ClaimObject tries to take ownership of an object for this controller.
2017-02-16 11:53:34 -05:00
//
// It will reconcile the following:
2022-07-19 20:54:13 -04:00
// - Adopt orphans if the match function returns true.
// - Release owned objects if the match function returns false.
2017-02-16 11:53:34 -05:00
//
2017-05-24 10:52:36 -04:00
// A non-nil error is returned if some form of reconciliation was attempted and
2017-02-16 11:53:34 -05:00
// failed. Usually, controllers should try again later in case reconciliation
// is still needed.
//
// If the error is nil, either the reconciliation succeeded, or no
// reconciliation was necessary. The returned boolean indicates whether you now
// own the object.
//
// No reconciliation will be attempted if the controller is being deleted.
2021-11-10 17:56:46 -05:00
func ( m * BaseControllerRefManager ) ClaimObject ( ctx context . Context , obj metav1 . Object , match func ( metav1 . Object ) bool , adopt , release func ( context . Context , metav1 . Object ) error ) ( bool , error ) {
2019-09-23 09:48:39 -04:00
controllerRef := metav1 . GetControllerOfNoCopy ( obj )
2017-02-16 11:53:34 -05:00
if controllerRef != nil {
2017-05-24 10:52:36 -04:00
if controllerRef . UID != m . Controller . GetUID ( ) {
2017-02-16 11:53:34 -05:00
// Owned by someone else. Ignore.
return false , nil
}
2017-02-23 19:23:59 -05:00
if match ( obj ) {
2017-02-16 11:53:34 -05:00
// We already own it and the selector matches.
// Return true (successfully claimed) before checking deletion timestamp.
// We're still allowed to claim things we already own while being deleted
// because doing so requires taking no actions.
return true , nil
}
// Owned by us but selector doesn't match.
// Try to release, unless we're being deleted.
2017-05-24 10:52:36 -04:00
if m . Controller . GetDeletionTimestamp ( ) != nil {
2017-02-16 11:53:34 -05:00
return false , nil
}
2021-11-10 17:56:46 -05:00
if err := release ( ctx , obj ) ; err != nil {
2017-02-16 11:53:34 -05:00
// If the pod no longer exists, ignore the error.
if errors . IsNotFound ( err ) {
return false , nil
}
// Either someone else released it, or there was a transient error.
// The controller should requeue and try again if it's still stale.
return false , err
}
// Successfully released.
return false , nil
}
// It's an orphan.
2017-05-24 10:52:36 -04:00
if m . Controller . GetDeletionTimestamp ( ) != nil || ! match ( obj ) {
2017-02-16 11:53:34 -05:00
// Ignore if we're being deleted or selector doesn't match.
return false , nil
}
2017-04-06 06:57:39 -04:00
if obj . GetDeletionTimestamp ( ) != nil {
// Ignore if the object is being deleted
return false , nil
}
2021-11-01 05:36:15 -04:00
2021-11-04 01:08:47 -04:00
if len ( m . Controller . GetNamespace ( ) ) > 0 && m . Controller . GetNamespace ( ) != obj . GetNamespace ( ) {
2021-11-01 05:36:15 -04:00
// Ignore if namespace not match
return false , nil
}
2017-02-16 11:53:34 -05:00
// Selector matches. Try to adopt.
2021-04-22 14:14:52 -04:00
if err := adopt ( ctx , obj ) ; err != nil {
2017-02-16 11:53:34 -05:00
// If the pod no longer exists, ignore the error.
if errors . IsNotFound ( err ) {
return false , nil
}
// Either someone else claimed it first, or there was a transient error.
// The controller should requeue and try again if it's still orphaned.
return false , err
}
// Successfully adopted.
return true , nil
}
2016-06-10 19:28:42 -04:00
type PodControllerRefManager struct {
2017-05-24 10:52:36 -04:00
BaseControllerRefManager
2017-02-16 11:53:34 -05:00
controllerKind schema . GroupVersionKind
podControl PodControlInterface
2021-01-19 17:04:39 -05:00
finalizers [ ] string
2016-06-10 19:28:42 -04:00
}
// NewPodControllerRefManager returns a PodControllerRefManager that exposes
// methods to manage the controllerRef of pods.
2017-03-10 20:13:51 -05:00
//
2017-05-24 10:52:36 -04:00
// The CanAdopt() function can be used to perform a potentially expensive check
2017-03-10 20:13:51 -05:00
// (such as a live GET from the API server) prior to the first adoption.
// It will only be called (at most once) if an adoption is actually attempted.
2017-05-24 10:52:36 -04:00
// If CanAdopt() returns a non-nil error, all adoptions will fail.
2017-03-10 20:13:51 -05:00
//
2017-05-24 10:52:36 -04:00
// NOTE: Once CanAdopt() is called, it will not be called again by the same
2022-12-17 17:31:05 -05:00
// PodControllerRefManager instance. Create a new instance if it makes
// sense to check CanAdopt() again (e.g. in a different sync pass).
2016-06-10 19:28:42 -04:00
func NewPodControllerRefManager (
podControl PodControlInterface ,
2017-02-16 11:53:34 -05:00
controller metav1 . Object ,
selector labels . Selector ,
2016-11-20 21:55:31 -05:00
controllerKind schema . GroupVersionKind ,
2021-04-22 14:14:52 -04:00
canAdopt func ( ctx context . Context ) error ,
2021-01-19 17:04:39 -05:00
finalizers ... string ,
2016-06-10 19:28:42 -04:00
) * PodControllerRefManager {
2017-02-16 11:53:34 -05:00
return & PodControllerRefManager {
2017-05-24 10:52:36 -04:00
BaseControllerRefManager : BaseControllerRefManager {
Controller : controller ,
Selector : selector ,
CanAdoptFunc : canAdopt ,
2017-02-16 11:53:34 -05:00
} ,
controllerKind : controllerKind ,
podControl : podControl ,
2021-01-19 17:04:39 -05:00
finalizers : finalizers ,
2017-02-16 11:53:34 -05:00
}
2016-06-10 19:28:42 -04:00
}
2017-02-16 11:53:34 -05:00
// ClaimPods tries to take ownership of a list of Pods.
//
// It will reconcile the following:
2022-07-19 20:54:13 -04:00
// - Adopt orphans if the selector matches.
// - Release owned objects if the selector no longer matches.
2017-02-16 11:53:34 -05:00
//
2017-02-23 19:23:59 -05:00
// Optional: If one or more filters are specified, a Pod will only be claimed if
// all filters return true.
//
2017-05-24 10:52:36 -04:00
// A non-nil error is returned if some form of reconciliation was attempted and
2017-02-16 11:53:34 -05:00
// failed. Usually, controllers should try again later in case reconciliation
// is still needed.
//
// If the error is nil, either the reconciliation succeeded, or no
// reconciliation was necessary. The list of Pods that you now own is returned.
2021-04-22 14:14:52 -04:00
func ( m * PodControllerRefManager ) ClaimPods ( ctx context . Context , pods [ ] * v1 . Pod , filters ... func ( * v1 . Pod ) bool ) ( [ ] * v1 . Pod , error ) {
2017-02-16 11:53:34 -05:00
var claimed [ ] * v1 . Pod
var errlist [ ] error
2017-02-23 19:23:59 -05:00
match := func ( obj metav1 . Object ) bool {
pod := obj . ( * v1 . Pod )
// Check selector first so filters only run on potentially matching Pods.
2017-05-24 10:52:36 -04:00
if ! m . Selector . Matches ( labels . Set ( pod . Labels ) ) {
2017-02-23 19:23:59 -05:00
return false
}
for _ , filter := range filters {
if ! filter ( pod ) {
return false
}
}
return true
}
2021-04-22 14:14:52 -04:00
adopt := func ( ctx context . Context , obj metav1 . Object ) error {
return m . AdoptPod ( ctx , obj . ( * v1 . Pod ) )
2017-02-16 11:53:34 -05:00
}
2021-11-10 17:56:46 -05:00
release := func ( ctx context . Context , obj metav1 . Object ) error {
return m . ReleasePod ( ctx , obj . ( * v1 . Pod ) )
2017-02-16 11:53:34 -05:00
}
for _ , pod := range pods {
2021-04-22 14:14:52 -04:00
ok , err := m . ClaimObject ( ctx , pod , match , adopt , release )
2017-02-16 11:53:34 -05:00
if err != nil {
errlist = append ( errlist , err )
continue
2016-06-10 19:28:42 -04:00
}
2017-02-16 11:53:34 -05:00
if ok {
claimed = append ( claimed , pod )
2016-06-10 19:28:42 -04:00
}
}
2017-02-16 11:53:34 -05:00
return claimed , utilerrors . NewAggregate ( errlist )
2016-06-10 19:28:42 -04:00
}
// AdoptPod sends a patch to take control of the pod. It returns the error if
// the patching fails.
2021-04-22 14:14:52 -04:00
func ( m * PodControllerRefManager ) AdoptPod ( ctx context . Context , pod * v1 . Pod ) error {
if err := m . CanAdopt ( ctx ) ; err != nil {
2017-03-10 20:13:51 -05:00
return fmt . Errorf ( "can't adopt Pod %v/%v (%v): %v" , pod . Namespace , pod . Name , pod . UID , err )
2016-06-10 19:28:42 -04:00
}
2017-02-16 11:53:34 -05:00
// Note that ValidateOwnerReferences() will reject this patch if another
// OwnerReference exists with controller=true.
2019-10-09 21:44:54 -04:00
2021-01-19 17:04:39 -05:00
patchBytes , err := ownerRefControllerPatch ( m . Controller , m . controllerKind , pod . UID , m . finalizers ... )
2019-10-09 21:44:54 -04:00
if err != nil {
return err
}
2021-11-10 17:56:46 -05:00
return m . podControl . PatchPod ( ctx , pod . Namespace , pod . Name , patchBytes )
2016-06-10 19:28:42 -04:00
}
// ReleasePod sends a patch to free the pod from the control of the controller.
// It returns the error if the patching fails. 404 and 422 errors are ignored.
2021-11-10 17:56:46 -05:00
func ( m * PodControllerRefManager ) ReleasePod ( ctx context . Context , pod * v1 . Pod ) error {
2023-07-12 04:45:00 -04:00
logger := klog . FromContext ( ctx )
logger . V ( 2 ) . Info ( "Patching pod to remove its controllerRef" , "pod" , klog . KObj ( pod ) , "gvk" , m . controllerKind , "controller" , m . Controller . GetName ( ) )
2021-11-05 09:33:52 -04:00
patchBytes , err := GenerateDeleteOwnerRefStrategicMergeBytes ( pod . UID , [ ] types . UID { m . Controller . GetUID ( ) } , m . finalizers ... )
2019-10-09 21:44:54 -04:00
if err != nil {
return err
}
2021-11-10 17:56:46 -05:00
err = m . podControl . PatchPod ( ctx , pod . Namespace , pod . Name , patchBytes )
2016-06-10 19:28:42 -04:00
if err != nil {
if errors . IsNotFound ( err ) {
// If the pod no longer exists, ignore it.
return nil
}
if errors . IsInvalid ( err ) {
// Invalid error will be returned in two cases: 1. the pod
// has no owner reference, 2. the uid of the pod doesn't
// match, which means the pod is deleted and then recreated.
// In both cases, the error can be ignored.
// TODO: If the pod has owner references, but none of them
// has the owner.UID, server will silently ignore the patch.
// Investigate why.
return nil
}
}
return err
}
2016-10-27 02:58:20 -04:00
// ReplicaSetControllerRefManager is used to manage controllerRef of ReplicaSets.
// Three methods are defined on this object 1: Classify 2: AdoptReplicaSet and
// 3: ReleaseReplicaSet which are used to classify the ReplicaSets into appropriate
// categories and accordingly adopt or release them. See comments on these functions
// for more details.
type ReplicaSetControllerRefManager struct {
2017-05-24 10:52:36 -04:00
BaseControllerRefManager
2017-02-16 11:53:34 -05:00
controllerKind schema . GroupVersionKind
rsControl RSControlInterface
2016-10-27 02:58:20 -04:00
}
// NewReplicaSetControllerRefManager returns a ReplicaSetControllerRefManager that exposes
// methods to manage the controllerRef of ReplicaSets.
2017-03-10 20:13:51 -05:00
//
2017-05-24 10:52:36 -04:00
// The CanAdopt() function can be used to perform a potentially expensive check
2017-03-10 20:13:51 -05:00
// (such as a live GET from the API server) prior to the first adoption.
// It will only be called (at most once) if an adoption is actually attempted.
2017-05-24 10:52:36 -04:00
// If CanAdopt() returns a non-nil error, all adoptions will fail.
2017-03-10 20:13:51 -05:00
//
2017-05-24 10:52:36 -04:00
// NOTE: Once CanAdopt() is called, it will not be called again by the same
2022-12-17 17:31:05 -05:00
// ReplicaSetControllerRefManager instance. Create a new instance if it
// makes sense to check CanAdopt() again (e.g. in a different sync pass).
2016-10-27 02:58:20 -04:00
func NewReplicaSetControllerRefManager (
rsControl RSControlInterface ,
2017-02-16 11:53:34 -05:00
controller metav1 . Object ,
selector labels . Selector ,
2016-10-27 02:58:20 -04:00
controllerKind schema . GroupVersionKind ,
2021-04-22 14:14:52 -04:00
canAdopt func ( ctx context . Context ) error ,
2016-10-27 02:58:20 -04:00
) * ReplicaSetControllerRefManager {
2017-02-16 11:53:34 -05:00
return & ReplicaSetControllerRefManager {
2017-05-24 10:52:36 -04:00
BaseControllerRefManager : BaseControllerRefManager {
Controller : controller ,
Selector : selector ,
CanAdoptFunc : canAdopt ,
2017-02-16 11:53:34 -05:00
} ,
controllerKind : controllerKind ,
rsControl : rsControl ,
}
2016-10-27 02:58:20 -04:00
}
2017-02-16 11:53:34 -05:00
// ClaimReplicaSets tries to take ownership of a list of ReplicaSets.
//
// It will reconcile the following:
2022-07-19 20:54:13 -04:00
// - Adopt orphans if the selector matches.
// - Release owned objects if the selector no longer matches.
2017-02-16 11:53:34 -05:00
//
2017-05-24 10:52:36 -04:00
// A non-nil error is returned if some form of reconciliation was attempted and
2017-02-16 11:53:34 -05:00
// failed. Usually, controllers should try again later in case reconciliation
// is still needed.
//
// If the error is nil, either the reconciliation succeeded, or no
// reconciliation was necessary. The list of ReplicaSets that you now own is
// returned.
2021-04-22 14:14:52 -04:00
func ( m * ReplicaSetControllerRefManager ) ClaimReplicaSets ( ctx context . Context , sets [ ] * apps . ReplicaSet ) ( [ ] * apps . ReplicaSet , error ) {
2018-03-19 19:47:20 -04:00
var claimed [ ] * apps . ReplicaSet
2017-02-16 11:53:34 -05:00
var errlist [ ] error
2017-02-23 19:23:59 -05:00
match := func ( obj metav1 . Object ) bool {
2017-05-24 10:52:36 -04:00
return m . Selector . Matches ( labels . Set ( obj . GetLabels ( ) ) )
2017-02-23 19:23:59 -05:00
}
2021-04-22 14:14:52 -04:00
adopt := func ( ctx context . Context , obj metav1 . Object ) error {
return m . AdoptReplicaSet ( ctx , obj . ( * apps . ReplicaSet ) )
2017-02-16 11:53:34 -05:00
}
2021-11-10 17:56:46 -05:00
release := func ( ctx context . Context , obj metav1 . Object ) error {
return m . ReleaseReplicaSet ( ctx , obj . ( * apps . ReplicaSet ) )
2017-02-16 11:53:34 -05:00
}
for _ , rs := range sets {
2021-04-22 14:14:52 -04:00
ok , err := m . ClaimObject ( ctx , rs , match , adopt , release )
2017-02-16 11:53:34 -05:00
if err != nil {
errlist = append ( errlist , err )
continue
}
if ok {
claimed = append ( claimed , rs )
2016-10-27 02:58:20 -04:00
}
}
2017-02-16 11:53:34 -05:00
return claimed , utilerrors . NewAggregate ( errlist )
2016-10-27 02:58:20 -04:00
}
2017-06-26 00:41:10 -04:00
// AdoptReplicaSet sends a patch to take control of the ReplicaSet. It returns
// the error if the patching fails.
2021-04-22 14:14:52 -04:00
func ( m * ReplicaSetControllerRefManager ) AdoptReplicaSet ( ctx context . Context , rs * apps . ReplicaSet ) error {
if err := m . CanAdopt ( ctx ) ; err != nil {
2017-03-10 20:13:51 -05:00
return fmt . Errorf ( "can't adopt ReplicaSet %v/%v (%v): %v" , rs . Namespace , rs . Name , rs . UID , err )
2016-10-27 02:58:20 -04:00
}
2017-02-16 11:53:34 -05:00
// Note that ValidateOwnerReferences() will reject this patch if another
// OwnerReference exists with controller=true.
2019-10-09 21:44:54 -04:00
patchBytes , err := ownerRefControllerPatch ( m . Controller , m . controllerKind , rs . UID )
if err != nil {
return err
}
2021-11-10 17:56:46 -05:00
return m . rsControl . PatchReplicaSet ( ctx , rs . Namespace , rs . Name , patchBytes )
2016-10-27 02:58:20 -04:00
}
// ReleaseReplicaSet sends a patch to free the ReplicaSet from the control of the Deployment controller.
// It returns the error if the patching fails. 404 and 422 errors are ignored.
2021-11-10 17:56:46 -05:00
func ( m * ReplicaSetControllerRefManager ) ReleaseReplicaSet ( ctx context . Context , replicaSet * apps . ReplicaSet ) error {
2023-07-12 04:45:00 -04:00
logger := klog . FromContext ( ctx )
logger . V ( 2 ) . Info ( "Patching ReplicaSet to remove its controllerRef" , "replicaSet" , klog . KObj ( replicaSet ) , "gvk" , m . controllerKind , "controller" , m . Controller . GetName ( ) )
2021-11-05 09:33:52 -04:00
patchBytes , err := GenerateDeleteOwnerRefStrategicMergeBytes ( replicaSet . UID , [ ] types . UID { m . Controller . GetUID ( ) } )
2019-10-09 21:44:54 -04:00
if err != nil {
return err
}
2021-11-10 17:56:46 -05:00
err = m . rsControl . PatchReplicaSet ( ctx , replicaSet . Namespace , replicaSet . Name , patchBytes )
2016-10-27 02:58:20 -04:00
if err != nil {
if errors . IsNotFound ( err ) {
// If the ReplicaSet no longer exists, ignore it.
return nil
}
if errors . IsInvalid ( err ) {
// Invalid error will be returned in two cases: 1. the ReplicaSet
// has no owner reference, 2. the uid of the ReplicaSet doesn't
// match, which means the ReplicaSet is deleted and then recreated.
// In both cases, the error can be ignored.
return nil
}
}
return err
}
2017-03-10 20:13:51 -05:00
2017-05-24 10:52:36 -04:00
// RecheckDeletionTimestamp returns a CanAdopt() function to recheck deletion.
2017-03-10 20:13:51 -05:00
//
2017-05-24 10:52:36 -04:00
// The CanAdopt() function calls getObject() to fetch the latest value,
2017-03-10 20:13:51 -05:00
// and denies adoption attempts if that object has a non-nil DeletionTimestamp.
2021-04-22 14:14:52 -04:00
func RecheckDeletionTimestamp ( getObject func ( context . Context ) ( metav1 . Object , error ) ) func ( context . Context ) error {
return func ( ctx context . Context ) error {
obj , err := getObject ( ctx )
2017-03-10 20:13:51 -05:00
if err != nil {
return fmt . Errorf ( "can't recheck DeletionTimestamp: %v" , err )
}
if obj . GetDeletionTimestamp ( ) != nil {
return fmt . Errorf ( "%v/%v has just been deleted at %v" , obj . GetNamespace ( ) , obj . GetName ( ) , obj . GetDeletionTimestamp ( ) )
}
return nil
}
}
2017-06-02 21:02:01 -04:00
// ControllerRevisionControllerRefManager is used to manage controllerRef of ControllerRevisions.
// Three methods are defined on this object 1: Classify 2: AdoptControllerRevision and
// 3: ReleaseControllerRevision which are used to classify the ControllerRevisions into appropriate
// categories and accordingly adopt or release them. See comments on these functions
// for more details.
type ControllerRevisionControllerRefManager struct {
2017-05-24 10:52:36 -04:00
BaseControllerRefManager
2017-06-02 21:02:01 -04:00
controllerKind schema . GroupVersionKind
crControl ControllerRevisionControlInterface
}
// NewControllerRevisionControllerRefManager returns a ControllerRevisionControllerRefManager that exposes
// methods to manage the controllerRef of ControllerRevisions.
//
// The canAdopt() function can be used to perform a potentially expensive check
// (such as a live GET from the API server) prior to the first adoption.
// It will only be called (at most once) if an adoption is actually attempted.
// If canAdopt() returns a non-nil error, all adoptions will fail.
//
// NOTE: Once canAdopt() is called, it will not be called again by the same
2022-12-17 17:31:05 -05:00
// ControllerRevisionControllerRefManager instance. Create a new instance if it
// makes sense to check canAdopt() again (e.g. in a different sync pass).
2017-06-02 21:02:01 -04:00
func NewControllerRevisionControllerRefManager (
crControl ControllerRevisionControlInterface ,
controller metav1 . Object ,
selector labels . Selector ,
controllerKind schema . GroupVersionKind ,
2021-04-22 14:14:52 -04:00
canAdopt func ( ctx context . Context ) error ,
2017-06-02 21:02:01 -04:00
) * ControllerRevisionControllerRefManager {
return & ControllerRevisionControllerRefManager {
2017-05-24 10:52:36 -04:00
BaseControllerRefManager : BaseControllerRefManager {
Controller : controller ,
Selector : selector ,
CanAdoptFunc : canAdopt ,
2017-06-02 21:02:01 -04:00
} ,
controllerKind : controllerKind ,
crControl : crControl ,
}
}
// ClaimControllerRevisions tries to take ownership of a list of ControllerRevisions.
//
// It will reconcile the following:
2022-07-19 20:54:13 -04:00
// - Adopt orphans if the selector matches.
// - Release owned objects if the selector no longer matches.
2017-06-02 21:02:01 -04:00
//
2018-02-09 01:53:53 -05:00
// A non-nil error is returned if some form of reconciliation was attempted and
2017-06-02 21:02:01 -04:00
// failed. Usually, controllers should try again later in case reconciliation
// is still needed.
//
// If the error is nil, either the reconciliation succeeded, or no
// reconciliation was necessary. The list of ControllerRevisions that you now own is
// returned.
2021-04-22 14:14:52 -04:00
func ( m * ControllerRevisionControllerRefManager ) ClaimControllerRevisions ( ctx context . Context , histories [ ] * apps . ControllerRevision ) ( [ ] * apps . ControllerRevision , error ) {
2018-02-14 13:35:38 -05:00
var claimed [ ] * apps . ControllerRevision
2017-06-02 21:02:01 -04:00
var errlist [ ] error
match := func ( obj metav1 . Object ) bool {
2017-05-24 10:52:36 -04:00
return m . Selector . Matches ( labels . Set ( obj . GetLabels ( ) ) )
2017-06-02 21:02:01 -04:00
}
2021-04-22 14:14:52 -04:00
adopt := func ( ctx context . Context , obj metav1 . Object ) error {
return m . AdoptControllerRevision ( ctx , obj . ( * apps . ControllerRevision ) )
2017-06-02 21:02:01 -04:00
}
2021-11-10 17:56:46 -05:00
release := func ( ctx context . Context , obj metav1 . Object ) error {
return m . ReleaseControllerRevision ( ctx , obj . ( * apps . ControllerRevision ) )
2017-06-02 21:02:01 -04:00
}
for _ , h := range histories {
2021-04-22 14:14:52 -04:00
ok , err := m . ClaimObject ( ctx , h , match , adopt , release )
2017-06-02 21:02:01 -04:00
if err != nil {
errlist = append ( errlist , err )
continue
}
if ok {
claimed = append ( claimed , h )
}
}
return claimed , utilerrors . NewAggregate ( errlist )
}
// AdoptControllerRevision sends a patch to take control of the ControllerRevision. It returns the error if
// the patching fails.
2021-04-22 14:14:52 -04:00
func ( m * ControllerRevisionControllerRefManager ) AdoptControllerRevision ( ctx context . Context , history * apps . ControllerRevision ) error {
if err := m . CanAdopt ( ctx ) ; err != nil {
2017-06-02 21:02:01 -04:00
return fmt . Errorf ( "can't adopt ControllerRevision %v/%v (%v): %v" , history . Namespace , history . Name , history . UID , err )
}
// Note that ValidateOwnerReferences() will reject this patch if another
// OwnerReference exists with controller=true.
2019-10-09 21:44:54 -04:00
patchBytes , err := ownerRefControllerPatch ( m . Controller , m . controllerKind , history . UID )
if err != nil {
return err
}
2021-11-10 17:56:46 -05:00
return m . crControl . PatchControllerRevision ( ctx , history . Namespace , history . Name , patchBytes )
2017-06-02 21:02:01 -04:00
}
// ReleaseControllerRevision sends a patch to free the ControllerRevision from the control of its controller.
// It returns the error if the patching fails. 404 and 422 errors are ignored.
2021-11-10 17:56:46 -05:00
func ( m * ControllerRevisionControllerRefManager ) ReleaseControllerRevision ( ctx context . Context , history * apps . ControllerRevision ) error {
2023-07-12 04:45:00 -04:00
logger := klog . FromContext ( ctx )
logger . V ( 2 ) . Info ( "Patching ControllerRevision to remove its controllerRef" , "controllerRevision" , klog . KObj ( history ) , "gvk" , m . controllerKind , "controller" , m . Controller . GetName ( ) )
2021-11-05 09:33:52 -04:00
patchBytes , err := GenerateDeleteOwnerRefStrategicMergeBytes ( history . UID , [ ] types . UID { m . Controller . GetUID ( ) } )
2019-10-09 21:44:54 -04:00
if err != nil {
return err
}
2021-11-10 17:56:46 -05:00
err = m . crControl . PatchControllerRevision ( ctx , history . Namespace , history . Name , patchBytes )
2017-06-02 21:02:01 -04:00
if err != nil {
if errors . IsNotFound ( err ) {
// If the ControllerRevision no longer exists, ignore it.
return nil
}
if errors . IsInvalid ( err ) {
// Invalid error will be returned in two cases: 1. the ControllerRevision
// has no owner reference, 2. the uid of the ControllerRevision doesn't
// match, which means the ControllerRevision is deleted and then recreated.
// In both cases, the error can be ignored.
return nil
}
}
return err
}
2019-10-09 21:44:54 -04:00
type objectForAddOwnerRefPatch struct {
Metadata objectMetaForPatch ` json:"metadata" `
}
type objectMetaForPatch struct {
OwnerReferences [ ] metav1 . OwnerReference ` json:"ownerReferences" `
UID types . UID ` json:"uid" `
2021-01-19 17:04:39 -05:00
Finalizers [ ] string ` json:"finalizers,omitempty" `
2019-10-09 21:44:54 -04:00
}
2021-01-19 17:04:39 -05:00
func ownerRefControllerPatch ( controller metav1 . Object , controllerKind schema . GroupVersionKind , uid types . UID , finalizers ... string ) ( [ ] byte , error ) {
2019-10-09 21:44:54 -04:00
blockOwnerDeletion := true
isController := true
addControllerPatch := objectForAddOwnerRefPatch {
Metadata : objectMetaForPatch {
UID : uid ,
OwnerReferences : [ ] metav1 . OwnerReference {
{
APIVersion : controllerKind . GroupVersion ( ) . String ( ) ,
Kind : controllerKind . Kind ,
Name : controller . GetName ( ) ,
UID : controller . GetUID ( ) ,
Controller : & isController ,
BlockOwnerDeletion : & blockOwnerDeletion ,
} ,
} ,
2021-01-19 17:04:39 -05:00
Finalizers : finalizers ,
2019-10-09 21:44:54 -04:00
} ,
}
patchBytes , err := json . Marshal ( & addControllerPatch )
if err != nil {
return nil , err
}
return patchBytes , nil
}
2021-11-05 09:33:52 -04:00
type objectForDeleteOwnerRefStrategicMergePatch struct {
Metadata objectMetaForMergePatch ` json:"metadata" `
}
type objectMetaForMergePatch struct {
UID types . UID ` json:"uid" `
OwnerReferences [ ] map [ string ] string ` json:"ownerReferences" `
DeleteFinalizers [ ] string ` json:"$deleteFromPrimitiveList/finalizers,omitempty" `
}
func GenerateDeleteOwnerRefStrategicMergeBytes ( dependentUID types . UID , ownerUIDs [ ] types . UID , finalizers ... string ) ( [ ] byte , error ) {
var ownerReferences [ ] map [ string ] string
for _ , ownerUID := range ownerUIDs {
ownerReferences = append ( ownerReferences , ownerReference ( ownerUID , "delete" ) )
}
patch := objectForDeleteOwnerRefStrategicMergePatch {
Metadata : objectMetaForMergePatch {
UID : dependentUID ,
OwnerReferences : ownerReferences ,
DeleteFinalizers : finalizers ,
} ,
}
patchBytes , err := json . Marshal ( & patch )
if err != nil {
return nil , err
}
return patchBytes , nil
}
func ownerReference ( uid types . UID , patchType string ) map [ string ] string {
return map [ string ] string {
"$patch" : patchType ,
"uid" : string ( uid ) ,
}
}