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