ReplicaSet has owner ref of the Deployment that created it

This commit is contained in:
Mayank Kumar
2016-10-26 23:58:20 -07:00
parent 9ef610b672
commit 777977612b
9 changed files with 382 additions and 17 deletions

View File

@@ -23,6 +23,7 @@ import (
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/v1"
extensions "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/runtime/schema"
@@ -143,3 +144,103 @@ func (m *PodControllerRefManager) ReleasePod(pod *v1.Pod) error {
}
return err
}
// 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 {
rsControl RSControlInterface
controllerObject v1.ObjectMeta
controllerSelector labels.Selector
controllerKind schema.GroupVersionKind
}
// NewReplicaSetControllerRefManager returns a ReplicaSetControllerRefManager that exposes
// methods to manage the controllerRef of ReplicaSets.
func NewReplicaSetControllerRefManager(
rsControl RSControlInterface,
controllerObject v1.ObjectMeta,
controllerSelector labels.Selector,
controllerKind schema.GroupVersionKind,
) *ReplicaSetControllerRefManager {
return &ReplicaSetControllerRefManager{rsControl, controllerObject, controllerSelector, controllerKind}
}
// Classify, classifies the ReplicaSets into three categories:
// 1. matchesAndControlled are the ReplicaSets whose labels
// match the selector of the Deployment, and have a controllerRef pointing to the
// Deployment.
// 2. matchesNeedsController are ReplicaSets ,whose labels match the Deployment,
// but don't have a controllerRef. (ReplicaSets with matching labels but with a
// controllerRef pointing to other object are ignored)
// 3. controlledDoesNotMatch are the ReplicaSets that have a controllerRef pointing
// to the Deployment, but their labels no longer match the selector.
func (m *ReplicaSetControllerRefManager) Classify(replicaSets []*extensions.ReplicaSet) (
matchesAndControlled []*extensions.ReplicaSet,
matchesNeedsController []*extensions.ReplicaSet,
controlledDoesNotMatch []*extensions.ReplicaSet) {
for i := range replicaSets {
replicaSet := replicaSets[i]
controllerRef := GetControllerOf(replicaSet.ObjectMeta)
if controllerRef != nil {
if controllerRef.UID != m.controllerObject.UID {
// ignoring the ReplicaSet controlled by other Deployment
glog.V(4).Infof("Ignoring ReplicaSet %v/%v, it's owned by [%s/%s, name: %s, uid: %s]",
replicaSet.Namespace, replicaSet.Name, controllerRef.APIVersion, controllerRef.Kind, controllerRef.Name, controllerRef.UID)
continue
}
// already controlled by this Deployment
if m.controllerSelector.Matches(labels.Set(replicaSet.Labels)) {
matchesAndControlled = append(matchesAndControlled, replicaSet)
} else {
controlledDoesNotMatch = append(controlledDoesNotMatch, replicaSet)
}
} else {
if !m.controllerSelector.Matches(labels.Set(replicaSet.Labels)) {
continue
}
matchesNeedsController = append(matchesNeedsController, replicaSet)
}
}
return matchesAndControlled, matchesNeedsController, controlledDoesNotMatch
}
// AdoptReplicaSet sends a patch to take control of the ReplicaSet. It returns the error if
// the patching fails.
func (m *ReplicaSetControllerRefManager) AdoptReplicaSet(replicaSet *extensions.ReplicaSet) error {
// we should not adopt any ReplicaSets if the Deployment is about to be deleted
if m.controllerObject.DeletionTimestamp != nil {
return fmt.Errorf("cancel the adopt attempt for RS %s because the controller %v is being deleted",
strings.Join([]string{replicaSet.Namespace, replicaSet.Name, string(replicaSet.UID)}, "_"), m.controllerObject.Name)
}
addControllerPatch := fmt.Sprintf(
`{"metadata":{"ownerReferences":[{"apiVersion":"%s","kind":"%s","name":"%s","uid":"%s","controller":true}],"uid":"%s"}}`,
m.controllerKind.GroupVersion(), m.controllerKind.Kind,
m.controllerObject.Name, m.controllerObject.UID, replicaSet.UID)
return m.rsControl.PatchReplicaSet(replicaSet.Namespace, replicaSet.Name, []byte(addControllerPatch))
}
// 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.
func (m *ReplicaSetControllerRefManager) ReleaseReplicaSet(replicaSet *extensions.ReplicaSet) error {
glog.V(2).Infof("patching ReplicaSet %s_%s to remove its controllerRef to %s/%s:%s",
replicaSet.Namespace, replicaSet.Name, m.controllerKind.GroupVersion(), m.controllerKind.Kind, m.controllerObject.Name)
deleteOwnerRefPatch := fmt.Sprintf(`{"metadata":{"ownerReferences":[{"$patch":"delete","uid":"%s"}],"uid":"%s"}}`, m.controllerObject.UID, replicaSet.UID)
err := m.rsControl.PatchReplicaSet(replicaSet.Namespace, replicaSet.Name, []byte(deleteOwnerRefPatch))
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
}