k8s.io/kubernetes@v1.29.3/pkg/printers/internalversion/printers.go (about)

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