From 7956a9239ab6e28b5260340aeae5f3e6b1b94a36 Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Tue, 9 Mar 2021 10:56:48 -0500 Subject: [PATCH] kubectl describe policy/v1 PodDisruptionBudget --- .../k8s.io/kubectl/pkg/describe/describe.go | 66 ++++++++++++++++--- .../kubectl/pkg/describe/describe_test.go | 31 ++++++++- 2 files changed, 88 insertions(+), 9 deletions(-) diff --git a/staging/src/k8s.io/kubectl/pkg/describe/describe.go b/staging/src/k8s.io/kubectl/pkg/describe/describe.go index 2580c7837cc..78232643193 100644 --- a/staging/src/k8s.io/kubectl/pkg/describe/describe.go +++ b/staging/src/k8s.io/kubectl/pkg/describe/describe.go @@ -47,11 +47,13 @@ import ( extensionsv1beta1 "k8s.io/api/extensions/v1beta1" networkingv1 "k8s.io/api/networking/v1" networkingv1beta1 "k8s.io/api/networking/v1beta1" + policyv1 "k8s.io/api/policy/v1" policyv1beta1 "k8s.io/api/policy/v1beta1" rbacv1 "k8s.io/api/rbac/v1" schedulingv1 "k8s.io/api/scheduling/v1" storagev1 "k8s.io/api/storage/v1" "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -224,6 +226,7 @@ func describerMap(clientConfig *rest.Config) (map[schema.GroupKind]ResourceDescr {Group: storagev1.GroupName, Kind: "StorageClass"}: &StorageClassDescriber{c}, {Group: storagev1.GroupName, Kind: "CSINode"}: &CSINodeDescriber{c}, {Group: policyv1beta1.GroupName, Kind: "PodDisruptionBudget"}: &PodDisruptionBudgetDescriber{c}, + {Group: policyv1.GroupName, Kind: "PodDisruptionBudget"}: &PodDisruptionBudgetDescriber{c}, {Group: rbacv1.GroupName, Kind: "Role"}: &RoleDescriber{c}, {Group: rbacv1.GroupName, Kind: "ClusterRole"}: &ClusterRoleDescriber{c}, {Group: rbacv1.GroupName, Kind: "RoleBinding"}: &RoleBindingDescriber{c}, @@ -4533,20 +4536,67 @@ type PodDisruptionBudgetDescriber struct { } func (p *PodDisruptionBudgetDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) { - pdb, err := p.PolicyV1beta1().PodDisruptionBudgets(namespace).Get(context.TODO(), name, metav1.GetOptions{}) - if err != nil { - return "", err + var ( + pdbv1 *policyv1.PodDisruptionBudget + pdbv1beta1 *policyv1beta1.PodDisruptionBudget + err error + ) + + pdbv1, err = p.PolicyV1().PodDisruptionBudgets(namespace).Get(context.TODO(), name, metav1.GetOptions{}) + if err == nil { + var events *corev1.EventList + if describerSettings.ShowEvents { + events, _ = p.CoreV1().Events(namespace).Search(scheme.Scheme, pdbv1) + } + return describePodDisruptionBudgetV1(pdbv1, events) } - var events *corev1.EventList - if describerSettings.ShowEvents { - events, _ = p.CoreV1().Events(namespace).Search(scheme.Scheme, pdb) + // try falling back to v1beta1 in NotFound error cases + if apierrors.IsNotFound(err) { + pdbv1beta1, err = p.PolicyV1beta1().PodDisruptionBudgets(namespace).Get(context.TODO(), name, metav1.GetOptions{}) + } + if err == nil { + var events *corev1.EventList + if describerSettings.ShowEvents { + events, _ = p.CoreV1().Events(namespace).Search(scheme.Scheme, pdbv1beta1) + } + return describePodDisruptionBudgetV1beta1(pdbv1beta1, events) } - return describePodDisruptionBudget(pdb, events) + return "", err } -func describePodDisruptionBudget(pdb *policyv1beta1.PodDisruptionBudget, events *corev1.EventList) (string, error) { +func describePodDisruptionBudgetV1(pdb *policyv1.PodDisruptionBudget, events *corev1.EventList) (string, error) { + return tabbedString(func(out io.Writer) error { + w := NewPrefixWriter(out) + w.Write(LEVEL_0, "Name:\t%s\n", pdb.Name) + w.Write(LEVEL_0, "Namespace:\t%s\n", pdb.Namespace) + + if pdb.Spec.MinAvailable != nil { + w.Write(LEVEL_0, "Min available:\t%s\n", pdb.Spec.MinAvailable.String()) + } else if pdb.Spec.MaxUnavailable != nil { + w.Write(LEVEL_0, "Max unavailable:\t%s\n", pdb.Spec.MaxUnavailable.String()) + } + + if pdb.Spec.Selector != nil { + w.Write(LEVEL_0, "Selector:\t%s\n", metav1.FormatLabelSelector(pdb.Spec.Selector)) + } else { + w.Write(LEVEL_0, "Selector:\t\n") + } + w.Write(LEVEL_0, "Status:\n") + w.Write(LEVEL_2, "Allowed disruptions:\t%d\n", pdb.Status.DisruptionsAllowed) + w.Write(LEVEL_2, "Current:\t%d\n", pdb.Status.CurrentHealthy) + w.Write(LEVEL_2, "Desired:\t%d\n", pdb.Status.DesiredHealthy) + w.Write(LEVEL_2, "Total:\t%d\n", pdb.Status.ExpectedPods) + if events != nil { + DescribeEvents(events, w) + } + + return nil + }) +} + +func describePodDisruptionBudgetV1beta1(pdb *policyv1beta1.PodDisruptionBudget, events *corev1.EventList) (string, error) { return tabbedString(func(out io.Writer) error { w := NewPrefixWriter(out) w.Write(LEVEL_0, "Name:\t%s\n", pdb.Name) diff --git a/staging/src/k8s.io/kubectl/pkg/describe/describe_test.go b/staging/src/k8s.io/kubectl/pkg/describe/describe_test.go index c5391e1339c..487decf7e57 100644 --- a/staging/src/k8s.io/kubectl/pkg/describe/describe_test.go +++ b/staging/src/k8s.io/kubectl/pkg/describe/describe_test.go @@ -35,6 +35,7 @@ import ( discoveryv1beta1 "k8s.io/api/discovery/v1beta1" networkingv1 "k8s.io/api/networking/v1" networkingv1beta1 "k8s.io/api/networking/v1beta1" + policyv1 "k8s.io/api/policy/v1" policyv1beta1 "k8s.io/api/policy/v1beta1" storagev1 "k8s.io/api/storage/v1" apiequality "k8s.io/apimachinery/pkg/api/equality" @@ -2577,7 +2578,7 @@ func TestDescribeCSINode(t *testing.T) { } } -func TestDescribePodDisruptionBudget(t *testing.T) { +func TestDescribePodDisruptionBudgetV1beta1(t *testing.T) { minAvailable := intstr.FromInt(22) f := fake.NewSimpleClientset(&policyv1beta1.PodDisruptionBudget{ ObjectMeta: metav1.ObjectMeta{ @@ -2605,6 +2606,34 @@ func TestDescribePodDisruptionBudget(t *testing.T) { } } +func TestDescribePodDisruptionBudgetV1(t *testing.T) { + minAvailable := intstr.FromInt(22) + f := fake.NewSimpleClientset(&policyv1.PodDisruptionBudget{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "ns1", + Name: "pdb1", + CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)}, + }, + Spec: policyv1.PodDisruptionBudgetSpec{ + MinAvailable: &minAvailable, + }, + Status: policyv1.PodDisruptionBudgetStatus{ + DisruptionsAllowed: 5, + }, + }) + s := PodDisruptionBudgetDescriber{f} + out, err := s.Describe("ns1", "pdb1", DescriberSettings{ShowEvents: true}) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if !strings.Contains(out, "pdb1") || + !strings.Contains(out, "ns1") || + !strings.Contains(out, "22") || + !strings.Contains(out, "5") { + t.Errorf("unexpected out: %s", out) + } +} + func TestDescribeHorizontalPodAutoscaler(t *testing.T) { minReplicasVal := int32(2) targetUtilizationVal := int32(80)