diff --git a/pkg/printers/internalversion/describe.go b/pkg/printers/internalversion/describe.go index a3c1adadc6e..1e27451bea0 100644 --- a/pkg/printers/internalversion/describe.go +++ b/pkg/printers/internalversion/describe.go @@ -643,7 +643,7 @@ func describePod(pod *api.Pod, events *api.EventList) (string, error) { printLabelsMultiline(w, "Labels", pod.Labels) printAnnotationsMultiline(w, "Annotations", pod.Annotations) 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) } else { w.Write(LEVEL_0, "Status:\t%s\n", string(pod.Status.Phase)) @@ -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, "StorageClass:\t%s\n", helper.GetPersistentVolumeClass(pv)) 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 { w.Write(LEVEL_0, "Status:\t%v\n", pv.Status.Phase) } @@ -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, "StorageClass:\t%s\n", helper.GetPersistentVolumeClaimClass(pvc)) 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 { w.Write(LEVEL_0, "Status:\t%v\n", pvc.Status.Phase) } @@ -3130,9 +3130,9 @@ func DescribeEvents(el *api.EventList, w PrefixWriter) { for _, e := range el.Items { var interval string 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 { - interval = translateTimestamp(e.FirstTimestamp) + interval = translateTimestampSince(e.FirstTimestamp) } w.Write(LEVEL_1, "%v\t%v\t%s\t%v\t%v\n", e.Type, diff --git a/pkg/printers/internalversion/describe_test.go b/pkg/printers/internalversion/describe_test.go index 73cae18fd64..bafea3a899d 100644 --- a/pkg/printers/internalversion/describe_test.go +++ b/pkg/printers/internalversion/describe_test.go @@ -54,10 +54,14 @@ type describeClient struct { } func TestDescribePod(t *testing.T) { + deletionTimestamp := metav1.Time{Time: time.Now().UTC().AddDate(10, 0, 0)} + gracePeriod := int64(1234) fake := fake.NewSimpleClientset(&api.Pod{ ObjectMeta: metav1.ObjectMeta{ - Name: "bar", - Namespace: "foo", + Name: "bar", + Namespace: "foo", + DeletionTimestamp: &deletionTimestamp, + DeletionGracePeriodSeconds: &gracePeriod, }, }) c := &describeClient{T: t, Namespace: "foo", Interface: fake} @@ -69,6 +73,9 @@ func TestDescribePod(t *testing.T) { if !strings.Contains(out, "bar") || !strings.Contains(out, "Status:") { 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) { @@ -892,6 +899,7 @@ func TestGetPodsTotalRequests(t *testing.T) { func TestPersistentVolumeDescriber(t *testing.T) { block := api.PersistentVolumeBlock file := api.PersistentVolumeFilesystem + deletionTimestamp := metav1.Time{Time: time.Now().UTC().AddDate(10, 0, 0)} testCases := []struct { name string plugin string @@ -1137,6 +1145,22 @@ func TestPersistentVolumeDescriber(t *testing.T) { "foo in [val1, val2]", "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 { @@ -1169,6 +1193,7 @@ func TestPersistentVolumeClaimDescriber(t *testing.T) { file := api.PersistentVolumeFilesystem goldClassName := "gold" now := time.Now() + deletionTimestamp := metav1.Time{Time: time.Now().UTC().AddDate(10, 0, 0)} testCases := []struct { name string pvc *api.PersistentVolumeClaim @@ -1316,6 +1341,22 @@ func TestPersistentVolumeClaimDescriber(t *testing.T) { }, 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 { diff --git a/pkg/printers/internalversion/printers.go b/pkg/printers/internalversion/printers.go index 43873bbb7f7..6450a43aba5 100644 --- a/pkg/printers/internalversion/printers.go +++ b/pkg/printers/internalversion/printers.go @@ -467,7 +467,7 @@ func printObjectMeta(obj runtime.Object, options printers.PrintOptions) ([]metav row := metav1beta1.TableRow{ Object: runtime.RawExtension{Object: obj}, } - row.Cells = append(row.Cells, m.GetName(), translateTimestamp(m.GetCreationTimestamp())) + row.Cells = append(row.Cells, m.GetName(), translateTimestampSince(m.GetCreationTimestamp())) rows = append(rows, row) return rows, nil } @@ -507,9 +507,9 @@ func formatEndpoints(endpoints *api.Endpoints, ports sets.String) string { return ret } -// translateTimestamp returns the elapsed time since timestamp in +// translateTimestampSince returns the elapsed time since timestamp in // human-readable approximation. -func translateTimestamp(timestamp metav1.Time) string { +func translateTimestampSince(timestamp metav1.Time) string { if timestamp.IsZero() { return "" } @@ -517,6 +517,16 @@ func translateTimestamp(timestamp metav1.Time) string { return duration.ShortHumanDuration(time.Since(timestamp.Time)) } +// translateTimestampUntil returns the elapsed time until timestamp in +// human-readable approximation. +func translateTimestampUntil(timestamp metav1.Time) string { + if timestamp.IsZero() { + return "" + } + + return duration.ShortHumanDuration(time.Until(timestamp.Time)) +} + var ( podSuccessConditions = []metav1beta1.TableRowCondition{{Type: metav1beta1.RowCompleted, Status: metav1beta1.ConditionTrue, Reason: string(api.PodSucceeded), Message: "The pod has completed successfully."}} podFailedConditions = []metav1beta1.TableRowCondition{{Type: metav1beta1.RowCompleted, Status: metav1beta1.ConditionTrue, Reason: string(api.PodFailed), Message: "The pod failed."}} @@ -618,7 +628,7 @@ func printPod(pod *api.Pod, options printers.PrintOptions) ([]metav1beta1.TableR reason = "Terminating" } - row.Cells = append(row.Cells, pod.Name, fmt.Sprintf("%d/%d", readyContainers, totalContainers), reason, int64(restarts), translateTimestamp(pod.CreationTimestamp)) + row.Cells = append(row.Cells, pod.Name, fmt.Sprintf("%d/%d", readyContainers, totalContainers), reason, int64(restarts), translateTimestampSince(pod.CreationTimestamp)) if options.Wide { nodeName := pod.Spec.NodeName @@ -678,7 +688,7 @@ func printPodDisruptionBudget(obj *policy.PodDisruptionBudget, options printers. maxUnavailable = "N/A" } - row.Cells = append(row.Cells, obj.Name, minAvailable, maxUnavailable, int64(obj.Status.PodDisruptionsAllowed), translateTimestamp(obj.CreationTimestamp)) + row.Cells = append(row.Cells, obj.Name, minAvailable, maxUnavailable, int64(obj.Status.PodDisruptionsAllowed), translateTimestampSince(obj.CreationTimestamp)) return []metav1beta1.TableRow{row}, nil } @@ -704,7 +714,7 @@ func printReplicationController(obj *api.ReplicationController, options printers currentReplicas := obj.Status.Replicas readyReplicas := obj.Status.ReadyReplicas - row.Cells = append(row.Cells, obj.Name, int64(desiredReplicas), int64(currentReplicas), int64(readyReplicas), translateTimestamp(obj.CreationTimestamp)) + row.Cells = append(row.Cells, obj.Name, int64(desiredReplicas), int64(currentReplicas), int64(readyReplicas), translateTimestampSince(obj.CreationTimestamp)) if options.Wide { names, images := layoutContainerCells(obj.Spec.Template.Spec.Containers) row.Cells = append(row.Cells, names, images, labels.FormatLabels(obj.Spec.Selector)) @@ -733,7 +743,7 @@ func printReplicaSet(obj *extensions.ReplicaSet, options printers.PrintOptions) currentReplicas := obj.Status.Replicas readyReplicas := obj.Status.ReadyReplicas - row.Cells = append(row.Cells, obj.Name, int64(desiredReplicas), int64(currentReplicas), int64(readyReplicas), translateTimestamp(obj.CreationTimestamp)) + row.Cells = append(row.Cells, obj.Name, int64(desiredReplicas), int64(currentReplicas), int64(readyReplicas), translateTimestampSince(obj.CreationTimestamp)) if options.Wide { names, images := layoutContainerCells(obj.Spec.Template.Spec.Containers) row.Cells = append(row.Cells, names, images, metav1.FormatLabelSelector(obj.Spec.Selector)) @@ -781,7 +791,7 @@ func printJob(obj *batch.Job, options printers.PrintOptions) ([]metav1beta1.Tabl jobDuration = duration.HumanDuration(obj.Status.CompletionTime.Sub(obj.Status.StartTime.Time)) } - row.Cells = append(row.Cells, obj.Name, completions, jobDuration, translateTimestamp(obj.CreationTimestamp)) + row.Cells = append(row.Cells, obj.Name, completions, jobDuration, translateTimestampSince(obj.CreationTimestamp)) if options.Wide { names, images := layoutContainerCells(obj.Spec.Template.Spec.Containers) row.Cells = append(row.Cells, names, images, metav1.FormatLabelSelector(obj.Spec.Selector)) @@ -808,10 +818,10 @@ func printCronJob(obj *batch.CronJob, options printers.PrintOptions) ([]metav1be lastScheduleTime := "" if obj.Status.LastScheduleTime != nil { - lastScheduleTime = translateTimestamp(*obj.Status.LastScheduleTime) + lastScheduleTime = translateTimestampSince(*obj.Status.LastScheduleTime) } - row.Cells = append(row.Cells, obj.Name, obj.Spec.Schedule, printBoolPtr(obj.Spec.Suspend), int64(len(obj.Status.Active)), lastScheduleTime, translateTimestamp(obj.CreationTimestamp)) + row.Cells = append(row.Cells, obj.Name, obj.Spec.Schedule, printBoolPtr(obj.Spec.Suspend), int64(len(obj.Status.Active)), lastScheduleTime, translateTimestampSince(obj.CreationTimestamp)) if options.Wide { names, images := layoutContainerCells(obj.Spec.JobTemplate.Spec.Template.Spec.Containers) row.Cells = append(row.Cells, names, images, metav1.FormatLabelSelector(obj.Spec.JobTemplate.Spec.Selector)) @@ -910,7 +920,7 @@ func printService(obj *api.Service, options printers.PrintOptions) ([]metav1beta svcPorts = "" } - row.Cells = append(row.Cells, obj.Name, string(svcType), internalIP, externalIP, svcPorts, translateTimestamp(obj.CreationTimestamp)) + row.Cells = append(row.Cells, obj.Name, string(svcType), internalIP, externalIP, svcPorts, translateTimestampSince(obj.CreationTimestamp)) if options.Wide { row.Cells = append(row.Cells, labels.FormatLabels(obj.Spec.Selector)) } @@ -974,7 +984,7 @@ func printIngress(obj *extensions.Ingress, options printers.PrintOptions) ([]met hosts := formatHosts(obj.Spec.Rules) address := loadBalancerStatusStringer(obj.Status.LoadBalancer, options.Wide) ports := formatPorts(obj.Spec.TLS) - createTime := translateTimestamp(obj.CreationTimestamp) + createTime := translateTimestampSince(obj.CreationTimestamp) row.Cells = append(row.Cells, obj.Name, hosts, address, ports, createTime) return []metav1beta1.TableRow{row}, nil } @@ -997,7 +1007,7 @@ func printStatefulSet(obj *apps.StatefulSet, options printers.PrintOptions) ([]m } desiredReplicas := obj.Spec.Replicas currentReplicas := obj.Status.Replicas - createTime := translateTimestamp(obj.CreationTimestamp) + createTime := translateTimestampSince(obj.CreationTimestamp) row.Cells = append(row.Cells, obj.Name, int64(desiredReplicas), int64(currentReplicas), createTime) if options.Wide { names, images := layoutContainerCells(obj.Spec.Template.Spec.Containers) @@ -1029,7 +1039,7 @@ func printDaemonSet(obj *extensions.DaemonSet, options printers.PrintOptions) ([ numberUpdated := obj.Status.UpdatedNumberScheduled numberAvailable := obj.Status.NumberAvailable - row.Cells = append(row.Cells, obj.Name, int64(desiredScheduled), int64(currentScheduled), int64(numberReady), int64(numberUpdated), int64(numberAvailable), labels.FormatLabels(obj.Spec.Template.Spec.NodeSelector), translateTimestamp(obj.CreationTimestamp)) + row.Cells = append(row.Cells, obj.Name, int64(desiredScheduled), int64(currentScheduled), int64(numberReady), int64(numberUpdated), int64(numberAvailable), labels.FormatLabels(obj.Spec.Template.Spec.NodeSelector), translateTimestampSince(obj.CreationTimestamp)) if options.Wide { names, images := layoutContainerCells(obj.Spec.Template.Spec.Containers) row.Cells = append(row.Cells, names, images, metav1.FormatLabelSelector(obj.Spec.Selector)) @@ -1053,7 +1063,7 @@ func printEndpoints(obj *api.Endpoints, options printers.PrintOptions) ([]metav1 row := metav1beta1.TableRow{ Object: runtime.RawExtension{Object: obj}, } - row.Cells = append(row.Cells, obj.Name, formatEndpoints(obj, nil), translateTimestamp(obj.CreationTimestamp)) + row.Cells = append(row.Cells, obj.Name, formatEndpoints(obj, nil), translateTimestampSince(obj.CreationTimestamp)) return []metav1beta1.TableRow{row}, nil } @@ -1073,7 +1083,7 @@ func printNamespace(obj *api.Namespace, options printers.PrintOptions) ([]metav1 row := metav1beta1.TableRow{ Object: runtime.RawExtension{Object: obj}, } - row.Cells = append(row.Cells, obj.Name, string(obj.Status.Phase), translateTimestamp(obj.CreationTimestamp)) + row.Cells = append(row.Cells, obj.Name, string(obj.Status.Phase), translateTimestampSince(obj.CreationTimestamp)) return []metav1beta1.TableRow{row}, nil } @@ -1093,7 +1103,7 @@ func printSecret(obj *api.Secret, options printers.PrintOptions) ([]metav1beta1. row := metav1beta1.TableRow{ Object: runtime.RawExtension{Object: obj}, } - row.Cells = append(row.Cells, obj.Name, string(obj.Type), int64(len(obj.Data)), translateTimestamp(obj.CreationTimestamp)) + row.Cells = append(row.Cells, obj.Name, string(obj.Type), int64(len(obj.Data)), translateTimestampSince(obj.CreationTimestamp)) return []metav1beta1.TableRow{row}, nil } @@ -1113,7 +1123,7 @@ func printServiceAccount(obj *api.ServiceAccount, options printers.PrintOptions) row := metav1beta1.TableRow{ Object: runtime.RawExtension{Object: obj}, } - row.Cells = append(row.Cells, obj.Name, int64(len(obj.Secrets)), translateTimestamp(obj.CreationTimestamp)) + row.Cells = append(row.Cells, obj.Name, int64(len(obj.Secrets)), translateTimestampSince(obj.CreationTimestamp)) return []metav1beta1.TableRow{row}, nil } @@ -1162,7 +1172,7 @@ func printNode(obj *api.Node, options printers.PrintOptions) ([]metav1beta1.Tabl roles = "" } - row.Cells = append(row.Cells, obj.Name, strings.Join(status, ","), roles, translateTimestamp(obj.CreationTimestamp), obj.Status.NodeInfo.KubeletVersion) + row.Cells = append(row.Cells, obj.Name, strings.Join(status, ","), roles, translateTimestampSince(obj.CreationTimestamp), obj.Status.NodeInfo.KubeletVersion) if options.Wide { osImage, kernelVersion, crVersion := obj.Status.NodeInfo.OSImage, obj.Status.NodeInfo.KernelVersion, obj.Status.NodeInfo.ContainerRuntimeVersion if osImage == "" { @@ -1260,7 +1270,7 @@ func printPersistentVolume(obj *api.PersistentVolume, options printers.PrintOpti row.Cells = append(row.Cells, obj.Name, aSize, modesStr, reclaimPolicyStr, string(phase), claimRefUID, helper.GetPersistentVolumeClass(obj), obj.Status.Reason, - translateTimestamp(obj.CreationTimestamp)) + translateTimestampSince(obj.CreationTimestamp)) return []metav1beta1.TableRow{row}, nil } @@ -1295,7 +1305,7 @@ func printPersistentVolumeClaim(obj *api.PersistentVolumeClaim, options printers capacity = storage.String() } - row.Cells = append(row.Cells, obj.Name, string(phase), obj.Spec.VolumeName, capacity, accessModes, helper.GetPersistentVolumeClaimClass(obj), translateTimestamp(obj.CreationTimestamp)) + row.Cells = append(row.Cells, obj.Name, string(phase), obj.Spec.VolumeName, capacity, accessModes, helper.GetPersistentVolumeClaimClass(obj), translateTimestampSince(obj.CreationTimestamp)) return []metav1beta1.TableRow{row}, nil } @@ -1321,8 +1331,8 @@ func printEvent(obj *api.Event, options printers.PrintOptions) ([]metav1beta1.Ta FirstTimestamp = obj.FirstTimestamp.String() LastTimestamp = obj.LastTimestamp.String() } else { - FirstTimestamp = translateTimestamp(obj.FirstTimestamp) - LastTimestamp = translateTimestamp(obj.LastTimestamp) + FirstTimestamp = translateTimestampSince(obj.FirstTimestamp) + LastTimestamp = translateTimestampSince(obj.LastTimestamp) } row.Cells = append(row.Cells, LastTimestamp, FirstTimestamp, int64(obj.Count), obj.Name, obj.InvolvedObject.Kind, @@ -1351,7 +1361,7 @@ func printRoleBinding(obj *rbac.RoleBinding, options printers.PrintOptions) ([]m Object: runtime.RawExtension{Object: obj}, } - row.Cells = append(row.Cells, obj.Name, translateTimestamp(obj.CreationTimestamp)) + row.Cells = append(row.Cells, obj.Name, translateTimestampSince(obj.CreationTimestamp)) if options.Wide { roleRef := fmt.Sprintf("%s/%s", obj.RoleRef.Kind, obj.RoleRef.Name) users, groups, sas, _ := rbac.SubjectsStrings(obj.Subjects) @@ -1378,7 +1388,7 @@ func printClusterRoleBinding(obj *rbac.ClusterRoleBinding, options printers.Prin Object: runtime.RawExtension{Object: obj}, } - row.Cells = append(row.Cells, obj.Name, translateTimestamp(obj.CreationTimestamp)) + row.Cells = append(row.Cells, obj.Name, translateTimestampSince(obj.CreationTimestamp)) if options.Wide { roleRef := fmt.Sprintf("%s/%s", obj.RoleRef.Kind, obj.RoleRef.Name) users, groups, sas, _ := rbac.SubjectsStrings(obj.Subjects) @@ -1408,7 +1418,7 @@ func printCertificateSigningRequest(obj *certificates.CertificateSigningRequest, if err != nil { return nil, err } - row.Cells = append(row.Cells, obj.Name, translateTimestamp(obj.CreationTimestamp), obj.Spec.Username, status) + row.Cells = append(row.Cells, obj.Name, translateTimestampSince(obj.CreationTimestamp), obj.Spec.Username, status) return []metav1beta1.TableRow{row}, nil } @@ -1501,7 +1511,7 @@ func printDeployment(obj *extensions.Deployment, options printers.PrintOptions) currentReplicas := obj.Status.Replicas updatedReplicas := obj.Status.UpdatedReplicas availableReplicas := obj.Status.AvailableReplicas - age := translateTimestamp(obj.CreationTimestamp) + age := translateTimestampSince(obj.CreationTimestamp) containers := obj.Spec.Template.Spec.Containers selector, err := metav1.LabelSelectorAsSelector(obj.Spec.Selector) if err != nil { @@ -1617,7 +1627,7 @@ func printHorizontalPodAutoscaler(obj *autoscaling.HorizontalPodAutoscaler, opti } maxPods := obj.Spec.MaxReplicas currentReplicas := obj.Status.CurrentReplicas - row.Cells = append(row.Cells, obj.Name, reference, metrics, minPods, int64(maxPods), int64(currentReplicas), translateTimestamp(obj.CreationTimestamp)) + row.Cells = append(row.Cells, obj.Name, reference, metrics, minPods, int64(maxPods), int64(currentReplicas), translateTimestampSince(obj.CreationTimestamp)) return []metav1beta1.TableRow{row}, nil } @@ -1637,7 +1647,7 @@ func printConfigMap(obj *api.ConfigMap, options printers.PrintOptions) ([]metav1 row := metav1beta1.TableRow{ Object: runtime.RawExtension{Object: obj}, } - row.Cells = append(row.Cells, obj.Name, int64(len(obj.Data)), translateTimestamp(obj.CreationTimestamp)) + row.Cells = append(row.Cells, obj.Name, int64(len(obj.Data)), translateTimestampSince(obj.CreationTimestamp)) return []metav1beta1.TableRow{row}, nil } @@ -1690,7 +1700,7 @@ func printNetworkPolicy(obj *networking.NetworkPolicy, options printers.PrintOpt row := metav1beta1.TableRow{ Object: runtime.RawExtension{Object: obj}, } - row.Cells = append(row.Cells, obj.Name, metav1.FormatLabelSelector(&obj.Spec.PodSelector), translateTimestamp(obj.CreationTimestamp)) + row.Cells = append(row.Cells, obj.Name, metav1.FormatLabelSelector(&obj.Spec.PodSelector), translateTimestampSince(obj.CreationTimestamp)) return []metav1beta1.TableRow{row}, nil } @@ -1716,7 +1726,7 @@ func printStorageClass(obj *storage.StorageClass, options printers.PrintOptions) name += " (default)" } provtype := obj.Provisioner - row.Cells = append(row.Cells, name, provtype, translateTimestamp(obj.CreationTimestamp)) + row.Cells = append(row.Cells, name, provtype, translateTimestampSince(obj.CreationTimestamp)) return []metav1beta1.TableRow{row}, nil } @@ -1742,7 +1752,7 @@ func printLease(obj *coordination.Lease, options printers.PrintOptions) ([]metav if obj.Spec.HolderIdentity != nil { holderIdentity = *obj.Spec.HolderIdentity } - row.Cells = append(row.Cells, obj.Name, holderIdentity, translateTimestamp(obj.CreationTimestamp)) + row.Cells = append(row.Cells, obj.Name, holderIdentity, translateTimestampSince(obj.CreationTimestamp)) return []metav1beta1.TableRow{row}, nil } @@ -1827,7 +1837,7 @@ func printControllerRevision(obj *apps.ControllerRevision, options printers.Prin controllerName = printers.FormatResourceName(gvk.GroupKind(), controllerRef.Name, withKind) } revision := obj.Revision - age := translateTimestamp(obj.CreationTimestamp) + age := translateTimestampSince(obj.CreationTimestamp) row.Cells = append(row.Cells, obj.Name, controllerName, revision, age) return []metav1beta1.TableRow{row}, nil } diff --git a/pkg/printers/internalversion/printers_test.go b/pkg/printers/internalversion/printers_test.go index 318734d6c4e..9cf2b93030b 100644 --- a/pkg/printers/internalversion/printers_test.go +++ b/pkg/printers/internalversion/printers_test.go @@ -1919,18 +1919,43 @@ type stringTestList []struct { name, got, exp string } -func TestTranslateTimestamp(t *testing.T) { +func TestTranslateTimestampSince(t *testing.T) { tl := stringTestList{ - {"a while from now", translateTimestamp(metav1.Time{Time: time.Now().Add(2.1e9)}), ""}, - {"almost now", translateTimestamp(metav1.Time{Time: time.Now().Add(1.9e9)}), "0s"}, - {"now", translateTimestamp(metav1.Time{Time: time.Now()}), "0s"}, - {"unknown", translateTimestamp(metav1.Time{}), ""}, - {"30 seconds ago", translateTimestamp(metav1.Time{Time: time.Now().Add(-3e10)}), "30s"}, - {"5 minutes ago", translateTimestamp(metav1.Time{Time: time.Now().Add(-3e11)}), "5m"}, - {"an hour ago", translateTimestamp(metav1.Time{Time: time.Now().Add(-6e12)}), "1h"}, - {"2 days ago", translateTimestamp(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"}, - {"10 years ago", translateTimestamp(metav1.Time{Time: time.Now().UTC().AddDate(-10, 0, 0)}), "10y"}, + {"a while from now", translateTimestampSince(metav1.Time{Time: time.Now().Add(2.1e9)}), ""}, + {"almost now", translateTimestampSince(metav1.Time{Time: time.Now().Add(1.9e9)}), "0s"}, + {"now", translateTimestampSince(metav1.Time{Time: time.Now()}), "0s"}, + {"unknown", translateTimestampSince(metav1.Time{}), ""}, + {"30 seconds ago", translateTimestampSince(metav1.Time{Time: time.Now().Add(-3e10)}), "30s"}, + {"5 minutes ago", translateTimestampSince(metav1.Time{Time: time.Now().Add(-3e11)}), "5m"}, + {"an hour ago", translateTimestampSince(metav1.Time{Time: time.Now().Add(-6e12)}), "1h"}, + {"2 days ago", translateTimestampSince(metav1.Time{Time: time.Now().UTC().AddDate(0, 0, -2)}), "2d"}, + {"months ago", translateTimestampSince(metav1.Time{Time: time.Now().UTC().AddDate(0, 0, -90)}), "90d"}, + {"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)}), ""}, + {"almost now", translateTimestampUntil(metav1.Time{Time: time.Now().Add(-1.9e9)}), "0s"}, + {"now", translateTimestampUntil(metav1.Time{Time: time.Now()}), "0s"}, + {"unknown", translateTimestampUntil(metav1.Time{}), ""}, + {"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 { if test.got != test.exp {