Unverified Commit 5f55fd21 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #65351 from dtaniwaki/fix-deletion-timestamp-printing

Automatic merge from submit-queue (batch tested with PRs 65993, 65986, 65351, 65996, 65985). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. Fix DeletionTimestamp printing **What this PR does / why we need it**: I found a bug that `ObjectMeta.DeletionTimestamp` is not displayed correctly because it's a future time but it uses the time difference until now. So I fixed it by calculating the time difference from now instead of until now. Before this fix: ``` Name: test-pod-7bd594bd96-hf5kk Namespace: default Node: kube-node-2/10.192.0.4 Start Time: Fri, 22 Jun 2018 14:57:09 +0900 Labels: pod-template-hash=3681506852 run=test-pod Annotations: <none> Status: Terminating (lasts <invalid>) Termination Grace Period: 30s IP: 10.244.3.5 Controlled By: ReplicaSet/test-pod-7bd594bd96 Containers: ... ``` After this fix: ``` Name: test-pod-7bd594bd96-85cdd Namespace: default Node: kube-node-2/10.192.0.4 Start Time: Fri, 22 Jun 2018 14:56:44 +0900 Labels: pod-template-hash=3681506852 run=test-pod Annotations: <none> Status: Terminating (lasts 2m) Termination Grace Period: 123s IP: 10.244.3.4 Controlled By: ReplicaSet/test-pod-7bd594bd96 ... ``` Could you consider merging it? We heavily use preemptible jobs in my company and knowing deletion time and grace periods is really important when jobs trap `SIGTERM` and decide if it should continue to run until the deletion time or just stop immediately. **Which issue(s) this PR fixes** N/A **Special notes for your reviewer**: N/A **Release note**: ```release-note NONE ```
parents 24555bbc 7cb10e14
...@@ -643,7 +643,7 @@ func describePod(pod *api.Pod, events *api.EventList) (string, error) { ...@@ -643,7 +643,7 @@ func describePod(pod *api.Pod, events *api.EventList) (string, error) {
printLabelsMultiline(w, "Labels", pod.Labels) printLabelsMultiline(w, "Labels", pod.Labels)
printAnnotationsMultiline(w, "Annotations", pod.Annotations) printAnnotationsMultiline(w, "Annotations", pod.Annotations)
if pod.DeletionTimestamp != nil { if pod.DeletionTimestamp != nil {
w.Write(LEVEL_0, "Status:\tTerminating (lasts %s)\n", translateTimestamp(*pod.DeletionTimestamp)) w.Write(LEVEL_0, "Status:\tTerminating (lasts %s)\n", translateTimestampUntil(*pod.DeletionTimestamp))
w.Write(LEVEL_0, "Termination Grace Period:\t%ds\n", *pod.DeletionGracePeriodSeconds) w.Write(LEVEL_0, "Termination Grace Period:\t%ds\n", *pod.DeletionGracePeriodSeconds)
} else { } else {
w.Write(LEVEL_0, "Status:\t%s\n", string(pod.Status.Phase)) w.Write(LEVEL_0, "Status:\t%s\n", string(pod.Status.Phase))
...@@ -1202,7 +1202,7 @@ func describePersistentVolume(pv *api.PersistentVolume, events *api.EventList) ( ...@@ -1202,7 +1202,7 @@ func describePersistentVolume(pv *api.PersistentVolume, events *api.EventList) (
w.Write(LEVEL_0, "Finalizers:\t%v\n", pv.ObjectMeta.Finalizers) w.Write(LEVEL_0, "Finalizers:\t%v\n", pv.ObjectMeta.Finalizers)
w.Write(LEVEL_0, "StorageClass:\t%s\n", helper.GetPersistentVolumeClass(pv)) w.Write(LEVEL_0, "StorageClass:\t%s\n", helper.GetPersistentVolumeClass(pv))
if pv.ObjectMeta.DeletionTimestamp != nil { if pv.ObjectMeta.DeletionTimestamp != nil {
w.Write(LEVEL_0, "Status:\tTerminating (lasts %s)\n", translateTimestamp(*pv.ObjectMeta.DeletionTimestamp)) w.Write(LEVEL_0, "Status:\tTerminating (lasts %s)\n", translateTimestampUntil(*pv.ObjectMeta.DeletionTimestamp))
} else { } else {
w.Write(LEVEL_0, "Status:\t%v\n", pv.Status.Phase) w.Write(LEVEL_0, "Status:\t%v\n", pv.Status.Phase)
} }
...@@ -1343,7 +1343,7 @@ func describePersistentVolumeClaim(pvc *api.PersistentVolumeClaim, events *api.E ...@@ -1343,7 +1343,7 @@ func describePersistentVolumeClaim(pvc *api.PersistentVolumeClaim, events *api.E
w.Write(LEVEL_0, "Namespace:\t%s\n", pvc.Namespace) w.Write(LEVEL_0, "Namespace:\t%s\n", pvc.Namespace)
w.Write(LEVEL_0, "StorageClass:\t%s\n", helper.GetPersistentVolumeClaimClass(pvc)) w.Write(LEVEL_0, "StorageClass:\t%s\n", helper.GetPersistentVolumeClaimClass(pvc))
if pvc.ObjectMeta.DeletionTimestamp != nil { if pvc.ObjectMeta.DeletionTimestamp != nil {
w.Write(LEVEL_0, "Status:\tTerminating (lasts %s)\n", translateTimestamp(*pvc.ObjectMeta.DeletionTimestamp)) w.Write(LEVEL_0, "Status:\tTerminating (lasts %s)\n", translateTimestampUntil(*pvc.ObjectMeta.DeletionTimestamp))
} else { } else {
w.Write(LEVEL_0, "Status:\t%v\n", pvc.Status.Phase) w.Write(LEVEL_0, "Status:\t%v\n", pvc.Status.Phase)
} }
...@@ -3130,9 +3130,9 @@ func DescribeEvents(el *api.EventList, w PrefixWriter) { ...@@ -3130,9 +3130,9 @@ func DescribeEvents(el *api.EventList, w PrefixWriter) {
for _, e := range el.Items { for _, e := range el.Items {
var interval string var interval string
if e.Count > 1 { if e.Count > 1 {
interval = fmt.Sprintf("%s (x%d over %s)", translateTimestamp(e.LastTimestamp), e.Count, translateTimestamp(e.FirstTimestamp)) interval = fmt.Sprintf("%s (x%d over %s)", translateTimestampSince(e.LastTimestamp), e.Count, translateTimestampSince(e.FirstTimestamp))
} else { } else {
interval = translateTimestamp(e.FirstTimestamp) interval = translateTimestampSince(e.FirstTimestamp)
} }
w.Write(LEVEL_1, "%v\t%v\t%s\t%v\t%v\n", w.Write(LEVEL_1, "%v\t%v\t%s\t%v\t%v\n",
e.Type, e.Type,
......
...@@ -54,10 +54,14 @@ type describeClient struct { ...@@ -54,10 +54,14 @@ type describeClient struct {
} }
func TestDescribePod(t *testing.T) { func TestDescribePod(t *testing.T) {
deletionTimestamp := metav1.Time{Time: time.Now().UTC().AddDate(10, 0, 0)}
gracePeriod := int64(1234)
fake := fake.NewSimpleClientset(&api.Pod{ fake := fake.NewSimpleClientset(&api.Pod{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "bar", Name: "bar",
Namespace: "foo", Namespace: "foo",
DeletionTimestamp: &deletionTimestamp,
DeletionGracePeriodSeconds: &gracePeriod,
}, },
}) })
c := &describeClient{T: t, Namespace: "foo", Interface: fake} c := &describeClient{T: t, Namespace: "foo", Interface: fake}
...@@ -69,6 +73,9 @@ func TestDescribePod(t *testing.T) { ...@@ -69,6 +73,9 @@ func TestDescribePod(t *testing.T) {
if !strings.Contains(out, "bar") || !strings.Contains(out, "Status:") { if !strings.Contains(out, "bar") || !strings.Contains(out, "Status:") {
t.Errorf("unexpected out: %s", out) t.Errorf("unexpected out: %s", out)
} }
if !strings.Contains(out, "Terminating (lasts 10y)") || !strings.Contains(out, "1234s") {
t.Errorf("unexpected out: %s", out)
}
} }
func TestDescribePodNode(t *testing.T) { func TestDescribePodNode(t *testing.T) {
...@@ -892,6 +899,7 @@ func TestGetPodsTotalRequests(t *testing.T) { ...@@ -892,6 +899,7 @@ func TestGetPodsTotalRequests(t *testing.T) {
func TestPersistentVolumeDescriber(t *testing.T) { func TestPersistentVolumeDescriber(t *testing.T) {
block := api.PersistentVolumeBlock block := api.PersistentVolumeBlock
file := api.PersistentVolumeFilesystem file := api.PersistentVolumeFilesystem
deletionTimestamp := metav1.Time{Time: time.Now().UTC().AddDate(10, 0, 0)}
testCases := []struct { testCases := []struct {
name string name string
plugin string plugin string
...@@ -1137,6 +1145,22 @@ func TestPersistentVolumeDescriber(t *testing.T) { ...@@ -1137,6 +1145,22 @@ func TestPersistentVolumeDescriber(t *testing.T) {
"foo in [val1, val2]", "foo in [val1, val2]",
"foo exists"}, "foo exists"},
}, },
{
name: "test15",
plugin: "local",
pv: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: "bar",
DeletionTimestamp: &deletionTimestamp,
},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{
Local: &api.LocalVolumeSource{},
},
},
},
expectedElements: []string{"Terminating (lasts 10y)"},
},
} }
for _, test := range testCases { for _, test := range testCases {
...@@ -1169,6 +1193,7 @@ func TestPersistentVolumeClaimDescriber(t *testing.T) { ...@@ -1169,6 +1193,7 @@ func TestPersistentVolumeClaimDescriber(t *testing.T) {
file := api.PersistentVolumeFilesystem file := api.PersistentVolumeFilesystem
goldClassName := "gold" goldClassName := "gold"
now := time.Now() now := time.Now()
deletionTimestamp := metav1.Time{Time: time.Now().UTC().AddDate(10, 0, 0)}
testCases := []struct { testCases := []struct {
name string name string
pvc *api.PersistentVolumeClaim pvc *api.PersistentVolumeClaim
...@@ -1316,6 +1341,22 @@ func TestPersistentVolumeClaimDescriber(t *testing.T) { ...@@ -1316,6 +1341,22 @@ func TestPersistentVolumeClaimDescriber(t *testing.T) {
}, },
expectedElements: []string{"Conditions", "Message", "User request resize"}, expectedElements: []string{"Conditions", "Message", "User request resize"},
}, },
{
name: "deletion-timestamp",
pvc: &api.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Namespace: "foo",
Name: "bar",
DeletionTimestamp: &deletionTimestamp,
},
Spec: api.PersistentVolumeClaimSpec{
VolumeName: "volume10",
StorageClassName: &goldClassName,
},
Status: api.PersistentVolumeClaimStatus{},
},
expectedElements: []string{"Terminating (lasts 10y)"},
},
} }
for _, test := range testCases { for _, test := range testCases {
......
...@@ -1919,18 +1919,43 @@ type stringTestList []struct { ...@@ -1919,18 +1919,43 @@ type stringTestList []struct {
name, got, exp string name, got, exp string
} }
func TestTranslateTimestamp(t *testing.T) { func TestTranslateTimestampSince(t *testing.T) {
tl := stringTestList{ tl := stringTestList{
{"a while from now", translateTimestamp(metav1.Time{Time: time.Now().Add(2.1e9)}), "<invalid>"}, {"a while from now", translateTimestampSince(metav1.Time{Time: time.Now().Add(2.1e9)}), "<invalid>"},
{"almost now", translateTimestamp(metav1.Time{Time: time.Now().Add(1.9e9)}), "0s"}, {"almost now", translateTimestampSince(metav1.Time{Time: time.Now().Add(1.9e9)}), "0s"},
{"now", translateTimestamp(metav1.Time{Time: time.Now()}), "0s"}, {"now", translateTimestampSince(metav1.Time{Time: time.Now()}), "0s"},
{"unknown", translateTimestamp(metav1.Time{}), "<unknown>"}, {"unknown", translateTimestampSince(metav1.Time{}), "<unknown>"},
{"30 seconds ago", translateTimestamp(metav1.Time{Time: time.Now().Add(-3e10)}), "30s"}, {"30 seconds ago", translateTimestampSince(metav1.Time{Time: time.Now().Add(-3e10)}), "30s"},
{"5 minutes ago", translateTimestamp(metav1.Time{Time: time.Now().Add(-3e11)}), "5m"}, {"5 minutes ago", translateTimestampSince(metav1.Time{Time: time.Now().Add(-3e11)}), "5m"},
{"an hour ago", translateTimestamp(metav1.Time{Time: time.Now().Add(-6e12)}), "1h"}, {"an hour ago", translateTimestampSince(metav1.Time{Time: time.Now().Add(-6e12)}), "1h"},
{"2 days ago", translateTimestamp(metav1.Time{Time: time.Now().UTC().AddDate(0, 0, -2)}), "2d"}, {"2 days ago", translateTimestampSince(metav1.Time{Time: time.Now().UTC().AddDate(0, 0, -2)}), "2d"},
{"months ago", translateTimestamp(metav1.Time{Time: time.Now().UTC().AddDate(0, 0, -90)}), "90d"}, {"months ago", translateTimestampSince(metav1.Time{Time: time.Now().UTC().AddDate(0, 0, -90)}), "90d"},
{"10 years ago", translateTimestamp(metav1.Time{Time: time.Now().UTC().AddDate(-10, 0, 0)}), "10y"}, {"10 years ago", translateTimestampSince(metav1.Time{Time: time.Now().UTC().AddDate(-10, 0, 0)}), "10y"},
}
for _, test := range tl {
if test.got != test.exp {
t.Errorf("On %v, expected '%v', but got '%v'",
test.name, test.exp, test.got)
}
}
}
func TestTranslateTimestampUntil(t *testing.T) {
// Since this method compares the time with time.Now() internally,
// small buffers of 0.1 seconds are added on comparing times to consider method call overhead.
// Otherwise, the output strings become shorter than expected.
const buf = 1e8
tl := stringTestList{
{"a while ago", translateTimestampUntil(metav1.Time{Time: time.Now().Add(-2.1e9)}), "<invalid>"},
{"almost now", translateTimestampUntil(metav1.Time{Time: time.Now().Add(-1.9e9)}), "0s"},
{"now", translateTimestampUntil(metav1.Time{Time: time.Now()}), "0s"},
{"unknown", translateTimestampUntil(metav1.Time{}), "<unknown>"},
{"in 30 seconds", translateTimestampUntil(metav1.Time{Time: time.Now().Add(3e10 + buf)}), "30s"},
{"in 5 minutes", translateTimestampUntil(metav1.Time{Time: time.Now().Add(3e11 + buf)}), "5m"},
{"in an hour", translateTimestampUntil(metav1.Time{Time: time.Now().Add(6e12 + buf)}), "1h"},
{"in 2 days", translateTimestampUntil(metav1.Time{Time: time.Now().UTC().AddDate(0, 0, 2).Add(buf)}), "2d"},
{"in months", translateTimestampUntil(metav1.Time{Time: time.Now().UTC().AddDate(0, 0, 90).Add(buf)}), "90d"},
{"in 10 years", translateTimestampUntil(metav1.Time{Time: time.Now().UTC().AddDate(10, 0, 0).Add(buf)}), "10y"},
} }
for _, test := range tl { for _, test := range tl {
if test.got != test.exp { if test.got != test.exp {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment