kubectl describe: show annotations

This commit is contained in:
Chun Chen 2016-10-20 10:34:57 +08:00
parent 36a5c0091b
commit b605da2522
3 changed files with 110 additions and 5 deletions

View File

@ -243,6 +243,7 @@ func describeNamespace(namespace *api.Namespace, resourceQuotaList *api.Resource
w := &PrefixWriter{out}
w.Write(LEVEL_0, "Name:\t%s\n", namespace.Name)
printLabelsMultiline(w, "Labels", namespace.Labels)
printAnnotationsMultiline(w, "Annotations", namespace.Annotations)
w.Write(LEVEL_0, "Status:\t%s\n", string(namespace.Status.Phase))
if resourceQuotaList != nil {
w.Write(LEVEL_0, "\n")
@ -522,6 +523,7 @@ func describePod(pod *api.Pod, events *api.EventList) (string, error) {
w.Write(LEVEL_0, "Start Time:\t%s\n", pod.Status.StartTime.Time.Format(time.RFC1123Z))
}
printLabelsMultiline(w, "Labels", pod.Labels)
printAnnotationsMultiline(w, "Annotations", pod.Annotations)
if pod.DeletionTimestamp != nil {
w.Write(LEVEL_0, "Status:\tTerminating (expires %s)\n", pod.DeletionTimestamp.Time.Format(time.RFC1123Z))
w.Write(LEVEL_0, "Termination Grace Period:\t%ds\n", *pod.DeletionGracePeriodSeconds)
@ -800,6 +802,7 @@ func (d *PersistentVolumeDescriber) Describe(namespace, name string, describerSe
w := &PrefixWriter{out}
w.Write(LEVEL_0, "Name:\t%s\n", pv.Name)
printLabelsMultiline(w, "Labels", pv.Labels)
printAnnotationsMultiline(w, "Annotations", pv.Annotations)
w.Write(LEVEL_0, "StorageClass:\t%s\n", storageutil.GetStorageClassAnnotation(pv.ObjectMeta))
w.Write(LEVEL_0, "Status:\t%s\n", pv.Status.Phase)
if pv.Spec.ClaimRef != nil {
@ -879,6 +882,7 @@ func (d *PersistentVolumeClaimDescriber) Describe(namespace, name string, descri
w.Write(LEVEL_0, "Status:\t%v\n", pvc.Status.Phase)
w.Write(LEVEL_0, "Volume:\t%s\n", pvc.Spec.VolumeName)
printLabelsMultiline(w, "Labels", pvc.Labels)
printAnnotationsMultiline(w, "Annotations", pvc.Annotations)
w.Write(LEVEL_0, "Capacity:\t%s\n", capacity)
w.Write(LEVEL_0, "Access Modes:\t%s\n", accessModes)
if events != nil {
@ -1219,6 +1223,7 @@ func describeReplicationController(controller *api.ReplicationController, events
}
w.Write(LEVEL_0, "Selector:\t%s\n", labels.FormatLabels(controller.Spec.Selector))
printLabelsMultiline(w, "Labels", controller.Labels)
printAnnotationsMultiline(w, "Annotations", controller.Annotations)
w.Write(LEVEL_0, "Replicas:\t%d current / %d desired\n", controller.Status.Replicas, controller.Spec.Replicas)
w.Write(LEVEL_0, "Pods Status:\t%d Running / %d Waiting / %d Succeeded / %d Failed\n", running, waiting, succeeded, failed)
@ -1240,7 +1245,7 @@ func DescribePodTemplate(template *api.PodTemplateSpec, out io.Writer) {
}
printLabelsMultiline(w, " Labels", template.Labels)
if len(template.Annotations) > 0 {
printLabelsMultiline(w, " Annotations", template.Annotations)
printAnnotationsMultiline(w, " Annotations", template.Annotations)
}
if len(template.Spec.ServiceAccountName) > 0 {
w.Write(LEVEL_1, "Service Account:\t%s\n", template.Spec.ServiceAccountName)
@ -1289,6 +1294,7 @@ func describeReplicaSet(rs *extensions.ReplicaSet, events *api.EventList, runnin
w.Write(LEVEL_0, "Image(s):\t%s\n", makeImageList(&rs.Spec.Template.Spec))
w.Write(LEVEL_0, "Selector:\t%s\n", metav1.FormatLabelSelector(rs.Spec.Selector))
printLabelsMultiline(w, "Labels", rs.Labels)
printAnnotationsMultiline(w, "Annotations", rs.Annotations)
w.Write(LEVEL_0, "Replicas:\t%d current / %d desired\n", rs.Status.Replicas, rs.Spec.Replicas)
w.Write(LEVEL_0, "Pods Status:\t")
if getPodErr != nil {
@ -1344,6 +1350,7 @@ func describeJob(job *batch.Job, events *api.EventList) (string, error) {
w.Write(LEVEL_0, "Active Deadline Seconds:\t%ds\n", *job.Spec.ActiveDeadlineSeconds)
}
printLabelsMultiline(w, "Labels", job.Labels)
printAnnotationsMultiline(w, "Annotations", job.Annotations)
w.Write(LEVEL_0, "Pods Statuses:\t%d Running / %d Succeeded / %d Failed\n", job.Status.Active, job.Status.Succeeded, job.Status.Failed)
describeVolumes(job.Spec.Template.Spec.Volumes, w, "")
if events != nil {
@ -1387,6 +1394,7 @@ func describeCronJob(scheduledJob *batch.CronJob, events *api.EventList) (string
}
describeJobTemplate(scheduledJob.Spec.JobTemplate, w)
printLabelsMultiline(w, "Labels", scheduledJob.Labels)
printAnnotationsMultiline(w, "Annotations", scheduledJob.Annotations)
if scheduledJob.Status.LastScheduleTime != nil {
w.Write(LEVEL_0, "Last Schedule Time:\t%s\n", scheduledJob.Status.LastScheduleTime.Time.Format(time.RFC1123Z))
} else {
@ -1484,6 +1492,7 @@ func describeDaemonSet(daemon *extensions.DaemonSet, events *api.EventList, runn
w.Write(LEVEL_0, "Selector:\t%s\n", selector)
w.Write(LEVEL_0, "Node-Selector:\t%s\n", labels.FormatLabels(daemon.Spec.Template.Spec.NodeSelector))
printLabelsMultiline(w, "Labels", daemon.Labels)
printAnnotationsMultiline(w, "Annotations", daemon.Annotations)
w.Write(LEVEL_0, "Desired Number of Nodes Scheduled: %d\n", daemon.Status.DesiredNumberScheduled)
w.Write(LEVEL_0, "Current Number of Nodes Scheduled: %d\n", daemon.Status.CurrentNumberScheduled)
w.Write(LEVEL_0, "Number of Nodes Misscheduled: %d\n", daemon.Status.NumberMisscheduled)
@ -1518,7 +1527,7 @@ func describeSecret(secret *api.Secret) (string, error) {
w.Write(LEVEL_0, "Namespace:\t%s\n", secret.Namespace)
printLabelsMultiline(w, "Labels", secret.Labels)
skipAnnotations := sets.NewString(annotations.LastAppliedConfigAnnotation)
printLabelsMultilineWithFilter(w, "Annotations", secret.Annotations, skipAnnotations)
printAnnotationsMultilineWithFilter(w, "Annotations", secret.Annotations, skipAnnotations)
w.Write(LEVEL_0, "\nType:\t%s\n", secret.Type)
@ -1694,6 +1703,7 @@ func describeService(service *api.Service, endpoints *api.Endpoints, events *api
w.Write(LEVEL_0, "Name:\t%s\n", service.Name)
w.Write(LEVEL_0, "Namespace:\t%s\n", service.Namespace)
printLabelsMultiline(w, "Labels", service.Labels)
printAnnotationsMultiline(w, "Annotations", service.Annotations)
w.Write(LEVEL_0, "Selector:\t%s\n", labels.FormatLabels(service.Spec.Selector))
w.Write(LEVEL_0, "Type:\t%s\n", service.Spec.Type)
w.Write(LEVEL_0, "IP:\t%s\n", service.Spec.ClusterIP)
@ -1755,6 +1765,7 @@ func describeEndpoints(ep *api.Endpoints, events *api.EventList) (string, error)
w.Write(LEVEL_0, "Name:\t%s\n", ep.Name)
w.Write(LEVEL_0, "Namespace:\t%s\n", ep.Namespace)
printLabelsMultiline(w, "Labels", ep.Labels)
printAnnotationsMultiline(w, "Annotations", ep.Annotations)
w.Write(LEVEL_0, "Subsets:\n")
for i := range ep.Subsets {
@ -1861,6 +1872,7 @@ func describeServiceAccount(serviceAccount *api.ServiceAccount, tokens []api.Sec
w.Write(LEVEL_0, "Name:\t%s\n", serviceAccount.Name)
w.Write(LEVEL_0, "Namespace:\t%s\n", serviceAccount.Namespace)
printLabelsMultiline(w, "Labels", serviceAccount.Labels)
printAnnotationsMultiline(w, "Annotations", serviceAccount.Annotations)
w.WriteLine()
var (
@ -1957,6 +1969,7 @@ func describeNode(node *api.Node, nodeNonTerminatedPodsList *api.PodList, events
w.Write(LEVEL_0, "Name:\t%s\n", node.Name)
w.Write(LEVEL_0, "Role:\t%s\n", findNodeRole(node))
printLabelsMultiline(w, "Labels", node.Labels)
printAnnotationsMultiline(w, "Annotations", node.Annotations)
printNodeTaintsMultiline(w, "Taints", node.Spec.Taints)
w.Write(LEVEL_0, "CreationTimestamp:\t%s\n", node.CreationTimestamp.Time.Format(time.RFC1123Z))
w.Write(LEVEL_0, "Phase:\t%v\n", node.Status.Phase)
@ -2159,7 +2172,7 @@ func (d *HorizontalPodAutoscalerDescriber) Describe(namespace, name string, desc
w.Write(LEVEL_0, "Name:\t%s\n", hpa.Name)
w.Write(LEVEL_0, "Namespace:\t%s\n", hpa.Namespace)
printLabelsMultiline(w, "Labels", hpa.Labels)
printLabelsMultiline(w, "Annotations", hpa.Annotations)
printAnnotationsMultiline(w, "Annotations", hpa.Annotations)
w.Write(LEVEL_0, "CreationTimestamp:\t%s\n", hpa.CreationTimestamp.Time.Format(time.RFC1123Z))
w.Write(LEVEL_0, "Reference:\t%s/%s\n",
hpa.Spec.ScaleTargetRef.Kind,
@ -2355,6 +2368,7 @@ func (dd *DeploymentDescriber) Describe(namespace, name string, describerSetting
w.Write(LEVEL_0, "Namespace:\t%s\n", d.ObjectMeta.Namespace)
w.Write(LEVEL_0, "CreationTimestamp:\t%s\n", d.CreationTimestamp.Time.Format(time.RFC1123Z))
printLabelsMultiline(w, "Labels", d.Labels)
printAnnotationsMultiline(w, "Annotations", d.Annotations)
w.Write(LEVEL_0, "Selector:\t%s\n", selector)
w.Write(LEVEL_0, "Replicas:\t%d desired | %d updated | %d total | %d available | %d unavailable\n", *(d.Spec.Replicas), d.Status.UpdatedReplicas, d.Status.Replicas, d.Status.AvailableReplicas, d.Status.UnavailableReplicas)
w.Write(LEVEL_0, "StrategyType:\t%s\n", d.Spec.Strategy.Type)
@ -2492,7 +2506,7 @@ func describeConfigMap(configMap *api.ConfigMap) (string, error) {
w.Write(LEVEL_0, "Name:\t%s\n", configMap.Name)
w.Write(LEVEL_0, "Namespace:\t%s\n", configMap.Namespace)
printLabelsMultiline(w, "Labels", configMap.Labels)
printLabelsMultiline(w, "Annotations", configMap.Annotations)
printAnnotationsMultiline(w, "Annotations", configMap.Annotations)
w.Write(LEVEL_0, "\nData\n====\n")
for k, v := range configMap.Data {
@ -2567,7 +2581,7 @@ func describeNetworkPolicy(networkPolicy *extensions.NetworkPolicy) (string, err
w.Write(LEVEL_0, "Name:\t%s\n", networkPolicy.Name)
w.Write(LEVEL_0, "Namespace:\t%s\n", networkPolicy.Namespace)
printLabelsMultiline(w, "Labels", networkPolicy.Labels)
printLabelsMultiline(w, "Annotations", networkPolicy.Annotations)
printAnnotationsMultiline(w, "Annotations", networkPolicy.Annotations)
return nil
})
@ -2998,3 +3012,55 @@ func versionedClientsetForDeployment(internalClient clientset.Interface) version
ExtensionsV1beta1Client: extensionsclientset.New(internalClient.Extensions().RESTClient()),
}
}
var maxAnnotationLen = 200
// printAnnotationsMultilineWithFilter prints filtered multiple annotations with a proper alignment.
func printAnnotationsMultilineWithFilter(w *PrefixWriter, title string, annotations map[string]string, skip sets.String) {
printAnnotationsMultilineWithIndent(w, "", title, "\t", annotations, skip)
}
// printAnnotationsMultiline prints multiple annotations with a proper alignment.
func printAnnotationsMultiline(w *PrefixWriter, title string, annotations map[string]string) {
printAnnotationsMultilineWithIndent(w, "", title, "\t", annotations, sets.NewString())
}
// printAnnotationsMultilineWithIndent prints multiple annotations with a user-defined alignment.
// If annotation string is too long, we omit chars more than 200 length.
func printAnnotationsMultilineWithIndent(w *PrefixWriter, initialIndent, title, innerIndent string, annotations map[string]string, skip sets.String) {
w.Write(LEVEL_0, "%s%s:%s", initialIndent, title, innerIndent)
if len(annotations) == 0 {
w.WriteLine("<none>")
return
}
// to print labels in the sorted order
keys := make([]string, 0, len(annotations))
for key := range annotations {
if skip.Has(key) {
continue
}
keys = append(keys, key)
}
if len(annotations) == 0 {
w.WriteLine("<none>")
return
}
sort.Strings(keys)
for i, key := range keys {
if i != 0 {
w.Write(LEVEL_0, initialIndent)
w.Write(LEVEL_0, innerIndent)
}
line := fmt.Sprintf("%s=%s", key, annotations[key])
if len(line) > maxAnnotationLen {
w.Write(LEVEL_0, "%s...\n", line[:maxAnnotationLen])
} else {
w.Write(LEVEL_0, "%s\n", line)
}
i++
}
}

View File

@ -1265,3 +1265,37 @@ func TestDescribeEvents(t *testing.T) {
}
}
}
func TestPrintLabelsMultiline(t *testing.T) {
var maxLenAnnotationStr string = "MaxLenAnnotation=Multicast addressing can be used in the link layer (Layer 2 in the OSI model), such as Ethernet multicast, and at the internet layer (Layer 3 for OSI) for Internet Protocol Version 4 "
testCases := []struct {
annotations map[string]string
expectPrint string
}{
{
annotations: map[string]string{"col1": "asd", "COL2": "zxc"},
expectPrint: "Annotations:\tCOL2=zxc\n\tcol1=asd\n",
},
{
annotations: map[string]string{"MaxLenAnnotation": maxLenAnnotationStr[17:]},
expectPrint: "Annotations:\t" + maxLenAnnotationStr + "\n",
},
{
annotations: map[string]string{"MaxLenAnnotation": maxLenAnnotationStr[17:] + "1"},
expectPrint: "Annotations:\t" + maxLenAnnotationStr + "...\n",
},
{
annotations: map[string]string{},
expectPrint: "Annotations:\t<none>\n",
},
}
for i, testCase := range testCases {
out := new(bytes.Buffer)
writer := &PrefixWriter{out}
printAnnotationsMultiline(writer, "Annotations", testCase.annotations)
output := out.String()
if output != testCase.expectPrint {
t.Errorf("Test case %d: expected to find %q in output: %q", i, testCase.expectPrint, output)
}
}
}

View File

@ -718,6 +718,7 @@ var _ = framework.KubeDescribe("Kubectl client", func() {
{"Node:"},
{"Labels:", "app=redis"},
{"role=master"},
{"Annotations:"},
{"Status:", "Running"},
{"IP:"},
{"Controllers:", "ReplicationController/redis-master"},
@ -737,6 +738,7 @@ var _ = framework.KubeDescribe("Kubectl client", func() {
{"Selector:", "app=redis,role=master"},
{"Labels:", "app=redis"},
{"role=master"},
{"Annotations:"},
{"Replicas:", "1 current", "1 desired"},
{"Pods Status:", "1 Running", "0 Waiting", "0 Succeeded", "0 Failed"},
// {"Events:"} would ordinarily go in the list
@ -754,6 +756,7 @@ var _ = framework.KubeDescribe("Kubectl client", func() {
{"Namespace:", ns},
{"Labels:", "app=redis"},
{"role=master"},
{"Annotations:"},
{"Selector:", "app=redis", "role=master"},
{"Type:", "ClusterIP"},
{"IP:"},
@ -771,6 +774,7 @@ var _ = framework.KubeDescribe("Kubectl client", func() {
requiredStrings = [][]string{
{"Name:", node.Name},
{"Labels:"},
{"Annotations:"},
{"CreationTimestamp:"},
{"Conditions:"},
{"Type", "Status", "LastHeartbeatTime", "LastTransitionTime", "Reason", "Message"},
@ -790,6 +794,7 @@ var _ = framework.KubeDescribe("Kubectl client", func() {
requiredStrings = [][]string{
{"Name:", ns},
{"Labels:"},
{"Annotations:"},
{"Status:", "Active"}}
checkOutput(output, requiredStrings)