mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 12:43:23 +00:00
Include Conditions in kubectl describe namespace
If a namespace deletion is blocked, finding the reason why can require reading the Conditions on the namespace. Currently, `kubectl describe namespace` does not include Conditions. This change adds Conditions to the output. Example output: ``` Name: example Labels: <none> Annotations: <none> Status: Terminating Conditions: Type Status LastTransitionTime Reason Message ---- ------ ------------------ ------ ------- NamespaceDeletionContentFailure True Wed, 15 Jan 2014 00:00:00 +0000 example reason example message No resource quota. No LimitRange resource. ```
This commit is contained in:
parent
fa040a9945
commit
eb6e8ce00a
@ -451,14 +451,31 @@ func describeNamespace(namespace *corev1.Namespace, resourceQuotaList *corev1.Re
|
||||
printLabelsMultiline(w, "Labels", namespace.Labels)
|
||||
printAnnotationsMultiline(w, "Annotations", namespace.Annotations)
|
||||
w.Write(LEVEL_0, "Status:\t%s\n", string(namespace.Status.Phase))
|
||||
|
||||
if len(namespace.Status.Conditions) > 0 {
|
||||
w.Write(LEVEL_0, "Conditions:\n")
|
||||
w.Write(LEVEL_1, "Type\tStatus\tLastTransitionTime\tReason\tMessage\n")
|
||||
w.Write(LEVEL_1, "----\t------\t------------------\t------\t-------\n")
|
||||
for _, c := range namespace.Status.Conditions {
|
||||
w.Write(LEVEL_1, "%v\t%v\t%s\t%v\t%v\n",
|
||||
c.Type,
|
||||
c.Status,
|
||||
c.LastTransitionTime.Time.Format(time.RFC1123Z),
|
||||
c.Reason,
|
||||
c.Message)
|
||||
}
|
||||
}
|
||||
|
||||
if resourceQuotaList != nil {
|
||||
w.Write(LEVEL_0, "\n")
|
||||
DescribeResourceQuotas(resourceQuotaList, w)
|
||||
}
|
||||
|
||||
if limitRangeList != nil {
|
||||
w.Write(LEVEL_0, "\n")
|
||||
DescribeLimitRanges(limitRangeList, w)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
@ -236,19 +236,88 @@ func TestDescribeSecret(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDescribeNamespace(t *testing.T) {
|
||||
fake := fake.NewSimpleClientset(&corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "myns",
|
||||
exampleNamespaceName := "example"
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
namespace *corev1.Namespace
|
||||
expect []string
|
||||
}{
|
||||
{
|
||||
name: "no quotas or limit ranges",
|
||||
namespace: &corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: exampleNamespaceName,
|
||||
},
|
||||
Status: corev1.NamespaceStatus{
|
||||
Phase: corev1.NamespaceActive,
|
||||
},
|
||||
},
|
||||
expect: []string{
|
||||
"Name",
|
||||
exampleNamespaceName,
|
||||
"Status",
|
||||
string(corev1.NamespaceActive),
|
||||
"No resource quota",
|
||||
"No LimitRange resource.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "has conditions",
|
||||
namespace: &corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: exampleNamespaceName,
|
||||
},
|
||||
Status: corev1.NamespaceStatus{
|
||||
Phase: corev1.NamespaceTerminating,
|
||||
Conditions: []corev1.NamespaceCondition{
|
||||
{
|
||||
LastTransitionTime: metav1.NewTime(time.Date(2014, time.January, 15, 0, 0, 0, 0, time.UTC)),
|
||||
Message: "example message",
|
||||
Reason: "example reason",
|
||||
Status: corev1.ConditionTrue,
|
||||
Type: corev1.NamespaceDeletionContentFailure,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expect: []string{
|
||||
"Name",
|
||||
exampleNamespaceName,
|
||||
"Status",
|
||||
string(corev1.NamespaceTerminating),
|
||||
"Conditions",
|
||||
"Type",
|
||||
string(corev1.NamespaceDeletionContentFailure),
|
||||
"Status",
|
||||
string(corev1.ConditionTrue),
|
||||
"Reason",
|
||||
"example reason",
|
||||
"Message",
|
||||
"example message",
|
||||
"No resource quota",
|
||||
"No LimitRange resource.",
|
||||
},
|
||||
},
|
||||
})
|
||||
c := &describeClient{T: t, Namespace: "", Interface: fake}
|
||||
d := NamespaceDescriber{c}
|
||||
out, err := d.Describe("", "myns", DescriberSettings{ShowEvents: true})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if !strings.Contains(out, "myns") {
|
||||
t.Errorf("unexpected out: %s", out)
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
fake := fake.NewSimpleClientset(testCase.namespace)
|
||||
c := &describeClient{T: t, Namespace: "", Interface: fake}
|
||||
d := NamespaceDescriber{c}
|
||||
|
||||
out, err := d.Describe("", testCase.namespace.Name, DescriberSettings{ShowEvents: true})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
for _, expected := range testCase.expect {
|
||||
if !strings.Contains(out, expected) {
|
||||
t.Errorf("expected to find %q in output: %q", expected, out)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user