printers.go 81 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046
  1. /*
  2. Copyright 2017 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package internalversion
  14. import (
  15. "bytes"
  16. "fmt"
  17. "net"
  18. "sort"
  19. "strconv"
  20. "strings"
  21. "time"
  22. appsv1beta1 "k8s.io/api/apps/v1beta1"
  23. autoscalingv2beta1 "k8s.io/api/autoscaling/v2beta1"
  24. batchv1 "k8s.io/api/batch/v1"
  25. batchv1beta1 "k8s.io/api/batch/v1beta1"
  26. certificatesv1beta1 "k8s.io/api/certificates/v1beta1"
  27. coordinationv1 "k8s.io/api/coordination/v1"
  28. apiv1 "k8s.io/api/core/v1"
  29. extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
  30. policyv1beta1 "k8s.io/api/policy/v1beta1"
  31. rbacv1beta1 "k8s.io/api/rbac/v1beta1"
  32. schedulingv1 "k8s.io/api/scheduling/v1"
  33. storagev1 "k8s.io/api/storage/v1"
  34. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  35. metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
  36. "k8s.io/apimachinery/pkg/labels"
  37. "k8s.io/apimachinery/pkg/runtime"
  38. "k8s.io/apimachinery/pkg/runtime/schema"
  39. "k8s.io/apimachinery/pkg/util/duration"
  40. "k8s.io/apimachinery/pkg/util/sets"
  41. "k8s.io/kubernetes/pkg/apis/apps"
  42. "k8s.io/kubernetes/pkg/apis/autoscaling"
  43. "k8s.io/kubernetes/pkg/apis/batch"
  44. "k8s.io/kubernetes/pkg/apis/certificates"
  45. "k8s.io/kubernetes/pkg/apis/coordination"
  46. api "k8s.io/kubernetes/pkg/apis/core"
  47. "k8s.io/kubernetes/pkg/apis/core/helper"
  48. "k8s.io/kubernetes/pkg/apis/networking"
  49. nodeapi "k8s.io/kubernetes/pkg/apis/node"
  50. "k8s.io/kubernetes/pkg/apis/policy"
  51. "k8s.io/kubernetes/pkg/apis/rbac"
  52. "k8s.io/kubernetes/pkg/apis/scheduling"
  53. "k8s.io/kubernetes/pkg/apis/storage"
  54. storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
  55. "k8s.io/kubernetes/pkg/printers"
  56. "k8s.io/kubernetes/pkg/util/node"
  57. )
  58. const (
  59. loadBalancerWidth = 16
  60. // labelNodeRolePrefix is a label prefix for node roles
  61. // It's copied over to here until it's merged in core: https://github.com/kubernetes/kubernetes/pull/39112
  62. labelNodeRolePrefix = "node-role.kubernetes.io/"
  63. // nodeLabelRole specifies the role of a node
  64. nodeLabelRole = "kubernetes.io/role"
  65. )
  66. // AddHandlers adds print handlers for default Kubernetes types dealing with internal versions.
  67. // TODO: handle errors from Handler
  68. func AddHandlers(h printers.PrintHandler) {
  69. podColumnDefinitions := []metav1beta1.TableColumnDefinition{
  70. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  71. {Name: "Ready", Type: "string", Description: "The aggregate readiness state of this pod for accepting traffic."},
  72. {Name: "Status", Type: "string", Description: "The aggregate status of the containers in this pod."},
  73. {Name: "Restarts", Type: "integer", Description: "The number of times the containers in this pod have been restarted."},
  74. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  75. {Name: "IP", Type: "string", Priority: 1, Description: apiv1.PodStatus{}.SwaggerDoc()["podIP"]},
  76. {Name: "Node", Type: "string", Priority: 1, Description: apiv1.PodSpec{}.SwaggerDoc()["nodeName"]},
  77. {Name: "Nominated Node", Type: "string", Priority: 1, Description: apiv1.PodStatus{}.SwaggerDoc()["nominatedNodeName"]},
  78. {Name: "Readiness Gates", Type: "string", Priority: 1, Description: apiv1.PodSpec{}.SwaggerDoc()["readinessGates"]},
  79. }
  80. h.TableHandler(podColumnDefinitions, printPodList)
  81. h.TableHandler(podColumnDefinitions, printPod)
  82. podTemplateColumnDefinitions := []metav1beta1.TableColumnDefinition{
  83. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  84. {Name: "Containers", Type: "string", Description: "Names of each container in the template."},
  85. {Name: "Images", Type: "string", Description: "Images referenced by each container in the template."},
  86. {Name: "Pod Labels", Type: "string", Description: "The labels for the pod template."},
  87. }
  88. h.TableHandler(podTemplateColumnDefinitions, printPodTemplate)
  89. h.TableHandler(podTemplateColumnDefinitions, printPodTemplateList)
  90. podDisruptionBudgetColumnDefinitions := []metav1beta1.TableColumnDefinition{
  91. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  92. {Name: "Min Available", Type: "string", Description: "The minimum number of pods that must be available."},
  93. {Name: "Max Unavailable", Type: "string", Description: "The maximum number of pods that may be unavailable."},
  94. {Name: "Allowed Disruptions", Type: "integer", Description: "Calculated number of pods that may be disrupted at this time."},
  95. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  96. }
  97. h.TableHandler(podDisruptionBudgetColumnDefinitions, printPodDisruptionBudget)
  98. h.TableHandler(podDisruptionBudgetColumnDefinitions, printPodDisruptionBudgetList)
  99. replicationControllerColumnDefinitions := []metav1beta1.TableColumnDefinition{
  100. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  101. {Name: "Desired", Type: "integer", Description: apiv1.ReplicationControllerSpec{}.SwaggerDoc()["replicas"]},
  102. {Name: "Current", Type: "integer", Description: apiv1.ReplicationControllerStatus{}.SwaggerDoc()["replicas"]},
  103. {Name: "Ready", Type: "integer", Description: apiv1.ReplicationControllerStatus{}.SwaggerDoc()["readyReplicas"]},
  104. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  105. {Name: "Containers", Type: "string", Priority: 1, Description: "Names of each container in the template."},
  106. {Name: "Images", Type: "string", Priority: 1, Description: "Images referenced by each container in the template."},
  107. {Name: "Selector", Type: "string", Priority: 1, Description: apiv1.ReplicationControllerSpec{}.SwaggerDoc()["selector"]},
  108. }
  109. h.TableHandler(replicationControllerColumnDefinitions, printReplicationController)
  110. h.TableHandler(replicationControllerColumnDefinitions, printReplicationControllerList)
  111. replicaSetColumnDefinitions := []metav1beta1.TableColumnDefinition{
  112. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  113. {Name: "Desired", Type: "integer", Description: extensionsv1beta1.ReplicaSetSpec{}.SwaggerDoc()["replicas"]},
  114. {Name: "Current", Type: "integer", Description: extensionsv1beta1.ReplicaSetStatus{}.SwaggerDoc()["replicas"]},
  115. {Name: "Ready", Type: "integer", Description: extensionsv1beta1.ReplicaSetStatus{}.SwaggerDoc()["readyReplicas"]},
  116. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  117. {Name: "Containers", Type: "string", Priority: 1, Description: "Names of each container in the template."},
  118. {Name: "Images", Type: "string", Priority: 1, Description: "Images referenced by each container in the template."},
  119. {Name: "Selector", Type: "string", Priority: 1, Description: extensionsv1beta1.ReplicaSetSpec{}.SwaggerDoc()["selector"]},
  120. }
  121. h.TableHandler(replicaSetColumnDefinitions, printReplicaSet)
  122. h.TableHandler(replicaSetColumnDefinitions, printReplicaSetList)
  123. daemonSetColumnDefinitions := []metav1beta1.TableColumnDefinition{
  124. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  125. {Name: "Desired", Type: "integer", Description: extensionsv1beta1.DaemonSetStatus{}.SwaggerDoc()["desiredNumberScheduled"]},
  126. {Name: "Current", Type: "integer", Description: extensionsv1beta1.DaemonSetStatus{}.SwaggerDoc()["currentNumberScheduled"]},
  127. {Name: "Ready", Type: "integer", Description: extensionsv1beta1.DaemonSetStatus{}.SwaggerDoc()["numberReady"]},
  128. {Name: "Up-to-date", Type: "integer", Description: extensionsv1beta1.DaemonSetStatus{}.SwaggerDoc()["updatedNumberScheduled"]},
  129. {Name: "Available", Type: "integer", Description: extensionsv1beta1.DaemonSetStatus{}.SwaggerDoc()["numberAvailable"]},
  130. {Name: "Node Selector", Type: "string", Description: apiv1.PodSpec{}.SwaggerDoc()["nodeSelector"]},
  131. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  132. {Name: "Containers", Type: "string", Priority: 1, Description: "Names of each container in the template."},
  133. {Name: "Images", Type: "string", Priority: 1, Description: "Images referenced by each container in the template."},
  134. {Name: "Selector", Type: "string", Priority: 1, Description: extensionsv1beta1.DaemonSetSpec{}.SwaggerDoc()["selector"]},
  135. }
  136. h.TableHandler(daemonSetColumnDefinitions, printDaemonSet)
  137. h.TableHandler(daemonSetColumnDefinitions, printDaemonSetList)
  138. jobColumnDefinitions := []metav1beta1.TableColumnDefinition{
  139. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  140. {Name: "Completions", Type: "string", Description: batchv1.JobStatus{}.SwaggerDoc()["succeeded"]},
  141. {Name: "Duration", Type: "string", Description: "Time required to complete the job."},
  142. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  143. {Name: "Containers", Type: "string", Priority: 1, Description: "Names of each container in the template."},
  144. {Name: "Images", Type: "string", Priority: 1, Description: "Images referenced by each container in the template."},
  145. {Name: "Selector", Type: "string", Priority: 1, Description: batchv1.JobSpec{}.SwaggerDoc()["selector"]},
  146. }
  147. h.TableHandler(jobColumnDefinitions, printJob)
  148. h.TableHandler(jobColumnDefinitions, printJobList)
  149. cronJobColumnDefinitions := []metav1beta1.TableColumnDefinition{
  150. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  151. {Name: "Schedule", Type: "string", Description: batchv1beta1.CronJobSpec{}.SwaggerDoc()["schedule"]},
  152. {Name: "Suspend", Type: "boolean", Description: batchv1beta1.CronJobSpec{}.SwaggerDoc()["suspend"]},
  153. {Name: "Active", Type: "integer", Description: batchv1beta1.CronJobStatus{}.SwaggerDoc()["active"]},
  154. {Name: "Last Schedule", Type: "string", Description: batchv1beta1.CronJobStatus{}.SwaggerDoc()["lastScheduleTime"]},
  155. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  156. {Name: "Containers", Type: "string", Priority: 1, Description: "Names of each container in the template."},
  157. {Name: "Images", Type: "string", Priority: 1, Description: "Images referenced by each container in the template."},
  158. {Name: "Selector", Type: "string", Priority: 1, Description: batchv1.JobSpec{}.SwaggerDoc()["selector"]},
  159. }
  160. h.TableHandler(cronJobColumnDefinitions, printCronJob)
  161. h.TableHandler(cronJobColumnDefinitions, printCronJobList)
  162. serviceColumnDefinitions := []metav1beta1.TableColumnDefinition{
  163. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  164. {Name: "Type", Type: "string", Description: apiv1.ServiceSpec{}.SwaggerDoc()["type"]},
  165. {Name: "Cluster-IP", Type: "string", Description: apiv1.ServiceSpec{}.SwaggerDoc()["clusterIP"]},
  166. {Name: "External-IP", Type: "string", Description: apiv1.ServiceSpec{}.SwaggerDoc()["externalIPs"]},
  167. {Name: "Port(s)", Type: "string", Description: apiv1.ServiceSpec{}.SwaggerDoc()["ports"]},
  168. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  169. {Name: "Selector", Type: "string", Priority: 1, Description: apiv1.ServiceSpec{}.SwaggerDoc()["selector"]},
  170. }
  171. h.TableHandler(serviceColumnDefinitions, printService)
  172. h.TableHandler(serviceColumnDefinitions, printServiceList)
  173. ingressColumnDefinitions := []metav1beta1.TableColumnDefinition{
  174. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  175. {Name: "Hosts", Type: "string", Description: "Hosts that incoming requests are matched against before the ingress rule"},
  176. {Name: "Address", Type: "string", Description: "Address is a list containing ingress points for the load-balancer"},
  177. {Name: "Ports", Type: "string", Description: "Ports of TLS configurations that open"},
  178. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  179. }
  180. h.TableHandler(ingressColumnDefinitions, printIngress)
  181. h.TableHandler(ingressColumnDefinitions, printIngressList)
  182. statefulSetColumnDefinitions := []metav1beta1.TableColumnDefinition{
  183. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  184. {Name: "Ready", Type: "string", Description: "Number of the pod with ready state"},
  185. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  186. {Name: "Containers", Type: "string", Priority: 1, Description: "Names of each container in the template."},
  187. {Name: "Images", Type: "string", Priority: 1, Description: "Images referenced by each container in the template."},
  188. }
  189. h.TableHandler(statefulSetColumnDefinitions, printStatefulSet)
  190. h.TableHandler(statefulSetColumnDefinitions, printStatefulSetList)
  191. endpointColumnDefinitions := []metav1beta1.TableColumnDefinition{
  192. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  193. {Name: "Endpoints", Type: "string", Description: apiv1.Endpoints{}.SwaggerDoc()["subsets"]},
  194. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  195. }
  196. h.TableHandler(endpointColumnDefinitions, printEndpoints)
  197. h.TableHandler(endpointColumnDefinitions, printEndpointsList)
  198. nodeColumnDefinitions := []metav1beta1.TableColumnDefinition{
  199. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  200. {Name: "Status", Type: "string", Description: "The status of the node"},
  201. {Name: "Roles", Type: "string", Description: "The roles of the node"},
  202. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  203. {Name: "Version", Type: "string", Description: apiv1.NodeSystemInfo{}.SwaggerDoc()["kubeletVersion"]},
  204. {Name: "Internal-IP", Type: "string", Priority: 1, Description: apiv1.NodeStatus{}.SwaggerDoc()["addresses"]},
  205. {Name: "External-IP", Type: "string", Priority: 1, Description: apiv1.NodeStatus{}.SwaggerDoc()["addresses"]},
  206. {Name: "OS-Image", Type: "string", Priority: 1, Description: apiv1.NodeSystemInfo{}.SwaggerDoc()["osImage"]},
  207. {Name: "Kernel-Version", Type: "string", Priority: 1, Description: apiv1.NodeSystemInfo{}.SwaggerDoc()["kernelVersion"]},
  208. {Name: "Container-Runtime", Type: "string", Priority: 1, Description: apiv1.NodeSystemInfo{}.SwaggerDoc()["containerRuntimeVersion"]},
  209. }
  210. h.TableHandler(nodeColumnDefinitions, printNode)
  211. h.TableHandler(nodeColumnDefinitions, printNodeList)
  212. eventColumnDefinitions := []metav1beta1.TableColumnDefinition{
  213. {Name: "Last Seen", Type: "string", Description: apiv1.Event{}.SwaggerDoc()["lastTimestamp"]},
  214. {Name: "Type", Type: "string", Description: apiv1.Event{}.SwaggerDoc()["type"]},
  215. {Name: "Reason", Type: "string", Description: apiv1.Event{}.SwaggerDoc()["reason"]},
  216. {Name: "Object", Type: "string", Description: apiv1.Event{}.SwaggerDoc()["involvedObject"]},
  217. {Name: "Subobject", Type: "string", Priority: 1, Description: apiv1.Event{}.InvolvedObject.SwaggerDoc()["fieldPath"]},
  218. {Name: "Source", Type: "string", Priority: 1, Description: apiv1.Event{}.SwaggerDoc()["source"]},
  219. {Name: "Message", Type: "string", Description: apiv1.Event{}.SwaggerDoc()["message"]},
  220. {Name: "First Seen", Type: "string", Priority: 1, Description: apiv1.Event{}.SwaggerDoc()["firstTimestamp"]},
  221. {Name: "Count", Type: "string", Priority: 1, Description: apiv1.Event{}.SwaggerDoc()["count"]},
  222. {Name: "Name", Type: "string", Priority: 1, Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  223. }
  224. h.TableHandler(eventColumnDefinitions, printEvent)
  225. h.TableHandler(eventColumnDefinitions, printEventList)
  226. namespaceColumnDefinitions := []metav1beta1.TableColumnDefinition{
  227. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  228. {Name: "Status", Type: "string", Description: "The status of the namespace"},
  229. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  230. }
  231. h.TableHandler(namespaceColumnDefinitions, printNamespace)
  232. h.TableHandler(namespaceColumnDefinitions, printNamespaceList)
  233. secretColumnDefinitions := []metav1beta1.TableColumnDefinition{
  234. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  235. {Name: "Type", Type: "string", Description: apiv1.Secret{}.SwaggerDoc()["type"]},
  236. {Name: "Data", Type: "string", Description: apiv1.Secret{}.SwaggerDoc()["data"]},
  237. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  238. }
  239. h.TableHandler(secretColumnDefinitions, printSecret)
  240. h.TableHandler(secretColumnDefinitions, printSecretList)
  241. serviceAccountColumnDefinitions := []metav1beta1.TableColumnDefinition{
  242. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  243. {Name: "Secrets", Type: "string", Description: apiv1.ServiceAccount{}.SwaggerDoc()["secrets"]},
  244. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  245. }
  246. h.TableHandler(serviceAccountColumnDefinitions, printServiceAccount)
  247. h.TableHandler(serviceAccountColumnDefinitions, printServiceAccountList)
  248. persistentVolumeColumnDefinitions := []metav1beta1.TableColumnDefinition{
  249. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  250. {Name: "Capacity", Type: "string", Description: apiv1.PersistentVolumeSpec{}.SwaggerDoc()["capacity"]},
  251. {Name: "Access Modes", Type: "string", Description: apiv1.PersistentVolumeSpec{}.SwaggerDoc()["accessModes"]},
  252. {Name: "Reclaim Policy", Type: "string", Description: apiv1.PersistentVolumeSpec{}.SwaggerDoc()["persistentVolumeReclaimPolicy"]},
  253. {Name: "Status", Type: "string", Description: apiv1.PersistentVolumeStatus{}.SwaggerDoc()["phase"]},
  254. {Name: "Claim", Type: "string", Description: apiv1.PersistentVolumeSpec{}.SwaggerDoc()["claimRef"]},
  255. {Name: "StorageClass", Type: "string", Description: "StorageClass of the pv"},
  256. {Name: "Reason", Type: "string", Description: apiv1.PersistentVolumeStatus{}.SwaggerDoc()["reason"]},
  257. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  258. {Name: "VolumeMode", Type: "string", Priority: 1, Description: apiv1.PersistentVolumeSpec{}.SwaggerDoc()["volumeMode"]},
  259. }
  260. h.TableHandler(persistentVolumeColumnDefinitions, printPersistentVolume)
  261. h.TableHandler(persistentVolumeColumnDefinitions, printPersistentVolumeList)
  262. persistentVolumeClaimColumnDefinitions := []metav1beta1.TableColumnDefinition{
  263. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  264. {Name: "Status", Type: "string", Description: apiv1.PersistentVolumeClaimStatus{}.SwaggerDoc()["phase"]},
  265. {Name: "Volume", Type: "string", Description: apiv1.PersistentVolumeClaimSpec{}.SwaggerDoc()["volumeName"]},
  266. {Name: "Capacity", Type: "string", Description: apiv1.PersistentVolumeClaimStatus{}.SwaggerDoc()["capacity"]},
  267. {Name: "Access Modes", Type: "string", Description: apiv1.PersistentVolumeClaimStatus{}.SwaggerDoc()["accessModes"]},
  268. {Name: "StorageClass", Type: "string", Description: "StorageClass of the pvc"},
  269. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  270. {Name: "VolumeMode", Type: "string", Priority: 1, Description: apiv1.PersistentVolumeClaimSpec{}.SwaggerDoc()["volumeMode"]},
  271. }
  272. h.TableHandler(persistentVolumeClaimColumnDefinitions, printPersistentVolumeClaim)
  273. h.TableHandler(persistentVolumeClaimColumnDefinitions, printPersistentVolumeClaimList)
  274. componentStatusColumnDefinitions := []metav1beta1.TableColumnDefinition{
  275. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  276. {Name: "Status", Type: "string", Description: "Status of the component conditions"},
  277. {Name: "Message", Type: "string", Description: "Message of the component conditions"},
  278. {Name: "Error", Type: "string", Description: "Error of the component conditions"},
  279. }
  280. h.TableHandler(componentStatusColumnDefinitions, printComponentStatus)
  281. h.TableHandler(componentStatusColumnDefinitions, printComponentStatusList)
  282. deploymentColumnDefinitions := []metav1beta1.TableColumnDefinition{
  283. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  284. {Name: "Ready", Type: "string", Description: "Number of the pod with ready state"},
  285. {Name: "Up-to-date", Type: "string", Description: extensionsv1beta1.DeploymentStatus{}.SwaggerDoc()["updatedReplicas"]},
  286. {Name: "Available", Type: "string", Description: extensionsv1beta1.DeploymentStatus{}.SwaggerDoc()["availableReplicas"]},
  287. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  288. {Name: "Containers", Type: "string", Priority: 1, Description: "Names of each container in the template."},
  289. {Name: "Images", Type: "string", Priority: 1, Description: "Images referenced by each container in the template."},
  290. {Name: "Selector", Type: "string", Priority: 1, Description: extensionsv1beta1.DeploymentSpec{}.SwaggerDoc()["selector"]},
  291. }
  292. h.TableHandler(deploymentColumnDefinitions, printDeployment)
  293. h.TableHandler(deploymentColumnDefinitions, printDeploymentList)
  294. horizontalPodAutoscalerColumnDefinitions := []metav1beta1.TableColumnDefinition{
  295. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  296. {Name: "Reference", Type: "string", Description: autoscalingv2beta1.HorizontalPodAutoscalerSpec{}.SwaggerDoc()["scaleTargetRef"]},
  297. {Name: "Targets", Type: "string", Description: autoscalingv2beta1.HorizontalPodAutoscalerSpec{}.SwaggerDoc()["metrics"]},
  298. {Name: "MinPods", Type: "string", Description: autoscalingv2beta1.HorizontalPodAutoscalerSpec{}.SwaggerDoc()["minReplicas"]},
  299. {Name: "MaxPods", Type: "string", Description: autoscalingv2beta1.HorizontalPodAutoscalerSpec{}.SwaggerDoc()["maxReplicas"]},
  300. {Name: "Replicas", Type: "string", Description: autoscalingv2beta1.HorizontalPodAutoscalerStatus{}.SwaggerDoc()["currentReplicas"]},
  301. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  302. }
  303. h.TableHandler(horizontalPodAutoscalerColumnDefinitions, printHorizontalPodAutoscaler)
  304. h.TableHandler(horizontalPodAutoscalerColumnDefinitions, printHorizontalPodAutoscalerList)
  305. configMapColumnDefinitions := []metav1beta1.TableColumnDefinition{
  306. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  307. {Name: "Data", Type: "string", Description: apiv1.ConfigMap{}.SwaggerDoc()["data"]},
  308. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  309. }
  310. h.TableHandler(configMapColumnDefinitions, printConfigMap)
  311. h.TableHandler(configMapColumnDefinitions, printConfigMapList)
  312. podSecurityPolicyColumnDefinitions := []metav1beta1.TableColumnDefinition{
  313. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  314. {Name: "Priv", Type: "string", Description: policyv1beta1.PodSecurityPolicySpec{}.SwaggerDoc()["privileged"]},
  315. {Name: "Caps", Type: "string", Description: policyv1beta1.PodSecurityPolicySpec{}.SwaggerDoc()["allowedCapabilities"]},
  316. {Name: "SELinux", Type: "string", Description: policyv1beta1.PodSecurityPolicySpec{}.SwaggerDoc()["seLinux"]},
  317. {Name: "RunAsUser", Type: "string", Description: policyv1beta1.PodSecurityPolicySpec{}.SwaggerDoc()["runAsUser"]},
  318. {Name: "FsGroup", Type: "string", Description: policyv1beta1.PodSecurityPolicySpec{}.SwaggerDoc()["fsGroup"]},
  319. {Name: "SupGroup", Type: "string", Description: policyv1beta1.PodSecurityPolicySpec{}.SwaggerDoc()["supplementalGroups"]},
  320. {Name: "ReadOnlyRootFs", Type: "string", Description: policyv1beta1.PodSecurityPolicySpec{}.SwaggerDoc()["readOnlyRootFilesystem"]},
  321. {Name: "Volumes", Type: "string", Description: policyv1beta1.PodSecurityPolicySpec{}.SwaggerDoc()["volumes"]},
  322. }
  323. h.TableHandler(podSecurityPolicyColumnDefinitions, printPodSecurityPolicy)
  324. h.TableHandler(podSecurityPolicyColumnDefinitions, printPodSecurityPolicyList)
  325. networkPolicyColumnDefinitioins := []metav1beta1.TableColumnDefinition{
  326. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  327. {Name: "Pod-Selector", Type: "string", Description: extensionsv1beta1.NetworkPolicySpec{}.SwaggerDoc()["podSelector"]},
  328. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  329. }
  330. h.TableHandler(networkPolicyColumnDefinitioins, printNetworkPolicy)
  331. h.TableHandler(networkPolicyColumnDefinitioins, printNetworkPolicyList)
  332. roleBindingsColumnDefinitions := []metav1beta1.TableColumnDefinition{
  333. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  334. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  335. {Name: "Role", Type: "string", Priority: 1, Description: rbacv1beta1.RoleBinding{}.SwaggerDoc()["roleRef"]},
  336. {Name: "Users", Type: "string", Priority: 1, Description: "Users in the roleBinding"},
  337. {Name: "Groups", Type: "string", Priority: 1, Description: "Groups in the roleBinding"},
  338. {Name: "ServiceAccounts", Type: "string", Priority: 1, Description: "ServiceAccounts in the roleBinding"},
  339. }
  340. h.TableHandler(roleBindingsColumnDefinitions, printRoleBinding)
  341. h.TableHandler(roleBindingsColumnDefinitions, printRoleBindingList)
  342. clusterRoleBindingsColumnDefinitions := []metav1beta1.TableColumnDefinition{
  343. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  344. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  345. {Name: "Role", Type: "string", Priority: 1, Description: rbacv1beta1.ClusterRoleBinding{}.SwaggerDoc()["roleRef"]},
  346. {Name: "Users", Type: "string", Priority: 1, Description: "Users in the clusterRoleBinding"},
  347. {Name: "Groups", Type: "string", Priority: 1, Description: "Groups in the clusterRoleBinding"},
  348. {Name: "ServiceAccounts", Type: "string", Priority: 1, Description: "ServiceAccounts in the clusterRoleBinding"},
  349. }
  350. h.TableHandler(clusterRoleBindingsColumnDefinitions, printClusterRoleBinding)
  351. h.TableHandler(clusterRoleBindingsColumnDefinitions, printClusterRoleBindingList)
  352. certificateSigningRequestColumnDefinitions := []metav1beta1.TableColumnDefinition{
  353. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  354. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  355. {Name: "Requestor", Type: "string", Description: certificatesv1beta1.CertificateSigningRequestSpec{}.SwaggerDoc()["request"]},
  356. {Name: "Condition", Type: "string", Description: certificatesv1beta1.CertificateSigningRequestStatus{}.SwaggerDoc()["conditions"]},
  357. }
  358. h.TableHandler(certificateSigningRequestColumnDefinitions, printCertificateSigningRequest)
  359. h.TableHandler(certificateSigningRequestColumnDefinitions, printCertificateSigningRequestList)
  360. leaseColumnDefinitions := []metav1beta1.TableColumnDefinition{
  361. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  362. {Name: "Holder", Type: "string", Description: coordinationv1.LeaseSpec{}.SwaggerDoc()["holderIdentity"]},
  363. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  364. }
  365. h.TableHandler(leaseColumnDefinitions, printLease)
  366. h.TableHandler(leaseColumnDefinitions, printLeaseList)
  367. storageClassColumnDefinitions := []metav1beta1.TableColumnDefinition{
  368. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  369. {Name: "Provisioner", Type: "string", Description: storagev1.StorageClass{}.SwaggerDoc()["provisioner"]},
  370. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  371. }
  372. h.TableHandler(storageClassColumnDefinitions, printStorageClass)
  373. h.TableHandler(storageClassColumnDefinitions, printStorageClassList)
  374. statusColumnDefinitions := []metav1beta1.TableColumnDefinition{
  375. {Name: "Status", Type: "string", Description: metav1.Status{}.SwaggerDoc()["status"]},
  376. {Name: "Reason", Type: "string", Description: metav1.Status{}.SwaggerDoc()["reason"]},
  377. {Name: "Message", Type: "string", Description: metav1.Status{}.SwaggerDoc()["Message"]},
  378. }
  379. h.TableHandler(statusColumnDefinitions, printStatus)
  380. controllerRevisionColumnDefinition := []metav1beta1.TableColumnDefinition{
  381. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  382. {Name: "Controller", Type: "string", Description: "Controller of the object"},
  383. {Name: "Revision", Type: "string", Description: appsv1beta1.ControllerRevision{}.SwaggerDoc()["revision"]},
  384. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  385. }
  386. h.TableHandler(controllerRevisionColumnDefinition, printControllerRevision)
  387. h.TableHandler(controllerRevisionColumnDefinition, printControllerRevisionList)
  388. resourceQuotaColumnDefinitions := []metav1beta1.TableColumnDefinition{
  389. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  390. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  391. {Name: "Request", Type: "string", Description: "Request represents a minimum amount of cpu/memory that a container may consume."},
  392. {Name: "Limit", Type: "string", Description: "Limits control the maximum amount of cpu/memory that a container may use independent of contention on the node."},
  393. }
  394. h.TableHandler(resourceQuotaColumnDefinitions, printResourceQuota)
  395. h.TableHandler(resourceQuotaColumnDefinitions, printResourceQuotaList)
  396. priorityClassColumnDefinitions := []metav1beta1.TableColumnDefinition{
  397. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  398. {Name: "Value", Type: "integer", Description: schedulingv1.PriorityClass{}.SwaggerDoc()["value"]},
  399. {Name: "Global-Default", Type: "boolean", Description: schedulingv1.PriorityClass{}.SwaggerDoc()["globalDefault"]},
  400. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  401. }
  402. h.TableHandler(priorityClassColumnDefinitions, printPriorityClass)
  403. h.TableHandler(priorityClassColumnDefinitions, printPriorityClassList)
  404. runtimeClassColumnDefinitions := []metav1beta1.TableColumnDefinition{
  405. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  406. {Name: "Handler", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["handler"]},
  407. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  408. }
  409. h.TableHandler(runtimeClassColumnDefinitions, printRuntimeClass)
  410. h.TableHandler(runtimeClassColumnDefinitions, printRuntimeClassList)
  411. volumeAttachmentColumnDefinitions := []metav1beta1.TableColumnDefinition{
  412. {Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
  413. {Name: "Attacher", Type: "string", Format: "name", Description: storagev1.VolumeAttachmentSpec{}.SwaggerDoc()["attacher"]},
  414. {Name: "PV", Type: "string", Description: storagev1.VolumeAttachmentSource{}.SwaggerDoc()["persistentVolumeName"]},
  415. {Name: "Node", Type: "string", Description: storagev1.VolumeAttachmentSpec{}.SwaggerDoc()["nodeName"]},
  416. {Name: "Attached", Type: "boolean", Description: storagev1.VolumeAttachmentStatus{}.SwaggerDoc()["attached"]},
  417. {Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
  418. }
  419. h.TableHandler(volumeAttachmentColumnDefinitions, printVolumeAttachment)
  420. h.TableHandler(volumeAttachmentColumnDefinitions, printVolumeAttachmentList)
  421. }
  422. // Pass ports=nil for all ports.
  423. func formatEndpoints(endpoints *api.Endpoints, ports sets.String) string {
  424. if len(endpoints.Subsets) == 0 {
  425. return "<none>"
  426. }
  427. list := []string{}
  428. max := 3
  429. more := false
  430. count := 0
  431. for i := range endpoints.Subsets {
  432. ss := &endpoints.Subsets[i]
  433. if len(ss.Ports) == 0 {
  434. // It's possible to have headless services with no ports.
  435. for i := range ss.Addresses {
  436. if len(list) == max {
  437. more = true
  438. }
  439. if !more {
  440. list = append(list, ss.Addresses[i].IP)
  441. }
  442. count++
  443. }
  444. } else {
  445. // "Normal" services with ports defined.
  446. for i := range ss.Ports {
  447. port := &ss.Ports[i]
  448. if ports == nil || ports.Has(port.Name) {
  449. for i := range ss.Addresses {
  450. if len(list) == max {
  451. more = true
  452. }
  453. addr := &ss.Addresses[i]
  454. if !more {
  455. hostPort := net.JoinHostPort(addr.IP, strconv.Itoa(int(port.Port)))
  456. list = append(list, hostPort)
  457. }
  458. count++
  459. }
  460. }
  461. }
  462. }
  463. }
  464. ret := strings.Join(list, ",")
  465. if more {
  466. return fmt.Sprintf("%s + %d more...", ret, count-max)
  467. }
  468. return ret
  469. }
  470. // translateTimestampSince returns the elapsed time since timestamp in
  471. // human-readable approximation.
  472. func translateTimestampSince(timestamp metav1.Time) string {
  473. if timestamp.IsZero() {
  474. return "<unknown>"
  475. }
  476. return duration.HumanDuration(time.Since(timestamp.Time))
  477. }
  478. // translateTimestampUntil returns the elapsed time until timestamp in
  479. // human-readable approximation.
  480. func translateTimestampUntil(timestamp metav1.Time) string {
  481. if timestamp.IsZero() {
  482. return "<unknown>"
  483. }
  484. return duration.HumanDuration(time.Until(timestamp.Time))
  485. }
  486. var (
  487. podSuccessConditions = []metav1.TableRowCondition{{Type: metav1.RowCompleted, Status: metav1.ConditionTrue, Reason: string(api.PodSucceeded), Message: "The pod has completed successfully."}}
  488. podFailedConditions = []metav1.TableRowCondition{{Type: metav1.RowCompleted, Status: metav1.ConditionTrue, Reason: string(api.PodFailed), Message: "The pod failed."}}
  489. )
  490. func printPodList(podList *api.PodList, options printers.PrintOptions) ([]metav1.TableRow, error) {
  491. rows := make([]metav1.TableRow, 0, len(podList.Items))
  492. for i := range podList.Items {
  493. r, err := printPod(&podList.Items[i], options)
  494. if err != nil {
  495. return nil, err
  496. }
  497. rows = append(rows, r...)
  498. }
  499. return rows, nil
  500. }
  501. func printPod(pod *api.Pod, options printers.PrintOptions) ([]metav1.TableRow, error) {
  502. restarts := 0
  503. totalContainers := len(pod.Spec.Containers)
  504. readyContainers := 0
  505. reason := string(pod.Status.Phase)
  506. if pod.Status.Reason != "" {
  507. reason = pod.Status.Reason
  508. }
  509. row := metav1.TableRow{
  510. Object: runtime.RawExtension{Object: pod},
  511. }
  512. switch pod.Status.Phase {
  513. case api.PodSucceeded:
  514. row.Conditions = podSuccessConditions
  515. case api.PodFailed:
  516. row.Conditions = podFailedConditions
  517. }
  518. initializing := false
  519. for i := range pod.Status.InitContainerStatuses {
  520. container := pod.Status.InitContainerStatuses[i]
  521. restarts += int(container.RestartCount)
  522. switch {
  523. case container.State.Terminated != nil && container.State.Terminated.ExitCode == 0:
  524. continue
  525. case container.State.Terminated != nil:
  526. // initialization is failed
  527. if len(container.State.Terminated.Reason) == 0 {
  528. if container.State.Terminated.Signal != 0 {
  529. reason = fmt.Sprintf("Init:Signal:%d", container.State.Terminated.Signal)
  530. } else {
  531. reason = fmt.Sprintf("Init:ExitCode:%d", container.State.Terminated.ExitCode)
  532. }
  533. } else {
  534. reason = "Init:" + container.State.Terminated.Reason
  535. }
  536. initializing = true
  537. case container.State.Waiting != nil && len(container.State.Waiting.Reason) > 0 && container.State.Waiting.Reason != "PodInitializing":
  538. reason = "Init:" + container.State.Waiting.Reason
  539. initializing = true
  540. default:
  541. reason = fmt.Sprintf("Init:%d/%d", i, len(pod.Spec.InitContainers))
  542. initializing = true
  543. }
  544. break
  545. }
  546. if !initializing {
  547. restarts = 0
  548. hasRunning := false
  549. for i := len(pod.Status.ContainerStatuses) - 1; i >= 0; i-- {
  550. container := pod.Status.ContainerStatuses[i]
  551. restarts += int(container.RestartCount)
  552. if container.State.Waiting != nil && container.State.Waiting.Reason != "" {
  553. reason = container.State.Waiting.Reason
  554. } else if container.State.Terminated != nil && container.State.Terminated.Reason != "" {
  555. reason = container.State.Terminated.Reason
  556. } else if container.State.Terminated != nil && container.State.Terminated.Reason == "" {
  557. if container.State.Terminated.Signal != 0 {
  558. reason = fmt.Sprintf("Signal:%d", container.State.Terminated.Signal)
  559. } else {
  560. reason = fmt.Sprintf("ExitCode:%d", container.State.Terminated.ExitCode)
  561. }
  562. } else if container.Ready && container.State.Running != nil {
  563. hasRunning = true
  564. readyContainers++
  565. }
  566. }
  567. // change pod status back to "Running" if there is at least one container still reporting as "Running" status
  568. if reason == "Completed" && hasRunning {
  569. reason = "Running"
  570. }
  571. }
  572. if pod.DeletionTimestamp != nil && pod.Status.Reason == node.NodeUnreachablePodReason {
  573. reason = "Unknown"
  574. } else if pod.DeletionTimestamp != nil {
  575. reason = "Terminating"
  576. }
  577. row.Cells = append(row.Cells, pod.Name, fmt.Sprintf("%d/%d", readyContainers, totalContainers), reason, int64(restarts), translateTimestampSince(pod.CreationTimestamp))
  578. if options.Wide {
  579. nodeName := pod.Spec.NodeName
  580. nominatedNodeName := pod.Status.NominatedNodeName
  581. podIP := pod.Status.PodIP
  582. if podIP == "" {
  583. podIP = "<none>"
  584. }
  585. if nodeName == "" {
  586. nodeName = "<none>"
  587. }
  588. if nominatedNodeName == "" {
  589. nominatedNodeName = "<none>"
  590. }
  591. readinessGates := "<none>"
  592. if len(pod.Spec.ReadinessGates) > 0 {
  593. trueConditions := 0
  594. for _, readinessGate := range pod.Spec.ReadinessGates {
  595. conditionType := readinessGate.ConditionType
  596. for _, condition := range pod.Status.Conditions {
  597. if condition.Type == conditionType {
  598. if condition.Status == api.ConditionTrue {
  599. trueConditions++
  600. }
  601. break
  602. }
  603. }
  604. }
  605. readinessGates = fmt.Sprintf("%d/%d", trueConditions, len(pod.Spec.ReadinessGates))
  606. }
  607. row.Cells = append(row.Cells, podIP, nodeName, nominatedNodeName, readinessGates)
  608. }
  609. return []metav1beta1.TableRow{row}, nil
  610. }
  611. func printPodTemplate(obj *api.PodTemplate, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  612. row := metav1beta1.TableRow{
  613. Object: runtime.RawExtension{Object: obj},
  614. }
  615. names, images := layoutContainerCells(obj.Template.Spec.Containers)
  616. row.Cells = append(row.Cells, obj.Name, names, images, labels.FormatLabels(obj.Template.Labels))
  617. return []metav1beta1.TableRow{row}, nil
  618. }
  619. func printPodTemplateList(list *api.PodTemplateList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  620. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  621. for i := range list.Items {
  622. r, err := printPodTemplate(&list.Items[i], options)
  623. if err != nil {
  624. return nil, err
  625. }
  626. rows = append(rows, r...)
  627. }
  628. return rows, nil
  629. }
  630. func printPodDisruptionBudget(obj *policy.PodDisruptionBudget, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  631. row := metav1beta1.TableRow{
  632. Object: runtime.RawExtension{Object: obj},
  633. }
  634. var minAvailable string
  635. var maxUnavailable string
  636. if obj.Spec.MinAvailable != nil {
  637. minAvailable = obj.Spec.MinAvailable.String()
  638. } else {
  639. minAvailable = "N/A"
  640. }
  641. if obj.Spec.MaxUnavailable != nil {
  642. maxUnavailable = obj.Spec.MaxUnavailable.String()
  643. } else {
  644. maxUnavailable = "N/A"
  645. }
  646. row.Cells = append(row.Cells, obj.Name, minAvailable, maxUnavailable, int64(obj.Status.PodDisruptionsAllowed), translateTimestampSince(obj.CreationTimestamp))
  647. return []metav1beta1.TableRow{row}, nil
  648. }
  649. func printPodDisruptionBudgetList(list *policy.PodDisruptionBudgetList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  650. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  651. for i := range list.Items {
  652. r, err := printPodDisruptionBudget(&list.Items[i], options)
  653. if err != nil {
  654. return nil, err
  655. }
  656. rows = append(rows, r...)
  657. }
  658. return rows, nil
  659. }
  660. // TODO(AdoHe): try to put wide output in a single method
  661. func printReplicationController(obj *api.ReplicationController, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  662. row := metav1beta1.TableRow{
  663. Object: runtime.RawExtension{Object: obj},
  664. }
  665. desiredReplicas := obj.Spec.Replicas
  666. currentReplicas := obj.Status.Replicas
  667. readyReplicas := obj.Status.ReadyReplicas
  668. row.Cells = append(row.Cells, obj.Name, int64(desiredReplicas), int64(currentReplicas), int64(readyReplicas), translateTimestampSince(obj.CreationTimestamp))
  669. if options.Wide {
  670. names, images := layoutContainerCells(obj.Spec.Template.Spec.Containers)
  671. row.Cells = append(row.Cells, names, images, labels.FormatLabels(obj.Spec.Selector))
  672. }
  673. return []metav1beta1.TableRow{row}, nil
  674. }
  675. func printReplicationControllerList(list *api.ReplicationControllerList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  676. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  677. for i := range list.Items {
  678. r, err := printReplicationController(&list.Items[i], options)
  679. if err != nil {
  680. return nil, err
  681. }
  682. rows = append(rows, r...)
  683. }
  684. return rows, nil
  685. }
  686. func printReplicaSet(obj *apps.ReplicaSet, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  687. row := metav1beta1.TableRow{
  688. Object: runtime.RawExtension{Object: obj},
  689. }
  690. desiredReplicas := obj.Spec.Replicas
  691. currentReplicas := obj.Status.Replicas
  692. readyReplicas := obj.Status.ReadyReplicas
  693. row.Cells = append(row.Cells, obj.Name, int64(desiredReplicas), int64(currentReplicas), int64(readyReplicas), translateTimestampSince(obj.CreationTimestamp))
  694. if options.Wide {
  695. names, images := layoutContainerCells(obj.Spec.Template.Spec.Containers)
  696. row.Cells = append(row.Cells, names, images, metav1.FormatLabelSelector(obj.Spec.Selector))
  697. }
  698. return []metav1beta1.TableRow{row}, nil
  699. }
  700. func printReplicaSetList(list *apps.ReplicaSetList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  701. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  702. for i := range list.Items {
  703. r, err := printReplicaSet(&list.Items[i], options)
  704. if err != nil {
  705. return nil, err
  706. }
  707. rows = append(rows, r...)
  708. }
  709. return rows, nil
  710. }
  711. func printJob(obj *batch.Job, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  712. row := metav1beta1.TableRow{
  713. Object: runtime.RawExtension{Object: obj},
  714. }
  715. var completions string
  716. if obj.Spec.Completions != nil {
  717. completions = fmt.Sprintf("%d/%d", obj.Status.Succeeded, *obj.Spec.Completions)
  718. } else {
  719. parallelism := int32(0)
  720. if obj.Spec.Parallelism != nil {
  721. parallelism = *obj.Spec.Parallelism
  722. }
  723. if parallelism > 1 {
  724. completions = fmt.Sprintf("%d/1 of %d", obj.Status.Succeeded, parallelism)
  725. } else {
  726. completions = fmt.Sprintf("%d/1", obj.Status.Succeeded)
  727. }
  728. }
  729. var jobDuration string
  730. switch {
  731. case obj.Status.StartTime == nil:
  732. case obj.Status.CompletionTime == nil:
  733. jobDuration = duration.HumanDuration(time.Since(obj.Status.StartTime.Time))
  734. default:
  735. jobDuration = duration.HumanDuration(obj.Status.CompletionTime.Sub(obj.Status.StartTime.Time))
  736. }
  737. row.Cells = append(row.Cells, obj.Name, completions, jobDuration, translateTimestampSince(obj.CreationTimestamp))
  738. if options.Wide {
  739. names, images := layoutContainerCells(obj.Spec.Template.Spec.Containers)
  740. row.Cells = append(row.Cells, names, images, metav1.FormatLabelSelector(obj.Spec.Selector))
  741. }
  742. return []metav1beta1.TableRow{row}, nil
  743. }
  744. func printJobList(list *batch.JobList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  745. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  746. for i := range list.Items {
  747. r, err := printJob(&list.Items[i], options)
  748. if err != nil {
  749. return nil, err
  750. }
  751. rows = append(rows, r...)
  752. }
  753. return rows, nil
  754. }
  755. func printCronJob(obj *batch.CronJob, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  756. row := metav1beta1.TableRow{
  757. Object: runtime.RawExtension{Object: obj},
  758. }
  759. lastScheduleTime := "<none>"
  760. if obj.Status.LastScheduleTime != nil {
  761. lastScheduleTime = translateTimestampSince(*obj.Status.LastScheduleTime)
  762. }
  763. row.Cells = append(row.Cells, obj.Name, obj.Spec.Schedule, printBoolPtr(obj.Spec.Suspend), int64(len(obj.Status.Active)), lastScheduleTime, translateTimestampSince(obj.CreationTimestamp))
  764. if options.Wide {
  765. names, images := layoutContainerCells(obj.Spec.JobTemplate.Spec.Template.Spec.Containers)
  766. row.Cells = append(row.Cells, names, images, metav1.FormatLabelSelector(obj.Spec.JobTemplate.Spec.Selector))
  767. }
  768. return []metav1beta1.TableRow{row}, nil
  769. }
  770. func printCronJobList(list *batch.CronJobList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  771. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  772. for i := range list.Items {
  773. r, err := printCronJob(&list.Items[i], options)
  774. if err != nil {
  775. return nil, err
  776. }
  777. rows = append(rows, r...)
  778. }
  779. return rows, nil
  780. }
  781. // loadBalancerStatusStringer behaves mostly like a string interface and converts the given status to a string.
  782. // `wide` indicates whether the returned value is meant for --o=wide output. If not, it's clipped to 16 bytes.
  783. func loadBalancerStatusStringer(s api.LoadBalancerStatus, wide bool) string {
  784. ingress := s.Ingress
  785. result := sets.NewString()
  786. for i := range ingress {
  787. if ingress[i].IP != "" {
  788. result.Insert(ingress[i].IP)
  789. } else if ingress[i].Hostname != "" {
  790. result.Insert(ingress[i].Hostname)
  791. }
  792. }
  793. r := strings.Join(result.List(), ",")
  794. if !wide && len(r) > loadBalancerWidth {
  795. r = r[0:(loadBalancerWidth-3)] + "..."
  796. }
  797. return r
  798. }
  799. func getServiceExternalIP(svc *api.Service, wide bool) string {
  800. switch svc.Spec.Type {
  801. case api.ServiceTypeClusterIP:
  802. if len(svc.Spec.ExternalIPs) > 0 {
  803. return strings.Join(svc.Spec.ExternalIPs, ",")
  804. }
  805. return "<none>"
  806. case api.ServiceTypeNodePort:
  807. if len(svc.Spec.ExternalIPs) > 0 {
  808. return strings.Join(svc.Spec.ExternalIPs, ",")
  809. }
  810. return "<none>"
  811. case api.ServiceTypeLoadBalancer:
  812. lbIps := loadBalancerStatusStringer(svc.Status.LoadBalancer, wide)
  813. if len(svc.Spec.ExternalIPs) > 0 {
  814. results := []string{}
  815. if len(lbIps) > 0 {
  816. results = append(results, strings.Split(lbIps, ",")...)
  817. }
  818. results = append(results, svc.Spec.ExternalIPs...)
  819. return strings.Join(results, ",")
  820. }
  821. if len(lbIps) > 0 {
  822. return lbIps
  823. }
  824. return "<pending>"
  825. case api.ServiceTypeExternalName:
  826. return svc.Spec.ExternalName
  827. }
  828. return "<unknown>"
  829. }
  830. func makePortString(ports []api.ServicePort) string {
  831. pieces := make([]string, len(ports))
  832. for ix := range ports {
  833. port := &ports[ix]
  834. pieces[ix] = fmt.Sprintf("%d/%s", port.Port, port.Protocol)
  835. if port.NodePort > 0 {
  836. pieces[ix] = fmt.Sprintf("%d:%d/%s", port.Port, port.NodePort, port.Protocol)
  837. }
  838. }
  839. return strings.Join(pieces, ",")
  840. }
  841. func printService(obj *api.Service, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  842. row := metav1beta1.TableRow{
  843. Object: runtime.RawExtension{Object: obj},
  844. }
  845. svcType := obj.Spec.Type
  846. internalIP := obj.Spec.ClusterIP
  847. if len(internalIP) == 0 {
  848. internalIP = "<none>"
  849. }
  850. externalIP := getServiceExternalIP(obj, options.Wide)
  851. svcPorts := makePortString(obj.Spec.Ports)
  852. if len(svcPorts) == 0 {
  853. svcPorts = "<none>"
  854. }
  855. row.Cells = append(row.Cells, obj.Name, string(svcType), internalIP, externalIP, svcPorts, translateTimestampSince(obj.CreationTimestamp))
  856. if options.Wide {
  857. row.Cells = append(row.Cells, labels.FormatLabels(obj.Spec.Selector))
  858. }
  859. return []metav1beta1.TableRow{row}, nil
  860. }
  861. func printServiceList(list *api.ServiceList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  862. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  863. for i := range list.Items {
  864. r, err := printService(&list.Items[i], options)
  865. if err != nil {
  866. return nil, err
  867. }
  868. rows = append(rows, r...)
  869. }
  870. return rows, nil
  871. }
  872. func formatHosts(rules []networking.IngressRule) string {
  873. list := []string{}
  874. max := 3
  875. more := false
  876. for _, rule := range rules {
  877. if len(list) == max {
  878. more = true
  879. }
  880. if !more && len(rule.Host) != 0 {
  881. list = append(list, rule.Host)
  882. }
  883. }
  884. if len(list) == 0 {
  885. return "*"
  886. }
  887. ret := strings.Join(list, ",")
  888. if more {
  889. return fmt.Sprintf("%s + %d more...", ret, len(rules)-max)
  890. }
  891. return ret
  892. }
  893. func formatPorts(tls []networking.IngressTLS) string {
  894. if len(tls) != 0 {
  895. return "80, 443"
  896. }
  897. return "80"
  898. }
  899. func printIngress(obj *networking.Ingress, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  900. row := metav1beta1.TableRow{
  901. Object: runtime.RawExtension{Object: obj},
  902. }
  903. hosts := formatHosts(obj.Spec.Rules)
  904. address := loadBalancerStatusStringer(obj.Status.LoadBalancer, options.Wide)
  905. ports := formatPorts(obj.Spec.TLS)
  906. createTime := translateTimestampSince(obj.CreationTimestamp)
  907. row.Cells = append(row.Cells, obj.Name, hosts, address, ports, createTime)
  908. return []metav1beta1.TableRow{row}, nil
  909. }
  910. func printIngressList(list *networking.IngressList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  911. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  912. for i := range list.Items {
  913. r, err := printIngress(&list.Items[i], options)
  914. if err != nil {
  915. return nil, err
  916. }
  917. rows = append(rows, r...)
  918. }
  919. return rows, nil
  920. }
  921. func printStatefulSet(obj *apps.StatefulSet, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  922. row := metav1beta1.TableRow{
  923. Object: runtime.RawExtension{Object: obj},
  924. }
  925. desiredReplicas := obj.Spec.Replicas
  926. readyReplicas := obj.Status.ReadyReplicas
  927. createTime := translateTimestampSince(obj.CreationTimestamp)
  928. row.Cells = append(row.Cells, obj.Name, fmt.Sprintf("%d/%d", int64(readyReplicas), int64(desiredReplicas)), createTime)
  929. if options.Wide {
  930. names, images := layoutContainerCells(obj.Spec.Template.Spec.Containers)
  931. row.Cells = append(row.Cells, names, images)
  932. }
  933. return []metav1beta1.TableRow{row}, nil
  934. }
  935. func printStatefulSetList(list *apps.StatefulSetList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  936. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  937. for i := range list.Items {
  938. r, err := printStatefulSet(&list.Items[i], options)
  939. if err != nil {
  940. return nil, err
  941. }
  942. rows = append(rows, r...)
  943. }
  944. return rows, nil
  945. }
  946. func printDaemonSet(obj *apps.DaemonSet, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  947. row := metav1beta1.TableRow{
  948. Object: runtime.RawExtension{Object: obj},
  949. }
  950. desiredScheduled := obj.Status.DesiredNumberScheduled
  951. currentScheduled := obj.Status.CurrentNumberScheduled
  952. numberReady := obj.Status.NumberReady
  953. numberUpdated := obj.Status.UpdatedNumberScheduled
  954. numberAvailable := obj.Status.NumberAvailable
  955. 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))
  956. if options.Wide {
  957. names, images := layoutContainerCells(obj.Spec.Template.Spec.Containers)
  958. row.Cells = append(row.Cells, names, images, metav1.FormatLabelSelector(obj.Spec.Selector))
  959. }
  960. return []metav1beta1.TableRow{row}, nil
  961. }
  962. func printDaemonSetList(list *apps.DaemonSetList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  963. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  964. for i := range list.Items {
  965. r, err := printDaemonSet(&list.Items[i], options)
  966. if err != nil {
  967. return nil, err
  968. }
  969. rows = append(rows, r...)
  970. }
  971. return rows, nil
  972. }
  973. func printEndpoints(obj *api.Endpoints, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  974. row := metav1beta1.TableRow{
  975. Object: runtime.RawExtension{Object: obj},
  976. }
  977. row.Cells = append(row.Cells, obj.Name, formatEndpoints(obj, nil), translateTimestampSince(obj.CreationTimestamp))
  978. return []metav1beta1.TableRow{row}, nil
  979. }
  980. func printEndpointsList(list *api.EndpointsList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  981. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  982. for i := range list.Items {
  983. r, err := printEndpoints(&list.Items[i], options)
  984. if err != nil {
  985. return nil, err
  986. }
  987. rows = append(rows, r...)
  988. }
  989. return rows, nil
  990. }
  991. func printNamespace(obj *api.Namespace, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  992. row := metav1beta1.TableRow{
  993. Object: runtime.RawExtension{Object: obj},
  994. }
  995. row.Cells = append(row.Cells, obj.Name, string(obj.Status.Phase), translateTimestampSince(obj.CreationTimestamp))
  996. return []metav1beta1.TableRow{row}, nil
  997. }
  998. func printNamespaceList(list *api.NamespaceList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  999. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  1000. for i := range list.Items {
  1001. r, err := printNamespace(&list.Items[i], options)
  1002. if err != nil {
  1003. return nil, err
  1004. }
  1005. rows = append(rows, r...)
  1006. }
  1007. return rows, nil
  1008. }
  1009. func printSecret(obj *api.Secret, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1010. row := metav1beta1.TableRow{
  1011. Object: runtime.RawExtension{Object: obj},
  1012. }
  1013. row.Cells = append(row.Cells, obj.Name, string(obj.Type), int64(len(obj.Data)), translateTimestampSince(obj.CreationTimestamp))
  1014. return []metav1beta1.TableRow{row}, nil
  1015. }
  1016. func printSecretList(list *api.SecretList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1017. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  1018. for i := range list.Items {
  1019. r, err := printSecret(&list.Items[i], options)
  1020. if err != nil {
  1021. return nil, err
  1022. }
  1023. rows = append(rows, r...)
  1024. }
  1025. return rows, nil
  1026. }
  1027. func printServiceAccount(obj *api.ServiceAccount, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1028. row := metav1beta1.TableRow{
  1029. Object: runtime.RawExtension{Object: obj},
  1030. }
  1031. row.Cells = append(row.Cells, obj.Name, int64(len(obj.Secrets)), translateTimestampSince(obj.CreationTimestamp))
  1032. return []metav1beta1.TableRow{row}, nil
  1033. }
  1034. func printServiceAccountList(list *api.ServiceAccountList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1035. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  1036. for i := range list.Items {
  1037. r, err := printServiceAccount(&list.Items[i], options)
  1038. if err != nil {
  1039. return nil, err
  1040. }
  1041. rows = append(rows, r...)
  1042. }
  1043. return rows, nil
  1044. }
  1045. func printNode(obj *api.Node, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1046. row := metav1beta1.TableRow{
  1047. Object: runtime.RawExtension{Object: obj},
  1048. }
  1049. conditionMap := make(map[api.NodeConditionType]*api.NodeCondition)
  1050. NodeAllConditions := []api.NodeConditionType{api.NodeReady}
  1051. for i := range obj.Status.Conditions {
  1052. cond := obj.Status.Conditions[i]
  1053. conditionMap[cond.Type] = &cond
  1054. }
  1055. var status []string
  1056. for _, validCondition := range NodeAllConditions {
  1057. if condition, ok := conditionMap[validCondition]; ok {
  1058. if condition.Status == api.ConditionTrue {
  1059. status = append(status, string(condition.Type))
  1060. } else {
  1061. status = append(status, "Not"+string(condition.Type))
  1062. }
  1063. }
  1064. }
  1065. if len(status) == 0 {
  1066. status = append(status, "Unknown")
  1067. }
  1068. if obj.Spec.Unschedulable {
  1069. status = append(status, "SchedulingDisabled")
  1070. }
  1071. roles := strings.Join(findNodeRoles(obj), ",")
  1072. if len(roles) == 0 {
  1073. roles = "<none>"
  1074. }
  1075. row.Cells = append(row.Cells, obj.Name, strings.Join(status, ","), roles, translateTimestampSince(obj.CreationTimestamp), obj.Status.NodeInfo.KubeletVersion)
  1076. if options.Wide {
  1077. osImage, kernelVersion, crVersion := obj.Status.NodeInfo.OSImage, obj.Status.NodeInfo.KernelVersion, obj.Status.NodeInfo.ContainerRuntimeVersion
  1078. if osImage == "" {
  1079. osImage = "<unknown>"
  1080. }
  1081. if kernelVersion == "" {
  1082. kernelVersion = "<unknown>"
  1083. }
  1084. if crVersion == "" {
  1085. crVersion = "<unknown>"
  1086. }
  1087. row.Cells = append(row.Cells, getNodeInternalIP(obj), getNodeExternalIP(obj), osImage, kernelVersion, crVersion)
  1088. }
  1089. return []metav1beta1.TableRow{row}, nil
  1090. }
  1091. // Returns first external ip of the node or "<none>" if none is found.
  1092. func getNodeExternalIP(node *api.Node) string {
  1093. for _, address := range node.Status.Addresses {
  1094. if address.Type == api.NodeExternalIP {
  1095. return address.Address
  1096. }
  1097. }
  1098. return "<none>"
  1099. }
  1100. // Returns the internal IP of the node or "<none>" if none is found.
  1101. func getNodeInternalIP(node *api.Node) string {
  1102. for _, address := range node.Status.Addresses {
  1103. if address.Type == api.NodeInternalIP {
  1104. return address.Address
  1105. }
  1106. }
  1107. return "<none>"
  1108. }
  1109. // findNodeRoles returns the roles of a given node.
  1110. // The roles are determined by looking for:
  1111. // * a node-role.kubernetes.io/<role>="" label
  1112. // * a kubernetes.io/role="<role>" label
  1113. func findNodeRoles(node *api.Node) []string {
  1114. roles := sets.NewString()
  1115. for k, v := range node.Labels {
  1116. switch {
  1117. case strings.HasPrefix(k, labelNodeRolePrefix):
  1118. if role := strings.TrimPrefix(k, labelNodeRolePrefix); len(role) > 0 {
  1119. roles.Insert(role)
  1120. }
  1121. case k == nodeLabelRole && v != "":
  1122. roles.Insert(v)
  1123. }
  1124. }
  1125. return roles.List()
  1126. }
  1127. func printNodeList(list *api.NodeList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1128. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  1129. for i := range list.Items {
  1130. r, err := printNode(&list.Items[i], options)
  1131. if err != nil {
  1132. return nil, err
  1133. }
  1134. rows = append(rows, r...)
  1135. }
  1136. return rows, nil
  1137. }
  1138. func printPersistentVolume(obj *api.PersistentVolume, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1139. row := metav1beta1.TableRow{
  1140. Object: runtime.RawExtension{Object: obj},
  1141. }
  1142. claimRefUID := ""
  1143. if obj.Spec.ClaimRef != nil {
  1144. claimRefUID += obj.Spec.ClaimRef.Namespace
  1145. claimRefUID += "/"
  1146. claimRefUID += obj.Spec.ClaimRef.Name
  1147. }
  1148. modesStr := helper.GetAccessModesAsString(obj.Spec.AccessModes)
  1149. reclaimPolicyStr := string(obj.Spec.PersistentVolumeReclaimPolicy)
  1150. aQty := obj.Spec.Capacity[api.ResourceStorage]
  1151. aSize := aQty.String()
  1152. phase := obj.Status.Phase
  1153. if obj.ObjectMeta.DeletionTimestamp != nil {
  1154. phase = "Terminating"
  1155. }
  1156. volumeMode := "<unset>"
  1157. if obj.Spec.VolumeMode != nil {
  1158. volumeMode = string(*obj.Spec.VolumeMode)
  1159. }
  1160. row.Cells = append(row.Cells, obj.Name, aSize, modesStr, reclaimPolicyStr,
  1161. string(phase), claimRefUID, helper.GetPersistentVolumeClass(obj),
  1162. obj.Status.Reason, translateTimestampSince(obj.CreationTimestamp), volumeMode)
  1163. return []metav1beta1.TableRow{row}, nil
  1164. }
  1165. func printPersistentVolumeList(list *api.PersistentVolumeList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1166. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  1167. for i := range list.Items {
  1168. r, err := printPersistentVolume(&list.Items[i], options)
  1169. if err != nil {
  1170. return nil, err
  1171. }
  1172. rows = append(rows, r...)
  1173. }
  1174. return rows, nil
  1175. }
  1176. func printPersistentVolumeClaim(obj *api.PersistentVolumeClaim, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1177. row := metav1beta1.TableRow{
  1178. Object: runtime.RawExtension{Object: obj},
  1179. }
  1180. phase := obj.Status.Phase
  1181. if obj.ObjectMeta.DeletionTimestamp != nil {
  1182. phase = "Terminating"
  1183. }
  1184. storage := obj.Spec.Resources.Requests[api.ResourceStorage]
  1185. capacity := ""
  1186. accessModes := ""
  1187. volumeMode := "<unset>"
  1188. if obj.Spec.VolumeName != "" {
  1189. accessModes = helper.GetAccessModesAsString(obj.Status.AccessModes)
  1190. storage = obj.Status.Capacity[api.ResourceStorage]
  1191. capacity = storage.String()
  1192. }
  1193. if obj.Spec.VolumeMode != nil {
  1194. volumeMode = string(*obj.Spec.VolumeMode)
  1195. }
  1196. row.Cells = append(row.Cells, obj.Name, string(phase), obj.Spec.VolumeName, capacity, accessModes,
  1197. helper.GetPersistentVolumeClaimClass(obj), translateTimestampSince(obj.CreationTimestamp), volumeMode)
  1198. return []metav1beta1.TableRow{row}, nil
  1199. }
  1200. func printPersistentVolumeClaimList(list *api.PersistentVolumeClaimList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1201. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  1202. for i := range list.Items {
  1203. r, err := printPersistentVolumeClaim(&list.Items[i], options)
  1204. if err != nil {
  1205. return nil, err
  1206. }
  1207. rows = append(rows, r...)
  1208. }
  1209. return rows, nil
  1210. }
  1211. func printEvent(obj *api.Event, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1212. row := metav1beta1.TableRow{
  1213. Object: runtime.RawExtension{Object: obj},
  1214. }
  1215. // While watching event, we should print absolute time.
  1216. var firstTimestamp, lastTimestamp string
  1217. if options.AbsoluteTimestamps {
  1218. firstTimestamp = obj.FirstTimestamp.String()
  1219. lastTimestamp = obj.LastTimestamp.String()
  1220. } else {
  1221. firstTimestamp = translateTimestampSince(obj.FirstTimestamp)
  1222. lastTimestamp = translateTimestampSince(obj.LastTimestamp)
  1223. }
  1224. var target string
  1225. if len(obj.InvolvedObject.Name) > 0 {
  1226. target = fmt.Sprintf("%s/%s", strings.ToLower(obj.InvolvedObject.Kind), obj.InvolvedObject.Name)
  1227. } else {
  1228. target = strings.ToLower(obj.InvolvedObject.Kind)
  1229. }
  1230. if options.Wide {
  1231. row.Cells = append(row.Cells,
  1232. lastTimestamp,
  1233. obj.Type,
  1234. obj.Reason,
  1235. target,
  1236. obj.InvolvedObject.FieldPath,
  1237. formatEventSource(obj.Source),
  1238. strings.TrimSpace(obj.Message),
  1239. firstTimestamp,
  1240. int64(obj.Count),
  1241. obj.Name,
  1242. )
  1243. } else {
  1244. row.Cells = append(row.Cells,
  1245. lastTimestamp,
  1246. obj.Type,
  1247. obj.Reason,
  1248. target,
  1249. strings.TrimSpace(obj.Message),
  1250. )
  1251. }
  1252. return []metav1beta1.TableRow{row}, nil
  1253. }
  1254. // Sorts and prints the EventList in a human-friendly format.
  1255. func printEventList(list *api.EventList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1256. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  1257. for i := range list.Items {
  1258. r, err := printEvent(&list.Items[i], options)
  1259. if err != nil {
  1260. return nil, err
  1261. }
  1262. rows = append(rows, r...)
  1263. }
  1264. return rows, nil
  1265. }
  1266. func printRoleBinding(obj *rbac.RoleBinding, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1267. row := metav1beta1.TableRow{
  1268. Object: runtime.RawExtension{Object: obj},
  1269. }
  1270. row.Cells = append(row.Cells, obj.Name, translateTimestampSince(obj.CreationTimestamp))
  1271. if options.Wide {
  1272. roleRef := fmt.Sprintf("%s/%s", obj.RoleRef.Kind, obj.RoleRef.Name)
  1273. users, groups, sas, _ := rbac.SubjectsStrings(obj.Subjects)
  1274. row.Cells = append(row.Cells, roleRef, strings.Join(users, ", "), strings.Join(groups, ", "), strings.Join(sas, ", "))
  1275. }
  1276. return []metav1beta1.TableRow{row}, nil
  1277. }
  1278. // Prints the RoleBinding in a human-friendly format.
  1279. func printRoleBindingList(list *rbac.RoleBindingList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1280. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  1281. for i := range list.Items {
  1282. r, err := printRoleBinding(&list.Items[i], options)
  1283. if err != nil {
  1284. return nil, err
  1285. }
  1286. rows = append(rows, r...)
  1287. }
  1288. return rows, nil
  1289. }
  1290. func printClusterRoleBinding(obj *rbac.ClusterRoleBinding, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1291. row := metav1beta1.TableRow{
  1292. Object: runtime.RawExtension{Object: obj},
  1293. }
  1294. row.Cells = append(row.Cells, obj.Name, translateTimestampSince(obj.CreationTimestamp))
  1295. if options.Wide {
  1296. roleRef := fmt.Sprintf("%s/%s", obj.RoleRef.Kind, obj.RoleRef.Name)
  1297. users, groups, sas, _ := rbac.SubjectsStrings(obj.Subjects)
  1298. row.Cells = append(row.Cells, roleRef, strings.Join(users, ", "), strings.Join(groups, ", "), strings.Join(sas, ", "))
  1299. }
  1300. return []metav1beta1.TableRow{row}, nil
  1301. }
  1302. // Prints the ClusterRoleBinding in a human-friendly format.
  1303. func printClusterRoleBindingList(list *rbac.ClusterRoleBindingList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1304. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  1305. for i := range list.Items {
  1306. r, err := printClusterRoleBinding(&list.Items[i], options)
  1307. if err != nil {
  1308. return nil, err
  1309. }
  1310. rows = append(rows, r...)
  1311. }
  1312. return rows, nil
  1313. }
  1314. func printCertificateSigningRequest(obj *certificates.CertificateSigningRequest, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1315. row := metav1beta1.TableRow{
  1316. Object: runtime.RawExtension{Object: obj},
  1317. }
  1318. status, err := extractCSRStatus(obj)
  1319. if err != nil {
  1320. return nil, err
  1321. }
  1322. row.Cells = append(row.Cells, obj.Name, translateTimestampSince(obj.CreationTimestamp), obj.Spec.Username, status)
  1323. return []metav1beta1.TableRow{row}, nil
  1324. }
  1325. func extractCSRStatus(csr *certificates.CertificateSigningRequest) (string, error) {
  1326. var approved, denied bool
  1327. for _, c := range csr.Status.Conditions {
  1328. switch c.Type {
  1329. case certificates.CertificateApproved:
  1330. approved = true
  1331. case certificates.CertificateDenied:
  1332. denied = true
  1333. default:
  1334. return "", fmt.Errorf("unknown csr condition %q", c)
  1335. }
  1336. }
  1337. var status string
  1338. // must be in order of presidence
  1339. if denied {
  1340. status += "Denied"
  1341. } else if approved {
  1342. status += "Approved"
  1343. } else {
  1344. status += "Pending"
  1345. }
  1346. if len(csr.Status.Certificate) > 0 {
  1347. status += ",Issued"
  1348. }
  1349. return status, nil
  1350. }
  1351. func printCertificateSigningRequestList(list *certificates.CertificateSigningRequestList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1352. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  1353. for i := range list.Items {
  1354. r, err := printCertificateSigningRequest(&list.Items[i], options)
  1355. if err != nil {
  1356. return nil, err
  1357. }
  1358. rows = append(rows, r...)
  1359. }
  1360. return rows, nil
  1361. }
  1362. func printComponentStatus(obj *api.ComponentStatus, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1363. row := metav1beta1.TableRow{
  1364. Object: runtime.RawExtension{Object: obj},
  1365. }
  1366. status := "Unknown"
  1367. message := ""
  1368. error := ""
  1369. for _, condition := range obj.Conditions {
  1370. if condition.Type == api.ComponentHealthy {
  1371. if condition.Status == api.ConditionTrue {
  1372. status = "Healthy"
  1373. } else {
  1374. status = "Unhealthy"
  1375. }
  1376. message = condition.Message
  1377. error = condition.Error
  1378. break
  1379. }
  1380. }
  1381. row.Cells = append(row.Cells, obj.Name, status, message, error)
  1382. return []metav1beta1.TableRow{row}, nil
  1383. }
  1384. func printComponentStatusList(list *api.ComponentStatusList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1385. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  1386. for i := range list.Items {
  1387. r, err := printComponentStatus(&list.Items[i], options)
  1388. if err != nil {
  1389. return nil, err
  1390. }
  1391. rows = append(rows, r...)
  1392. }
  1393. return rows, nil
  1394. }
  1395. func printDeployment(obj *apps.Deployment, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1396. row := metav1beta1.TableRow{
  1397. Object: runtime.RawExtension{Object: obj},
  1398. }
  1399. desiredReplicas := obj.Spec.Replicas
  1400. updatedReplicas := obj.Status.UpdatedReplicas
  1401. readyReplicas := obj.Status.ReadyReplicas
  1402. availableReplicas := obj.Status.AvailableReplicas
  1403. age := translateTimestampSince(obj.CreationTimestamp)
  1404. containers := obj.Spec.Template.Spec.Containers
  1405. selector, err := metav1.LabelSelectorAsSelector(obj.Spec.Selector)
  1406. if err != nil {
  1407. // this shouldn't happen if LabelSelector passed validation
  1408. return nil, err
  1409. }
  1410. row.Cells = append(row.Cells, obj.Name, fmt.Sprintf("%d/%d", int64(readyReplicas), int64(desiredReplicas)), int64(updatedReplicas), int64(availableReplicas), age)
  1411. if options.Wide {
  1412. containers, images := layoutContainerCells(containers)
  1413. row.Cells = append(row.Cells, containers, images, selector.String())
  1414. }
  1415. return []metav1beta1.TableRow{row}, nil
  1416. }
  1417. func printDeploymentList(list *apps.DeploymentList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1418. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  1419. for i := range list.Items {
  1420. r, err := printDeployment(&list.Items[i], options)
  1421. if err != nil {
  1422. return nil, err
  1423. }
  1424. rows = append(rows, r...)
  1425. }
  1426. return rows, nil
  1427. }
  1428. func formatHPAMetrics(specs []autoscaling.MetricSpec, statuses []autoscaling.MetricStatus) string {
  1429. if len(specs) == 0 {
  1430. return "<none>"
  1431. }
  1432. list := []string{}
  1433. max := 2
  1434. more := false
  1435. count := 0
  1436. for i, spec := range specs {
  1437. switch spec.Type {
  1438. case autoscaling.ExternalMetricSourceType:
  1439. if spec.External.Target.AverageValue != nil {
  1440. current := "<unknown>"
  1441. if len(statuses) > i && statuses[i].External != nil && statuses[i].External.Current.AverageValue != nil {
  1442. current = statuses[i].External.Current.AverageValue.String()
  1443. }
  1444. list = append(list, fmt.Sprintf("%s/%s (avg)", current, spec.External.Target.AverageValue.String()))
  1445. } else {
  1446. current := "<unknown>"
  1447. if len(statuses) > i && statuses[i].External != nil {
  1448. current = statuses[i].External.Current.Value.String()
  1449. }
  1450. list = append(list, fmt.Sprintf("%s/%s", current, spec.External.Target.Value.String()))
  1451. }
  1452. case autoscaling.PodsMetricSourceType:
  1453. current := "<unknown>"
  1454. if len(statuses) > i && statuses[i].Pods != nil {
  1455. current = statuses[i].Pods.Current.AverageValue.String()
  1456. }
  1457. list = append(list, fmt.Sprintf("%s/%s", current, spec.Pods.Target.AverageValue.String()))
  1458. case autoscaling.ObjectMetricSourceType:
  1459. current := "<unknown>"
  1460. if len(statuses) > i && statuses[i].Object != nil {
  1461. current = statuses[i].Object.Current.Value.String()
  1462. }
  1463. list = append(list, fmt.Sprintf("%s/%s", current, spec.Object.Target.Value.String()))
  1464. case autoscaling.ResourceMetricSourceType:
  1465. if spec.Resource.Target.AverageValue != nil {
  1466. current := "<unknown>"
  1467. if len(statuses) > i && statuses[i].Resource != nil {
  1468. current = statuses[i].Resource.Current.AverageValue.String()
  1469. }
  1470. list = append(list, fmt.Sprintf("%s/%s", current, spec.Resource.Target.AverageValue.String()))
  1471. } else {
  1472. current := "<unknown>"
  1473. if len(statuses) > i && statuses[i].Resource != nil && statuses[i].Resource.Current.AverageUtilization != nil {
  1474. current = fmt.Sprintf("%d%%", *statuses[i].Resource.Current.AverageUtilization)
  1475. }
  1476. target := "<auto>"
  1477. if spec.Resource.Target.AverageUtilization != nil {
  1478. target = fmt.Sprintf("%d%%", *spec.Resource.Target.AverageUtilization)
  1479. }
  1480. list = append(list, fmt.Sprintf("%s/%s", current, target))
  1481. }
  1482. default:
  1483. list = append(list, "<unknown type>")
  1484. }
  1485. count++
  1486. }
  1487. if count > max {
  1488. list = list[:max]
  1489. more = true
  1490. }
  1491. ret := strings.Join(list, ", ")
  1492. if more {
  1493. return fmt.Sprintf("%s + %d more...", ret, count-max)
  1494. }
  1495. return ret
  1496. }
  1497. func printHorizontalPodAutoscaler(obj *autoscaling.HorizontalPodAutoscaler, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1498. row := metav1beta1.TableRow{
  1499. Object: runtime.RawExtension{Object: obj},
  1500. }
  1501. reference := fmt.Sprintf("%s/%s",
  1502. obj.Spec.ScaleTargetRef.Kind,
  1503. obj.Spec.ScaleTargetRef.Name)
  1504. minPods := "<unset>"
  1505. metrics := formatHPAMetrics(obj.Spec.Metrics, obj.Status.CurrentMetrics)
  1506. if obj.Spec.MinReplicas != nil {
  1507. minPods = fmt.Sprintf("%d", *obj.Spec.MinReplicas)
  1508. }
  1509. maxPods := obj.Spec.MaxReplicas
  1510. currentReplicas := obj.Status.CurrentReplicas
  1511. row.Cells = append(row.Cells, obj.Name, reference, metrics, minPods, int64(maxPods), int64(currentReplicas), translateTimestampSince(obj.CreationTimestamp))
  1512. return []metav1beta1.TableRow{row}, nil
  1513. }
  1514. func printHorizontalPodAutoscalerList(list *autoscaling.HorizontalPodAutoscalerList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1515. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  1516. for i := range list.Items {
  1517. r, err := printHorizontalPodAutoscaler(&list.Items[i], options)
  1518. if err != nil {
  1519. return nil, err
  1520. }
  1521. rows = append(rows, r...)
  1522. }
  1523. return rows, nil
  1524. }
  1525. func printConfigMap(obj *api.ConfigMap, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1526. row := metav1beta1.TableRow{
  1527. Object: runtime.RawExtension{Object: obj},
  1528. }
  1529. row.Cells = append(row.Cells, obj.Name, int64(len(obj.Data)), translateTimestampSince(obj.CreationTimestamp))
  1530. return []metav1beta1.TableRow{row}, nil
  1531. }
  1532. func printConfigMapList(list *api.ConfigMapList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1533. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  1534. for i := range list.Items {
  1535. r, err := printConfigMap(&list.Items[i], options)
  1536. if err != nil {
  1537. return nil, err
  1538. }
  1539. rows = append(rows, r...)
  1540. }
  1541. return rows, nil
  1542. }
  1543. func printPodSecurityPolicy(obj *policy.PodSecurityPolicy, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1544. row := metav1beta1.TableRow{
  1545. Object: runtime.RawExtension{Object: obj},
  1546. }
  1547. capabilities := make([]string, len(obj.Spec.AllowedCapabilities))
  1548. for i, c := range obj.Spec.AllowedCapabilities {
  1549. capabilities[i] = string(c)
  1550. }
  1551. volumes := make([]string, len(obj.Spec.Volumes))
  1552. for i, v := range obj.Spec.Volumes {
  1553. volumes[i] = string(v)
  1554. }
  1555. row.Cells = append(row.Cells, obj.Name, fmt.Sprintf("%v", obj.Spec.Privileged),
  1556. strings.Join(capabilities, ","), string(obj.Spec.SELinux.Rule),
  1557. string(obj.Spec.RunAsUser.Rule), string(obj.Spec.FSGroup.Rule),
  1558. string(obj.Spec.SupplementalGroups.Rule), obj.Spec.ReadOnlyRootFilesystem,
  1559. strings.Join(volumes, ","))
  1560. return []metav1beta1.TableRow{row}, nil
  1561. }
  1562. func printPodSecurityPolicyList(list *policy.PodSecurityPolicyList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1563. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  1564. for i := range list.Items {
  1565. r, err := printPodSecurityPolicy(&list.Items[i], options)
  1566. if err != nil {
  1567. return nil, err
  1568. }
  1569. rows = append(rows, r...)
  1570. }
  1571. return rows, nil
  1572. }
  1573. func printNetworkPolicy(obj *networking.NetworkPolicy, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1574. row := metav1beta1.TableRow{
  1575. Object: runtime.RawExtension{Object: obj},
  1576. }
  1577. row.Cells = append(row.Cells, obj.Name, metav1.FormatLabelSelector(&obj.Spec.PodSelector), translateTimestampSince(obj.CreationTimestamp))
  1578. return []metav1beta1.TableRow{row}, nil
  1579. }
  1580. func printNetworkPolicyList(list *networking.NetworkPolicyList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1581. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  1582. for i := range list.Items {
  1583. r, err := printNetworkPolicy(&list.Items[i], options)
  1584. if err != nil {
  1585. return nil, err
  1586. }
  1587. rows = append(rows, r...)
  1588. }
  1589. return rows, nil
  1590. }
  1591. func printStorageClass(obj *storage.StorageClass, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1592. row := metav1beta1.TableRow{
  1593. Object: runtime.RawExtension{Object: obj},
  1594. }
  1595. name := obj.Name
  1596. if storageutil.IsDefaultAnnotation(obj.ObjectMeta) {
  1597. name += " (default)"
  1598. }
  1599. provtype := obj.Provisioner
  1600. row.Cells = append(row.Cells, name, provtype, translateTimestampSince(obj.CreationTimestamp))
  1601. return []metav1beta1.TableRow{row}, nil
  1602. }
  1603. func printStorageClassList(list *storage.StorageClassList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1604. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  1605. for i := range list.Items {
  1606. r, err := printStorageClass(&list.Items[i], options)
  1607. if err != nil {
  1608. return nil, err
  1609. }
  1610. rows = append(rows, r...)
  1611. }
  1612. return rows, nil
  1613. }
  1614. func printLease(obj *coordination.Lease, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1615. row := metav1beta1.TableRow{
  1616. Object: runtime.RawExtension{Object: obj},
  1617. }
  1618. var holderIdentity string
  1619. if obj.Spec.HolderIdentity != nil {
  1620. holderIdentity = *obj.Spec.HolderIdentity
  1621. }
  1622. row.Cells = append(row.Cells, obj.Name, holderIdentity, translateTimestampSince(obj.CreationTimestamp))
  1623. return []metav1beta1.TableRow{row}, nil
  1624. }
  1625. func printLeaseList(list *coordination.LeaseList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1626. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  1627. for i := range list.Items {
  1628. r, err := printLease(&list.Items[i], options)
  1629. if err != nil {
  1630. return nil, err
  1631. }
  1632. rows = append(rows, r...)
  1633. }
  1634. return rows, nil
  1635. }
  1636. func printStatus(obj *metav1.Status, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1637. row := metav1beta1.TableRow{
  1638. Object: runtime.RawExtension{Object: obj},
  1639. }
  1640. row.Cells = append(row.Cells, obj.Status, obj.Reason, obj.Message)
  1641. return []metav1beta1.TableRow{row}, nil
  1642. }
  1643. // Lay out all the containers on one line if use wide output.
  1644. func layoutContainerCells(containers []api.Container) (names string, images string) {
  1645. var namesBuffer bytes.Buffer
  1646. var imagesBuffer bytes.Buffer
  1647. for i, container := range containers {
  1648. namesBuffer.WriteString(container.Name)
  1649. imagesBuffer.WriteString(container.Image)
  1650. if i != len(containers)-1 {
  1651. namesBuffer.WriteString(",")
  1652. imagesBuffer.WriteString(",")
  1653. }
  1654. }
  1655. return namesBuffer.String(), imagesBuffer.String()
  1656. }
  1657. // formatEventSource formats EventSource as a comma separated string excluding Host when empty
  1658. func formatEventSource(es api.EventSource) string {
  1659. EventSourceString := []string{es.Component}
  1660. if len(es.Host) > 0 {
  1661. EventSourceString = append(EventSourceString, es.Host)
  1662. }
  1663. return strings.Join(EventSourceString, ", ")
  1664. }
  1665. func printControllerRevision(obj *apps.ControllerRevision, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1666. row := metav1beta1.TableRow{
  1667. Object: runtime.RawExtension{Object: obj},
  1668. }
  1669. controllerRef := metav1.GetControllerOf(obj)
  1670. controllerName := "<none>"
  1671. if controllerRef != nil {
  1672. withKind := true
  1673. gv, err := schema.ParseGroupVersion(controllerRef.APIVersion)
  1674. if err != nil {
  1675. return nil, err
  1676. }
  1677. gvk := gv.WithKind(controllerRef.Kind)
  1678. controllerName = formatResourceName(gvk.GroupKind(), controllerRef.Name, withKind)
  1679. }
  1680. revision := obj.Revision
  1681. age := translateTimestampSince(obj.CreationTimestamp)
  1682. row.Cells = append(row.Cells, obj.Name, controllerName, revision, age)
  1683. return []metav1beta1.TableRow{row}, nil
  1684. }
  1685. func printControllerRevisionList(list *apps.ControllerRevisionList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1686. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  1687. for i := range list.Items {
  1688. r, err := printControllerRevision(&list.Items[i], options)
  1689. if err != nil {
  1690. return nil, err
  1691. }
  1692. rows = append(rows, r...)
  1693. }
  1694. return rows, nil
  1695. }
  1696. // formatResourceName receives a resource kind, name, and boolean specifying
  1697. // whether or not to update the current name to "kind/name"
  1698. func formatResourceName(kind schema.GroupKind, name string, withKind bool) string {
  1699. if !withKind || kind.Empty() {
  1700. return name
  1701. }
  1702. return strings.ToLower(kind.String()) + "/" + name
  1703. }
  1704. func printResourceQuota(resourceQuota *api.ResourceQuota, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1705. row := metav1beta1.TableRow{
  1706. Object: runtime.RawExtension{Object: resourceQuota},
  1707. }
  1708. resources := make([]api.ResourceName, 0, len(resourceQuota.Status.Hard))
  1709. for resource := range resourceQuota.Status.Hard {
  1710. resources = append(resources, resource)
  1711. }
  1712. sort.Sort(SortableResourceNames(resources))
  1713. requestColumn := bytes.NewBuffer([]byte{})
  1714. limitColumn := bytes.NewBuffer([]byte{})
  1715. for i := range resources {
  1716. w := requestColumn
  1717. resource := resources[i]
  1718. usedQuantity := resourceQuota.Status.Used[resource]
  1719. hardQuantity := resourceQuota.Status.Hard[resource]
  1720. // use limitColumn writer if a resource name prefixed with "limits" is found
  1721. if pieces := strings.Split(resource.String(), "."); len(pieces) > 1 && pieces[0] == "limits" {
  1722. w = limitColumn
  1723. }
  1724. fmt.Fprintf(w, "%s: %s/%s, ", resource, usedQuantity.String(), hardQuantity.String())
  1725. }
  1726. age := translateTimestampSince(resourceQuota.CreationTimestamp)
  1727. row.Cells = append(row.Cells, resourceQuota.Name, age, strings.TrimSuffix(requestColumn.String(), ", "), strings.TrimSuffix(limitColumn.String(), ", "))
  1728. return []metav1beta1.TableRow{row}, nil
  1729. }
  1730. func printResourceQuotaList(list *api.ResourceQuotaList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1731. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  1732. for i := range list.Items {
  1733. r, err := printResourceQuota(&list.Items[i], options)
  1734. if err != nil {
  1735. return nil, err
  1736. }
  1737. rows = append(rows, r...)
  1738. }
  1739. return rows, nil
  1740. }
  1741. func printPriorityClass(obj *scheduling.PriorityClass, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1742. row := metav1beta1.TableRow{
  1743. Object: runtime.RawExtension{Object: obj},
  1744. }
  1745. name := obj.Name
  1746. value := obj.Value
  1747. globalDefault := obj.GlobalDefault
  1748. row.Cells = append(row.Cells, name, int64(value), globalDefault, translateTimestampSince(obj.CreationTimestamp))
  1749. return []metav1beta1.TableRow{row}, nil
  1750. }
  1751. func printPriorityClassList(list *scheduling.PriorityClassList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1752. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  1753. for i := range list.Items {
  1754. r, err := printPriorityClass(&list.Items[i], options)
  1755. if err != nil {
  1756. return nil, err
  1757. }
  1758. rows = append(rows, r...)
  1759. }
  1760. return rows, nil
  1761. }
  1762. func printRuntimeClass(obj *nodeapi.RuntimeClass, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1763. row := metav1beta1.TableRow{
  1764. Object: runtime.RawExtension{Object: obj},
  1765. }
  1766. name := obj.Name
  1767. handler := obj.Handler
  1768. row.Cells = append(row.Cells, name, handler, translateTimestampSince(obj.CreationTimestamp))
  1769. return []metav1beta1.TableRow{row}, nil
  1770. }
  1771. func printRuntimeClassList(list *nodeapi.RuntimeClassList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1772. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  1773. for i := range list.Items {
  1774. r, err := printRuntimeClass(&list.Items[i], options)
  1775. if err != nil {
  1776. return nil, err
  1777. }
  1778. rows = append(rows, r...)
  1779. }
  1780. return rows, nil
  1781. }
  1782. func printVolumeAttachment(obj *storage.VolumeAttachment, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1783. row := metav1beta1.TableRow{
  1784. Object: runtime.RawExtension{Object: obj},
  1785. }
  1786. name := obj.Name
  1787. pvName := ""
  1788. if obj.Spec.Source.PersistentVolumeName != nil {
  1789. pvName = *obj.Spec.Source.PersistentVolumeName
  1790. }
  1791. row.Cells = append(row.Cells, name, obj.Spec.Attacher, pvName, obj.Spec.NodeName, obj.Status.Attached, translateTimestampSince(obj.CreationTimestamp))
  1792. return []metav1beta1.TableRow{row}, nil
  1793. }
  1794. func printVolumeAttachmentList(list *storage.VolumeAttachmentList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
  1795. rows := make([]metav1beta1.TableRow, 0, len(list.Items))
  1796. for i := range list.Items {
  1797. r, err := printVolumeAttachment(&list.Items[i], options)
  1798. if err != nil {
  1799. return nil, err
  1800. }
  1801. rows = append(rows, r...)
  1802. }
  1803. return rows, nil
  1804. }
  1805. func printBoolPtr(value *bool) string {
  1806. if value != nil {
  1807. return printBool(*value)
  1808. }
  1809. return "<unset>"
  1810. }
  1811. func printBool(value bool) string {
  1812. if value {
  1813. return "True"
  1814. }
  1815. return "False"
  1816. }
  1817. // SortableResourceNames - An array of sortable resource names
  1818. type SortableResourceNames []api.ResourceName
  1819. func (list SortableResourceNames) Len() int {
  1820. return len(list)
  1821. }
  1822. func (list SortableResourceNames) Swap(i, j int) {
  1823. list[i], list[j] = list[j], list[i]
  1824. }
  1825. func (list SortableResourceNames) Less(i, j int) bool {
  1826. return list[i] < list[j]
  1827. }