controller_ref_manager.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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. "strings"
  17. "github.com/golang/glog"
  18. "k8s.io/kubernetes/pkg/api"
  19. "k8s.io/kubernetes/pkg/api/errors"
  20. "k8s.io/kubernetes/pkg/api/unversioned"
  21. "k8s.io/kubernetes/pkg/labels"
  22. )
  23. type PodControllerRefManager struct {
  24. podControl PodControlInterface
  25. controllerObject api.ObjectMeta
  26. controllerSelector labels.Selector
  27. controllerKind unversioned.GroupVersionKind
  28. }
  29. // NewPodControllerRefManager returns a PodControllerRefManager that exposes
  30. // methods to manage the controllerRef of pods.
  31. func NewPodControllerRefManager(
  32. podControl PodControlInterface,
  33. controllerObject api.ObjectMeta,
  34. controllerSelector labels.Selector,
  35. controllerKind unversioned.GroupVersionKind,
  36. ) *PodControllerRefManager {
  37. return &PodControllerRefManager{podControl, controllerObject, controllerSelector, controllerKind}
  38. }
  39. // Classify first filters out inactive pods, then it classify the remaining pods
  40. // into three categories: 1. matchesAndControlled are the pods whose labels
  41. // match the selector of the RC, and have a controllerRef pointing to the
  42. // controller 2. matchesNeedsController are the pods whose labels match the RC,
  43. // but don't have a controllerRef. (Pods with matching labels but with a
  44. // controllerRef pointing to other object are ignored) 3. controlledDoesNotMatch
  45. // are the pods that have a controllerRef pointing to the controller, but their
  46. // labels no longer match the selector.
  47. func (m *PodControllerRefManager) Classify(pods []*api.Pod) (
  48. matchesAndControlled []*api.Pod,
  49. matchesNeedsController []*api.Pod,
  50. controlledDoesNotMatch []*api.Pod) {
  51. for i := range pods {
  52. pod := pods[i]
  53. if !IsPodActive(pod) {
  54. glog.V(4).Infof("Ignoring inactive pod %v/%v in state %v, deletion time %v",
  55. pod.Namespace, pod.Name, pod.Status.Phase, pod.DeletionTimestamp)
  56. continue
  57. }
  58. controllerRef := getControllerOf(pod.ObjectMeta)
  59. if controllerRef != nil {
  60. if controllerRef.UID == m.controllerObject.UID {
  61. // already controlled
  62. if m.controllerSelector.Matches(labels.Set(pod.Labels)) {
  63. matchesAndControlled = append(matchesAndControlled, pod)
  64. } else {
  65. controlledDoesNotMatch = append(controlledDoesNotMatch, pod)
  66. }
  67. } else {
  68. // ignoring the pod controlled by other controller
  69. glog.V(4).Infof("Ignoring pod %v/%v, it's owned by [%s/%s, name: %s, uid: %s]",
  70. pod.Namespace, pod.Name, controllerRef.APIVersion, controllerRef.Kind, controllerRef.Name, controllerRef.UID)
  71. continue
  72. }
  73. } else {
  74. if !m.controllerSelector.Matches(labels.Set(pod.Labels)) {
  75. continue
  76. }
  77. matchesNeedsController = append(matchesNeedsController, pod)
  78. }
  79. }
  80. return matchesAndControlled, matchesNeedsController, controlledDoesNotMatch
  81. }
  82. // getControllerOf returns the controllerRef if controllee has a controller,
  83. // otherwise returns nil.
  84. func getControllerOf(controllee api.ObjectMeta) *api.OwnerReference {
  85. for _, owner := range controllee.OwnerReferences {
  86. // controlled by other controller
  87. if owner.Controller != nil && *owner.Controller == true {
  88. return &owner
  89. }
  90. }
  91. return nil
  92. }
  93. // AdoptPod sends a patch to take control of the pod. It returns the error if
  94. // the patching fails.
  95. func (m *PodControllerRefManager) AdoptPod(pod *api.Pod) error {
  96. // we should not adopt any pods if the controller is about to be deleted
  97. if m.controllerObject.DeletionTimestamp != nil {
  98. return fmt.Errorf("cancel the adopt attempt for pod %s because the controlller is being deleted",
  99. strings.Join([]string{pod.Namespace, pod.Name, string(pod.UID)}, "_"))
  100. }
  101. addControllerPatch := fmt.Sprintf(
  102. `{"metadata":{"ownerReferences":[{"apiVersion":"%s","kind":"%s","name":"%s","uid":"%s","controller":true}],"uid":"%s"}}`,
  103. m.controllerKind.GroupVersion(), m.controllerKind.Kind,
  104. m.controllerObject.Name, m.controllerObject.UID, pod.UID)
  105. return m.podControl.PatchPod(pod.Namespace, pod.Name, []byte(addControllerPatch))
  106. }
  107. // ReleasePod sends a patch to free the pod from the control of the controller.
  108. // It returns the error if the patching fails. 404 and 422 errors are ignored.
  109. func (m *PodControllerRefManager) ReleasePod(pod *api.Pod) error {
  110. glog.V(2).Infof("patching pod %s_%s to remove its controllerRef to %s/%s:%s",
  111. pod.Namespace, pod.Name, m.controllerKind.GroupVersion(), m.controllerKind.Kind, m.controllerObject.Name)
  112. deleteOwnerRefPatch := fmt.Sprintf(`{"metadata":{"ownerReferences":[{"$patch":"delete","uid":"%s"}],"uid":"%s"}}`, m.controllerObject.UID, pod.UID)
  113. err := m.podControl.PatchPod(pod.Namespace, pod.Name, []byte(deleteOwnerRefPatch))
  114. if err != nil {
  115. if errors.IsNotFound(err) {
  116. // If the pod no longer exists, ignore it.
  117. return nil
  118. }
  119. if errors.IsInvalid(err) {
  120. // Invalid error will be returned in two cases: 1. the pod
  121. // has no owner reference, 2. the uid of the pod doesn't
  122. // match, which means the pod is deleted and then recreated.
  123. // In both cases, the error can be ignored.
  124. // TODO: If the pod has owner references, but none of them
  125. // has the owner.UID, server will silently ignore the patch.
  126. // Investigate why.
  127. return nil
  128. }
  129. }
  130. return err
  131. }