...

Source file src/k8s.io/kubernetes/pkg/printers/internalversion/printers.go

Documentation: k8s.io/kubernetes/pkg/printers/internalversion

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package internalversion
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"net"
    23  	"sort"
    24  	"strconv"
    25  	"strings"
    26  	"time"
    27  
    28  	apiserverinternalv1alpha1 "k8s.io/api/apiserverinternal/v1alpha1"
    29  	appsv1beta1 "k8s.io/api/apps/v1beta1"
    30  	autoscalingv1 "k8s.io/api/autoscaling/v1"
    31  	autoscalingv2beta1 "k8s.io/api/autoscaling/v2beta1"
    32  	batchv1 "k8s.io/api/batch/v1"
    33  	batchv1beta1 "k8s.io/api/batch/v1beta1"
    34  	certificatesv1alpha1 "k8s.io/api/certificates/v1alpha1"
    35  	certificatesv1beta1 "k8s.io/api/certificates/v1beta1"
    36  	coordinationv1 "k8s.io/api/coordination/v1"
    37  	apiv1 "k8s.io/api/core/v1"
    38  	discoveryv1beta1 "k8s.io/api/discovery/v1beta1"
    39  	extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
    40  	flowcontrolv1 "k8s.io/api/flowcontrol/v1"
    41  	networkingv1alpha1 "k8s.io/api/networking/v1alpha1"
    42  	rbacv1beta1 "k8s.io/api/rbac/v1beta1"
    43  	resourcev1alpha2 "k8s.io/api/resource/v1alpha2"
    44  	schedulingv1 "k8s.io/api/scheduling/v1"
    45  	storagev1 "k8s.io/api/storage/v1"
    46  	storagev1alpha1 "k8s.io/api/storage/v1alpha1"
    47  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    48  	"k8s.io/apimachinery/pkg/labels"
    49  	"k8s.io/apimachinery/pkg/runtime"
    50  	"k8s.io/apimachinery/pkg/runtime/schema"
    51  	"k8s.io/apimachinery/pkg/util/duration"
    52  	"k8s.io/apimachinery/pkg/util/sets"
    53  	"k8s.io/client-go/util/certificate/csr"
    54  	"k8s.io/kubernetes/pkg/apis/admissionregistration"
    55  	"k8s.io/kubernetes/pkg/apis/apiserverinternal"
    56  	"k8s.io/kubernetes/pkg/apis/apps"
    57  	"k8s.io/kubernetes/pkg/apis/autoscaling"
    58  	"k8s.io/kubernetes/pkg/apis/batch"
    59  	"k8s.io/kubernetes/pkg/apis/certificates"
    60  	"k8s.io/kubernetes/pkg/apis/coordination"
    61  	api "k8s.io/kubernetes/pkg/apis/core"
    62  	"k8s.io/kubernetes/pkg/apis/core/helper"
    63  	"k8s.io/kubernetes/pkg/apis/discovery"
    64  	"k8s.io/kubernetes/pkg/apis/flowcontrol"
    65  	apihelpers "k8s.io/kubernetes/pkg/apis/flowcontrol/util"
    66  	"k8s.io/kubernetes/pkg/apis/networking"
    67  	nodeapi "k8s.io/kubernetes/pkg/apis/node"
    68  	"k8s.io/kubernetes/pkg/apis/policy"
    69  	"k8s.io/kubernetes/pkg/apis/rbac"
    70  	"k8s.io/kubernetes/pkg/apis/resource"
    71  	"k8s.io/kubernetes/pkg/apis/scheduling"
    72  	"k8s.io/kubernetes/pkg/apis/storage"
    73  	storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
    74  	svmv1alpha1 "k8s.io/kubernetes/pkg/apis/storagemigration"
    75  	"k8s.io/kubernetes/pkg/printers"
    76  	"k8s.io/kubernetes/pkg/util/node"
    77  )
    78  
    79  const (
    80  	loadBalancerWidth = 16
    81  
    82  	// labelNodeRolePrefix is a label prefix for node roles
    83  	// It's copied over to here until it's merged in core: https://github.com/kubernetes/kubernetes/pull/39112
    84  	labelNodeRolePrefix = "node-role.kubernetes.io/"
    85  
    86  	// nodeLabelRole specifies the role of a node
    87  	nodeLabelRole = "kubernetes.io/role"
    88  )
    89  
    90  // AddHandlers adds print handlers for default Kubernetes types dealing with internal versions.
    91  func AddHandlers(h printers.PrintHandler) {
    92  	podColumnDefinitions := []metav1.TableColumnDefinition{
    93  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
    94  		{Name: "Ready", Type: "string", Description: "The aggregate readiness state of this pod for accepting traffic."},
    95  		{Name: "Status", Type: "string", Description: "The aggregate status of the containers in this pod."},
    96  		{Name: "Restarts", Type: "string", Description: "The number of times the containers in this pod have been restarted and when the last container in this pod has restarted."},
    97  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
    98  		{Name: "IP", Type: "string", Priority: 1, Description: apiv1.PodStatus{}.SwaggerDoc()["podIP"]},
    99  		{Name: "Node", Type: "string", Priority: 1, Description: apiv1.PodSpec{}.SwaggerDoc()["nodeName"]},
   100  		{Name: "Nominated Node", Type: "string", Priority: 1, Description: apiv1.PodStatus{}.SwaggerDoc()["nominatedNodeName"]},
   101  		{Name: "Readiness Gates", Type: "string", Priority: 1, Description: apiv1.PodSpec{}.SwaggerDoc()["readinessGates"]},
   102  	}
   103  
   104  	// Errors are suppressed as TableHandler already logs internally
   105  	_ = h.TableHandler(podColumnDefinitions, printPodList)
   106  	_ = h.TableHandler(podColumnDefinitions, printPod)
   107  
   108  	podTemplateColumnDefinitions := []metav1.TableColumnDefinition{
   109  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   110  		{Name: "Containers", Type: "string", Description: "Names of each container in the template."},
   111  		{Name: "Images", Type: "string", Description: "Images referenced by each container in the template."},
   112  		{Name: "Pod Labels", Type: "string", Description: "The labels for the pod template."},
   113  	}
   114  	_ = h.TableHandler(podTemplateColumnDefinitions, printPodTemplate)
   115  	_ = h.TableHandler(podTemplateColumnDefinitions, printPodTemplateList)
   116  
   117  	podDisruptionBudgetColumnDefinitions := []metav1.TableColumnDefinition{
   118  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   119  		{Name: "Min Available", Type: "string", Description: "The minimum number of pods that must be available."},
   120  		{Name: "Max Unavailable", Type: "string", Description: "The maximum number of pods that may be unavailable."},
   121  		{Name: "Allowed Disruptions", Type: "integer", Description: "Calculated number of pods that may be disrupted at this time."},
   122  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   123  	}
   124  	_ = h.TableHandler(podDisruptionBudgetColumnDefinitions, printPodDisruptionBudget)
   125  	_ = h.TableHandler(podDisruptionBudgetColumnDefinitions, printPodDisruptionBudgetList)
   126  
   127  	replicationControllerColumnDefinitions := []metav1.TableColumnDefinition{
   128  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   129  		{Name: "Desired", Type: "integer", Description: apiv1.ReplicationControllerSpec{}.SwaggerDoc()["replicas"]},
   130  		{Name: "Current", Type: "integer", Description: apiv1.ReplicationControllerStatus{}.SwaggerDoc()["replicas"]},
   131  		{Name: "Ready", Type: "integer", Description: apiv1.ReplicationControllerStatus{}.SwaggerDoc()["readyReplicas"]},
   132  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   133  		{Name: "Containers", Type: "string", Priority: 1, Description: "Names of each container in the template."},
   134  		{Name: "Images", Type: "string", Priority: 1, Description: "Images referenced by each container in the template."},
   135  		{Name: "Selector", Type: "string", Priority: 1, Description: apiv1.ReplicationControllerSpec{}.SwaggerDoc()["selector"]},
   136  	}
   137  	_ = h.TableHandler(replicationControllerColumnDefinitions, printReplicationController)
   138  	_ = h.TableHandler(replicationControllerColumnDefinitions, printReplicationControllerList)
   139  
   140  	replicaSetColumnDefinitions := []metav1.TableColumnDefinition{
   141  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   142  		{Name: "Desired", Type: "integer", Description: extensionsv1beta1.ReplicaSetSpec{}.SwaggerDoc()["replicas"]},
   143  		{Name: "Current", Type: "integer", Description: extensionsv1beta1.ReplicaSetStatus{}.SwaggerDoc()["replicas"]},
   144  		{Name: "Ready", Type: "integer", Description: extensionsv1beta1.ReplicaSetStatus{}.SwaggerDoc()["readyReplicas"]},
   145  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   146  		{Name: "Containers", Type: "string", Priority: 1, Description: "Names of each container in the template."},
   147  		{Name: "Images", Type: "string", Priority: 1, Description: "Images referenced by each container in the template."},
   148  		{Name: "Selector", Type: "string", Priority: 1, Description: extensionsv1beta1.ReplicaSetSpec{}.SwaggerDoc()["selector"]},
   149  	}
   150  	_ = h.TableHandler(replicaSetColumnDefinitions, printReplicaSet)
   151  	_ = h.TableHandler(replicaSetColumnDefinitions, printReplicaSetList)
   152  
   153  	daemonSetColumnDefinitions := []metav1.TableColumnDefinition{
   154  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   155  		{Name: "Desired", Type: "integer", Description: extensionsv1beta1.DaemonSetStatus{}.SwaggerDoc()["desiredNumberScheduled"]},
   156  		{Name: "Current", Type: "integer", Description: extensionsv1beta1.DaemonSetStatus{}.SwaggerDoc()["currentNumberScheduled"]},
   157  		{Name: "Ready", Type: "integer", Description: extensionsv1beta1.DaemonSetStatus{}.SwaggerDoc()["numberReady"]},
   158  		{Name: "Up-to-date", Type: "integer", Description: extensionsv1beta1.DaemonSetStatus{}.SwaggerDoc()["updatedNumberScheduled"]},
   159  		{Name: "Available", Type: "integer", Description: extensionsv1beta1.DaemonSetStatus{}.SwaggerDoc()["numberAvailable"]},
   160  		{Name: "Node Selector", Type: "string", Description: apiv1.PodSpec{}.SwaggerDoc()["nodeSelector"]},
   161  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   162  		{Name: "Containers", Type: "string", Priority: 1, Description: "Names of each container in the template."},
   163  		{Name: "Images", Type: "string", Priority: 1, Description: "Images referenced by each container in the template."},
   164  		{Name: "Selector", Type: "string", Priority: 1, Description: extensionsv1beta1.DaemonSetSpec{}.SwaggerDoc()["selector"]},
   165  	}
   166  	_ = h.TableHandler(daemonSetColumnDefinitions, printDaemonSet)
   167  	_ = h.TableHandler(daemonSetColumnDefinitions, printDaemonSetList)
   168  
   169  	jobColumnDefinitions := []metav1.TableColumnDefinition{
   170  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   171  		{Name: "Status", Type: "string", Description: "Status of the job."},
   172  		{Name: "Completions", Type: "string", Description: batchv1.JobStatus{}.SwaggerDoc()["succeeded"]},
   173  		{Name: "Duration", Type: "string", Description: "Time required to complete the job."},
   174  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   175  		{Name: "Containers", Type: "string", Priority: 1, Description: "Names of each container in the template."},
   176  		{Name: "Images", Type: "string", Priority: 1, Description: "Images referenced by each container in the template."},
   177  		{Name: "Selector", Type: "string", Priority: 1, Description: batchv1.JobSpec{}.SwaggerDoc()["selector"]},
   178  	}
   179  	_ = h.TableHandler(jobColumnDefinitions, printJob)
   180  	_ = h.TableHandler(jobColumnDefinitions, printJobList)
   181  
   182  	cronJobColumnDefinitions := []metav1.TableColumnDefinition{
   183  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   184  		{Name: "Schedule", Type: "string", Description: batchv1beta1.CronJobSpec{}.SwaggerDoc()["schedule"]},
   185  		{Name: "Timezone", Type: "string", Description: batchv1beta1.CronJobSpec{}.SwaggerDoc()["timeZone"]},
   186  		{Name: "Suspend", Type: "boolean", Description: batchv1beta1.CronJobSpec{}.SwaggerDoc()["suspend"]},
   187  		{Name: "Active", Type: "integer", Description: batchv1beta1.CronJobStatus{}.SwaggerDoc()["active"]},
   188  		{Name: "Last Schedule", Type: "string", Description: batchv1beta1.CronJobStatus{}.SwaggerDoc()["lastScheduleTime"]},
   189  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   190  		{Name: "Containers", Type: "string", Priority: 1, Description: "Names of each container in the template."},
   191  		{Name: "Images", Type: "string", Priority: 1, Description: "Images referenced by each container in the template."},
   192  		{Name: "Selector", Type: "string", Priority: 1, Description: batchv1.JobSpec{}.SwaggerDoc()["selector"]},
   193  	}
   194  	_ = h.TableHandler(cronJobColumnDefinitions, printCronJob)
   195  	_ = h.TableHandler(cronJobColumnDefinitions, printCronJobList)
   196  
   197  	serviceColumnDefinitions := []metav1.TableColumnDefinition{
   198  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   199  		{Name: "Type", Type: "string", Description: apiv1.ServiceSpec{}.SwaggerDoc()["type"]},
   200  		{Name: "Cluster-IP", Type: "string", Description: apiv1.ServiceSpec{}.SwaggerDoc()["clusterIP"]},
   201  		{Name: "External-IP", Type: "string", Description: apiv1.ServiceSpec{}.SwaggerDoc()["externalIPs"]},
   202  		{Name: "Port(s)", Type: "string", Description: apiv1.ServiceSpec{}.SwaggerDoc()["ports"]},
   203  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   204  		{Name: "Selector", Type: "string", Priority: 1, Description: apiv1.ServiceSpec{}.SwaggerDoc()["selector"]},
   205  	}
   206  
   207  	_ = h.TableHandler(serviceColumnDefinitions, printService)
   208  	_ = h.TableHandler(serviceColumnDefinitions, printServiceList)
   209  
   210  	ingressColumnDefinitions := []metav1.TableColumnDefinition{
   211  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   212  		{Name: "Class", Type: "string", Description: "The name of the IngressClass resource that should be used for additional configuration"},
   213  		{Name: "Hosts", Type: "string", Description: "Hosts that incoming requests are matched against before the ingress rule"},
   214  		{Name: "Address", Type: "string", Description: "Address is a list containing ingress points for the load-balancer"},
   215  		{Name: "Ports", Type: "string", Description: "Ports of TLS configurations that open"},
   216  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   217  	}
   218  	_ = h.TableHandler(ingressColumnDefinitions, printIngress)
   219  	_ = h.TableHandler(ingressColumnDefinitions, printIngressList)
   220  
   221  	ingressClassColumnDefinitions := []metav1.TableColumnDefinition{
   222  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   223  		{Name: "Controller", Type: "string", Description: "Controller that is responsible for handling this class"},
   224  		{Name: "Parameters", Type: "string", Description: "A reference to a resource with additional parameters"},
   225  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   226  	}
   227  	_ = h.TableHandler(ingressClassColumnDefinitions, printIngressClass)
   228  	_ = h.TableHandler(ingressClassColumnDefinitions, printIngressClassList)
   229  
   230  	statefulSetColumnDefinitions := []metav1.TableColumnDefinition{
   231  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   232  		{Name: "Ready", Type: "string", Description: "Number of the pod with ready state"},
   233  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   234  		{Name: "Containers", Type: "string", Priority: 1, Description: "Names of each container in the template."},
   235  		{Name: "Images", Type: "string", Priority: 1, Description: "Images referenced by each container in the template."},
   236  	}
   237  	_ = h.TableHandler(statefulSetColumnDefinitions, printStatefulSet)
   238  	_ = h.TableHandler(statefulSetColumnDefinitions, printStatefulSetList)
   239  
   240  	endpointColumnDefinitions := []metav1.TableColumnDefinition{
   241  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   242  		{Name: "Endpoints", Type: "string", Description: apiv1.Endpoints{}.SwaggerDoc()["subsets"]},
   243  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   244  	}
   245  	_ = h.TableHandler(endpointColumnDefinitions, printEndpoints)
   246  	_ = h.TableHandler(endpointColumnDefinitions, printEndpointsList)
   247  
   248  	nodeColumnDefinitions := []metav1.TableColumnDefinition{
   249  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   250  		{Name: "Status", Type: "string", Description: "The status of the node"},
   251  		{Name: "Roles", Type: "string", Description: "The roles of the node"},
   252  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   253  		{Name: "Version", Type: "string", Description: apiv1.NodeSystemInfo{}.SwaggerDoc()["kubeletVersion"]},
   254  		{Name: "Internal-IP", Type: "string", Priority: 1, Description: apiv1.NodeStatus{}.SwaggerDoc()["addresses"]},
   255  		{Name: "External-IP", Type: "string", Priority: 1, Description: apiv1.NodeStatus{}.SwaggerDoc()["addresses"]},
   256  		{Name: "OS-Image", Type: "string", Priority: 1, Description: apiv1.NodeSystemInfo{}.SwaggerDoc()["osImage"]},
   257  		{Name: "Kernel-Version", Type: "string", Priority: 1, Description: apiv1.NodeSystemInfo{}.SwaggerDoc()["kernelVersion"]},
   258  		{Name: "Container-Runtime", Type: "string", Priority: 1, Description: apiv1.NodeSystemInfo{}.SwaggerDoc()["containerRuntimeVersion"]},
   259  	}
   260  
   261  	_ = h.TableHandler(nodeColumnDefinitions, printNode)
   262  	_ = h.TableHandler(nodeColumnDefinitions, printNodeList)
   263  
   264  	eventColumnDefinitions := []metav1.TableColumnDefinition{
   265  		{Name: "Last Seen", Type: "string", Description: apiv1.Event{}.SwaggerDoc()["lastTimestamp"]},
   266  		{Name: "Type", Type: "string", Description: apiv1.Event{}.SwaggerDoc()["type"]},
   267  		{Name: "Reason", Type: "string", Description: apiv1.Event{}.SwaggerDoc()["reason"]},
   268  		{Name: "Object", Type: "string", Description: apiv1.Event{}.SwaggerDoc()["involvedObject"]},
   269  		{Name: "Subobject", Type: "string", Priority: 1, Description: apiv1.Event{}.InvolvedObject.SwaggerDoc()["fieldPath"]},
   270  		{Name: "Source", Type: "string", Priority: 1, Description: apiv1.Event{}.SwaggerDoc()["source"]},
   271  		{Name: "Message", Type: "string", Description: apiv1.Event{}.SwaggerDoc()["message"]},
   272  		{Name: "First Seen", Type: "string", Priority: 1, Description: apiv1.Event{}.SwaggerDoc()["firstTimestamp"]},
   273  		{Name: "Count", Type: "string", Priority: 1, Description: apiv1.Event{}.SwaggerDoc()["count"]},
   274  		{Name: "Name", Type: "string", Priority: 1, Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   275  	}
   276  	_ = h.TableHandler(eventColumnDefinitions, printEvent)
   277  	_ = h.TableHandler(eventColumnDefinitions, printEventList)
   278  
   279  	namespaceColumnDefinitions := []metav1.TableColumnDefinition{
   280  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   281  		{Name: "Status", Type: "string", Description: "The status of the namespace"},
   282  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   283  	}
   284  	_ = h.TableHandler(namespaceColumnDefinitions, printNamespace)
   285  	_ = h.TableHandler(namespaceColumnDefinitions, printNamespaceList)
   286  
   287  	secretColumnDefinitions := []metav1.TableColumnDefinition{
   288  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   289  		{Name: "Type", Type: "string", Description: apiv1.Secret{}.SwaggerDoc()["type"]},
   290  		{Name: "Data", Type: "string", Description: apiv1.Secret{}.SwaggerDoc()["data"]},
   291  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   292  	}
   293  	_ = h.TableHandler(secretColumnDefinitions, printSecret)
   294  	_ = h.TableHandler(secretColumnDefinitions, printSecretList)
   295  
   296  	serviceAccountColumnDefinitions := []metav1.TableColumnDefinition{
   297  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   298  		{Name: "Secrets", Type: "string", Description: apiv1.ServiceAccount{}.SwaggerDoc()["secrets"]},
   299  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   300  	}
   301  	_ = h.TableHandler(serviceAccountColumnDefinitions, printServiceAccount)
   302  	_ = h.TableHandler(serviceAccountColumnDefinitions, printServiceAccountList)
   303  
   304  	persistentVolumeColumnDefinitions := []metav1.TableColumnDefinition{
   305  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   306  		{Name: "Capacity", Type: "string", Description: apiv1.PersistentVolumeSpec{}.SwaggerDoc()["capacity"]},
   307  		{Name: "Access Modes", Type: "string", Description: apiv1.PersistentVolumeSpec{}.SwaggerDoc()["accessModes"]},
   308  		{Name: "Reclaim Policy", Type: "string", Description: apiv1.PersistentVolumeSpec{}.SwaggerDoc()["persistentVolumeReclaimPolicy"]},
   309  		{Name: "Status", Type: "string", Description: apiv1.PersistentVolumeStatus{}.SwaggerDoc()["phase"]},
   310  		{Name: "Claim", Type: "string", Description: apiv1.PersistentVolumeSpec{}.SwaggerDoc()["claimRef"]},
   311  		{Name: "StorageClass", Type: "string", Description: "StorageClass of the pv"},
   312  		{Name: "VolumeAttributesClass", Type: "string", Description: "VolumeAttributesClass of the pv"},
   313  		{Name: "Reason", Type: "string", Description: apiv1.PersistentVolumeStatus{}.SwaggerDoc()["reason"]},
   314  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   315  		{Name: "VolumeMode", Type: "string", Priority: 1, Description: apiv1.PersistentVolumeSpec{}.SwaggerDoc()["volumeMode"]},
   316  	}
   317  	_ = h.TableHandler(persistentVolumeColumnDefinitions, printPersistentVolume)
   318  	_ = h.TableHandler(persistentVolumeColumnDefinitions, printPersistentVolumeList)
   319  
   320  	persistentVolumeClaimColumnDefinitions := []metav1.TableColumnDefinition{
   321  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   322  		{Name: "Status", Type: "string", Description: apiv1.PersistentVolumeClaimStatus{}.SwaggerDoc()["phase"]},
   323  		{Name: "Volume", Type: "string", Description: apiv1.PersistentVolumeClaimSpec{}.SwaggerDoc()["volumeName"]},
   324  		{Name: "Capacity", Type: "string", Description: apiv1.PersistentVolumeClaimStatus{}.SwaggerDoc()["capacity"]},
   325  		{Name: "Access Modes", Type: "string", Description: apiv1.PersistentVolumeClaimStatus{}.SwaggerDoc()["accessModes"]},
   326  		{Name: "StorageClass", Type: "string", Description: "StorageClass of the pvc"},
   327  		{Name: "VolumeAttributesClass", Type: "string", Description: "VolumeAttributesClass of the pvc"},
   328  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   329  		{Name: "VolumeMode", Type: "string", Priority: 1, Description: apiv1.PersistentVolumeClaimSpec{}.SwaggerDoc()["volumeMode"]},
   330  	}
   331  	_ = h.TableHandler(persistentVolumeClaimColumnDefinitions, printPersistentVolumeClaim)
   332  	_ = h.TableHandler(persistentVolumeClaimColumnDefinitions, printPersistentVolumeClaimList)
   333  
   334  	componentStatusColumnDefinitions := []metav1.TableColumnDefinition{
   335  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   336  		{Name: "Status", Type: "string", Description: "Status of the component conditions"},
   337  		{Name: "Message", Type: "string", Description: "Message of the component conditions"},
   338  		{Name: "Error", Type: "string", Description: "Error of the component conditions"},
   339  	}
   340  	_ = h.TableHandler(componentStatusColumnDefinitions, printComponentStatus)
   341  	_ = h.TableHandler(componentStatusColumnDefinitions, printComponentStatusList)
   342  
   343  	deploymentColumnDefinitions := []metav1.TableColumnDefinition{
   344  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   345  		{Name: "Ready", Type: "string", Description: "Number of the pod with ready state"},
   346  		{Name: "Up-to-date", Type: "string", Description: extensionsv1beta1.DeploymentStatus{}.SwaggerDoc()["updatedReplicas"]},
   347  		{Name: "Available", Type: "string", Description: extensionsv1beta1.DeploymentStatus{}.SwaggerDoc()["availableReplicas"]},
   348  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   349  		{Name: "Containers", Type: "string", Priority: 1, Description: "Names of each container in the template."},
   350  		{Name: "Images", Type: "string", Priority: 1, Description: "Images referenced by each container in the template."},
   351  		{Name: "Selector", Type: "string", Priority: 1, Description: extensionsv1beta1.DeploymentSpec{}.SwaggerDoc()["selector"]},
   352  	}
   353  	_ = h.TableHandler(deploymentColumnDefinitions, printDeployment)
   354  	_ = h.TableHandler(deploymentColumnDefinitions, printDeploymentList)
   355  
   356  	horizontalPodAutoscalerColumnDefinitions := []metav1.TableColumnDefinition{
   357  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   358  		{Name: "Reference", Type: "string", Description: autoscalingv2beta1.HorizontalPodAutoscalerSpec{}.SwaggerDoc()["scaleTargetRef"]},
   359  		{Name: "Targets", Type: "string", Description: autoscalingv2beta1.HorizontalPodAutoscalerSpec{}.SwaggerDoc()["metrics"]},
   360  		{Name: "MinPods", Type: "string", Description: autoscalingv2beta1.HorizontalPodAutoscalerSpec{}.SwaggerDoc()["minReplicas"]},
   361  		{Name: "MaxPods", Type: "string", Description: autoscalingv2beta1.HorizontalPodAutoscalerSpec{}.SwaggerDoc()["maxReplicas"]},
   362  		{Name: "Replicas", Type: "string", Description: autoscalingv2beta1.HorizontalPodAutoscalerStatus{}.SwaggerDoc()["currentReplicas"]},
   363  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   364  	}
   365  	_ = h.TableHandler(horizontalPodAutoscalerColumnDefinitions, printHorizontalPodAutoscaler)
   366  	_ = h.TableHandler(horizontalPodAutoscalerColumnDefinitions, printHorizontalPodAutoscalerList)
   367  
   368  	configMapColumnDefinitions := []metav1.TableColumnDefinition{
   369  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   370  		{Name: "Data", Type: "string", Description: apiv1.ConfigMap{}.SwaggerDoc()["data"]},
   371  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   372  	}
   373  	_ = h.TableHandler(configMapColumnDefinitions, printConfigMap)
   374  	_ = h.TableHandler(configMapColumnDefinitions, printConfigMapList)
   375  
   376  	networkPolicyColumnDefinitioins := []metav1.TableColumnDefinition{
   377  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   378  		{Name: "Pod-Selector", Type: "string", Description: extensionsv1beta1.NetworkPolicySpec{}.SwaggerDoc()["podSelector"]},
   379  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   380  	}
   381  	_ = h.TableHandler(networkPolicyColumnDefinitioins, printNetworkPolicy)
   382  	_ = h.TableHandler(networkPolicyColumnDefinitioins, printNetworkPolicyList)
   383  
   384  	roleBindingsColumnDefinitions := []metav1.TableColumnDefinition{
   385  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   386  		{Name: "Role", Type: "string", Description: rbacv1beta1.RoleBinding{}.SwaggerDoc()["roleRef"]},
   387  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   388  		{Name: "Users", Type: "string", Priority: 1, Description: "Users in the roleBinding"},
   389  		{Name: "Groups", Type: "string", Priority: 1, Description: "Groups in the roleBinding"},
   390  		{Name: "ServiceAccounts", Type: "string", Priority: 1, Description: "ServiceAccounts in the roleBinding"},
   391  	}
   392  	_ = h.TableHandler(roleBindingsColumnDefinitions, printRoleBinding)
   393  	_ = h.TableHandler(roleBindingsColumnDefinitions, printRoleBindingList)
   394  
   395  	clusterRoleBindingsColumnDefinitions := []metav1.TableColumnDefinition{
   396  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   397  		{Name: "Role", Type: "string", Description: rbacv1beta1.ClusterRoleBinding{}.SwaggerDoc()["roleRef"]},
   398  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   399  		{Name: "Users", Type: "string", Priority: 1, Description: "Users in the clusterRoleBinding"},
   400  		{Name: "Groups", Type: "string", Priority: 1, Description: "Groups in the clusterRoleBinding"},
   401  		{Name: "ServiceAccounts", Type: "string", Priority: 1, Description: "ServiceAccounts in the clusterRoleBinding"},
   402  	}
   403  	_ = h.TableHandler(clusterRoleBindingsColumnDefinitions, printClusterRoleBinding)
   404  	_ = h.TableHandler(clusterRoleBindingsColumnDefinitions, printClusterRoleBindingList)
   405  
   406  	certificateSigningRequestColumnDefinitions := []metav1.TableColumnDefinition{
   407  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   408  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   409  		{Name: "SignerName", Type: "string", Description: certificatesv1beta1.CertificateSigningRequestSpec{}.SwaggerDoc()["signerName"]},
   410  		{Name: "Requestor", Type: "string", Description: certificatesv1beta1.CertificateSigningRequestSpec{}.SwaggerDoc()["request"]},
   411  		{Name: "RequestedDuration", Type: "string", Description: certificatesv1beta1.CertificateSigningRequestSpec{}.SwaggerDoc()["expirationSeconds"]},
   412  		{Name: "Condition", Type: "string", Description: certificatesv1beta1.CertificateSigningRequestStatus{}.SwaggerDoc()["conditions"]},
   413  	}
   414  	_ = h.TableHandler(certificateSigningRequestColumnDefinitions, printCertificateSigningRequest)
   415  	_ = h.TableHandler(certificateSigningRequestColumnDefinitions, printCertificateSigningRequestList)
   416  
   417  	clusterTrustBundleColumnDefinitions := []metav1.TableColumnDefinition{
   418  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   419  		{Name: "SignerName", Type: "string", Description: certificatesv1alpha1.ClusterTrustBundleSpec{}.SwaggerDoc()["signerName"]},
   420  	}
   421  	h.TableHandler(clusterTrustBundleColumnDefinitions, printClusterTrustBundle)
   422  	h.TableHandler(clusterTrustBundleColumnDefinitions, printClusterTrustBundleList)
   423  
   424  	leaseColumnDefinitions := []metav1.TableColumnDefinition{
   425  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   426  		{Name: "Holder", Type: "string", Description: coordinationv1.LeaseSpec{}.SwaggerDoc()["holderIdentity"]},
   427  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   428  	}
   429  	_ = h.TableHandler(leaseColumnDefinitions, printLease)
   430  	_ = h.TableHandler(leaseColumnDefinitions, printLeaseList)
   431  
   432  	storageClassColumnDefinitions := []metav1.TableColumnDefinition{
   433  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   434  		{Name: "Provisioner", Type: "string", Description: storagev1.StorageClass{}.SwaggerDoc()["provisioner"]},
   435  		{Name: "ReclaimPolicy", Type: "string", Description: storagev1.StorageClass{}.SwaggerDoc()["reclaimPolicy"]},
   436  		{Name: "VolumeBindingMode", Type: "string", Description: storagev1.StorageClass{}.SwaggerDoc()["volumeBindingMode"]},
   437  		{Name: "AllowVolumeExpansion", Type: "string", Description: storagev1.StorageClass{}.SwaggerDoc()["allowVolumeExpansion"]},
   438  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   439  	}
   440  
   441  	_ = h.TableHandler(storageClassColumnDefinitions, printStorageClass)
   442  	_ = h.TableHandler(storageClassColumnDefinitions, printStorageClassList)
   443  
   444  	volumeAttributesClassColumnDefinitions := []metav1.TableColumnDefinition{
   445  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   446  		{Name: "DriverName", Type: "string", Description: storagev1alpha1.VolumeAttributesClass{}.SwaggerDoc()["driverName"]},
   447  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   448  	}
   449  
   450  	_ = h.TableHandler(volumeAttributesClassColumnDefinitions, printVolumeAttributesClass)
   451  	_ = h.TableHandler(volumeAttributesClassColumnDefinitions, printVolumeAttributesClassList)
   452  
   453  	statusColumnDefinitions := []metav1.TableColumnDefinition{
   454  		{Name: "Status", Type: "string", Description: metav1.Status{}.SwaggerDoc()["status"]},
   455  		{Name: "Reason", Type: "string", Description: metav1.Status{}.SwaggerDoc()["reason"]},
   456  		{Name: "Message", Type: "string", Description: metav1.Status{}.SwaggerDoc()["Message"]},
   457  	}
   458  
   459  	_ = h.TableHandler(statusColumnDefinitions, printStatus)
   460  
   461  	controllerRevisionColumnDefinition := []metav1.TableColumnDefinition{
   462  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   463  		{Name: "Controller", Type: "string", Description: "Controller of the object"},
   464  		{Name: "Revision", Type: "string", Description: appsv1beta1.ControllerRevision{}.SwaggerDoc()["revision"]},
   465  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   466  	}
   467  	_ = h.TableHandler(controllerRevisionColumnDefinition, printControllerRevision)
   468  	_ = h.TableHandler(controllerRevisionColumnDefinition, printControllerRevisionList)
   469  
   470  	resourceQuotaColumnDefinitions := []metav1.TableColumnDefinition{
   471  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   472  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   473  		{Name: "Request", Type: "string", Description: "Request represents a minimum amount of cpu/memory that a container may consume."},
   474  		{Name: "Limit", Type: "string", Description: "Limits control the maximum amount of cpu/memory that a container may use independent of contention on the node."},
   475  	}
   476  	_ = h.TableHandler(resourceQuotaColumnDefinitions, printResourceQuota)
   477  	_ = h.TableHandler(resourceQuotaColumnDefinitions, printResourceQuotaList)
   478  
   479  	priorityClassColumnDefinitions := []metav1.TableColumnDefinition{
   480  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   481  		{Name: "Value", Type: "integer", Description: schedulingv1.PriorityClass{}.SwaggerDoc()["value"]},
   482  		{Name: "Global-Default", Type: "boolean", Description: schedulingv1.PriorityClass{}.SwaggerDoc()["globalDefault"]},
   483  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   484  	}
   485  	_ = h.TableHandler(priorityClassColumnDefinitions, printPriorityClass)
   486  	_ = h.TableHandler(priorityClassColumnDefinitions, printPriorityClassList)
   487  
   488  	runtimeClassColumnDefinitions := []metav1.TableColumnDefinition{
   489  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   490  		{Name: "Handler", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["handler"]},
   491  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   492  	}
   493  	_ = h.TableHandler(runtimeClassColumnDefinitions, printRuntimeClass)
   494  	_ = h.TableHandler(runtimeClassColumnDefinitions, printRuntimeClassList)
   495  
   496  	volumeAttachmentColumnDefinitions := []metav1.TableColumnDefinition{
   497  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   498  		{Name: "Attacher", Type: "string", Format: "name", Description: storagev1.VolumeAttachmentSpec{}.SwaggerDoc()["attacher"]},
   499  		{Name: "PV", Type: "string", Description: storagev1.VolumeAttachmentSource{}.SwaggerDoc()["persistentVolumeName"]},
   500  		{Name: "Node", Type: "string", Description: storagev1.VolumeAttachmentSpec{}.SwaggerDoc()["nodeName"]},
   501  		{Name: "Attached", Type: "boolean", Description: storagev1.VolumeAttachmentStatus{}.SwaggerDoc()["attached"]},
   502  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   503  	}
   504  	_ = h.TableHandler(volumeAttachmentColumnDefinitions, printVolumeAttachment)
   505  	_ = h.TableHandler(volumeAttachmentColumnDefinitions, printVolumeAttachmentList)
   506  
   507  	endpointSliceColumnDefinitions := []metav1.TableColumnDefinition{
   508  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   509  		{Name: "AddressType", Type: "string", Description: discoveryv1beta1.EndpointSlice{}.SwaggerDoc()["addressType"]},
   510  		{Name: "Ports", Type: "string", Description: discoveryv1beta1.EndpointSlice{}.SwaggerDoc()["ports"]},
   511  		{Name: "Endpoints", Type: "string", Description: discoveryv1beta1.EndpointSlice{}.SwaggerDoc()["endpoints"]},
   512  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   513  	}
   514  	_ = h.TableHandler(endpointSliceColumnDefinitions, printEndpointSlice)
   515  	_ = h.TableHandler(endpointSliceColumnDefinitions, printEndpointSliceList)
   516  
   517  	csiNodeColumnDefinitions := []metav1.TableColumnDefinition{
   518  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   519  		{Name: "Drivers", Type: "integer", Description: "Drivers indicates the number of CSI drivers registered on the node"},
   520  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   521  	}
   522  	_ = h.TableHandler(csiNodeColumnDefinitions, printCSINode)
   523  	_ = h.TableHandler(csiNodeColumnDefinitions, printCSINodeList)
   524  
   525  	csiDriverColumnDefinitions := []metav1.TableColumnDefinition{
   526  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   527  		{Name: "AttachRequired", Type: "boolean", Description: storagev1.CSIDriverSpec{}.SwaggerDoc()["attachRequired"]},
   528  		{Name: "PodInfoOnMount", Type: "boolean", Description: storagev1.CSIDriverSpec{}.SwaggerDoc()["podInfoOnMount"]},
   529  		{Name: "StorageCapacity", Type: "boolean", Description: storagev1.CSIDriverSpec{}.SwaggerDoc()["storageCapacity"]},
   530  	}
   531  	csiDriverColumnDefinitions = append(csiDriverColumnDefinitions, []metav1.TableColumnDefinition{
   532  		{Name: "TokenRequests", Type: "string", Description: storagev1.CSIDriverSpec{}.SwaggerDoc()["tokenRequests"]},
   533  		{Name: "RequiresRepublish", Type: "boolean", Description: storagev1.CSIDriverSpec{}.SwaggerDoc()["requiresRepublish"]},
   534  	}...)
   535  
   536  	csiDriverColumnDefinitions = append(csiDriverColumnDefinitions, []metav1.TableColumnDefinition{
   537  		{Name: "Modes", Type: "string", Description: storagev1.CSIDriverSpec{}.SwaggerDoc()["volumeLifecycleModes"]},
   538  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   539  	}...)
   540  	_ = h.TableHandler(csiDriverColumnDefinitions, printCSIDriver)
   541  	_ = h.TableHandler(csiDriverColumnDefinitions, printCSIDriverList)
   542  
   543  	csiStorageCapacityColumnDefinitions := []metav1.TableColumnDefinition{
   544  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   545  		{Name: "StorageClassName", Type: "string", Description: storagev1.CSIStorageCapacity{}.SwaggerDoc()["storageClassName"]},
   546  		{Name: "Capacity", Type: "string", Description: storagev1.CSIStorageCapacity{}.SwaggerDoc()["capacity"]},
   547  	}
   548  	_ = h.TableHandler(csiStorageCapacityColumnDefinitions, printCSIStorageCapacity)
   549  	_ = h.TableHandler(csiStorageCapacityColumnDefinitions, printCSIStorageCapacityList)
   550  
   551  	mutatingWebhookColumnDefinitions := []metav1.TableColumnDefinition{
   552  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   553  		{Name: "Webhooks", Type: "integer", Description: "Webhooks indicates the number of webhooks registered in this configuration"},
   554  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   555  	}
   556  	_ = h.TableHandler(mutatingWebhookColumnDefinitions, printMutatingWebhook)
   557  	_ = h.TableHandler(mutatingWebhookColumnDefinitions, printMutatingWebhookList)
   558  
   559  	validatingWebhookColumnDefinitions := []metav1.TableColumnDefinition{
   560  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   561  		{Name: "Webhooks", Type: "integer", Description: "Webhooks indicates the number of webhooks registered in this configuration"},
   562  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   563  	}
   564  	_ = h.TableHandler(validatingWebhookColumnDefinitions, printValidatingWebhook)
   565  	_ = h.TableHandler(validatingWebhookColumnDefinitions, printValidatingWebhookList)
   566  
   567  	validatingAdmissionPolicy := []metav1.TableColumnDefinition{
   568  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   569  		{Name: "Validations", Type: "integer", Description: "Validations indicates the number of validation rules defined in this configuration"},
   570  		{Name: "ParamKind", Type: "string", Description: "ParamKind specifies the kind of resources used to parameterize this policy"},
   571  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   572  	}
   573  	_ = h.TableHandler(validatingAdmissionPolicy, printValidatingAdmissionPolicy)
   574  	_ = h.TableHandler(validatingAdmissionPolicy, printValidatingAdmissionPolicyList)
   575  
   576  	validatingAdmissionPolicyBinding := []metav1.TableColumnDefinition{
   577  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   578  		{Name: "PolicyName", Type: "string", Description: "PolicyName indicates the policy definition which the policy binding binded to"},
   579  		{Name: "ParamRef", Type: "string", Description: "ParamRef indicates the param resource which sets the configration param"},
   580  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   581  	}
   582  	_ = h.TableHandler(validatingAdmissionPolicyBinding, printValidatingAdmissionPolicyBinding)
   583  	_ = h.TableHandler(validatingAdmissionPolicyBinding, printValidatingAdmissionPolicyBindingList)
   584  
   585  	flowSchemaColumnDefinitions := []metav1.TableColumnDefinition{
   586  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   587  		{Name: "PriorityLevel", Type: "string", Description: flowcontrolv1.PriorityLevelConfigurationReference{}.SwaggerDoc()["name"]},
   588  		{Name: "MatchingPrecedence", Type: "string", Description: flowcontrolv1.FlowSchemaSpec{}.SwaggerDoc()["matchingPrecedence"]},
   589  		{Name: "DistinguisherMethod", Type: "string", Description: flowcontrolv1.FlowSchemaSpec{}.SwaggerDoc()["distinguisherMethod"]},
   590  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   591  		{Name: "MissingPL", Type: "string", Description: "references a broken or non-existent PriorityLevelConfiguration"},
   592  	}
   593  	_ = h.TableHandler(flowSchemaColumnDefinitions, printFlowSchema)
   594  	_ = h.TableHandler(flowSchemaColumnDefinitions, printFlowSchemaList)
   595  
   596  	priorityLevelColumnDefinitions := []metav1.TableColumnDefinition{
   597  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   598  		{Name: "Type", Type: "string", Description: flowcontrolv1.PriorityLevelConfigurationSpec{}.SwaggerDoc()["type"]},
   599  		{Name: "NominalConcurrencyShares", Type: "string", Description: flowcontrolv1.LimitedPriorityLevelConfiguration{}.SwaggerDoc()["nominalConcurrencyShares"]},
   600  		{Name: "Queues", Type: "string", Description: flowcontrolv1.QueuingConfiguration{}.SwaggerDoc()["queues"]},
   601  		{Name: "HandSize", Type: "string", Description: flowcontrolv1.QueuingConfiguration{}.SwaggerDoc()["handSize"]},
   602  		{Name: "QueueLengthLimit", Type: "string", Description: flowcontrolv1.QueuingConfiguration{}.SwaggerDoc()["queueLengthLimit"]},
   603  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   604  	}
   605  	_ = h.TableHandler(priorityLevelColumnDefinitions, printPriorityLevelConfiguration)
   606  	_ = h.TableHandler(priorityLevelColumnDefinitions, printPriorityLevelConfigurationList)
   607  
   608  	storageVersionColumnDefinitions := []metav1.TableColumnDefinition{
   609  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   610  		{Name: "CommonEncodingVersion", Type: "string", Description: apiserverinternalv1alpha1.StorageVersionStatus{}.SwaggerDoc()["commonEncodingVersion"]},
   611  		{Name: "StorageVersions", Type: "string", Description: apiserverinternalv1alpha1.StorageVersionStatus{}.SwaggerDoc()["storageVersions"]},
   612  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   613  	}
   614  	_ = h.TableHandler(storageVersionColumnDefinitions, printStorageVersion)
   615  	_ = h.TableHandler(storageVersionColumnDefinitions, printStorageVersionList)
   616  
   617  	scaleColumnDefinitions := []metav1.TableColumnDefinition{
   618  		{Name: "Name", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   619  		{Name: "Desired", Type: "integer", Description: autoscalingv1.ScaleSpec{}.SwaggerDoc()["replicas"]},
   620  		{Name: "Available", Type: "integer", Description: autoscalingv1.ScaleStatus{}.SwaggerDoc()["replicas"]},
   621  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   622  	}
   623  	_ = h.TableHandler(scaleColumnDefinitions, printScale)
   624  
   625  	resourceClassColumnDefinitions := []metav1.TableColumnDefinition{
   626  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   627  		{Name: "DriverName", Type: "string", Description: resourcev1alpha2.ResourceClass{}.SwaggerDoc()["driverName"]},
   628  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   629  	}
   630  	_ = h.TableHandler(resourceClassColumnDefinitions, printResourceClass)
   631  	_ = h.TableHandler(resourceClassColumnDefinitions, printResourceClassList)
   632  
   633  	resourceClaimColumnDefinitions := []metav1.TableColumnDefinition{
   634  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   635  		{Name: "ResourceClassName", Type: "string", Description: resourcev1alpha2.ResourceClaimSpec{}.SwaggerDoc()["resourceClassName"]},
   636  		{Name: "AllocationMode", Type: "string", Description: resourcev1alpha2.ResourceClaimSpec{}.SwaggerDoc()["allocationMode"]},
   637  		{Name: "State", Type: "string", Description: "A summary of the current state (allocated, pending, reserved, etc.)."},
   638  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   639  	}
   640  	_ = h.TableHandler(resourceClaimColumnDefinitions, printResourceClaim)
   641  	_ = h.TableHandler(resourceClaimColumnDefinitions, printResourceClaimList)
   642  
   643  	resourceClaimTemplateColumnDefinitions := []metav1.TableColumnDefinition{
   644  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   645  		{Name: "ResourceClassName", Type: "string", Description: resourcev1alpha2.ResourceClaimSpec{}.SwaggerDoc()["resourceClassName"]},
   646  		{Name: "AllocationMode", Type: "string", Description: resourcev1alpha2.ResourceClaimSpec{}.SwaggerDoc()["allocationMode"]},
   647  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   648  	}
   649  	_ = h.TableHandler(resourceClaimTemplateColumnDefinitions, printResourceClaimTemplate)
   650  	_ = h.TableHandler(resourceClaimTemplateColumnDefinitions, printResourceClaimTemplateList)
   651  
   652  	podSchedulingCtxColumnDefinitions := []metav1.TableColumnDefinition{
   653  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   654  		{Name: "SelectedNode", Type: "string", Description: resourcev1alpha2.PodSchedulingContextSpec{}.SwaggerDoc()["selectedNode"]},
   655  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   656  	}
   657  	_ = h.TableHandler(podSchedulingCtxColumnDefinitions, printPodSchedulingContext)
   658  	_ = h.TableHandler(podSchedulingCtxColumnDefinitions, printPodSchedulingContextList)
   659  
   660  	resourceClaimParametersColumnDefinitions := []metav1.TableColumnDefinition{
   661  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   662  		{Name: "GeneratedFrom", Type: "string", Description: resourcev1alpha2.ResourceClaimParameters{}.SwaggerDoc()["generatedFrom"]},
   663  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   664  	}
   665  	_ = h.TableHandler(resourceClaimParametersColumnDefinitions, printResourceClaimParameters)
   666  	_ = h.TableHandler(resourceClaimParametersColumnDefinitions, printResourceClaimParametersList)
   667  
   668  	resourceClassParametersColumnDefinitions := []metav1.TableColumnDefinition{
   669  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   670  		{Name: "GeneratedFrom", Type: "string", Description: resourcev1alpha2.ResourceClassParameters{}.SwaggerDoc()["generatedFrom"]},
   671  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   672  	}
   673  	_ = h.TableHandler(resourceClassParametersColumnDefinitions, printResourceClassParameters)
   674  	_ = h.TableHandler(resourceClassParametersColumnDefinitions, printResourceClassParametersList)
   675  
   676  	nodeResourceCapacityColumnDefinitions := []metav1.TableColumnDefinition{
   677  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   678  		{Name: "Node", Type: "string", Description: resourcev1alpha2.ResourceSlice{}.SwaggerDoc()["nodeName"]},
   679  		{Name: "Driver", Type: "string", Description: resourcev1alpha2.ResourceSlice{}.SwaggerDoc()["driverName"]},
   680  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   681  	}
   682  	_ = h.TableHandler(nodeResourceCapacityColumnDefinitions, printResourceSlice)
   683  	_ = h.TableHandler(nodeResourceCapacityColumnDefinitions, printResourceSliceList)
   684  
   685  	serviceCIDRColumnDefinitions := []metav1.TableColumnDefinition{
   686  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   687  		{Name: "CIDRs", Type: "string", Description: networkingv1alpha1.ServiceCIDRSpec{}.SwaggerDoc()["cidrs"]},
   688  		{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
   689  	}
   690  
   691  	_ = h.TableHandler(serviceCIDRColumnDefinitions, printServiceCIDR)
   692  	_ = h.TableHandler(serviceCIDRColumnDefinitions, printServiceCIDRList)
   693  
   694  	ipAddressColumnDefinitions := []metav1.TableColumnDefinition{
   695  		{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   696  		{Name: "ParentRef", Type: "string", Description: networkingv1alpha1.IPAddressSpec{}.SwaggerDoc()["parentRef"]},
   697  	}
   698  
   699  	_ = h.TableHandler(ipAddressColumnDefinitions, printIPAddress)
   700  	_ = h.TableHandler(ipAddressColumnDefinitions, printIPAddressList)
   701  
   702  	storageVersionMigrationColumnDefinitions := []metav1.TableColumnDefinition{
   703  		{Name: "Name", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
   704  		{Name: "Resource", Type: "string", Description: "Fully qualified resource to migrate"},
   705  	}
   706  	_ = h.TableHandler(storageVersionMigrationColumnDefinitions, printStorageVersionMigration)
   707  	_ = h.TableHandler(storageVersionMigrationColumnDefinitions, printStorageVersionMigrationList)
   708  }
   709  
   710  // Pass ports=nil for all ports.
   711  func formatEndpoints(endpoints *api.Endpoints, ports sets.String) string {
   712  	if len(endpoints.Subsets) == 0 {
   713  		return "<none>"
   714  	}
   715  	list := []string{}
   716  	max := 3
   717  	more := false
   718  	count := 0
   719  	for i := range endpoints.Subsets {
   720  		ss := &endpoints.Subsets[i]
   721  		if len(ss.Ports) == 0 {
   722  			// It's possible to have headless services with no ports.
   723  			count += len(ss.Addresses)
   724  			for i := range ss.Addresses {
   725  				if len(list) == max {
   726  					more = true
   727  					// the next loop is redundant
   728  					break
   729  				}
   730  				list = append(list, ss.Addresses[i].IP)
   731  			}
   732  			// avoid nesting code too deeply
   733  			continue
   734  		}
   735  
   736  		// "Normal" services with ports defined.
   737  		for i := range ss.Ports {
   738  			port := &ss.Ports[i]
   739  			if ports == nil || ports.Has(port.Name) {
   740  				count += len(ss.Addresses)
   741  				for i := range ss.Addresses {
   742  					if len(list) == max {
   743  						more = true
   744  						// the next loop is redundant
   745  						break
   746  					}
   747  					addr := &ss.Addresses[i]
   748  					hostPort := net.JoinHostPort(addr.IP, strconv.Itoa(int(port.Port)))
   749  					list = append(list, hostPort)
   750  				}
   751  			}
   752  		}
   753  	}
   754  
   755  	ret := strings.Join(list, ",")
   756  	if more {
   757  		return fmt.Sprintf("%s + %d more...", ret, count-max)
   758  	}
   759  	return ret
   760  }
   761  
   762  func formatDiscoveryPorts(ports []discovery.EndpointPort) string {
   763  	list := []string{}
   764  	max := 3
   765  	more := false
   766  	count := 0
   767  	for _, port := range ports {
   768  		if len(list) < max {
   769  			portNum := "*"
   770  			if port.Port != nil {
   771  				portNum = strconv.Itoa(int(*port.Port))
   772  			} else if port.Name != nil {
   773  				portNum = *port.Name
   774  			}
   775  			list = append(list, portNum)
   776  		} else if len(list) == max {
   777  			more = true
   778  		}
   779  		count++
   780  	}
   781  	return listWithMoreString(list, more, count, max)
   782  }
   783  
   784  func formatDiscoveryEndpoints(endpoints []discovery.Endpoint) string {
   785  	list := []string{}
   786  	max := 3
   787  	more := false
   788  	count := 0
   789  	for _, endpoint := range endpoints {
   790  		for _, address := range endpoint.Addresses {
   791  			if len(list) < max {
   792  				list = append(list, address)
   793  			} else if len(list) == max {
   794  				more = true
   795  			}
   796  			count++
   797  		}
   798  	}
   799  	return listWithMoreString(list, more, count, max)
   800  }
   801  
   802  func listWithMoreString(list []string, more bool, count, max int) string {
   803  	ret := strings.Join(list, ",")
   804  	if more {
   805  		return fmt.Sprintf("%s + %d more...", ret, count-max)
   806  	}
   807  	if ret == "" {
   808  		ret = "<unset>"
   809  	}
   810  	return ret
   811  }
   812  
   813  // translateMicroTimestampSince returns the elapsed time since timestamp in
   814  // human-readable approximation.
   815  func translateMicroTimestampSince(timestamp metav1.MicroTime) string {
   816  	if timestamp.IsZero() {
   817  		return "<unknown>"
   818  	}
   819  
   820  	return duration.HumanDuration(time.Since(timestamp.Time))
   821  }
   822  
   823  // translateTimestampSince returns the elapsed time since timestamp in
   824  // human-readable approximation.
   825  func translateTimestampSince(timestamp metav1.Time) string {
   826  	if timestamp.IsZero() {
   827  		return "<unknown>"
   828  	}
   829  
   830  	return duration.HumanDuration(time.Since(timestamp.Time))
   831  }
   832  
   833  // translateTimestampUntil returns the elapsed time until timestamp in
   834  // human-readable approximation.
   835  func translateTimestampUntil(timestamp metav1.Time) string {
   836  	if timestamp.IsZero() {
   837  		return "<unknown>"
   838  	}
   839  
   840  	return duration.HumanDuration(time.Until(timestamp.Time))
   841  }
   842  
   843  var (
   844  	podSuccessConditions = []metav1.TableRowCondition{{Type: metav1.RowCompleted, Status: metav1.ConditionTrue, Reason: string(api.PodSucceeded), Message: "The pod has completed successfully."}}
   845  	podFailedConditions  = []metav1.TableRowCondition{{Type: metav1.RowCompleted, Status: metav1.ConditionTrue, Reason: string(api.PodFailed), Message: "The pod failed."}}
   846  )
   847  
   848  func printPodList(podList *api.PodList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
   849  	rows := make([]metav1.TableRow, 0, len(podList.Items))
   850  	for i := range podList.Items {
   851  		r, err := printPod(&podList.Items[i], options)
   852  		if err != nil {
   853  			return nil, err
   854  		}
   855  		rows = append(rows, r...)
   856  	}
   857  	return rows, nil
   858  }
   859  
   860  func printPod(pod *api.Pod, options printers.GenerateOptions) ([]metav1.TableRow, error) {
   861  	restarts := 0
   862  	restartableInitContainerRestarts := 0
   863  	totalContainers := len(pod.Spec.Containers)
   864  	readyContainers := 0
   865  	lastRestartDate := metav1.NewTime(time.Time{})
   866  	lastRestartableInitContainerRestartDate := metav1.NewTime(time.Time{})
   867  
   868  	reason := string(pod.Status.Phase)
   869  	if pod.Status.Reason != "" {
   870  		reason = pod.Status.Reason
   871  	}
   872  
   873  	// If the Pod carries {type:PodScheduled, reason:SchedulingGated}, set reason to 'SchedulingGated'.
   874  	for _, condition := range pod.Status.Conditions {
   875  		if condition.Type == api.PodScheduled && condition.Reason == apiv1.PodReasonSchedulingGated {
   876  			reason = apiv1.PodReasonSchedulingGated
   877  		}
   878  	}
   879  
   880  	row := metav1.TableRow{
   881  		Object: runtime.RawExtension{Object: pod},
   882  	}
   883  
   884  	switch pod.Status.Phase {
   885  	case api.PodSucceeded:
   886  		row.Conditions = podSuccessConditions
   887  	case api.PodFailed:
   888  		row.Conditions = podFailedConditions
   889  	}
   890  
   891  	initContainers := make(map[string]*api.Container)
   892  	for i := range pod.Spec.InitContainers {
   893  		initContainers[pod.Spec.InitContainers[i].Name] = &pod.Spec.InitContainers[i]
   894  		if isRestartableInitContainer(&pod.Spec.InitContainers[i]) {
   895  			totalContainers++
   896  		}
   897  	}
   898  
   899  	initializing := false
   900  	for i := range pod.Status.InitContainerStatuses {
   901  		container := pod.Status.InitContainerStatuses[i]
   902  		restarts += int(container.RestartCount)
   903  		if container.LastTerminationState.Terminated != nil {
   904  			terminatedDate := container.LastTerminationState.Terminated.FinishedAt
   905  			if lastRestartDate.Before(&terminatedDate) {
   906  				lastRestartDate = terminatedDate
   907  			}
   908  		}
   909  		if isRestartableInitContainer(initContainers[container.Name]) {
   910  			restartableInitContainerRestarts += int(container.RestartCount)
   911  			if container.LastTerminationState.Terminated != nil {
   912  				terminatedDate := container.LastTerminationState.Terminated.FinishedAt
   913  				if lastRestartableInitContainerRestartDate.Before(&terminatedDate) {
   914  					lastRestartableInitContainerRestartDate = terminatedDate
   915  				}
   916  			}
   917  		}
   918  		switch {
   919  		case container.State.Terminated != nil && container.State.Terminated.ExitCode == 0:
   920  			continue
   921  		case isRestartableInitContainer(initContainers[container.Name]) &&
   922  			container.Started != nil && *container.Started:
   923  			if container.Ready {
   924  				readyContainers++
   925  			}
   926  			continue
   927  		case container.State.Terminated != nil:
   928  			// initialization is failed
   929  			if len(container.State.Terminated.Reason) == 0 {
   930  				if container.State.Terminated.Signal != 0 {
   931  					reason = fmt.Sprintf("Init:Signal:%d", container.State.Terminated.Signal)
   932  				} else {
   933  					reason = fmt.Sprintf("Init:ExitCode:%d", container.State.Terminated.ExitCode)
   934  				}
   935  			} else {
   936  				reason = "Init:" + container.State.Terminated.Reason
   937  			}
   938  			initializing = true
   939  		case container.State.Waiting != nil && len(container.State.Waiting.Reason) > 0 && container.State.Waiting.Reason != "PodInitializing":
   940  			reason = "Init:" + container.State.Waiting.Reason
   941  			initializing = true
   942  		default:
   943  			reason = fmt.Sprintf("Init:%d/%d", i, len(pod.Spec.InitContainers))
   944  			initializing = true
   945  		}
   946  		break
   947  	}
   948  
   949  	if !initializing || isPodInitializedConditionTrue(&pod.Status) {
   950  		restarts = restartableInitContainerRestarts
   951  		lastRestartDate = lastRestartableInitContainerRestartDate
   952  		hasRunning := false
   953  		for i := len(pod.Status.ContainerStatuses) - 1; i >= 0; i-- {
   954  			container := pod.Status.ContainerStatuses[i]
   955  
   956  			restarts += int(container.RestartCount)
   957  			if container.LastTerminationState.Terminated != nil {
   958  				terminatedDate := container.LastTerminationState.Terminated.FinishedAt
   959  				if lastRestartDate.Before(&terminatedDate) {
   960  					lastRestartDate = terminatedDate
   961  				}
   962  			}
   963  			if container.State.Waiting != nil && container.State.Waiting.Reason != "" {
   964  				reason = container.State.Waiting.Reason
   965  			} else if container.State.Terminated != nil && container.State.Terminated.Reason != "" {
   966  				reason = container.State.Terminated.Reason
   967  			} else if container.State.Terminated != nil && container.State.Terminated.Reason == "" {
   968  				if container.State.Terminated.Signal != 0 {
   969  					reason = fmt.Sprintf("Signal:%d", container.State.Terminated.Signal)
   970  				} else {
   971  					reason = fmt.Sprintf("ExitCode:%d", container.State.Terminated.ExitCode)
   972  				}
   973  			} else if container.Ready && container.State.Running != nil {
   974  				hasRunning = true
   975  				readyContainers++
   976  			}
   977  		}
   978  
   979  		// change pod status back to "Running" if there is at least one container still reporting as "Running" status
   980  		if reason == "Completed" && hasRunning {
   981  			if hasPodReadyCondition(pod.Status.Conditions) {
   982  				reason = "Running"
   983  			} else {
   984  				reason = "NotReady"
   985  			}
   986  		}
   987  	}
   988  
   989  	if pod.DeletionTimestamp != nil && pod.Status.Reason == node.NodeUnreachablePodReason {
   990  		reason = "Unknown"
   991  	} else if pod.DeletionTimestamp != nil {
   992  		reason = "Terminating"
   993  	}
   994  
   995  	restartsStr := strconv.Itoa(restarts)
   996  	if restarts != 0 && !lastRestartDate.IsZero() {
   997  		restartsStr = fmt.Sprintf("%d (%s ago)", restarts, translateTimestampSince(lastRestartDate))
   998  	}
   999  
  1000  	row.Cells = append(row.Cells, pod.Name, fmt.Sprintf("%d/%d", readyContainers, totalContainers), reason, restartsStr, translateTimestampSince(pod.CreationTimestamp))
  1001  	if options.Wide {
  1002  		nodeName := pod.Spec.NodeName
  1003  		nominatedNodeName := pod.Status.NominatedNodeName
  1004  		podIP := ""
  1005  		if len(pod.Status.PodIPs) > 0 {
  1006  			podIP = pod.Status.PodIPs[0].IP
  1007  		}
  1008  
  1009  		if podIP == "" {
  1010  			podIP = "<none>"
  1011  		}
  1012  		if nodeName == "" {
  1013  			nodeName = "<none>"
  1014  		}
  1015  		if nominatedNodeName == "" {
  1016  			nominatedNodeName = "<none>"
  1017  		}
  1018  
  1019  		readinessGates := "<none>"
  1020  		if len(pod.Spec.ReadinessGates) > 0 {
  1021  			trueConditions := 0
  1022  			for _, readinessGate := range pod.Spec.ReadinessGates {
  1023  				conditionType := readinessGate.ConditionType
  1024  				for _, condition := range pod.Status.Conditions {
  1025  					if condition.Type == conditionType {
  1026  						if condition.Status == api.ConditionTrue {
  1027  							trueConditions++
  1028  						}
  1029  						break
  1030  					}
  1031  				}
  1032  			}
  1033  			readinessGates = fmt.Sprintf("%d/%d", trueConditions, len(pod.Spec.ReadinessGates))
  1034  		}
  1035  		row.Cells = append(row.Cells, podIP, nodeName, nominatedNodeName, readinessGates)
  1036  	}
  1037  
  1038  	return []metav1.TableRow{row}, nil
  1039  }
  1040  
  1041  func hasPodReadyCondition(conditions []api.PodCondition) bool {
  1042  	for _, condition := range conditions {
  1043  		if condition.Type == api.PodReady && condition.Status == api.ConditionTrue {
  1044  			return true
  1045  		}
  1046  	}
  1047  	return false
  1048  }
  1049  
  1050  func hasJobCondition(conditions []batch.JobCondition, conditionType batch.JobConditionType) bool {
  1051  	for _, condition := range conditions {
  1052  		if condition.Type == conditionType {
  1053  			return condition.Status == api.ConditionTrue
  1054  		}
  1055  	}
  1056  	return false
  1057  }
  1058  
  1059  func printPodTemplate(obj *api.PodTemplate, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1060  	row := metav1.TableRow{
  1061  		Object: runtime.RawExtension{Object: obj},
  1062  	}
  1063  	names, images := layoutContainerCells(obj.Template.Spec.Containers)
  1064  	row.Cells = append(row.Cells, obj.Name, names, images, labels.FormatLabels(obj.Template.Labels))
  1065  	return []metav1.TableRow{row}, nil
  1066  }
  1067  
  1068  func printPodTemplateList(list *api.PodTemplateList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1069  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1070  	for i := range list.Items {
  1071  		r, err := printPodTemplate(&list.Items[i], options)
  1072  		if err != nil {
  1073  			return nil, err
  1074  		}
  1075  		rows = append(rows, r...)
  1076  	}
  1077  	return rows, nil
  1078  }
  1079  
  1080  func printPodDisruptionBudget(obj *policy.PodDisruptionBudget, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1081  	row := metav1.TableRow{
  1082  		Object: runtime.RawExtension{Object: obj},
  1083  	}
  1084  
  1085  	var minAvailable string
  1086  	var maxUnavailable string
  1087  	if obj.Spec.MinAvailable != nil {
  1088  		minAvailable = obj.Spec.MinAvailable.String()
  1089  	} else {
  1090  		minAvailable = "N/A"
  1091  	}
  1092  
  1093  	if obj.Spec.MaxUnavailable != nil {
  1094  		maxUnavailable = obj.Spec.MaxUnavailable.String()
  1095  	} else {
  1096  		maxUnavailable = "N/A"
  1097  	}
  1098  
  1099  	row.Cells = append(row.Cells, obj.Name, minAvailable, maxUnavailable, int64(obj.Status.DisruptionsAllowed), translateTimestampSince(obj.CreationTimestamp))
  1100  	return []metav1.TableRow{row}, nil
  1101  }
  1102  
  1103  func printPodDisruptionBudgetList(list *policy.PodDisruptionBudgetList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1104  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1105  	for i := range list.Items {
  1106  		r, err := printPodDisruptionBudget(&list.Items[i], options)
  1107  		if err != nil {
  1108  			return nil, err
  1109  		}
  1110  		rows = append(rows, r...)
  1111  	}
  1112  	return rows, nil
  1113  }
  1114  
  1115  // TODO(AdoHe): try to put wide output in a single method
  1116  func printReplicationController(obj *api.ReplicationController, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1117  	row := metav1.TableRow{
  1118  		Object: runtime.RawExtension{Object: obj},
  1119  	}
  1120  
  1121  	desiredReplicas := obj.Spec.Replicas
  1122  	currentReplicas := obj.Status.Replicas
  1123  	readyReplicas := obj.Status.ReadyReplicas
  1124  
  1125  	row.Cells = append(row.Cells, obj.Name, int64(desiredReplicas), int64(currentReplicas), int64(readyReplicas), translateTimestampSince(obj.CreationTimestamp))
  1126  	if options.Wide {
  1127  		names, images := layoutContainerCells(obj.Spec.Template.Spec.Containers)
  1128  		row.Cells = append(row.Cells, names, images, labels.FormatLabels(obj.Spec.Selector))
  1129  	}
  1130  	return []metav1.TableRow{row}, nil
  1131  }
  1132  
  1133  func printReplicationControllerList(list *api.ReplicationControllerList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1134  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1135  	for i := range list.Items {
  1136  		r, err := printReplicationController(&list.Items[i], options)
  1137  		if err != nil {
  1138  			return nil, err
  1139  		}
  1140  		rows = append(rows, r...)
  1141  	}
  1142  	return rows, nil
  1143  }
  1144  
  1145  func printReplicaSet(obj *apps.ReplicaSet, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1146  	row := metav1.TableRow{
  1147  		Object: runtime.RawExtension{Object: obj},
  1148  	}
  1149  
  1150  	desiredReplicas := obj.Spec.Replicas
  1151  	currentReplicas := obj.Status.Replicas
  1152  	readyReplicas := obj.Status.ReadyReplicas
  1153  
  1154  	row.Cells = append(row.Cells, obj.Name, int64(desiredReplicas), int64(currentReplicas), int64(readyReplicas), translateTimestampSince(obj.CreationTimestamp))
  1155  	if options.Wide {
  1156  		names, images := layoutContainerCells(obj.Spec.Template.Spec.Containers)
  1157  		row.Cells = append(row.Cells, names, images, metav1.FormatLabelSelector(obj.Spec.Selector))
  1158  	}
  1159  	return []metav1.TableRow{row}, nil
  1160  }
  1161  
  1162  func printReplicaSetList(list *apps.ReplicaSetList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1163  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1164  	for i := range list.Items {
  1165  		r, err := printReplicaSet(&list.Items[i], options)
  1166  		if err != nil {
  1167  			return nil, err
  1168  		}
  1169  		rows = append(rows, r...)
  1170  	}
  1171  	return rows, nil
  1172  }
  1173  
  1174  func printJob(obj *batch.Job, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1175  	row := metav1.TableRow{
  1176  		Object: runtime.RawExtension{Object: obj},
  1177  	}
  1178  
  1179  	var completions string
  1180  	if obj.Spec.Completions != nil {
  1181  		completions = fmt.Sprintf("%d/%d", obj.Status.Succeeded, *obj.Spec.Completions)
  1182  	} else {
  1183  		parallelism := int32(0)
  1184  		if obj.Spec.Parallelism != nil {
  1185  			parallelism = *obj.Spec.Parallelism
  1186  		}
  1187  		if parallelism > 1 {
  1188  			completions = fmt.Sprintf("%d/1 of %d", obj.Status.Succeeded, parallelism)
  1189  		} else {
  1190  			completions = fmt.Sprintf("%d/1", obj.Status.Succeeded)
  1191  		}
  1192  	}
  1193  	var jobDuration string
  1194  	switch {
  1195  	case obj.Status.StartTime == nil:
  1196  	case obj.Status.CompletionTime == nil:
  1197  		jobDuration = duration.HumanDuration(time.Since(obj.Status.StartTime.Time))
  1198  	default:
  1199  		jobDuration = duration.HumanDuration(obj.Status.CompletionTime.Sub(obj.Status.StartTime.Time))
  1200  	}
  1201  	var status string
  1202  	if hasJobCondition(obj.Status.Conditions, batch.JobComplete) {
  1203  		status = "Complete"
  1204  	} else if hasJobCondition(obj.Status.Conditions, batch.JobFailed) {
  1205  		status = "Failed"
  1206  	} else if obj.ObjectMeta.DeletionTimestamp != nil {
  1207  		status = "Terminating"
  1208  	} else if hasJobCondition(obj.Status.Conditions, batch.JobSuspended) {
  1209  		status = "Suspended"
  1210  	} else if hasJobCondition(obj.Status.Conditions, batch.JobFailureTarget) {
  1211  		status = "FailureTarget"
  1212  	} else {
  1213  		status = "Running"
  1214  	}
  1215  
  1216  	row.Cells = append(row.Cells, obj.Name, status, completions, jobDuration, translateTimestampSince(obj.CreationTimestamp))
  1217  	if options.Wide {
  1218  		names, images := layoutContainerCells(obj.Spec.Template.Spec.Containers)
  1219  		row.Cells = append(row.Cells, names, images, metav1.FormatLabelSelector(obj.Spec.Selector))
  1220  	}
  1221  	return []metav1.TableRow{row}, nil
  1222  }
  1223  
  1224  func printJobList(list *batch.JobList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1225  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1226  	for i := range list.Items {
  1227  		r, err := printJob(&list.Items[i], options)
  1228  		if err != nil {
  1229  			return nil, err
  1230  		}
  1231  		rows = append(rows, r...)
  1232  	}
  1233  	return rows, nil
  1234  }
  1235  
  1236  func printCronJob(obj *batch.CronJob, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1237  	row := metav1.TableRow{
  1238  		Object: runtime.RawExtension{Object: obj},
  1239  	}
  1240  
  1241  	lastScheduleTime := "<none>"
  1242  	if obj.Status.LastScheduleTime != nil {
  1243  		lastScheduleTime = translateTimestampSince(*obj.Status.LastScheduleTime)
  1244  	}
  1245  
  1246  	timeZone := "<none>"
  1247  	if obj.Spec.TimeZone != nil {
  1248  		timeZone = *obj.Spec.TimeZone
  1249  	}
  1250  
  1251  	row.Cells = append(row.Cells, obj.Name, obj.Spec.Schedule, timeZone, printBoolPtr(obj.Spec.Suspend), int64(len(obj.Status.Active)), lastScheduleTime, translateTimestampSince(obj.CreationTimestamp))
  1252  	if options.Wide {
  1253  		names, images := layoutContainerCells(obj.Spec.JobTemplate.Spec.Template.Spec.Containers)
  1254  		row.Cells = append(row.Cells, names, images, metav1.FormatLabelSelector(obj.Spec.JobTemplate.Spec.Selector))
  1255  	}
  1256  	return []metav1.TableRow{row}, nil
  1257  }
  1258  
  1259  func printCronJobList(list *batch.CronJobList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1260  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1261  	for i := range list.Items {
  1262  		r, err := printCronJob(&list.Items[i], options)
  1263  		if err != nil {
  1264  			return nil, err
  1265  		}
  1266  		rows = append(rows, r...)
  1267  	}
  1268  	return rows, nil
  1269  }
  1270  
  1271  // loadBalancerStatusStringer behaves mostly like a string interface and converts the given status to a string.
  1272  // `wide` indicates whether the returned value is meant for --o=wide output. If not, it's clipped to 16 bytes.
  1273  func loadBalancerStatusStringer(s api.LoadBalancerStatus, wide bool) string {
  1274  	ingress := s.Ingress
  1275  	result := sets.NewString()
  1276  	for i := range ingress {
  1277  		if ingress[i].IP != "" {
  1278  			result.Insert(ingress[i].IP)
  1279  		} else if ingress[i].Hostname != "" {
  1280  			result.Insert(ingress[i].Hostname)
  1281  		}
  1282  	}
  1283  
  1284  	r := strings.Join(result.List(), ",")
  1285  	if !wide && len(r) > loadBalancerWidth {
  1286  		r = r[0:(loadBalancerWidth-3)] + "..."
  1287  	}
  1288  	return r
  1289  }
  1290  
  1291  func getServiceExternalIP(svc *api.Service, wide bool) string {
  1292  	switch svc.Spec.Type {
  1293  	case api.ServiceTypeClusterIP:
  1294  		if len(svc.Spec.ExternalIPs) > 0 {
  1295  			return strings.Join(svc.Spec.ExternalIPs, ",")
  1296  		}
  1297  		return "<none>"
  1298  	case api.ServiceTypeNodePort:
  1299  		if len(svc.Spec.ExternalIPs) > 0 {
  1300  			return strings.Join(svc.Spec.ExternalIPs, ",")
  1301  		}
  1302  		return "<none>"
  1303  	case api.ServiceTypeLoadBalancer:
  1304  		lbIps := loadBalancerStatusStringer(svc.Status.LoadBalancer, wide)
  1305  		if len(svc.Spec.ExternalIPs) > 0 {
  1306  			results := []string{}
  1307  			if len(lbIps) > 0 {
  1308  				results = append(results, strings.Split(lbIps, ",")...)
  1309  			}
  1310  			results = append(results, svc.Spec.ExternalIPs...)
  1311  			return strings.Join(results, ",")
  1312  		}
  1313  		if len(lbIps) > 0 {
  1314  			return lbIps
  1315  		}
  1316  		return "<pending>"
  1317  	case api.ServiceTypeExternalName:
  1318  		return svc.Spec.ExternalName
  1319  	}
  1320  	return "<unknown>"
  1321  }
  1322  
  1323  func makePortString(ports []api.ServicePort) string {
  1324  	pieces := make([]string, len(ports))
  1325  	for ix := range ports {
  1326  		port := &ports[ix]
  1327  		pieces[ix] = fmt.Sprintf("%d/%s", port.Port, port.Protocol)
  1328  		if port.NodePort > 0 {
  1329  			pieces[ix] = fmt.Sprintf("%d:%d/%s", port.Port, port.NodePort, port.Protocol)
  1330  		}
  1331  	}
  1332  	return strings.Join(pieces, ",")
  1333  }
  1334  
  1335  func printService(obj *api.Service, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1336  	row := metav1.TableRow{
  1337  		Object: runtime.RawExtension{Object: obj},
  1338  	}
  1339  	svcType := obj.Spec.Type
  1340  	internalIP := "<none>"
  1341  	if len(obj.Spec.ClusterIPs) > 0 {
  1342  		internalIP = obj.Spec.ClusterIPs[0]
  1343  	}
  1344  
  1345  	externalIP := getServiceExternalIP(obj, options.Wide)
  1346  	svcPorts := makePortString(obj.Spec.Ports)
  1347  	if len(svcPorts) == 0 {
  1348  		svcPorts = "<none>"
  1349  	}
  1350  
  1351  	row.Cells = append(row.Cells, obj.Name, string(svcType), internalIP, externalIP, svcPorts, translateTimestampSince(obj.CreationTimestamp))
  1352  	if options.Wide {
  1353  		row.Cells = append(row.Cells, labels.FormatLabels(obj.Spec.Selector))
  1354  	}
  1355  
  1356  	return []metav1.TableRow{row}, nil
  1357  }
  1358  
  1359  func printServiceList(list *api.ServiceList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1360  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1361  	for i := range list.Items {
  1362  		r, err := printService(&list.Items[i], options)
  1363  		if err != nil {
  1364  			return nil, err
  1365  		}
  1366  		rows = append(rows, r...)
  1367  	}
  1368  	return rows, nil
  1369  }
  1370  
  1371  func formatHosts(rules []networking.IngressRule) string {
  1372  	list := []string{}
  1373  	max := 3
  1374  	more := false
  1375  	for _, rule := range rules {
  1376  		if len(list) == max {
  1377  			more = true
  1378  		}
  1379  		if !more && len(rule.Host) != 0 {
  1380  			list = append(list, rule.Host)
  1381  		}
  1382  	}
  1383  	if len(list) == 0 {
  1384  		return "*"
  1385  	}
  1386  	ret := strings.Join(list, ",")
  1387  	if more {
  1388  		return fmt.Sprintf("%s + %d more...", ret, len(rules)-max)
  1389  	}
  1390  	return ret
  1391  }
  1392  
  1393  func formatPorts(tls []networking.IngressTLS) string {
  1394  	if len(tls) != 0 {
  1395  		return "80, 443"
  1396  	}
  1397  	return "80"
  1398  }
  1399  
  1400  func printIngress(obj *networking.Ingress, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1401  	row := metav1.TableRow{
  1402  		Object: runtime.RawExtension{Object: obj},
  1403  	}
  1404  	className := "<none>"
  1405  	if obj.Spec.IngressClassName != nil {
  1406  		className = *obj.Spec.IngressClassName
  1407  	}
  1408  	hosts := formatHosts(obj.Spec.Rules)
  1409  	address := ingressLoadBalancerStatusStringer(obj.Status.LoadBalancer, options.Wide)
  1410  	ports := formatPorts(obj.Spec.TLS)
  1411  	createTime := translateTimestampSince(obj.CreationTimestamp)
  1412  	row.Cells = append(row.Cells, obj.Name, className, hosts, address, ports, createTime)
  1413  	return []metav1.TableRow{row}, nil
  1414  }
  1415  
  1416  // ingressLoadBalancerStatusStringer behaves mostly like a string interface and converts the given status to a string.
  1417  // `wide` indicates whether the returned value is meant for --o=wide output. If not, it's clipped to 16 bytes.
  1418  func ingressLoadBalancerStatusStringer(s networking.IngressLoadBalancerStatus, wide bool) string {
  1419  	ingress := s.Ingress
  1420  	result := sets.NewString()
  1421  	for i := range ingress {
  1422  		if ingress[i].IP != "" {
  1423  			result.Insert(ingress[i].IP)
  1424  		} else if ingress[i].Hostname != "" {
  1425  			result.Insert(ingress[i].Hostname)
  1426  		}
  1427  	}
  1428  
  1429  	r := strings.Join(result.List(), ",")
  1430  	if !wide && len(r) > loadBalancerWidth {
  1431  		r = r[0:(loadBalancerWidth-3)] + "..."
  1432  	}
  1433  	return r
  1434  }
  1435  
  1436  func printIngressList(list *networking.IngressList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1437  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1438  	for i := range list.Items {
  1439  		r, err := printIngress(&list.Items[i], options)
  1440  		if err != nil {
  1441  			return nil, err
  1442  		}
  1443  		rows = append(rows, r...)
  1444  	}
  1445  	return rows, nil
  1446  }
  1447  
  1448  func printIngressClass(obj *networking.IngressClass, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1449  	row := metav1.TableRow{
  1450  		Object: runtime.RawExtension{Object: obj},
  1451  	}
  1452  	parameters := "<none>"
  1453  	if obj.Spec.Parameters != nil {
  1454  		parameters = obj.Spec.Parameters.Kind
  1455  		if obj.Spec.Parameters.APIGroup != nil {
  1456  			parameters = parameters + "." + *obj.Spec.Parameters.APIGroup
  1457  		}
  1458  		parameters = parameters + "/" + obj.Spec.Parameters.Name
  1459  	}
  1460  	createTime := translateTimestampSince(obj.CreationTimestamp)
  1461  	row.Cells = append(row.Cells, obj.Name, obj.Spec.Controller, parameters, createTime)
  1462  	return []metav1.TableRow{row}, nil
  1463  }
  1464  
  1465  func printIngressClassList(list *networking.IngressClassList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1466  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1467  	for i := range list.Items {
  1468  		r, err := printIngressClass(&list.Items[i], options)
  1469  		if err != nil {
  1470  			return nil, err
  1471  		}
  1472  		rows = append(rows, r...)
  1473  	}
  1474  	return rows, nil
  1475  }
  1476  
  1477  func printStatefulSet(obj *apps.StatefulSet, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1478  	row := metav1.TableRow{
  1479  		Object: runtime.RawExtension{Object: obj},
  1480  	}
  1481  	desiredReplicas := obj.Spec.Replicas
  1482  	readyReplicas := obj.Status.ReadyReplicas
  1483  	createTime := translateTimestampSince(obj.CreationTimestamp)
  1484  	row.Cells = append(row.Cells, obj.Name, fmt.Sprintf("%d/%d", int64(readyReplicas), int64(desiredReplicas)), createTime)
  1485  	if options.Wide {
  1486  		names, images := layoutContainerCells(obj.Spec.Template.Spec.Containers)
  1487  		row.Cells = append(row.Cells, names, images)
  1488  	}
  1489  	return []metav1.TableRow{row}, nil
  1490  }
  1491  
  1492  func printStatefulSetList(list *apps.StatefulSetList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1493  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1494  	for i := range list.Items {
  1495  		r, err := printStatefulSet(&list.Items[i], options)
  1496  		if err != nil {
  1497  			return nil, err
  1498  		}
  1499  		rows = append(rows, r...)
  1500  	}
  1501  	return rows, nil
  1502  }
  1503  
  1504  func printDaemonSet(obj *apps.DaemonSet, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1505  	row := metav1.TableRow{
  1506  		Object: runtime.RawExtension{Object: obj},
  1507  	}
  1508  
  1509  	desiredScheduled := obj.Status.DesiredNumberScheduled
  1510  	currentScheduled := obj.Status.CurrentNumberScheduled
  1511  	numberReady := obj.Status.NumberReady
  1512  	numberUpdated := obj.Status.UpdatedNumberScheduled
  1513  	numberAvailable := obj.Status.NumberAvailable
  1514  
  1515  	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))
  1516  	if options.Wide {
  1517  		names, images := layoutContainerCells(obj.Spec.Template.Spec.Containers)
  1518  		row.Cells = append(row.Cells, names, images, metav1.FormatLabelSelector(obj.Spec.Selector))
  1519  	}
  1520  	return []metav1.TableRow{row}, nil
  1521  }
  1522  
  1523  func printDaemonSetList(list *apps.DaemonSetList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1524  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1525  	for i := range list.Items {
  1526  		r, err := printDaemonSet(&list.Items[i], options)
  1527  		if err != nil {
  1528  			return nil, err
  1529  		}
  1530  		rows = append(rows, r...)
  1531  	}
  1532  	return rows, nil
  1533  }
  1534  
  1535  func printEndpoints(obj *api.Endpoints, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1536  	row := metav1.TableRow{
  1537  		Object: runtime.RawExtension{Object: obj},
  1538  	}
  1539  	row.Cells = append(row.Cells, obj.Name, formatEndpoints(obj, nil), translateTimestampSince(obj.CreationTimestamp))
  1540  	return []metav1.TableRow{row}, nil
  1541  }
  1542  
  1543  func printEndpointsList(list *api.EndpointsList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1544  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1545  	for i := range list.Items {
  1546  		r, err := printEndpoints(&list.Items[i], options)
  1547  		if err != nil {
  1548  			return nil, err
  1549  		}
  1550  		rows = append(rows, r...)
  1551  	}
  1552  	return rows, nil
  1553  }
  1554  
  1555  func printEndpointSlice(obj *discovery.EndpointSlice, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1556  	row := metav1.TableRow{
  1557  		Object: runtime.RawExtension{Object: obj},
  1558  	}
  1559  	row.Cells = append(row.Cells, obj.Name, string(obj.AddressType), formatDiscoveryPorts(obj.Ports), formatDiscoveryEndpoints(obj.Endpoints), translateTimestampSince(obj.CreationTimestamp))
  1560  	return []metav1.TableRow{row}, nil
  1561  }
  1562  
  1563  func printEndpointSliceList(list *discovery.EndpointSliceList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1564  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1565  	for i := range list.Items {
  1566  		r, err := printEndpointSlice(&list.Items[i], options)
  1567  		if err != nil {
  1568  			return nil, err
  1569  		}
  1570  		rows = append(rows, r...)
  1571  	}
  1572  	return rows, nil
  1573  }
  1574  
  1575  func printCSINode(obj *storage.CSINode, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1576  	row := metav1.TableRow{
  1577  		Object: runtime.RawExtension{Object: obj},
  1578  	}
  1579  	row.Cells = append(row.Cells, obj.Name, int64(len(obj.Spec.Drivers)), translateTimestampSince(obj.CreationTimestamp))
  1580  	return []metav1.TableRow{row}, nil
  1581  }
  1582  
  1583  func printCSINodeList(list *storage.CSINodeList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1584  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1585  	for i := range list.Items {
  1586  		r, err := printCSINode(&list.Items[i], options)
  1587  		if err != nil {
  1588  			return nil, err
  1589  		}
  1590  		rows = append(rows, r...)
  1591  	}
  1592  	return rows, nil
  1593  }
  1594  
  1595  func printCSIDriver(obj *storage.CSIDriver, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1596  	row := metav1.TableRow{
  1597  		Object: runtime.RawExtension{Object: obj},
  1598  	}
  1599  	attachRequired := true
  1600  	if obj.Spec.AttachRequired != nil {
  1601  		attachRequired = *obj.Spec.AttachRequired
  1602  	}
  1603  	podInfoOnMount := false
  1604  	if obj.Spec.PodInfoOnMount != nil {
  1605  		podInfoOnMount = *obj.Spec.PodInfoOnMount
  1606  	}
  1607  	allModes := []string{}
  1608  	for _, mode := range obj.Spec.VolumeLifecycleModes {
  1609  		allModes = append(allModes, string(mode))
  1610  	}
  1611  	modes := strings.Join(allModes, ",")
  1612  	if len(modes) == 0 {
  1613  		modes = "<none>"
  1614  	}
  1615  
  1616  	row.Cells = append(row.Cells, obj.Name, attachRequired, podInfoOnMount)
  1617  	storageCapacity := false
  1618  	if obj.Spec.StorageCapacity != nil {
  1619  		storageCapacity = *obj.Spec.StorageCapacity
  1620  	}
  1621  	row.Cells = append(row.Cells, storageCapacity)
  1622  
  1623  	tokenRequests := "<unset>"
  1624  	if obj.Spec.TokenRequests != nil {
  1625  		audiences := []string{}
  1626  		for _, t := range obj.Spec.TokenRequests {
  1627  			audiences = append(audiences, t.Audience)
  1628  		}
  1629  		tokenRequests = strings.Join(audiences, ",")
  1630  	}
  1631  	requiresRepublish := false
  1632  	if obj.Spec.RequiresRepublish != nil {
  1633  		requiresRepublish = *obj.Spec.RequiresRepublish
  1634  	}
  1635  	row.Cells = append(row.Cells, tokenRequests, requiresRepublish)
  1636  
  1637  	row.Cells = append(row.Cells, modes, translateTimestampSince(obj.CreationTimestamp))
  1638  	return []metav1.TableRow{row}, nil
  1639  }
  1640  
  1641  func printCSIDriverList(list *storage.CSIDriverList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1642  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1643  	for i := range list.Items {
  1644  		r, err := printCSIDriver(&list.Items[i], options)
  1645  		if err != nil {
  1646  			return nil, err
  1647  		}
  1648  		rows = append(rows, r...)
  1649  	}
  1650  	return rows, nil
  1651  }
  1652  
  1653  func printCSIStorageCapacity(obj *storage.CSIStorageCapacity, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1654  	row := metav1.TableRow{
  1655  		Object: runtime.RawExtension{Object: obj},
  1656  	}
  1657  
  1658  	capacity := "<unset>"
  1659  	if obj.Capacity != nil {
  1660  		capacity = obj.Capacity.String()
  1661  	}
  1662  
  1663  	row.Cells = append(row.Cells, obj.Name, obj.StorageClassName, capacity)
  1664  	return []metav1.TableRow{row}, nil
  1665  }
  1666  
  1667  func printCSIStorageCapacityList(list *storage.CSIStorageCapacityList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1668  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1669  	for i := range list.Items {
  1670  		r, err := printCSIStorageCapacity(&list.Items[i], options)
  1671  		if err != nil {
  1672  			return nil, err
  1673  		}
  1674  		rows = append(rows, r...)
  1675  	}
  1676  	return rows, nil
  1677  }
  1678  
  1679  func printMutatingWebhook(obj *admissionregistration.MutatingWebhookConfiguration, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1680  	row := metav1.TableRow{
  1681  		Object: runtime.RawExtension{Object: obj},
  1682  	}
  1683  	row.Cells = append(row.Cells, obj.Name, int64(len(obj.Webhooks)), translateTimestampSince(obj.CreationTimestamp))
  1684  	return []metav1.TableRow{row}, nil
  1685  }
  1686  
  1687  func printMutatingWebhookList(list *admissionregistration.MutatingWebhookConfigurationList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1688  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1689  	for i := range list.Items {
  1690  		r, err := printMutatingWebhook(&list.Items[i], options)
  1691  		if err != nil {
  1692  			return nil, err
  1693  		}
  1694  		rows = append(rows, r...)
  1695  	}
  1696  	return rows, nil
  1697  }
  1698  
  1699  func printValidatingWebhook(obj *admissionregistration.ValidatingWebhookConfiguration, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1700  	row := metav1.TableRow{
  1701  		Object: runtime.RawExtension{Object: obj},
  1702  	}
  1703  	row.Cells = append(row.Cells, obj.Name, int64(len(obj.Webhooks)), translateTimestampSince(obj.CreationTimestamp))
  1704  	return []metav1.TableRow{row}, nil
  1705  }
  1706  
  1707  func printValidatingWebhookList(list *admissionregistration.ValidatingWebhookConfigurationList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1708  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1709  	for i := range list.Items {
  1710  		r, err := printValidatingWebhook(&list.Items[i], options)
  1711  		if err != nil {
  1712  			return nil, err
  1713  		}
  1714  		rows = append(rows, r...)
  1715  	}
  1716  	return rows, nil
  1717  }
  1718  
  1719  func printValidatingAdmissionPolicy(obj *admissionregistration.ValidatingAdmissionPolicy, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1720  	row := metav1.TableRow{
  1721  		Object: runtime.RawExtension{Object: obj},
  1722  	}
  1723  	paramKind := "<unset>"
  1724  	if obj.Spec.ParamKind != nil {
  1725  		paramKind = obj.Spec.ParamKind.APIVersion + "/" + obj.Spec.ParamKind.Kind
  1726  	}
  1727  	row.Cells = append(row.Cells, obj.Name, int64(len(obj.Spec.Validations)), paramKind, translateTimestampSince(obj.CreationTimestamp))
  1728  	return []metav1.TableRow{row}, nil
  1729  }
  1730  
  1731  func printValidatingAdmissionPolicyList(list *admissionregistration.ValidatingAdmissionPolicyList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1732  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1733  	for i := range list.Items {
  1734  		r, err := printValidatingAdmissionPolicy(&list.Items[i], options)
  1735  		if err != nil {
  1736  			return nil, err
  1737  		}
  1738  		rows = append(rows, r...)
  1739  	}
  1740  	return rows, nil
  1741  }
  1742  
  1743  func printValidatingAdmissionPolicyBinding(obj *admissionregistration.ValidatingAdmissionPolicyBinding, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1744  	row := metav1.TableRow{
  1745  		Object: runtime.RawExtension{Object: obj},
  1746  	}
  1747  	paramName := "<unset>"
  1748  	if pr := obj.Spec.ParamRef; pr != nil {
  1749  		if len(pr.Name) > 0 {
  1750  			if pr.Namespace != "" {
  1751  				paramName = pr.Namespace + "/" + pr.Name
  1752  			} else {
  1753  				// Can't tell from here if param is cluster-scoped, so all
  1754  				// params without names get * namespace
  1755  				paramName = "*/" + pr.Name
  1756  			}
  1757  		} else if pr.Selector != nil {
  1758  			paramName = pr.Selector.String()
  1759  		}
  1760  	}
  1761  	row.Cells = append(row.Cells, obj.Name, obj.Spec.PolicyName, paramName, translateTimestampSince(obj.CreationTimestamp))
  1762  	return []metav1.TableRow{row}, nil
  1763  }
  1764  
  1765  func printValidatingAdmissionPolicyBindingList(list *admissionregistration.ValidatingAdmissionPolicyBindingList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1766  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1767  	for i := range list.Items {
  1768  		r, err := printValidatingAdmissionPolicyBinding(&list.Items[i], options)
  1769  		if err != nil {
  1770  			return nil, err
  1771  		}
  1772  		rows = append(rows, r...)
  1773  	}
  1774  	return rows, nil
  1775  }
  1776  
  1777  func printNamespace(obj *api.Namespace, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1778  	row := metav1.TableRow{
  1779  		Object: runtime.RawExtension{Object: obj},
  1780  	}
  1781  	row.Cells = append(row.Cells, obj.Name, string(obj.Status.Phase), translateTimestampSince(obj.CreationTimestamp))
  1782  	return []metav1.TableRow{row}, nil
  1783  }
  1784  
  1785  func printNamespaceList(list *api.NamespaceList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1786  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1787  	for i := range list.Items {
  1788  		r, err := printNamespace(&list.Items[i], options)
  1789  		if err != nil {
  1790  			return nil, err
  1791  		}
  1792  		rows = append(rows, r...)
  1793  	}
  1794  	return rows, nil
  1795  }
  1796  
  1797  func printSecret(obj *api.Secret, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1798  	row := metav1.TableRow{
  1799  		Object: runtime.RawExtension{Object: obj},
  1800  	}
  1801  	row.Cells = append(row.Cells, obj.Name, string(obj.Type), int64(len(obj.Data)), translateTimestampSince(obj.CreationTimestamp))
  1802  	return []metav1.TableRow{row}, nil
  1803  }
  1804  
  1805  func printSecretList(list *api.SecretList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1806  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1807  	for i := range list.Items {
  1808  		r, err := printSecret(&list.Items[i], options)
  1809  		if err != nil {
  1810  			return nil, err
  1811  		}
  1812  		rows = append(rows, r...)
  1813  	}
  1814  	return rows, nil
  1815  }
  1816  
  1817  func printServiceAccount(obj *api.ServiceAccount, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1818  	row := metav1.TableRow{
  1819  		Object: runtime.RawExtension{Object: obj},
  1820  	}
  1821  	row.Cells = append(row.Cells, obj.Name, int64(len(obj.Secrets)), translateTimestampSince(obj.CreationTimestamp))
  1822  	return []metav1.TableRow{row}, nil
  1823  }
  1824  
  1825  func printServiceAccountList(list *api.ServiceAccountList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1826  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1827  	for i := range list.Items {
  1828  		r, err := printServiceAccount(&list.Items[i], options)
  1829  		if err != nil {
  1830  			return nil, err
  1831  		}
  1832  		rows = append(rows, r...)
  1833  	}
  1834  	return rows, nil
  1835  }
  1836  
  1837  func printNode(obj *api.Node, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1838  	row := metav1.TableRow{
  1839  		Object: runtime.RawExtension{Object: obj},
  1840  	}
  1841  
  1842  	conditionMap := make(map[api.NodeConditionType]*api.NodeCondition)
  1843  	NodeAllConditions := []api.NodeConditionType{api.NodeReady}
  1844  	for i := range obj.Status.Conditions {
  1845  		cond := obj.Status.Conditions[i]
  1846  		conditionMap[cond.Type] = &cond
  1847  	}
  1848  	var status []string
  1849  	for _, validCondition := range NodeAllConditions {
  1850  		if condition, ok := conditionMap[validCondition]; ok {
  1851  			if condition.Status == api.ConditionTrue {
  1852  				status = append(status, string(condition.Type))
  1853  			} else {
  1854  				status = append(status, "Not"+string(condition.Type))
  1855  			}
  1856  		}
  1857  	}
  1858  	if len(status) == 0 {
  1859  		status = append(status, "Unknown")
  1860  	}
  1861  	if obj.Spec.Unschedulable {
  1862  		status = append(status, "SchedulingDisabled")
  1863  	}
  1864  
  1865  	roles := strings.Join(findNodeRoles(obj), ",")
  1866  	if len(roles) == 0 {
  1867  		roles = "<none>"
  1868  	}
  1869  
  1870  	row.Cells = append(row.Cells, obj.Name, strings.Join(status, ","), roles, translateTimestampSince(obj.CreationTimestamp), obj.Status.NodeInfo.KubeletVersion)
  1871  	if options.Wide {
  1872  		osImage, kernelVersion, crVersion := obj.Status.NodeInfo.OSImage, obj.Status.NodeInfo.KernelVersion, obj.Status.NodeInfo.ContainerRuntimeVersion
  1873  		if osImage == "" {
  1874  			osImage = "<unknown>"
  1875  		}
  1876  		if kernelVersion == "" {
  1877  			kernelVersion = "<unknown>"
  1878  		}
  1879  		if crVersion == "" {
  1880  			crVersion = "<unknown>"
  1881  		}
  1882  		row.Cells = append(row.Cells, getNodeInternalIP(obj), getNodeExternalIP(obj), osImage, kernelVersion, crVersion)
  1883  	}
  1884  
  1885  	return []metav1.TableRow{row}, nil
  1886  }
  1887  
  1888  // Returns first external ip of the node or "<none>" if none is found.
  1889  func getNodeExternalIP(node *api.Node) string {
  1890  	for _, address := range node.Status.Addresses {
  1891  		if address.Type == api.NodeExternalIP {
  1892  			return address.Address
  1893  		}
  1894  	}
  1895  
  1896  	return "<none>"
  1897  }
  1898  
  1899  // Returns the internal IP of the node or "<none>" if none is found.
  1900  func getNodeInternalIP(node *api.Node) string {
  1901  	for _, address := range node.Status.Addresses {
  1902  		if address.Type == api.NodeInternalIP {
  1903  			return address.Address
  1904  		}
  1905  	}
  1906  
  1907  	return "<none>"
  1908  }
  1909  
  1910  // findNodeRoles returns the roles of a given node.
  1911  // The roles are determined by looking for:
  1912  // * a node-role.kubernetes.io/<role>="" label
  1913  // * a kubernetes.io/role="<role>" label
  1914  func findNodeRoles(node *api.Node) []string {
  1915  	roles := sets.NewString()
  1916  	for k, v := range node.Labels {
  1917  		switch {
  1918  		case strings.HasPrefix(k, labelNodeRolePrefix):
  1919  			if role := strings.TrimPrefix(k, labelNodeRolePrefix); len(role) > 0 {
  1920  				roles.Insert(role)
  1921  			}
  1922  
  1923  		case k == nodeLabelRole && v != "":
  1924  			roles.Insert(v)
  1925  		}
  1926  	}
  1927  	return roles.List()
  1928  }
  1929  
  1930  func printNodeList(list *api.NodeList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1931  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1932  	for i := range list.Items {
  1933  		r, err := printNode(&list.Items[i], options)
  1934  		if err != nil {
  1935  			return nil, err
  1936  		}
  1937  		rows = append(rows, r...)
  1938  	}
  1939  	return rows, nil
  1940  }
  1941  
  1942  func printPersistentVolume(obj *api.PersistentVolume, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1943  	row := metav1.TableRow{
  1944  		Object: runtime.RawExtension{Object: obj},
  1945  	}
  1946  
  1947  	claimRefUID := ""
  1948  	if obj.Spec.ClaimRef != nil {
  1949  		claimRefUID += obj.Spec.ClaimRef.Namespace
  1950  		claimRefUID += "/"
  1951  		claimRefUID += obj.Spec.ClaimRef.Name
  1952  	}
  1953  
  1954  	modesStr := helper.GetAccessModesAsString(obj.Spec.AccessModes)
  1955  	reclaimPolicyStr := string(obj.Spec.PersistentVolumeReclaimPolicy)
  1956  
  1957  	aQty := obj.Spec.Capacity[api.ResourceStorage]
  1958  	aSize := aQty.String()
  1959  
  1960  	phase := obj.Status.Phase
  1961  	if obj.ObjectMeta.DeletionTimestamp != nil {
  1962  		phase = "Terminating"
  1963  	}
  1964  	volumeMode := "<unset>"
  1965  	if obj.Spec.VolumeMode != nil {
  1966  		volumeMode = string(*obj.Spec.VolumeMode)
  1967  	}
  1968  
  1969  	volumeAttributeClass := "<unset>"
  1970  	if obj.Spec.VolumeAttributesClassName != nil {
  1971  		volumeAttributeClass = *obj.Spec.VolumeAttributesClassName
  1972  	}
  1973  
  1974  	row.Cells = append(row.Cells, obj.Name, aSize, modesStr, reclaimPolicyStr,
  1975  		string(phase), claimRefUID, helper.GetPersistentVolumeClass(obj), volumeAttributeClass,
  1976  		obj.Status.Reason, translateTimestampSince(obj.CreationTimestamp), volumeMode)
  1977  	return []metav1.TableRow{row}, nil
  1978  }
  1979  
  1980  func printPersistentVolumeList(list *api.PersistentVolumeList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1981  	rows := make([]metav1.TableRow, 0, len(list.Items))
  1982  	for i := range list.Items {
  1983  		r, err := printPersistentVolume(&list.Items[i], options)
  1984  		if err != nil {
  1985  			return nil, err
  1986  		}
  1987  		rows = append(rows, r...)
  1988  	}
  1989  	return rows, nil
  1990  }
  1991  
  1992  func printPersistentVolumeClaim(obj *api.PersistentVolumeClaim, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  1993  	row := metav1.TableRow{
  1994  		Object: runtime.RawExtension{Object: obj},
  1995  	}
  1996  
  1997  	phase := obj.Status.Phase
  1998  	if obj.ObjectMeta.DeletionTimestamp != nil {
  1999  		phase = "Terminating"
  2000  	}
  2001  
  2002  	volumeAttributeClass := "<unset>"
  2003  	storage := obj.Spec.Resources.Requests[api.ResourceStorage]
  2004  	capacity := ""
  2005  	accessModes := ""
  2006  	volumeMode := "<unset>"
  2007  
  2008  	if obj.Spec.VolumeAttributesClassName != nil {
  2009  		volumeAttributeClass = *obj.Spec.VolumeAttributesClassName
  2010  	}
  2011  
  2012  	if obj.Spec.VolumeName != "" {
  2013  		accessModes = helper.GetAccessModesAsString(obj.Status.AccessModes)
  2014  		storage = obj.Status.Capacity[api.ResourceStorage]
  2015  		capacity = storage.String()
  2016  	}
  2017  
  2018  	if obj.Spec.VolumeMode != nil {
  2019  		volumeMode = string(*obj.Spec.VolumeMode)
  2020  	}
  2021  
  2022  	row.Cells = append(row.Cells, obj.Name, string(phase), obj.Spec.VolumeName, capacity, accessModes,
  2023  		helper.GetPersistentVolumeClaimClass(obj), volumeAttributeClass, translateTimestampSince(obj.CreationTimestamp), volumeMode)
  2024  	return []metav1.TableRow{row}, nil
  2025  }
  2026  
  2027  func printPersistentVolumeClaimList(list *api.PersistentVolumeClaimList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2028  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2029  	for i := range list.Items {
  2030  		r, err := printPersistentVolumeClaim(&list.Items[i], options)
  2031  		if err != nil {
  2032  			return nil, err
  2033  		}
  2034  		rows = append(rows, r...)
  2035  	}
  2036  	return rows, nil
  2037  }
  2038  
  2039  func printEvent(obj *api.Event, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2040  	row := metav1.TableRow{
  2041  		Object: runtime.RawExtension{Object: obj},
  2042  	}
  2043  
  2044  	firstTimestamp := translateTimestampSince(obj.FirstTimestamp)
  2045  	if obj.FirstTimestamp.IsZero() {
  2046  		firstTimestamp = translateMicroTimestampSince(obj.EventTime)
  2047  	}
  2048  
  2049  	lastTimestamp := translateTimestampSince(obj.LastTimestamp)
  2050  	if obj.LastTimestamp.IsZero() {
  2051  		lastTimestamp = firstTimestamp
  2052  	}
  2053  
  2054  	count := obj.Count
  2055  	if obj.Series != nil {
  2056  		lastTimestamp = translateMicroTimestampSince(obj.Series.LastObservedTime)
  2057  		count = obj.Series.Count
  2058  	} else if count == 0 {
  2059  		// Singleton events don't have a count set in the new API.
  2060  		count = 1
  2061  	}
  2062  
  2063  	var target string
  2064  	if len(obj.InvolvedObject.Name) > 0 {
  2065  		target = fmt.Sprintf("%s/%s", strings.ToLower(obj.InvolvedObject.Kind), obj.InvolvedObject.Name)
  2066  	} else {
  2067  		target = strings.ToLower(obj.InvolvedObject.Kind)
  2068  	}
  2069  	if options.Wide {
  2070  		row.Cells = append(row.Cells,
  2071  			lastTimestamp,
  2072  			obj.Type,
  2073  			obj.Reason,
  2074  			target,
  2075  			obj.InvolvedObject.FieldPath,
  2076  			formatEventSource(obj.Source, obj.ReportingController, obj.ReportingInstance),
  2077  			strings.TrimSpace(obj.Message),
  2078  			firstTimestamp,
  2079  			int64(count),
  2080  			obj.Name,
  2081  		)
  2082  	} else {
  2083  		row.Cells = append(row.Cells,
  2084  			lastTimestamp,
  2085  			obj.Type,
  2086  			obj.Reason,
  2087  			target,
  2088  			strings.TrimSpace(obj.Message),
  2089  		)
  2090  	}
  2091  
  2092  	return []metav1.TableRow{row}, nil
  2093  }
  2094  
  2095  // Sorts and prints the EventList in a human-friendly format.
  2096  func printEventList(list *api.EventList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2097  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2098  	for i := range list.Items {
  2099  		r, err := printEvent(&list.Items[i], options)
  2100  		if err != nil {
  2101  			return nil, err
  2102  		}
  2103  		rows = append(rows, r...)
  2104  	}
  2105  	return rows, nil
  2106  }
  2107  
  2108  func printRoleBinding(obj *rbac.RoleBinding, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2109  	row := metav1.TableRow{
  2110  		Object: runtime.RawExtension{Object: obj},
  2111  	}
  2112  
  2113  	roleRef := fmt.Sprintf("%s/%s", obj.RoleRef.Kind, obj.RoleRef.Name)
  2114  	row.Cells = append(row.Cells, obj.Name, roleRef, translateTimestampSince(obj.CreationTimestamp))
  2115  	if options.Wide {
  2116  		users, groups, sas, _ := rbac.SubjectsStrings(obj.Subjects)
  2117  		row.Cells = append(row.Cells, strings.Join(users, ", "), strings.Join(groups, ", "), strings.Join(sas, ", "))
  2118  	}
  2119  	return []metav1.TableRow{row}, nil
  2120  }
  2121  
  2122  // Prints the RoleBinding in a human-friendly format.
  2123  func printRoleBindingList(list *rbac.RoleBindingList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2124  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2125  	for i := range list.Items {
  2126  		r, err := printRoleBinding(&list.Items[i], options)
  2127  		if err != nil {
  2128  			return nil, err
  2129  		}
  2130  		rows = append(rows, r...)
  2131  	}
  2132  	return rows, nil
  2133  }
  2134  
  2135  func printClusterRoleBinding(obj *rbac.ClusterRoleBinding, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2136  	row := metav1.TableRow{
  2137  		Object: runtime.RawExtension{Object: obj},
  2138  	}
  2139  
  2140  	roleRef := fmt.Sprintf("%s/%s", obj.RoleRef.Kind, obj.RoleRef.Name)
  2141  	row.Cells = append(row.Cells, obj.Name, roleRef, translateTimestampSince(obj.CreationTimestamp))
  2142  	if options.Wide {
  2143  		users, groups, sas, _ := rbac.SubjectsStrings(obj.Subjects)
  2144  		row.Cells = append(row.Cells, strings.Join(users, ", "), strings.Join(groups, ", "), strings.Join(sas, ", "))
  2145  	}
  2146  	return []metav1.TableRow{row}, nil
  2147  }
  2148  
  2149  // Prints the ClusterRoleBinding in a human-friendly format.
  2150  func printClusterRoleBindingList(list *rbac.ClusterRoleBindingList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2151  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2152  	for i := range list.Items {
  2153  		r, err := printClusterRoleBinding(&list.Items[i], options)
  2154  		if err != nil {
  2155  			return nil, err
  2156  		}
  2157  		rows = append(rows, r...)
  2158  	}
  2159  	return rows, nil
  2160  }
  2161  
  2162  func printCertificateSigningRequest(obj *certificates.CertificateSigningRequest, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2163  	row := metav1.TableRow{
  2164  		Object: runtime.RawExtension{Object: obj},
  2165  	}
  2166  	status := extractCSRStatus(obj)
  2167  	signerName := "<none>"
  2168  	if obj.Spec.SignerName != "" {
  2169  		signerName = obj.Spec.SignerName
  2170  	}
  2171  	requestedDuration := "<none>"
  2172  	if obj.Spec.ExpirationSeconds != nil {
  2173  		requestedDuration = duration.HumanDuration(csr.ExpirationSecondsToDuration(*obj.Spec.ExpirationSeconds))
  2174  	}
  2175  	row.Cells = append(row.Cells, obj.Name, translateTimestampSince(obj.CreationTimestamp), signerName, obj.Spec.Username, requestedDuration, status)
  2176  	return []metav1.TableRow{row}, nil
  2177  }
  2178  
  2179  func extractCSRStatus(csr *certificates.CertificateSigningRequest) string {
  2180  	var approved, denied, failed bool
  2181  	for _, c := range csr.Status.Conditions {
  2182  		switch c.Type {
  2183  		case certificates.CertificateApproved:
  2184  			approved = true
  2185  		case certificates.CertificateDenied:
  2186  			denied = true
  2187  		case certificates.CertificateFailed:
  2188  			failed = true
  2189  		}
  2190  	}
  2191  	var status string
  2192  	// must be in order of presidence
  2193  	if denied {
  2194  		status += "Denied"
  2195  	} else if approved {
  2196  		status += "Approved"
  2197  	} else {
  2198  		status += "Pending"
  2199  	}
  2200  	if failed {
  2201  		status += ",Failed"
  2202  	}
  2203  	if len(csr.Status.Certificate) > 0 {
  2204  		status += ",Issued"
  2205  	}
  2206  	return status
  2207  }
  2208  
  2209  func printCertificateSigningRequestList(list *certificates.CertificateSigningRequestList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2210  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2211  	for i := range list.Items {
  2212  		r, err := printCertificateSigningRequest(&list.Items[i], options)
  2213  		if err != nil {
  2214  			return nil, err
  2215  		}
  2216  		rows = append(rows, r...)
  2217  	}
  2218  	return rows, nil
  2219  }
  2220  
  2221  func printClusterTrustBundle(obj *certificates.ClusterTrustBundle, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2222  	row := metav1.TableRow{
  2223  		Object: runtime.RawExtension{Object: obj},
  2224  	}
  2225  	signerName := "<none>"
  2226  	if obj.Spec.SignerName != "" {
  2227  		signerName = obj.Spec.SignerName
  2228  	}
  2229  	row.Cells = append(row.Cells, obj.Name, signerName)
  2230  	return []metav1.TableRow{row}, nil
  2231  }
  2232  
  2233  func printClusterTrustBundleList(list *certificates.ClusterTrustBundleList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2234  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2235  	for i := range list.Items {
  2236  		r, err := printClusterTrustBundle(&list.Items[i], options)
  2237  		if err != nil {
  2238  			return nil, err
  2239  		}
  2240  		rows = append(rows, r...)
  2241  	}
  2242  	return rows, nil
  2243  }
  2244  
  2245  func printComponentStatus(obj *api.ComponentStatus, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2246  	row := metav1.TableRow{
  2247  		Object: runtime.RawExtension{Object: obj},
  2248  	}
  2249  	status := "Unknown"
  2250  	message := ""
  2251  	error := ""
  2252  	for _, condition := range obj.Conditions {
  2253  		if condition.Type == api.ComponentHealthy {
  2254  			if condition.Status == api.ConditionTrue {
  2255  				status = "Healthy"
  2256  			} else {
  2257  				status = "Unhealthy"
  2258  			}
  2259  			message = condition.Message
  2260  			error = condition.Error
  2261  			break
  2262  		}
  2263  	}
  2264  	row.Cells = append(row.Cells, obj.Name, status, message, error)
  2265  	return []metav1.TableRow{row}, nil
  2266  }
  2267  
  2268  func printComponentStatusList(list *api.ComponentStatusList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2269  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2270  	for i := range list.Items {
  2271  		r, err := printComponentStatus(&list.Items[i], options)
  2272  		if err != nil {
  2273  			return nil, err
  2274  		}
  2275  		rows = append(rows, r...)
  2276  	}
  2277  	return rows, nil
  2278  }
  2279  
  2280  func printDeployment(obj *apps.Deployment, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2281  	row := metav1.TableRow{
  2282  		Object: runtime.RawExtension{Object: obj},
  2283  	}
  2284  	desiredReplicas := obj.Spec.Replicas
  2285  	updatedReplicas := obj.Status.UpdatedReplicas
  2286  	readyReplicas := obj.Status.ReadyReplicas
  2287  	availableReplicas := obj.Status.AvailableReplicas
  2288  	age := translateTimestampSince(obj.CreationTimestamp)
  2289  	containers := obj.Spec.Template.Spec.Containers
  2290  	selector, err := metav1.LabelSelectorAsSelector(obj.Spec.Selector)
  2291  	selectorString := ""
  2292  	if err != nil {
  2293  		selectorString = "<invalid>"
  2294  	} else {
  2295  		selectorString = selector.String()
  2296  	}
  2297  	row.Cells = append(row.Cells, obj.Name, fmt.Sprintf("%d/%d", int64(readyReplicas), int64(desiredReplicas)), int64(updatedReplicas), int64(availableReplicas), age)
  2298  	if options.Wide {
  2299  		containers, images := layoutContainerCells(containers)
  2300  		row.Cells = append(row.Cells, containers, images, selectorString)
  2301  	}
  2302  	return []metav1.TableRow{row}, nil
  2303  }
  2304  
  2305  func printDeploymentList(list *apps.DeploymentList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2306  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2307  	for i := range list.Items {
  2308  		r, err := printDeployment(&list.Items[i], options)
  2309  		if err != nil {
  2310  			return nil, err
  2311  		}
  2312  		rows = append(rows, r...)
  2313  	}
  2314  	return rows, nil
  2315  }
  2316  
  2317  func formatHPAMetrics(specs []autoscaling.MetricSpec, statuses []autoscaling.MetricStatus) string {
  2318  	if len(specs) == 0 {
  2319  		return "<none>"
  2320  	}
  2321  	list := []string{}
  2322  	max := 2
  2323  	more := false
  2324  	count := 0
  2325  	for i, spec := range specs {
  2326  		switch spec.Type {
  2327  		case autoscaling.ExternalMetricSourceType:
  2328  			if spec.External.Target.AverageValue != nil {
  2329  				current := "<unknown>"
  2330  				if len(statuses) > i && statuses[i].External != nil && statuses[i].External.Current.AverageValue != nil {
  2331  					current = statuses[i].External.Current.AverageValue.String()
  2332  				}
  2333  				list = append(list, fmt.Sprintf("%s/%s (avg)", current, spec.External.Target.AverageValue.String()))
  2334  			} else {
  2335  				current := "<unknown>"
  2336  				if len(statuses) > i && statuses[i].External != nil {
  2337  					current = statuses[i].External.Current.Value.String()
  2338  				}
  2339  				list = append(list, fmt.Sprintf("%s/%s", current, spec.External.Target.Value.String()))
  2340  			}
  2341  		case autoscaling.PodsMetricSourceType:
  2342  			current := "<unknown>"
  2343  			if len(statuses) > i && statuses[i].Pods != nil {
  2344  				current = statuses[i].Pods.Current.AverageValue.String()
  2345  			}
  2346  			list = append(list, fmt.Sprintf("%s/%s", current, spec.Pods.Target.AverageValue.String()))
  2347  		case autoscaling.ObjectMetricSourceType:
  2348  			if spec.Object.Target.AverageValue != nil {
  2349  				current := "<unknown>"
  2350  				if len(statuses) > i && statuses[i].Object != nil && statuses[i].Object.Current.AverageValue != nil {
  2351  					current = statuses[i].Object.Current.AverageValue.String()
  2352  				}
  2353  				list = append(list, fmt.Sprintf("%s/%s (avg)", current, spec.Object.Target.AverageValue.String()))
  2354  			} else {
  2355  				current := "<unknown>"
  2356  				if len(statuses) > i && statuses[i].Object != nil {
  2357  					current = statuses[i].Object.Current.Value.String()
  2358  				}
  2359  				list = append(list, fmt.Sprintf("%s/%s", current, spec.Object.Target.Value.String()))
  2360  			}
  2361  		case autoscaling.ResourceMetricSourceType:
  2362  			if spec.Resource.Target.AverageValue != nil {
  2363  				current := "<unknown>"
  2364  				if len(statuses) > i && statuses[i].Resource != nil {
  2365  					current = statuses[i].Resource.Current.AverageValue.String()
  2366  				}
  2367  				list = append(list, fmt.Sprintf("%s: %s/%s", spec.Resource.Name.String(), current, spec.Resource.Target.AverageValue.String()))
  2368  			} else {
  2369  				current := "<unknown>"
  2370  				if len(statuses) > i && statuses[i].Resource != nil && statuses[i].Resource.Current.AverageUtilization != nil {
  2371  					current = fmt.Sprintf("%d%%", *statuses[i].Resource.Current.AverageUtilization)
  2372  				}
  2373  
  2374  				target := "<auto>"
  2375  				if spec.Resource.Target.AverageUtilization != nil {
  2376  					target = fmt.Sprintf("%d%%", *spec.Resource.Target.AverageUtilization)
  2377  				}
  2378  				list = append(list, fmt.Sprintf("%s: %s/%s", spec.Resource.Name.String(), current, target))
  2379  			}
  2380  		case autoscaling.ContainerResourceMetricSourceType:
  2381  			if spec.ContainerResource.Target.AverageValue != nil {
  2382  				current := "<unknown>"
  2383  				if len(statuses) > i && statuses[i].ContainerResource != nil {
  2384  					current = statuses[i].ContainerResource.Current.AverageValue.String()
  2385  				}
  2386  				list = append(list, fmt.Sprintf("%s: %s/%s", spec.ContainerResource.Name.String(), current, spec.ContainerResource.Target.AverageValue.String()))
  2387  			} else {
  2388  				current := "<unknown>"
  2389  				if len(statuses) > i && statuses[i].ContainerResource != nil && statuses[i].ContainerResource.Current.AverageUtilization != nil {
  2390  					current = fmt.Sprintf("%d%%", *statuses[i].ContainerResource.Current.AverageUtilization)
  2391  				}
  2392  
  2393  				target := "<auto>"
  2394  				if spec.ContainerResource.Target.AverageUtilization != nil {
  2395  					target = fmt.Sprintf("%d%%", *spec.ContainerResource.Target.AverageUtilization)
  2396  				}
  2397  				list = append(list, fmt.Sprintf("%s: %s/%s", spec.ContainerResource.Name.String(), current, target))
  2398  			}
  2399  		default:
  2400  			list = append(list, "<unknown type>")
  2401  		}
  2402  
  2403  		count++
  2404  	}
  2405  
  2406  	if count > max {
  2407  		list = list[:max]
  2408  		more = true
  2409  	}
  2410  
  2411  	ret := strings.Join(list, ", ")
  2412  	if more {
  2413  		return fmt.Sprintf("%s + %d more...", ret, count-max)
  2414  	}
  2415  	return ret
  2416  }
  2417  
  2418  func printHorizontalPodAutoscaler(obj *autoscaling.HorizontalPodAutoscaler, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2419  	row := metav1.TableRow{
  2420  		Object: runtime.RawExtension{Object: obj},
  2421  	}
  2422  
  2423  	reference := fmt.Sprintf("%s/%s",
  2424  		obj.Spec.ScaleTargetRef.Kind,
  2425  		obj.Spec.ScaleTargetRef.Name)
  2426  	minPods := "<unset>"
  2427  	metrics := formatHPAMetrics(obj.Spec.Metrics, obj.Status.CurrentMetrics)
  2428  	if obj.Spec.MinReplicas != nil {
  2429  		minPods = fmt.Sprintf("%d", *obj.Spec.MinReplicas)
  2430  	}
  2431  	maxPods := obj.Spec.MaxReplicas
  2432  	currentReplicas := obj.Status.CurrentReplicas
  2433  	row.Cells = append(row.Cells, obj.Name, reference, metrics, minPods, int64(maxPods), int64(currentReplicas), translateTimestampSince(obj.CreationTimestamp))
  2434  	return []metav1.TableRow{row}, nil
  2435  }
  2436  
  2437  func printHorizontalPodAutoscalerList(list *autoscaling.HorizontalPodAutoscalerList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2438  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2439  	for i := range list.Items {
  2440  		r, err := printHorizontalPodAutoscaler(&list.Items[i], options)
  2441  		if err != nil {
  2442  			return nil, err
  2443  		}
  2444  		rows = append(rows, r...)
  2445  	}
  2446  	return rows, nil
  2447  }
  2448  
  2449  func printConfigMap(obj *api.ConfigMap, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2450  	row := metav1.TableRow{
  2451  		Object: runtime.RawExtension{Object: obj},
  2452  	}
  2453  	row.Cells = append(row.Cells, obj.Name, int64(len(obj.Data)+len(obj.BinaryData)), translateTimestampSince(obj.CreationTimestamp))
  2454  	return []metav1.TableRow{row}, nil
  2455  }
  2456  
  2457  func printConfigMapList(list *api.ConfigMapList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2458  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2459  	for i := range list.Items {
  2460  		r, err := printConfigMap(&list.Items[i], options)
  2461  		if err != nil {
  2462  			return nil, err
  2463  		}
  2464  		rows = append(rows, r...)
  2465  	}
  2466  	return rows, nil
  2467  }
  2468  
  2469  func printNetworkPolicy(obj *networking.NetworkPolicy, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2470  	row := metav1.TableRow{
  2471  		Object: runtime.RawExtension{Object: obj},
  2472  	}
  2473  	row.Cells = append(row.Cells, obj.Name, metav1.FormatLabelSelector(&obj.Spec.PodSelector), translateTimestampSince(obj.CreationTimestamp))
  2474  	return []metav1.TableRow{row}, nil
  2475  }
  2476  
  2477  func printNetworkPolicyList(list *networking.NetworkPolicyList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2478  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2479  	for i := range list.Items {
  2480  		r, err := printNetworkPolicy(&list.Items[i], options)
  2481  		if err != nil {
  2482  			return nil, err
  2483  		}
  2484  		rows = append(rows, r...)
  2485  	}
  2486  	return rows, nil
  2487  }
  2488  
  2489  func printStorageClass(obj *storage.StorageClass, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2490  	row := metav1.TableRow{
  2491  		Object: runtime.RawExtension{Object: obj},
  2492  	}
  2493  
  2494  	name := obj.Name
  2495  	if storageutil.IsDefaultAnnotation(obj.ObjectMeta) {
  2496  		name += " (default)"
  2497  	}
  2498  	provtype := obj.Provisioner
  2499  	reclaimPolicy := string(api.PersistentVolumeReclaimDelete)
  2500  	if obj.ReclaimPolicy != nil {
  2501  		reclaimPolicy = string(*obj.ReclaimPolicy)
  2502  	}
  2503  
  2504  	volumeBindingMode := string(storage.VolumeBindingImmediate)
  2505  	if obj.VolumeBindingMode != nil {
  2506  		volumeBindingMode = string(*obj.VolumeBindingMode)
  2507  	}
  2508  
  2509  	allowVolumeExpansion := false
  2510  	if obj.AllowVolumeExpansion != nil {
  2511  		allowVolumeExpansion = *obj.AllowVolumeExpansion
  2512  	}
  2513  
  2514  	row.Cells = append(row.Cells, name, provtype, reclaimPolicy, volumeBindingMode, allowVolumeExpansion,
  2515  		translateTimestampSince(obj.CreationTimestamp))
  2516  
  2517  	return []metav1.TableRow{row}, nil
  2518  }
  2519  
  2520  func printStorageClassList(list *storage.StorageClassList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2521  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2522  	for i := range list.Items {
  2523  		r, err := printStorageClass(&list.Items[i], options)
  2524  		if err != nil {
  2525  			return nil, err
  2526  		}
  2527  		rows = append(rows, r...)
  2528  	}
  2529  	return rows, nil
  2530  }
  2531  
  2532  func printVolumeAttributesClass(obj *storage.VolumeAttributesClass, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2533  	row := metav1.TableRow{
  2534  		Object: runtime.RawExtension{Object: obj},
  2535  	}
  2536  
  2537  	name := obj.Name
  2538  	if storageutil.IsDefaultAnnotationForVolumeAttributesClass(obj.ObjectMeta) {
  2539  		name += " (default)"
  2540  	}
  2541  
  2542  	row.Cells = append(row.Cells, name, obj.DriverName, translateTimestampSince(obj.CreationTimestamp))
  2543  
  2544  	return []metav1.TableRow{row}, nil
  2545  }
  2546  
  2547  func printVolumeAttributesClassList(list *storage.VolumeAttributesClassList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2548  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2549  	for i := range list.Items {
  2550  		r, err := printVolumeAttributesClass(&list.Items[i], options)
  2551  		if err != nil {
  2552  			return nil, err
  2553  		}
  2554  		rows = append(rows, r...)
  2555  	}
  2556  	return rows, nil
  2557  }
  2558  
  2559  func printLease(obj *coordination.Lease, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2560  	row := metav1.TableRow{
  2561  		Object: runtime.RawExtension{Object: obj},
  2562  	}
  2563  
  2564  	var holderIdentity string
  2565  	if obj.Spec.HolderIdentity != nil {
  2566  		holderIdentity = *obj.Spec.HolderIdentity
  2567  	}
  2568  	row.Cells = append(row.Cells, obj.Name, holderIdentity, translateTimestampSince(obj.CreationTimestamp))
  2569  	return []metav1.TableRow{row}, nil
  2570  }
  2571  
  2572  func printLeaseList(list *coordination.LeaseList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2573  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2574  	for i := range list.Items {
  2575  		r, err := printLease(&list.Items[i], options)
  2576  		if err != nil {
  2577  			return nil, err
  2578  		}
  2579  		rows = append(rows, r...)
  2580  	}
  2581  	return rows, nil
  2582  }
  2583  
  2584  func printStatus(obj *metav1.Status, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2585  	row := metav1.TableRow{
  2586  		Object: runtime.RawExtension{Object: obj},
  2587  	}
  2588  	row.Cells = append(row.Cells, obj.Status, string(obj.Reason), obj.Message)
  2589  
  2590  	return []metav1.TableRow{row}, nil
  2591  }
  2592  
  2593  // Lay out all the containers on one line if use wide output.
  2594  func layoutContainerCells(containers []api.Container) (names string, images string) {
  2595  	var namesBuffer bytes.Buffer
  2596  	var imagesBuffer bytes.Buffer
  2597  
  2598  	for i, container := range containers {
  2599  		namesBuffer.WriteString(container.Name)
  2600  		imagesBuffer.WriteString(container.Image)
  2601  		if i != len(containers)-1 {
  2602  			namesBuffer.WriteString(",")
  2603  			imagesBuffer.WriteString(",")
  2604  		}
  2605  	}
  2606  	return namesBuffer.String(), imagesBuffer.String()
  2607  }
  2608  
  2609  // formatEventSource formats EventSource as a comma separated string excluding Host when empty.
  2610  // It uses reportingController when Source.Component is empty and reportingInstance when Source.Host is empty
  2611  func formatEventSource(es api.EventSource, reportingController, reportingInstance string) string {
  2612  	return formatEventSourceComponentInstance(
  2613  		firstNonEmpty(es.Component, reportingController),
  2614  		firstNonEmpty(es.Host, reportingInstance),
  2615  	)
  2616  }
  2617  
  2618  func firstNonEmpty(ss ...string) string {
  2619  	for _, s := range ss {
  2620  		if len(s) > 0 {
  2621  			return s
  2622  		}
  2623  	}
  2624  	return ""
  2625  }
  2626  
  2627  func formatEventSourceComponentInstance(component, instance string) string {
  2628  	if len(instance) == 0 {
  2629  		return component
  2630  	}
  2631  	return component + ", " + instance
  2632  }
  2633  
  2634  func printControllerRevision(obj *apps.ControllerRevision, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2635  	row := metav1.TableRow{
  2636  		Object: runtime.RawExtension{Object: obj},
  2637  	}
  2638  
  2639  	controllerRef := metav1.GetControllerOf(obj)
  2640  	controllerName := "<none>"
  2641  	if controllerRef != nil {
  2642  		withKind := true
  2643  		gv, err := schema.ParseGroupVersion(controllerRef.APIVersion)
  2644  		if err != nil {
  2645  			return nil, err
  2646  		}
  2647  		gvk := gv.WithKind(controllerRef.Kind)
  2648  		controllerName = formatResourceName(gvk.GroupKind(), controllerRef.Name, withKind)
  2649  	}
  2650  	revision := obj.Revision
  2651  	age := translateTimestampSince(obj.CreationTimestamp)
  2652  	row.Cells = append(row.Cells, obj.Name, controllerName, revision, age)
  2653  	return []metav1.TableRow{row}, nil
  2654  }
  2655  
  2656  func printControllerRevisionList(list *apps.ControllerRevisionList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2657  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2658  	for i := range list.Items {
  2659  		r, err := printControllerRevision(&list.Items[i], options)
  2660  		if err != nil {
  2661  			return nil, err
  2662  		}
  2663  		rows = append(rows, r...)
  2664  	}
  2665  	return rows, nil
  2666  }
  2667  
  2668  // formatResourceName receives a resource kind, name, and boolean specifying
  2669  // whether or not to update the current name to "kind/name"
  2670  func formatResourceName(kind schema.GroupKind, name string, withKind bool) string {
  2671  	if !withKind || kind.Empty() {
  2672  		return name
  2673  	}
  2674  
  2675  	return strings.ToLower(kind.String()) + "/" + name
  2676  }
  2677  
  2678  func printResourceQuota(resourceQuota *api.ResourceQuota, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2679  	row := metav1.TableRow{
  2680  		Object: runtime.RawExtension{Object: resourceQuota},
  2681  	}
  2682  
  2683  	resources := make([]api.ResourceName, 0, len(resourceQuota.Status.Hard))
  2684  	for resource := range resourceQuota.Status.Hard {
  2685  		resources = append(resources, resource)
  2686  	}
  2687  	sort.Sort(SortableResourceNames(resources))
  2688  
  2689  	requestColumn := bytes.NewBuffer([]byte{})
  2690  	limitColumn := bytes.NewBuffer([]byte{})
  2691  	for i := range resources {
  2692  		w := requestColumn
  2693  		resource := resources[i]
  2694  		usedQuantity := resourceQuota.Status.Used[resource]
  2695  		hardQuantity := resourceQuota.Status.Hard[resource]
  2696  
  2697  		// use limitColumn writer if a resource name prefixed with "limits" is found
  2698  		if pieces := strings.Split(resource.String(), "."); len(pieces) > 1 && pieces[0] == "limits" {
  2699  			w = limitColumn
  2700  		}
  2701  
  2702  		fmt.Fprintf(w, "%s: %s/%s, ", resource, usedQuantity.String(), hardQuantity.String())
  2703  	}
  2704  
  2705  	age := translateTimestampSince(resourceQuota.CreationTimestamp)
  2706  	row.Cells = append(row.Cells, resourceQuota.Name, age, strings.TrimSuffix(requestColumn.String(), ", "), strings.TrimSuffix(limitColumn.String(), ", "))
  2707  	return []metav1.TableRow{row}, nil
  2708  }
  2709  
  2710  func printResourceQuotaList(list *api.ResourceQuotaList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2711  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2712  	for i := range list.Items {
  2713  		r, err := printResourceQuota(&list.Items[i], options)
  2714  		if err != nil {
  2715  			return nil, err
  2716  		}
  2717  		rows = append(rows, r...)
  2718  	}
  2719  	return rows, nil
  2720  }
  2721  
  2722  func printPriorityClass(obj *scheduling.PriorityClass, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2723  	row := metav1.TableRow{
  2724  		Object: runtime.RawExtension{Object: obj},
  2725  	}
  2726  
  2727  	name := obj.Name
  2728  	value := obj.Value
  2729  	globalDefault := obj.GlobalDefault
  2730  	row.Cells = append(row.Cells, name, int64(value), globalDefault, translateTimestampSince(obj.CreationTimestamp))
  2731  
  2732  	return []metav1.TableRow{row}, nil
  2733  }
  2734  
  2735  func printPriorityClassList(list *scheduling.PriorityClassList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2736  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2737  	for i := range list.Items {
  2738  		r, err := printPriorityClass(&list.Items[i], options)
  2739  		if err != nil {
  2740  			return nil, err
  2741  		}
  2742  		rows = append(rows, r...)
  2743  	}
  2744  	return rows, nil
  2745  }
  2746  
  2747  func printRuntimeClass(obj *nodeapi.RuntimeClass, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2748  	row := metav1.TableRow{
  2749  		Object: runtime.RawExtension{Object: obj},
  2750  	}
  2751  
  2752  	name := obj.Name
  2753  	handler := obj.Handler
  2754  	row.Cells = append(row.Cells, name, handler, translateTimestampSince(obj.CreationTimestamp))
  2755  
  2756  	return []metav1.TableRow{row}, nil
  2757  }
  2758  
  2759  func printRuntimeClassList(list *nodeapi.RuntimeClassList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2760  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2761  	for i := range list.Items {
  2762  		r, err := printRuntimeClass(&list.Items[i], options)
  2763  
  2764  		if err != nil {
  2765  			return nil, err
  2766  		}
  2767  		rows = append(rows, r...)
  2768  	}
  2769  	return rows, nil
  2770  }
  2771  
  2772  func printVolumeAttachment(obj *storage.VolumeAttachment, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2773  	row := metav1.TableRow{
  2774  		Object: runtime.RawExtension{Object: obj},
  2775  	}
  2776  
  2777  	name := obj.Name
  2778  	pvName := ""
  2779  	if obj.Spec.Source.PersistentVolumeName != nil {
  2780  		pvName = *obj.Spec.Source.PersistentVolumeName
  2781  	}
  2782  	row.Cells = append(row.Cells, name, obj.Spec.Attacher, pvName, obj.Spec.NodeName, obj.Status.Attached, translateTimestampSince(obj.CreationTimestamp))
  2783  
  2784  	return []metav1.TableRow{row}, nil
  2785  }
  2786  
  2787  func printVolumeAttachmentList(list *storage.VolumeAttachmentList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2788  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2789  	for i := range list.Items {
  2790  		r, err := printVolumeAttachment(&list.Items[i], options)
  2791  		if err != nil {
  2792  			return nil, err
  2793  		}
  2794  		rows = append(rows, r...)
  2795  	}
  2796  	return rows, nil
  2797  }
  2798  
  2799  func printFlowSchema(obj *flowcontrol.FlowSchema, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2800  	row := metav1.TableRow{
  2801  		Object: runtime.RawExtension{Object: obj},
  2802  	}
  2803  
  2804  	name := obj.Name
  2805  	plName := obj.Spec.PriorityLevelConfiguration.Name
  2806  	distinguisherMethod := "<none>"
  2807  	if obj.Spec.DistinguisherMethod != nil {
  2808  		distinguisherMethod = string(obj.Spec.DistinguisherMethod.Type)
  2809  	}
  2810  	badPLRef := "?"
  2811  	for _, cond := range obj.Status.Conditions {
  2812  		if cond.Type == flowcontrol.FlowSchemaConditionDangling {
  2813  			badPLRef = string(cond.Status)
  2814  			break
  2815  		}
  2816  	}
  2817  	row.Cells = append(row.Cells, name, plName, int64(obj.Spec.MatchingPrecedence), distinguisherMethod, translateTimestampSince(obj.CreationTimestamp), badPLRef)
  2818  
  2819  	return []metav1.TableRow{row}, nil
  2820  }
  2821  
  2822  func printFlowSchemaList(list *flowcontrol.FlowSchemaList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2823  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2824  	fsSeq := make(apihelpers.FlowSchemaSequence, len(list.Items))
  2825  	for i := range list.Items {
  2826  		fsSeq[i] = &list.Items[i]
  2827  	}
  2828  	sort.Sort(fsSeq)
  2829  	for i := range fsSeq {
  2830  		r, err := printFlowSchema(fsSeq[i], options)
  2831  		if err != nil {
  2832  			return nil, err
  2833  		}
  2834  		rows = append(rows, r...)
  2835  	}
  2836  	return rows, nil
  2837  }
  2838  
  2839  func printStorageVersion(obj *apiserverinternal.StorageVersion, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2840  	row := metav1.TableRow{
  2841  		Object: runtime.RawExtension{Object: obj},
  2842  	}
  2843  	commonEncodingVersion := "<unset>"
  2844  	if obj.Status.CommonEncodingVersion != nil {
  2845  		commonEncodingVersion = *obj.Status.CommonEncodingVersion
  2846  	}
  2847  	row.Cells = append(row.Cells, obj.Name, commonEncodingVersion, formatStorageVersions(obj.Status.StorageVersions), translateTimestampSince(obj.CreationTimestamp))
  2848  	return []metav1.TableRow{row}, nil
  2849  }
  2850  
  2851  func formatStorageVersions(storageVersions []apiserverinternal.ServerStorageVersion) string {
  2852  	list := []string{}
  2853  	max := 3
  2854  	more := false
  2855  	count := 0
  2856  	for _, sv := range storageVersions {
  2857  		if len(list) < max {
  2858  			list = append(list, fmt.Sprintf("%s=%s", sv.APIServerID, sv.EncodingVersion))
  2859  		} else if len(list) == max {
  2860  			more = true
  2861  		}
  2862  		count++
  2863  	}
  2864  	return listWithMoreString(list, more, count, max)
  2865  }
  2866  
  2867  func printStorageVersionList(list *apiserverinternal.StorageVersionList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2868  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2869  	for i := range list.Items {
  2870  		r, err := printStorageVersion(&list.Items[i], options)
  2871  		if err != nil {
  2872  			return nil, err
  2873  		}
  2874  		rows = append(rows, r...)
  2875  	}
  2876  	return rows, nil
  2877  }
  2878  
  2879  func printPriorityLevelConfiguration(obj *flowcontrol.PriorityLevelConfiguration, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2880  	row := metav1.TableRow{
  2881  		Object: runtime.RawExtension{Object: obj},
  2882  	}
  2883  	name := obj.Name
  2884  	ncs := interface{}("<none>")
  2885  	queues := interface{}("<none>")
  2886  	handSize := interface{}("<none>")
  2887  	queueLengthLimit := interface{}("<none>")
  2888  	if obj.Spec.Limited != nil {
  2889  		ncs = obj.Spec.Limited.NominalConcurrencyShares
  2890  		if qc := obj.Spec.Limited.LimitResponse.Queuing; qc != nil {
  2891  			queues = qc.Queues
  2892  			handSize = qc.HandSize
  2893  			queueLengthLimit = qc.QueueLengthLimit
  2894  		}
  2895  	}
  2896  	row.Cells = append(row.Cells, name, string(obj.Spec.Type), ncs, queues, handSize, queueLengthLimit, translateTimestampSince(obj.CreationTimestamp))
  2897  
  2898  	return []metav1.TableRow{row}, nil
  2899  }
  2900  
  2901  func printPriorityLevelConfigurationList(list *flowcontrol.PriorityLevelConfigurationList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2902  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2903  	for i := range list.Items {
  2904  		r, err := printPriorityLevelConfiguration(&list.Items[i], options)
  2905  		if err != nil {
  2906  			return nil, err
  2907  		}
  2908  		rows = append(rows, r...)
  2909  	}
  2910  	return rows, nil
  2911  }
  2912  
  2913  func printServiceCIDR(obj *networking.ServiceCIDR, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2914  	row := metav1.TableRow{
  2915  		Object: runtime.RawExtension{Object: obj},
  2916  	}
  2917  
  2918  	cidrs := strings.Join(obj.Spec.CIDRs, ",")
  2919  	row.Cells = append(row.Cells, obj.Name, cidrs, translateTimestampSince(obj.CreationTimestamp))
  2920  	return []metav1.TableRow{row}, nil
  2921  }
  2922  
  2923  func printServiceCIDRList(list *networking.ServiceCIDRList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2924  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2925  	for i := range list.Items {
  2926  		r, err := printServiceCIDR(&list.Items[i], options)
  2927  		if err != nil {
  2928  			return nil, err
  2929  		}
  2930  		rows = append(rows, r...)
  2931  	}
  2932  	return rows, nil
  2933  }
  2934  
  2935  func printIPAddress(obj *networking.IPAddress, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2936  	row := metav1.TableRow{
  2937  		Object: runtime.RawExtension{Object: obj},
  2938  	}
  2939  
  2940  	parentRefName := "<none>"
  2941  	if obj.Spec.ParentRef != nil {
  2942  		gr := schema.GroupResource{
  2943  			Group:    obj.Spec.ParentRef.Group,
  2944  			Resource: obj.Spec.ParentRef.Resource,
  2945  		}
  2946  		parentRefName = strings.ToLower(gr.String())
  2947  		if obj.Spec.ParentRef.Namespace != "" {
  2948  			parentRefName += "/" + obj.Spec.ParentRef.Namespace
  2949  		}
  2950  		parentRefName += "/" + obj.Spec.ParentRef.Name
  2951  	}
  2952  	age := translateTimestampSince(obj.CreationTimestamp)
  2953  	row.Cells = append(row.Cells, obj.Name, parentRefName, age)
  2954  
  2955  	return []metav1.TableRow{row}, nil
  2956  }
  2957  
  2958  func printIPAddressList(list *networking.IPAddressList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2959  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2960  	for i := range list.Items {
  2961  		r, err := printIPAddress(&list.Items[i], options)
  2962  		if err != nil {
  2963  			return nil, err
  2964  		}
  2965  		rows = append(rows, r...)
  2966  	}
  2967  	return rows, nil
  2968  }
  2969  
  2970  func printScale(obj *autoscaling.Scale, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2971  	row := metav1.TableRow{
  2972  		Object: runtime.RawExtension{Object: obj},
  2973  	}
  2974  	row.Cells = append(row.Cells, obj.Name, int64(obj.Spec.Replicas), int64(obj.Status.Replicas), translateTimestampSince(obj.CreationTimestamp))
  2975  	return []metav1.TableRow{row}, nil
  2976  }
  2977  
  2978  func printResourceClass(obj *resource.ResourceClass, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2979  	row := metav1.TableRow{
  2980  		Object: runtime.RawExtension{Object: obj},
  2981  	}
  2982  	row.Cells = append(row.Cells, obj.Name, obj.DriverName, translateTimestampSince(obj.CreationTimestamp))
  2983  
  2984  	return []metav1.TableRow{row}, nil
  2985  }
  2986  
  2987  func printResourceClassList(list *resource.ResourceClassList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  2988  	rows := make([]metav1.TableRow, 0, len(list.Items))
  2989  	for i := range list.Items {
  2990  		r, err := printResourceClass(&list.Items[i], options)
  2991  		if err != nil {
  2992  			return nil, err
  2993  		}
  2994  		rows = append(rows, r...)
  2995  	}
  2996  	return rows, nil
  2997  }
  2998  
  2999  func printResourceClaim(obj *resource.ResourceClaim, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  3000  	row := metav1.TableRow{
  3001  		Object: runtime.RawExtension{Object: obj},
  3002  	}
  3003  	row.Cells = append(row.Cells, obj.Name, obj.Spec.ResourceClassName, string(obj.Spec.AllocationMode), resourceClaimState(obj), translateTimestampSince(obj.CreationTimestamp))
  3004  
  3005  	return []metav1.TableRow{row}, nil
  3006  }
  3007  
  3008  func resourceClaimState(obj *resource.ResourceClaim) string {
  3009  	var states []string
  3010  	if obj.DeletionTimestamp != nil {
  3011  		states = append(states, "deleted")
  3012  	}
  3013  	if obj.Status.Allocation == nil {
  3014  		if obj.DeletionTimestamp == nil {
  3015  			states = append(states, "pending")
  3016  		}
  3017  	} else {
  3018  		states = append(states, "allocated")
  3019  		if len(obj.Status.ReservedFor) > 0 {
  3020  			states = append(states, "reserved")
  3021  		} else if obj.DeletionTimestamp != nil || obj.Status.DeallocationRequested {
  3022  			states = append(states, "deallocating")
  3023  		}
  3024  	}
  3025  	return strings.Join(states, ",")
  3026  }
  3027  
  3028  func printResourceClaimList(list *resource.ResourceClaimList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  3029  	rows := make([]metav1.TableRow, 0, len(list.Items))
  3030  	for i := range list.Items {
  3031  		r, err := printResourceClaim(&list.Items[i], options)
  3032  		if err != nil {
  3033  			return nil, err
  3034  		}
  3035  		rows = append(rows, r...)
  3036  	}
  3037  	return rows, nil
  3038  }
  3039  
  3040  func printResourceClaimTemplate(obj *resource.ResourceClaimTemplate, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  3041  	row := metav1.TableRow{
  3042  		Object: runtime.RawExtension{Object: obj},
  3043  	}
  3044  	row.Cells = append(row.Cells, obj.Name, obj.Spec.Spec.ResourceClassName, string(obj.Spec.Spec.AllocationMode), translateTimestampSince(obj.CreationTimestamp))
  3045  
  3046  	return []metav1.TableRow{row}, nil
  3047  }
  3048  
  3049  func printResourceClaimTemplateList(list *resource.ResourceClaimTemplateList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  3050  	rows := make([]metav1.TableRow, 0, len(list.Items))
  3051  	for i := range list.Items {
  3052  		r, err := printResourceClaimTemplate(&list.Items[i], options)
  3053  		if err != nil {
  3054  			return nil, err
  3055  		}
  3056  		rows = append(rows, r...)
  3057  	}
  3058  	return rows, nil
  3059  }
  3060  
  3061  func printPodSchedulingContext(obj *resource.PodSchedulingContext, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  3062  	row := metav1.TableRow{
  3063  		Object: runtime.RawExtension{Object: obj},
  3064  	}
  3065  	row.Cells = append(row.Cells, obj.Name, obj.Spec.SelectedNode, translateTimestampSince(obj.CreationTimestamp))
  3066  
  3067  	return []metav1.TableRow{row}, nil
  3068  }
  3069  
  3070  func printPodSchedulingContextList(list *resource.PodSchedulingContextList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  3071  	rows := make([]metav1.TableRow, 0, len(list.Items))
  3072  	for i := range list.Items {
  3073  		r, err := printPodSchedulingContext(&list.Items[i], options)
  3074  		if err != nil {
  3075  			return nil, err
  3076  		}
  3077  		rows = append(rows, r...)
  3078  	}
  3079  	return rows, nil
  3080  }
  3081  
  3082  func printResourceClaimParameters(obj *resource.ResourceClaimParameters, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  3083  	row := metav1.TableRow{
  3084  		Object: runtime.RawExtension{Object: obj},
  3085  	}
  3086  	generatedFrom := ""
  3087  	if obj.GeneratedFrom != nil {
  3088  		generatedFrom = fmt.Sprintf("%s.%s %s", obj.GeneratedFrom.Kind, obj.GeneratedFrom.APIGroup, obj.GeneratedFrom.Name)
  3089  	}
  3090  	row.Cells = append(row.Cells, obj.Name, generatedFrom, translateTimestampSince(obj.CreationTimestamp))
  3091  
  3092  	return []metav1.TableRow{row}, nil
  3093  }
  3094  
  3095  func printResourceClaimParametersList(list *resource.ResourceClaimParametersList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  3096  	rows := make([]metav1.TableRow, 0, len(list.Items))
  3097  	for i := range list.Items {
  3098  		r, err := printResourceClaimParameters(&list.Items[i], options)
  3099  		if err != nil {
  3100  			return nil, err
  3101  		}
  3102  		rows = append(rows, r...)
  3103  	}
  3104  	return rows, nil
  3105  }
  3106  
  3107  func printResourceClassParameters(obj *resource.ResourceClassParameters, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  3108  	row := metav1.TableRow{
  3109  		Object: runtime.RawExtension{Object: obj},
  3110  	}
  3111  	generatedFrom := ""
  3112  	if obj.GeneratedFrom != nil {
  3113  		generatedFrom = fmt.Sprintf("%s.%s %s", obj.GeneratedFrom.Kind, obj.GeneratedFrom.APIGroup, obj.GeneratedFrom.Name)
  3114  	}
  3115  	row.Cells = append(row.Cells, obj.Name, generatedFrom, translateTimestampSince(obj.CreationTimestamp))
  3116  
  3117  	return []metav1.TableRow{row}, nil
  3118  }
  3119  
  3120  func printResourceClassParametersList(list *resource.ResourceClassParametersList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  3121  	rows := make([]metav1.TableRow, 0, len(list.Items))
  3122  	for i := range list.Items {
  3123  		r, err := printResourceClassParameters(&list.Items[i], options)
  3124  		if err != nil {
  3125  			return nil, err
  3126  		}
  3127  		rows = append(rows, r...)
  3128  	}
  3129  	return rows, nil
  3130  }
  3131  
  3132  func printResourceSlice(obj *resource.ResourceSlice, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  3133  	row := metav1.TableRow{
  3134  		Object: runtime.RawExtension{Object: obj},
  3135  	}
  3136  	row.Cells = append(row.Cells, obj.Name, obj.NodeName, obj.DriverName, translateTimestampSince(obj.CreationTimestamp))
  3137  
  3138  	return []metav1.TableRow{row}, nil
  3139  }
  3140  
  3141  func printResourceSliceList(list *resource.ResourceSliceList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  3142  	rows := make([]metav1.TableRow, 0, len(list.Items))
  3143  	for i := range list.Items {
  3144  		r, err := printResourceSlice(&list.Items[i], options)
  3145  		if err != nil {
  3146  			return nil, err
  3147  		}
  3148  		rows = append(rows, r...)
  3149  	}
  3150  	return rows, nil
  3151  }
  3152  
  3153  func printStorageVersionMigration(obj *svmv1alpha1.StorageVersionMigration, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  3154  	row := metav1.TableRow{
  3155  		Object: runtime.RawExtension{Object: obj},
  3156  	}
  3157  
  3158  	migrationGVR := obj.Spec.Resource.Resource + "." + obj.Spec.Resource.Version + "." + obj.Spec.Resource.Group
  3159  	row.Cells = append(row.Cells, obj.Name, migrationGVR)
  3160  	//ToDo: add migration condition 'status' and 'type' (migration successful | failed)
  3161  
  3162  	return []metav1.TableRow{row}, nil
  3163  }
  3164  
  3165  func printStorageVersionMigrationList(list *svmv1alpha1.StorageVersionMigrationList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
  3166  	rows := make([]metav1.TableRow, 0, len(list.Items))
  3167  
  3168  	for i := range list.Items {
  3169  		r, err := printStorageVersionMigration(&list.Items[i], options)
  3170  		if err != nil {
  3171  			return nil, err
  3172  		}
  3173  		rows = append(rows, r...)
  3174  	}
  3175  	return rows, nil
  3176  }
  3177  
  3178  func printBoolPtr(value *bool) string {
  3179  	if value != nil {
  3180  		return printBool(*value)
  3181  	}
  3182  
  3183  	return "<unset>"
  3184  }
  3185  
  3186  func printBool(value bool) string {
  3187  	if value {
  3188  		return "True"
  3189  	}
  3190  
  3191  	return "False"
  3192  }
  3193  
  3194  // SortableResourceNames - An array of sortable resource names
  3195  type SortableResourceNames []api.ResourceName
  3196  
  3197  func (list SortableResourceNames) Len() int {
  3198  	return len(list)
  3199  }
  3200  
  3201  func (list SortableResourceNames) Swap(i, j int) {
  3202  	list[i], list[j] = list[j], list[i]
  3203  }
  3204  
  3205  func (list SortableResourceNames) Less(i, j int) bool {
  3206  	return list[i] < list[j]
  3207  }
  3208  
  3209  func isRestartableInitContainer(initContainer *api.Container) bool {
  3210  	if initContainer.RestartPolicy == nil {
  3211  		return false
  3212  	}
  3213  
  3214  	return *initContainer.RestartPolicy == api.ContainerRestartPolicyAlways
  3215  }
  3216  
  3217  func isPodInitializedConditionTrue(status *api.PodStatus) bool {
  3218  	for _, condition := range status.Conditions {
  3219  		if condition.Type != api.PodInitialized {
  3220  			continue
  3221  		}
  3222  
  3223  		return condition.Status == api.ConditionTrue
  3224  	}
  3225  	return false
  3226  }
  3227  

View as plain text