controller_ref_manager.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  1. /*
  2. Copyright 2016 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package controller
  14. import (
  15. "fmt"
  16. "sync"
  17. apps "k8s.io/api/apps/v1"
  18. "k8s.io/api/core/v1"
  19. "k8s.io/apimachinery/pkg/api/errors"
  20. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  21. "k8s.io/apimachinery/pkg/labels"
  22. "k8s.io/apimachinery/pkg/runtime/schema"
  23. utilerrors "k8s.io/apimachinery/pkg/util/errors"
  24. "k8s.io/klog"
  25. )
  26. type BaseControllerRefManager struct {
  27. Controller metav1.Object
  28. Selector labels.Selector
  29. canAdoptErr error
  30. canAdoptOnce sync.Once
  31. CanAdoptFunc func() error
  32. }
  33. func (m *BaseControllerRefManager) CanAdopt() error {
  34. m.canAdoptOnce.Do(func() {
  35. if m.CanAdoptFunc != nil {
  36. m.canAdoptErr = m.CanAdoptFunc()
  37. }
  38. })
  39. return m.canAdoptErr
  40. }
  41. // ClaimObject tries to take ownership of an object for this controller.
  42. //
  43. // It will reconcile the following:
  44. // * Adopt orphans if the match function returns true.
  45. // * Release owned objects if the match function returns false.
  46. //
  47. // A non-nil error is returned if some form of reconciliation was attempted and
  48. // failed. Usually, controllers should try again later in case reconciliation
  49. // is still needed.
  50. //
  51. // If the error is nil, either the reconciliation succeeded, or no
  52. // reconciliation was necessary. The returned boolean indicates whether you now
  53. // own the object.
  54. //
  55. // No reconciliation will be attempted if the controller is being deleted.
  56. func (m *BaseControllerRefManager) ClaimObject(obj metav1.Object, match func(metav1.Object) bool, adopt, release func(metav1.Object) error) (bool, error) {
  57. controllerRef := metav1.GetControllerOf(obj)
  58. if controllerRef != nil {
  59. if controllerRef.UID != m.Controller.GetUID() {
  60. // Owned by someone else. Ignore.
  61. return false, nil
  62. }
  63. if match(obj) {
  64. // We already own it and the selector matches.
  65. // Return true (successfully claimed) before checking deletion timestamp.
  66. // We're still allowed to claim things we already own while being deleted
  67. // because doing so requires taking no actions.
  68. return true, nil
  69. }
  70. // Owned by us but selector doesn't match.
  71. // Try to release, unless we're being deleted.
  72. if m.Controller.GetDeletionTimestamp() != nil {
  73. return false, nil
  74. }
  75. if err := release(obj); err != nil {
  76. // If the pod no longer exists, ignore the error.
  77. if errors.IsNotFound(err) {
  78. return false, nil
  79. }
  80. // Either someone else released it, or there was a transient error.
  81. // The controller should requeue and try again if it's still stale.
  82. return false, err
  83. }
  84. // Successfully released.
  85. return false, nil
  86. }
  87. // It's an orphan.
  88. if m.Controller.GetDeletionTimestamp() != nil || !match(obj) {
  89. // Ignore if we're being deleted or selector doesn't match.
  90. return false, nil
  91. }
  92. if obj.GetDeletionTimestamp() != nil {
  93. // Ignore if the object is being deleted
  94. return false, nil
  95. }
  96. // Selector matches. Try to adopt.
  97. if err := adopt(obj); err != nil {
  98. // If the pod no longer exists, ignore the error.
  99. if errors.IsNotFound(err) {
  100. return false, nil
  101. }
  102. // Either someone else claimed it first, or there was a transient error.
  103. // The controller should requeue and try again if it's still orphaned.
  104. return false, err
  105. }
  106. // Successfully adopted.
  107. return true, nil
  108. }
  109. type PodControllerRefManager struct {
  110. BaseControllerRefManager
  111. controllerKind schema.GroupVersionKind
  112. podControl PodControlInterface
  113. }
  114. // NewPodControllerRefManager returns a PodControllerRefManager that exposes
  115. // methods to manage the controllerRef of pods.
  116. //
  117. // The CanAdopt() function can be used to perform a potentially expensive check
  118. // (such as a live GET from the API server) prior to the first adoption.
  119. // It will only be called (at most once) if an adoption is actually attempted.
  120. // If CanAdopt() returns a non-nil error, all adoptions will fail.
  121. //
  122. // NOTE: Once CanAdopt() is called, it will not be called again by the same
  123. // PodControllerRefManager instance. Create a new instance if it makes
  124. // sense to check CanAdopt() again (e.g. in a different sync pass).
  125. func NewPodControllerRefManager(
  126. podControl PodControlInterface,
  127. controller metav1.Object,
  128. selector labels.Selector,
  129. controllerKind schema.GroupVersionKind,
  130. canAdopt func() error,
  131. ) *PodControllerRefManager {
  132. return &PodControllerRefManager{
  133. BaseControllerRefManager: BaseControllerRefManager{
  134. Controller: controller,
  135. Selector: selector,
  136. CanAdoptFunc: canAdopt,
  137. },
  138. controllerKind: controllerKind,
  139. podControl: podControl,
  140. }
  141. }
  142. // ClaimPods tries to take ownership of a list of Pods.
  143. //
  144. // It will reconcile the following:
  145. // * Adopt orphans if the selector matches.
  146. // * Release owned objects if the selector no longer matches.
  147. //
  148. // Optional: If one or more filters are specified, a Pod will only be claimed if
  149. // all filters return true.
  150. //
  151. // A non-nil error is returned if some form of reconciliation was attempted and
  152. // failed. Usually, controllers should try again later in case reconciliation
  153. // is still needed.
  154. //
  155. // If the error is nil, either the reconciliation succeeded, or no
  156. // reconciliation was necessary. The list of Pods that you now own is returned.
  157. func (m *PodControllerRefManager) ClaimPods(pods []*v1.Pod, filters ...func(*v1.Pod) bool) ([]*v1.Pod, error) {
  158. var claimed []*v1.Pod
  159. var errlist []error
  160. match := func(obj metav1.Object) bool {
  161. pod := obj.(*v1.Pod)
  162. // Check selector first so filters only run on potentially matching Pods.
  163. if !m.Selector.Matches(labels.Set(pod.Labels)) {
  164. return false
  165. }
  166. for _, filter := range filters {
  167. if !filter(pod) {
  168. return false
  169. }
  170. }
  171. return true
  172. }
  173. adopt := func(obj metav1.Object) error {
  174. return m.AdoptPod(obj.(*v1.Pod))
  175. }
  176. release := func(obj metav1.Object) error {
  177. return m.ReleasePod(obj.(*v1.Pod))
  178. }
  179. for _, pod := range pods {
  180. ok, err := m.ClaimObject(pod, match, adopt, release)
  181. if err != nil {
  182. errlist = append(errlist, err)
  183. continue
  184. }
  185. if ok {
  186. claimed = append(claimed, pod)
  187. }
  188. }
  189. return claimed, utilerrors.NewAggregate(errlist)
  190. }
  191. // AdoptPod sends a patch to take control of the pod. It returns the error if
  192. // the patching fails.
  193. func (m *PodControllerRefManager) AdoptPod(pod *v1.Pod) error {
  194. if err := m.CanAdopt(); err != nil {
  195. return fmt.Errorf("can't adopt Pod %v/%v (%v): %v", pod.Namespace, pod.Name, pod.UID, err)
  196. }
  197. // Note that ValidateOwnerReferences() will reject this patch if another
  198. // OwnerReference exists with controller=true.
  199. addControllerPatch := fmt.Sprintf(
  200. `{"metadata":{"ownerReferences":[{"apiVersion":"%s","kind":"%s","name":"%s","uid":"%s","controller":true,"blockOwnerDeletion":true}],"uid":"%s"}}`,
  201. m.controllerKind.GroupVersion(), m.controllerKind.Kind,
  202. m.Controller.GetName(), m.Controller.GetUID(), pod.UID)
  203. return m.podControl.PatchPod(pod.Namespace, pod.Name, []byte(addControllerPatch))
  204. }
  205. // ReleasePod sends a patch to free the pod from the control of the controller.
  206. // It returns the error if the patching fails. 404 and 422 errors are ignored.
  207. func (m *PodControllerRefManager) ReleasePod(pod *v1.Pod) error {
  208. klog.V(2).Infof("patching pod %s_%s to remove its controllerRef to %s/%s:%s",
  209. pod.Namespace, pod.Name, m.controllerKind.GroupVersion(), m.controllerKind.Kind, m.Controller.GetName())
  210. deleteOwnerRefPatch := fmt.Sprintf(`{"metadata":{"ownerReferences":[{"$patch":"delete","uid":"%s"}],"uid":"%s"}}`, m.Controller.GetUID(), pod.UID)
  211. err := m.podControl.PatchPod(pod.Namespace, pod.Name, []byte(deleteOwnerRefPatch))
  212. if err != nil {
  213. if errors.IsNotFound(err) {
  214. // If the pod no longer exists, ignore it.
  215. return nil
  216. }
  217. if errors.IsInvalid(err) {
  218. // Invalid error will be returned in two cases: 1. the pod
  219. // has no owner reference, 2. the uid of the pod doesn't
  220. // match, which means the pod is deleted and then recreated.
  221. // In both cases, the error can be ignored.
  222. // TODO: If the pod has owner references, but none of them
  223. // has the owner.UID, server will silently ignore the patch.
  224. // Investigate why.
  225. return nil
  226. }
  227. }
  228. return err
  229. }
  230. // ReplicaSetControllerRefManager is used to manage controllerRef of ReplicaSets.
  231. // Three methods are defined on this object 1: Classify 2: AdoptReplicaSet and
  232. // 3: ReleaseReplicaSet which are used to classify the ReplicaSets into appropriate
  233. // categories and accordingly adopt or release them. See comments on these functions
  234. // for more details.
  235. type ReplicaSetControllerRefManager struct {
  236. BaseControllerRefManager
  237. controllerKind schema.GroupVersionKind
  238. rsControl RSControlInterface
  239. }
  240. // NewReplicaSetControllerRefManager returns a ReplicaSetControllerRefManager that exposes
  241. // methods to manage the controllerRef of ReplicaSets.
  242. //
  243. // The CanAdopt() function can be used to perform a potentially expensive check
  244. // (such as a live GET from the API server) prior to the first adoption.
  245. // It will only be called (at most once) if an adoption is actually attempted.
  246. // If CanAdopt() returns a non-nil error, all adoptions will fail.
  247. //
  248. // NOTE: Once CanAdopt() is called, it will not be called again by the same
  249. // ReplicaSetControllerRefManager instance. Create a new instance if it
  250. // makes sense to check CanAdopt() again (e.g. in a different sync pass).
  251. func NewReplicaSetControllerRefManager(
  252. rsControl RSControlInterface,
  253. controller metav1.Object,
  254. selector labels.Selector,
  255. controllerKind schema.GroupVersionKind,
  256. canAdopt func() error,
  257. ) *ReplicaSetControllerRefManager {
  258. return &ReplicaSetControllerRefManager{
  259. BaseControllerRefManager: BaseControllerRefManager{
  260. Controller: controller,
  261. Selector: selector,
  262. CanAdoptFunc: canAdopt,
  263. },
  264. controllerKind: controllerKind,
  265. rsControl: rsControl,
  266. }
  267. }
  268. // ClaimReplicaSets tries to take ownership of a list of ReplicaSets.
  269. //
  270. // It will reconcile the following:
  271. // * Adopt orphans if the selector matches.
  272. // * Release owned objects if the selector no longer matches.
  273. //
  274. // A non-nil error is returned if some form of reconciliation was attempted and
  275. // failed. Usually, controllers should try again later in case reconciliation
  276. // is still needed.
  277. //
  278. // If the error is nil, either the reconciliation succeeded, or no
  279. // reconciliation was necessary. The list of ReplicaSets that you now own is
  280. // returned.
  281. func (m *ReplicaSetControllerRefManager) ClaimReplicaSets(sets []*apps.ReplicaSet) ([]*apps.ReplicaSet, error) {
  282. var claimed []*apps.ReplicaSet
  283. var errlist []error
  284. match := func(obj metav1.Object) bool {
  285. return m.Selector.Matches(labels.Set(obj.GetLabels()))
  286. }
  287. adopt := func(obj metav1.Object) error {
  288. return m.AdoptReplicaSet(obj.(*apps.ReplicaSet))
  289. }
  290. release := func(obj metav1.Object) error {
  291. return m.ReleaseReplicaSet(obj.(*apps.ReplicaSet))
  292. }
  293. for _, rs := range sets {
  294. ok, err := m.ClaimObject(rs, match, adopt, release)
  295. if err != nil {
  296. errlist = append(errlist, err)
  297. continue
  298. }
  299. if ok {
  300. claimed = append(claimed, rs)
  301. }
  302. }
  303. return claimed, utilerrors.NewAggregate(errlist)
  304. }
  305. // AdoptReplicaSet sends a patch to take control of the ReplicaSet. It returns
  306. // the error if the patching fails.
  307. func (m *ReplicaSetControllerRefManager) AdoptReplicaSet(rs *apps.ReplicaSet) error {
  308. if err := m.CanAdopt(); err != nil {
  309. return fmt.Errorf("can't adopt ReplicaSet %v/%v (%v): %v", rs.Namespace, rs.Name, rs.UID, err)
  310. }
  311. // Note that ValidateOwnerReferences() will reject this patch if another
  312. // OwnerReference exists with controller=true.
  313. addControllerPatch := fmt.Sprintf(
  314. `{"metadata":{"ownerReferences":[{"apiVersion":"%s","kind":"%s","name":"%s","uid":"%s","controller":true,"blockOwnerDeletion":true}],"uid":"%s"}}`,
  315. m.controllerKind.GroupVersion(), m.controllerKind.Kind,
  316. m.Controller.GetName(), m.Controller.GetUID(), rs.UID)
  317. return m.rsControl.PatchReplicaSet(rs.Namespace, rs.Name, []byte(addControllerPatch))
  318. }
  319. // ReleaseReplicaSet sends a patch to free the ReplicaSet from the control of the Deployment controller.
  320. // It returns the error if the patching fails. 404 and 422 errors are ignored.
  321. func (m *ReplicaSetControllerRefManager) ReleaseReplicaSet(replicaSet *apps.ReplicaSet) error {
  322. klog.V(2).Infof("patching ReplicaSet %s_%s to remove its controllerRef to %s/%s:%s",
  323. replicaSet.Namespace, replicaSet.Name, m.controllerKind.GroupVersion(), m.controllerKind.Kind, m.Controller.GetName())
  324. deleteOwnerRefPatch := fmt.Sprintf(`{"metadata":{"ownerReferences":[{"$patch":"delete","uid":"%s"}],"uid":"%s"}}`, m.Controller.GetUID(), replicaSet.UID)
  325. err := m.rsControl.PatchReplicaSet(replicaSet.Namespace, replicaSet.Name, []byte(deleteOwnerRefPatch))
  326. if err != nil {
  327. if errors.IsNotFound(err) {
  328. // If the ReplicaSet no longer exists, ignore it.
  329. return nil
  330. }
  331. if errors.IsInvalid(err) {
  332. // Invalid error will be returned in two cases: 1. the ReplicaSet
  333. // has no owner reference, 2. the uid of the ReplicaSet doesn't
  334. // match, which means the ReplicaSet is deleted and then recreated.
  335. // In both cases, the error can be ignored.
  336. return nil
  337. }
  338. }
  339. return err
  340. }
  341. // RecheckDeletionTimestamp returns a CanAdopt() function to recheck deletion.
  342. //
  343. // The CanAdopt() function calls getObject() to fetch the latest value,
  344. // and denies adoption attempts if that object has a non-nil DeletionTimestamp.
  345. func RecheckDeletionTimestamp(getObject func() (metav1.Object, error)) func() error {
  346. return func() error {
  347. obj, err := getObject()
  348. if err != nil {
  349. return fmt.Errorf("can't recheck DeletionTimestamp: %v", err)
  350. }
  351. if obj.GetDeletionTimestamp() != nil {
  352. return fmt.Errorf("%v/%v has just been deleted at %v", obj.GetNamespace(), obj.GetName(), obj.GetDeletionTimestamp())
  353. }
  354. return nil
  355. }
  356. }
  357. // ControllerRevisionControllerRefManager is used to manage controllerRef of ControllerRevisions.
  358. // Three methods are defined on this object 1: Classify 2: AdoptControllerRevision and
  359. // 3: ReleaseControllerRevision which are used to classify the ControllerRevisions into appropriate
  360. // categories and accordingly adopt or release them. See comments on these functions
  361. // for more details.
  362. type ControllerRevisionControllerRefManager struct {
  363. BaseControllerRefManager
  364. controllerKind schema.GroupVersionKind
  365. crControl ControllerRevisionControlInterface
  366. }
  367. // NewControllerRevisionControllerRefManager returns a ControllerRevisionControllerRefManager that exposes
  368. // methods to manage the controllerRef of ControllerRevisions.
  369. //
  370. // The canAdopt() function can be used to perform a potentially expensive check
  371. // (such as a live GET from the API server) prior to the first adoption.
  372. // It will only be called (at most once) if an adoption is actually attempted.
  373. // If canAdopt() returns a non-nil error, all adoptions will fail.
  374. //
  375. // NOTE: Once canAdopt() is called, it will not be called again by the same
  376. // ControllerRevisionControllerRefManager instance. Create a new instance if it
  377. // makes sense to check canAdopt() again (e.g. in a different sync pass).
  378. func NewControllerRevisionControllerRefManager(
  379. crControl ControllerRevisionControlInterface,
  380. controller metav1.Object,
  381. selector labels.Selector,
  382. controllerKind schema.GroupVersionKind,
  383. canAdopt func() error,
  384. ) *ControllerRevisionControllerRefManager {
  385. return &ControllerRevisionControllerRefManager{
  386. BaseControllerRefManager: BaseControllerRefManager{
  387. Controller: controller,
  388. Selector: selector,
  389. CanAdoptFunc: canAdopt,
  390. },
  391. controllerKind: controllerKind,
  392. crControl: crControl,
  393. }
  394. }
  395. // ClaimControllerRevisions tries to take ownership of a list of ControllerRevisions.
  396. //
  397. // It will reconcile the following:
  398. // * Adopt orphans if the selector matches.
  399. // * Release owned objects if the selector no longer matches.
  400. //
  401. // A non-nil error is returned if some form of reconciliation was attempted and
  402. // failed. Usually, controllers should try again later in case reconciliation
  403. // is still needed.
  404. //
  405. // If the error is nil, either the reconciliation succeeded, or no
  406. // reconciliation was necessary. The list of ControllerRevisions that you now own is
  407. // returned.
  408. func (m *ControllerRevisionControllerRefManager) ClaimControllerRevisions(histories []*apps.ControllerRevision) ([]*apps.ControllerRevision, error) {
  409. var claimed []*apps.ControllerRevision
  410. var errlist []error
  411. match := func(obj metav1.Object) bool {
  412. return m.Selector.Matches(labels.Set(obj.GetLabels()))
  413. }
  414. adopt := func(obj metav1.Object) error {
  415. return m.AdoptControllerRevision(obj.(*apps.ControllerRevision))
  416. }
  417. release := func(obj metav1.Object) error {
  418. return m.ReleaseControllerRevision(obj.(*apps.ControllerRevision))
  419. }
  420. for _, h := range histories {
  421. ok, err := m.ClaimObject(h, match, adopt, release)
  422. if err != nil {
  423. errlist = append(errlist, err)
  424. continue
  425. }
  426. if ok {
  427. claimed = append(claimed, h)
  428. }
  429. }
  430. return claimed, utilerrors.NewAggregate(errlist)
  431. }
  432. // AdoptControllerRevision sends a patch to take control of the ControllerRevision. It returns the error if
  433. // the patching fails.
  434. func (m *ControllerRevisionControllerRefManager) AdoptControllerRevision(history *apps.ControllerRevision) error {
  435. if err := m.CanAdopt(); err != nil {
  436. return fmt.Errorf("can't adopt ControllerRevision %v/%v (%v): %v", history.Namespace, history.Name, history.UID, err)
  437. }
  438. // Note that ValidateOwnerReferences() will reject this patch if another
  439. // OwnerReference exists with controller=true.
  440. addControllerPatch := fmt.Sprintf(
  441. `{"metadata":{"ownerReferences":[{"apiVersion":"%s","kind":"%s","name":"%s","uid":"%s","controller":true,"blockOwnerDeletion":true}],"uid":"%s"}}`,
  442. m.controllerKind.GroupVersion(), m.controllerKind.Kind,
  443. m.Controller.GetName(), m.Controller.GetUID(), history.UID)
  444. return m.crControl.PatchControllerRevision(history.Namespace, history.Name, []byte(addControllerPatch))
  445. }
  446. // ReleaseControllerRevision sends a patch to free the ControllerRevision from the control of its controller.
  447. // It returns the error if the patching fails. 404 and 422 errors are ignored.
  448. func (m *ControllerRevisionControllerRefManager) ReleaseControllerRevision(history *apps.ControllerRevision) error {
  449. klog.V(2).Infof("patching ControllerRevision %s_%s to remove its controllerRef to %s/%s:%s",
  450. history.Namespace, history.Name, m.controllerKind.GroupVersion(), m.controllerKind.Kind, m.Controller.GetName())
  451. deleteOwnerRefPatch := fmt.Sprintf(`{"metadata":{"ownerReferences":[{"$patch":"delete","uid":"%s"}],"uid":"%s"}}`, m.Controller.GetUID(), history.UID)
  452. err := m.crControl.PatchControllerRevision(history.Namespace, history.Name, []byte(deleteOwnerRefPatch))
  453. if err != nil {
  454. if errors.IsNotFound(err) {
  455. // If the ControllerRevision no longer exists, ignore it.
  456. return nil
  457. }
  458. if errors.IsInvalid(err) {
  459. // Invalid error will be returned in two cases: 1. the ControllerRevision
  460. // has no owner reference, 2. the uid of the ControllerRevision doesn't
  461. // match, which means the ControllerRevision is deleted and then recreated.
  462. // In both cases, the error can be ignored.
  463. return nil
  464. }
  465. }
  466. return err
  467. }