123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439 |
- /*
- Copyright 2014 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package kubectl
- import (
- "bytes"
- "encoding/json"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "reflect"
- "sort"
- "strings"
- "text/tabwriter"
- "text/template"
- "time"
- "github.com/ghodss/yaml"
- "github.com/golang/glog"
- "k8s.io/kubernetes/federation/apis/federation"
- "k8s.io/kubernetes/pkg/api"
- "k8s.io/kubernetes/pkg/api/meta"
- "k8s.io/kubernetes/pkg/api/unversioned"
- "k8s.io/kubernetes/pkg/apis/apps"
- "k8s.io/kubernetes/pkg/apis/autoscaling"
- "k8s.io/kubernetes/pkg/apis/batch"
- "k8s.io/kubernetes/pkg/apis/certificates"
- "k8s.io/kubernetes/pkg/apis/extensions"
- "k8s.io/kubernetes/pkg/apis/rbac"
- "k8s.io/kubernetes/pkg/labels"
- "k8s.io/kubernetes/pkg/runtime"
- utilerrors "k8s.io/kubernetes/pkg/util/errors"
- "k8s.io/kubernetes/pkg/util/jsonpath"
- "k8s.io/kubernetes/pkg/util/sets"
- )
- const (
- tabwriterMinWidth = 10
- tabwriterWidth = 4
- tabwriterPadding = 3
- tabwriterPadChar = ' '
- tabwriterFlags = 0
- loadBalancerWidth = 16
- )
- // GetPrinter takes a format type, an optional format argument. It will return true
- // if the format is generic (untyped), otherwise it will return false. The printer
- // is agnostic to schema versions, so you must send arguments to PrintObj in the
- // version you wish them to be shown using a VersionedPrinter (typically when
- // generic is true).
- func GetPrinter(format, formatArgument string, noHeaders bool) (ResourcePrinter, bool, error) {
- var printer ResourcePrinter
- switch format {
- case "json":
- printer = &JSONPrinter{}
- case "yaml":
- printer = &YAMLPrinter{}
- case "name":
- printer = &NamePrinter{
- // TODO: this is wrong, these should be provided as an argument to GetPrinter
- Typer: api.Scheme,
- Decoder: api.Codecs.UniversalDecoder(),
- }
- case "template", "go-template":
- if len(formatArgument) == 0 {
- return nil, false, fmt.Errorf("template format specified but no template given")
- }
- var err error
- printer, err = NewTemplatePrinter([]byte(formatArgument))
- if err != nil {
- return nil, false, fmt.Errorf("error parsing template %s, %v\n", formatArgument, err)
- }
- case "templatefile", "go-template-file":
- if len(formatArgument) == 0 {
- return nil, false, fmt.Errorf("templatefile format specified but no template file given")
- }
- data, err := ioutil.ReadFile(formatArgument)
- if err != nil {
- return nil, false, fmt.Errorf("error reading template %s, %v\n", formatArgument, err)
- }
- printer, err = NewTemplatePrinter(data)
- if err != nil {
- return nil, false, fmt.Errorf("error parsing template %s, %v\n", string(data), err)
- }
- case "jsonpath":
- if len(formatArgument) == 0 {
- return nil, false, fmt.Errorf("jsonpath template format specified but no template given")
- }
- var err error
- printer, err = NewJSONPathPrinter(formatArgument)
- if err != nil {
- return nil, false, fmt.Errorf("error parsing jsonpath %s, %v\n", formatArgument, err)
- }
- case "jsonpath-file":
- if len(formatArgument) == 0 {
- return nil, false, fmt.Errorf("jsonpath file format specified but no template file file given")
- }
- data, err := ioutil.ReadFile(formatArgument)
- if err != nil {
- return nil, false, fmt.Errorf("error reading template %s, %v\n", formatArgument, err)
- }
- printer, err = NewJSONPathPrinter(string(data))
- if err != nil {
- return nil, false, fmt.Errorf("error parsing template %s, %v\n", string(data), err)
- }
- case "custom-columns":
- var err error
- if printer, err = NewCustomColumnsPrinterFromSpec(formatArgument, api.Codecs.UniversalDecoder(), noHeaders); err != nil {
- return nil, false, err
- }
- case "custom-columns-file":
- file, err := os.Open(formatArgument)
- if err != nil {
- return nil, false, fmt.Errorf("error reading template %s, %v\n", formatArgument, err)
- }
- defer file.Close()
- if printer, err = NewCustomColumnsPrinterFromTemplate(file, api.Codecs.UniversalDecoder()); err != nil {
- return nil, false, err
- }
- case "wide":
- fallthrough
- case "":
- return nil, false, nil
- default:
- return nil, false, fmt.Errorf("output format %q not recognized", format)
- }
- return printer, true, nil
- }
- // ResourcePrinter is an interface that knows how to print runtime objects.
- type ResourcePrinter interface {
- // Print receives a runtime object, formats it and prints it to a writer.
- PrintObj(runtime.Object, io.Writer) error
- HandledResources() []string
- //Can be used to print out warning/clarifications if needed
- //after all objects were printed
- FinishPrint(io.Writer, string) error
- }
- // ResourcePrinterFunc is a function that can print objects
- type ResourcePrinterFunc func(runtime.Object, io.Writer) error
- // PrintObj implements ResourcePrinter
- func (fn ResourcePrinterFunc) PrintObj(obj runtime.Object, w io.Writer) error {
- return fn(obj, w)
- }
- // TODO: implement HandledResources()
- func (fn ResourcePrinterFunc) HandledResources() []string {
- return []string{}
- }
- func (fn ResourcePrinterFunc) FinishPrint(io.Writer, string) error {
- return nil
- }
- // VersionedPrinter takes runtime objects and ensures they are converted to a given API version
- // prior to being passed to a nested printer.
- type VersionedPrinter struct {
- printer ResourcePrinter
- converter runtime.ObjectConvertor
- versions []unversioned.GroupVersion
- }
- // NewVersionedPrinter wraps a printer to convert objects to a known API version prior to printing.
- func NewVersionedPrinter(printer ResourcePrinter, converter runtime.ObjectConvertor, versions ...unversioned.GroupVersion) ResourcePrinter {
- return &VersionedPrinter{
- printer: printer,
- converter: converter,
- versions: versions,
- }
- }
- func (p *VersionedPrinter) FinishPrint(w io.Writer, res string) error {
- return nil
- }
- // PrintObj implements ResourcePrinter
- func (p *VersionedPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
- if len(p.versions) == 0 {
- return fmt.Errorf("no version specified, object cannot be converted")
- }
- converted, err := p.converter.ConvertToVersion(obj, unversioned.GroupVersions(p.versions))
- if err != nil {
- return err
- }
- return p.printer.PrintObj(converted, w)
- }
- // TODO: implement HandledResources()
- func (p *VersionedPrinter) HandledResources() []string {
- return []string{}
- }
- // NamePrinter is an implementation of ResourcePrinter which outputs "resource/name" pair of an object.
- type NamePrinter struct {
- Decoder runtime.Decoder
- Typer runtime.ObjectTyper
- }
- func (p *NamePrinter) FinishPrint(w io.Writer, res string) error {
- return nil
- }
- // PrintObj is an implementation of ResourcePrinter.PrintObj which decodes the object
- // and print "resource/name" pair. If the object is a List, print all items in it.
- func (p *NamePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
- if meta.IsListType(obj) {
- items, err := meta.ExtractList(obj)
- if err != nil {
- return err
- }
- if errs := runtime.DecodeList(items, p.Decoder, runtime.UnstructuredJSONScheme); len(errs) > 0 {
- return utilerrors.NewAggregate(errs)
- }
- for _, obj := range items {
- if err := p.PrintObj(obj, w); err != nil {
- return err
- }
- }
- return nil
- }
- // TODO: this is wrong, runtime.Unknown and runtime.Unstructured are not handled properly here.
- name := "<unknown>"
- if acc, err := meta.Accessor(obj); err == nil {
- if n := acc.GetName(); len(n) > 0 {
- name = n
- }
- }
- if gvks, _, err := p.Typer.ObjectKinds(obj); err == nil {
- // TODO: this is wrong, it assumes that meta knows about all Kinds - should take a RESTMapper
- _, resource := meta.KindToResource(gvks[0])
- fmt.Fprintf(w, "%s/%s\n", resource.Resource, name)
- } else {
- fmt.Fprintf(w, "<unknown>/%s\n", name)
- }
- return nil
- }
- // TODO: implement HandledResources()
- func (p *NamePrinter) HandledResources() []string {
- return []string{}
- }
- // JSONPrinter is an implementation of ResourcePrinter which outputs an object as JSON.
- type JSONPrinter struct {
- }
- func (p *JSONPrinter) FinishPrint(w io.Writer, res string) error {
- return nil
- }
- // PrintObj is an implementation of ResourcePrinter.PrintObj which simply writes the object to the Writer.
- func (p *JSONPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
- switch obj := obj.(type) {
- case *runtime.Unknown:
- _, err := w.Write(obj.Raw)
- return err
- }
- data, err := json.MarshalIndent(obj, "", " ")
- if err != nil {
- return err
- }
- data = append(data, '\n')
- _, err = w.Write(data)
- return err
- }
- // TODO: implement HandledResources()
- func (p *JSONPrinter) HandledResources() []string {
- return []string{}
- }
- // YAMLPrinter is an implementation of ResourcePrinter which outputs an object as YAML.
- // The input object is assumed to be in the internal version of an API and is converted
- // to the given version first.
- type YAMLPrinter struct {
- version string
- converter runtime.ObjectConvertor
- }
- func (p *YAMLPrinter) FinishPrint(w io.Writer, res string) error {
- return nil
- }
- // PrintObj prints the data as YAML.
- func (p *YAMLPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
- switch obj := obj.(type) {
- case *runtime.Unknown:
- data, err := yaml.JSONToYAML(obj.Raw)
- if err != nil {
- return err
- }
- _, err = w.Write(data)
- return err
- }
- output, err := yaml.Marshal(obj)
- if err != nil {
- return err
- }
- _, err = fmt.Fprint(w, string(output))
- return err
- }
- // TODO: implement HandledResources()
- func (p *YAMLPrinter) HandledResources() []string {
- return []string{}
- }
- type handlerEntry struct {
- columns []string
- printFunc reflect.Value
- args []reflect.Value
- }
- type PrintOptions struct {
- NoHeaders bool
- WithNamespace bool
- WithKind bool
- Wide bool
- ShowAll bool
- ShowLabels bool
- AbsoluteTimestamps bool
- Kind string
- ColumnLabels []string
- }
- // HumanReadablePrinter is an implementation of ResourcePrinter which attempts to provide
- // more elegant output. It is not threadsafe, but you may call PrintObj repeatedly; headers
- // will only be printed if the object type changes. This makes it useful for printing items
- // received from watches.
- type HumanReadablePrinter struct {
- handlerMap map[reflect.Type]*handlerEntry
- options PrintOptions
- lastType reflect.Type
- hiddenObjNum int
- }
- // NewHumanReadablePrinter creates a HumanReadablePrinter.
- func NewHumanReadablePrinter(options PrintOptions) *HumanReadablePrinter {
- printer := &HumanReadablePrinter{
- handlerMap: make(map[reflect.Type]*handlerEntry),
- options: options,
- }
- printer.addDefaultHandlers()
- return printer
- }
- // formatResourceName receives a resource kind, name, and boolean specifying
- // whether or not to update the current name to "kind/name"
- func formatResourceName(kind, name string, withKind bool) string {
- if !withKind || kind == "" {
- return name
- }
- return kind + "/" + name
- }
- // GetResourceKind returns the type currently set for a resource
- func (h *HumanReadablePrinter) GetResourceKind() string {
- return h.options.Kind
- }
- // EnsurePrintWithKind sets HumanReadablePrinter options "WithKind" to true
- // and "Kind" to the string arg it receives, pre-pending this string
- // to the "NAME" column in an output of resources.
- func (h *HumanReadablePrinter) EnsurePrintWithKind(kind string) {
- h.options.WithKind = true
- h.options.Kind = kind
- }
- // Handler adds a print handler with a given set of columns to HumanReadablePrinter instance.
- // See validatePrintHandlerFunc for required method signature.
- func (h *HumanReadablePrinter) Handler(columns []string, printFunc interface{}) error {
- printFuncValue := reflect.ValueOf(printFunc)
- if err := h.validatePrintHandlerFunc(printFuncValue); err != nil {
- glog.Errorf("Unable to add print handler: %v", err)
- return err
- }
- objType := printFuncValue.Type().In(0)
- h.handlerMap[objType] = &handlerEntry{
- columns: columns,
- printFunc: printFuncValue,
- }
- return nil
- }
- // validatePrintHandlerFunc validates print handler signature.
- // printFunc is the function that will be called to print an object.
- // It must be of the following type:
- // func printFunc(object ObjectType, w io.Writer, options PrintOptions) error
- // where ObjectType is the type of the object that will be printed.
- func (h *HumanReadablePrinter) validatePrintHandlerFunc(printFunc reflect.Value) error {
- if printFunc.Kind() != reflect.Func {
- return fmt.Errorf("invalid print handler. %#v is not a function", printFunc)
- }
- funcType := printFunc.Type()
- if funcType.NumIn() != 3 || funcType.NumOut() != 1 {
- return fmt.Errorf("invalid print handler." +
- "Must accept 3 parameters and return 1 value.")
- }
- if funcType.In(1) != reflect.TypeOf((*io.Writer)(nil)).Elem() ||
- funcType.In(2) != reflect.TypeOf((*PrintOptions)(nil)).Elem() ||
- funcType.Out(0) != reflect.TypeOf((*error)(nil)).Elem() {
- return fmt.Errorf("invalid print handler. The expected signature is: "+
- "func handler(obj %v, w io.Writer, options PrintOptions) error", funcType.In(0))
- }
- return nil
- }
- func (h *HumanReadablePrinter) HandledResources() []string {
- keys := make([]string, 0)
- for k := range h.handlerMap {
- // k.String looks like "*api.PodList" and we want just "pod"
- api := strings.Split(k.String(), ".")
- resource := api[len(api)-1]
- if strings.HasSuffix(resource, "List") {
- continue
- }
- resource = strings.ToLower(resource)
- keys = append(keys, resource)
- }
- return keys
- }
- func (h *HumanReadablePrinter) FinishPrint(output io.Writer, res string) error {
- if !h.options.NoHeaders && !h.options.ShowAll && h.hiddenObjNum > 0 {
- _, 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)
- return err
- }
- return nil
- }
- // NOTE: When adding a new resource type here, please update the list
- // pkg/kubectl/cmd/get.go to reflect the new resource type.
- var podColumns = []string{"NAME", "READY", "STATUS", "RESTARTS", "AGE"}
- var podTemplateColumns = []string{"TEMPLATE", "CONTAINER(S)", "IMAGE(S)", "PODLABELS"}
- var replicationControllerColumns = []string{"NAME", "DESIRED", "CURRENT", "READY", "AGE"}
- var replicaSetColumns = []string{"NAME", "DESIRED", "CURRENT", "READY", "AGE"}
- var jobColumns = []string{"NAME", "DESIRED", "SUCCESSFUL", "AGE"}
- var scheduledJobColumns = []string{"NAME", "SCHEDULE", "SUSPEND", "ACTIVE", "LAST-SCHEDULE"}
- var serviceColumns = []string{"NAME", "CLUSTER-IP", "EXTERNAL-IP", "PORT(S)", "AGE"}
- var ingressColumns = []string{"NAME", "HOSTS", "ADDRESS", "PORTS", "AGE"}
- var petSetColumns = []string{"NAME", "DESIRED", "CURRENT", "AGE"}
- var endpointColumns = []string{"NAME", "ENDPOINTS", "AGE"}
- var nodeColumns = []string{"NAME", "STATUS", "AGE"}
- var daemonSetColumns = []string{"NAME", "DESIRED", "CURRENT", "NODE-SELECTOR", "AGE"}
- var eventColumns = []string{"LASTSEEN", "FIRSTSEEN", "COUNT", "NAME", "KIND", "SUBOBJECT", "TYPE", "REASON", "SOURCE", "MESSAGE"}
- var limitRangeColumns = []string{"NAME", "AGE"}
- var resourceQuotaColumns = []string{"NAME", "AGE"}
- var namespaceColumns = []string{"NAME", "STATUS", "AGE"}
- var secretColumns = []string{"NAME", "TYPE", "DATA", "AGE"}
- var serviceAccountColumns = []string{"NAME", "SECRETS", "AGE"}
- var persistentVolumeColumns = []string{"NAME", "CAPACITY", "ACCESSMODES", "RECLAIMPOLICY", "STATUS", "CLAIM", "REASON", "AGE"}
- var persistentVolumeClaimColumns = []string{"NAME", "STATUS", "VOLUME", "CAPACITY", "ACCESSMODES", "AGE"}
- var componentStatusColumns = []string{"NAME", "STATUS", "MESSAGE", "ERROR"}
- var thirdPartyResourceColumns = []string{"NAME", "DESCRIPTION", "VERSION(S)"}
- var roleColumns = []string{"NAME", "AGE"}
- var roleBindingColumns = []string{"NAME", "AGE"}
- var clusterRoleColumns = []string{"NAME", "AGE"}
- var clusterRoleBindingColumns = []string{"NAME", "AGE"}
- var storageClassColumns = []string{"NAME", "TYPE"}
- // TODO: consider having 'KIND' for third party resource data
- var thirdPartyResourceDataColumns = []string{"NAME", "LABELS", "DATA"}
- var horizontalPodAutoscalerColumns = []string{"NAME", "REFERENCE", "TARGET", "CURRENT", "MINPODS", "MAXPODS", "AGE"}
- var withNamespacePrefixColumns = []string{"NAMESPACE"} // TODO(erictune): print cluster name too.
- var deploymentColumns = []string{"NAME", "DESIRED", "CURRENT", "UP-TO-DATE", "AVAILABLE", "AGE"}
- var configMapColumns = []string{"NAME", "DATA", "AGE"}
- var podSecurityPolicyColumns = []string{"NAME", "PRIV", "CAPS", "VOLUMEPLUGINS", "SELINUX", "RUNASUSER"}
- var clusterColumns = []string{"NAME", "STATUS", "AGE"}
- var networkPolicyColumns = []string{"NAME", "POD-SELECTOR", "AGE"}
- var certificateSigningRequestColumns = []string{"NAME", "AGE", "REQUESTOR", "CONDITION"}
- func (h *HumanReadablePrinter) printPod(pod *api.Pod, w io.Writer, options PrintOptions) error {
- reason := string(pod.Status.Phase)
- // if not printing all pods, skip terminated pods (default)
- if !options.ShowAll && (reason == string(api.PodSucceeded) || reason == string(api.PodFailed)) {
- h.hiddenObjNum++
- return nil
- }
- if err := printPodBase(pod, w, options); err != nil {
- return err
- }
- return nil
- }
- func (h *HumanReadablePrinter) printPodList(podList *api.PodList, w io.Writer, options PrintOptions) error {
- for _, pod := range podList.Items {
- reason := string(pod.Status.Phase)
- // if not printing all pods, skip terminated pods (default)
- if !options.ShowAll && (reason == string(api.PodSucceeded) || reason == string(api.PodFailed)) {
- h.hiddenObjNum++
- continue
- }
- if err := printPodBase(&pod, w, options); err != nil {
- return err
- }
- }
- return nil
- }
- // addDefaultHandlers adds print handlers for default Kubernetes types.
- func (h *HumanReadablePrinter) addDefaultHandlers() {
- h.Handler(podColumns, h.printPodList)
- h.Handler(podColumns, h.printPod)
- h.Handler(podTemplateColumns, printPodTemplate)
- h.Handler(podTemplateColumns, printPodTemplateList)
- h.Handler(replicationControllerColumns, printReplicationController)
- h.Handler(replicationControllerColumns, printReplicationControllerList)
- h.Handler(replicaSetColumns, printReplicaSet)
- h.Handler(replicaSetColumns, printReplicaSetList)
- h.Handler(daemonSetColumns, printDaemonSet)
- h.Handler(daemonSetColumns, printDaemonSetList)
- h.Handler(jobColumns, printJob)
- h.Handler(jobColumns, printJobList)
- h.Handler(scheduledJobColumns, printScheduledJob)
- h.Handler(scheduledJobColumns, printScheduledJobList)
- h.Handler(serviceColumns, printService)
- h.Handler(serviceColumns, printServiceList)
- h.Handler(ingressColumns, printIngress)
- h.Handler(ingressColumns, printIngressList)
- h.Handler(petSetColumns, printPetSet)
- h.Handler(petSetColumns, printPetSetList)
- h.Handler(endpointColumns, printEndpoints)
- h.Handler(endpointColumns, printEndpointsList)
- h.Handler(nodeColumns, printNode)
- h.Handler(nodeColumns, printNodeList)
- h.Handler(eventColumns, printEvent)
- h.Handler(eventColumns, printEventList)
- h.Handler(limitRangeColumns, printLimitRange)
- h.Handler(limitRangeColumns, printLimitRangeList)
- h.Handler(resourceQuotaColumns, printResourceQuota)
- h.Handler(resourceQuotaColumns, printResourceQuotaList)
- h.Handler(namespaceColumns, printNamespace)
- h.Handler(namespaceColumns, printNamespaceList)
- h.Handler(secretColumns, printSecret)
- h.Handler(secretColumns, printSecretList)
- h.Handler(serviceAccountColumns, printServiceAccount)
- h.Handler(serviceAccountColumns, printServiceAccountList)
- h.Handler(persistentVolumeClaimColumns, printPersistentVolumeClaim)
- h.Handler(persistentVolumeClaimColumns, printPersistentVolumeClaimList)
- h.Handler(persistentVolumeColumns, printPersistentVolume)
- h.Handler(persistentVolumeColumns, printPersistentVolumeList)
- h.Handler(componentStatusColumns, printComponentStatus)
- h.Handler(componentStatusColumns, printComponentStatusList)
- h.Handler(thirdPartyResourceColumns, printThirdPartyResource)
- h.Handler(thirdPartyResourceColumns, printThirdPartyResourceList)
- h.Handler(deploymentColumns, printDeployment)
- h.Handler(deploymentColumns, printDeploymentList)
- h.Handler(horizontalPodAutoscalerColumns, printHorizontalPodAutoscaler)
- h.Handler(horizontalPodAutoscalerColumns, printHorizontalPodAutoscalerList)
- h.Handler(configMapColumns, printConfigMap)
- h.Handler(configMapColumns, printConfigMapList)
- h.Handler(podSecurityPolicyColumns, printPodSecurityPolicy)
- h.Handler(podSecurityPolicyColumns, printPodSecurityPolicyList)
- h.Handler(thirdPartyResourceDataColumns, printThirdPartyResourceData)
- h.Handler(thirdPartyResourceDataColumns, printThirdPartyResourceDataList)
- h.Handler(clusterColumns, printCluster)
- h.Handler(clusterColumns, printClusterList)
- h.Handler(networkPolicyColumns, printNetworkPolicy)
- h.Handler(networkPolicyColumns, printNetworkPolicyList)
- h.Handler(roleColumns, printRole)
- h.Handler(roleColumns, printRoleList)
- h.Handler(roleBindingColumns, printRoleBinding)
- h.Handler(roleBindingColumns, printRoleBindingList)
- h.Handler(clusterRoleColumns, printClusterRole)
- h.Handler(clusterRoleColumns, printClusterRoleList)
- h.Handler(clusterRoleBindingColumns, printClusterRoleBinding)
- h.Handler(clusterRoleBindingColumns, printClusterRoleBindingList)
- h.Handler(certificateSigningRequestColumns, printCertificateSigningRequest)
- h.Handler(certificateSigningRequestColumns, printCertificateSigningRequestList)
- h.Handler(storageClassColumns, printStorageClass)
- h.Handler(storageClassColumns, printStorageClassList)
- }
- func (h *HumanReadablePrinter) unknown(data []byte, w io.Writer) error {
- _, err := fmt.Fprintf(w, "Unknown object: %s", string(data))
- return err
- }
- func (h *HumanReadablePrinter) printHeader(columnNames []string, w io.Writer) error {
- if _, err := fmt.Fprintf(w, "%s\n", strings.Join(columnNames, "\t")); err != nil {
- return err
- }
- return nil
- }
- // Pass ports=nil for all ports.
- func formatEndpoints(endpoints *api.Endpoints, ports sets.String) string {
- if len(endpoints.Subsets) == 0 {
- return "<none>"
- }
- list := []string{}
- max := 3
- more := false
- count := 0
- for i := range endpoints.Subsets {
- ss := &endpoints.Subsets[i]
- for i := range ss.Ports {
- port := &ss.Ports[i]
- if ports == nil || ports.Has(port.Name) {
- for i := range ss.Addresses {
- if len(list) == max {
- more = true
- }
- addr := &ss.Addresses[i]
- if !more {
- list = append(list, fmt.Sprintf("%s:%d", addr.IP, port.Port))
- }
- count++
- }
- }
- }
- }
- ret := strings.Join(list, ",")
- if more {
- return fmt.Sprintf("%s + %d more...", ret, count-max)
- }
- return ret
- }
- func shortHumanDuration(d time.Duration) string {
- // Allow deviation no more than 2 seconds(excluded) to tolerate machine time
- // inconsistence, it can be considered as almost now.
- if seconds := int(d.Seconds()); seconds < -1 {
- return fmt.Sprintf("<invalid>")
- } else if seconds < 0 {
- return fmt.Sprintf("0s")
- } else if seconds < 60 {
- return fmt.Sprintf("%ds", seconds)
- } else if minutes := int(d.Minutes()); minutes < 60 {
- return fmt.Sprintf("%dm", minutes)
- } else if hours := int(d.Hours()); hours < 24 {
- return fmt.Sprintf("%dh", hours)
- } else if hours < 24*364 {
- return fmt.Sprintf("%dd", hours/24)
- }
- return fmt.Sprintf("%dy", int(d.Hours()/24/365))
- }
- // translateTimestamp returns the elapsed time since timestamp in
- // human-readable approximation.
- func translateTimestamp(timestamp unversioned.Time) string {
- if timestamp.IsZero() {
- return "<unknown>"
- }
- return shortHumanDuration(time.Now().Sub(timestamp.Time))
- }
- func printPodBase(pod *api.Pod, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, pod.Name, options.WithKind)
- namespace := pod.Namespace
- restarts := 0
- totalContainers := len(pod.Spec.Containers)
- readyContainers := 0
- reason := string(pod.Status.Phase)
- if pod.Status.Reason != "" {
- reason = pod.Status.Reason
- }
- initializing := false
- for i := range pod.Status.InitContainerStatuses {
- container := pod.Status.InitContainerStatuses[i]
- restarts += int(container.RestartCount)
- switch {
- case container.State.Terminated != nil && container.State.Terminated.ExitCode == 0:
- continue
- case container.State.Terminated != nil:
- // initialization is failed
- if len(container.State.Terminated.Reason) == 0 {
- if container.State.Terminated.Signal != 0 {
- reason = fmt.Sprintf("Init:Signal:%d", container.State.Terminated.Signal)
- } else {
- reason = fmt.Sprintf("Init:ExitCode:%d", container.State.Terminated.ExitCode)
- }
- } else {
- reason = "Init:" + container.State.Terminated.Reason
- }
- initializing = true
- case container.State.Waiting != nil && len(container.State.Waiting.Reason) > 0 && container.State.Waiting.Reason != "PodInitializing":
- reason = "Init:" + container.State.Waiting.Reason
- initializing = true
- default:
- reason = fmt.Sprintf("Init:%d/%d", i, len(pod.Spec.InitContainers))
- initializing = true
- }
- break
- }
- if !initializing {
- restarts = 0
- for i := len(pod.Status.ContainerStatuses) - 1; i >= 0; i-- {
- container := pod.Status.ContainerStatuses[i]
- restarts += int(container.RestartCount)
- if container.State.Waiting != nil && container.State.Waiting.Reason != "" {
- reason = container.State.Waiting.Reason
- } else if container.State.Terminated != nil && container.State.Terminated.Reason != "" {
- reason = container.State.Terminated.Reason
- } else if container.State.Terminated != nil && container.State.Terminated.Reason == "" {
- if container.State.Terminated.Signal != 0 {
- reason = fmt.Sprintf("Signal:%d", container.State.Terminated.Signal)
- } else {
- reason = fmt.Sprintf("ExitCode:%d", container.State.Terminated.ExitCode)
- }
- } else if container.Ready && container.State.Running != nil {
- readyContainers++
- }
- }
- }
- if pod.DeletionTimestamp != nil {
- reason = "Terminating"
- }
- if options.WithNamespace {
- if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
- return err
- }
- }
- if _, err := fmt.Fprintf(w, "%s\t%d/%d\t%s\t%d\t%s",
- name,
- readyContainers,
- totalContainers,
- reason,
- restarts,
- translateTimestamp(pod.CreationTimestamp),
- ); err != nil {
- return err
- }
- if options.Wide {
- nodeName := pod.Spec.NodeName
- podIP := pod.Status.PodIP
- if podIP == "" {
- podIP = "<none>"
- }
- if _, err := fmt.Fprintf(w, "\t%s\t%s",
- podIP,
- nodeName,
- ); err != nil {
- return err
- }
- }
- if _, err := fmt.Fprint(w, AppendLabels(pod.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, pod.Labels)); err != nil {
- return err
- }
- return nil
- }
- func printPodTemplate(pod *api.PodTemplate, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, pod.Name, options.WithKind)
- namespace := pod.Namespace
- containers := pod.Template.Spec.Containers
- if options.WithNamespace {
- if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
- return err
- }
- }
- if _, err := fmt.Fprintf(w, "%s", name); err != nil {
- return err
- }
- if err := layoutContainers(containers, w); err != nil {
- return err
- }
- if _, err := fmt.Fprintf(w, "\t%s", labels.FormatLabels(pod.Template.Labels)); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendLabels(pod.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, pod.Labels)); err != nil {
- return err
- }
- return nil
- }
- func printPodTemplateList(podList *api.PodTemplateList, w io.Writer, options PrintOptions) error {
- for _, pod := range podList.Items {
- if err := printPodTemplate(&pod, w, options); err != nil {
- return err
- }
- }
- return nil
- }
- // TODO(AdoHe): try to put wide output in a single method
- func printReplicationController(controller *api.ReplicationController, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, controller.Name, options.WithKind)
- namespace := controller.Namespace
- containers := controller.Spec.Template.Spec.Containers
- if options.WithNamespace {
- if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
- return err
- }
- }
- desiredReplicas := controller.Spec.Replicas
- currentReplicas := controller.Status.Replicas
- readyReplicas := controller.Status.ReadyReplicas
- if _, err := fmt.Fprintf(w, "%s\t%d\t%d\t%d\t%s",
- name,
- desiredReplicas,
- currentReplicas,
- readyReplicas,
- translateTimestamp(controller.CreationTimestamp),
- ); err != nil {
- return err
- }
- if options.Wide {
- if err := layoutContainers(containers, w); err != nil {
- return err
- }
- if _, err := fmt.Fprintf(w, "\t%s", labels.FormatLabels(controller.Spec.Selector)); err != nil {
- return err
- }
- }
- if _, err := fmt.Fprint(w, AppendLabels(controller.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, controller.Labels)); err != nil {
- return err
- }
- return nil
- }
- func printReplicationControllerList(list *api.ReplicationControllerList, w io.Writer, options PrintOptions) error {
- for _, controller := range list.Items {
- if err := printReplicationController(&controller, w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printReplicaSet(rs *extensions.ReplicaSet, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, rs.Name, options.WithKind)
- namespace := rs.Namespace
- containers := rs.Spec.Template.Spec.Containers
- if options.WithNamespace {
- if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
- return err
- }
- }
- desiredReplicas := rs.Spec.Replicas
- currentReplicas := rs.Status.Replicas
- readyReplicas := rs.Status.ReadyReplicas
- if _, err := fmt.Fprintf(w, "%s\t%d\t%d\t%d\t%s",
- name,
- desiredReplicas,
- currentReplicas,
- readyReplicas,
- translateTimestamp(rs.CreationTimestamp),
- ); err != nil {
- return err
- }
- if options.Wide {
- if err := layoutContainers(containers, w); err != nil {
- return err
- }
- if _, err := fmt.Fprintf(w, "\t%s", unversioned.FormatLabelSelector(rs.Spec.Selector)); err != nil {
- return err
- }
- }
- if _, err := fmt.Fprint(w, AppendLabels(rs.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, rs.Labels)); err != nil {
- return err
- }
- return nil
- }
- func printReplicaSetList(list *extensions.ReplicaSetList, w io.Writer, options PrintOptions) error {
- for _, rs := range list.Items {
- if err := printReplicaSet(&rs, w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printCluster(c *federation.Cluster, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, c.Name, options.WithKind)
- var statuses []string
- for _, condition := range c.Status.Conditions {
- if condition.Status == api.ConditionTrue {
- statuses = append(statuses, string(condition.Type))
- } else {
- statuses = append(statuses, "Not"+string(condition.Type))
- }
- }
- if len(statuses) == 0 {
- statuses = append(statuses, "Unknown")
- }
- if _, err := fmt.Fprintf(w, "%s\t%s\t%s\n",
- name,
- strings.Join(statuses, ","),
- translateTimestamp(c.CreationTimestamp),
- ); err != nil {
- return err
- }
- return nil
- }
- func printClusterList(list *federation.ClusterList, w io.Writer, options PrintOptions) error {
- for _, rs := range list.Items {
- if err := printCluster(&rs, w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printJob(job *batch.Job, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, job.Name, options.WithKind)
- namespace := job.Namespace
- containers := job.Spec.Template.Spec.Containers
- if options.WithNamespace {
- if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
- return err
- }
- }
- selector, err := unversioned.LabelSelectorAsSelector(job.Spec.Selector)
- if err != nil {
- // this shouldn't happen if LabelSelector passed validation
- return err
- }
- if job.Spec.Completions != nil {
- if _, err := fmt.Fprintf(w, "%s\t%d\t%d\t%s",
- name,
- *job.Spec.Completions,
- job.Status.Succeeded,
- translateTimestamp(job.CreationTimestamp),
- ); err != nil {
- return err
- }
- } else {
- if _, err := fmt.Fprintf(w, "%s\t%s\t%d\t%s",
- name,
- "<none>",
- job.Status.Succeeded,
- translateTimestamp(job.CreationTimestamp),
- ); err != nil {
- return err
- }
- }
- if options.Wide {
- if err := layoutContainers(containers, w); err != nil {
- return err
- }
- if _, err := fmt.Fprintf(w, "\t%s", selector.String()); err != nil {
- return err
- }
- }
- if _, err := fmt.Fprint(w, AppendLabels(job.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, job.Labels)); err != nil {
- return err
- }
- return nil
- }
- func printJobList(list *batch.JobList, w io.Writer, options PrintOptions) error {
- for _, job := range list.Items {
- if err := printJob(&job, w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printScheduledJob(scheduledJob *batch.ScheduledJob, w io.Writer, options PrintOptions) error {
- name := scheduledJob.Name
- namespace := scheduledJob.Namespace
- if options.WithNamespace {
- if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
- return err
- }
- }
- lastScheduleTime := "<none>"
- if scheduledJob.Status.LastScheduleTime != nil {
- lastScheduleTime = scheduledJob.Status.LastScheduleTime.Time.Format(time.RFC1123Z)
- }
- if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%d\t%s\n",
- name,
- scheduledJob.Spec.Schedule,
- printBoolPtr(scheduledJob.Spec.Suspend),
- len(scheduledJob.Status.Active),
- lastScheduleTime,
- ); err != nil {
- return err
- }
- return nil
- }
- func printScheduledJobList(list *batch.ScheduledJobList, w io.Writer, options PrintOptions) error {
- for _, scheduledJob := range list.Items {
- if err := printScheduledJob(&scheduledJob, w, options); err != nil {
- return err
- }
- }
- return nil
- }
- // loadBalancerStatusStringer behaves mostly like a string interface and converts the given status to a string.
- // `wide` indicates whether the returned value is meant for --o=wide output. If not, it's clipped to 16 bytes.
- func loadBalancerStatusStringer(s api.LoadBalancerStatus, wide bool) string {
- ingress := s.Ingress
- result := []string{}
- for i := range ingress {
- if ingress[i].IP != "" {
- result = append(result, ingress[i].IP)
- } else if ingress[i].Hostname != "" {
- result = append(result, ingress[i].Hostname)
- }
- }
- r := strings.Join(result, ",")
- if !wide && len(r) > loadBalancerWidth {
- r = r[0:(loadBalancerWidth-3)] + "..."
- }
- return r
- }
- func getServiceExternalIP(svc *api.Service, wide bool) string {
- switch svc.Spec.Type {
- case api.ServiceTypeClusterIP:
- if len(svc.Spec.ExternalIPs) > 0 {
- return strings.Join(svc.Spec.ExternalIPs, ",")
- }
- return "<none>"
- case api.ServiceTypeNodePort:
- if len(svc.Spec.ExternalIPs) > 0 {
- return strings.Join(svc.Spec.ExternalIPs, ",")
- }
- return "<nodes>"
- case api.ServiceTypeLoadBalancer:
- lbIps := loadBalancerStatusStringer(svc.Status.LoadBalancer, wide)
- if len(svc.Spec.ExternalIPs) > 0 {
- result := append(strings.Split(lbIps, ","), svc.Spec.ExternalIPs...)
- return strings.Join(result, ",")
- }
- if len(lbIps) > 0 {
- return lbIps
- }
- return "<pending>"
- case api.ServiceTypeExternalName:
- return svc.Spec.ExternalName
- }
- return "<unknown>"
- }
- func makePortString(ports []api.ServicePort) string {
- pieces := make([]string, len(ports))
- for ix := range ports {
- port := &ports[ix]
- pieces[ix] = fmt.Sprintf("%d/%s", port.Port, port.Protocol)
- }
- return strings.Join(pieces, ",")
- }
- func printService(svc *api.Service, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, svc.Name, options.WithKind)
- namespace := svc.Namespace
- internalIP := svc.Spec.ClusterIP
- externalIP := getServiceExternalIP(svc, options.Wide)
- if options.WithNamespace {
- if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
- return err
- }
- }
- if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s",
- name,
- internalIP,
- externalIP,
- makePortString(svc.Spec.Ports),
- translateTimestamp(svc.CreationTimestamp),
- ); err != nil {
- return err
- }
- if options.Wide {
- if _, err := fmt.Fprintf(w, "\t%s", labels.FormatLabels(svc.Spec.Selector)); err != nil {
- return err
- }
- }
- if _, err := fmt.Fprint(w, AppendLabels(svc.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, svc.Labels))
- return err
- }
- func printServiceList(list *api.ServiceList, w io.Writer, options PrintOptions) error {
- for _, svc := range list.Items {
- if err := printService(&svc, w, options); err != nil {
- return err
- }
- }
- return nil
- }
- // backendStringer behaves just like a string interface and converts the given backend to a string.
- func backendStringer(backend *extensions.IngressBackend) string {
- if backend == nil {
- return ""
- }
- return fmt.Sprintf("%v:%v", backend.ServiceName, backend.ServicePort.String())
- }
- func formatHosts(rules []extensions.IngressRule) string {
- list := []string{}
- max := 3
- more := false
- for _, rule := range rules {
- if len(list) == max {
- more = true
- }
- if !more && len(rule.Host) != 0 {
- list = append(list, rule.Host)
- }
- }
- if len(list) == 0 {
- return "*"
- }
- ret := strings.Join(list, ",")
- if more {
- return fmt.Sprintf("%s + %d more...", ret, len(rules)-max)
- }
- return ret
- }
- func formatPorts(tls []extensions.IngressTLS) string {
- if len(tls) != 0 {
- return "80, 443"
- }
- return "80"
- }
- func printIngress(ingress *extensions.Ingress, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, ingress.Name, options.WithKind)
- namespace := ingress.Namespace
- if options.WithNamespace {
- if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
- return err
- }
- }
- if _, err := fmt.Fprintf(w, "%s\t%v\t%v\t%v\t%s",
- name,
- formatHosts(ingress.Spec.Rules),
- loadBalancerStatusStringer(ingress.Status.LoadBalancer, options.Wide),
- formatPorts(ingress.Spec.TLS),
- translateTimestamp(ingress.CreationTimestamp),
- ); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendLabels(ingress.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, ingress.Labels)); err != nil {
- return err
- }
- return nil
- }
- func printIngressList(ingressList *extensions.IngressList, w io.Writer, options PrintOptions) error {
- for _, ingress := range ingressList.Items {
- if err := printIngress(&ingress, w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printPetSet(ps *apps.PetSet, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, ps.Name, options.WithKind)
- namespace := ps.Namespace
- containers := ps.Spec.Template.Spec.Containers
- if options.WithNamespace {
- if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
- return err
- }
- }
- desiredReplicas := ps.Spec.Replicas
- currentReplicas := ps.Status.Replicas
- if _, err := fmt.Fprintf(w, "%s\t%d\t%d\t%s",
- name,
- desiredReplicas,
- currentReplicas,
- translateTimestamp(ps.CreationTimestamp),
- ); err != nil {
- return err
- }
- if options.Wide {
- if err := layoutContainers(containers, w); err != nil {
- return err
- }
- if _, err := fmt.Fprintf(w, "\t%s", unversioned.FormatLabelSelector(ps.Spec.Selector)); err != nil {
- return err
- }
- }
- if _, err := fmt.Fprint(w, AppendLabels(ps.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, ps.Labels)); err != nil {
- return err
- }
- return nil
- }
- func printPetSetList(petSetList *apps.PetSetList, w io.Writer, options PrintOptions) error {
- for _, ps := range petSetList.Items {
- if err := printPetSet(&ps, w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printDaemonSet(ds *extensions.DaemonSet, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, ds.Name, options.WithKind)
- namespace := ds.Namespace
- containers := ds.Spec.Template.Spec.Containers
- if options.WithNamespace {
- if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
- return err
- }
- }
- desiredScheduled := ds.Status.DesiredNumberScheduled
- currentScheduled := ds.Status.CurrentNumberScheduled
- selector, err := unversioned.LabelSelectorAsSelector(ds.Spec.Selector)
- if err != nil {
- // this shouldn't happen if LabelSelector passed validation
- return err
- }
- if _, err := fmt.Fprintf(w, "%s\t%d\t%d\t%s\t%s",
- name,
- desiredScheduled,
- currentScheduled,
- labels.FormatLabels(ds.Spec.Template.Spec.NodeSelector),
- translateTimestamp(ds.CreationTimestamp),
- ); err != nil {
- return err
- }
- if options.Wide {
- if err := layoutContainers(containers, w); err != nil {
- return err
- }
- if _, err := fmt.Fprintf(w, "\t%s", selector.String()); err != nil {
- return err
- }
- }
- if _, err := fmt.Fprint(w, AppendLabels(ds.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, ds.Labels)); err != nil {
- return err
- }
- return nil
- }
- func printDaemonSetList(list *extensions.DaemonSetList, w io.Writer, options PrintOptions) error {
- for _, ds := range list.Items {
- if err := printDaemonSet(&ds, w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printEndpoints(endpoints *api.Endpoints, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, endpoints.Name, options.WithKind)
- namespace := endpoints.Namespace
- if options.WithNamespace {
- if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
- return err
- }
- }
- if _, err := fmt.Fprintf(w, "%s\t%s\t%s", name, formatEndpoints(endpoints, nil), translateTimestamp(endpoints.CreationTimestamp)); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendLabels(endpoints.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, endpoints.Labels))
- return err
- }
- func printEndpointsList(list *api.EndpointsList, w io.Writer, options PrintOptions) error {
- for _, item := range list.Items {
- if err := printEndpoints(&item, w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printNamespace(item *api.Namespace, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, item.Name, options.WithKind)
- if options.WithNamespace {
- return fmt.Errorf("namespace is not namespaced")
- }
- if _, err := fmt.Fprintf(w, "%s\t%s\t%s", name, item.Status.Phase, translateTimestamp(item.CreationTimestamp)); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendLabels(item.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, item.Labels))
- return err
- }
- func printNamespaceList(list *api.NamespaceList, w io.Writer, options PrintOptions) error {
- for _, item := range list.Items {
- if err := printNamespace(&item, w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printSecret(item *api.Secret, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, item.Name, options.WithKind)
- namespace := item.Namespace
- if options.WithNamespace {
- if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
- return err
- }
- }
- if _, err := fmt.Fprintf(w, "%s\t%s\t%v\t%s", name, item.Type, len(item.Data), translateTimestamp(item.CreationTimestamp)); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendLabels(item.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, item.Labels))
- return err
- }
- func printSecretList(list *api.SecretList, w io.Writer, options PrintOptions) error {
- for _, item := range list.Items {
- if err := printSecret(&item, w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printServiceAccount(item *api.ServiceAccount, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, item.Name, options.WithKind)
- namespace := item.Namespace
- if options.WithNamespace {
- if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
- return err
- }
- }
- if _, err := fmt.Fprintf(w, "%s\t%d\t%s", name, len(item.Secrets), translateTimestamp(item.CreationTimestamp)); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendLabels(item.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, item.Labels))
- return err
- }
- func printServiceAccountList(list *api.ServiceAccountList, w io.Writer, options PrintOptions) error {
- for _, item := range list.Items {
- if err := printServiceAccount(&item, w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printNode(node *api.Node, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, node.Name, options.WithKind)
- if options.WithNamespace {
- return fmt.Errorf("node is not namespaced")
- }
- conditionMap := make(map[api.NodeConditionType]*api.NodeCondition)
- NodeAllConditions := []api.NodeConditionType{api.NodeReady}
- for i := range node.Status.Conditions {
- cond := node.Status.Conditions[i]
- conditionMap[cond.Type] = &cond
- }
- var status []string
- for _, validCondition := range NodeAllConditions {
- if condition, ok := conditionMap[validCondition]; ok {
- if condition.Status == api.ConditionTrue {
- status = append(status, string(condition.Type))
- } else {
- status = append(status, "Not"+string(condition.Type))
- }
- }
- }
- if len(status) == 0 {
- status = append(status, "Unknown")
- }
- if node.Spec.Unschedulable {
- status = append(status, "SchedulingDisabled")
- }
- if _, err := fmt.Fprintf(w, "%s\t%s\t%s", name, strings.Join(status, ","), translateTimestamp(node.CreationTimestamp)); err != nil {
- return err
- }
- // Display caller specify column labels first.
- if _, err := fmt.Fprint(w, AppendLabels(node.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, node.Labels))
- return err
- }
- func printNodeList(list *api.NodeList, w io.Writer, options PrintOptions) error {
- for _, node := range list.Items {
- if err := printNode(&node, w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printPersistentVolume(pv *api.PersistentVolume, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, pv.Name, options.WithKind)
- if options.WithNamespace {
- return fmt.Errorf("persistentVolume is not namespaced")
- }
- claimRefUID := ""
- if pv.Spec.ClaimRef != nil {
- claimRefUID += pv.Spec.ClaimRef.Namespace
- claimRefUID += "/"
- claimRefUID += pv.Spec.ClaimRef.Name
- }
- modesStr := api.GetAccessModesAsString(pv.Spec.AccessModes)
- reclaimPolicyStr := string(pv.Spec.PersistentVolumeReclaimPolicy)
- aQty := pv.Spec.Capacity[api.ResourceStorage]
- aSize := aQty.String()
- if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s",
- name,
- aSize, modesStr, reclaimPolicyStr,
- pv.Status.Phase,
- claimRefUID,
- pv.Status.Reason,
- translateTimestamp(pv.CreationTimestamp),
- ); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendLabels(pv.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, pv.Labels))
- return err
- }
- func printPersistentVolumeList(list *api.PersistentVolumeList, w io.Writer, options PrintOptions) error {
- for _, pv := range list.Items {
- if err := printPersistentVolume(&pv, w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printPersistentVolumeClaim(pvc *api.PersistentVolumeClaim, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, pvc.Name, options.WithKind)
- namespace := pvc.Namespace
- if options.WithNamespace {
- if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
- return err
- }
- }
- phase := pvc.Status.Phase
- storage := pvc.Spec.Resources.Requests[api.ResourceStorage]
- capacity := ""
- accessModes := ""
- if pvc.Spec.VolumeName != "" {
- accessModes = api.GetAccessModesAsString(pvc.Status.AccessModes)
- storage = pvc.Status.Capacity[api.ResourceStorage]
- capacity = storage.String()
- }
- 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 {
- return err
- }
- if _, err := fmt.Fprint(w, AppendLabels(pvc.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, pvc.Labels))
- return err
- }
- func printPersistentVolumeClaimList(list *api.PersistentVolumeClaimList, w io.Writer, options PrintOptions) error {
- for _, psd := range list.Items {
- if err := printPersistentVolumeClaim(&psd, w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printEvent(event *api.Event, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, event.InvolvedObject.Name, options.WithKind)
- namespace := event.Namespace
- if options.WithNamespace {
- if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
- return err
- }
- }
- // While watching event, we should print absolute time.
- var FirstTimestamp, LastTimestamp string
- if options.AbsoluteTimestamps {
- FirstTimestamp = event.FirstTimestamp.String()
- LastTimestamp = event.LastTimestamp.String()
- } else {
- FirstTimestamp = translateTimestamp(event.FirstTimestamp)
- LastTimestamp = translateTimestamp(event.LastTimestamp)
- }
- if _, err := fmt.Fprintf(
- w, "%s\t%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\t%s",
- LastTimestamp,
- FirstTimestamp,
- event.Count,
- name,
- event.InvolvedObject.Kind,
- event.InvolvedObject.FieldPath,
- event.Type,
- event.Reason,
- event.Source,
- event.Message,
- ); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendLabels(event.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, event.Labels))
- return err
- }
- // Sorts and prints the EventList in a human-friendly format.
- func printEventList(list *api.EventList, w io.Writer, options PrintOptions) error {
- sort.Sort(SortableEvents(list.Items))
- for i := range list.Items {
- if err := printEvent(&list.Items[i], w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printLimitRange(limitRange *api.LimitRange, w io.Writer, options PrintOptions) error {
- return printObjectMeta(limitRange.ObjectMeta, w, options, true)
- }
- // Prints the LimitRangeList in a human-friendly format.
- func printLimitRangeList(list *api.LimitRangeList, w io.Writer, options PrintOptions) error {
- for i := range list.Items {
- if err := printLimitRange(&list.Items[i], w, options); err != nil {
- return err
- }
- }
- return nil
- }
- // printObjectMeta prints the object metadata of a given resource.
- func printObjectMeta(meta api.ObjectMeta, w io.Writer, options PrintOptions, namespaced bool) error {
- name := formatResourceName(options.Kind, meta.Name, options.WithKind)
- if namespaced && options.WithNamespace {
- if _, err := fmt.Fprintf(w, "%s\t", meta.Namespace); err != nil {
- return err
- }
- }
- if _, err := fmt.Fprintf(
- w, "%s\t%s",
- name,
- translateTimestamp(meta.CreationTimestamp),
- ); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendLabels(meta.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, meta.Labels))
- return err
- }
- func printResourceQuota(resourceQuota *api.ResourceQuota, w io.Writer, options PrintOptions) error {
- return printObjectMeta(resourceQuota.ObjectMeta, w, options, true)
- }
- // Prints the ResourceQuotaList in a human-friendly format.
- func printResourceQuotaList(list *api.ResourceQuotaList, w io.Writer, options PrintOptions) error {
- for i := range list.Items {
- if err := printResourceQuota(&list.Items[i], w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printRole(role *rbac.Role, w io.Writer, options PrintOptions) error {
- return printObjectMeta(role.ObjectMeta, w, options, true)
- }
- // Prints the Role in a human-friendly format.
- func printRoleList(list *rbac.RoleList, w io.Writer, options PrintOptions) error {
- for i := range list.Items {
- if err := printRole(&list.Items[i], w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printRoleBinding(roleBinding *rbac.RoleBinding, w io.Writer, options PrintOptions) error {
- return printObjectMeta(roleBinding.ObjectMeta, w, options, true)
- }
- // Prints the RoleBinding in a human-friendly format.
- func printRoleBindingList(list *rbac.RoleBindingList, w io.Writer, options PrintOptions) error {
- for i := range list.Items {
- if err := printRoleBinding(&list.Items[i], w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printClusterRole(clusterRole *rbac.ClusterRole, w io.Writer, options PrintOptions) error {
- return printObjectMeta(clusterRole.ObjectMeta, w, options, false)
- }
- // Prints the ClusterRole in a human-friendly format.
- func printClusterRoleList(list *rbac.ClusterRoleList, w io.Writer, options PrintOptions) error {
- for i := range list.Items {
- if err := printClusterRole(&list.Items[i], w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printClusterRoleBinding(clusterRoleBinding *rbac.ClusterRoleBinding, w io.Writer, options PrintOptions) error {
- return printObjectMeta(clusterRoleBinding.ObjectMeta, w, options, false)
- }
- // Prints the ClusterRoleBinding in a human-friendly format.
- func printClusterRoleBindingList(list *rbac.ClusterRoleBindingList, w io.Writer, options PrintOptions) error {
- for i := range list.Items {
- if err := printClusterRoleBinding(&list.Items[i], w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printCertificateSigningRequest(csr *certificates.CertificateSigningRequest, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, csr.Name, options.WithKind)
- meta := csr.ObjectMeta
- status, err := extractCSRStatus(csr)
- if err != nil {
- return err
- }
- if _, err := fmt.Fprintf(
- w, "%s\t%s\t%s\t%s",
- name,
- translateTimestamp(meta.CreationTimestamp),
- csr.Spec.Username,
- status,
- ); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendLabels(meta.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- _, err = fmt.Fprint(w, AppendAllLabels(options.ShowLabels, meta.Labels))
- return err
- }
- func extractCSRStatus(csr *certificates.CertificateSigningRequest) (string, error) {
- var approved, denied bool
- for _, c := range csr.Status.Conditions {
- switch c.Type {
- case certificates.CertificateApproved:
- approved = true
- case certificates.CertificateDenied:
- denied = true
- default:
- return "", fmt.Errorf("unknown csr conditon %q", c)
- }
- }
- var status string
- // must be in order of presidence
- if denied {
- status += "Denied"
- } else if approved {
- status += "Approved"
- } else {
- status += "Pending"
- }
- if len(csr.Status.Certificate) > 0 {
- status += ",Issued"
- }
- return status, nil
- }
- func printCertificateSigningRequestList(list *certificates.CertificateSigningRequestList, w io.Writer, options PrintOptions) error {
- for i := range list.Items {
- if err := printCertificateSigningRequest(&list.Items[i], w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printComponentStatus(item *api.ComponentStatus, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, item.Name, options.WithKind)
- if options.WithNamespace {
- return fmt.Errorf("componentStatus is not namespaced")
- }
- status := "Unknown"
- message := ""
- error := ""
- for _, condition := range item.Conditions {
- if condition.Type == api.ComponentHealthy {
- if condition.Status == api.ConditionTrue {
- status = "Healthy"
- } else {
- status = "Unhealthy"
- }
- message = condition.Message
- error = condition.Error
- break
- }
- }
- if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s", name, status, message, error); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendLabels(item.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, item.Labels))
- return err
- }
- func printComponentStatusList(list *api.ComponentStatusList, w io.Writer, options PrintOptions) error {
- for _, item := range list.Items {
- if err := printComponentStatus(&item, w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printThirdPartyResource(rsrc *extensions.ThirdPartyResource, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, rsrc.Name, options.WithKind)
- versions := make([]string, len(rsrc.Versions))
- for ix := range rsrc.Versions {
- version := &rsrc.Versions[ix]
- versions[ix] = fmt.Sprintf("%s", version.Name)
- }
- versionsString := strings.Join(versions, ",")
- if _, err := fmt.Fprintf(w, "%s\t%s\t%s\n", name, rsrc.Description, versionsString); err != nil {
- return err
- }
- return nil
- }
- func printThirdPartyResourceList(list *extensions.ThirdPartyResourceList, w io.Writer, options PrintOptions) error {
- for _, item := range list.Items {
- if err := printThirdPartyResource(&item, w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func truncate(str string, maxLen int) string {
- if len(str) > maxLen {
- return str[0:maxLen] + "..."
- }
- return str
- }
- func printThirdPartyResourceData(rsrc *extensions.ThirdPartyResourceData, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, rsrc.Name, options.WithKind)
- l := labels.FormatLabels(rsrc.Labels)
- truncateCols := 50
- if options.Wide {
- truncateCols = 100
- }
- if _, err := fmt.Fprintf(w, "%s\t%s\t%s\n", name, l, truncate(string(rsrc.Data), truncateCols)); err != nil {
- return err
- }
- return nil
- }
- func printThirdPartyResourceDataList(list *extensions.ThirdPartyResourceDataList, w io.Writer, options PrintOptions) error {
- for _, item := range list.Items {
- if err := printThirdPartyResourceData(&item, w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printDeployment(deployment *extensions.Deployment, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, deployment.Name, options.WithKind)
- if options.WithNamespace {
- if _, err := fmt.Fprintf(w, "%s\t", deployment.Namespace); err != nil {
- return err
- }
- }
- desiredReplicas := deployment.Spec.Replicas
- currentReplicas := deployment.Status.Replicas
- updatedReplicas := deployment.Status.UpdatedReplicas
- availableReplicas := deployment.Status.AvailableReplicas
- age := translateTimestamp(deployment.CreationTimestamp)
- if _, err := fmt.Fprintf(w, "%s\t%d\t%d\t%d\t%d\t%s", name, desiredReplicas, currentReplicas, updatedReplicas, availableReplicas, age); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendLabels(deployment.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, deployment.Labels))
- return err
- }
- func printDeploymentList(list *extensions.DeploymentList, w io.Writer, options PrintOptions) error {
- for _, item := range list.Items {
- if err := printDeployment(&item, w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printHorizontalPodAutoscaler(hpa *autoscaling.HorizontalPodAutoscaler, w io.Writer, options PrintOptions) error {
- namespace := hpa.Namespace
- name := formatResourceName(options.Kind, hpa.Name, options.WithKind)
- reference := fmt.Sprintf("%s/%s",
- hpa.Spec.ScaleTargetRef.Kind,
- hpa.Spec.ScaleTargetRef.Name)
- target := "<unset>"
- if hpa.Spec.TargetCPUUtilizationPercentage != nil {
- target = fmt.Sprintf("%d%%", *hpa.Spec.TargetCPUUtilizationPercentage)
- }
- current := "<waiting>"
- if hpa.Status.CurrentCPUUtilizationPercentage != nil {
- current = fmt.Sprintf("%d%%", *hpa.Status.CurrentCPUUtilizationPercentage)
- }
- minPods := "<unset>"
- if hpa.Spec.MinReplicas != nil {
- minPods = fmt.Sprintf("%d", *hpa.Spec.MinReplicas)
- }
- maxPods := hpa.Spec.MaxReplicas
- if options.WithNamespace {
- if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
- return err
- }
- }
- if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%d\t%s",
- name,
- reference,
- target,
- current,
- minPods,
- maxPods,
- translateTimestamp(hpa.CreationTimestamp),
- ); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendLabels(hpa.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, hpa.Labels))
- return err
- }
- func printHorizontalPodAutoscalerList(list *autoscaling.HorizontalPodAutoscalerList, w io.Writer, options PrintOptions) error {
- for i := range list.Items {
- if err := printHorizontalPodAutoscaler(&list.Items[i], w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printConfigMap(configMap *api.ConfigMap, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, configMap.Name, options.WithKind)
- namespace := configMap.Namespace
- if options.WithNamespace {
- if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
- return err
- }
- }
- if _, err := fmt.Fprintf(w, "%s\t%v\t%s", name, len(configMap.Data), translateTimestamp(configMap.CreationTimestamp)); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendLabels(configMap.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, configMap.Labels))
- return err
- }
- func printConfigMapList(list *api.ConfigMapList, w io.Writer, options PrintOptions) error {
- for i := range list.Items {
- if err := printConfigMap(&list.Items[i], w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printPodSecurityPolicy(item *extensions.PodSecurityPolicy, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, item.Name, options.WithKind)
- _, 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,
- item.Spec.AllowedCapabilities, item.Spec.SELinux.Rule,
- item.Spec.RunAsUser.Rule, item.Spec.FSGroup.Rule, item.Spec.SupplementalGroups.Rule, item.Spec.ReadOnlyRootFilesystem, item.Spec.Volumes)
- return err
- }
- func printPodSecurityPolicyList(list *extensions.PodSecurityPolicyList, w io.Writer, options PrintOptions) error {
- for _, item := range list.Items {
- if err := printPodSecurityPolicy(&item, w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printNetworkPolicy(networkPolicy *extensions.NetworkPolicy, w io.Writer, options PrintOptions) error {
- name := formatResourceName(options.Kind, networkPolicy.Name, options.WithKind)
- namespace := networkPolicy.Namespace
- if options.WithNamespace {
- if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
- return err
- }
- }
- if _, err := fmt.Fprintf(w, "%s\t%v\t%s", name, unversioned.FormatLabelSelector(&networkPolicy.Spec.PodSelector), translateTimestamp(networkPolicy.CreationTimestamp)); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendLabels(networkPolicy.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, networkPolicy.Labels))
- return err
- }
- func printNetworkPolicyList(list *extensions.NetworkPolicyList, w io.Writer, options PrintOptions) error {
- for i := range list.Items {
- if err := printNetworkPolicy(&list.Items[i], w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func printStorageClass(sc *extensions.StorageClass, w io.Writer, options PrintOptions) error {
- name := sc.Name
- provtype := sc.Provisioner
- if _, err := fmt.Fprintf(w, "%s\t%s\t", name, provtype); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendLabels(sc.Labels, options.ColumnLabels)); err != nil {
- return err
- }
- if _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, sc.Labels)); err != nil {
- return err
- }
- return nil
- }
- func printStorageClassList(scList *extensions.StorageClassList, w io.Writer, options PrintOptions) error {
- for _, sc := range scList.Items {
- if err := printStorageClass(&sc, w, options); err != nil {
- return err
- }
- }
- return nil
- }
- func AppendLabels(itemLabels map[string]string, columnLabels []string) string {
- var buffer bytes.Buffer
- for _, cl := range columnLabels {
- buffer.WriteString(fmt.Sprint("\t"))
- if il, ok := itemLabels[cl]; ok {
- buffer.WriteString(fmt.Sprint(il))
- } else {
- buffer.WriteString("<none>")
- }
- }
- return buffer.String()
- }
- // Append all labels to a single column. We need this even when show-labels flag* is
- // false, since this adds newline delimiter to the end of each row.
- func AppendAllLabels(showLabels bool, itemLabels map[string]string) string {
- var buffer bytes.Buffer
- if showLabels {
- buffer.WriteString(fmt.Sprint("\t"))
- buffer.WriteString(labels.FormatLabels(itemLabels))
- }
- buffer.WriteString("\n")
- return buffer.String()
- }
- // Append a set of tabs for each label column. We need this in the case where
- // we have extra lines so that the tabwriter will still line things up.
- func AppendLabelTabs(columnLabels []string) string {
- var buffer bytes.Buffer
- for range columnLabels {
- buffer.WriteString("\t")
- }
- buffer.WriteString("\n")
- return buffer.String()
- }
- // Lay out all the containers on one line if use wide output.
- func layoutContainers(containers []api.Container, w io.Writer) error {
- var namesBuffer bytes.Buffer
- var imagesBuffer bytes.Buffer
- for i, container := range containers {
- namesBuffer.WriteString(container.Name)
- imagesBuffer.WriteString(container.Image)
- if i != len(containers)-1 {
- namesBuffer.WriteString(",")
- imagesBuffer.WriteString(",")
- }
- }
- _, err := fmt.Fprintf(w, "\t%s\t%s", namesBuffer.String(), imagesBuffer.String())
- if err != nil {
- return err
- }
- return nil
- }
- func formatLabelHeaders(columnLabels []string) []string {
- formHead := make([]string, len(columnLabels))
- for i, l := range columnLabels {
- p := strings.Split(l, "/")
- formHead[i] = strings.ToUpper((p[len(p)-1]))
- }
- return formHead
- }
- // headers for -o wide
- func formatWideHeaders(wide bool, t reflect.Type) []string {
- if wide {
- if t.String() == "*api.Pod" || t.String() == "*api.PodList" {
- return []string{"IP", "NODE"}
- }
- if t.String() == "*api.ReplicationController" || t.String() == "*api.ReplicationControllerList" {
- return []string{"CONTAINER(S)", "IMAGE(S)", "SELECTOR"}
- }
- if t.String() == "*batch.Job" || t.String() == "*batch.JobList" {
- return []string{"CONTAINER(S)", "IMAGE(S)", "SELECTOR"}
- }
- if t.String() == "*api.Service" || t.String() == "*api.ServiceList" {
- return []string{"SELECTOR"}
- }
- if t.String() == "*extensions.DaemonSet" || t.String() == "*extensions.DaemonSetList" {
- return []string{"CONTAINER(S)", "IMAGE(S)", "SELECTOR"}
- }
- if t.String() == "*extensions.ReplicaSet" || t.String() == "*extensions.ReplicaSetList" {
- return []string{"CONTAINER(S)", "IMAGE(S)", "SELECTOR"}
- }
- }
- return nil
- }
- // headers for --show-labels=true
- func formatShowLabelsHeader(showLabels bool, t reflect.Type) []string {
- if showLabels {
- if t.String() != "*api.ThirdPartyResource" && t.String() != "*api.ThirdPartyResourceList" {
- return []string{"LABELS"}
- }
- }
- return nil
- }
- // GetNewTabWriter returns a tabwriter that translates tabbed columns in input into properly aligned text.
- func GetNewTabWriter(output io.Writer) *tabwriter.Writer {
- return tabwriter.NewWriter(output, tabwriterMinWidth, tabwriterWidth, tabwriterPadding, tabwriterPadChar, tabwriterFlags)
- }
- // PrintObj prints the obj in a human-friendly format according to the type of the obj.
- func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) error {
- // if output is a tabwriter (when it's called by kubectl get), we use it; create a new tabwriter otherwise
- w, found := output.(*tabwriter.Writer)
- if !found {
- w = GetNewTabWriter(output)
- defer w.Flush()
- }
- t := reflect.TypeOf(obj)
- if handler := h.handlerMap[t]; handler != nil {
- if !h.options.NoHeaders && t != h.lastType {
- headers := append(handler.columns, formatWideHeaders(h.options.Wide, t)...)
- headers = append(headers, formatLabelHeaders(h.options.ColumnLabels)...)
- // LABELS is always the last column.
- headers = append(headers, formatShowLabelsHeader(h.options.ShowLabels, t)...)
- if h.options.WithNamespace {
- headers = append(withNamespacePrefixColumns, headers...)
- }
- h.printHeader(headers, w)
- h.lastType = t
- }
- args := []reflect.Value{reflect.ValueOf(obj), reflect.ValueOf(w), reflect.ValueOf(h.options)}
- resultValue := handler.printFunc.Call(args)[0]
- if resultValue.IsNil() {
- return nil
- }
- return resultValue.Interface().(error)
- }
- return fmt.Errorf("error: unknown type %#v", obj)
- }
- // TemplatePrinter is an implementation of ResourcePrinter which formats data with a Go Template.
- type TemplatePrinter struct {
- rawTemplate string
- template *template.Template
- }
- func NewTemplatePrinter(tmpl []byte) (*TemplatePrinter, error) {
- t, err := template.New("output").
- Funcs(template.FuncMap{"exists": exists}).
- Parse(string(tmpl))
- if err != nil {
- return nil, err
- }
- return &TemplatePrinter{
- rawTemplate: string(tmpl),
- template: t,
- }, nil
- }
- func (p *TemplatePrinter) FinishPrint(w io.Writer, res string) error {
- return nil
- }
- // PrintObj formats the obj with the Go Template.
- func (p *TemplatePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
- data, err := json.Marshal(obj)
- if err != nil {
- return err
- }
- out := map[string]interface{}{}
- if err := json.Unmarshal(data, &out); err != nil {
- return err
- }
- if err = p.safeExecute(w, out); err != nil {
- // It is way easier to debug this stuff when it shows up in
- // stdout instead of just stdin. So in addition to returning
- // a nice error, also print useful stuff with the writer.
- fmt.Fprintf(w, "Error executing template: %v. Printing more information for debugging the template:\n", err)
- fmt.Fprintf(w, "\ttemplate was:\n\t\t%v\n", p.rawTemplate)
- fmt.Fprintf(w, "\traw data was:\n\t\t%v\n", string(data))
- fmt.Fprintf(w, "\tobject given to template engine was:\n\t\t%+v\n\n", out)
- return fmt.Errorf("error executing template %q: %v", p.rawTemplate, err)
- }
- return nil
- }
- // TODO: implement HandledResources()
- func (p *TemplatePrinter) HandledResources() []string {
- return []string{}
- }
- // safeExecute tries to execute the template, but catches panics and returns an error
- // should the template engine panic.
- func (p *TemplatePrinter) safeExecute(w io.Writer, obj interface{}) error {
- var panicErr error
- // Sorry for the double anonymous function. There's probably a clever way
- // to do this that has the defer'd func setting the value to be returned, but
- // that would be even less obvious.
- retErr := func() error {
- defer func() {
- if x := recover(); x != nil {
- panicErr = fmt.Errorf("caught panic: %+v", x)
- }
- }()
- return p.template.Execute(w, obj)
- }()
- if panicErr != nil {
- return panicErr
- }
- return retErr
- }
- func tabbedString(f func(io.Writer) error) (string, error) {
- out := new(tabwriter.Writer)
- buf := &bytes.Buffer{}
- out.Init(buf, 0, 8, 1, '\t', 0)
- err := f(out)
- if err != nil {
- return "", err
- }
- out.Flush()
- str := string(buf.String())
- return str, nil
- }
- // exists returns true if it would be possible to call the index function
- // with these arguments.
- //
- // TODO: how to document this for users?
- //
- // index returns the result of indexing its first argument by the following
- // arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each
- // indexed item must be a map, slice, or array.
- func exists(item interface{}, indices ...interface{}) bool {
- v := reflect.ValueOf(item)
- for _, i := range indices {
- index := reflect.ValueOf(i)
- var isNil bool
- if v, isNil = indirect(v); isNil {
- return false
- }
- switch v.Kind() {
- case reflect.Array, reflect.Slice, reflect.String:
- var x int64
- switch index.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- x = index.Int()
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- x = int64(index.Uint())
- default:
- return false
- }
- if x < 0 || x >= int64(v.Len()) {
- return false
- }
- v = v.Index(int(x))
- case reflect.Map:
- if !index.IsValid() {
- index = reflect.Zero(v.Type().Key())
- }
- if !index.Type().AssignableTo(v.Type().Key()) {
- return false
- }
- if x := v.MapIndex(index); x.IsValid() {
- v = x
- } else {
- v = reflect.Zero(v.Type().Elem())
- }
- default:
- return false
- }
- }
- if _, isNil := indirect(v); isNil {
- return false
- }
- return true
- }
- // stolen from text/template
- // indirect returns the item at the end of indirection, and a bool to indicate if it's nil.
- // We indirect through pointers and empty interfaces (only) because
- // non-empty interfaces have methods we might need.
- func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
- for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
- if v.IsNil() {
- return v, true
- }
- if v.Kind() == reflect.Interface && v.NumMethod() > 0 {
- break
- }
- }
- return v, false
- }
- // JSONPathPrinter is an implementation of ResourcePrinter which formats data with jsonpath expression.
- type JSONPathPrinter struct {
- rawTemplate string
- *jsonpath.JSONPath
- }
- func NewJSONPathPrinter(tmpl string) (*JSONPathPrinter, error) {
- j := jsonpath.New("out")
- if err := j.Parse(tmpl); err != nil {
- return nil, err
- }
- return &JSONPathPrinter{tmpl, j}, nil
- }
- func (j *JSONPathPrinter) FinishPrint(w io.Writer, res string) error {
- return nil
- }
- // PrintObj formats the obj with the JSONPath Template.
- func (j *JSONPathPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
- var queryObj interface{} = obj
- if meta.IsListType(obj) {
- data, err := json.Marshal(obj)
- if err != nil {
- return err
- }
- queryObj = map[string]interface{}{}
- if err := json.Unmarshal(data, &queryObj); err != nil {
- return err
- }
- }
- if err := j.JSONPath.Execute(w, queryObj); err != nil {
- fmt.Fprintf(w, "Error executing template: %v. Printing more information for debugging the template:\n", err)
- fmt.Fprintf(w, "\ttemplate was:\n\t\t%v\n", j.rawTemplate)
- fmt.Fprintf(w, "\tobject given to jsonpath engine was:\n\t\t%#v\n\n", queryObj)
- return fmt.Errorf("error executing jsonpath %q: %v\n", j.rawTemplate, err)
- }
- return nil
- }
- // TODO: implement HandledResources()
- func (p *JSONPathPrinter) HandledResources() []string {
- return []string{}
- }
|