describe.go 88 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637
  1. /*
  2. Copyright 2014 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 kubectl
  14. import (
  15. "bytes"
  16. "encoding/json"
  17. "fmt"
  18. "io"
  19. "net"
  20. "net/url"
  21. "reflect"
  22. "sort"
  23. "strings"
  24. "time"
  25. "k8s.io/kubernetes/federation/apis/federation"
  26. fed_clientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_internalclientset"
  27. "k8s.io/kubernetes/pkg/api"
  28. "k8s.io/kubernetes/pkg/api/errors"
  29. "k8s.io/kubernetes/pkg/api/resource"
  30. "k8s.io/kubernetes/pkg/api/unversioned"
  31. "k8s.io/kubernetes/pkg/apis/apps"
  32. "k8s.io/kubernetes/pkg/apis/autoscaling"
  33. "k8s.io/kubernetes/pkg/apis/batch"
  34. "k8s.io/kubernetes/pkg/apis/certificates"
  35. "k8s.io/kubernetes/pkg/apis/extensions"
  36. clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
  37. client "k8s.io/kubernetes/pkg/client/unversioned"
  38. adapter "k8s.io/kubernetes/pkg/client/unversioned/adapters/internalclientset"
  39. deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util"
  40. "k8s.io/kubernetes/pkg/fieldpath"
  41. "k8s.io/kubernetes/pkg/fields"
  42. "k8s.io/kubernetes/pkg/kubelet/qos"
  43. "k8s.io/kubernetes/pkg/labels"
  44. "k8s.io/kubernetes/pkg/types"
  45. utilcertificates "k8s.io/kubernetes/pkg/util/certificates"
  46. "k8s.io/kubernetes/pkg/util/intstr"
  47. "k8s.io/kubernetes/pkg/util/sets"
  48. "github.com/golang/glog"
  49. )
  50. // Describer generates output for the named resource or an error
  51. // if the output could not be generated. Implementers typically
  52. // abstract the retrieval of the named object from a remote server.
  53. type Describer interface {
  54. Describe(namespace, name string, describerSettings DescriberSettings) (output string, err error)
  55. }
  56. // DescriberSettings holds display configuration for each object
  57. // describer to control what is printed.
  58. type DescriberSettings struct {
  59. ShowEvents bool
  60. }
  61. // ObjectDescriber is an interface for displaying arbitrary objects with extra
  62. // information. Use when an object is in hand (on disk, or already retrieved).
  63. // Implementers may ignore the additional information passed on extra, or use it
  64. // by default. ObjectDescribers may return ErrNoDescriber if no suitable describer
  65. // is found.
  66. type ObjectDescriber interface {
  67. DescribeObject(object interface{}, extra ...interface{}) (output string, err error)
  68. }
  69. // ErrNoDescriber is a structured error indicating the provided object or objects
  70. // cannot be described.
  71. type ErrNoDescriber struct {
  72. Types []string
  73. }
  74. // Error implements the error interface.
  75. func (e ErrNoDescriber) Error() string {
  76. return fmt.Sprintf("no describer has been defined for %v", e.Types)
  77. }
  78. func describerMap(c *client.Client) map[unversioned.GroupKind]Describer {
  79. m := map[unversioned.GroupKind]Describer{
  80. api.Kind("Pod"): &PodDescriber{c},
  81. api.Kind("ReplicationController"): &ReplicationControllerDescriber{c},
  82. api.Kind("Secret"): &SecretDescriber{c},
  83. api.Kind("Service"): &ServiceDescriber{c},
  84. api.Kind("ServiceAccount"): &ServiceAccountDescriber{c},
  85. api.Kind("Node"): &NodeDescriber{c},
  86. api.Kind("LimitRange"): &LimitRangeDescriber{c},
  87. api.Kind("ResourceQuota"): &ResourceQuotaDescriber{c},
  88. api.Kind("PersistentVolume"): &PersistentVolumeDescriber{c},
  89. api.Kind("PersistentVolumeClaim"): &PersistentVolumeClaimDescriber{c},
  90. api.Kind("Namespace"): &NamespaceDescriber{c},
  91. api.Kind("Endpoints"): &EndpointsDescriber{c},
  92. api.Kind("ConfigMap"): &ConfigMapDescriber{c},
  93. extensions.Kind("ReplicaSet"): &ReplicaSetDescriber{c},
  94. extensions.Kind("HorizontalPodAutoscaler"): &HorizontalPodAutoscalerDescriber{c},
  95. extensions.Kind("NetworkPolicy"): &NetworkPolicyDescriber{c},
  96. autoscaling.Kind("HorizontalPodAutoscaler"): &HorizontalPodAutoscalerDescriber{c},
  97. extensions.Kind("DaemonSet"): &DaemonSetDescriber{c},
  98. extensions.Kind("Deployment"): &DeploymentDescriber{adapter.FromUnversionedClient(c)},
  99. extensions.Kind("Job"): &JobDescriber{c},
  100. extensions.Kind("Ingress"): &IngressDescriber{c},
  101. batch.Kind("Job"): &JobDescriber{c},
  102. batch.Kind("ScheduledJob"): &ScheduledJobDescriber{adapter.FromUnversionedClient(c)},
  103. apps.Kind("PetSet"): &PetSetDescriber{c},
  104. certificates.Kind("CertificateSigningRequest"): &CertificateSigningRequestDescriber{c},
  105. }
  106. return m
  107. }
  108. // List of all resource types we can describe
  109. func DescribableResources() []string {
  110. keys := make([]string, 0)
  111. for k := range describerMap(nil) {
  112. resource := strings.ToLower(k.Kind)
  113. keys = append(keys, resource)
  114. }
  115. return keys
  116. }
  117. // Describer returns the default describe functions for each of the standard
  118. // Kubernetes types.
  119. func DescriberFor(kind unversioned.GroupKind, c *client.Client) (Describer, bool) {
  120. f, ok := describerMap(c)[kind]
  121. return f, ok
  122. }
  123. // DefaultObjectDescriber can describe the default Kubernetes objects.
  124. var DefaultObjectDescriber ObjectDescriber
  125. func init() {
  126. d := &Describers{}
  127. err := d.Add(
  128. describeLimitRange,
  129. describeQuota,
  130. describePod,
  131. describeService,
  132. describeReplicationController,
  133. describeDaemonSet,
  134. describeNode,
  135. describeNamespace,
  136. )
  137. if err != nil {
  138. glog.Fatalf("Cannot register describers: %v", err)
  139. }
  140. DefaultObjectDescriber = d
  141. }
  142. // NamespaceDescriber generates information about a namespace
  143. type NamespaceDescriber struct {
  144. client.Interface
  145. }
  146. func (d *NamespaceDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
  147. ns, err := d.Namespaces().Get(name)
  148. if err != nil {
  149. return "", err
  150. }
  151. resourceQuotaList, err := d.ResourceQuotas(name).List(api.ListOptions{})
  152. if err != nil {
  153. return "", err
  154. }
  155. limitRangeList, err := d.LimitRanges(name).List(api.ListOptions{})
  156. if err != nil {
  157. return "", err
  158. }
  159. return describeNamespace(ns, resourceQuotaList, limitRangeList)
  160. }
  161. func describeNamespace(namespace *api.Namespace, resourceQuotaList *api.ResourceQuotaList, limitRangeList *api.LimitRangeList) (string, error) {
  162. return tabbedString(func(out io.Writer) error {
  163. fmt.Fprintf(out, "Name:\t%s\n", namespace.Name)
  164. printLabelsMultiline(out, "Labels", namespace.Labels)
  165. fmt.Fprintf(out, "Status:\t%s\n", string(namespace.Status.Phase))
  166. if resourceQuotaList != nil {
  167. fmt.Fprintf(out, "\n")
  168. DescribeResourceQuotas(resourceQuotaList, out)
  169. }
  170. if limitRangeList != nil {
  171. fmt.Fprintf(out, "\n")
  172. DescribeLimitRanges(limitRangeList, out)
  173. }
  174. return nil
  175. })
  176. }
  177. // DescribeLimitRanges merges a set of limit range items into a single tabular description
  178. func DescribeLimitRanges(limitRanges *api.LimitRangeList, w io.Writer) {
  179. if len(limitRanges.Items) == 0 {
  180. fmt.Fprint(w, "No resource limits.\n")
  181. return
  182. }
  183. fmt.Fprintf(w, "Resource Limits\n Type\tResource\tMin\tMax\tDefault Request\tDefault Limit\tMax Limit/Request Ratio\n")
  184. fmt.Fprintf(w, " ----\t--------\t---\t---\t---------------\t-------------\t-----------------------\n")
  185. for _, limitRange := range limitRanges.Items {
  186. for i := range limitRange.Spec.Limits {
  187. item := limitRange.Spec.Limits[i]
  188. maxResources := item.Max
  189. minResources := item.Min
  190. defaultLimitResources := item.Default
  191. defaultRequestResources := item.DefaultRequest
  192. ratio := item.MaxLimitRequestRatio
  193. set := map[api.ResourceName]bool{}
  194. for k := range maxResources {
  195. set[k] = true
  196. }
  197. for k := range minResources {
  198. set[k] = true
  199. }
  200. for k := range defaultLimitResources {
  201. set[k] = true
  202. }
  203. for k := range defaultRequestResources {
  204. set[k] = true
  205. }
  206. for k := range ratio {
  207. set[k] = true
  208. }
  209. for k := range set {
  210. // if no value is set, we output -
  211. maxValue := "-"
  212. minValue := "-"
  213. defaultLimitValue := "-"
  214. defaultRequestValue := "-"
  215. ratioValue := "-"
  216. maxQuantity, maxQuantityFound := maxResources[k]
  217. if maxQuantityFound {
  218. maxValue = maxQuantity.String()
  219. }
  220. minQuantity, minQuantityFound := minResources[k]
  221. if minQuantityFound {
  222. minValue = minQuantity.String()
  223. }
  224. defaultLimitQuantity, defaultLimitQuantityFound := defaultLimitResources[k]
  225. if defaultLimitQuantityFound {
  226. defaultLimitValue = defaultLimitQuantity.String()
  227. }
  228. defaultRequestQuantity, defaultRequestQuantityFound := defaultRequestResources[k]
  229. if defaultRequestQuantityFound {
  230. defaultRequestValue = defaultRequestQuantity.String()
  231. }
  232. ratioQuantity, ratioQuantityFound := ratio[k]
  233. if ratioQuantityFound {
  234. ratioValue = ratioQuantity.String()
  235. }
  236. msg := " %s\t%v\t%v\t%v\t%v\t%v\t%v\n"
  237. fmt.Fprintf(w, msg, item.Type, k, minValue, maxValue, defaultRequestValue, defaultLimitValue, ratioValue)
  238. }
  239. }
  240. }
  241. }
  242. // DescribeResourceQuotas merges a set of quota items into a single tabular description of all quotas
  243. func DescribeResourceQuotas(quotas *api.ResourceQuotaList, w io.Writer) {
  244. if len(quotas.Items) == 0 {
  245. fmt.Fprint(w, "No resource quota.\n")
  246. return
  247. }
  248. sort.Sort(SortableResourceQuotas(quotas.Items))
  249. fmt.Fprint(w, "Resource Quotas")
  250. for _, q := range quotas.Items {
  251. fmt.Fprintf(w, "\n Name:\t%s\n", q.Name)
  252. if len(q.Spec.Scopes) > 0 {
  253. scopes := make([]string, 0, len(q.Spec.Scopes))
  254. for _, scope := range q.Spec.Scopes {
  255. scopes = append(scopes, string(scope))
  256. }
  257. sort.Strings(scopes)
  258. fmt.Fprintf(w, " Scopes:\t%s\n", strings.Join(scopes, ", "))
  259. for _, scope := range scopes {
  260. helpText := helpTextForResourceQuotaScope(api.ResourceQuotaScope(scope))
  261. if len(helpText) > 0 {
  262. fmt.Fprintf(w, " * %s\n", helpText)
  263. }
  264. }
  265. }
  266. fmt.Fprintf(w, " Resource\tUsed\tHard\n")
  267. fmt.Fprint(w, " --------\t---\t---\n")
  268. resources := make([]api.ResourceName, 0, len(q.Status.Hard))
  269. for resource := range q.Status.Hard {
  270. resources = append(resources, resource)
  271. }
  272. sort.Sort(SortableResourceNames(resources))
  273. for _, resource := range resources {
  274. hardQuantity := q.Status.Hard[resource]
  275. usedQuantity := q.Status.Used[resource]
  276. fmt.Fprintf(w, " %s\t%s\t%s\n", string(resource), usedQuantity.String(), hardQuantity.String())
  277. }
  278. }
  279. }
  280. // LimitRangeDescriber generates information about a limit range
  281. type LimitRangeDescriber struct {
  282. client.Interface
  283. }
  284. func (d *LimitRangeDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
  285. lr := d.LimitRanges(namespace)
  286. limitRange, err := lr.Get(name)
  287. if err != nil {
  288. return "", err
  289. }
  290. return describeLimitRange(limitRange)
  291. }
  292. func describeLimitRange(limitRange *api.LimitRange) (string, error) {
  293. return tabbedString(func(out io.Writer) error {
  294. fmt.Fprintf(out, "Name:\t%s\n", limitRange.Name)
  295. fmt.Fprintf(out, "Namespace:\t%s\n", limitRange.Namespace)
  296. fmt.Fprintf(out, "Type\tResource\tMin\tMax\tDefault Request\tDefault Limit\tMax Limit/Request Ratio\n")
  297. fmt.Fprintf(out, "----\t--------\t---\t---\t---------------\t-------------\t-----------------------\n")
  298. for i := range limitRange.Spec.Limits {
  299. item := limitRange.Spec.Limits[i]
  300. maxResources := item.Max
  301. minResources := item.Min
  302. defaultLimitResources := item.Default
  303. defaultRequestResources := item.DefaultRequest
  304. ratio := item.MaxLimitRequestRatio
  305. set := map[api.ResourceName]bool{}
  306. for k := range maxResources {
  307. set[k] = true
  308. }
  309. for k := range minResources {
  310. set[k] = true
  311. }
  312. for k := range defaultLimitResources {
  313. set[k] = true
  314. }
  315. for k := range defaultRequestResources {
  316. set[k] = true
  317. }
  318. for k := range ratio {
  319. set[k] = true
  320. }
  321. for k := range set {
  322. // if no value is set, we output -
  323. maxValue := "-"
  324. minValue := "-"
  325. defaultLimitValue := "-"
  326. defaultRequestValue := "-"
  327. ratioValue := "-"
  328. maxQuantity, maxQuantityFound := maxResources[k]
  329. if maxQuantityFound {
  330. maxValue = maxQuantity.String()
  331. }
  332. minQuantity, minQuantityFound := minResources[k]
  333. if minQuantityFound {
  334. minValue = minQuantity.String()
  335. }
  336. defaultLimitQuantity, defaultLimitQuantityFound := defaultLimitResources[k]
  337. if defaultLimitQuantityFound {
  338. defaultLimitValue = defaultLimitQuantity.String()
  339. }
  340. defaultRequestQuantity, defaultRequestQuantityFound := defaultRequestResources[k]
  341. if defaultRequestQuantityFound {
  342. defaultRequestValue = defaultRequestQuantity.String()
  343. }
  344. ratioQuantity, ratioQuantityFound := ratio[k]
  345. if ratioQuantityFound {
  346. ratioValue = ratioQuantity.String()
  347. }
  348. msg := "%v\t%v\t%v\t%v\t%v\t%v\t%v\n"
  349. fmt.Fprintf(out, msg, item.Type, k, minValue, maxValue, defaultRequestValue, defaultLimitValue, ratioValue)
  350. }
  351. }
  352. return nil
  353. })
  354. }
  355. // ResourceQuotaDescriber generates information about a resource quota
  356. type ResourceQuotaDescriber struct {
  357. client.Interface
  358. }
  359. func (d *ResourceQuotaDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
  360. rq := d.ResourceQuotas(namespace)
  361. resourceQuota, err := rq.Get(name)
  362. if err != nil {
  363. return "", err
  364. }
  365. return describeQuota(resourceQuota)
  366. }
  367. func helpTextForResourceQuotaScope(scope api.ResourceQuotaScope) string {
  368. switch scope {
  369. case api.ResourceQuotaScopeTerminating:
  370. return "Matches all pods that have an active deadline."
  371. case api.ResourceQuotaScopeNotTerminating:
  372. return "Matches all pods that do not have an active deadline."
  373. case api.ResourceQuotaScopeBestEffort:
  374. return "Matches all pods that have best effort quality of service."
  375. case api.ResourceQuotaScopeNotBestEffort:
  376. return "Matches all pods that do not have best effort quality of service."
  377. default:
  378. return ""
  379. }
  380. }
  381. func describeQuota(resourceQuota *api.ResourceQuota) (string, error) {
  382. return tabbedString(func(out io.Writer) error {
  383. fmt.Fprintf(out, "Name:\t%s\n", resourceQuota.Name)
  384. fmt.Fprintf(out, "Namespace:\t%s\n", resourceQuota.Namespace)
  385. if len(resourceQuota.Spec.Scopes) > 0 {
  386. scopes := make([]string, 0, len(resourceQuota.Spec.Scopes))
  387. for _, scope := range resourceQuota.Spec.Scopes {
  388. scopes = append(scopes, string(scope))
  389. }
  390. sort.Strings(scopes)
  391. fmt.Fprintf(out, "Scopes:\t%s\n", strings.Join(scopes, ", "))
  392. for _, scope := range scopes {
  393. helpText := helpTextForResourceQuotaScope(api.ResourceQuotaScope(scope))
  394. if len(helpText) > 0 {
  395. fmt.Fprintf(out, " * %s\n", helpText)
  396. }
  397. }
  398. }
  399. fmt.Fprintf(out, "Resource\tUsed\tHard\n")
  400. fmt.Fprintf(out, "--------\t----\t----\n")
  401. resources := make([]api.ResourceName, 0, len(resourceQuota.Status.Hard))
  402. for resource := range resourceQuota.Status.Hard {
  403. resources = append(resources, resource)
  404. }
  405. sort.Sort(SortableResourceNames(resources))
  406. msg := "%v\t%v\t%v\n"
  407. for i := range resources {
  408. resource := resources[i]
  409. hardQuantity := resourceQuota.Status.Hard[resource]
  410. usedQuantity := resourceQuota.Status.Used[resource]
  411. fmt.Fprintf(out, msg, resource, usedQuantity.String(), hardQuantity.String())
  412. }
  413. return nil
  414. })
  415. }
  416. // PodDescriber generates information about a pod and the replication controllers that
  417. // create it.
  418. type PodDescriber struct {
  419. client.Interface
  420. }
  421. func (d *PodDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
  422. pod, err := d.Pods(namespace).Get(name)
  423. if err != nil {
  424. if describerSettings.ShowEvents {
  425. eventsInterface := d.Events(namespace)
  426. selector := eventsInterface.GetFieldSelector(&name, &namespace, nil, nil)
  427. options := api.ListOptions{FieldSelector: selector}
  428. events, err2 := eventsInterface.List(options)
  429. if describerSettings.ShowEvents && err2 == nil && len(events.Items) > 0 {
  430. return tabbedString(func(out io.Writer) error {
  431. fmt.Fprintf(out, "Pod '%v': error '%v', but found events.\n", name, err)
  432. DescribeEvents(events, out)
  433. return nil
  434. })
  435. }
  436. }
  437. return "", err
  438. }
  439. var events *api.EventList
  440. if describerSettings.ShowEvents {
  441. if ref, err := api.GetReference(pod); err != nil {
  442. glog.Errorf("Unable to construct reference to '%#v': %v", pod, err)
  443. } else {
  444. ref.Kind = ""
  445. events, _ = d.Events(namespace).Search(ref)
  446. }
  447. }
  448. return describePod(pod, events)
  449. }
  450. func describePod(pod *api.Pod, events *api.EventList) (string, error) {
  451. return tabbedString(func(out io.Writer) error {
  452. fmt.Fprintf(out, "Name:\t%s\n", pod.Name)
  453. fmt.Fprintf(out, "Namespace:\t%s\n", pod.Namespace)
  454. fmt.Fprintf(out, "Node:\t%s\n", pod.Spec.NodeName+"/"+pod.Status.HostIP)
  455. if pod.Status.StartTime != nil {
  456. fmt.Fprintf(out, "Start Time:\t%s\n", pod.Status.StartTime.Time.Format(time.RFC1123Z))
  457. }
  458. printLabelsMultiline(out, "Labels", pod.Labels)
  459. if pod.DeletionTimestamp != nil {
  460. fmt.Fprintf(out, "Status:\tTerminating (expires %s)\n", pod.DeletionTimestamp.Time.Format(time.RFC1123Z))
  461. fmt.Fprintf(out, "Termination Grace Period:\t%ds\n", *pod.DeletionGracePeriodSeconds)
  462. } else {
  463. fmt.Fprintf(out, "Status:\t%s\n", string(pod.Status.Phase))
  464. }
  465. if len(pod.Status.Reason) > 0 {
  466. fmt.Fprintf(out, "Reason:\t%s\n", pod.Status.Reason)
  467. }
  468. if len(pod.Status.Message) > 0 {
  469. fmt.Fprintf(out, "Message:\t%s\n", pod.Status.Message)
  470. }
  471. fmt.Fprintf(out, "IP:\t%s\n", pod.Status.PodIP)
  472. fmt.Fprintf(out, "Controllers:\t%s\n", printControllers(pod.Annotations))
  473. if len(pod.Spec.InitContainers) > 0 {
  474. describeContainers("Init Containers", pod.Spec.InitContainers, pod.Status.InitContainerStatuses, EnvValueRetriever(pod), out, "")
  475. }
  476. describeContainers("Containers", pod.Spec.Containers, pod.Status.ContainerStatuses, EnvValueRetriever(pod), out, "")
  477. if len(pod.Status.Conditions) > 0 {
  478. fmt.Fprint(out, "Conditions:\n Type\tStatus\n")
  479. for _, c := range pod.Status.Conditions {
  480. fmt.Fprintf(out, " %v \t%v \n",
  481. c.Type,
  482. c.Status)
  483. }
  484. }
  485. describeVolumes(pod.Spec.Volumes, out, "")
  486. fmt.Fprintf(out, "QoS Class:\t%s\n", qos.GetPodQOS(pod))
  487. printTolerationsInAnnotationMultiline(out, "Tolerations", pod.Annotations)
  488. if events != nil {
  489. DescribeEvents(events, out)
  490. }
  491. return nil
  492. })
  493. }
  494. func printControllers(annotation map[string]string) string {
  495. value, ok := annotation[api.CreatedByAnnotation]
  496. if ok {
  497. var r api.SerializedReference
  498. err := json.Unmarshal([]byte(value), &r)
  499. if err == nil {
  500. return fmt.Sprintf("%s/%s", r.Reference.Kind, r.Reference.Name)
  501. }
  502. }
  503. return "<none>"
  504. }
  505. // TODO: Do a better job at indenting, maybe by using a prefix writer
  506. func describeVolumes(volumes []api.Volume, out io.Writer, space string) {
  507. if volumes == nil || len(volumes) == 0 {
  508. fmt.Fprintf(out, "%sNo volumes.\n", space)
  509. return
  510. }
  511. fmt.Fprintf(out, "%sVolumes:\n", space)
  512. for _, volume := range volumes {
  513. nameIndent := ""
  514. if len(space) > 0 {
  515. nameIndent = " "
  516. }
  517. fmt.Fprintf(out, " %s%v:\n", nameIndent, volume.Name)
  518. switch {
  519. case volume.VolumeSource.HostPath != nil:
  520. printHostPathVolumeSource(volume.VolumeSource.HostPath, out)
  521. case volume.VolumeSource.EmptyDir != nil:
  522. printEmptyDirVolumeSource(volume.VolumeSource.EmptyDir, out)
  523. case volume.VolumeSource.GCEPersistentDisk != nil:
  524. printGCEPersistentDiskVolumeSource(volume.VolumeSource.GCEPersistentDisk, out)
  525. case volume.VolumeSource.AWSElasticBlockStore != nil:
  526. printAWSElasticBlockStoreVolumeSource(volume.VolumeSource.AWSElasticBlockStore, out)
  527. case volume.VolumeSource.GitRepo != nil:
  528. printGitRepoVolumeSource(volume.VolumeSource.GitRepo, out)
  529. case volume.VolumeSource.Secret != nil:
  530. printSecretVolumeSource(volume.VolumeSource.Secret, out)
  531. case volume.VolumeSource.ConfigMap != nil:
  532. printConfigMapVolumeSource(volume.VolumeSource.ConfigMap, out)
  533. case volume.VolumeSource.NFS != nil:
  534. printNFSVolumeSource(volume.VolumeSource.NFS, out)
  535. case volume.VolumeSource.ISCSI != nil:
  536. printISCSIVolumeSource(volume.VolumeSource.ISCSI, out)
  537. case volume.VolumeSource.Glusterfs != nil:
  538. printGlusterfsVolumeSource(volume.VolumeSource.Glusterfs, out)
  539. case volume.VolumeSource.PersistentVolumeClaim != nil:
  540. printPersistentVolumeClaimVolumeSource(volume.VolumeSource.PersistentVolumeClaim, out)
  541. case volume.VolumeSource.RBD != nil:
  542. printRBDVolumeSource(volume.VolumeSource.RBD, out)
  543. case volume.VolumeSource.Quobyte != nil:
  544. printQuobyteVolumeSource(volume.VolumeSource.Quobyte, out)
  545. case volume.VolumeSource.DownwardAPI != nil:
  546. printDownwardAPIVolumeSource(volume.VolumeSource.DownwardAPI, out)
  547. case volume.VolumeSource.AzureDisk != nil:
  548. printAzureDiskVolumeSource(volume.VolumeSource.AzureDisk, out)
  549. default:
  550. fmt.Fprintf(out, " <unknown>\n")
  551. }
  552. }
  553. }
  554. func printHostPathVolumeSource(hostPath *api.HostPathVolumeSource, out io.Writer) {
  555. fmt.Fprintf(out, " Type:\tHostPath (bare host directory volume)\n"+
  556. " Path:\t%v\n", hostPath.Path)
  557. }
  558. func printEmptyDirVolumeSource(emptyDir *api.EmptyDirVolumeSource, out io.Writer) {
  559. fmt.Fprintf(out, " Type:\tEmptyDir (a temporary directory that shares a pod's lifetime)\n"+
  560. " Medium:\t%v\n", emptyDir.Medium)
  561. }
  562. func printGCEPersistentDiskVolumeSource(gce *api.GCEPersistentDiskVolumeSource, out io.Writer) {
  563. fmt.Fprintf(out, " Type:\tGCEPersistentDisk (a Persistent Disk resource in Google Compute Engine)\n"+
  564. " PDName:\t%v\n"+
  565. " FSType:\t%v\n"+
  566. " Partition:\t%v\n"+
  567. " ReadOnly:\t%v\n",
  568. gce.PDName, gce.FSType, gce.Partition, gce.ReadOnly)
  569. }
  570. func printAWSElasticBlockStoreVolumeSource(aws *api.AWSElasticBlockStoreVolumeSource, out io.Writer) {
  571. fmt.Fprintf(out, " Type:\tAWSElasticBlockStore (a Persistent Disk resource in AWS)\n"+
  572. " VolumeID:\t%v\n"+
  573. " FSType:\t%v\n"+
  574. " Partition:\t%v\n"+
  575. " ReadOnly:\t%v\n",
  576. aws.VolumeID, aws.FSType, aws.Partition, aws.ReadOnly)
  577. }
  578. func printGitRepoVolumeSource(git *api.GitRepoVolumeSource, out io.Writer) {
  579. fmt.Fprintf(out, " Type:\tGitRepo (a volume that is pulled from git when the pod is created)\n"+
  580. " Repository:\t%v\n"+
  581. " Revision:\t%v\n",
  582. git.Repository, git.Revision)
  583. }
  584. func printSecretVolumeSource(secret *api.SecretVolumeSource, out io.Writer) {
  585. fmt.Fprintf(out, " Type:\tSecret (a volume populated by a Secret)\n"+
  586. " SecretName:\t%v\n", secret.SecretName)
  587. }
  588. func printConfigMapVolumeSource(configMap *api.ConfigMapVolumeSource, out io.Writer) {
  589. fmt.Fprintf(out, " Type:\tConfigMap (a volume populated by a ConfigMap)\n"+
  590. " Name:\t%v\n", configMap.Name)
  591. }
  592. func printNFSVolumeSource(nfs *api.NFSVolumeSource, out io.Writer) {
  593. fmt.Fprintf(out, " Type:\tNFS (an NFS mount that lasts the lifetime of a pod)\n"+
  594. " Server:\t%v\n"+
  595. " Path:\t%v\n"+
  596. " ReadOnly:\t%v\n",
  597. nfs.Server, nfs.Path, nfs.ReadOnly)
  598. }
  599. func printQuobyteVolumeSource(quobyte *api.QuobyteVolumeSource, out io.Writer) {
  600. fmt.Fprintf(out, " Type:\tQuobyte (a Quobyte mount on the host that shares a pod's lifetime)\n"+
  601. " Registry:\t%v\n"+
  602. " Volume:\t%v\n"+
  603. " ReadOnly:\t%v\n",
  604. quobyte.Registry, quobyte.Volume, quobyte.ReadOnly)
  605. }
  606. func printISCSIVolumeSource(iscsi *api.ISCSIVolumeSource, out io.Writer) {
  607. fmt.Fprintf(out, " Type:\tISCSI (an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod)\n"+
  608. " TargetPortal:\t%v\n"+
  609. " IQN:\t%v\n"+
  610. " Lun:\t%v\n"+
  611. " ISCSIInterface\t%v\n"+
  612. " FSType:\t%v\n"+
  613. " ReadOnly:\t%v\n",
  614. iscsi.TargetPortal, iscsi.IQN, iscsi.Lun, iscsi.ISCSIInterface, iscsi.FSType, iscsi.ReadOnly)
  615. }
  616. func printGlusterfsVolumeSource(glusterfs *api.GlusterfsVolumeSource, out io.Writer) {
  617. fmt.Fprintf(out, " Type:\tGlusterfs (a Glusterfs mount on the host that shares a pod's lifetime)\n"+
  618. " EndpointsName:\t%v\n"+
  619. " Path:\t%v\n"+
  620. " ReadOnly:\t%v\n",
  621. glusterfs.EndpointsName, glusterfs.Path, glusterfs.ReadOnly)
  622. }
  623. func printPersistentVolumeClaimVolumeSource(claim *api.PersistentVolumeClaimVolumeSource, out io.Writer) {
  624. fmt.Fprintf(out, " Type:\tPersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)\n"+
  625. " ClaimName:\t%v\n"+
  626. " ReadOnly:\t%v\n",
  627. claim.ClaimName, claim.ReadOnly)
  628. }
  629. func printRBDVolumeSource(rbd *api.RBDVolumeSource, out io.Writer) {
  630. fmt.Fprintf(out, " Type:\tRBD (a Rados Block Device mount on the host that shares a pod's lifetime)\n"+
  631. " CephMonitors:\t%v\n"+
  632. " RBDImage:\t%v\n"+
  633. " FSType:\t%v\n"+
  634. " RBDPool:\t%v\n"+
  635. " RadosUser:\t%v\n"+
  636. " Keyring:\t%v\n"+
  637. " SecretRef:\t%v\n"+
  638. " ReadOnly:\t%v\n",
  639. rbd.CephMonitors, rbd.RBDImage, rbd.FSType, rbd.RBDPool, rbd.RadosUser, rbd.Keyring, rbd.SecretRef, rbd.ReadOnly)
  640. }
  641. func printDownwardAPIVolumeSource(d *api.DownwardAPIVolumeSource, out io.Writer) {
  642. fmt.Fprintf(out, " Type:\tDownwardAPI (a volume populated by information about the pod)\n Items:\n")
  643. for _, mapping := range d.Items {
  644. if mapping.FieldRef != nil {
  645. fmt.Fprintf(out, " %v -> %v\n", mapping.FieldRef.FieldPath, mapping.Path)
  646. }
  647. if mapping.ResourceFieldRef != nil {
  648. fmt.Fprintf(out, " %v -> %v\n", mapping.ResourceFieldRef.Resource, mapping.Path)
  649. }
  650. }
  651. }
  652. func printAzureDiskVolumeSource(d *api.AzureDiskVolumeSource, out io.Writer) {
  653. fmt.Fprintf(out, " Type:\tAzureDisk (an Azure Data Disk mount on the host and bind mount to the pod)\n"+
  654. " DiskName:\t%v\n"+
  655. " DiskURI:\t%v\n"+
  656. " FSType:\t%v\n"+
  657. " CachingMode:\t%v\n"+
  658. " ReadOnly:\t%v\n",
  659. d.DiskName, d.DataDiskURI, *d.FSType, *d.CachingMode, *d.ReadOnly)
  660. }
  661. type PersistentVolumeDescriber struct {
  662. client.Interface
  663. }
  664. func (d *PersistentVolumeDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
  665. c := d.PersistentVolumes()
  666. pv, err := c.Get(name)
  667. if err != nil {
  668. return "", err
  669. }
  670. storage := pv.Spec.Capacity[api.ResourceStorage]
  671. var events *api.EventList
  672. if describerSettings.ShowEvents {
  673. events, _ = d.Events(namespace).Search(pv)
  674. }
  675. return tabbedString(func(out io.Writer) error {
  676. fmt.Fprintf(out, "Name:\t%s\n", pv.Name)
  677. printLabelsMultiline(out, "Labels", pv.Labels)
  678. fmt.Fprintf(out, "Status:\t%s\n", pv.Status.Phase)
  679. if pv.Spec.ClaimRef != nil {
  680. fmt.Fprintf(out, "Claim:\t%s\n", pv.Spec.ClaimRef.Namespace+"/"+pv.Spec.ClaimRef.Name)
  681. } else {
  682. fmt.Fprintf(out, "Claim:\t%s\n", "")
  683. }
  684. fmt.Fprintf(out, "Reclaim Policy:\t%v\n", pv.Spec.PersistentVolumeReclaimPolicy)
  685. fmt.Fprintf(out, "Access Modes:\t%s\n", api.GetAccessModesAsString(pv.Spec.AccessModes))
  686. fmt.Fprintf(out, "Capacity:\t%s\n", storage.String())
  687. fmt.Fprintf(out, "Message:\t%s\n", pv.Status.Message)
  688. fmt.Fprintf(out, "Source:\n")
  689. switch {
  690. case pv.Spec.HostPath != nil:
  691. printHostPathVolumeSource(pv.Spec.HostPath, out)
  692. case pv.Spec.GCEPersistentDisk != nil:
  693. printGCEPersistentDiskVolumeSource(pv.Spec.GCEPersistentDisk, out)
  694. case pv.Spec.AWSElasticBlockStore != nil:
  695. printAWSElasticBlockStoreVolumeSource(pv.Spec.AWSElasticBlockStore, out)
  696. case pv.Spec.NFS != nil:
  697. printNFSVolumeSource(pv.Spec.NFS, out)
  698. case pv.Spec.ISCSI != nil:
  699. printISCSIVolumeSource(pv.Spec.ISCSI, out)
  700. case pv.Spec.Glusterfs != nil:
  701. printGlusterfsVolumeSource(pv.Spec.Glusterfs, out)
  702. case pv.Spec.RBD != nil:
  703. printRBDVolumeSource(pv.Spec.RBD, out)
  704. case pv.Spec.Quobyte != nil:
  705. printQuobyteVolumeSource(pv.Spec.Quobyte, out)
  706. }
  707. if events != nil {
  708. DescribeEvents(events, out)
  709. }
  710. return nil
  711. })
  712. }
  713. type PersistentVolumeClaimDescriber struct {
  714. client.Interface
  715. }
  716. func (d *PersistentVolumeClaimDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
  717. c := d.PersistentVolumeClaims(namespace)
  718. pvc, err := c.Get(name)
  719. if err != nil {
  720. return "", err
  721. }
  722. storage := pvc.Spec.Resources.Requests[api.ResourceStorage]
  723. capacity := ""
  724. accessModes := ""
  725. if pvc.Spec.VolumeName != "" {
  726. accessModes = api.GetAccessModesAsString(pvc.Status.AccessModes)
  727. storage = pvc.Status.Capacity[api.ResourceStorage]
  728. capacity = storage.String()
  729. }
  730. events, _ := d.Events(namespace).Search(pvc)
  731. return tabbedString(func(out io.Writer) error {
  732. fmt.Fprintf(out, "Name:\t%s\n", pvc.Name)
  733. fmt.Fprintf(out, "Namespace:\t%s\n", pvc.Namespace)
  734. fmt.Fprintf(out, "Status:\t%v\n", pvc.Status.Phase)
  735. fmt.Fprintf(out, "Volume:\t%s\n", pvc.Spec.VolumeName)
  736. printLabelsMultiline(out, "Labels", pvc.Labels)
  737. fmt.Fprintf(out, "Capacity:\t%s\n", capacity)
  738. fmt.Fprintf(out, "Access Modes:\t%s\n", accessModes)
  739. if events != nil {
  740. DescribeEvents(events, out)
  741. }
  742. return nil
  743. })
  744. }
  745. // TODO: Do a better job at indenting, maybe by using a prefix writer
  746. func describeContainers(label string, containers []api.Container, containerStatuses []api.ContainerStatus, resolverFn EnvVarResolverFunc, out io.Writer, space string) {
  747. statuses := map[string]api.ContainerStatus{}
  748. for _, status := range containerStatuses {
  749. statuses[status.Name] = status
  750. }
  751. if len(containers) == 0 {
  752. fmt.Fprintf(out, "%s%s: <none>\n", space, label)
  753. } else {
  754. fmt.Fprintf(out, "%s%s:\n", space, label)
  755. }
  756. for _, container := range containers {
  757. status, ok := statuses[container.Name]
  758. nameIndent := ""
  759. if len(space) > 0 {
  760. nameIndent = " "
  761. }
  762. fmt.Fprintf(out, " %s%v:\n", nameIndent, container.Name)
  763. if ok {
  764. fmt.Fprintf(out, " Container ID:\t%s\n", status.ContainerID)
  765. }
  766. fmt.Fprintf(out, " Image:\t%s\n", container.Image)
  767. if ok {
  768. fmt.Fprintf(out, " Image ID:\t%s\n", status.ImageID)
  769. }
  770. portString := describeContainerPorts(container.Ports)
  771. if strings.Contains(portString, ",") {
  772. fmt.Fprintf(out, " Ports:\t%s\n", portString)
  773. } else {
  774. fmt.Fprintf(out, " Port:\t%s\n", portString)
  775. }
  776. if len(container.Command) > 0 {
  777. fmt.Fprintf(out, " Command:\n")
  778. for _, c := range container.Command {
  779. fmt.Fprintf(out, " %s\n", c)
  780. }
  781. }
  782. if len(container.Args) > 0 {
  783. fmt.Fprintf(out, " Args:\n")
  784. for _, arg := range container.Args {
  785. fmt.Fprintf(out, " %s\n", arg)
  786. }
  787. }
  788. resources := container.Resources
  789. if len(resources.Limits) > 0 {
  790. fmt.Fprintf(out, " Limits:\n")
  791. }
  792. for _, name := range SortedResourceNames(resources.Limits) {
  793. quantity := resources.Limits[name]
  794. fmt.Fprintf(out, " %s:\t%s\n", name, quantity.String())
  795. }
  796. if len(resources.Requests) > 0 {
  797. fmt.Fprintf(out, " Requests:\n")
  798. }
  799. for _, name := range SortedResourceNames(resources.Requests) {
  800. quantity := resources.Requests[name]
  801. fmt.Fprintf(out, " %s:\t%s\n", name, quantity.String())
  802. }
  803. if ok {
  804. describeStatus("State", status.State, out)
  805. if status.LastTerminationState.Terminated != nil {
  806. describeStatus("Last State", status.LastTerminationState, out)
  807. }
  808. fmt.Fprintf(out, " Ready:\t%v\n", printBool(status.Ready))
  809. fmt.Fprintf(out, " Restart Count:\t%d\n", status.RestartCount)
  810. }
  811. if container.LivenessProbe != nil {
  812. probe := DescribeProbe(container.LivenessProbe)
  813. fmt.Fprintf(out, " Liveness:\t%s\n", probe)
  814. }
  815. if container.ReadinessProbe != nil {
  816. probe := DescribeProbe(container.ReadinessProbe)
  817. fmt.Fprintf(out, " Readiness:\t%s\n", probe)
  818. }
  819. none := ""
  820. if len(container.VolumeMounts) == 0 {
  821. none = "\t<none>"
  822. }
  823. fmt.Fprintf(out, " Volume Mounts:%s\n", none)
  824. sort.Sort(SortableVolumeMounts(container.VolumeMounts))
  825. for _, mount := range container.VolumeMounts {
  826. flags := []string{}
  827. switch {
  828. case mount.ReadOnly:
  829. flags = append(flags, "ro")
  830. case !mount.ReadOnly:
  831. flags = append(flags, "rw")
  832. case len(mount.SubPath) > 0:
  833. flags = append(flags, fmt.Sprintf("path=%q", mount.SubPath))
  834. }
  835. fmt.Fprintf(out, " %s from %s (%s)\n", mount.MountPath, mount.Name, strings.Join(flags, ","))
  836. }
  837. none = ""
  838. if len(container.Env) == 0 {
  839. none = "\t<none>"
  840. }
  841. fmt.Fprintf(out, " Environment Variables:%s\n", none)
  842. for _, e := range container.Env {
  843. if e.ValueFrom == nil {
  844. fmt.Fprintf(out, " %s:\t%s\n", e.Name, e.Value)
  845. continue
  846. }
  847. switch {
  848. case e.ValueFrom.FieldRef != nil:
  849. var valueFrom string
  850. if resolverFn != nil {
  851. valueFrom = resolverFn(e)
  852. }
  853. fmt.Fprintf(out, " %s:\t%s (%s:%s)\n", e.Name, valueFrom, e.ValueFrom.FieldRef.APIVersion, e.ValueFrom.FieldRef.FieldPath)
  854. case e.ValueFrom.ResourceFieldRef != nil:
  855. valueFrom, err := fieldpath.ExtractContainerResourceValue(e.ValueFrom.ResourceFieldRef, &container)
  856. if err != nil {
  857. valueFrom = ""
  858. }
  859. resource := e.ValueFrom.ResourceFieldRef.Resource
  860. if valueFrom == "0" && (resource == "limits.cpu" || resource == "limits.memory") {
  861. valueFrom = "node allocatable"
  862. }
  863. fmt.Fprintf(out, " %s:\t%s (%s)\n", e.Name, valueFrom, resource)
  864. case e.ValueFrom.SecretKeyRef != nil:
  865. fmt.Fprintf(out, " %s:\t<set to the key '%s' in secret '%s'>\n", e.Name, e.ValueFrom.SecretKeyRef.Key, e.ValueFrom.SecretKeyRef.Name)
  866. case e.ValueFrom.ConfigMapKeyRef != nil:
  867. fmt.Fprintf(out, " %s:\t<set to the key '%s' of config map '%s'>\n", e.Name, e.ValueFrom.ConfigMapKeyRef.Key, e.ValueFrom.ConfigMapKeyRef.Name)
  868. }
  869. }
  870. }
  871. }
  872. func describeContainerPorts(cPorts []api.ContainerPort) string {
  873. ports := make([]string, 0, len(cPorts))
  874. for _, cPort := range cPorts {
  875. ports = append(ports, fmt.Sprintf("%d/%s", cPort.ContainerPort, cPort.Protocol))
  876. }
  877. return strings.Join(ports, ", ")
  878. }
  879. // DescribeProbe is exported for consumers in other API groups that have probes
  880. func DescribeProbe(probe *api.Probe) string {
  881. attrs := fmt.Sprintf("delay=%ds timeout=%ds period=%ds #success=%d #failure=%d", probe.InitialDelaySeconds, probe.TimeoutSeconds, probe.PeriodSeconds, probe.SuccessThreshold, probe.FailureThreshold)
  882. switch {
  883. case probe.Exec != nil:
  884. return fmt.Sprintf("exec %v %s", probe.Exec.Command, attrs)
  885. case probe.HTTPGet != nil:
  886. url := &url.URL{}
  887. url.Scheme = strings.ToLower(string(probe.HTTPGet.Scheme))
  888. if len(probe.HTTPGet.Port.String()) > 0 {
  889. url.Host = net.JoinHostPort(probe.HTTPGet.Host, probe.HTTPGet.Port.String())
  890. } else {
  891. url.Host = probe.HTTPGet.Host
  892. }
  893. url.Path = probe.HTTPGet.Path
  894. return fmt.Sprintf("http-get %s %s", url.String(), attrs)
  895. case probe.TCPSocket != nil:
  896. return fmt.Sprintf("tcp-socket :%s %s", probe.TCPSocket.Port.String(), attrs)
  897. }
  898. return fmt.Sprintf("unknown %s", attrs)
  899. }
  900. type EnvVarResolverFunc func(e api.EnvVar) string
  901. // EnvValueFrom is exported for use by describers in other packages
  902. func EnvValueRetriever(pod *api.Pod) EnvVarResolverFunc {
  903. return func(e api.EnvVar) string {
  904. internalFieldPath, _, err := api.Scheme.ConvertFieldLabel(e.ValueFrom.FieldRef.APIVersion, "Pod", e.ValueFrom.FieldRef.FieldPath, "")
  905. if err != nil {
  906. return "" // pod validation should catch this on create
  907. }
  908. valueFrom, err := fieldpath.ExtractFieldPathAsString(pod, internalFieldPath)
  909. if err != nil {
  910. return "" // pod validation should catch this on create
  911. }
  912. return valueFrom
  913. }
  914. }
  915. func describeStatus(stateName string, state api.ContainerState, out io.Writer) {
  916. switch {
  917. case state.Running != nil:
  918. fmt.Fprintf(out, " %s:\tRunning\n", stateName)
  919. fmt.Fprintf(out, " Started:\t%v\n", state.Running.StartedAt.Time.Format(time.RFC1123Z))
  920. case state.Waiting != nil:
  921. fmt.Fprintf(out, " %s:\tWaiting\n", stateName)
  922. if state.Waiting.Reason != "" {
  923. fmt.Fprintf(out, " Reason:\t%s\n", state.Waiting.Reason)
  924. }
  925. case state.Terminated != nil:
  926. fmt.Fprintf(out, " %s:\tTerminated\n", stateName)
  927. if state.Terminated.Reason != "" {
  928. fmt.Fprintf(out, " Reason:\t%s\n", state.Terminated.Reason)
  929. }
  930. if state.Terminated.Message != "" {
  931. fmt.Fprintf(out, " Message:\t%s\n", state.Terminated.Message)
  932. }
  933. fmt.Fprintf(out, " Exit Code:\t%d\n", state.Terminated.ExitCode)
  934. if state.Terminated.Signal > 0 {
  935. fmt.Fprintf(out, " Signal:\t%d\n", state.Terminated.Signal)
  936. }
  937. fmt.Fprintf(out, " Started:\t%s\n", state.Terminated.StartedAt.Time.Format(time.RFC1123Z))
  938. fmt.Fprintf(out, " Finished:\t%s\n", state.Terminated.FinishedAt.Time.Format(time.RFC1123Z))
  939. default:
  940. fmt.Fprintf(out, " %s:\tWaiting\n", stateName)
  941. }
  942. }
  943. func printBoolPtr(value *bool) string {
  944. if value != nil {
  945. return printBool(*value)
  946. }
  947. return "<unset>"
  948. }
  949. func printBool(value bool) string {
  950. if value {
  951. return "True"
  952. }
  953. return "False"
  954. }
  955. // ReplicationControllerDescriber generates information about a replication controller
  956. // and the pods it has created.
  957. type ReplicationControllerDescriber struct {
  958. client.Interface
  959. }
  960. func (d *ReplicationControllerDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
  961. rc := d.ReplicationControllers(namespace)
  962. pc := d.Pods(namespace)
  963. controller, err := rc.Get(name)
  964. if err != nil {
  965. return "", err
  966. }
  967. running, waiting, succeeded, failed, err := getPodStatusForController(pc, labels.SelectorFromSet(controller.Spec.Selector))
  968. if err != nil {
  969. return "", err
  970. }
  971. var events *api.EventList
  972. if describerSettings.ShowEvents {
  973. events, _ = d.Events(namespace).Search(controller)
  974. }
  975. return describeReplicationController(controller, events, running, waiting, succeeded, failed)
  976. }
  977. func describeReplicationController(controller *api.ReplicationController, events *api.EventList, running, waiting, succeeded, failed int) (string, error) {
  978. return tabbedString(func(out io.Writer) error {
  979. fmt.Fprintf(out, "Name:\t%s\n", controller.Name)
  980. fmt.Fprintf(out, "Namespace:\t%s\n", controller.Namespace)
  981. if controller.Spec.Template != nil {
  982. fmt.Fprintf(out, "Image(s):\t%s\n", makeImageList(&controller.Spec.Template.Spec))
  983. } else {
  984. fmt.Fprintf(out, "Image(s):\t%s\n", "<unset>")
  985. }
  986. fmt.Fprintf(out, "Selector:\t%s\n", labels.FormatLabels(controller.Spec.Selector))
  987. printLabelsMultiline(out, "Labels", controller.Labels)
  988. fmt.Fprintf(out, "Replicas:\t%d current / %d desired\n", controller.Status.Replicas, controller.Spec.Replicas)
  989. fmt.Fprintf(out, "Pods Status:\t%d Running / %d Waiting / %d Succeeded / %d Failed\n", running, waiting, succeeded, failed)
  990. if controller.Spec.Template != nil {
  991. describeVolumes(controller.Spec.Template.Spec.Volumes, out, "")
  992. }
  993. if events != nil {
  994. DescribeEvents(events, out)
  995. }
  996. return nil
  997. })
  998. }
  999. func DescribePodTemplate(template *api.PodTemplateSpec, out io.Writer) {
  1000. if template == nil {
  1001. fmt.Fprintf(out, " <unset>")
  1002. return
  1003. }
  1004. printLabelsMultiline(out, " Labels", template.Labels)
  1005. if len(template.Annotations) > 0 {
  1006. printLabelsMultiline(out, " Annotations", template.Annotations)
  1007. }
  1008. if len(template.Spec.ServiceAccountName) > 0 {
  1009. fmt.Fprintf(out, " Service Account:\t%s\n", template.Spec.ServiceAccountName)
  1010. }
  1011. if len(template.Spec.InitContainers) > 0 {
  1012. describeContainers("Init Containers", template.Spec.InitContainers, nil, nil, out, " ")
  1013. }
  1014. describeContainers("Containers", template.Spec.Containers, nil, nil, out, " ")
  1015. describeVolumes(template.Spec.Volumes, out, " ")
  1016. }
  1017. // ReplicaSetDescriber generates information about a ReplicaSet and the pods it has created.
  1018. type ReplicaSetDescriber struct {
  1019. client.Interface
  1020. }
  1021. func (d *ReplicaSetDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
  1022. rsc := d.Extensions().ReplicaSets(namespace)
  1023. pc := d.Pods(namespace)
  1024. rs, err := rsc.Get(name)
  1025. if err != nil {
  1026. return "", err
  1027. }
  1028. selector, err := unversioned.LabelSelectorAsSelector(rs.Spec.Selector)
  1029. if err != nil {
  1030. return "", err
  1031. }
  1032. running, waiting, succeeded, failed, err := getPodStatusForController(pc, selector)
  1033. if err != nil {
  1034. return "", err
  1035. }
  1036. var events *api.EventList
  1037. if describerSettings.ShowEvents {
  1038. events, _ = d.Events(namespace).Search(rs)
  1039. }
  1040. return describeReplicaSet(rs, events, running, waiting, succeeded, failed)
  1041. }
  1042. func describeReplicaSet(rs *extensions.ReplicaSet, events *api.EventList, running, waiting, succeeded, failed int) (string, error) {
  1043. return tabbedString(func(out io.Writer) error {
  1044. fmt.Fprintf(out, "Name:\t%s\n", rs.Name)
  1045. fmt.Fprintf(out, "Namespace:\t%s\n", rs.Namespace)
  1046. fmt.Fprintf(out, "Image(s):\t%s\n", makeImageList(&rs.Spec.Template.Spec))
  1047. fmt.Fprintf(out, "Selector:\t%s\n", unversioned.FormatLabelSelector(rs.Spec.Selector))
  1048. printLabelsMultiline(out, "Labels", rs.Labels)
  1049. fmt.Fprintf(out, "Replicas:\t%d current / %d desired\n", rs.Status.Replicas, rs.Spec.Replicas)
  1050. fmt.Fprintf(out, "Pods Status:\t%d Running / %d Waiting / %d Succeeded / %d Failed\n", running, waiting, succeeded, failed)
  1051. describeVolumes(rs.Spec.Template.Spec.Volumes, out, "")
  1052. if events != nil {
  1053. DescribeEvents(events, out)
  1054. }
  1055. return nil
  1056. })
  1057. }
  1058. // JobDescriber generates information about a job and the pods it has created.
  1059. type JobDescriber struct {
  1060. client.Interface
  1061. }
  1062. func (d *JobDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
  1063. job, err := d.Batch().Jobs(namespace).Get(name)
  1064. if err != nil {
  1065. return "", err
  1066. }
  1067. var events *api.EventList
  1068. if describerSettings.ShowEvents {
  1069. events, _ = d.Events(namespace).Search(job)
  1070. }
  1071. return describeJob(job, events)
  1072. }
  1073. func describeJob(job *batch.Job, events *api.EventList) (string, error) {
  1074. return tabbedString(func(out io.Writer) error {
  1075. fmt.Fprintf(out, "Name:\t%s\n", job.Name)
  1076. fmt.Fprintf(out, "Namespace:\t%s\n", job.Namespace)
  1077. fmt.Fprintf(out, "Image(s):\t%s\n", makeImageList(&job.Spec.Template.Spec))
  1078. selector, _ := unversioned.LabelSelectorAsSelector(job.Spec.Selector)
  1079. fmt.Fprintf(out, "Selector:\t%s\n", selector)
  1080. fmt.Fprintf(out, "Parallelism:\t%d\n", *job.Spec.Parallelism)
  1081. if job.Spec.Completions != nil {
  1082. fmt.Fprintf(out, "Completions:\t%d\n", *job.Spec.Completions)
  1083. } else {
  1084. fmt.Fprintf(out, "Completions:\t<unset>\n")
  1085. }
  1086. if job.Status.StartTime != nil {
  1087. fmt.Fprintf(out, "Start Time:\t%s\n", job.Status.StartTime.Time.Format(time.RFC1123Z))
  1088. }
  1089. if job.Spec.ActiveDeadlineSeconds != nil {
  1090. fmt.Fprintf(out, "Active Deadline Seconds:\t%ds\n", *job.Spec.ActiveDeadlineSeconds)
  1091. }
  1092. printLabelsMultiline(out, "Labels", job.Labels)
  1093. fmt.Fprintf(out, "Pods Statuses:\t%d Running / %d Succeeded / %d Failed\n", job.Status.Active, job.Status.Succeeded, job.Status.Failed)
  1094. describeVolumes(job.Spec.Template.Spec.Volumes, out, "")
  1095. if events != nil {
  1096. DescribeEvents(events, out)
  1097. }
  1098. return nil
  1099. })
  1100. }
  1101. // ScheduledJobDescriber generates information about a scheduled job and the jobs it has created.
  1102. type ScheduledJobDescriber struct {
  1103. clientset.Interface
  1104. }
  1105. func (d *ScheduledJobDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
  1106. scheduledJob, err := d.Batch().ScheduledJobs(namespace).Get(name)
  1107. if err != nil {
  1108. return "", err
  1109. }
  1110. var events *api.EventList
  1111. if describerSettings.ShowEvents {
  1112. events, _ = d.Core().Events(namespace).Search(scheduledJob)
  1113. }
  1114. return describeScheduledJob(scheduledJob, events)
  1115. }
  1116. func describeScheduledJob(scheduledJob *batch.ScheduledJob, events *api.EventList) (string, error) {
  1117. return tabbedString(func(out io.Writer) error {
  1118. fmt.Fprintf(out, "Name:\t%s\n", scheduledJob.Name)
  1119. fmt.Fprintf(out, "Namespace:\t%s\n", scheduledJob.Namespace)
  1120. fmt.Fprintf(out, "Schedule:\t%s\n", scheduledJob.Spec.Schedule)
  1121. fmt.Fprintf(out, "Concurrency Policy:\t%s\n", scheduledJob.Spec.ConcurrencyPolicy)
  1122. fmt.Fprintf(out, "Suspend:\t%s\n", printBoolPtr(scheduledJob.Spec.Suspend))
  1123. if scheduledJob.Spec.StartingDeadlineSeconds != nil {
  1124. fmt.Fprintf(out, "Starting Deadline Seconds:\t%ds\n", *scheduledJob.Spec.StartingDeadlineSeconds)
  1125. } else {
  1126. fmt.Fprintf(out, "Starting Deadline Seconds:\t<unset>\n")
  1127. }
  1128. describeJobTemplate(scheduledJob.Spec.JobTemplate, out)
  1129. printLabelsMultiline(out, "Labels", scheduledJob.Labels)
  1130. if scheduledJob.Status.LastScheduleTime != nil {
  1131. fmt.Fprintf(out, "Last Schedule Time:\t%s\n", scheduledJob.Status.LastScheduleTime.Time.Format(time.RFC1123Z))
  1132. } else {
  1133. fmt.Fprintf(out, "Last Schedule Time:\t<unset>\n")
  1134. }
  1135. printActiveJobs(out, "Active Jobs", scheduledJob.Status.Active)
  1136. if events != nil {
  1137. DescribeEvents(events, out)
  1138. }
  1139. return nil
  1140. })
  1141. }
  1142. func describeJobTemplate(jobTemplate batch.JobTemplateSpec, out io.Writer) {
  1143. fmt.Fprintf(out, "Image(s):\t%s\n", makeImageList(&jobTemplate.Spec.Template.Spec))
  1144. if jobTemplate.Spec.Selector != nil {
  1145. selector, _ := unversioned.LabelSelectorAsSelector(jobTemplate.Spec.Selector)
  1146. fmt.Fprintf(out, "Selector:\t%s\n", selector)
  1147. } else {
  1148. fmt.Fprintf(out, "Selector:\t<unset>\n")
  1149. }
  1150. if jobTemplate.Spec.Parallelism != nil {
  1151. fmt.Fprintf(out, "Parallelism:\t%d\n", *jobTemplate.Spec.Parallelism)
  1152. } else {
  1153. fmt.Fprintf(out, "Parallelism:\t<unset>\n")
  1154. }
  1155. if jobTemplate.Spec.Completions != nil {
  1156. fmt.Fprintf(out, "Completions:\t%d\n", *jobTemplate.Spec.Completions)
  1157. } else {
  1158. fmt.Fprintf(out, "Completions:\t<unset>\n")
  1159. }
  1160. if jobTemplate.Spec.ActiveDeadlineSeconds != nil {
  1161. fmt.Fprintf(out, "Active Deadline Seconds:\t%ds\n", *jobTemplate.Spec.ActiveDeadlineSeconds)
  1162. }
  1163. describeVolumes(jobTemplate.Spec.Template.Spec.Volumes, out, "")
  1164. }
  1165. func printActiveJobs(out io.Writer, title string, jobs []api.ObjectReference) {
  1166. fmt.Fprintf(out, "%s:\t", title)
  1167. if len(jobs) == 0 {
  1168. fmt.Fprintln(out, "<none>")
  1169. return
  1170. }
  1171. for i, job := range jobs {
  1172. if i != 0 {
  1173. fmt.Fprint(out, ", ")
  1174. }
  1175. fmt.Fprintf(out, "%s", job.Name)
  1176. }
  1177. fmt.Fprintln(out, "")
  1178. }
  1179. // DaemonSetDescriber generates information about a daemon set and the pods it has created.
  1180. type DaemonSetDescriber struct {
  1181. client.Interface
  1182. }
  1183. func (d *DaemonSetDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
  1184. dc := d.Extensions().DaemonSets(namespace)
  1185. pc := d.Pods(namespace)
  1186. daemon, err := dc.Get(name)
  1187. if err != nil {
  1188. return "", err
  1189. }
  1190. selector, err := unversioned.LabelSelectorAsSelector(daemon.Spec.Selector)
  1191. if err != nil {
  1192. return "", err
  1193. }
  1194. running, waiting, succeeded, failed, err := getPodStatusForController(pc, selector)
  1195. if err != nil {
  1196. return "", err
  1197. }
  1198. var events *api.EventList
  1199. if describerSettings.ShowEvents {
  1200. events, _ = d.Events(namespace).Search(daemon)
  1201. }
  1202. return describeDaemonSet(daemon, events, running, waiting, succeeded, failed)
  1203. }
  1204. func describeDaemonSet(daemon *extensions.DaemonSet, events *api.EventList, running, waiting, succeeded, failed int) (string, error) {
  1205. return tabbedString(func(out io.Writer) error {
  1206. fmt.Fprintf(out, "Name:\t%s\n", daemon.Name)
  1207. fmt.Fprintf(out, "Image(s):\t%s\n", makeImageList(&daemon.Spec.Template.Spec))
  1208. selector, err := unversioned.LabelSelectorAsSelector(daemon.Spec.Selector)
  1209. if err != nil {
  1210. // this shouldn't happen if LabelSelector passed validation
  1211. return err
  1212. }
  1213. fmt.Fprintf(out, "Selector:\t%s\n", selector)
  1214. fmt.Fprintf(out, "Node-Selector:\t%s\n", labels.FormatLabels(daemon.Spec.Template.Spec.NodeSelector))
  1215. printLabelsMultiline(out, "Labels", daemon.Labels)
  1216. fmt.Fprintf(out, "Desired Number of Nodes Scheduled: %d\n", daemon.Status.DesiredNumberScheduled)
  1217. fmt.Fprintf(out, "Current Number of Nodes Scheduled: %d\n", daemon.Status.CurrentNumberScheduled)
  1218. fmt.Fprintf(out, "Number of Nodes Misscheduled: %d\n", daemon.Status.NumberMisscheduled)
  1219. fmt.Fprintf(out, "Pods Status:\t%d Running / %d Waiting / %d Succeeded / %d Failed\n", running, waiting, succeeded, failed)
  1220. if events != nil {
  1221. DescribeEvents(events, out)
  1222. }
  1223. return nil
  1224. })
  1225. }
  1226. // SecretDescriber generates information about a secret
  1227. type SecretDescriber struct {
  1228. client.Interface
  1229. }
  1230. func (d *SecretDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
  1231. c := d.Secrets(namespace)
  1232. secret, err := c.Get(name)
  1233. if err != nil {
  1234. return "", err
  1235. }
  1236. return describeSecret(secret)
  1237. }
  1238. func describeSecret(secret *api.Secret) (string, error) {
  1239. return tabbedString(func(out io.Writer) error {
  1240. fmt.Fprintf(out, "Name:\t%s\n", secret.Name)
  1241. fmt.Fprintf(out, "Namespace:\t%s\n", secret.Namespace)
  1242. printLabelsMultiline(out, "Labels", secret.Labels)
  1243. printLabelsMultiline(out, "Annotations", secret.Annotations)
  1244. fmt.Fprintf(out, "\nType:\t%s\n", secret.Type)
  1245. fmt.Fprintf(out, "\nData\n====\n")
  1246. for k, v := range secret.Data {
  1247. switch {
  1248. case k == api.ServiceAccountTokenKey && secret.Type == api.SecretTypeServiceAccountToken:
  1249. fmt.Fprintf(out, "%s:\t%s\n", k, string(v))
  1250. default:
  1251. fmt.Fprintf(out, "%s:\t%d bytes\n", k, len(v))
  1252. }
  1253. }
  1254. return nil
  1255. })
  1256. }
  1257. type IngressDescriber struct {
  1258. client.Interface
  1259. }
  1260. func (i *IngressDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
  1261. c := i.Extensions().Ingress(namespace)
  1262. ing, err := c.Get(name)
  1263. if err != nil {
  1264. return "", err
  1265. }
  1266. return i.describeIngress(ing, describerSettings)
  1267. }
  1268. func (i *IngressDescriber) describeBackend(ns string, backend *extensions.IngressBackend) string {
  1269. endpoints, _ := i.Endpoints(ns).Get(backend.ServiceName)
  1270. service, _ := i.Services(ns).Get(backend.ServiceName)
  1271. spName := ""
  1272. for i := range service.Spec.Ports {
  1273. sp := &service.Spec.Ports[i]
  1274. switch backend.ServicePort.Type {
  1275. case intstr.String:
  1276. if backend.ServicePort.StrVal == sp.Name {
  1277. spName = sp.Name
  1278. }
  1279. case intstr.Int:
  1280. if int32(backend.ServicePort.IntVal) == sp.Port {
  1281. spName = sp.Name
  1282. }
  1283. }
  1284. }
  1285. return formatEndpoints(endpoints, sets.NewString(spName))
  1286. }
  1287. func (i *IngressDescriber) describeIngress(ing *extensions.Ingress, describerSettings DescriberSettings) (string, error) {
  1288. return tabbedString(func(out io.Writer) error {
  1289. fmt.Fprintf(out, "Name:\t%v\n", ing.Name)
  1290. fmt.Fprintf(out, "Namespace:\t%v\n", ing.Namespace)
  1291. fmt.Fprintf(out, "Address:\t%v\n", loadBalancerStatusStringer(ing.Status.LoadBalancer, true))
  1292. def := ing.Spec.Backend
  1293. ns := ing.Namespace
  1294. if def == nil {
  1295. // Ingresses that don't specify a default backend inherit the
  1296. // default backend in the kube-system namespace.
  1297. def = &extensions.IngressBackend{
  1298. ServiceName: "default-http-backend",
  1299. ServicePort: intstr.IntOrString{Type: intstr.Int, IntVal: 80},
  1300. }
  1301. ns = api.NamespaceSystem
  1302. }
  1303. fmt.Fprintf(out, "Default backend:\t%s (%s)\n", backendStringer(def), i.describeBackend(ns, def))
  1304. if len(ing.Spec.TLS) != 0 {
  1305. describeIngressTLS(out, ing.Spec.TLS)
  1306. }
  1307. fmt.Fprint(out, "Rules:\n Host\tPath\tBackends\n")
  1308. fmt.Fprint(out, " ----\t----\t--------\n")
  1309. count := 0
  1310. for _, rules := range ing.Spec.Rules {
  1311. if rules.HTTP == nil {
  1312. continue
  1313. }
  1314. count++
  1315. host := rules.Host
  1316. if len(host) == 0 {
  1317. host = "*"
  1318. }
  1319. fmt.Fprintf(out, " %s\t\n", host)
  1320. for _, path := range rules.HTTP.Paths {
  1321. fmt.Fprintf(out, " \t%s \t%s (%s)\n", path.Path, backendStringer(&path.Backend), i.describeBackend(ns, &path.Backend))
  1322. }
  1323. }
  1324. if count == 0 {
  1325. fmt.Fprintf(out, " %s\t%s \t%s (%s)\n", "*", "*", backendStringer(def), i.describeBackend(ns, def))
  1326. }
  1327. describeIngressAnnotations(out, ing.Annotations)
  1328. if describerSettings.ShowEvents {
  1329. events, _ := i.Events(ing.Namespace).Search(ing)
  1330. if events != nil {
  1331. DescribeEvents(events, out)
  1332. }
  1333. }
  1334. return nil
  1335. })
  1336. }
  1337. func describeIngressTLS(out io.Writer, ingTLS []extensions.IngressTLS) {
  1338. fmt.Fprintf(out, "TLS:\n")
  1339. for _, t := range ingTLS {
  1340. if t.SecretName == "" {
  1341. fmt.Fprintf(out, " SNI routes %v\n", strings.Join(t.Hosts, ","))
  1342. } else {
  1343. fmt.Fprintf(out, " %v terminates %v\n", t.SecretName, strings.Join(t.Hosts, ","))
  1344. }
  1345. }
  1346. return
  1347. }
  1348. // TODO: Move from annotations into Ingress status.
  1349. func describeIngressAnnotations(out io.Writer, annotations map[string]string) {
  1350. fmt.Fprintf(out, "Annotations:\n")
  1351. for k, v := range annotations {
  1352. if !strings.HasPrefix(k, "ingress") {
  1353. continue
  1354. }
  1355. parts := strings.Split(k, "/")
  1356. name := parts[len(parts)-1]
  1357. fmt.Fprintf(out, " %v:\t%s\n", name, v)
  1358. }
  1359. return
  1360. }
  1361. // ServiceDescriber generates information about a service.
  1362. type ServiceDescriber struct {
  1363. client.Interface
  1364. }
  1365. func (d *ServiceDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
  1366. c := d.Services(namespace)
  1367. service, err := c.Get(name)
  1368. if err != nil {
  1369. return "", err
  1370. }
  1371. endpoints, _ := d.Endpoints(namespace).Get(name)
  1372. var events *api.EventList
  1373. if describerSettings.ShowEvents {
  1374. events, _ = d.Events(namespace).Search(service)
  1375. }
  1376. return describeService(service, endpoints, events)
  1377. }
  1378. func buildIngressString(ingress []api.LoadBalancerIngress) string {
  1379. var buffer bytes.Buffer
  1380. for i := range ingress {
  1381. if i != 0 {
  1382. buffer.WriteString(", ")
  1383. }
  1384. if ingress[i].IP != "" {
  1385. buffer.WriteString(ingress[i].IP)
  1386. } else {
  1387. buffer.WriteString(ingress[i].Hostname)
  1388. }
  1389. }
  1390. return buffer.String()
  1391. }
  1392. func describeService(service *api.Service, endpoints *api.Endpoints, events *api.EventList) (string, error) {
  1393. if endpoints == nil {
  1394. endpoints = &api.Endpoints{}
  1395. }
  1396. return tabbedString(func(out io.Writer) error {
  1397. fmt.Fprintf(out, "Name:\t%s\n", service.Name)
  1398. fmt.Fprintf(out, "Namespace:\t%s\n", service.Namespace)
  1399. printLabelsMultiline(out, "Labels", service.Labels)
  1400. fmt.Fprintf(out, "Selector:\t%s\n", labels.FormatLabels(service.Spec.Selector))
  1401. fmt.Fprintf(out, "Type:\t%s\n", service.Spec.Type)
  1402. fmt.Fprintf(out, "IP:\t%s\n", service.Spec.ClusterIP)
  1403. if len(service.Spec.ExternalIPs) > 0 {
  1404. fmt.Fprintf(out, "External IPs:\t%v\n", strings.Join(service.Spec.ExternalIPs, ","))
  1405. }
  1406. if service.Spec.ExternalName != "" {
  1407. fmt.Fprintf(out, "External Name:\t%s\n", service.Spec.ExternalName)
  1408. }
  1409. if len(service.Status.LoadBalancer.Ingress) > 0 {
  1410. list := buildIngressString(service.Status.LoadBalancer.Ingress)
  1411. fmt.Fprintf(out, "LoadBalancer Ingress:\t%s\n", list)
  1412. }
  1413. for i := range service.Spec.Ports {
  1414. sp := &service.Spec.Ports[i]
  1415. name := sp.Name
  1416. if name == "" {
  1417. name = "<unset>"
  1418. }
  1419. fmt.Fprintf(out, "Port:\t%s\t%d/%s\n", name, sp.Port, sp.Protocol)
  1420. if sp.NodePort != 0 {
  1421. fmt.Fprintf(out, "NodePort:\t%s\t%d/%s\n", name, sp.NodePort, sp.Protocol)
  1422. }
  1423. fmt.Fprintf(out, "Endpoints:\t%s\n", formatEndpoints(endpoints, sets.NewString(sp.Name)))
  1424. }
  1425. fmt.Fprintf(out, "Session Affinity:\t%s\n", service.Spec.SessionAffinity)
  1426. if events != nil {
  1427. DescribeEvents(events, out)
  1428. }
  1429. return nil
  1430. })
  1431. }
  1432. // EndpointsDescriber generates information about an Endpoint.
  1433. type EndpointsDescriber struct {
  1434. client.Interface
  1435. }
  1436. func (d *EndpointsDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
  1437. c := d.Endpoints(namespace)
  1438. ep, err := c.Get(name)
  1439. if err != nil {
  1440. return "", err
  1441. }
  1442. var events *api.EventList
  1443. if describerSettings.ShowEvents {
  1444. events, _ = d.Events(namespace).Search(ep)
  1445. }
  1446. return describeEndpoints(ep, events)
  1447. }
  1448. func describeEndpoints(ep *api.Endpoints, events *api.EventList) (string, error) {
  1449. return tabbedString(func(out io.Writer) error {
  1450. fmt.Fprintf(out, "Name:\t%s\n", ep.Name)
  1451. fmt.Fprintf(out, "Namespace:\t%s\n", ep.Namespace)
  1452. printLabelsMultiline(out, "Labels", ep.Labels)
  1453. fmt.Fprintf(out, "Subsets:\n")
  1454. for i := range ep.Subsets {
  1455. subset := &ep.Subsets[i]
  1456. addresses := make([]string, 0, len(subset.Addresses))
  1457. for _, addr := range subset.Addresses {
  1458. addresses = append(addresses, addr.IP)
  1459. }
  1460. addressesString := strings.Join(addresses, ",")
  1461. if len(addressesString) == 0 {
  1462. addressesString = "<none>"
  1463. }
  1464. fmt.Fprintf(out, " Addresses:\t%s\n", addressesString)
  1465. notReadyAddresses := make([]string, 0, len(subset.NotReadyAddresses))
  1466. for _, addr := range subset.NotReadyAddresses {
  1467. notReadyAddresses = append(notReadyAddresses, addr.IP)
  1468. }
  1469. notReadyAddressesString := strings.Join(notReadyAddresses, ",")
  1470. if len(notReadyAddressesString) == 0 {
  1471. notReadyAddressesString = "<none>"
  1472. }
  1473. fmt.Fprintf(out, " NotReadyAddresses:\t%s\n", notReadyAddressesString)
  1474. if len(subset.Ports) > 0 {
  1475. fmt.Fprintf(out, " Ports:\n")
  1476. fmt.Fprintf(out, " Name\tPort\tProtocol\n")
  1477. fmt.Fprintf(out, " ----\t----\t--------\n")
  1478. for _, port := range subset.Ports {
  1479. name := port.Name
  1480. if len(name) == 0 {
  1481. name = "<unset>"
  1482. }
  1483. fmt.Fprintf(out, " %s\t%d\t%s\n", name, port.Port, port.Protocol)
  1484. }
  1485. }
  1486. fmt.Fprintf(out, "\n")
  1487. }
  1488. if events != nil {
  1489. DescribeEvents(events, out)
  1490. }
  1491. return nil
  1492. })
  1493. }
  1494. // ServiceAccountDescriber generates information about a service.
  1495. type ServiceAccountDescriber struct {
  1496. client.Interface
  1497. }
  1498. func (d *ServiceAccountDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
  1499. c := d.ServiceAccounts(namespace)
  1500. serviceAccount, err := c.Get(name)
  1501. if err != nil {
  1502. return "", err
  1503. }
  1504. tokens := []api.Secret{}
  1505. tokenSelector := fields.SelectorFromSet(map[string]string{api.SecretTypeField: string(api.SecretTypeServiceAccountToken)})
  1506. options := api.ListOptions{FieldSelector: tokenSelector}
  1507. secrets, err := d.Secrets(namespace).List(options)
  1508. if err == nil {
  1509. for _, s := range secrets.Items {
  1510. name, _ := s.Annotations[api.ServiceAccountNameKey]
  1511. uid, _ := s.Annotations[api.ServiceAccountUIDKey]
  1512. if name == serviceAccount.Name && uid == string(serviceAccount.UID) {
  1513. tokens = append(tokens, s)
  1514. }
  1515. }
  1516. }
  1517. return describeServiceAccount(serviceAccount, tokens)
  1518. }
  1519. func describeServiceAccount(serviceAccount *api.ServiceAccount, tokens []api.Secret) (string, error) {
  1520. return tabbedString(func(out io.Writer) error {
  1521. fmt.Fprintf(out, "Name:\t%s\n", serviceAccount.Name)
  1522. fmt.Fprintf(out, "Namespace:\t%s\n", serviceAccount.Namespace)
  1523. printLabelsMultiline(out, "Labels", serviceAccount.Labels)
  1524. fmt.Fprintln(out)
  1525. var (
  1526. emptyHeader = " "
  1527. pullHeader = "Image pull secrets:"
  1528. mountHeader = "Mountable secrets: "
  1529. tokenHeader = "Tokens: "
  1530. pullSecretNames = []string{}
  1531. mountSecretNames = []string{}
  1532. tokenSecretNames = []string{}
  1533. )
  1534. for _, s := range serviceAccount.ImagePullSecrets {
  1535. pullSecretNames = append(pullSecretNames, s.Name)
  1536. }
  1537. for _, s := range serviceAccount.Secrets {
  1538. mountSecretNames = append(mountSecretNames, s.Name)
  1539. }
  1540. for _, s := range tokens {
  1541. tokenSecretNames = append(tokenSecretNames, s.Name)
  1542. }
  1543. types := map[string][]string{
  1544. pullHeader: pullSecretNames,
  1545. mountHeader: mountSecretNames,
  1546. tokenHeader: tokenSecretNames,
  1547. }
  1548. for header, names := range types {
  1549. if len(names) == 0 {
  1550. fmt.Fprintf(out, "%s\t<none>\n", header)
  1551. } else {
  1552. prefix := header
  1553. for _, name := range names {
  1554. fmt.Fprintf(out, "%s\t%s\n", prefix, name)
  1555. prefix = emptyHeader
  1556. }
  1557. }
  1558. fmt.Fprintln(out)
  1559. }
  1560. return nil
  1561. })
  1562. }
  1563. // NodeDescriber generates information about a node.
  1564. type NodeDescriber struct {
  1565. client.Interface
  1566. }
  1567. func (d *NodeDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
  1568. mc := d.Nodes()
  1569. node, err := mc.Get(name)
  1570. if err != nil {
  1571. return "", err
  1572. }
  1573. fieldSelector, err := fields.ParseSelector("spec.nodeName=" + name + ",status.phase!=" + string(api.PodSucceeded) + ",status.phase!=" + string(api.PodFailed))
  1574. if err != nil {
  1575. return "", err
  1576. }
  1577. // in a policy aware setting, users may have access to a node, but not all pods
  1578. // in that case, we note that the user does not have access to the pods
  1579. canViewPods := true
  1580. nodeNonTerminatedPodsList, err := d.Pods(namespace).List(api.ListOptions{FieldSelector: fieldSelector})
  1581. if err != nil {
  1582. if !errors.IsForbidden(err) {
  1583. return "", err
  1584. }
  1585. canViewPods = false
  1586. }
  1587. var events *api.EventList
  1588. if describerSettings.ShowEvents {
  1589. if ref, err := api.GetReference(node); err != nil {
  1590. glog.Errorf("Unable to construct reference to '%#v': %v", node, err)
  1591. } else {
  1592. // TODO: We haven't decided the namespace for Node object yet.
  1593. ref.UID = types.UID(ref.Name)
  1594. events, _ = d.Events("").Search(ref)
  1595. }
  1596. }
  1597. return describeNode(node, nodeNonTerminatedPodsList, events, canViewPods)
  1598. }
  1599. func describeNode(node *api.Node, nodeNonTerminatedPodsList *api.PodList, events *api.EventList, canViewPods bool) (string, error) {
  1600. return tabbedString(func(out io.Writer) error {
  1601. fmt.Fprintf(out, "Name:\t%s\n", node.Name)
  1602. printLabelsMultiline(out, "Labels", node.Labels)
  1603. printTaintsInAnnotationMultiline(out, "Taints", node.Annotations)
  1604. fmt.Fprintf(out, "CreationTimestamp:\t%s\n", node.CreationTimestamp.Time.Format(time.RFC1123Z))
  1605. fmt.Fprintf(out, "Phase:\t%v\n", node.Status.Phase)
  1606. if len(node.Status.Conditions) > 0 {
  1607. fmt.Fprint(out, "Conditions:\n Type\tStatus\tLastHeartbeatTime\tLastTransitionTime\tReason\tMessage\n")
  1608. fmt.Fprint(out, " ----\t------\t-----------------\t------------------\t------\t-------\n")
  1609. for _, c := range node.Status.Conditions {
  1610. fmt.Fprintf(out, " %v \t%v \t%s \t%s \t%v \t%v\n",
  1611. c.Type,
  1612. c.Status,
  1613. c.LastHeartbeatTime.Time.Format(time.RFC1123Z),
  1614. c.LastTransitionTime.Time.Format(time.RFC1123Z),
  1615. c.Reason,
  1616. c.Message)
  1617. }
  1618. }
  1619. addresses := make([]string, 0, len(node.Status.Addresses))
  1620. for _, address := range node.Status.Addresses {
  1621. addresses = append(addresses, address.Address)
  1622. }
  1623. printResourceList := func(resourceList api.ResourceList) {
  1624. resources := make([]api.ResourceName, 0, len(resourceList))
  1625. for resource := range resourceList {
  1626. resources = append(resources, resource)
  1627. }
  1628. sort.Sort(SortableResourceNames(resources))
  1629. for _, resource := range resources {
  1630. value := resourceList[resource]
  1631. fmt.Fprintf(out, " %s:\t%s\n", resource, value.String())
  1632. }
  1633. }
  1634. fmt.Fprintf(out, "Addresses:\t%s\n", strings.Join(addresses, ","))
  1635. if len(node.Status.Capacity) > 0 {
  1636. fmt.Fprintf(out, "Capacity:\n")
  1637. printResourceList(node.Status.Capacity)
  1638. }
  1639. if len(node.Status.Allocatable) > 0 {
  1640. fmt.Fprintf(out, "Allocatable:\n")
  1641. printResourceList(node.Status.Allocatable)
  1642. }
  1643. fmt.Fprintf(out, "System Info:\n")
  1644. fmt.Fprintf(out, " Machine ID:\t%s\n", node.Status.NodeInfo.MachineID)
  1645. fmt.Fprintf(out, " System UUID:\t%s\n", node.Status.NodeInfo.SystemUUID)
  1646. fmt.Fprintf(out, " Boot ID:\t%s\n", node.Status.NodeInfo.BootID)
  1647. fmt.Fprintf(out, " Kernel Version:\t%s\n", node.Status.NodeInfo.KernelVersion)
  1648. fmt.Fprintf(out, " OS Image:\t%s\n", node.Status.NodeInfo.OSImage)
  1649. fmt.Fprintf(out, " Operating System:\t%s\n", node.Status.NodeInfo.OperatingSystem)
  1650. fmt.Fprintf(out, " Architecture:\t%s\n", node.Status.NodeInfo.Architecture)
  1651. fmt.Fprintf(out, " Container Runtime Version:\t%s\n", node.Status.NodeInfo.ContainerRuntimeVersion)
  1652. fmt.Fprintf(out, " Kubelet Version:\t%s\n", node.Status.NodeInfo.KubeletVersion)
  1653. fmt.Fprintf(out, " Kube-Proxy Version:\t%s\n", node.Status.NodeInfo.KubeProxyVersion)
  1654. if len(node.Spec.PodCIDR) > 0 {
  1655. fmt.Fprintf(out, "PodCIDR:\t%s\n", node.Spec.PodCIDR)
  1656. }
  1657. if len(node.Spec.ExternalID) > 0 {
  1658. fmt.Fprintf(out, "ExternalID:\t%s\n", node.Spec.ExternalID)
  1659. }
  1660. if canViewPods && nodeNonTerminatedPodsList != nil {
  1661. if err := describeNodeResource(nodeNonTerminatedPodsList, node, out); err != nil {
  1662. return err
  1663. }
  1664. } else {
  1665. fmt.Fprintf(out, "Pods:\tnot authorized\n")
  1666. }
  1667. if events != nil {
  1668. DescribeEvents(events, out)
  1669. }
  1670. return nil
  1671. })
  1672. }
  1673. type PetSetDescriber struct {
  1674. client *client.Client
  1675. }
  1676. func (p *PetSetDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
  1677. ps, err := p.client.Apps().PetSets(namespace).Get(name)
  1678. if err != nil {
  1679. return "", err
  1680. }
  1681. pc := p.client.Pods(namespace)
  1682. selector, err := unversioned.LabelSelectorAsSelector(ps.Spec.Selector)
  1683. if err != nil {
  1684. return "", err
  1685. }
  1686. running, waiting, succeeded, failed, err := getPodStatusForController(pc, selector)
  1687. if err != nil {
  1688. return "", err
  1689. }
  1690. return tabbedString(func(out io.Writer) error {
  1691. fmt.Fprintf(out, "Name:\t%s\n", ps.Name)
  1692. fmt.Fprintf(out, "Namespace:\t%s\n", ps.Namespace)
  1693. fmt.Fprintf(out, "Image(s):\t%s\n", makeImageList(&ps.Spec.Template.Spec))
  1694. fmt.Fprintf(out, "Selector:\t%s\n", unversioned.FormatLabelSelector(ps.Spec.Selector))
  1695. fmt.Fprintf(out, "Labels:\t%s\n", labels.FormatLabels(ps.Labels))
  1696. fmt.Fprintf(out, "Replicas:\t%d current / %d desired\n", ps.Status.Replicas, ps.Spec.Replicas)
  1697. fmt.Fprintf(out, "Annotations:\t%s\n", labels.FormatLabels(ps.Annotations))
  1698. fmt.Fprintf(out, "CreationTimestamp:\t%s\n", ps.CreationTimestamp.Time.Format(time.RFC1123Z))
  1699. fmt.Fprintf(out, "Pods Status:\t%d Running / %d Waiting / %d Succeeded / %d Failed\n", running, waiting, succeeded, failed)
  1700. describeVolumes(ps.Spec.Template.Spec.Volumes, out, "")
  1701. if describerSettings.ShowEvents {
  1702. events, _ := p.client.Events(namespace).Search(ps)
  1703. if events != nil {
  1704. DescribeEvents(events, out)
  1705. }
  1706. }
  1707. return nil
  1708. })
  1709. }
  1710. type CertificateSigningRequestDescriber struct {
  1711. client *client.Client
  1712. }
  1713. func (p *CertificateSigningRequestDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
  1714. csr, err := p.client.Certificates().CertificateSigningRequests().Get(name)
  1715. if err != nil {
  1716. return "", err
  1717. }
  1718. cr, err := utilcertificates.ParseCertificateRequestObject(csr)
  1719. if err != nil {
  1720. return "", fmt.Errorf("Error parsing CSR: %v", err)
  1721. }
  1722. status, err := extractCSRStatus(csr)
  1723. if err != nil {
  1724. return "", err
  1725. }
  1726. printListHelper := func(out io.Writer, prefix, name string, values []string) {
  1727. if len(values) == 0 {
  1728. return
  1729. }
  1730. fmt.Fprintf(out, prefix+name+":\t")
  1731. fmt.Fprintf(out, strings.Join(values, "\n"+prefix+"\t"))
  1732. fmt.Fprintf(out, "\n")
  1733. }
  1734. return tabbedString(func(out io.Writer) error {
  1735. fmt.Fprintf(out, "Name:\t%s\n", csr.Name)
  1736. fmt.Fprintf(out, "Labels:\t%s\n", labels.FormatLabels(csr.Labels))
  1737. fmt.Fprintf(out, "Annotations:\t%s\n", labels.FormatLabels(csr.Annotations))
  1738. fmt.Fprintf(out, "CreationTimestamp:\t%s\n", csr.CreationTimestamp.Time.Format(time.RFC1123Z))
  1739. fmt.Fprintf(out, "Requesting User:\t%s\n", csr.Spec.Username)
  1740. fmt.Fprintf(out, "Status:\t%s\n", status)
  1741. fmt.Fprintf(out, "Subject:\n")
  1742. fmt.Fprintf(out, "\tCommon Name:\t%s\n", cr.Subject.CommonName)
  1743. fmt.Fprintf(out, "\tSerial Number:\t%s\n", cr.Subject.SerialNumber)
  1744. printListHelper(out, "\t", "Organization", cr.Subject.Organization)
  1745. printListHelper(out, "\t", "Organizational Unit", cr.Subject.OrganizationalUnit)
  1746. printListHelper(out, "\t", "Country", cr.Subject.Country)
  1747. printListHelper(out, "\t", "Locality", cr.Subject.Locality)
  1748. printListHelper(out, "\t", "Province", cr.Subject.Province)
  1749. printListHelper(out, "\t", "StreetAddress", cr.Subject.StreetAddress)
  1750. printListHelper(out, "\t", "PostalCode", cr.Subject.PostalCode)
  1751. if len(cr.DNSNames)+len(cr.EmailAddresses)+len(cr.IPAddresses) > 0 {
  1752. fmt.Fprintf(out, "Subject Alternative Names:\n")
  1753. printListHelper(out, "\t", "DNS Names", cr.DNSNames)
  1754. printListHelper(out, "\t", "Email Addresses", cr.EmailAddresses)
  1755. var ipaddrs []string
  1756. for _, ipaddr := range cr.IPAddresses {
  1757. ipaddrs = append(ipaddrs, ipaddr.String())
  1758. }
  1759. printListHelper(out, "\t", "IP Addresses", ipaddrs)
  1760. }
  1761. if describerSettings.ShowEvents {
  1762. events, _ := p.client.Events(namespace).Search(csr)
  1763. if events != nil {
  1764. DescribeEvents(events, out)
  1765. }
  1766. }
  1767. return nil
  1768. })
  1769. }
  1770. // HorizontalPodAutoscalerDescriber generates information about a horizontal pod autoscaler.
  1771. type HorizontalPodAutoscalerDescriber struct {
  1772. client *client.Client
  1773. }
  1774. func (d *HorizontalPodAutoscalerDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
  1775. hpa, err := d.client.Autoscaling().HorizontalPodAutoscalers(namespace).Get(name)
  1776. if err != nil {
  1777. return "", err
  1778. }
  1779. return tabbedString(func(out io.Writer) error {
  1780. fmt.Fprintf(out, "Name:\t%s\n", hpa.Name)
  1781. fmt.Fprintf(out, "Namespace:\t%s\n", hpa.Namespace)
  1782. printLabelsMultiline(out, "Labels", hpa.Labels)
  1783. printLabelsMultiline(out, "Annotations", hpa.Annotations)
  1784. fmt.Fprintf(out, "CreationTimestamp:\t%s\n", hpa.CreationTimestamp.Time.Format(time.RFC1123Z))
  1785. fmt.Fprintf(out, "Reference:\t%s/%s\n",
  1786. hpa.Spec.ScaleTargetRef.Kind,
  1787. hpa.Spec.ScaleTargetRef.Name)
  1788. if hpa.Spec.TargetCPUUtilizationPercentage != nil {
  1789. fmt.Fprintf(out, "Target CPU utilization:\t%d%%\n", *hpa.Spec.TargetCPUUtilizationPercentage)
  1790. fmt.Fprintf(out, "Current CPU utilization:\t")
  1791. if hpa.Status.CurrentCPUUtilizationPercentage != nil {
  1792. fmt.Fprintf(out, "%d%%\n", *hpa.Status.CurrentCPUUtilizationPercentage)
  1793. } else {
  1794. fmt.Fprintf(out, "<unset>\n")
  1795. }
  1796. }
  1797. minReplicas := "<unset>"
  1798. if hpa.Spec.MinReplicas != nil {
  1799. minReplicas = fmt.Sprintf("%d", *hpa.Spec.MinReplicas)
  1800. }
  1801. fmt.Fprintf(out, "Min replicas:\t%s\n", minReplicas)
  1802. fmt.Fprintf(out, "Max replicas:\t%d\n", hpa.Spec.MaxReplicas)
  1803. // TODO: switch to scale subresource once the required code is submitted.
  1804. if strings.ToLower(hpa.Spec.ScaleTargetRef.Kind) == "replicationcontroller" {
  1805. fmt.Fprintf(out, "ReplicationController pods:\t")
  1806. rc, err := d.client.ReplicationControllers(hpa.Namespace).Get(hpa.Spec.ScaleTargetRef.Name)
  1807. if err == nil {
  1808. fmt.Fprintf(out, "%d current / %d desired\n", rc.Status.Replicas, rc.Spec.Replicas)
  1809. } else {
  1810. fmt.Fprintf(out, "failed to check Replication Controller\n")
  1811. }
  1812. }
  1813. if describerSettings.ShowEvents {
  1814. events, _ := d.client.Events(namespace).Search(hpa)
  1815. if events != nil {
  1816. DescribeEvents(events, out)
  1817. }
  1818. }
  1819. return nil
  1820. })
  1821. }
  1822. func describeNodeResource(nodeNonTerminatedPodsList *api.PodList, node *api.Node, out io.Writer) error {
  1823. fmt.Fprintf(out, "Non-terminated Pods:\t(%d in total)\n", len(nodeNonTerminatedPodsList.Items))
  1824. fmt.Fprint(out, " Namespace\tName\t\tCPU Requests\tCPU Limits\tMemory Requests\tMemory Limits\n")
  1825. fmt.Fprint(out, " ---------\t----\t\t------------\t----------\t---------------\t-------------\n")
  1826. allocatable := node.Status.Capacity
  1827. if len(node.Status.Allocatable) > 0 {
  1828. allocatable = node.Status.Allocatable
  1829. }
  1830. for _, pod := range nodeNonTerminatedPodsList.Items {
  1831. req, limit, err := api.PodRequestsAndLimits(&pod)
  1832. if err != nil {
  1833. return err
  1834. }
  1835. cpuReq, cpuLimit, memoryReq, memoryLimit := req[api.ResourceCPU], limit[api.ResourceCPU], req[api.ResourceMemory], limit[api.ResourceMemory]
  1836. fractionCpuReq := float64(cpuReq.MilliValue()) / float64(allocatable.Cpu().MilliValue()) * 100
  1837. fractionCpuLimit := float64(cpuLimit.MilliValue()) / float64(allocatable.Cpu().MilliValue()) * 100
  1838. fractionMemoryReq := float64(memoryReq.Value()) / float64(allocatable.Memory().Value()) * 100
  1839. fractionMemoryLimit := float64(memoryLimit.Value()) / float64(allocatable.Memory().Value()) * 100
  1840. fmt.Fprintf(out, " %s\t%s\t\t%s (%d%%)\t%s (%d%%)\t%s (%d%%)\t%s (%d%%)\n", pod.Namespace, pod.Name,
  1841. cpuReq.String(), int64(fractionCpuReq), cpuLimit.String(), int64(fractionCpuLimit),
  1842. memoryReq.String(), int64(fractionMemoryReq), memoryLimit.String(), int64(fractionMemoryLimit))
  1843. }
  1844. fmt.Fprint(out, "Allocated resources:\n (Total limits may be over 100 percent, i.e., overcommitted.\n CPU Requests\tCPU Limits\tMemory Requests\tMemory Limits\n")
  1845. fmt.Fprint(out, " ------------\t----------\t---------------\t-------------\n")
  1846. reqs, limits, err := getPodsTotalRequestsAndLimits(nodeNonTerminatedPodsList)
  1847. if err != nil {
  1848. return err
  1849. }
  1850. cpuReqs, cpuLimits, memoryReqs, memoryLimits := reqs[api.ResourceCPU], limits[api.ResourceCPU], reqs[api.ResourceMemory], limits[api.ResourceMemory]
  1851. fractionCpuReqs := float64(cpuReqs.MilliValue()) / float64(allocatable.Cpu().MilliValue()) * 100
  1852. fractionCpuLimits := float64(cpuLimits.MilliValue()) / float64(allocatable.Cpu().MilliValue()) * 100
  1853. fractionMemoryReqs := float64(memoryReqs.Value()) / float64(allocatable.Memory().Value()) * 100
  1854. fractionMemoryLimits := float64(memoryLimits.Value()) / float64(allocatable.Memory().Value()) * 100
  1855. fmt.Fprintf(out, " %s (%d%%)\t%s (%d%%)\t%s (%d%%)\t%s (%d%%)\n",
  1856. cpuReqs.String(), int64(fractionCpuReqs), cpuLimits.String(), int64(fractionCpuLimits),
  1857. memoryReqs.String(), int64(fractionMemoryReqs), memoryLimits.String(), int64(fractionMemoryLimits))
  1858. return nil
  1859. }
  1860. func filterTerminatedPods(pods []*api.Pod) []*api.Pod {
  1861. if len(pods) == 0 {
  1862. return pods
  1863. }
  1864. result := []*api.Pod{}
  1865. for _, pod := range pods {
  1866. if pod.Status.Phase == api.PodSucceeded || pod.Status.Phase == api.PodFailed {
  1867. continue
  1868. }
  1869. result = append(result, pod)
  1870. }
  1871. return result
  1872. }
  1873. func getPodsTotalRequestsAndLimits(podList *api.PodList) (reqs map[api.ResourceName]resource.Quantity, limits map[api.ResourceName]resource.Quantity, err error) {
  1874. reqs, limits = map[api.ResourceName]resource.Quantity{}, map[api.ResourceName]resource.Quantity{}
  1875. for _, pod := range podList.Items {
  1876. podReqs, podLimits, err := api.PodRequestsAndLimits(&pod)
  1877. if err != nil {
  1878. return nil, nil, err
  1879. }
  1880. for podReqName, podReqValue := range podReqs {
  1881. if value, ok := reqs[podReqName]; !ok {
  1882. reqs[podReqName] = *podReqValue.Copy()
  1883. } else {
  1884. value.Add(podReqValue)
  1885. reqs[podReqName] = value
  1886. }
  1887. }
  1888. for podLimitName, podLimitValue := range podLimits {
  1889. if value, ok := limits[podLimitName]; !ok {
  1890. limits[podLimitName] = *podLimitValue.Copy()
  1891. } else {
  1892. value.Add(podLimitValue)
  1893. limits[podLimitName] = value
  1894. }
  1895. }
  1896. }
  1897. return
  1898. }
  1899. func DescribeEvents(el *api.EventList, w io.Writer) {
  1900. if len(el.Items) == 0 {
  1901. fmt.Fprint(w, "No events.")
  1902. return
  1903. }
  1904. sort.Sort(SortableEvents(el.Items))
  1905. fmt.Fprint(w, "Events:\n FirstSeen\tLastSeen\tCount\tFrom\tSubobjectPath\tType\tReason\tMessage\n")
  1906. fmt.Fprint(w, " ---------\t--------\t-----\t----\t-------------\t--------\t------\t-------\n")
  1907. for _, e := range el.Items {
  1908. fmt.Fprintf(w, " %s\t%s\t%d\t%v\t%v\t%v\t%v\t%v\n",
  1909. translateTimestamp(e.FirstTimestamp),
  1910. translateTimestamp(e.LastTimestamp),
  1911. e.Count,
  1912. e.Source,
  1913. e.InvolvedObject.FieldPath,
  1914. e.Type,
  1915. e.Reason,
  1916. e.Message)
  1917. }
  1918. }
  1919. // DeploymentDescriber generates information about a deployment.
  1920. type DeploymentDescriber struct {
  1921. clientset.Interface
  1922. }
  1923. func (dd *DeploymentDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
  1924. d, err := dd.Extensions().Deployments(namespace).Get(name)
  1925. if err != nil {
  1926. return "", err
  1927. }
  1928. selector, err := unversioned.LabelSelectorAsSelector(d.Spec.Selector)
  1929. if err != nil {
  1930. return "", err
  1931. }
  1932. return tabbedString(func(out io.Writer) error {
  1933. fmt.Fprintf(out, "Name:\t%s\n", d.ObjectMeta.Name)
  1934. fmt.Fprintf(out, "Namespace:\t%s\n", d.ObjectMeta.Namespace)
  1935. fmt.Fprintf(out, "CreationTimestamp:\t%s\n", d.CreationTimestamp.Time.Format(time.RFC1123Z))
  1936. printLabelsMultiline(out, "Labels", d.Labels)
  1937. fmt.Fprintf(out, "Selector:\t%s\n", selector)
  1938. fmt.Fprintf(out, "Replicas:\t%d updated | %d total | %d available | %d unavailable\n", d.Status.UpdatedReplicas, d.Spec.Replicas, d.Status.AvailableReplicas, d.Status.UnavailableReplicas)
  1939. fmt.Fprintf(out, "StrategyType:\t%s\n", d.Spec.Strategy.Type)
  1940. fmt.Fprintf(out, "MinReadySeconds:\t%d\n", d.Spec.MinReadySeconds)
  1941. if d.Spec.Strategy.RollingUpdate != nil {
  1942. ru := d.Spec.Strategy.RollingUpdate
  1943. fmt.Fprintf(out, "RollingUpdateStrategy:\t%s max unavailable, %s max surge\n", ru.MaxUnavailable.String(), ru.MaxSurge.String())
  1944. }
  1945. oldRSs, _, newRS, err := deploymentutil.GetAllReplicaSets(d, dd)
  1946. if err == nil {
  1947. fmt.Fprintf(out, "OldReplicaSets:\t%s\n", printReplicaSetsByLabels(oldRSs))
  1948. var newRSs []*extensions.ReplicaSet
  1949. if newRS != nil {
  1950. newRSs = append(newRSs, newRS)
  1951. }
  1952. fmt.Fprintf(out, "NewReplicaSet:\t%s\n", printReplicaSetsByLabels(newRSs))
  1953. }
  1954. overlapWith := d.Annotations[deploymentutil.OverlapAnnotation]
  1955. if len(overlapWith) > 0 {
  1956. fmt.Fprintf(out, "!!!WARNING!!! This deployment has overlapping label selector with deployment %q and won't behave as expected. Please fix it before continue.\n", overlapWith)
  1957. }
  1958. if describerSettings.ShowEvents {
  1959. events, err := dd.Core().Events(namespace).Search(d)
  1960. if err == nil && events != nil {
  1961. DescribeEvents(events, out)
  1962. }
  1963. }
  1964. return nil
  1965. })
  1966. }
  1967. // Get all daemon set whose selectors would match a given set of labels.
  1968. // TODO: Move this to pkg/client and ideally implement it server-side (instead
  1969. // of getting all DS's and searching through them manually).
  1970. // TODO: write an interface for controllers and fuse getReplicationControllersForLabels
  1971. // and getDaemonSetsForLabels.
  1972. func getDaemonSetsForLabels(c client.DaemonSetInterface, labelsToMatch labels.Labels) ([]extensions.DaemonSet, error) {
  1973. // Get all daemon sets
  1974. // TODO: this needs a namespace scope as argument
  1975. dss, err := c.List(api.ListOptions{})
  1976. if err != nil {
  1977. return nil, fmt.Errorf("error getting daemon set: %v", err)
  1978. }
  1979. // Find the ones that match labelsToMatch.
  1980. var matchingDaemonSets []extensions.DaemonSet
  1981. for _, ds := range dss.Items {
  1982. selector, err := unversioned.LabelSelectorAsSelector(ds.Spec.Selector)
  1983. if err != nil {
  1984. // this should never happen if the DaemonSet passed validation
  1985. return nil, err
  1986. }
  1987. if selector.Matches(labelsToMatch) {
  1988. matchingDaemonSets = append(matchingDaemonSets, ds)
  1989. }
  1990. }
  1991. return matchingDaemonSets, nil
  1992. }
  1993. func printReplicationControllersByLabels(matchingRCs []*api.ReplicationController) string {
  1994. // Format the matching RC's into strings.
  1995. rcStrings := make([]string, 0, len(matchingRCs))
  1996. for _, controller := range matchingRCs {
  1997. rcStrings = append(rcStrings, fmt.Sprintf("%s (%d/%d replicas created)", controller.Name, controller.Status.Replicas, controller.Spec.Replicas))
  1998. }
  1999. list := strings.Join(rcStrings, ", ")
  2000. if list == "" {
  2001. return "<none>"
  2002. }
  2003. return list
  2004. }
  2005. func printReplicaSetsByLabels(matchingRSs []*extensions.ReplicaSet) string {
  2006. // Format the matching ReplicaSets into strings.
  2007. rsStrings := make([]string, 0, len(matchingRSs))
  2008. for _, rs := range matchingRSs {
  2009. rsStrings = append(rsStrings, fmt.Sprintf("%s (%d/%d replicas created)", rs.Name, rs.Status.Replicas, rs.Spec.Replicas))
  2010. }
  2011. list := strings.Join(rsStrings, ", ")
  2012. if list == "" {
  2013. return "<none>"
  2014. }
  2015. return list
  2016. }
  2017. func getPodStatusForController(c client.PodInterface, selector labels.Selector) (running, waiting, succeeded, failed int, err error) {
  2018. options := api.ListOptions{LabelSelector: selector}
  2019. rcPods, err := c.List(options)
  2020. if err != nil {
  2021. return
  2022. }
  2023. for _, pod := range rcPods.Items {
  2024. switch pod.Status.Phase {
  2025. case api.PodRunning:
  2026. running++
  2027. case api.PodPending:
  2028. waiting++
  2029. case api.PodSucceeded:
  2030. succeeded++
  2031. case api.PodFailed:
  2032. failed++
  2033. }
  2034. }
  2035. return
  2036. }
  2037. // ConfigMapDescriber generates information about a ConfigMap
  2038. type ConfigMapDescriber struct {
  2039. client.Interface
  2040. }
  2041. func (d *ConfigMapDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
  2042. c := d.ConfigMaps(namespace)
  2043. configMap, err := c.Get(name)
  2044. if err != nil {
  2045. return "", err
  2046. }
  2047. return describeConfigMap(configMap)
  2048. }
  2049. func describeConfigMap(configMap *api.ConfigMap) (string, error) {
  2050. return tabbedString(func(out io.Writer) error {
  2051. fmt.Fprintf(out, "Name:\t%s\n", configMap.Name)
  2052. fmt.Fprintf(out, "Namespace:\t%s\n", configMap.Namespace)
  2053. printLabelsMultiline(out, "Labels", configMap.Labels)
  2054. printLabelsMultiline(out, "Annotations", configMap.Annotations)
  2055. fmt.Fprintf(out, "\nData\n====\n")
  2056. for k, v := range configMap.Data {
  2057. fmt.Fprintf(out, "%s:\t%d bytes\n", k, len(v))
  2058. }
  2059. return nil
  2060. })
  2061. }
  2062. type ClusterDescriber struct {
  2063. fed_clientset.Interface
  2064. }
  2065. func (d *ClusterDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
  2066. cluster, err := d.Federation().Clusters().Get(name)
  2067. if err != nil {
  2068. return "", err
  2069. }
  2070. return describeCluster(cluster)
  2071. }
  2072. func describeCluster(cluster *federation.Cluster) (string, error) {
  2073. return tabbedString(func(out io.Writer) error {
  2074. fmt.Fprintf(out, "Name:\t%s\n", cluster.Name)
  2075. fmt.Fprintf(out, "Labels:\t%s\n", labels.FormatLabels(cluster.Labels))
  2076. fmt.Fprintf(out, "ServerAddressByClientCIDRs:\n ClientCIDR\tServerAddress\n")
  2077. fmt.Fprintf(out, " ----\t----\n")
  2078. for _, cidrAddr := range cluster.Spec.ServerAddressByClientCIDRs {
  2079. fmt.Fprintf(out, " %v \t%v\n\n", cidrAddr.ClientCIDR, cidrAddr.ServerAddress)
  2080. }
  2081. if len(cluster.Status.Conditions) > 0 {
  2082. fmt.Fprint(out, "Conditions:\n Type\tStatus\tLastUpdateTime\tLastTransitionTime\tReason\tMessage\n")
  2083. fmt.Fprint(out, " ----\t------\t-----------------\t------------------\t------\t-------\n")
  2084. for _, c := range cluster.Status.Conditions {
  2085. fmt.Fprintf(out, " %v \t%v \t%s \t%s \t%v \t%v\n",
  2086. c.Type,
  2087. c.Status,
  2088. c.LastProbeTime.Time.Format(time.RFC1123Z),
  2089. c.LastTransitionTime.Time.Format(time.RFC1123Z),
  2090. c.Reason,
  2091. c.Message)
  2092. }
  2093. }
  2094. return nil
  2095. })
  2096. }
  2097. // NetworkPolicyDescriber generates information about a NetworkPolicy
  2098. type NetworkPolicyDescriber struct {
  2099. client.Interface
  2100. }
  2101. func (d *NetworkPolicyDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
  2102. c := d.Extensions().NetworkPolicies(namespace)
  2103. networkPolicy, err := c.Get(name)
  2104. if err != nil {
  2105. return "", err
  2106. }
  2107. return describeNetworkPolicy(networkPolicy)
  2108. }
  2109. func describeNetworkPolicy(networkPolicy *extensions.NetworkPolicy) (string, error) {
  2110. return tabbedString(func(out io.Writer) error {
  2111. fmt.Fprintf(out, "Name:\t%s\n", networkPolicy.Name)
  2112. fmt.Fprintf(out, "Namespace:\t%s\n", networkPolicy.Namespace)
  2113. printLabelsMultiline(out, "Labels", networkPolicy.Labels)
  2114. printLabelsMultiline(out, "Annotations", networkPolicy.Annotations)
  2115. return nil
  2116. })
  2117. }
  2118. // newErrNoDescriber creates a new ErrNoDescriber with the names of the provided types.
  2119. func newErrNoDescriber(types ...reflect.Type) error {
  2120. names := make([]string, 0, len(types))
  2121. for _, t := range types {
  2122. names = append(names, t.String())
  2123. }
  2124. return ErrNoDescriber{Types: names}
  2125. }
  2126. // Describers implements ObjectDescriber against functions registered via Add. Those functions can
  2127. // be strongly typed. Types are exactly matched (no conversion or assignable checks).
  2128. type Describers struct {
  2129. searchFns map[reflect.Type][]typeFunc
  2130. }
  2131. // DescribeObject implements ObjectDescriber and will attempt to print the provided object to a string,
  2132. // if at least one describer function has been registered with the exact types passed, or if any
  2133. // describer can print the exact object in its first argument (the remainder will be provided empty
  2134. // values). If no function registered with Add can satisfy the passed objects, an ErrNoDescriber will
  2135. // be returned
  2136. // TODO: reorder and partial match extra.
  2137. func (d *Describers) DescribeObject(exact interface{}, extra ...interface{}) (string, error) {
  2138. exactType := reflect.TypeOf(exact)
  2139. fns, ok := d.searchFns[exactType]
  2140. if !ok {
  2141. return "", newErrNoDescriber(exactType)
  2142. }
  2143. if len(extra) == 0 {
  2144. for _, typeFn := range fns {
  2145. if len(typeFn.Extra) == 0 {
  2146. return typeFn.Describe(exact, extra...)
  2147. }
  2148. }
  2149. typeFn := fns[0]
  2150. for _, t := range typeFn.Extra {
  2151. v := reflect.New(t).Elem()
  2152. extra = append(extra, v.Interface())
  2153. }
  2154. return fns[0].Describe(exact, extra...)
  2155. }
  2156. types := make([]reflect.Type, 0, len(extra))
  2157. for _, obj := range extra {
  2158. types = append(types, reflect.TypeOf(obj))
  2159. }
  2160. for _, typeFn := range fns {
  2161. if typeFn.Matches(types) {
  2162. return typeFn.Describe(exact, extra...)
  2163. }
  2164. }
  2165. return "", newErrNoDescriber(append([]reflect.Type{exactType}, types...)...)
  2166. }
  2167. // Add adds one or more describer functions to the Describer. The passed function must
  2168. // match the signature:
  2169. //
  2170. // func(...) (string, error)
  2171. //
  2172. // Any number of arguments may be provided.
  2173. func (d *Describers) Add(fns ...interface{}) error {
  2174. for _, fn := range fns {
  2175. fv := reflect.ValueOf(fn)
  2176. ft := fv.Type()
  2177. if ft.Kind() != reflect.Func {
  2178. return fmt.Errorf("expected func, got: %v", ft)
  2179. }
  2180. numIn := ft.NumIn()
  2181. if numIn == 0 {
  2182. return fmt.Errorf("expected at least one 'in' params, got: %v", ft)
  2183. }
  2184. if ft.NumOut() != 2 {
  2185. return fmt.Errorf("expected two 'out' params - (string, error), got: %v", ft)
  2186. }
  2187. types := make([]reflect.Type, 0, numIn)
  2188. for i := 0; i < numIn; i++ {
  2189. types = append(types, ft.In(i))
  2190. }
  2191. if ft.Out(0) != reflect.TypeOf(string("")) {
  2192. return fmt.Errorf("expected string return, got: %v", ft)
  2193. }
  2194. var forErrorType error
  2195. // This convolution is necessary, otherwise TypeOf picks up on the fact
  2196. // that forErrorType is nil.
  2197. errorType := reflect.TypeOf(&forErrorType).Elem()
  2198. if ft.Out(1) != errorType {
  2199. return fmt.Errorf("expected error return, got: %v", ft)
  2200. }
  2201. exact := types[0]
  2202. extra := types[1:]
  2203. if d.searchFns == nil {
  2204. d.searchFns = make(map[reflect.Type][]typeFunc)
  2205. }
  2206. fns := d.searchFns[exact]
  2207. fn := typeFunc{Extra: extra, Fn: fv}
  2208. fns = append(fns, fn)
  2209. d.searchFns[exact] = fns
  2210. }
  2211. return nil
  2212. }
  2213. // typeFunc holds information about a describer function and the types it accepts
  2214. type typeFunc struct {
  2215. Extra []reflect.Type
  2216. Fn reflect.Value
  2217. }
  2218. // Matches returns true when the passed types exactly match the Extra list.
  2219. func (fn typeFunc) Matches(types []reflect.Type) bool {
  2220. if len(fn.Extra) != len(types) {
  2221. return false
  2222. }
  2223. // reorder the items in array types and fn.Extra
  2224. // convert the type into string and sort them, check if they are matched
  2225. varMap := make(map[reflect.Type]bool)
  2226. for i := range fn.Extra {
  2227. varMap[fn.Extra[i]] = true
  2228. }
  2229. for i := range types {
  2230. if _, found := varMap[types[i]]; !found {
  2231. return false
  2232. }
  2233. }
  2234. return true
  2235. }
  2236. // Describe invokes the nested function with the exact number of arguments.
  2237. func (fn typeFunc) Describe(exact interface{}, extra ...interface{}) (string, error) {
  2238. values := []reflect.Value{reflect.ValueOf(exact)}
  2239. for _, obj := range extra {
  2240. values = append(values, reflect.ValueOf(obj))
  2241. }
  2242. out := fn.Fn.Call(values)
  2243. s := out[0].Interface().(string)
  2244. var err error
  2245. if !out[1].IsNil() {
  2246. err = out[1].Interface().(error)
  2247. }
  2248. return s, err
  2249. }
  2250. // printLabelsMultiline prints multiple labels with a proper alignment.
  2251. func printLabelsMultiline(out io.Writer, title string, labels map[string]string) {
  2252. printLabelsMultilineWithIndent(out, "", title, "\t", labels)
  2253. }
  2254. // printLabelsMultiline prints multiple labels with a user-defined alignment.
  2255. func printLabelsMultilineWithIndent(out io.Writer, initialIndent, title, innerIndent string, labels map[string]string) {
  2256. fmt.Fprintf(out, "%s%s:%s", initialIndent, title, innerIndent)
  2257. if labels == nil || len(labels) == 0 {
  2258. fmt.Fprintln(out, "<none>")
  2259. return
  2260. }
  2261. // to print labels in the sorted order
  2262. keys := make([]string, 0, len(labels))
  2263. for key := range labels {
  2264. keys = append(keys, key)
  2265. }
  2266. sort.Strings(keys)
  2267. for i, key := range keys {
  2268. if i != 0 {
  2269. fmt.Fprint(out, initialIndent)
  2270. fmt.Fprint(out, innerIndent)
  2271. }
  2272. fmt.Fprintf(out, "%s=%s\n", key, labels[key])
  2273. i++
  2274. }
  2275. }
  2276. // printTaintsMultiline prints multiple taints with a proper alignment.
  2277. func printTaintsInAnnotationMultiline(out io.Writer, title string, annotations map[string]string) {
  2278. taints, err := api.GetTaintsFromNodeAnnotations(annotations)
  2279. if err != nil {
  2280. taints = []api.Taint{}
  2281. }
  2282. printTaintsMultilineWithIndent(out, "", title, "\t", taints)
  2283. }
  2284. // printTaintsMultilineWithIndent prints multiple taints with a user-defined alignment.
  2285. func printTaintsMultilineWithIndent(out io.Writer, initialIndent, title, innerIndent string, taints []api.Taint) {
  2286. fmt.Fprintf(out, "%s%s:%s", initialIndent, title, innerIndent)
  2287. if taints == nil || len(taints) == 0 {
  2288. fmt.Fprintln(out, "<none>")
  2289. return
  2290. }
  2291. // to print taints in the sorted order
  2292. keys := make([]string, 0, len(taints))
  2293. for _, taint := range taints {
  2294. keys = append(keys, taint.Key)
  2295. }
  2296. sort.Strings(keys)
  2297. effects := []api.TaintEffect{api.TaintEffectNoSchedule, api.TaintEffectPreferNoSchedule}
  2298. for i, key := range keys {
  2299. for _, effect := range effects {
  2300. for _, taint := range taints {
  2301. if taint.Key == key && taint.Effect == effect {
  2302. if i != 0 {
  2303. fmt.Fprint(out, initialIndent)
  2304. fmt.Fprint(out, innerIndent)
  2305. }
  2306. fmt.Fprintf(out, "%s=%s:%s\n", taint.Key, taint.Value, taint.Effect)
  2307. i++
  2308. }
  2309. }
  2310. }
  2311. }
  2312. }
  2313. // printTolerationsMultiline prints multiple tolerations with a proper alignment.
  2314. func printTolerationsInAnnotationMultiline(out io.Writer, title string, annotations map[string]string) {
  2315. tolerations, err := api.GetTolerationsFromPodAnnotations(annotations)
  2316. if err != nil {
  2317. tolerations = []api.Toleration{}
  2318. }
  2319. printTolerationsMultilineWithIndent(out, "", title, "\t", tolerations)
  2320. }
  2321. // printTolerationsMultilineWithIndent prints multiple tolerations with a user-defined alignment.
  2322. func printTolerationsMultilineWithIndent(out io.Writer, initialIndent, title, innerIndent string, tolerations []api.Toleration) {
  2323. fmt.Fprintf(out, "%s%s:%s", initialIndent, title, innerIndent)
  2324. if tolerations == nil || len(tolerations) == 0 {
  2325. fmt.Fprintln(out, "<none>")
  2326. return
  2327. }
  2328. // to print tolerations in the sorted order
  2329. keys := make([]string, 0, len(tolerations))
  2330. for _, toleration := range tolerations {
  2331. keys = append(keys, toleration.Key)
  2332. }
  2333. sort.Strings(keys)
  2334. for i, key := range keys {
  2335. for _, toleration := range tolerations {
  2336. if toleration.Key == key {
  2337. if i != 0 {
  2338. fmt.Fprint(out, initialIndent)
  2339. fmt.Fprint(out, innerIndent)
  2340. }
  2341. fmt.Fprintf(out, "%s=%s", toleration.Key, toleration.Value)
  2342. if len(toleration.Operator) != 0 {
  2343. fmt.Fprintf(out, ":%s", toleration.Operator)
  2344. }
  2345. if len(toleration.Effect) != 0 {
  2346. fmt.Fprintf(out, ":%s", toleration.Effect)
  2347. }
  2348. fmt.Fprintf(out, "\n")
  2349. i++
  2350. }
  2351. }
  2352. }
  2353. }