resource_printer.go 73 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439
  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. "io/ioutil"
  20. "os"
  21. "reflect"
  22. "sort"
  23. "strings"
  24. "text/tabwriter"
  25. "text/template"
  26. "time"
  27. "github.com/ghodss/yaml"
  28. "github.com/golang/glog"
  29. "k8s.io/kubernetes/federation/apis/federation"
  30. "k8s.io/kubernetes/pkg/api"
  31. "k8s.io/kubernetes/pkg/api/meta"
  32. "k8s.io/kubernetes/pkg/api/unversioned"
  33. "k8s.io/kubernetes/pkg/apis/apps"
  34. "k8s.io/kubernetes/pkg/apis/autoscaling"
  35. "k8s.io/kubernetes/pkg/apis/batch"
  36. "k8s.io/kubernetes/pkg/apis/certificates"
  37. "k8s.io/kubernetes/pkg/apis/extensions"
  38. "k8s.io/kubernetes/pkg/apis/rbac"
  39. "k8s.io/kubernetes/pkg/labels"
  40. "k8s.io/kubernetes/pkg/runtime"
  41. utilerrors "k8s.io/kubernetes/pkg/util/errors"
  42. "k8s.io/kubernetes/pkg/util/jsonpath"
  43. "k8s.io/kubernetes/pkg/util/sets"
  44. )
  45. const (
  46. tabwriterMinWidth = 10
  47. tabwriterWidth = 4
  48. tabwriterPadding = 3
  49. tabwriterPadChar = ' '
  50. tabwriterFlags = 0
  51. loadBalancerWidth = 16
  52. )
  53. // GetPrinter takes a format type, an optional format argument. It will return true
  54. // if the format is generic (untyped), otherwise it will return false. The printer
  55. // is agnostic to schema versions, so you must send arguments to PrintObj in the
  56. // version you wish them to be shown using a VersionedPrinter (typically when
  57. // generic is true).
  58. func GetPrinter(format, formatArgument string, noHeaders bool) (ResourcePrinter, bool, error) {
  59. var printer ResourcePrinter
  60. switch format {
  61. case "json":
  62. printer = &JSONPrinter{}
  63. case "yaml":
  64. printer = &YAMLPrinter{}
  65. case "name":
  66. printer = &NamePrinter{
  67. // TODO: this is wrong, these should be provided as an argument to GetPrinter
  68. Typer: api.Scheme,
  69. Decoder: api.Codecs.UniversalDecoder(),
  70. }
  71. case "template", "go-template":
  72. if len(formatArgument) == 0 {
  73. return nil, false, fmt.Errorf("template format specified but no template given")
  74. }
  75. var err error
  76. printer, err = NewTemplatePrinter([]byte(formatArgument))
  77. if err != nil {
  78. return nil, false, fmt.Errorf("error parsing template %s, %v\n", formatArgument, err)
  79. }
  80. case "templatefile", "go-template-file":
  81. if len(formatArgument) == 0 {
  82. return nil, false, fmt.Errorf("templatefile format specified but no template file given")
  83. }
  84. data, err := ioutil.ReadFile(formatArgument)
  85. if err != nil {
  86. return nil, false, fmt.Errorf("error reading template %s, %v\n", formatArgument, err)
  87. }
  88. printer, err = NewTemplatePrinter(data)
  89. if err != nil {
  90. return nil, false, fmt.Errorf("error parsing template %s, %v\n", string(data), err)
  91. }
  92. case "jsonpath":
  93. if len(formatArgument) == 0 {
  94. return nil, false, fmt.Errorf("jsonpath template format specified but no template given")
  95. }
  96. var err error
  97. printer, err = NewJSONPathPrinter(formatArgument)
  98. if err != nil {
  99. return nil, false, fmt.Errorf("error parsing jsonpath %s, %v\n", formatArgument, err)
  100. }
  101. case "jsonpath-file":
  102. if len(formatArgument) == 0 {
  103. return nil, false, fmt.Errorf("jsonpath file format specified but no template file file given")
  104. }
  105. data, err := ioutil.ReadFile(formatArgument)
  106. if err != nil {
  107. return nil, false, fmt.Errorf("error reading template %s, %v\n", formatArgument, err)
  108. }
  109. printer, err = NewJSONPathPrinter(string(data))
  110. if err != nil {
  111. return nil, false, fmt.Errorf("error parsing template %s, %v\n", string(data), err)
  112. }
  113. case "custom-columns":
  114. var err error
  115. if printer, err = NewCustomColumnsPrinterFromSpec(formatArgument, api.Codecs.UniversalDecoder(), noHeaders); err != nil {
  116. return nil, false, err
  117. }
  118. case "custom-columns-file":
  119. file, err := os.Open(formatArgument)
  120. if err != nil {
  121. return nil, false, fmt.Errorf("error reading template %s, %v\n", formatArgument, err)
  122. }
  123. defer file.Close()
  124. if printer, err = NewCustomColumnsPrinterFromTemplate(file, api.Codecs.UniversalDecoder()); err != nil {
  125. return nil, false, err
  126. }
  127. case "wide":
  128. fallthrough
  129. case "":
  130. return nil, false, nil
  131. default:
  132. return nil, false, fmt.Errorf("output format %q not recognized", format)
  133. }
  134. return printer, true, nil
  135. }
  136. // ResourcePrinter is an interface that knows how to print runtime objects.
  137. type ResourcePrinter interface {
  138. // Print receives a runtime object, formats it and prints it to a writer.
  139. PrintObj(runtime.Object, io.Writer) error
  140. HandledResources() []string
  141. //Can be used to print out warning/clarifications if needed
  142. //after all objects were printed
  143. FinishPrint(io.Writer, string) error
  144. }
  145. // ResourcePrinterFunc is a function that can print objects
  146. type ResourcePrinterFunc func(runtime.Object, io.Writer) error
  147. // PrintObj implements ResourcePrinter
  148. func (fn ResourcePrinterFunc) PrintObj(obj runtime.Object, w io.Writer) error {
  149. return fn(obj, w)
  150. }
  151. // TODO: implement HandledResources()
  152. func (fn ResourcePrinterFunc) HandledResources() []string {
  153. return []string{}
  154. }
  155. func (fn ResourcePrinterFunc) FinishPrint(io.Writer, string) error {
  156. return nil
  157. }
  158. // VersionedPrinter takes runtime objects and ensures they are converted to a given API version
  159. // prior to being passed to a nested printer.
  160. type VersionedPrinter struct {
  161. printer ResourcePrinter
  162. converter runtime.ObjectConvertor
  163. versions []unversioned.GroupVersion
  164. }
  165. // NewVersionedPrinter wraps a printer to convert objects to a known API version prior to printing.
  166. func NewVersionedPrinter(printer ResourcePrinter, converter runtime.ObjectConvertor, versions ...unversioned.GroupVersion) ResourcePrinter {
  167. return &VersionedPrinter{
  168. printer: printer,
  169. converter: converter,
  170. versions: versions,
  171. }
  172. }
  173. func (p *VersionedPrinter) FinishPrint(w io.Writer, res string) error {
  174. return nil
  175. }
  176. // PrintObj implements ResourcePrinter
  177. func (p *VersionedPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
  178. if len(p.versions) == 0 {
  179. return fmt.Errorf("no version specified, object cannot be converted")
  180. }
  181. converted, err := p.converter.ConvertToVersion(obj, unversioned.GroupVersions(p.versions))
  182. if err != nil {
  183. return err
  184. }
  185. return p.printer.PrintObj(converted, w)
  186. }
  187. // TODO: implement HandledResources()
  188. func (p *VersionedPrinter) HandledResources() []string {
  189. return []string{}
  190. }
  191. // NamePrinter is an implementation of ResourcePrinter which outputs "resource/name" pair of an object.
  192. type NamePrinter struct {
  193. Decoder runtime.Decoder
  194. Typer runtime.ObjectTyper
  195. }
  196. func (p *NamePrinter) FinishPrint(w io.Writer, res string) error {
  197. return nil
  198. }
  199. // PrintObj is an implementation of ResourcePrinter.PrintObj which decodes the object
  200. // and print "resource/name" pair. If the object is a List, print all items in it.
  201. func (p *NamePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
  202. if meta.IsListType(obj) {
  203. items, err := meta.ExtractList(obj)
  204. if err != nil {
  205. return err
  206. }
  207. if errs := runtime.DecodeList(items, p.Decoder, runtime.UnstructuredJSONScheme); len(errs) > 0 {
  208. return utilerrors.NewAggregate(errs)
  209. }
  210. for _, obj := range items {
  211. if err := p.PrintObj(obj, w); err != nil {
  212. return err
  213. }
  214. }
  215. return nil
  216. }
  217. // TODO: this is wrong, runtime.Unknown and runtime.Unstructured are not handled properly here.
  218. name := "<unknown>"
  219. if acc, err := meta.Accessor(obj); err == nil {
  220. if n := acc.GetName(); len(n) > 0 {
  221. name = n
  222. }
  223. }
  224. if gvks, _, err := p.Typer.ObjectKinds(obj); err == nil {
  225. // TODO: this is wrong, it assumes that meta knows about all Kinds - should take a RESTMapper
  226. _, resource := meta.KindToResource(gvks[0])
  227. fmt.Fprintf(w, "%s/%s\n", resource.Resource, name)
  228. } else {
  229. fmt.Fprintf(w, "<unknown>/%s\n", name)
  230. }
  231. return nil
  232. }
  233. // TODO: implement HandledResources()
  234. func (p *NamePrinter) HandledResources() []string {
  235. return []string{}
  236. }
  237. // JSONPrinter is an implementation of ResourcePrinter which outputs an object as JSON.
  238. type JSONPrinter struct {
  239. }
  240. func (p *JSONPrinter) FinishPrint(w io.Writer, res string) error {
  241. return nil
  242. }
  243. // PrintObj is an implementation of ResourcePrinter.PrintObj which simply writes the object to the Writer.
  244. func (p *JSONPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
  245. switch obj := obj.(type) {
  246. case *runtime.Unknown:
  247. _, err := w.Write(obj.Raw)
  248. return err
  249. }
  250. data, err := json.MarshalIndent(obj, "", " ")
  251. if err != nil {
  252. return err
  253. }
  254. data = append(data, '\n')
  255. _, err = w.Write(data)
  256. return err
  257. }
  258. // TODO: implement HandledResources()
  259. func (p *JSONPrinter) HandledResources() []string {
  260. return []string{}
  261. }
  262. // YAMLPrinter is an implementation of ResourcePrinter which outputs an object as YAML.
  263. // The input object is assumed to be in the internal version of an API and is converted
  264. // to the given version first.
  265. type YAMLPrinter struct {
  266. version string
  267. converter runtime.ObjectConvertor
  268. }
  269. func (p *YAMLPrinter) FinishPrint(w io.Writer, res string) error {
  270. return nil
  271. }
  272. // PrintObj prints the data as YAML.
  273. func (p *YAMLPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
  274. switch obj := obj.(type) {
  275. case *runtime.Unknown:
  276. data, err := yaml.JSONToYAML(obj.Raw)
  277. if err != nil {
  278. return err
  279. }
  280. _, err = w.Write(data)
  281. return err
  282. }
  283. output, err := yaml.Marshal(obj)
  284. if err != nil {
  285. return err
  286. }
  287. _, err = fmt.Fprint(w, string(output))
  288. return err
  289. }
  290. // TODO: implement HandledResources()
  291. func (p *YAMLPrinter) HandledResources() []string {
  292. return []string{}
  293. }
  294. type handlerEntry struct {
  295. columns []string
  296. printFunc reflect.Value
  297. args []reflect.Value
  298. }
  299. type PrintOptions struct {
  300. NoHeaders bool
  301. WithNamespace bool
  302. WithKind bool
  303. Wide bool
  304. ShowAll bool
  305. ShowLabels bool
  306. AbsoluteTimestamps bool
  307. Kind string
  308. ColumnLabels []string
  309. }
  310. // HumanReadablePrinter is an implementation of ResourcePrinter which attempts to provide
  311. // more elegant output. It is not threadsafe, but you may call PrintObj repeatedly; headers
  312. // will only be printed if the object type changes. This makes it useful for printing items
  313. // received from watches.
  314. type HumanReadablePrinter struct {
  315. handlerMap map[reflect.Type]*handlerEntry
  316. options PrintOptions
  317. lastType reflect.Type
  318. hiddenObjNum int
  319. }
  320. // NewHumanReadablePrinter creates a HumanReadablePrinter.
  321. func NewHumanReadablePrinter(options PrintOptions) *HumanReadablePrinter {
  322. printer := &HumanReadablePrinter{
  323. handlerMap: make(map[reflect.Type]*handlerEntry),
  324. options: options,
  325. }
  326. printer.addDefaultHandlers()
  327. return printer
  328. }
  329. // formatResourceName receives a resource kind, name, and boolean specifying
  330. // whether or not to update the current name to "kind/name"
  331. func formatResourceName(kind, name string, withKind bool) string {
  332. if !withKind || kind == "" {
  333. return name
  334. }
  335. return kind + "/" + name
  336. }
  337. // GetResourceKind returns the type currently set for a resource
  338. func (h *HumanReadablePrinter) GetResourceKind() string {
  339. return h.options.Kind
  340. }
  341. // EnsurePrintWithKind sets HumanReadablePrinter options "WithKind" to true
  342. // and "Kind" to the string arg it receives, pre-pending this string
  343. // to the "NAME" column in an output of resources.
  344. func (h *HumanReadablePrinter) EnsurePrintWithKind(kind string) {
  345. h.options.WithKind = true
  346. h.options.Kind = kind
  347. }
  348. // Handler adds a print handler with a given set of columns to HumanReadablePrinter instance.
  349. // See validatePrintHandlerFunc for required method signature.
  350. func (h *HumanReadablePrinter) Handler(columns []string, printFunc interface{}) error {
  351. printFuncValue := reflect.ValueOf(printFunc)
  352. if err := h.validatePrintHandlerFunc(printFuncValue); err != nil {
  353. glog.Errorf("Unable to add print handler: %v", err)
  354. return err
  355. }
  356. objType := printFuncValue.Type().In(0)
  357. h.handlerMap[objType] = &handlerEntry{
  358. columns: columns,
  359. printFunc: printFuncValue,
  360. }
  361. return nil
  362. }
  363. // validatePrintHandlerFunc validates print handler signature.
  364. // printFunc is the function that will be called to print an object.
  365. // It must be of the following type:
  366. // func printFunc(object ObjectType, w io.Writer, options PrintOptions) error
  367. // where ObjectType is the type of the object that will be printed.
  368. func (h *HumanReadablePrinter) validatePrintHandlerFunc(printFunc reflect.Value) error {
  369. if printFunc.Kind() != reflect.Func {
  370. return fmt.Errorf("invalid print handler. %#v is not a function", printFunc)
  371. }
  372. funcType := printFunc.Type()
  373. if funcType.NumIn() != 3 || funcType.NumOut() != 1 {
  374. return fmt.Errorf("invalid print handler." +
  375. "Must accept 3 parameters and return 1 value.")
  376. }
  377. if funcType.In(1) != reflect.TypeOf((*io.Writer)(nil)).Elem() ||
  378. funcType.In(2) != reflect.TypeOf((*PrintOptions)(nil)).Elem() ||
  379. funcType.Out(0) != reflect.TypeOf((*error)(nil)).Elem() {
  380. return fmt.Errorf("invalid print handler. The expected signature is: "+
  381. "func handler(obj %v, w io.Writer, options PrintOptions) error", funcType.In(0))
  382. }
  383. return nil
  384. }
  385. func (h *HumanReadablePrinter) HandledResources() []string {
  386. keys := make([]string, 0)
  387. for k := range h.handlerMap {
  388. // k.String looks like "*api.PodList" and we want just "pod"
  389. api := strings.Split(k.String(), ".")
  390. resource := api[len(api)-1]
  391. if strings.HasSuffix(resource, "List") {
  392. continue
  393. }
  394. resource = strings.ToLower(resource)
  395. keys = append(keys, resource)
  396. }
  397. return keys
  398. }
  399. func (h *HumanReadablePrinter) FinishPrint(output io.Writer, res string) error {
  400. if !h.options.NoHeaders && !h.options.ShowAll && h.hiddenObjNum > 0 {
  401. _, err := fmt.Fprintf(output, " info: %d completed object(s) was(were) not shown in %s list. Pass --show-all to see all objects.\n\n", h.hiddenObjNum, res)
  402. return err
  403. }
  404. return nil
  405. }
  406. // NOTE: When adding a new resource type here, please update the list
  407. // pkg/kubectl/cmd/get.go to reflect the new resource type.
  408. var podColumns = []string{"NAME", "READY", "STATUS", "RESTARTS", "AGE"}
  409. var podTemplateColumns = []string{"TEMPLATE", "CONTAINER(S)", "IMAGE(S)", "PODLABELS"}
  410. var replicationControllerColumns = []string{"NAME", "DESIRED", "CURRENT", "READY", "AGE"}
  411. var replicaSetColumns = []string{"NAME", "DESIRED", "CURRENT", "READY", "AGE"}
  412. var jobColumns = []string{"NAME", "DESIRED", "SUCCESSFUL", "AGE"}
  413. var scheduledJobColumns = []string{"NAME", "SCHEDULE", "SUSPEND", "ACTIVE", "LAST-SCHEDULE"}
  414. var serviceColumns = []string{"NAME", "CLUSTER-IP", "EXTERNAL-IP", "PORT(S)", "AGE"}
  415. var ingressColumns = []string{"NAME", "HOSTS", "ADDRESS", "PORTS", "AGE"}
  416. var petSetColumns = []string{"NAME", "DESIRED", "CURRENT", "AGE"}
  417. var endpointColumns = []string{"NAME", "ENDPOINTS", "AGE"}
  418. var nodeColumns = []string{"NAME", "STATUS", "AGE"}
  419. var daemonSetColumns = []string{"NAME", "DESIRED", "CURRENT", "NODE-SELECTOR", "AGE"}
  420. var eventColumns = []string{"LASTSEEN", "FIRSTSEEN", "COUNT", "NAME", "KIND", "SUBOBJECT", "TYPE", "REASON", "SOURCE", "MESSAGE"}
  421. var limitRangeColumns = []string{"NAME", "AGE"}
  422. var resourceQuotaColumns = []string{"NAME", "AGE"}
  423. var namespaceColumns = []string{"NAME", "STATUS", "AGE"}
  424. var secretColumns = []string{"NAME", "TYPE", "DATA", "AGE"}
  425. var serviceAccountColumns = []string{"NAME", "SECRETS", "AGE"}
  426. var persistentVolumeColumns = []string{"NAME", "CAPACITY", "ACCESSMODES", "RECLAIMPOLICY", "STATUS", "CLAIM", "REASON", "AGE"}
  427. var persistentVolumeClaimColumns = []string{"NAME", "STATUS", "VOLUME", "CAPACITY", "ACCESSMODES", "AGE"}
  428. var componentStatusColumns = []string{"NAME", "STATUS", "MESSAGE", "ERROR"}
  429. var thirdPartyResourceColumns = []string{"NAME", "DESCRIPTION", "VERSION(S)"}
  430. var roleColumns = []string{"NAME", "AGE"}
  431. var roleBindingColumns = []string{"NAME", "AGE"}
  432. var clusterRoleColumns = []string{"NAME", "AGE"}
  433. var clusterRoleBindingColumns = []string{"NAME", "AGE"}
  434. var storageClassColumns = []string{"NAME", "TYPE"}
  435. // TODO: consider having 'KIND' for third party resource data
  436. var thirdPartyResourceDataColumns = []string{"NAME", "LABELS", "DATA"}
  437. var horizontalPodAutoscalerColumns = []string{"NAME", "REFERENCE", "TARGET", "CURRENT", "MINPODS", "MAXPODS", "AGE"}
  438. var withNamespacePrefixColumns = []string{"NAMESPACE"} // TODO(erictune): print cluster name too.
  439. var deploymentColumns = []string{"NAME", "DESIRED", "CURRENT", "UP-TO-DATE", "AVAILABLE", "AGE"}
  440. var configMapColumns = []string{"NAME", "DATA", "AGE"}
  441. var podSecurityPolicyColumns = []string{"NAME", "PRIV", "CAPS", "VOLUMEPLUGINS", "SELINUX", "RUNASUSER"}
  442. var clusterColumns = []string{"NAME", "STATUS", "AGE"}
  443. var networkPolicyColumns = []string{"NAME", "POD-SELECTOR", "AGE"}
  444. var certificateSigningRequestColumns = []string{"NAME", "AGE", "REQUESTOR", "CONDITION"}
  445. func (h *HumanReadablePrinter) printPod(pod *api.Pod, w io.Writer, options PrintOptions) error {
  446. reason := string(pod.Status.Phase)
  447. // if not printing all pods, skip terminated pods (default)
  448. if !options.ShowAll && (reason == string(api.PodSucceeded) || reason == string(api.PodFailed)) {
  449. h.hiddenObjNum++
  450. return nil
  451. }
  452. if err := printPodBase(pod, w, options); err != nil {
  453. return err
  454. }
  455. return nil
  456. }
  457. func (h *HumanReadablePrinter) printPodList(podList *api.PodList, w io.Writer, options PrintOptions) error {
  458. for _, pod := range podList.Items {
  459. reason := string(pod.Status.Phase)
  460. // if not printing all pods, skip terminated pods (default)
  461. if !options.ShowAll && (reason == string(api.PodSucceeded) || reason == string(api.PodFailed)) {
  462. h.hiddenObjNum++
  463. continue
  464. }
  465. if err := printPodBase(&pod, w, options); err != nil {
  466. return err
  467. }
  468. }
  469. return nil
  470. }
  471. // addDefaultHandlers adds print handlers for default Kubernetes types.
  472. func (h *HumanReadablePrinter) addDefaultHandlers() {
  473. h.Handler(podColumns, h.printPodList)
  474. h.Handler(podColumns, h.printPod)
  475. h.Handler(podTemplateColumns, printPodTemplate)
  476. h.Handler(podTemplateColumns, printPodTemplateList)
  477. h.Handler(replicationControllerColumns, printReplicationController)
  478. h.Handler(replicationControllerColumns, printReplicationControllerList)
  479. h.Handler(replicaSetColumns, printReplicaSet)
  480. h.Handler(replicaSetColumns, printReplicaSetList)
  481. h.Handler(daemonSetColumns, printDaemonSet)
  482. h.Handler(daemonSetColumns, printDaemonSetList)
  483. h.Handler(jobColumns, printJob)
  484. h.Handler(jobColumns, printJobList)
  485. h.Handler(scheduledJobColumns, printScheduledJob)
  486. h.Handler(scheduledJobColumns, printScheduledJobList)
  487. h.Handler(serviceColumns, printService)
  488. h.Handler(serviceColumns, printServiceList)
  489. h.Handler(ingressColumns, printIngress)
  490. h.Handler(ingressColumns, printIngressList)
  491. h.Handler(petSetColumns, printPetSet)
  492. h.Handler(petSetColumns, printPetSetList)
  493. h.Handler(endpointColumns, printEndpoints)
  494. h.Handler(endpointColumns, printEndpointsList)
  495. h.Handler(nodeColumns, printNode)
  496. h.Handler(nodeColumns, printNodeList)
  497. h.Handler(eventColumns, printEvent)
  498. h.Handler(eventColumns, printEventList)
  499. h.Handler(limitRangeColumns, printLimitRange)
  500. h.Handler(limitRangeColumns, printLimitRangeList)
  501. h.Handler(resourceQuotaColumns, printResourceQuota)
  502. h.Handler(resourceQuotaColumns, printResourceQuotaList)
  503. h.Handler(namespaceColumns, printNamespace)
  504. h.Handler(namespaceColumns, printNamespaceList)
  505. h.Handler(secretColumns, printSecret)
  506. h.Handler(secretColumns, printSecretList)
  507. h.Handler(serviceAccountColumns, printServiceAccount)
  508. h.Handler(serviceAccountColumns, printServiceAccountList)
  509. h.Handler(persistentVolumeClaimColumns, printPersistentVolumeClaim)
  510. h.Handler(persistentVolumeClaimColumns, printPersistentVolumeClaimList)
  511. h.Handler(persistentVolumeColumns, printPersistentVolume)
  512. h.Handler(persistentVolumeColumns, printPersistentVolumeList)
  513. h.Handler(componentStatusColumns, printComponentStatus)
  514. h.Handler(componentStatusColumns, printComponentStatusList)
  515. h.Handler(thirdPartyResourceColumns, printThirdPartyResource)
  516. h.Handler(thirdPartyResourceColumns, printThirdPartyResourceList)
  517. h.Handler(deploymentColumns, printDeployment)
  518. h.Handler(deploymentColumns, printDeploymentList)
  519. h.Handler(horizontalPodAutoscalerColumns, printHorizontalPodAutoscaler)
  520. h.Handler(horizontalPodAutoscalerColumns, printHorizontalPodAutoscalerList)
  521. h.Handler(configMapColumns, printConfigMap)
  522. h.Handler(configMapColumns, printConfigMapList)
  523. h.Handler(podSecurityPolicyColumns, printPodSecurityPolicy)
  524. h.Handler(podSecurityPolicyColumns, printPodSecurityPolicyList)
  525. h.Handler(thirdPartyResourceDataColumns, printThirdPartyResourceData)
  526. h.Handler(thirdPartyResourceDataColumns, printThirdPartyResourceDataList)
  527. h.Handler(clusterColumns, printCluster)
  528. h.Handler(clusterColumns, printClusterList)
  529. h.Handler(networkPolicyColumns, printNetworkPolicy)
  530. h.Handler(networkPolicyColumns, printNetworkPolicyList)
  531. h.Handler(roleColumns, printRole)
  532. h.Handler(roleColumns, printRoleList)
  533. h.Handler(roleBindingColumns, printRoleBinding)
  534. h.Handler(roleBindingColumns, printRoleBindingList)
  535. h.Handler(clusterRoleColumns, printClusterRole)
  536. h.Handler(clusterRoleColumns, printClusterRoleList)
  537. h.Handler(clusterRoleBindingColumns, printClusterRoleBinding)
  538. h.Handler(clusterRoleBindingColumns, printClusterRoleBindingList)
  539. h.Handler(certificateSigningRequestColumns, printCertificateSigningRequest)
  540. h.Handler(certificateSigningRequestColumns, printCertificateSigningRequestList)
  541. h.Handler(storageClassColumns, printStorageClass)
  542. h.Handler(storageClassColumns, printStorageClassList)
  543. }
  544. func (h *HumanReadablePrinter) unknown(data []byte, w io.Writer) error {
  545. _, err := fmt.Fprintf(w, "Unknown object: %s", string(data))
  546. return err
  547. }
  548. func (h *HumanReadablePrinter) printHeader(columnNames []string, w io.Writer) error {
  549. if _, err := fmt.Fprintf(w, "%s\n", strings.Join(columnNames, "\t")); err != nil {
  550. return err
  551. }
  552. return nil
  553. }
  554. // Pass ports=nil for all ports.
  555. func formatEndpoints(endpoints *api.Endpoints, ports sets.String) string {
  556. if len(endpoints.Subsets) == 0 {
  557. return "<none>"
  558. }
  559. list := []string{}
  560. max := 3
  561. more := false
  562. count := 0
  563. for i := range endpoints.Subsets {
  564. ss := &endpoints.Subsets[i]
  565. for i := range ss.Ports {
  566. port := &ss.Ports[i]
  567. if ports == nil || ports.Has(port.Name) {
  568. for i := range ss.Addresses {
  569. if len(list) == max {
  570. more = true
  571. }
  572. addr := &ss.Addresses[i]
  573. if !more {
  574. list = append(list, fmt.Sprintf("%s:%d", addr.IP, port.Port))
  575. }
  576. count++
  577. }
  578. }
  579. }
  580. }
  581. ret := strings.Join(list, ",")
  582. if more {
  583. return fmt.Sprintf("%s + %d more...", ret, count-max)
  584. }
  585. return ret
  586. }
  587. func shortHumanDuration(d time.Duration) string {
  588. // Allow deviation no more than 2 seconds(excluded) to tolerate machine time
  589. // inconsistence, it can be considered as almost now.
  590. if seconds := int(d.Seconds()); seconds < -1 {
  591. return fmt.Sprintf("<invalid>")
  592. } else if seconds < 0 {
  593. return fmt.Sprintf("0s")
  594. } else if seconds < 60 {
  595. return fmt.Sprintf("%ds", seconds)
  596. } else if minutes := int(d.Minutes()); minutes < 60 {
  597. return fmt.Sprintf("%dm", minutes)
  598. } else if hours := int(d.Hours()); hours < 24 {
  599. return fmt.Sprintf("%dh", hours)
  600. } else if hours < 24*364 {
  601. return fmt.Sprintf("%dd", hours/24)
  602. }
  603. return fmt.Sprintf("%dy", int(d.Hours()/24/365))
  604. }
  605. // translateTimestamp returns the elapsed time since timestamp in
  606. // human-readable approximation.
  607. func translateTimestamp(timestamp unversioned.Time) string {
  608. if timestamp.IsZero() {
  609. return "<unknown>"
  610. }
  611. return shortHumanDuration(time.Now().Sub(timestamp.Time))
  612. }
  613. func printPodBase(pod *api.Pod, w io.Writer, options PrintOptions) error {
  614. name := formatResourceName(options.Kind, pod.Name, options.WithKind)
  615. namespace := pod.Namespace
  616. restarts := 0
  617. totalContainers := len(pod.Spec.Containers)
  618. readyContainers := 0
  619. reason := string(pod.Status.Phase)
  620. if pod.Status.Reason != "" {
  621. reason = pod.Status.Reason
  622. }
  623. initializing := false
  624. for i := range pod.Status.InitContainerStatuses {
  625. container := pod.Status.InitContainerStatuses[i]
  626. restarts += int(container.RestartCount)
  627. switch {
  628. case container.State.Terminated != nil && container.State.Terminated.ExitCode == 0:
  629. continue
  630. case container.State.Terminated != nil:
  631. // initialization is failed
  632. if len(container.State.Terminated.Reason) == 0 {
  633. if container.State.Terminated.Signal != 0 {
  634. reason = fmt.Sprintf("Init:Signal:%d", container.State.Terminated.Signal)
  635. } else {
  636. reason = fmt.Sprintf("Init:ExitCode:%d", container.State.Terminated.ExitCode)
  637. }
  638. } else {
  639. reason = "Init:" + container.State.Terminated.Reason
  640. }
  641. initializing = true
  642. case container.State.Waiting != nil && len(container.State.Waiting.Reason) > 0 && container.State.Waiting.Reason != "PodInitializing":
  643. reason = "Init:" + container.State.Waiting.Reason
  644. initializing = true
  645. default:
  646. reason = fmt.Sprintf("Init:%d/%d", i, len(pod.Spec.InitContainers))
  647. initializing = true
  648. }
  649. break
  650. }
  651. if !initializing {
  652. restarts = 0
  653. for i := len(pod.Status.ContainerStatuses) - 1; i >= 0; i-- {
  654. container := pod.Status.ContainerStatuses[i]
  655. restarts += int(container.RestartCount)
  656. if container.State.Waiting != nil && container.State.Waiting.Reason != "" {
  657. reason = container.State.Waiting.Reason
  658. } else if container.State.Terminated != nil && container.State.Terminated.Reason != "" {
  659. reason = container.State.Terminated.Reason
  660. } else if container.State.Terminated != nil && container.State.Terminated.Reason == "" {
  661. if container.State.Terminated.Signal != 0 {
  662. reason = fmt.Sprintf("Signal:%d", container.State.Terminated.Signal)
  663. } else {
  664. reason = fmt.Sprintf("ExitCode:%d", container.State.Terminated.ExitCode)
  665. }
  666. } else if container.Ready && container.State.Running != nil {
  667. readyContainers++
  668. }
  669. }
  670. }
  671. if pod.DeletionTimestamp != nil {
  672. reason = "Terminating"
  673. }
  674. if options.WithNamespace {
  675. if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
  676. return err
  677. }
  678. }
  679. if _, err := fmt.Fprintf(w, "%s\t%d/%d\t%s\t%d\t%s",
  680. name,
  681. readyContainers,
  682. totalContainers,
  683. reason,
  684. restarts,
  685. translateTimestamp(pod.CreationTimestamp),
  686. ); err != nil {
  687. return err
  688. }
  689. if options.Wide {
  690. nodeName := pod.Spec.NodeName
  691. podIP := pod.Status.PodIP
  692. if podIP == "" {
  693. podIP = "<none>"
  694. }
  695. if _, err := fmt.Fprintf(w, "\t%s\t%s",
  696. podIP,
  697. nodeName,
  698. ); err != nil {
  699. return err
  700. }
  701. }
  702. if _, err := fmt.Fprint(w, AppendLabels(pod.Labels, options.ColumnLabels)); err != nil {
  703. return err
  704. }
  705. if _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, pod.Labels)); err != nil {
  706. return err
  707. }
  708. return nil
  709. }
  710. func printPodTemplate(pod *api.PodTemplate, w io.Writer, options PrintOptions) error {
  711. name := formatResourceName(options.Kind, pod.Name, options.WithKind)
  712. namespace := pod.Namespace
  713. containers := pod.Template.Spec.Containers
  714. if options.WithNamespace {
  715. if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
  716. return err
  717. }
  718. }
  719. if _, err := fmt.Fprintf(w, "%s", name); err != nil {
  720. return err
  721. }
  722. if err := layoutContainers(containers, w); err != nil {
  723. return err
  724. }
  725. if _, err := fmt.Fprintf(w, "\t%s", labels.FormatLabels(pod.Template.Labels)); err != nil {
  726. return err
  727. }
  728. if _, err := fmt.Fprint(w, AppendLabels(pod.Labels, options.ColumnLabels)); err != nil {
  729. return err
  730. }
  731. if _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, pod.Labels)); err != nil {
  732. return err
  733. }
  734. return nil
  735. }
  736. func printPodTemplateList(podList *api.PodTemplateList, w io.Writer, options PrintOptions) error {
  737. for _, pod := range podList.Items {
  738. if err := printPodTemplate(&pod, w, options); err != nil {
  739. return err
  740. }
  741. }
  742. return nil
  743. }
  744. // TODO(AdoHe): try to put wide output in a single method
  745. func printReplicationController(controller *api.ReplicationController, w io.Writer, options PrintOptions) error {
  746. name := formatResourceName(options.Kind, controller.Name, options.WithKind)
  747. namespace := controller.Namespace
  748. containers := controller.Spec.Template.Spec.Containers
  749. if options.WithNamespace {
  750. if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
  751. return err
  752. }
  753. }
  754. desiredReplicas := controller.Spec.Replicas
  755. currentReplicas := controller.Status.Replicas
  756. readyReplicas := controller.Status.ReadyReplicas
  757. if _, err := fmt.Fprintf(w, "%s\t%d\t%d\t%d\t%s",
  758. name,
  759. desiredReplicas,
  760. currentReplicas,
  761. readyReplicas,
  762. translateTimestamp(controller.CreationTimestamp),
  763. ); err != nil {
  764. return err
  765. }
  766. if options.Wide {
  767. if err := layoutContainers(containers, w); err != nil {
  768. return err
  769. }
  770. if _, err := fmt.Fprintf(w, "\t%s", labels.FormatLabels(controller.Spec.Selector)); err != nil {
  771. return err
  772. }
  773. }
  774. if _, err := fmt.Fprint(w, AppendLabels(controller.Labels, options.ColumnLabels)); err != nil {
  775. return err
  776. }
  777. if _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, controller.Labels)); err != nil {
  778. return err
  779. }
  780. return nil
  781. }
  782. func printReplicationControllerList(list *api.ReplicationControllerList, w io.Writer, options PrintOptions) error {
  783. for _, controller := range list.Items {
  784. if err := printReplicationController(&controller, w, options); err != nil {
  785. return err
  786. }
  787. }
  788. return nil
  789. }
  790. func printReplicaSet(rs *extensions.ReplicaSet, w io.Writer, options PrintOptions) error {
  791. name := formatResourceName(options.Kind, rs.Name, options.WithKind)
  792. namespace := rs.Namespace
  793. containers := rs.Spec.Template.Spec.Containers
  794. if options.WithNamespace {
  795. if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
  796. return err
  797. }
  798. }
  799. desiredReplicas := rs.Spec.Replicas
  800. currentReplicas := rs.Status.Replicas
  801. readyReplicas := rs.Status.ReadyReplicas
  802. if _, err := fmt.Fprintf(w, "%s\t%d\t%d\t%d\t%s",
  803. name,
  804. desiredReplicas,
  805. currentReplicas,
  806. readyReplicas,
  807. translateTimestamp(rs.CreationTimestamp),
  808. ); err != nil {
  809. return err
  810. }
  811. if options.Wide {
  812. if err := layoutContainers(containers, w); err != nil {
  813. return err
  814. }
  815. if _, err := fmt.Fprintf(w, "\t%s", unversioned.FormatLabelSelector(rs.Spec.Selector)); err != nil {
  816. return err
  817. }
  818. }
  819. if _, err := fmt.Fprint(w, AppendLabels(rs.Labels, options.ColumnLabels)); err != nil {
  820. return err
  821. }
  822. if _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, rs.Labels)); err != nil {
  823. return err
  824. }
  825. return nil
  826. }
  827. func printReplicaSetList(list *extensions.ReplicaSetList, w io.Writer, options PrintOptions) error {
  828. for _, rs := range list.Items {
  829. if err := printReplicaSet(&rs, w, options); err != nil {
  830. return err
  831. }
  832. }
  833. return nil
  834. }
  835. func printCluster(c *federation.Cluster, w io.Writer, options PrintOptions) error {
  836. name := formatResourceName(options.Kind, c.Name, options.WithKind)
  837. var statuses []string
  838. for _, condition := range c.Status.Conditions {
  839. if condition.Status == api.ConditionTrue {
  840. statuses = append(statuses, string(condition.Type))
  841. } else {
  842. statuses = append(statuses, "Not"+string(condition.Type))
  843. }
  844. }
  845. if len(statuses) == 0 {
  846. statuses = append(statuses, "Unknown")
  847. }
  848. if _, err := fmt.Fprintf(w, "%s\t%s\t%s\n",
  849. name,
  850. strings.Join(statuses, ","),
  851. translateTimestamp(c.CreationTimestamp),
  852. ); err != nil {
  853. return err
  854. }
  855. return nil
  856. }
  857. func printClusterList(list *federation.ClusterList, w io.Writer, options PrintOptions) error {
  858. for _, rs := range list.Items {
  859. if err := printCluster(&rs, w, options); err != nil {
  860. return err
  861. }
  862. }
  863. return nil
  864. }
  865. func printJob(job *batch.Job, w io.Writer, options PrintOptions) error {
  866. name := formatResourceName(options.Kind, job.Name, options.WithKind)
  867. namespace := job.Namespace
  868. containers := job.Spec.Template.Spec.Containers
  869. if options.WithNamespace {
  870. if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
  871. return err
  872. }
  873. }
  874. selector, err := unversioned.LabelSelectorAsSelector(job.Spec.Selector)
  875. if err != nil {
  876. // this shouldn't happen if LabelSelector passed validation
  877. return err
  878. }
  879. if job.Spec.Completions != nil {
  880. if _, err := fmt.Fprintf(w, "%s\t%d\t%d\t%s",
  881. name,
  882. *job.Spec.Completions,
  883. job.Status.Succeeded,
  884. translateTimestamp(job.CreationTimestamp),
  885. ); err != nil {
  886. return err
  887. }
  888. } else {
  889. if _, err := fmt.Fprintf(w, "%s\t%s\t%d\t%s",
  890. name,
  891. "<none>",
  892. job.Status.Succeeded,
  893. translateTimestamp(job.CreationTimestamp),
  894. ); err != nil {
  895. return err
  896. }
  897. }
  898. if options.Wide {
  899. if err := layoutContainers(containers, w); err != nil {
  900. return err
  901. }
  902. if _, err := fmt.Fprintf(w, "\t%s", selector.String()); err != nil {
  903. return err
  904. }
  905. }
  906. if _, err := fmt.Fprint(w, AppendLabels(job.Labels, options.ColumnLabels)); err != nil {
  907. return err
  908. }
  909. if _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, job.Labels)); err != nil {
  910. return err
  911. }
  912. return nil
  913. }
  914. func printJobList(list *batch.JobList, w io.Writer, options PrintOptions) error {
  915. for _, job := range list.Items {
  916. if err := printJob(&job, w, options); err != nil {
  917. return err
  918. }
  919. }
  920. return nil
  921. }
  922. func printScheduledJob(scheduledJob *batch.ScheduledJob, w io.Writer, options PrintOptions) error {
  923. name := scheduledJob.Name
  924. namespace := scheduledJob.Namespace
  925. if options.WithNamespace {
  926. if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
  927. return err
  928. }
  929. }
  930. lastScheduleTime := "<none>"
  931. if scheduledJob.Status.LastScheduleTime != nil {
  932. lastScheduleTime = scheduledJob.Status.LastScheduleTime.Time.Format(time.RFC1123Z)
  933. }
  934. if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%d\t%s\n",
  935. name,
  936. scheduledJob.Spec.Schedule,
  937. printBoolPtr(scheduledJob.Spec.Suspend),
  938. len(scheduledJob.Status.Active),
  939. lastScheduleTime,
  940. ); err != nil {
  941. return err
  942. }
  943. return nil
  944. }
  945. func printScheduledJobList(list *batch.ScheduledJobList, w io.Writer, options PrintOptions) error {
  946. for _, scheduledJob := range list.Items {
  947. if err := printScheduledJob(&scheduledJob, w, options); err != nil {
  948. return err
  949. }
  950. }
  951. return nil
  952. }
  953. // loadBalancerStatusStringer behaves mostly like a string interface and converts the given status to a string.
  954. // `wide` indicates whether the returned value is meant for --o=wide output. If not, it's clipped to 16 bytes.
  955. func loadBalancerStatusStringer(s api.LoadBalancerStatus, wide bool) string {
  956. ingress := s.Ingress
  957. result := []string{}
  958. for i := range ingress {
  959. if ingress[i].IP != "" {
  960. result = append(result, ingress[i].IP)
  961. } else if ingress[i].Hostname != "" {
  962. result = append(result, ingress[i].Hostname)
  963. }
  964. }
  965. r := strings.Join(result, ",")
  966. if !wide && len(r) > loadBalancerWidth {
  967. r = r[0:(loadBalancerWidth-3)] + "..."
  968. }
  969. return r
  970. }
  971. func getServiceExternalIP(svc *api.Service, wide bool) string {
  972. switch svc.Spec.Type {
  973. case api.ServiceTypeClusterIP:
  974. if len(svc.Spec.ExternalIPs) > 0 {
  975. return strings.Join(svc.Spec.ExternalIPs, ",")
  976. }
  977. return "<none>"
  978. case api.ServiceTypeNodePort:
  979. if len(svc.Spec.ExternalIPs) > 0 {
  980. return strings.Join(svc.Spec.ExternalIPs, ",")
  981. }
  982. return "<nodes>"
  983. case api.ServiceTypeLoadBalancer:
  984. lbIps := loadBalancerStatusStringer(svc.Status.LoadBalancer, wide)
  985. if len(svc.Spec.ExternalIPs) > 0 {
  986. result := append(strings.Split(lbIps, ","), svc.Spec.ExternalIPs...)
  987. return strings.Join(result, ",")
  988. }
  989. if len(lbIps) > 0 {
  990. return lbIps
  991. }
  992. return "<pending>"
  993. case api.ServiceTypeExternalName:
  994. return svc.Spec.ExternalName
  995. }
  996. return "<unknown>"
  997. }
  998. func makePortString(ports []api.ServicePort) string {
  999. pieces := make([]string, len(ports))
  1000. for ix := range ports {
  1001. port := &ports[ix]
  1002. pieces[ix] = fmt.Sprintf("%d/%s", port.Port, port.Protocol)
  1003. }
  1004. return strings.Join(pieces, ",")
  1005. }
  1006. func printService(svc *api.Service, w io.Writer, options PrintOptions) error {
  1007. name := formatResourceName(options.Kind, svc.Name, options.WithKind)
  1008. namespace := svc.Namespace
  1009. internalIP := svc.Spec.ClusterIP
  1010. externalIP := getServiceExternalIP(svc, options.Wide)
  1011. if options.WithNamespace {
  1012. if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
  1013. return err
  1014. }
  1015. }
  1016. if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s",
  1017. name,
  1018. internalIP,
  1019. externalIP,
  1020. makePortString(svc.Spec.Ports),
  1021. translateTimestamp(svc.CreationTimestamp),
  1022. ); err != nil {
  1023. return err
  1024. }
  1025. if options.Wide {
  1026. if _, err := fmt.Fprintf(w, "\t%s", labels.FormatLabels(svc.Spec.Selector)); err != nil {
  1027. return err
  1028. }
  1029. }
  1030. if _, err := fmt.Fprint(w, AppendLabels(svc.Labels, options.ColumnLabels)); err != nil {
  1031. return err
  1032. }
  1033. _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, svc.Labels))
  1034. return err
  1035. }
  1036. func printServiceList(list *api.ServiceList, w io.Writer, options PrintOptions) error {
  1037. for _, svc := range list.Items {
  1038. if err := printService(&svc, w, options); err != nil {
  1039. return err
  1040. }
  1041. }
  1042. return nil
  1043. }
  1044. // backendStringer behaves just like a string interface and converts the given backend to a string.
  1045. func backendStringer(backend *extensions.IngressBackend) string {
  1046. if backend == nil {
  1047. return ""
  1048. }
  1049. return fmt.Sprintf("%v:%v", backend.ServiceName, backend.ServicePort.String())
  1050. }
  1051. func formatHosts(rules []extensions.IngressRule) string {
  1052. list := []string{}
  1053. max := 3
  1054. more := false
  1055. for _, rule := range rules {
  1056. if len(list) == max {
  1057. more = true
  1058. }
  1059. if !more && len(rule.Host) != 0 {
  1060. list = append(list, rule.Host)
  1061. }
  1062. }
  1063. if len(list) == 0 {
  1064. return "*"
  1065. }
  1066. ret := strings.Join(list, ",")
  1067. if more {
  1068. return fmt.Sprintf("%s + %d more...", ret, len(rules)-max)
  1069. }
  1070. return ret
  1071. }
  1072. func formatPorts(tls []extensions.IngressTLS) string {
  1073. if len(tls) != 0 {
  1074. return "80, 443"
  1075. }
  1076. return "80"
  1077. }
  1078. func printIngress(ingress *extensions.Ingress, w io.Writer, options PrintOptions) error {
  1079. name := formatResourceName(options.Kind, ingress.Name, options.WithKind)
  1080. namespace := ingress.Namespace
  1081. if options.WithNamespace {
  1082. if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
  1083. return err
  1084. }
  1085. }
  1086. if _, err := fmt.Fprintf(w, "%s\t%v\t%v\t%v\t%s",
  1087. name,
  1088. formatHosts(ingress.Spec.Rules),
  1089. loadBalancerStatusStringer(ingress.Status.LoadBalancer, options.Wide),
  1090. formatPorts(ingress.Spec.TLS),
  1091. translateTimestamp(ingress.CreationTimestamp),
  1092. ); err != nil {
  1093. return err
  1094. }
  1095. if _, err := fmt.Fprint(w, AppendLabels(ingress.Labels, options.ColumnLabels)); err != nil {
  1096. return err
  1097. }
  1098. if _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, ingress.Labels)); err != nil {
  1099. return err
  1100. }
  1101. return nil
  1102. }
  1103. func printIngressList(ingressList *extensions.IngressList, w io.Writer, options PrintOptions) error {
  1104. for _, ingress := range ingressList.Items {
  1105. if err := printIngress(&ingress, w, options); err != nil {
  1106. return err
  1107. }
  1108. }
  1109. return nil
  1110. }
  1111. func printPetSet(ps *apps.PetSet, w io.Writer, options PrintOptions) error {
  1112. name := formatResourceName(options.Kind, ps.Name, options.WithKind)
  1113. namespace := ps.Namespace
  1114. containers := ps.Spec.Template.Spec.Containers
  1115. if options.WithNamespace {
  1116. if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
  1117. return err
  1118. }
  1119. }
  1120. desiredReplicas := ps.Spec.Replicas
  1121. currentReplicas := ps.Status.Replicas
  1122. if _, err := fmt.Fprintf(w, "%s\t%d\t%d\t%s",
  1123. name,
  1124. desiredReplicas,
  1125. currentReplicas,
  1126. translateTimestamp(ps.CreationTimestamp),
  1127. ); err != nil {
  1128. return err
  1129. }
  1130. if options.Wide {
  1131. if err := layoutContainers(containers, w); err != nil {
  1132. return err
  1133. }
  1134. if _, err := fmt.Fprintf(w, "\t%s", unversioned.FormatLabelSelector(ps.Spec.Selector)); err != nil {
  1135. return err
  1136. }
  1137. }
  1138. if _, err := fmt.Fprint(w, AppendLabels(ps.Labels, options.ColumnLabels)); err != nil {
  1139. return err
  1140. }
  1141. if _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, ps.Labels)); err != nil {
  1142. return err
  1143. }
  1144. return nil
  1145. }
  1146. func printPetSetList(petSetList *apps.PetSetList, w io.Writer, options PrintOptions) error {
  1147. for _, ps := range petSetList.Items {
  1148. if err := printPetSet(&ps, w, options); err != nil {
  1149. return err
  1150. }
  1151. }
  1152. return nil
  1153. }
  1154. func printDaemonSet(ds *extensions.DaemonSet, w io.Writer, options PrintOptions) error {
  1155. name := formatResourceName(options.Kind, ds.Name, options.WithKind)
  1156. namespace := ds.Namespace
  1157. containers := ds.Spec.Template.Spec.Containers
  1158. if options.WithNamespace {
  1159. if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
  1160. return err
  1161. }
  1162. }
  1163. desiredScheduled := ds.Status.DesiredNumberScheduled
  1164. currentScheduled := ds.Status.CurrentNumberScheduled
  1165. selector, err := unversioned.LabelSelectorAsSelector(ds.Spec.Selector)
  1166. if err != nil {
  1167. // this shouldn't happen if LabelSelector passed validation
  1168. return err
  1169. }
  1170. if _, err := fmt.Fprintf(w, "%s\t%d\t%d\t%s\t%s",
  1171. name,
  1172. desiredScheduled,
  1173. currentScheduled,
  1174. labels.FormatLabels(ds.Spec.Template.Spec.NodeSelector),
  1175. translateTimestamp(ds.CreationTimestamp),
  1176. ); err != nil {
  1177. return err
  1178. }
  1179. if options.Wide {
  1180. if err := layoutContainers(containers, w); err != nil {
  1181. return err
  1182. }
  1183. if _, err := fmt.Fprintf(w, "\t%s", selector.String()); err != nil {
  1184. return err
  1185. }
  1186. }
  1187. if _, err := fmt.Fprint(w, AppendLabels(ds.Labels, options.ColumnLabels)); err != nil {
  1188. return err
  1189. }
  1190. if _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, ds.Labels)); err != nil {
  1191. return err
  1192. }
  1193. return nil
  1194. }
  1195. func printDaemonSetList(list *extensions.DaemonSetList, w io.Writer, options PrintOptions) error {
  1196. for _, ds := range list.Items {
  1197. if err := printDaemonSet(&ds, w, options); err != nil {
  1198. return err
  1199. }
  1200. }
  1201. return nil
  1202. }
  1203. func printEndpoints(endpoints *api.Endpoints, w io.Writer, options PrintOptions) error {
  1204. name := formatResourceName(options.Kind, endpoints.Name, options.WithKind)
  1205. namespace := endpoints.Namespace
  1206. if options.WithNamespace {
  1207. if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
  1208. return err
  1209. }
  1210. }
  1211. if _, err := fmt.Fprintf(w, "%s\t%s\t%s", name, formatEndpoints(endpoints, nil), translateTimestamp(endpoints.CreationTimestamp)); err != nil {
  1212. return err
  1213. }
  1214. if _, err := fmt.Fprint(w, AppendLabels(endpoints.Labels, options.ColumnLabels)); err != nil {
  1215. return err
  1216. }
  1217. _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, endpoints.Labels))
  1218. return err
  1219. }
  1220. func printEndpointsList(list *api.EndpointsList, w io.Writer, options PrintOptions) error {
  1221. for _, item := range list.Items {
  1222. if err := printEndpoints(&item, w, options); err != nil {
  1223. return err
  1224. }
  1225. }
  1226. return nil
  1227. }
  1228. func printNamespace(item *api.Namespace, w io.Writer, options PrintOptions) error {
  1229. name := formatResourceName(options.Kind, item.Name, options.WithKind)
  1230. if options.WithNamespace {
  1231. return fmt.Errorf("namespace is not namespaced")
  1232. }
  1233. if _, err := fmt.Fprintf(w, "%s\t%s\t%s", name, item.Status.Phase, translateTimestamp(item.CreationTimestamp)); err != nil {
  1234. return err
  1235. }
  1236. if _, err := fmt.Fprint(w, AppendLabels(item.Labels, options.ColumnLabels)); err != nil {
  1237. return err
  1238. }
  1239. _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, item.Labels))
  1240. return err
  1241. }
  1242. func printNamespaceList(list *api.NamespaceList, w io.Writer, options PrintOptions) error {
  1243. for _, item := range list.Items {
  1244. if err := printNamespace(&item, w, options); err != nil {
  1245. return err
  1246. }
  1247. }
  1248. return nil
  1249. }
  1250. func printSecret(item *api.Secret, w io.Writer, options PrintOptions) error {
  1251. name := formatResourceName(options.Kind, item.Name, options.WithKind)
  1252. namespace := item.Namespace
  1253. if options.WithNamespace {
  1254. if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
  1255. return err
  1256. }
  1257. }
  1258. if _, err := fmt.Fprintf(w, "%s\t%s\t%v\t%s", name, item.Type, len(item.Data), translateTimestamp(item.CreationTimestamp)); err != nil {
  1259. return err
  1260. }
  1261. if _, err := fmt.Fprint(w, AppendLabels(item.Labels, options.ColumnLabels)); err != nil {
  1262. return err
  1263. }
  1264. _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, item.Labels))
  1265. return err
  1266. }
  1267. func printSecretList(list *api.SecretList, w io.Writer, options PrintOptions) error {
  1268. for _, item := range list.Items {
  1269. if err := printSecret(&item, w, options); err != nil {
  1270. return err
  1271. }
  1272. }
  1273. return nil
  1274. }
  1275. func printServiceAccount(item *api.ServiceAccount, w io.Writer, options PrintOptions) error {
  1276. name := formatResourceName(options.Kind, item.Name, options.WithKind)
  1277. namespace := item.Namespace
  1278. if options.WithNamespace {
  1279. if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
  1280. return err
  1281. }
  1282. }
  1283. if _, err := fmt.Fprintf(w, "%s\t%d\t%s", name, len(item.Secrets), translateTimestamp(item.CreationTimestamp)); err != nil {
  1284. return err
  1285. }
  1286. if _, err := fmt.Fprint(w, AppendLabels(item.Labels, options.ColumnLabels)); err != nil {
  1287. return err
  1288. }
  1289. _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, item.Labels))
  1290. return err
  1291. }
  1292. func printServiceAccountList(list *api.ServiceAccountList, w io.Writer, options PrintOptions) error {
  1293. for _, item := range list.Items {
  1294. if err := printServiceAccount(&item, w, options); err != nil {
  1295. return err
  1296. }
  1297. }
  1298. return nil
  1299. }
  1300. func printNode(node *api.Node, w io.Writer, options PrintOptions) error {
  1301. name := formatResourceName(options.Kind, node.Name, options.WithKind)
  1302. if options.WithNamespace {
  1303. return fmt.Errorf("node is not namespaced")
  1304. }
  1305. conditionMap := make(map[api.NodeConditionType]*api.NodeCondition)
  1306. NodeAllConditions := []api.NodeConditionType{api.NodeReady}
  1307. for i := range node.Status.Conditions {
  1308. cond := node.Status.Conditions[i]
  1309. conditionMap[cond.Type] = &cond
  1310. }
  1311. var status []string
  1312. for _, validCondition := range NodeAllConditions {
  1313. if condition, ok := conditionMap[validCondition]; ok {
  1314. if condition.Status == api.ConditionTrue {
  1315. status = append(status, string(condition.Type))
  1316. } else {
  1317. status = append(status, "Not"+string(condition.Type))
  1318. }
  1319. }
  1320. }
  1321. if len(status) == 0 {
  1322. status = append(status, "Unknown")
  1323. }
  1324. if node.Spec.Unschedulable {
  1325. status = append(status, "SchedulingDisabled")
  1326. }
  1327. if _, err := fmt.Fprintf(w, "%s\t%s\t%s", name, strings.Join(status, ","), translateTimestamp(node.CreationTimestamp)); err != nil {
  1328. return err
  1329. }
  1330. // Display caller specify column labels first.
  1331. if _, err := fmt.Fprint(w, AppendLabels(node.Labels, options.ColumnLabels)); err != nil {
  1332. return err
  1333. }
  1334. _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, node.Labels))
  1335. return err
  1336. }
  1337. func printNodeList(list *api.NodeList, w io.Writer, options PrintOptions) error {
  1338. for _, node := range list.Items {
  1339. if err := printNode(&node, w, options); err != nil {
  1340. return err
  1341. }
  1342. }
  1343. return nil
  1344. }
  1345. func printPersistentVolume(pv *api.PersistentVolume, w io.Writer, options PrintOptions) error {
  1346. name := formatResourceName(options.Kind, pv.Name, options.WithKind)
  1347. if options.WithNamespace {
  1348. return fmt.Errorf("persistentVolume is not namespaced")
  1349. }
  1350. claimRefUID := ""
  1351. if pv.Spec.ClaimRef != nil {
  1352. claimRefUID += pv.Spec.ClaimRef.Namespace
  1353. claimRefUID += "/"
  1354. claimRefUID += pv.Spec.ClaimRef.Name
  1355. }
  1356. modesStr := api.GetAccessModesAsString(pv.Spec.AccessModes)
  1357. reclaimPolicyStr := string(pv.Spec.PersistentVolumeReclaimPolicy)
  1358. aQty := pv.Spec.Capacity[api.ResourceStorage]
  1359. aSize := aQty.String()
  1360. if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s",
  1361. name,
  1362. aSize, modesStr, reclaimPolicyStr,
  1363. pv.Status.Phase,
  1364. claimRefUID,
  1365. pv.Status.Reason,
  1366. translateTimestamp(pv.CreationTimestamp),
  1367. ); err != nil {
  1368. return err
  1369. }
  1370. if _, err := fmt.Fprint(w, AppendLabels(pv.Labels, options.ColumnLabels)); err != nil {
  1371. return err
  1372. }
  1373. _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, pv.Labels))
  1374. return err
  1375. }
  1376. func printPersistentVolumeList(list *api.PersistentVolumeList, w io.Writer, options PrintOptions) error {
  1377. for _, pv := range list.Items {
  1378. if err := printPersistentVolume(&pv, w, options); err != nil {
  1379. return err
  1380. }
  1381. }
  1382. return nil
  1383. }
  1384. func printPersistentVolumeClaim(pvc *api.PersistentVolumeClaim, w io.Writer, options PrintOptions) error {
  1385. name := formatResourceName(options.Kind, pvc.Name, options.WithKind)
  1386. namespace := pvc.Namespace
  1387. if options.WithNamespace {
  1388. if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
  1389. return err
  1390. }
  1391. }
  1392. phase := pvc.Status.Phase
  1393. storage := pvc.Spec.Resources.Requests[api.ResourceStorage]
  1394. capacity := ""
  1395. accessModes := ""
  1396. if pvc.Spec.VolumeName != "" {
  1397. accessModes = api.GetAccessModesAsString(pvc.Status.AccessModes)
  1398. storage = pvc.Status.Capacity[api.ResourceStorage]
  1399. capacity = storage.String()
  1400. }
  1401. if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s", name, phase, pvc.Spec.VolumeName, capacity, accessModes, translateTimestamp(pvc.CreationTimestamp)); err != nil {
  1402. return err
  1403. }
  1404. if _, err := fmt.Fprint(w, AppendLabels(pvc.Labels, options.ColumnLabels)); err != nil {
  1405. return err
  1406. }
  1407. _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, pvc.Labels))
  1408. return err
  1409. }
  1410. func printPersistentVolumeClaimList(list *api.PersistentVolumeClaimList, w io.Writer, options PrintOptions) error {
  1411. for _, psd := range list.Items {
  1412. if err := printPersistentVolumeClaim(&psd, w, options); err != nil {
  1413. return err
  1414. }
  1415. }
  1416. return nil
  1417. }
  1418. func printEvent(event *api.Event, w io.Writer, options PrintOptions) error {
  1419. name := formatResourceName(options.Kind, event.InvolvedObject.Name, options.WithKind)
  1420. namespace := event.Namespace
  1421. if options.WithNamespace {
  1422. if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
  1423. return err
  1424. }
  1425. }
  1426. // While watching event, we should print absolute time.
  1427. var FirstTimestamp, LastTimestamp string
  1428. if options.AbsoluteTimestamps {
  1429. FirstTimestamp = event.FirstTimestamp.String()
  1430. LastTimestamp = event.LastTimestamp.String()
  1431. } else {
  1432. FirstTimestamp = translateTimestamp(event.FirstTimestamp)
  1433. LastTimestamp = translateTimestamp(event.LastTimestamp)
  1434. }
  1435. if _, err := fmt.Fprintf(
  1436. w, "%s\t%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\t%s",
  1437. LastTimestamp,
  1438. FirstTimestamp,
  1439. event.Count,
  1440. name,
  1441. event.InvolvedObject.Kind,
  1442. event.InvolvedObject.FieldPath,
  1443. event.Type,
  1444. event.Reason,
  1445. event.Source,
  1446. event.Message,
  1447. ); err != nil {
  1448. return err
  1449. }
  1450. if _, err := fmt.Fprint(w, AppendLabels(event.Labels, options.ColumnLabels)); err != nil {
  1451. return err
  1452. }
  1453. _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, event.Labels))
  1454. return err
  1455. }
  1456. // Sorts and prints the EventList in a human-friendly format.
  1457. func printEventList(list *api.EventList, w io.Writer, options PrintOptions) error {
  1458. sort.Sort(SortableEvents(list.Items))
  1459. for i := range list.Items {
  1460. if err := printEvent(&list.Items[i], w, options); err != nil {
  1461. return err
  1462. }
  1463. }
  1464. return nil
  1465. }
  1466. func printLimitRange(limitRange *api.LimitRange, w io.Writer, options PrintOptions) error {
  1467. return printObjectMeta(limitRange.ObjectMeta, w, options, true)
  1468. }
  1469. // Prints the LimitRangeList in a human-friendly format.
  1470. func printLimitRangeList(list *api.LimitRangeList, w io.Writer, options PrintOptions) error {
  1471. for i := range list.Items {
  1472. if err := printLimitRange(&list.Items[i], w, options); err != nil {
  1473. return err
  1474. }
  1475. }
  1476. return nil
  1477. }
  1478. // printObjectMeta prints the object metadata of a given resource.
  1479. func printObjectMeta(meta api.ObjectMeta, w io.Writer, options PrintOptions, namespaced bool) error {
  1480. name := formatResourceName(options.Kind, meta.Name, options.WithKind)
  1481. if namespaced && options.WithNamespace {
  1482. if _, err := fmt.Fprintf(w, "%s\t", meta.Namespace); err != nil {
  1483. return err
  1484. }
  1485. }
  1486. if _, err := fmt.Fprintf(
  1487. w, "%s\t%s",
  1488. name,
  1489. translateTimestamp(meta.CreationTimestamp),
  1490. ); err != nil {
  1491. return err
  1492. }
  1493. if _, err := fmt.Fprint(w, AppendLabels(meta.Labels, options.ColumnLabels)); err != nil {
  1494. return err
  1495. }
  1496. _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, meta.Labels))
  1497. return err
  1498. }
  1499. func printResourceQuota(resourceQuota *api.ResourceQuota, w io.Writer, options PrintOptions) error {
  1500. return printObjectMeta(resourceQuota.ObjectMeta, w, options, true)
  1501. }
  1502. // Prints the ResourceQuotaList in a human-friendly format.
  1503. func printResourceQuotaList(list *api.ResourceQuotaList, w io.Writer, options PrintOptions) error {
  1504. for i := range list.Items {
  1505. if err := printResourceQuota(&list.Items[i], w, options); err != nil {
  1506. return err
  1507. }
  1508. }
  1509. return nil
  1510. }
  1511. func printRole(role *rbac.Role, w io.Writer, options PrintOptions) error {
  1512. return printObjectMeta(role.ObjectMeta, w, options, true)
  1513. }
  1514. // Prints the Role in a human-friendly format.
  1515. func printRoleList(list *rbac.RoleList, w io.Writer, options PrintOptions) error {
  1516. for i := range list.Items {
  1517. if err := printRole(&list.Items[i], w, options); err != nil {
  1518. return err
  1519. }
  1520. }
  1521. return nil
  1522. }
  1523. func printRoleBinding(roleBinding *rbac.RoleBinding, w io.Writer, options PrintOptions) error {
  1524. return printObjectMeta(roleBinding.ObjectMeta, w, options, true)
  1525. }
  1526. // Prints the RoleBinding in a human-friendly format.
  1527. func printRoleBindingList(list *rbac.RoleBindingList, w io.Writer, options PrintOptions) error {
  1528. for i := range list.Items {
  1529. if err := printRoleBinding(&list.Items[i], w, options); err != nil {
  1530. return err
  1531. }
  1532. }
  1533. return nil
  1534. }
  1535. func printClusterRole(clusterRole *rbac.ClusterRole, w io.Writer, options PrintOptions) error {
  1536. return printObjectMeta(clusterRole.ObjectMeta, w, options, false)
  1537. }
  1538. // Prints the ClusterRole in a human-friendly format.
  1539. func printClusterRoleList(list *rbac.ClusterRoleList, w io.Writer, options PrintOptions) error {
  1540. for i := range list.Items {
  1541. if err := printClusterRole(&list.Items[i], w, options); err != nil {
  1542. return err
  1543. }
  1544. }
  1545. return nil
  1546. }
  1547. func printClusterRoleBinding(clusterRoleBinding *rbac.ClusterRoleBinding, w io.Writer, options PrintOptions) error {
  1548. return printObjectMeta(clusterRoleBinding.ObjectMeta, w, options, false)
  1549. }
  1550. // Prints the ClusterRoleBinding in a human-friendly format.
  1551. func printClusterRoleBindingList(list *rbac.ClusterRoleBindingList, w io.Writer, options PrintOptions) error {
  1552. for i := range list.Items {
  1553. if err := printClusterRoleBinding(&list.Items[i], w, options); err != nil {
  1554. return err
  1555. }
  1556. }
  1557. return nil
  1558. }
  1559. func printCertificateSigningRequest(csr *certificates.CertificateSigningRequest, w io.Writer, options PrintOptions) error {
  1560. name := formatResourceName(options.Kind, csr.Name, options.WithKind)
  1561. meta := csr.ObjectMeta
  1562. status, err := extractCSRStatus(csr)
  1563. if err != nil {
  1564. return err
  1565. }
  1566. if _, err := fmt.Fprintf(
  1567. w, "%s\t%s\t%s\t%s",
  1568. name,
  1569. translateTimestamp(meta.CreationTimestamp),
  1570. csr.Spec.Username,
  1571. status,
  1572. ); err != nil {
  1573. return err
  1574. }
  1575. if _, err := fmt.Fprint(w, AppendLabels(meta.Labels, options.ColumnLabels)); err != nil {
  1576. return err
  1577. }
  1578. _, err = fmt.Fprint(w, AppendAllLabels(options.ShowLabels, meta.Labels))
  1579. return err
  1580. }
  1581. func extractCSRStatus(csr *certificates.CertificateSigningRequest) (string, error) {
  1582. var approved, denied bool
  1583. for _, c := range csr.Status.Conditions {
  1584. switch c.Type {
  1585. case certificates.CertificateApproved:
  1586. approved = true
  1587. case certificates.CertificateDenied:
  1588. denied = true
  1589. default:
  1590. return "", fmt.Errorf("unknown csr conditon %q", c)
  1591. }
  1592. }
  1593. var status string
  1594. // must be in order of presidence
  1595. if denied {
  1596. status += "Denied"
  1597. } else if approved {
  1598. status += "Approved"
  1599. } else {
  1600. status += "Pending"
  1601. }
  1602. if len(csr.Status.Certificate) > 0 {
  1603. status += ",Issued"
  1604. }
  1605. return status, nil
  1606. }
  1607. func printCertificateSigningRequestList(list *certificates.CertificateSigningRequestList, w io.Writer, options PrintOptions) error {
  1608. for i := range list.Items {
  1609. if err := printCertificateSigningRequest(&list.Items[i], w, options); err != nil {
  1610. return err
  1611. }
  1612. }
  1613. return nil
  1614. }
  1615. func printComponentStatus(item *api.ComponentStatus, w io.Writer, options PrintOptions) error {
  1616. name := formatResourceName(options.Kind, item.Name, options.WithKind)
  1617. if options.WithNamespace {
  1618. return fmt.Errorf("componentStatus is not namespaced")
  1619. }
  1620. status := "Unknown"
  1621. message := ""
  1622. error := ""
  1623. for _, condition := range item.Conditions {
  1624. if condition.Type == api.ComponentHealthy {
  1625. if condition.Status == api.ConditionTrue {
  1626. status = "Healthy"
  1627. } else {
  1628. status = "Unhealthy"
  1629. }
  1630. message = condition.Message
  1631. error = condition.Error
  1632. break
  1633. }
  1634. }
  1635. if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s", name, status, message, error); err != nil {
  1636. return err
  1637. }
  1638. if _, err := fmt.Fprint(w, AppendLabels(item.Labels, options.ColumnLabels)); err != nil {
  1639. return err
  1640. }
  1641. _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, item.Labels))
  1642. return err
  1643. }
  1644. func printComponentStatusList(list *api.ComponentStatusList, w io.Writer, options PrintOptions) error {
  1645. for _, item := range list.Items {
  1646. if err := printComponentStatus(&item, w, options); err != nil {
  1647. return err
  1648. }
  1649. }
  1650. return nil
  1651. }
  1652. func printThirdPartyResource(rsrc *extensions.ThirdPartyResource, w io.Writer, options PrintOptions) error {
  1653. name := formatResourceName(options.Kind, rsrc.Name, options.WithKind)
  1654. versions := make([]string, len(rsrc.Versions))
  1655. for ix := range rsrc.Versions {
  1656. version := &rsrc.Versions[ix]
  1657. versions[ix] = fmt.Sprintf("%s", version.Name)
  1658. }
  1659. versionsString := strings.Join(versions, ",")
  1660. if _, err := fmt.Fprintf(w, "%s\t%s\t%s\n", name, rsrc.Description, versionsString); err != nil {
  1661. return err
  1662. }
  1663. return nil
  1664. }
  1665. func printThirdPartyResourceList(list *extensions.ThirdPartyResourceList, w io.Writer, options PrintOptions) error {
  1666. for _, item := range list.Items {
  1667. if err := printThirdPartyResource(&item, w, options); err != nil {
  1668. return err
  1669. }
  1670. }
  1671. return nil
  1672. }
  1673. func truncate(str string, maxLen int) string {
  1674. if len(str) > maxLen {
  1675. return str[0:maxLen] + "..."
  1676. }
  1677. return str
  1678. }
  1679. func printThirdPartyResourceData(rsrc *extensions.ThirdPartyResourceData, w io.Writer, options PrintOptions) error {
  1680. name := formatResourceName(options.Kind, rsrc.Name, options.WithKind)
  1681. l := labels.FormatLabels(rsrc.Labels)
  1682. truncateCols := 50
  1683. if options.Wide {
  1684. truncateCols = 100
  1685. }
  1686. if _, err := fmt.Fprintf(w, "%s\t%s\t%s\n", name, l, truncate(string(rsrc.Data), truncateCols)); err != nil {
  1687. return err
  1688. }
  1689. return nil
  1690. }
  1691. func printThirdPartyResourceDataList(list *extensions.ThirdPartyResourceDataList, w io.Writer, options PrintOptions) error {
  1692. for _, item := range list.Items {
  1693. if err := printThirdPartyResourceData(&item, w, options); err != nil {
  1694. return err
  1695. }
  1696. }
  1697. return nil
  1698. }
  1699. func printDeployment(deployment *extensions.Deployment, w io.Writer, options PrintOptions) error {
  1700. name := formatResourceName(options.Kind, deployment.Name, options.WithKind)
  1701. if options.WithNamespace {
  1702. if _, err := fmt.Fprintf(w, "%s\t", deployment.Namespace); err != nil {
  1703. return err
  1704. }
  1705. }
  1706. desiredReplicas := deployment.Spec.Replicas
  1707. currentReplicas := deployment.Status.Replicas
  1708. updatedReplicas := deployment.Status.UpdatedReplicas
  1709. availableReplicas := deployment.Status.AvailableReplicas
  1710. age := translateTimestamp(deployment.CreationTimestamp)
  1711. if _, err := fmt.Fprintf(w, "%s\t%d\t%d\t%d\t%d\t%s", name, desiredReplicas, currentReplicas, updatedReplicas, availableReplicas, age); err != nil {
  1712. return err
  1713. }
  1714. if _, err := fmt.Fprint(w, AppendLabels(deployment.Labels, options.ColumnLabels)); err != nil {
  1715. return err
  1716. }
  1717. _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, deployment.Labels))
  1718. return err
  1719. }
  1720. func printDeploymentList(list *extensions.DeploymentList, w io.Writer, options PrintOptions) error {
  1721. for _, item := range list.Items {
  1722. if err := printDeployment(&item, w, options); err != nil {
  1723. return err
  1724. }
  1725. }
  1726. return nil
  1727. }
  1728. func printHorizontalPodAutoscaler(hpa *autoscaling.HorizontalPodAutoscaler, w io.Writer, options PrintOptions) error {
  1729. namespace := hpa.Namespace
  1730. name := formatResourceName(options.Kind, hpa.Name, options.WithKind)
  1731. reference := fmt.Sprintf("%s/%s",
  1732. hpa.Spec.ScaleTargetRef.Kind,
  1733. hpa.Spec.ScaleTargetRef.Name)
  1734. target := "<unset>"
  1735. if hpa.Spec.TargetCPUUtilizationPercentage != nil {
  1736. target = fmt.Sprintf("%d%%", *hpa.Spec.TargetCPUUtilizationPercentage)
  1737. }
  1738. current := "<waiting>"
  1739. if hpa.Status.CurrentCPUUtilizationPercentage != nil {
  1740. current = fmt.Sprintf("%d%%", *hpa.Status.CurrentCPUUtilizationPercentage)
  1741. }
  1742. minPods := "<unset>"
  1743. if hpa.Spec.MinReplicas != nil {
  1744. minPods = fmt.Sprintf("%d", *hpa.Spec.MinReplicas)
  1745. }
  1746. maxPods := hpa.Spec.MaxReplicas
  1747. if options.WithNamespace {
  1748. if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
  1749. return err
  1750. }
  1751. }
  1752. if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%d\t%s",
  1753. name,
  1754. reference,
  1755. target,
  1756. current,
  1757. minPods,
  1758. maxPods,
  1759. translateTimestamp(hpa.CreationTimestamp),
  1760. ); err != nil {
  1761. return err
  1762. }
  1763. if _, err := fmt.Fprint(w, AppendLabels(hpa.Labels, options.ColumnLabels)); err != nil {
  1764. return err
  1765. }
  1766. _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, hpa.Labels))
  1767. return err
  1768. }
  1769. func printHorizontalPodAutoscalerList(list *autoscaling.HorizontalPodAutoscalerList, w io.Writer, options PrintOptions) error {
  1770. for i := range list.Items {
  1771. if err := printHorizontalPodAutoscaler(&list.Items[i], w, options); err != nil {
  1772. return err
  1773. }
  1774. }
  1775. return nil
  1776. }
  1777. func printConfigMap(configMap *api.ConfigMap, w io.Writer, options PrintOptions) error {
  1778. name := formatResourceName(options.Kind, configMap.Name, options.WithKind)
  1779. namespace := configMap.Namespace
  1780. if options.WithNamespace {
  1781. if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
  1782. return err
  1783. }
  1784. }
  1785. if _, err := fmt.Fprintf(w, "%s\t%v\t%s", name, len(configMap.Data), translateTimestamp(configMap.CreationTimestamp)); err != nil {
  1786. return err
  1787. }
  1788. if _, err := fmt.Fprint(w, AppendLabels(configMap.Labels, options.ColumnLabels)); err != nil {
  1789. return err
  1790. }
  1791. _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, configMap.Labels))
  1792. return err
  1793. }
  1794. func printConfigMapList(list *api.ConfigMapList, w io.Writer, options PrintOptions) error {
  1795. for i := range list.Items {
  1796. if err := printConfigMap(&list.Items[i], w, options); err != nil {
  1797. return err
  1798. }
  1799. }
  1800. return nil
  1801. }
  1802. func printPodSecurityPolicy(item *extensions.PodSecurityPolicy, w io.Writer, options PrintOptions) error {
  1803. name := formatResourceName(options.Kind, item.Name, options.WithKind)
  1804. _, err := fmt.Fprintf(w, "%s\t%t\t%v\t%s\t%s\t%s\t%s\t%t\t%v\n", name, item.Spec.Privileged,
  1805. item.Spec.AllowedCapabilities, item.Spec.SELinux.Rule,
  1806. item.Spec.RunAsUser.Rule, item.Spec.FSGroup.Rule, item.Spec.SupplementalGroups.Rule, item.Spec.ReadOnlyRootFilesystem, item.Spec.Volumes)
  1807. return err
  1808. }
  1809. func printPodSecurityPolicyList(list *extensions.PodSecurityPolicyList, w io.Writer, options PrintOptions) error {
  1810. for _, item := range list.Items {
  1811. if err := printPodSecurityPolicy(&item, w, options); err != nil {
  1812. return err
  1813. }
  1814. }
  1815. return nil
  1816. }
  1817. func printNetworkPolicy(networkPolicy *extensions.NetworkPolicy, w io.Writer, options PrintOptions) error {
  1818. name := formatResourceName(options.Kind, networkPolicy.Name, options.WithKind)
  1819. namespace := networkPolicy.Namespace
  1820. if options.WithNamespace {
  1821. if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
  1822. return err
  1823. }
  1824. }
  1825. if _, err := fmt.Fprintf(w, "%s\t%v\t%s", name, unversioned.FormatLabelSelector(&networkPolicy.Spec.PodSelector), translateTimestamp(networkPolicy.CreationTimestamp)); err != nil {
  1826. return err
  1827. }
  1828. if _, err := fmt.Fprint(w, AppendLabels(networkPolicy.Labels, options.ColumnLabels)); err != nil {
  1829. return err
  1830. }
  1831. _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, networkPolicy.Labels))
  1832. return err
  1833. }
  1834. func printNetworkPolicyList(list *extensions.NetworkPolicyList, w io.Writer, options PrintOptions) error {
  1835. for i := range list.Items {
  1836. if err := printNetworkPolicy(&list.Items[i], w, options); err != nil {
  1837. return err
  1838. }
  1839. }
  1840. return nil
  1841. }
  1842. func printStorageClass(sc *extensions.StorageClass, w io.Writer, options PrintOptions) error {
  1843. name := sc.Name
  1844. provtype := sc.Provisioner
  1845. if _, err := fmt.Fprintf(w, "%s\t%s\t", name, provtype); err != nil {
  1846. return err
  1847. }
  1848. if _, err := fmt.Fprint(w, AppendLabels(sc.Labels, options.ColumnLabels)); err != nil {
  1849. return err
  1850. }
  1851. if _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, sc.Labels)); err != nil {
  1852. return err
  1853. }
  1854. return nil
  1855. }
  1856. func printStorageClassList(scList *extensions.StorageClassList, w io.Writer, options PrintOptions) error {
  1857. for _, sc := range scList.Items {
  1858. if err := printStorageClass(&sc, w, options); err != nil {
  1859. return err
  1860. }
  1861. }
  1862. return nil
  1863. }
  1864. func AppendLabels(itemLabels map[string]string, columnLabels []string) string {
  1865. var buffer bytes.Buffer
  1866. for _, cl := range columnLabels {
  1867. buffer.WriteString(fmt.Sprint("\t"))
  1868. if il, ok := itemLabels[cl]; ok {
  1869. buffer.WriteString(fmt.Sprint(il))
  1870. } else {
  1871. buffer.WriteString("<none>")
  1872. }
  1873. }
  1874. return buffer.String()
  1875. }
  1876. // Append all labels to a single column. We need this even when show-labels flag* is
  1877. // false, since this adds newline delimiter to the end of each row.
  1878. func AppendAllLabels(showLabels bool, itemLabels map[string]string) string {
  1879. var buffer bytes.Buffer
  1880. if showLabels {
  1881. buffer.WriteString(fmt.Sprint("\t"))
  1882. buffer.WriteString(labels.FormatLabels(itemLabels))
  1883. }
  1884. buffer.WriteString("\n")
  1885. return buffer.String()
  1886. }
  1887. // Append a set of tabs for each label column. We need this in the case where
  1888. // we have extra lines so that the tabwriter will still line things up.
  1889. func AppendLabelTabs(columnLabels []string) string {
  1890. var buffer bytes.Buffer
  1891. for range columnLabels {
  1892. buffer.WriteString("\t")
  1893. }
  1894. buffer.WriteString("\n")
  1895. return buffer.String()
  1896. }
  1897. // Lay out all the containers on one line if use wide output.
  1898. func layoutContainers(containers []api.Container, w io.Writer) error {
  1899. var namesBuffer bytes.Buffer
  1900. var imagesBuffer bytes.Buffer
  1901. for i, container := range containers {
  1902. namesBuffer.WriteString(container.Name)
  1903. imagesBuffer.WriteString(container.Image)
  1904. if i != len(containers)-1 {
  1905. namesBuffer.WriteString(",")
  1906. imagesBuffer.WriteString(",")
  1907. }
  1908. }
  1909. _, err := fmt.Fprintf(w, "\t%s\t%s", namesBuffer.String(), imagesBuffer.String())
  1910. if err != nil {
  1911. return err
  1912. }
  1913. return nil
  1914. }
  1915. func formatLabelHeaders(columnLabels []string) []string {
  1916. formHead := make([]string, len(columnLabels))
  1917. for i, l := range columnLabels {
  1918. p := strings.Split(l, "/")
  1919. formHead[i] = strings.ToUpper((p[len(p)-1]))
  1920. }
  1921. return formHead
  1922. }
  1923. // headers for -o wide
  1924. func formatWideHeaders(wide bool, t reflect.Type) []string {
  1925. if wide {
  1926. if t.String() == "*api.Pod" || t.String() == "*api.PodList" {
  1927. return []string{"IP", "NODE"}
  1928. }
  1929. if t.String() == "*api.ReplicationController" || t.String() == "*api.ReplicationControllerList" {
  1930. return []string{"CONTAINER(S)", "IMAGE(S)", "SELECTOR"}
  1931. }
  1932. if t.String() == "*batch.Job" || t.String() == "*batch.JobList" {
  1933. return []string{"CONTAINER(S)", "IMAGE(S)", "SELECTOR"}
  1934. }
  1935. if t.String() == "*api.Service" || t.String() == "*api.ServiceList" {
  1936. return []string{"SELECTOR"}
  1937. }
  1938. if t.String() == "*extensions.DaemonSet" || t.String() == "*extensions.DaemonSetList" {
  1939. return []string{"CONTAINER(S)", "IMAGE(S)", "SELECTOR"}
  1940. }
  1941. if t.String() == "*extensions.ReplicaSet" || t.String() == "*extensions.ReplicaSetList" {
  1942. return []string{"CONTAINER(S)", "IMAGE(S)", "SELECTOR"}
  1943. }
  1944. }
  1945. return nil
  1946. }
  1947. // headers for --show-labels=true
  1948. func formatShowLabelsHeader(showLabels bool, t reflect.Type) []string {
  1949. if showLabels {
  1950. if t.String() != "*api.ThirdPartyResource" && t.String() != "*api.ThirdPartyResourceList" {
  1951. return []string{"LABELS"}
  1952. }
  1953. }
  1954. return nil
  1955. }
  1956. // GetNewTabWriter returns a tabwriter that translates tabbed columns in input into properly aligned text.
  1957. func GetNewTabWriter(output io.Writer) *tabwriter.Writer {
  1958. return tabwriter.NewWriter(output, tabwriterMinWidth, tabwriterWidth, tabwriterPadding, tabwriterPadChar, tabwriterFlags)
  1959. }
  1960. // PrintObj prints the obj in a human-friendly format according to the type of the obj.
  1961. func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) error {
  1962. // if output is a tabwriter (when it's called by kubectl get), we use it; create a new tabwriter otherwise
  1963. w, found := output.(*tabwriter.Writer)
  1964. if !found {
  1965. w = GetNewTabWriter(output)
  1966. defer w.Flush()
  1967. }
  1968. t := reflect.TypeOf(obj)
  1969. if handler := h.handlerMap[t]; handler != nil {
  1970. if !h.options.NoHeaders && t != h.lastType {
  1971. headers := append(handler.columns, formatWideHeaders(h.options.Wide, t)...)
  1972. headers = append(headers, formatLabelHeaders(h.options.ColumnLabels)...)
  1973. // LABELS is always the last column.
  1974. headers = append(headers, formatShowLabelsHeader(h.options.ShowLabels, t)...)
  1975. if h.options.WithNamespace {
  1976. headers = append(withNamespacePrefixColumns, headers...)
  1977. }
  1978. h.printHeader(headers, w)
  1979. h.lastType = t
  1980. }
  1981. args := []reflect.Value{reflect.ValueOf(obj), reflect.ValueOf(w), reflect.ValueOf(h.options)}
  1982. resultValue := handler.printFunc.Call(args)[0]
  1983. if resultValue.IsNil() {
  1984. return nil
  1985. }
  1986. return resultValue.Interface().(error)
  1987. }
  1988. return fmt.Errorf("error: unknown type %#v", obj)
  1989. }
  1990. // TemplatePrinter is an implementation of ResourcePrinter which formats data with a Go Template.
  1991. type TemplatePrinter struct {
  1992. rawTemplate string
  1993. template *template.Template
  1994. }
  1995. func NewTemplatePrinter(tmpl []byte) (*TemplatePrinter, error) {
  1996. t, err := template.New("output").
  1997. Funcs(template.FuncMap{"exists": exists}).
  1998. Parse(string(tmpl))
  1999. if err != nil {
  2000. return nil, err
  2001. }
  2002. return &TemplatePrinter{
  2003. rawTemplate: string(tmpl),
  2004. template: t,
  2005. }, nil
  2006. }
  2007. func (p *TemplatePrinter) FinishPrint(w io.Writer, res string) error {
  2008. return nil
  2009. }
  2010. // PrintObj formats the obj with the Go Template.
  2011. func (p *TemplatePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
  2012. data, err := json.Marshal(obj)
  2013. if err != nil {
  2014. return err
  2015. }
  2016. out := map[string]interface{}{}
  2017. if err := json.Unmarshal(data, &out); err != nil {
  2018. return err
  2019. }
  2020. if err = p.safeExecute(w, out); err != nil {
  2021. // It is way easier to debug this stuff when it shows up in
  2022. // stdout instead of just stdin. So in addition to returning
  2023. // a nice error, also print useful stuff with the writer.
  2024. fmt.Fprintf(w, "Error executing template: %v. Printing more information for debugging the template:\n", err)
  2025. fmt.Fprintf(w, "\ttemplate was:\n\t\t%v\n", p.rawTemplate)
  2026. fmt.Fprintf(w, "\traw data was:\n\t\t%v\n", string(data))
  2027. fmt.Fprintf(w, "\tobject given to template engine was:\n\t\t%+v\n\n", out)
  2028. return fmt.Errorf("error executing template %q: %v", p.rawTemplate, err)
  2029. }
  2030. return nil
  2031. }
  2032. // TODO: implement HandledResources()
  2033. func (p *TemplatePrinter) HandledResources() []string {
  2034. return []string{}
  2035. }
  2036. // safeExecute tries to execute the template, but catches panics and returns an error
  2037. // should the template engine panic.
  2038. func (p *TemplatePrinter) safeExecute(w io.Writer, obj interface{}) error {
  2039. var panicErr error
  2040. // Sorry for the double anonymous function. There's probably a clever way
  2041. // to do this that has the defer'd func setting the value to be returned, but
  2042. // that would be even less obvious.
  2043. retErr := func() error {
  2044. defer func() {
  2045. if x := recover(); x != nil {
  2046. panicErr = fmt.Errorf("caught panic: %+v", x)
  2047. }
  2048. }()
  2049. return p.template.Execute(w, obj)
  2050. }()
  2051. if panicErr != nil {
  2052. return panicErr
  2053. }
  2054. return retErr
  2055. }
  2056. func tabbedString(f func(io.Writer) error) (string, error) {
  2057. out := new(tabwriter.Writer)
  2058. buf := &bytes.Buffer{}
  2059. out.Init(buf, 0, 8, 1, '\t', 0)
  2060. err := f(out)
  2061. if err != nil {
  2062. return "", err
  2063. }
  2064. out.Flush()
  2065. str := string(buf.String())
  2066. return str, nil
  2067. }
  2068. // exists returns true if it would be possible to call the index function
  2069. // with these arguments.
  2070. //
  2071. // TODO: how to document this for users?
  2072. //
  2073. // index returns the result of indexing its first argument by the following
  2074. // arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each
  2075. // indexed item must be a map, slice, or array.
  2076. func exists(item interface{}, indices ...interface{}) bool {
  2077. v := reflect.ValueOf(item)
  2078. for _, i := range indices {
  2079. index := reflect.ValueOf(i)
  2080. var isNil bool
  2081. if v, isNil = indirect(v); isNil {
  2082. return false
  2083. }
  2084. switch v.Kind() {
  2085. case reflect.Array, reflect.Slice, reflect.String:
  2086. var x int64
  2087. switch index.Kind() {
  2088. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  2089. x = index.Int()
  2090. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  2091. x = int64(index.Uint())
  2092. default:
  2093. return false
  2094. }
  2095. if x < 0 || x >= int64(v.Len()) {
  2096. return false
  2097. }
  2098. v = v.Index(int(x))
  2099. case reflect.Map:
  2100. if !index.IsValid() {
  2101. index = reflect.Zero(v.Type().Key())
  2102. }
  2103. if !index.Type().AssignableTo(v.Type().Key()) {
  2104. return false
  2105. }
  2106. if x := v.MapIndex(index); x.IsValid() {
  2107. v = x
  2108. } else {
  2109. v = reflect.Zero(v.Type().Elem())
  2110. }
  2111. default:
  2112. return false
  2113. }
  2114. }
  2115. if _, isNil := indirect(v); isNil {
  2116. return false
  2117. }
  2118. return true
  2119. }
  2120. // stolen from text/template
  2121. // indirect returns the item at the end of indirection, and a bool to indicate if it's nil.
  2122. // We indirect through pointers and empty interfaces (only) because
  2123. // non-empty interfaces have methods we might need.
  2124. func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
  2125. for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
  2126. if v.IsNil() {
  2127. return v, true
  2128. }
  2129. if v.Kind() == reflect.Interface && v.NumMethod() > 0 {
  2130. break
  2131. }
  2132. }
  2133. return v, false
  2134. }
  2135. // JSONPathPrinter is an implementation of ResourcePrinter which formats data with jsonpath expression.
  2136. type JSONPathPrinter struct {
  2137. rawTemplate string
  2138. *jsonpath.JSONPath
  2139. }
  2140. func NewJSONPathPrinter(tmpl string) (*JSONPathPrinter, error) {
  2141. j := jsonpath.New("out")
  2142. if err := j.Parse(tmpl); err != nil {
  2143. return nil, err
  2144. }
  2145. return &JSONPathPrinter{tmpl, j}, nil
  2146. }
  2147. func (j *JSONPathPrinter) FinishPrint(w io.Writer, res string) error {
  2148. return nil
  2149. }
  2150. // PrintObj formats the obj with the JSONPath Template.
  2151. func (j *JSONPathPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
  2152. var queryObj interface{} = obj
  2153. if meta.IsListType(obj) {
  2154. data, err := json.Marshal(obj)
  2155. if err != nil {
  2156. return err
  2157. }
  2158. queryObj = map[string]interface{}{}
  2159. if err := json.Unmarshal(data, &queryObj); err != nil {
  2160. return err
  2161. }
  2162. }
  2163. if err := j.JSONPath.Execute(w, queryObj); err != nil {
  2164. fmt.Fprintf(w, "Error executing template: %v. Printing more information for debugging the template:\n", err)
  2165. fmt.Fprintf(w, "\ttemplate was:\n\t\t%v\n", j.rawTemplate)
  2166. fmt.Fprintf(w, "\tobject given to jsonpath engine was:\n\t\t%#v\n\n", queryObj)
  2167. return fmt.Errorf("error executing jsonpath %q: %v\n", j.rawTemplate, err)
  2168. }
  2169. return nil
  2170. }
  2171. // TODO: implement HandledResources()
  2172. func (p *JSONPathPrinter) HandledResources() []string {
  2173. return []string{}
  2174. }