deprecate created-by annotation for pod drain
This commit is contained in:
parent
7560142e27
commit
d76b08d154
@ -84,6 +84,7 @@ go_library(
|
|||||||
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
|
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
|
||||||
"//pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion:go_default_library",
|
"//pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion:go_default_library",
|
||||||
"//pkg/client/unversioned:go_default_library",
|
"//pkg/client/unversioned:go_default_library",
|
||||||
|
"//pkg/controller:go_default_library",
|
||||||
"//pkg/kubectl:go_default_library",
|
"//pkg/kubectl:go_default_library",
|
||||||
"//pkg/kubectl/cmd/auth:go_default_library",
|
"//pkg/kubectl/cmd/auth:go_default_library",
|
||||||
"//pkg/kubectl/cmd/config:go_default_library",
|
"//pkg/kubectl/cmd/config:go_default_library",
|
||||||
|
@ -38,6 +38,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/apis/policy"
|
"k8s.io/kubernetes/pkg/apis/policy"
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||||
|
"k8s.io/kubernetes/pkg/controller"
|
||||||
"k8s.io/kubernetes/pkg/kubectl"
|
"k8s.io/kubernetes/pkg/kubectl"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
@ -266,40 +267,38 @@ func (o *DrainOptions) deleteOrEvictPodsSimple() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *DrainOptions) getController(sr *api.SerializedReference) (interface{}, error) {
|
func (o *DrainOptions) getController(namespace string, controllerRef *metav1.OwnerReference) (interface{}, error) {
|
||||||
switch sr.Reference.Kind {
|
switch controllerRef.Kind {
|
||||||
case "ReplicationController":
|
case "ReplicationController":
|
||||||
return o.client.Core().ReplicationControllers(sr.Reference.Namespace).Get(sr.Reference.Name, metav1.GetOptions{})
|
return o.client.Core().ReplicationControllers(namespace).Get(controllerRef.Name, metav1.GetOptions{})
|
||||||
case "DaemonSet":
|
case "DaemonSet":
|
||||||
return o.client.Extensions().DaemonSets(sr.Reference.Namespace).Get(sr.Reference.Name, metav1.GetOptions{})
|
return o.client.Extensions().DaemonSets(namespace).Get(controllerRef.Name, metav1.GetOptions{})
|
||||||
case "Job":
|
case "Job":
|
||||||
return o.client.Batch().Jobs(sr.Reference.Namespace).Get(sr.Reference.Name, metav1.GetOptions{})
|
return o.client.Batch().Jobs(namespace).Get(controllerRef.Name, metav1.GetOptions{})
|
||||||
case "ReplicaSet":
|
case "ReplicaSet":
|
||||||
return o.client.Extensions().ReplicaSets(sr.Reference.Namespace).Get(sr.Reference.Name, metav1.GetOptions{})
|
return o.client.Extensions().ReplicaSets(namespace).Get(controllerRef.Name, metav1.GetOptions{})
|
||||||
case "StatefulSet":
|
case "StatefulSet":
|
||||||
return o.client.Apps().StatefulSets(sr.Reference.Namespace).Get(sr.Reference.Name, metav1.GetOptions{})
|
return o.client.Apps().StatefulSets(namespace).Get(controllerRef.Name, metav1.GetOptions{})
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("Unknown controller kind %q", sr.Reference.Kind)
|
return nil, fmt.Errorf("Unknown controller kind %q", controllerRef.Kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *DrainOptions) getPodCreator(pod api.Pod) (*api.SerializedReference, error) {
|
func (o *DrainOptions) getPodController(pod api.Pod) (*metav1.OwnerReference, error) {
|
||||||
creatorRef, found := pod.ObjectMeta.Annotations[api.CreatedByAnnotation]
|
controllerRef := controller.GetControllerOf(&pod)
|
||||||
if !found {
|
if controllerRef == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
// Now verify that the specified creator actually exists.
|
|
||||||
sr := &api.SerializedReference{}
|
|
||||||
if err := runtime.DecodeInto(o.Factory.Decoder(true), []byte(creatorRef), sr); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// We assume the only reason for an error is because the controller is
|
// We assume the only reason for an error is because the controller is
|
||||||
// gone/missing, not for any other cause. TODO(mml): something more
|
// gone/missing, not for any other cause.
|
||||||
// sophisticated than this
|
// TODO(mml): something more sophisticated than this
|
||||||
_, err := o.getController(sr)
|
// TODO(juntee): determine if it's safe to remove getController(),
|
||||||
|
// so that drain can work for controller types that we don't know about
|
||||||
|
_, err := o.getController(pod.Namespace, controllerRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return sr, nil
|
return controllerRef, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *DrainOptions) unreplicatedFilter(pod api.Pod) (bool, *warning, *fatal) {
|
func (o *DrainOptions) unreplicatedFilter(pod api.Pod) (bool, *warning, *fatal) {
|
||||||
@ -308,7 +307,7 @@ func (o *DrainOptions) unreplicatedFilter(pod api.Pod) (bool, *warning, *fatal)
|
|||||||
return true, nil, nil
|
return true, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
sr, err := o.getPodCreator(pod)
|
controllerRef, err := o.getPodController(pod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// if we're forcing, remove orphaned pods with a warning
|
// if we're forcing, remove orphaned pods with a warning
|
||||||
if apierrors.IsNotFound(err) && o.Force {
|
if apierrors.IsNotFound(err) && o.Force {
|
||||||
@ -316,7 +315,7 @@ func (o *DrainOptions) unreplicatedFilter(pod api.Pod) (bool, *warning, *fatal)
|
|||||||
}
|
}
|
||||||
return false, nil, &fatal{err.Error()}
|
return false, nil, &fatal{err.Error()}
|
||||||
}
|
}
|
||||||
if sr != nil {
|
if controllerRef != nil {
|
||||||
return true, nil, nil
|
return true, nil, nil
|
||||||
}
|
}
|
||||||
if !o.Force {
|
if !o.Force {
|
||||||
@ -333,7 +332,7 @@ func (o *DrainOptions) daemonsetFilter(pod api.Pod) (bool, *warning, *fatal) {
|
|||||||
// The exception is for pods that are orphaned (the referencing
|
// The exception is for pods that are orphaned (the referencing
|
||||||
// management resource - including DaemonSet - is not found).
|
// management resource - including DaemonSet - is not found).
|
||||||
// Such pods will be deleted if --force is used.
|
// Such pods will be deleted if --force is used.
|
||||||
sr, err := o.getPodCreator(pod)
|
controllerRef, err := o.getPodController(pod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// if we're forcing, remove orphaned pods with a warning
|
// if we're forcing, remove orphaned pods with a warning
|
||||||
if apierrors.IsNotFound(err) && o.Force {
|
if apierrors.IsNotFound(err) && o.Force {
|
||||||
@ -341,10 +340,10 @@ func (o *DrainOptions) daemonsetFilter(pod api.Pod) (bool, *warning, *fatal) {
|
|||||||
}
|
}
|
||||||
return false, nil, &fatal{err.Error()}
|
return false, nil, &fatal{err.Error()}
|
||||||
}
|
}
|
||||||
if sr == nil || sr.Reference.Kind != "DaemonSet" {
|
if controllerRef == nil || controllerRef.Kind != "DaemonSet" {
|
||||||
return true, nil, nil
|
return true, nil, nil
|
||||||
}
|
}
|
||||||
if _, err := o.client.Extensions().DaemonSets(sr.Reference.Namespace).Get(sr.Reference.Name, metav1.GetOptions{}); err != nil {
|
if _, err := o.client.Extensions().DaemonSets(pod.Namespace).Get(controllerRef.Name, metav1.GetOptions{}); err != nil {
|
||||||
return false, nil, &fatal{err.Error()}
|
return false, nil, &fatal{err.Error()}
|
||||||
}
|
}
|
||||||
if !o.IgnoreDaemonsets {
|
if !o.IgnoreDaemonsets {
|
||||||
|
@ -58,6 +58,8 @@ const (
|
|||||||
var node *api.Node
|
var node *api.Node
|
||||||
var cordoned_node *api.Node
|
var cordoned_node *api.Node
|
||||||
|
|
||||||
|
func boolptr(b bool) *bool { return &b }
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
// Create a node.
|
// Create a node.
|
||||||
node = &api.Node{
|
node = &api.Node{
|
||||||
@ -244,7 +246,18 @@ func TestDrain(t *testing.T) {
|
|||||||
Namespace: "default",
|
Namespace: "default",
|
||||||
CreationTimestamp: metav1.Time{Time: time.Now()},
|
CreationTimestamp: metav1.Time{Time: time.Now()},
|
||||||
Labels: labels,
|
Labels: labels,
|
||||||
|
SelfLink: testapi.Default.SelfLink("pods", "bar"),
|
||||||
Annotations: rc_anno,
|
Annotations: rc_anno,
|
||||||
|
OwnerReferences: []metav1.OwnerReference{
|
||||||
|
{
|
||||||
|
APIVersion: "v1",
|
||||||
|
Kind: "ReplicationController",
|
||||||
|
Name: "rc",
|
||||||
|
UID: "123",
|
||||||
|
BlockOwnerDeletion: boolptr(true),
|
||||||
|
Controller: boolptr(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Spec: api.PodSpec{
|
Spec: api.PodSpec{
|
||||||
NodeName: "node",
|
NodeName: "node",
|
||||||
@ -256,7 +269,7 @@ func TestDrain(t *testing.T) {
|
|||||||
Name: "ds",
|
Name: "ds",
|
||||||
Namespace: "default",
|
Namespace: "default",
|
||||||
CreationTimestamp: metav1.Time{Time: time.Now()},
|
CreationTimestamp: metav1.Time{Time: time.Now()},
|
||||||
SelfLink: "/apis/extensions/v1beta1/namespaces/default/daemonsets/ds",
|
SelfLink: testapi.Default.SelfLink("daemonsets", "ds"),
|
||||||
},
|
},
|
||||||
Spec: extensions.DaemonSetSpec{
|
Spec: extensions.DaemonSetSpec{
|
||||||
Selector: &metav1.LabelSelector{MatchLabels: labels},
|
Selector: &metav1.LabelSelector{MatchLabels: labels},
|
||||||
@ -272,7 +285,17 @@ func TestDrain(t *testing.T) {
|
|||||||
Namespace: "default",
|
Namespace: "default",
|
||||||
CreationTimestamp: metav1.Time{Time: time.Now()},
|
CreationTimestamp: metav1.Time{Time: time.Now()},
|
||||||
Labels: labels,
|
Labels: labels,
|
||||||
|
SelfLink: testapi.Default.SelfLink("pods", "bar"),
|
||||||
Annotations: ds_anno,
|
Annotations: ds_anno,
|
||||||
|
OwnerReferences: []metav1.OwnerReference{
|
||||||
|
{
|
||||||
|
APIVersion: "extensions/v1beta1",
|
||||||
|
Kind: "DaemonSet",
|
||||||
|
Name: "ds",
|
||||||
|
BlockOwnerDeletion: boolptr(true),
|
||||||
|
Controller: boolptr(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Spec: api.PodSpec{
|
Spec: api.PodSpec{
|
||||||
NodeName: "node",
|
NodeName: "node",
|
||||||
@ -284,7 +307,7 @@ func TestDrain(t *testing.T) {
|
|||||||
Name: "missing-ds",
|
Name: "missing-ds",
|
||||||
Namespace: "default",
|
Namespace: "default",
|
||||||
CreationTimestamp: metav1.Time{Time: time.Now()},
|
CreationTimestamp: metav1.Time{Time: time.Now()},
|
||||||
SelfLink: "/apis/extensions/v1beta1/namespaces/default/daemonsets/missing-ds",
|
SelfLink: testapi.Default.SelfLink("daemonsets", "missing-ds"),
|
||||||
},
|
},
|
||||||
Spec: extensions.DaemonSetSpec{
|
Spec: extensions.DaemonSetSpec{
|
||||||
Selector: &metav1.LabelSelector{MatchLabels: labels},
|
Selector: &metav1.LabelSelector{MatchLabels: labels},
|
||||||
@ -300,7 +323,17 @@ func TestDrain(t *testing.T) {
|
|||||||
Namespace: "default",
|
Namespace: "default",
|
||||||
CreationTimestamp: metav1.Time{Time: time.Now()},
|
CreationTimestamp: metav1.Time{Time: time.Now()},
|
||||||
Labels: labels,
|
Labels: labels,
|
||||||
|
SelfLink: testapi.Default.SelfLink("pods", "bar"),
|
||||||
Annotations: missing_ds_anno,
|
Annotations: missing_ds_anno,
|
||||||
|
OwnerReferences: []metav1.OwnerReference{
|
||||||
|
{
|
||||||
|
APIVersion: "extensions/v1beta1",
|
||||||
|
Kind: "DaemonSet",
|
||||||
|
Name: "missing-ds",
|
||||||
|
BlockOwnerDeletion: boolptr(true),
|
||||||
|
Controller: boolptr(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Spec: api.PodSpec{
|
Spec: api.PodSpec{
|
||||||
NodeName: "node",
|
NodeName: "node",
|
||||||
@ -312,7 +345,7 @@ func TestDrain(t *testing.T) {
|
|||||||
Name: "job",
|
Name: "job",
|
||||||
Namespace: "default",
|
Namespace: "default",
|
||||||
CreationTimestamp: metav1.Time{Time: time.Now()},
|
CreationTimestamp: metav1.Time{Time: time.Now()},
|
||||||
SelfLink: "/apis/batch/v1/namespaces/default/jobs/job",
|
SelfLink: testapi.Default.SelfLink("jobs", "job"),
|
||||||
},
|
},
|
||||||
Spec: batch.JobSpec{
|
Spec: batch.JobSpec{
|
||||||
Selector: &metav1.LabelSelector{MatchLabels: labels},
|
Selector: &metav1.LabelSelector{MatchLabels: labels},
|
||||||
@ -325,7 +358,17 @@ func TestDrain(t *testing.T) {
|
|||||||
Namespace: "default",
|
Namespace: "default",
|
||||||
CreationTimestamp: metav1.Time{Time: time.Now()},
|
CreationTimestamp: metav1.Time{Time: time.Now()},
|
||||||
Labels: labels,
|
Labels: labels,
|
||||||
|
SelfLink: testapi.Default.SelfLink("pods", "bar"),
|
||||||
Annotations: map[string]string{api.CreatedByAnnotation: refJson(t, &job)},
|
Annotations: map[string]string{api.CreatedByAnnotation: refJson(t, &job)},
|
||||||
|
OwnerReferences: []metav1.OwnerReference{
|
||||||
|
{
|
||||||
|
APIVersion: "v1",
|
||||||
|
Kind: "Job",
|
||||||
|
Name: "job",
|
||||||
|
BlockOwnerDeletion: boolptr(true),
|
||||||
|
Controller: boolptr(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,7 +394,17 @@ func TestDrain(t *testing.T) {
|
|||||||
Namespace: "default",
|
Namespace: "default",
|
||||||
CreationTimestamp: metav1.Time{Time: time.Now()},
|
CreationTimestamp: metav1.Time{Time: time.Now()},
|
||||||
Labels: labels,
|
Labels: labels,
|
||||||
|
SelfLink: testapi.Default.SelfLink("pods", "bar"),
|
||||||
Annotations: rs_anno,
|
Annotations: rs_anno,
|
||||||
|
OwnerReferences: []metav1.OwnerReference{
|
||||||
|
{
|
||||||
|
APIVersion: "v1",
|
||||||
|
Kind: "ReplicaSet",
|
||||||
|
Name: "rs",
|
||||||
|
BlockOwnerDeletion: boolptr(true),
|
||||||
|
Controller: boolptr(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Spec: api.PodSpec{
|
Spec: api.PodSpec{
|
||||||
NodeName: "node",
|
NodeName: "node",
|
||||||
|
Loading…
Reference in New Issue
Block a user