Merge pull request #48022 from smarterclayton/more_printers

Automatic merge from submit-queue (batch tested with PRs 48036, 48022)

Move more printers to TablePrinter

Continues work from 1.7
This commit is contained in:
Kubernetes Submit Queue 2017-06-26 12:52:45 -07:00 committed by GitHub
commit 53a5ee7929
4 changed files with 259 additions and 275 deletions

View File

@ -257,8 +257,8 @@ func Example_printMultiContainersReplicationControllerWithWide() {
fmt.Printf("Unexpected error: %v", err)
}
// Output:
// NAME DESIRED CURRENT READY AGE CONTAINER(S) IMAGE(S) SELECTOR
// foo 1 1 0 10y foo,foo2 someimage,someimage2 foo=bar
// NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
// foo 1 1 0 10y foo,foo2 someimage,someimage2 foo=bar
}
func Example_printReplicationController() {

View File

@ -93,6 +93,8 @@ go_library(
"//pkg/util/slice:go_default_library",
"//vendor/github.com/fatih/camelcase:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/api/batch/v1:go_default_library",
"//vendor/k8s.io/api/batch/v2alpha1:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",

View File

@ -26,7 +26,10 @@ import (
"strings"
"time"
batchv1 "k8s.io/api/batch/v1"
batchv2alpha1 "k8s.io/api/batch/v2alpha1"
apiv1 "k8s.io/api/core/v1"
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metav1alpha1 "k8s.io/apimachinery/pkg/apis/meta/v1alpha1"
"k8s.io/apimachinery/pkg/labels"
@ -58,42 +61,33 @@ const loadBalancerWidth = 16
// NOTE: When adding a new resource type here, please update the list
// pkg/kubectl/cmd/get.go to reflect the new resource type.
var (
podTemplateColumns = []string{"TEMPLATE", "CONTAINER(S)", "IMAGE(S)", "PODLABELS"}
podDisruptionBudgetColumns = []string{"NAME", "MIN-AVAILABLE", "MAX-UNAVAILABLE", "ALLOWED-DISRUPTIONS", "AGE"}
replicationControllerColumns = []string{"NAME", "DESIRED", "CURRENT", "READY", "AGE"}
replicationControllerWideColumns = []string{"CONTAINER(S)", "IMAGE(S)", "SELECTOR"}
replicaSetColumns = []string{"NAME", "DESIRED", "CURRENT", "READY", "AGE"}
replicaSetWideColumns = []string{"CONTAINER(S)", "IMAGE(S)", "SELECTOR"}
jobColumns = []string{"NAME", "DESIRED", "SUCCESSFUL", "AGE"}
cronJobColumns = []string{"NAME", "SCHEDULE", "SUSPEND", "ACTIVE", "LAST-SCHEDULE"}
batchJobWideColumns = []string{"CONTAINER(S)", "IMAGE(S)", "SELECTOR"}
serviceColumns = []string{"NAME", "TYPE", "CLUSTER-IP", "EXTERNAL-IP", "PORT(S)", "AGE"}
serviceWideColumns = []string{"SELECTOR"}
ingressColumns = []string{"NAME", "HOSTS", "ADDRESS", "PORTS", "AGE"}
statefulSetColumns = []string{"NAME", "DESIRED", "CURRENT", "AGE"}
endpointColumns = []string{"NAME", "ENDPOINTS", "AGE"}
nodeColumns = []string{"NAME", "STATUS", "AGE", "VERSION"}
nodeWideColumns = []string{"EXTERNAL-IP", "OS-IMAGE", "KERNEL-VERSION", "CONTAINER-RUNTIME"}
daemonSetColumns = []string{"NAME", "DESIRED", "CURRENT", "READY", "UP-TO-DATE", "AVAILABLE", "NODE-SELECTOR", "AGE"}
daemonSetWideColumns = []string{"CONTAINER(S)", "IMAGE(S)", "SELECTOR"}
eventColumns = []string{"LASTSEEN", "FIRSTSEEN", "COUNT", "NAME", "KIND", "SUBOBJECT", "TYPE", "REASON", "SOURCE", "MESSAGE"}
limitRangeColumns = []string{"NAME", "AGE"}
resourceQuotaColumns = []string{"NAME", "AGE"}
namespaceColumns = []string{"NAME", "STATUS", "AGE"}
secretColumns = []string{"NAME", "TYPE", "DATA", "AGE"}
serviceAccountColumns = []string{"NAME", "SECRETS", "AGE"}
persistentVolumeColumns = []string{"NAME", "CAPACITY", "ACCESSMODES", "RECLAIMPOLICY", "STATUS", "CLAIM", "STORAGECLASS", "REASON", "AGE"}
persistentVolumeClaimColumns = []string{"NAME", "STATUS", "VOLUME", "CAPACITY", "ACCESSMODES", "STORAGECLASS", "AGE"}
componentStatusColumns = []string{"NAME", "STATUS", "MESSAGE", "ERROR"}
thirdPartyResourceColumns = []string{"NAME", "DESCRIPTION", "VERSION(S)"}
roleColumns = []string{"NAME", "AGE"}
roleBindingColumns = []string{"NAME", "AGE"}
roleBindingWideColumns = []string{"ROLE", "USERS", "GROUPS", "SERVICEACCOUNTS"}
clusterRoleColumns = []string{"NAME", "AGE"}
clusterRoleBindingColumns = []string{"NAME", "AGE"}
clusterRoleBindingWideColumns = []string{"ROLE", "USERS", "GROUPS", "SERVICEACCOUNTS"}
storageClassColumns = []string{"NAME", "PROVISIONER"}
statusColumns = []string{"STATUS", "REASON", "MESSAGE"}
serviceColumns = []string{"NAME", "TYPE", "CLUSTER-IP", "EXTERNAL-IP", "PORT(S)", "AGE"}
serviceWideColumns = []string{"SELECTOR"}
ingressColumns = []string{"NAME", "HOSTS", "ADDRESS", "PORTS", "AGE"}
statefulSetColumns = []string{"NAME", "DESIRED", "CURRENT", "AGE"}
endpointColumns = []string{"NAME", "ENDPOINTS", "AGE"}
nodeColumns = []string{"NAME", "STATUS", "AGE", "VERSION"}
nodeWideColumns = []string{"EXTERNAL-IP", "OS-IMAGE", "KERNEL-VERSION", "CONTAINER-RUNTIME"}
daemonSetColumns = []string{"NAME", "DESIRED", "CURRENT", "READY", "UP-TO-DATE", "AVAILABLE", "NODE-SELECTOR", "AGE"}
daemonSetWideColumns = []string{"CONTAINER(S)", "IMAGE(S)", "SELECTOR"}
eventColumns = []string{"LASTSEEN", "FIRSTSEEN", "COUNT", "NAME", "KIND", "SUBOBJECT", "TYPE", "REASON", "SOURCE", "MESSAGE"}
limitRangeColumns = []string{"NAME", "AGE"}
resourceQuotaColumns = []string{"NAME", "AGE"}
namespaceColumns = []string{"NAME", "STATUS", "AGE"}
secretColumns = []string{"NAME", "TYPE", "DATA", "AGE"}
serviceAccountColumns = []string{"NAME", "SECRETS", "AGE"}
persistentVolumeColumns = []string{"NAME", "CAPACITY", "ACCESSMODES", "RECLAIMPOLICY", "STATUS", "CLAIM", "STORAGECLASS", "REASON", "AGE"}
persistentVolumeClaimColumns = []string{"NAME", "STATUS", "VOLUME", "CAPACITY", "ACCESSMODES", "STORAGECLASS", "AGE"}
componentStatusColumns = []string{"NAME", "STATUS", "MESSAGE", "ERROR"}
thirdPartyResourceColumns = []string{"NAME", "DESCRIPTION", "VERSION(S)"}
roleColumns = []string{"NAME", "AGE"}
roleBindingColumns = []string{"NAME", "AGE"}
roleBindingWideColumns = []string{"ROLE", "USERS", "GROUPS", "SERVICEACCOUNTS"}
clusterRoleColumns = []string{"NAME", "AGE"}
clusterRoleBindingColumns = []string{"NAME", "AGE"}
clusterRoleBindingWideColumns = []string{"ROLE", "USERS", "GROUPS", "SERVICEACCOUNTS"}
storageClassColumns = []string{"NAME", "PROVISIONER"}
statusColumns = []string{"STATUS", "REASON", "MESSAGE"}
// TODO: consider having 'KIND' for third party resource data
thirdPartyResourceDataColumns = []string{"NAME", "LABELS", "DATA"}
@ -124,20 +118,80 @@ func AddHandlers(h printers.PrintHandler) {
h.TableHandler(podColumnDefinitions, printPodList)
h.TableHandler(podColumnDefinitions, printPod)
h.Handler(podTemplateColumns, nil, printPodTemplate)
h.Handler(podTemplateColumns, nil, printPodTemplateList)
h.Handler(podDisruptionBudgetColumns, nil, printPodDisruptionBudget)
h.Handler(podDisruptionBudgetColumns, nil, printPodDisruptionBudgetList)
h.Handler(replicationControllerColumns, replicationControllerWideColumns, printReplicationController)
h.Handler(replicationControllerColumns, replicationControllerWideColumns, printReplicationControllerList)
h.Handler(replicaSetColumns, replicaSetWideColumns, printReplicaSet)
h.Handler(replicaSetColumns, replicaSetWideColumns, printReplicaSetList)
podTemplateColumnDefinitions := []metav1alpha1.TableColumnDefinition{
{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
{Name: "Containers", Type: "string", Description: "Names of each container in the template."},
{Name: "Images", Type: "string", Description: "Images referenced by each container in the template."},
{Name: "Pod Labels", Type: "string", Description: "The labels for the pod template."},
}
h.TableHandler(podTemplateColumnDefinitions, printPodTemplate)
h.TableHandler(podTemplateColumnDefinitions, printPodTemplateList)
podDisruptionBudgetColumnDefinitions := []metav1alpha1.TableColumnDefinition{
{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
{Name: "Min Available", Type: "string", Description: "The minimum number of pods that must be available."},
{Name: "Max Unavailable", Type: "string", Description: "The maximum number of pods that may be unavailable."},
{Name: "Allowed Disruptions", Type: "integer", Description: "Calculated number of pods that may be disrupted at this time."},
{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
}
h.TableHandler(podDisruptionBudgetColumnDefinitions, printPodDisruptionBudget)
h.TableHandler(podDisruptionBudgetColumnDefinitions, printPodDisruptionBudgetList)
replicationControllerColumnDefinitions := []metav1alpha1.TableColumnDefinition{
{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
{Name: "Desired", Type: "integer", Description: apiv1.ReplicationControllerSpec{}.SwaggerDoc()["replicas"]},
{Name: "Current", Type: "integer", Description: apiv1.ReplicationControllerStatus{}.SwaggerDoc()["replicas"]},
{Name: "Ready", Type: "integer", Description: apiv1.ReplicationControllerStatus{}.SwaggerDoc()["readyReplicas"]},
{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
{Name: "Containers", Type: "string", Priority: 1, Description: "Names of each container in the template."},
{Name: "Images", Type: "string", Priority: 1, Description: "Images referenced by each container in the template."},
{Name: "Selector", Type: "string", Priority: 1, Description: apiv1.ReplicationControllerSpec{}.SwaggerDoc()["selector"]},
}
h.TableHandler(replicationControllerColumnDefinitions, printReplicationController)
h.TableHandler(replicationControllerColumnDefinitions, printReplicationControllerList)
replicaSetColumnDefinitions := []metav1alpha1.TableColumnDefinition{
{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
{Name: "Desired", Type: "integer", Description: extensionsv1beta1.ReplicaSetSpec{}.SwaggerDoc()["replicas"]},
{Name: "Current", Type: "integer", Description: extensionsv1beta1.ReplicaSetStatus{}.SwaggerDoc()["replicas"]},
{Name: "Ready", Type: "integer", Description: extensionsv1beta1.ReplicaSetStatus{}.SwaggerDoc()["readyReplicas"]},
{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
{Name: "Containers", Type: "string", Priority: 1, Description: "Names of each container in the template."},
{Name: "Images", Type: "string", Priority: 1, Description: "Images referenced by each container in the template."},
{Name: "Selector", Type: "string", Priority: 1, Description: extensionsv1beta1.ReplicaSetSpec{}.SwaggerDoc()["selector"]},
}
h.TableHandler(replicaSetColumnDefinitions, printReplicaSet)
h.TableHandler(replicaSetColumnDefinitions, printReplicaSetList)
h.Handler(daemonSetColumns, daemonSetWideColumns, printDaemonSet)
h.Handler(daemonSetColumns, daemonSetWideColumns, printDaemonSetList)
h.Handler(jobColumns, batchJobWideColumns, printJob)
h.Handler(jobColumns, batchJobWideColumns, printJobList)
h.Handler(cronJobColumns, batchJobWideColumns, printCronJob)
h.Handler(cronJobColumns, batchJobWideColumns, printCronJobList)
jobColumnDefinitions := []metav1alpha1.TableColumnDefinition{
{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
{Name: "Desired", Type: "integer", Description: batchv1.JobSpec{}.SwaggerDoc()["completions"]},
{Name: "Successful", Type: "integer", Description: batchv1.JobStatus{}.SwaggerDoc()["succeeded"]},
{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
{Name: "Containers", Type: "string", Priority: 1, Description: "Names of each container in the template."},
{Name: "Images", Type: "string", Priority: 1, Description: "Images referenced by each container in the template."},
{Name: "Selector", Type: "string", Priority: 1, Description: batchv1.JobSpec{}.SwaggerDoc()["selector"]},
}
h.TableHandler(jobColumnDefinitions, printJob)
h.TableHandler(jobColumnDefinitions, printJobList)
cronJobColumnDefinitions := []metav1alpha1.TableColumnDefinition{
{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
{Name: "Schedule", Type: "string", Description: batchv2alpha1.CronJobSpec{}.SwaggerDoc()["schedule"]},
{Name: "Suspend", Type: "boolean", Description: batchv2alpha1.CronJobSpec{}.SwaggerDoc()["suspend"]},
{Name: "Active", Type: "integer", Description: batchv2alpha1.CronJobStatus{}.SwaggerDoc()["active"]},
{Name: "Last Schedule", Type: "string", Description: batchv2alpha1.CronJobStatus{}.SwaggerDoc()["lastScheduleTime"]},
{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
{Name: "Containers", Type: "string", Priority: 1, Description: "Names of each container in the template."},
{Name: "Images", Type: "string", Priority: 1, Description: "Images referenced by each container in the template."},
{Name: "Selector", Type: "string", Priority: 1, Description: batchv1.JobSpec{}.SwaggerDoc()["selector"]},
}
h.TableHandler(cronJobColumnDefinitions, printCronJob)
h.TableHandler(cronJobColumnDefinitions, printCronJobList)
h.Handler(serviceColumns, serviceWideColumns, printService)
h.Handler(serviceColumns, serviceWideColumns, printServiceList)
h.Handler(ingressColumns, nil, printIngress)
@ -358,195 +412,119 @@ func printPod(pod *api.Pod, options printers.PrintOptions) ([]metav1alpha1.Table
return []metav1alpha1.TableRow{row}, nil
}
func printPodTemplate(pod *api.PodTemplate, w io.Writer, options printers.PrintOptions) error {
name := printers.FormatResourceName(options.Kind, pod.Name, options.WithKind)
namespace := pod.Namespace
containers := pod.Template.Spec.Containers
if options.WithNamespace {
if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
return err
}
func printPodTemplate(obj *api.PodTemplate, options printers.PrintOptions) ([]metav1alpha1.TableRow, error) {
row := metav1alpha1.TableRow{
Object: runtime.RawExtension{Object: obj},
}
if _, err := fmt.Fprintf(w, "%s", name); err != nil {
return err
}
if err := layoutContainers(containers, w); err != nil {
return err
}
if _, err := fmt.Fprintf(w, "\t%s", labels.FormatLabels(pod.Template.Labels)); err != nil {
return err
}
if _, err := fmt.Fprint(w, printers.AppendLabels(pod.Labels, options.ColumnLabels)); err != nil {
return err
}
if _, err := fmt.Fprint(w, printers.AppendAllLabels(options.ShowLabels, pod.Labels)); err != nil {
return err
}
return nil
names, images := layoutContainerCells(obj.Template.Spec.Containers)
row.Cells = append(row.Cells, obj.Name, names, images, labels.FormatLabels(obj.Template.Labels))
return []metav1alpha1.TableRow{row}, nil
}
func printPodTemplateList(podList *api.PodTemplateList, w io.Writer, options printers.PrintOptions) error {
for _, pod := range podList.Items {
if err := printPodTemplate(&pod, w, options); err != nil {
return err
func printPodTemplateList(list *api.PodTemplateList, options printers.PrintOptions) ([]metav1alpha1.TableRow, error) {
rows := make([]metav1alpha1.TableRow, 0, len(list.Items))
for i := range list.Items {
r, err := printPodTemplate(&list.Items[i], options)
if err != nil {
return nil, err
}
rows = append(rows, r...)
}
return nil
return rows, nil
}
func printPodDisruptionBudget(pdb *policy.PodDisruptionBudget, w io.Writer, options printers.PrintOptions) error {
// name, minavailable, maxUnavailable, selector
name := printers.FormatResourceName(options.Kind, pdb.Name, options.WithKind)
namespace := pdb.Namespace
if options.WithNamespace {
if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
return err
}
func printPodDisruptionBudget(obj *policy.PodDisruptionBudget, options printers.PrintOptions) ([]metav1alpha1.TableRow, error) {
row := metav1alpha1.TableRow{
Object: runtime.RawExtension{Object: obj},
}
var minAvailable string
var maxUnavailable string
if pdb.Spec.MinAvailable != nil {
minAvailable = pdb.Spec.MinAvailable.String()
if obj.Spec.MinAvailable != nil {
minAvailable = obj.Spec.MinAvailable.String()
} else {
minAvailable = "N/A"
}
if pdb.Spec.MaxUnavailable != nil {
maxUnavailable = pdb.Spec.MaxUnavailable.String()
if obj.Spec.MaxUnavailable != nil {
maxUnavailable = obj.Spec.MaxUnavailable.String()
} else {
maxUnavailable = "N/A"
}
if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%d\t%s\n",
name,
minAvailable,
maxUnavailable,
pdb.Status.PodDisruptionsAllowed,
translateTimestamp(pdb.CreationTimestamp),
); err != nil {
return err
}
return nil
row.Cells = append(row.Cells, obj.Name, minAvailable, maxUnavailable, obj.Status.PodDisruptionsAllowed, translateTimestamp(obj.CreationTimestamp))
return []metav1alpha1.TableRow{row}, nil
}
func printPodDisruptionBudgetList(pdbList *policy.PodDisruptionBudgetList, w io.Writer, options printers.PrintOptions) error {
for _, pdb := range pdbList.Items {
if err := printPodDisruptionBudget(&pdb, w, options); err != nil {
return err
func printPodDisruptionBudgetList(list *policy.PodDisruptionBudgetList, options printers.PrintOptions) ([]metav1alpha1.TableRow, error) {
rows := make([]metav1alpha1.TableRow, 0, len(list.Items))
for i := range list.Items {
r, err := printPodDisruptionBudget(&list.Items[i], options)
if err != nil {
return nil, err
}
rows = append(rows, r...)
}
return nil
return rows, nil
}
// TODO(AdoHe): try to put wide output in a single method
func printReplicationController(controller *api.ReplicationController, w io.Writer, options printers.PrintOptions) error {
name := printers.FormatResourceName(options.Kind, controller.Name, options.WithKind)
namespace := controller.Namespace
containers := controller.Spec.Template.Spec.Containers
if options.WithNamespace {
if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
return err
}
func printReplicationController(obj *api.ReplicationController, options printers.PrintOptions) ([]metav1alpha1.TableRow, error) {
row := metav1alpha1.TableRow{
Object: runtime.RawExtension{Object: obj},
}
desiredReplicas := controller.Spec.Replicas
currentReplicas := controller.Status.Replicas
readyReplicas := controller.Status.ReadyReplicas
if _, err := fmt.Fprintf(w, "%s\t%d\t%d\t%d\t%s",
name,
desiredReplicas,
currentReplicas,
readyReplicas,
translateTimestamp(controller.CreationTimestamp),
); err != nil {
return err
}
desiredReplicas := obj.Spec.Replicas
currentReplicas := obj.Status.Replicas
readyReplicas := obj.Status.ReadyReplicas
row.Cells = append(row.Cells, obj.Name, desiredReplicas, currentReplicas, readyReplicas, translateTimestamp(obj.CreationTimestamp))
if options.Wide {
if err := layoutContainers(containers, w); err != nil {
return err
}
if _, err := fmt.Fprintf(w, "\t%s", labels.FormatLabels(controller.Spec.Selector)); err != nil {
return err
}
names, images := layoutContainerCells(obj.Spec.Template.Spec.Containers)
row.Cells = append(row.Cells, names, images, labels.FormatLabels(obj.Spec.Selector))
}
if _, err := fmt.Fprint(w, printers.AppendLabels(controller.Labels, options.ColumnLabels)); err != nil {
return err
}
if _, err := fmt.Fprint(w, printers.AppendAllLabels(options.ShowLabels, controller.Labels)); err != nil {
return err
}
return nil
return []metav1alpha1.TableRow{row}, nil
}
func printReplicationControllerList(list *api.ReplicationControllerList, w io.Writer, options printers.PrintOptions) error {
for _, controller := range list.Items {
if err := printReplicationController(&controller, w, options); err != nil {
return err
func printReplicationControllerList(list *api.ReplicationControllerList, options printers.PrintOptions) ([]metav1alpha1.TableRow, error) {
rows := make([]metav1alpha1.TableRow, 0, len(list.Items))
for i := range list.Items {
r, err := printReplicationController(&list.Items[i], options)
if err != nil {
return nil, err
}
rows = append(rows, r...)
}
return nil
return rows, nil
}
func printReplicaSet(rs *extensions.ReplicaSet, w io.Writer, options printers.PrintOptions) error {
name := printers.FormatResourceName(options.Kind, rs.Name, options.WithKind)
namespace := rs.Namespace
containers := rs.Spec.Template.Spec.Containers
if options.WithNamespace {
if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
return err
}
func printReplicaSet(obj *extensions.ReplicaSet, options printers.PrintOptions) ([]metav1alpha1.TableRow, error) {
row := metav1alpha1.TableRow{
Object: runtime.RawExtension{Object: obj},
}
desiredReplicas := rs.Spec.Replicas
currentReplicas := rs.Status.Replicas
readyReplicas := rs.Status.ReadyReplicas
if _, err := fmt.Fprintf(w, "%s\t%d\t%d\t%d\t%s",
name,
desiredReplicas,
currentReplicas,
readyReplicas,
translateTimestamp(rs.CreationTimestamp),
); err != nil {
return err
}
desiredReplicas := obj.Spec.Replicas
currentReplicas := obj.Status.Replicas
readyReplicas := obj.Status.ReadyReplicas
row.Cells = append(row.Cells, obj.Name, desiredReplicas, currentReplicas, readyReplicas, translateTimestamp(obj.CreationTimestamp))
if options.Wide {
if err := layoutContainers(containers, w); err != nil {
return err
}
if _, err := fmt.Fprintf(w, "\t%s", metav1.FormatLabelSelector(rs.Spec.Selector)); err != nil {
return err
}
names, images := layoutContainerCells(obj.Spec.Template.Spec.Containers)
row.Cells = append(row.Cells, names, images, metav1.FormatLabelSelector(obj.Spec.Selector))
}
if _, err := fmt.Fprint(w, printers.AppendLabels(rs.Labels, options.ColumnLabels)); err != nil {
return err
}
if _, err := fmt.Fprint(w, printers.AppendAllLabels(options.ShowLabels, rs.Labels)); err != nil {
return err
}
return nil
return []metav1alpha1.TableRow{row}, nil
}
func printReplicaSetList(list *extensions.ReplicaSetList, w io.Writer, options printers.PrintOptions) error {
for _, rs := range list.Items {
if err := printReplicaSet(&rs, w, options); err != nil {
return err
func printReplicaSetList(list *extensions.ReplicaSetList, options printers.PrintOptions) ([]metav1alpha1.TableRow, error) {
rows := make([]metav1alpha1.TableRow, 0, len(list.Items))
for i := range list.Items {
r, err := printReplicaSet(&list.Items[i], options)
if err != nil {
return nil, err
}
rows = append(rows, r...)
}
return nil
return rows, nil
}
func printCluster(c *federation.Cluster, w io.Writer, options printers.PrintOptions) error {
@ -582,103 +560,66 @@ func printClusterList(list *federation.ClusterList, w io.Writer, options printer
return nil
}
func printJob(job *batch.Job, w io.Writer, options printers.PrintOptions) error {
name := printers.FormatResourceName(options.Kind, job.Name, options.WithKind)
namespace := job.Namespace
containers := job.Spec.Template.Spec.Containers
if options.WithNamespace {
if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
return err
}
func printJob(obj *batch.Job, options printers.PrintOptions) ([]metav1alpha1.TableRow, error) {
row := metav1alpha1.TableRow{
Object: runtime.RawExtension{Object: obj},
}
selector, err := metav1.LabelSelectorAsSelector(job.Spec.Selector)
if err != nil {
// this shouldn't happen if LabelSelector passed validation
return err
}
if job.Spec.Completions != nil {
if _, err := fmt.Fprintf(w, "%s\t%d\t%d\t%s",
name,
*job.Spec.Completions,
job.Status.Succeeded,
translateTimestamp(job.CreationTimestamp),
); err != nil {
return err
}
var completions string
if obj.Spec.Completions != nil {
completions = strconv.Itoa(int(*obj.Spec.Completions))
} else {
if _, err := fmt.Fprintf(w, "%s\t%s\t%d\t%s",
name,
"<none>",
job.Status.Succeeded,
translateTimestamp(job.CreationTimestamp),
); err != nil {
return err
}
completions = "<none>"
}
row.Cells = append(row.Cells, obj.Name, completions, obj.Status.Succeeded, translateTimestamp(obj.CreationTimestamp))
if options.Wide {
if err := layoutContainers(containers, w); err != nil {
return err
}
if _, err := fmt.Fprintf(w, "\t%s", selector.String()); err != nil {
return err
}
names, images := layoutContainerCells(obj.Spec.Template.Spec.Containers)
row.Cells = append(row.Cells, names, images, metav1.FormatLabelSelector(obj.Spec.Selector))
}
if _, err := fmt.Fprint(w, printers.AppendLabels(job.Labels, options.ColumnLabels)); err != nil {
return err
}
if _, err := fmt.Fprint(w, printers.AppendAllLabels(options.ShowLabels, job.Labels)); err != nil {
return err
}
return nil
return []metav1alpha1.TableRow{row}, nil
}
func printJobList(list *batch.JobList, w io.Writer, options printers.PrintOptions) error {
for _, job := range list.Items {
if err := printJob(&job, w, options); err != nil {
return err
func printJobList(list *batch.JobList, options printers.PrintOptions) ([]metav1alpha1.TableRow, error) {
rows := make([]metav1alpha1.TableRow, 0, len(list.Items))
for i := range list.Items {
r, err := printJob(&list.Items[i], options)
if err != nil {
return nil, err
}
rows = append(rows, r...)
}
return nil
return rows, nil
}
func printCronJob(cronJob *batch.CronJob, w io.Writer, options printers.PrintOptions) error {
name := cronJob.Name
namespace := cronJob.Namespace
if options.WithNamespace {
if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
return err
}
func printCronJob(obj *batch.CronJob, options printers.PrintOptions) ([]metav1alpha1.TableRow, error) {
row := metav1alpha1.TableRow{
Object: runtime.RawExtension{Object: obj},
}
lastScheduleTime := "<none>"
if cronJob.Status.LastScheduleTime != nil {
lastScheduleTime = cronJob.Status.LastScheduleTime.Time.Format(time.RFC1123Z)
}
if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%d\t%s\n",
name,
cronJob.Spec.Schedule,
printBoolPtr(cronJob.Spec.Suspend),
len(cronJob.Status.Active),
lastScheduleTime,
); err != nil {
return err
if obj.Status.LastScheduleTime != nil {
lastScheduleTime = obj.Status.LastScheduleTime.Time.Format(time.RFC1123Z)
}
return nil
row.Cells = append(row.Cells, obj.Name, obj.Spec.Schedule, printBoolPtr(obj.Spec.Suspend), len(obj.Status.Active), lastScheduleTime)
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))
}
return []metav1alpha1.TableRow{row}, nil
}
func printCronJobList(list *batch.CronJobList, w io.Writer, options printers.PrintOptions) error {
for _, cronJob := range list.Items {
if err := printCronJob(&cronJob, w, options); err != nil {
return err
func printCronJobList(list *batch.CronJobList, options printers.PrintOptions) ([]metav1alpha1.TableRow, error) {
rows := make([]metav1alpha1.TableRow, 0, len(list.Items))
for i := range list.Items {
r, err := printCronJob(&list.Items[i], options)
if err != nil {
return nil, err
}
rows = append(rows, r...)
}
return nil
return rows, nil
}
// loadBalancerStatusStringer behaves mostly like a string interface and converts the given status to a string.
@ -1971,7 +1912,8 @@ func printStatus(status *metav1.Status, w io.Writer, options printers.PrintOptio
return nil
}
// Lay out all the containers on one line if use wide output.
// Lay out all the containers on eone line if use wide output.
// DEPRECATED: convert to TableHandler and use layoutContainerCells
func layoutContainers(containers []api.Container, w io.Writer) error {
var namesBuffer bytes.Buffer
var imagesBuffer bytes.Buffer
@ -1991,6 +1933,22 @@ func layoutContainers(containers []api.Container, w io.Writer) error {
return nil
}
// Lay out all the containers on one line if use wide output.
func layoutContainerCells(containers []api.Container) (names string, images string) {
var namesBuffer bytes.Buffer
var imagesBuffer bytes.Buffer
for i, container := range containers {
namesBuffer.WriteString(container.Name)
imagesBuffer.WriteString(container.Image)
if i != len(containers)-1 {
namesBuffer.WriteString(",")
imagesBuffer.WriteString(",")
}
}
return namesBuffer.String(), imagesBuffer.String()
}
// formatEventSource formats EventSource as a comma separated string excluding Host when empty
func formatEventSource(es api.EventSource) string {
EventSourceString := []string{es.Component}

View File

@ -1873,7 +1873,13 @@ func TestPrintJob(t *testing.T) {
buf := bytes.NewBuffer([]byte{})
for _, test := range tests {
printJob(&test.job, buf, printers.PrintOptions{})
table, err := printers.NewTablePrinter().With(AddHandlers).PrintTable(&test.job, printers.PrintOptions{})
if err != nil {
t.Fatal(err)
}
if err := printers.PrintTable(table, buf, printers.PrintOptions{NoHeaders: true}); err != nil {
t.Fatal(err)
}
if buf.String() != test.expect {
t.Fatalf("Expected: %s, got: %s", test.expect, buf.String())
}
@ -2394,7 +2400,13 @@ func TestPrintPodDisruptionBudget(t *testing.T) {
buf := bytes.NewBuffer([]byte{})
for _, test := range tests {
printPodDisruptionBudget(&test.pdb, buf, printers.PrintOptions{})
table, err := printers.NewTablePrinter().With(AddHandlers).PrintTable(&test.pdb, printers.PrintOptions{})
if err != nil {
t.Fatal(err)
}
if err := printers.PrintTable(table, buf, printers.PrintOptions{NoHeaders: true}); err != nil {
t.Fatal(err)
}
if buf.String() != test.expect {
t.Fatalf("Expected: %s, got: %s", test.expect, buf.String())
}
@ -2559,13 +2571,25 @@ func TestPrintReplicaSet(t *testing.T) {
buf := bytes.NewBuffer([]byte{})
for _, test := range tests {
printReplicaSet(&test.replicaSet, buf, printers.PrintOptions{})
table, err := printers.NewTablePrinter().With(AddHandlers).PrintTable(&test.replicaSet, printers.PrintOptions{})
if err != nil {
t.Fatal(err)
}
if err := printers.PrintTable(table, buf, printers.PrintOptions{NoHeaders: true}); err != nil {
t.Fatal(err)
}
if buf.String() != test.expect {
t.Fatalf("Expected: %s, got: %s", test.expect, buf.String())
}
buf.Reset()
printReplicaSet(&test.replicaSet, buf, printers.PrintOptions{Wide: true})
table, err = printers.NewTablePrinter().With(AddHandlers).PrintTable(&test.replicaSet, printers.PrintOptions{Wide: true})
if err != nil {
t.Fatal(err)
}
if err := printers.PrintTable(table, buf, printers.PrintOptions{NoHeaders: true, Wide: true}); err != nil {
t.Fatal(err)
}
if buf.String() != test.wideExpect {
t.Fatalf("Expected: %s, got: %s", test.wideExpect, buf.String())
}