describe.go 157 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556
  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 versioned
  14. import (
  15. "bytes"
  16. "crypto/x509"
  17. "fmt"
  18. "io"
  19. "net"
  20. "net/url"
  21. "reflect"
  22. "sort"
  23. "strconv"
  24. "strings"
  25. "text/tabwriter"
  26. "time"
  27. "unicode"
  28. "github.com/fatih/camelcase"
  29. appsv1 "k8s.io/api/apps/v1"
  30. autoscalingv1 "k8s.io/api/autoscaling/v1"
  31. autoscalingv2beta2 "k8s.io/api/autoscaling/v2beta2"
  32. batchv1 "k8s.io/api/batch/v1"
  33. batchv1beta1 "k8s.io/api/batch/v1beta1"
  34. certificatesv1beta1 "k8s.io/api/certificates/v1beta1"
  35. corev1 "k8s.io/api/core/v1"
  36. extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
  37. networkingv1 "k8s.io/api/networking/v1"
  38. networkingv1beta1 "k8s.io/api/networking/v1beta1"
  39. policyv1beta1 "k8s.io/api/policy/v1beta1"
  40. rbacv1 "k8s.io/api/rbac/v1"
  41. schedulingv1 "k8s.io/api/scheduling/v1"
  42. storagev1 "k8s.io/api/storage/v1"
  43. "k8s.io/apimachinery/pkg/api/errors"
  44. "k8s.io/apimachinery/pkg/api/meta"
  45. "k8s.io/apimachinery/pkg/api/resource"
  46. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  47. "k8s.io/apimachinery/pkg/fields"
  48. "k8s.io/apimachinery/pkg/labels"
  49. "k8s.io/apimachinery/pkg/runtime/schema"
  50. "k8s.io/apimachinery/pkg/types"
  51. "k8s.io/apimachinery/pkg/util/duration"
  52. "k8s.io/apimachinery/pkg/util/intstr"
  53. "k8s.io/apimachinery/pkg/util/sets"
  54. "k8s.io/cli-runtime/pkg/genericclioptions"
  55. "k8s.io/client-go/dynamic"
  56. clientset "k8s.io/client-go/kubernetes"
  57. corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
  58. "k8s.io/client-go/rest"
  59. "k8s.io/client-go/tools/reference"
  60. "k8s.io/klog"
  61. "k8s.io/kubernetes/pkg/kubectl/describe"
  62. "k8s.io/kubernetes/pkg/kubectl/scheme"
  63. "k8s.io/kubernetes/pkg/kubectl/util/certificate"
  64. deploymentutil "k8s.io/kubernetes/pkg/kubectl/util/deployment"
  65. "k8s.io/kubernetes/pkg/kubectl/util/event"
  66. "k8s.io/kubernetes/pkg/kubectl/util/fieldpath"
  67. "k8s.io/kubernetes/pkg/kubectl/util/qos"
  68. "k8s.io/kubernetes/pkg/kubectl/util/rbac"
  69. resourcehelper "k8s.io/kubernetes/pkg/kubectl/util/resource"
  70. "k8s.io/kubernetes/pkg/kubectl/util/slice"
  71. storageutil "k8s.io/kubernetes/pkg/kubectl/util/storage"
  72. )
  73. // Each level has 2 spaces for PrefixWriter
  74. const (
  75. LEVEL_0 = iota
  76. LEVEL_1
  77. LEVEL_2
  78. LEVEL_3
  79. )
  80. // DescriberFn gives a way to easily override the function for unit testing if needed
  81. var DescriberFn describe.DescriberFunc = Describer
  82. // Describer returns a Describer for displaying the specified RESTMapping type or an error.
  83. func Describer(restClientGetter genericclioptions.RESTClientGetter, mapping *meta.RESTMapping) (describe.Describer, error) {
  84. clientConfig, err := restClientGetter.ToRESTConfig()
  85. if err != nil {
  86. return nil, err
  87. }
  88. // try to get a describer
  89. if describer, ok := DescriberFor(mapping.GroupVersionKind.GroupKind(), clientConfig); ok {
  90. return describer, nil
  91. }
  92. // if this is a kind we don't have a describer for yet, go generic if possible
  93. if genericDescriber, ok := GenericDescriberFor(mapping, clientConfig); ok {
  94. return genericDescriber, nil
  95. }
  96. // otherwise return an unregistered error
  97. return nil, fmt.Errorf("no description has been implemented for %s", mapping.GroupVersionKind.String())
  98. }
  99. // PrefixWriter can write text at various indentation levels.
  100. type PrefixWriter interface {
  101. // Write writes text with the specified indentation level.
  102. Write(level int, format string, a ...interface{})
  103. // WriteLine writes an entire line with no indentation level.
  104. WriteLine(a ...interface{})
  105. // Flush forces indentation to be reset.
  106. Flush()
  107. }
  108. // prefixWriter implements PrefixWriter
  109. type prefixWriter struct {
  110. out io.Writer
  111. }
  112. var _ PrefixWriter = &prefixWriter{}
  113. // NewPrefixWriter creates a new PrefixWriter.
  114. func NewPrefixWriter(out io.Writer) PrefixWriter {
  115. return &prefixWriter{out: out}
  116. }
  117. func (pw *prefixWriter) Write(level int, format string, a ...interface{}) {
  118. levelSpace := " "
  119. prefix := ""
  120. for i := 0; i < level; i++ {
  121. prefix += levelSpace
  122. }
  123. fmt.Fprintf(pw.out, prefix+format, a...)
  124. }
  125. func (pw *prefixWriter) WriteLine(a ...interface{}) {
  126. fmt.Fprintln(pw.out, a...)
  127. }
  128. func (pw *prefixWriter) Flush() {
  129. if f, ok := pw.out.(flusher); ok {
  130. f.Flush()
  131. }
  132. }
  133. func describerMap(clientConfig *rest.Config) (map[schema.GroupKind]describe.Describer, error) {
  134. c, err := clientset.NewForConfig(clientConfig)
  135. if err != nil {
  136. return nil, err
  137. }
  138. m := map[schema.GroupKind]describe.Describer{
  139. {Group: corev1.GroupName, Kind: "Pod"}: &PodDescriber{c},
  140. {Group: corev1.GroupName, Kind: "ReplicationController"}: &ReplicationControllerDescriber{c},
  141. {Group: corev1.GroupName, Kind: "Secret"}: &SecretDescriber{c},
  142. {Group: corev1.GroupName, Kind: "Service"}: &ServiceDescriber{c},
  143. {Group: corev1.GroupName, Kind: "ServiceAccount"}: &ServiceAccountDescriber{c},
  144. {Group: corev1.GroupName, Kind: "Node"}: &NodeDescriber{c},
  145. {Group: corev1.GroupName, Kind: "LimitRange"}: &LimitRangeDescriber{c},
  146. {Group: corev1.GroupName, Kind: "ResourceQuota"}: &ResourceQuotaDescriber{c},
  147. {Group: corev1.GroupName, Kind: "PersistentVolume"}: &PersistentVolumeDescriber{c},
  148. {Group: corev1.GroupName, Kind: "PersistentVolumeClaim"}: &PersistentVolumeClaimDescriber{c},
  149. {Group: corev1.GroupName, Kind: "Namespace"}: &NamespaceDescriber{c},
  150. {Group: corev1.GroupName, Kind: "Endpoints"}: &EndpointsDescriber{c},
  151. {Group: corev1.GroupName, Kind: "ConfigMap"}: &ConfigMapDescriber{c},
  152. {Group: corev1.GroupName, Kind: "PriorityClass"}: &PriorityClassDescriber{c},
  153. {Group: extensionsv1beta1.GroupName, Kind: "ReplicaSet"}: &ReplicaSetDescriber{c},
  154. {Group: extensionsv1beta1.GroupName, Kind: "NetworkPolicy"}: &NetworkPolicyDescriber{c},
  155. {Group: extensionsv1beta1.GroupName, Kind: "PodSecurityPolicy"}: &PodSecurityPolicyDescriber{c},
  156. {Group: autoscalingv2beta2.GroupName, Kind: "HorizontalPodAutoscaler"}: &HorizontalPodAutoscalerDescriber{c},
  157. {Group: extensionsv1beta1.GroupName, Kind: "DaemonSet"}: &DaemonSetDescriber{c},
  158. {Group: extensionsv1beta1.GroupName, Kind: "Deployment"}: &DeploymentDescriber{c},
  159. {Group: extensionsv1beta1.GroupName, Kind: "Ingress"}: &IngressDescriber{c},
  160. {Group: networkingv1beta1.GroupName, Kind: "Ingress"}: &IngressDescriber{c},
  161. {Group: batchv1.GroupName, Kind: "Job"}: &JobDescriber{c},
  162. {Group: batchv1.GroupName, Kind: "CronJob"}: &CronJobDescriber{c},
  163. {Group: appsv1.GroupName, Kind: "StatefulSet"}: &StatefulSetDescriber{c},
  164. {Group: appsv1.GroupName, Kind: "Deployment"}: &DeploymentDescriber{c},
  165. {Group: appsv1.GroupName, Kind: "DaemonSet"}: &DaemonSetDescriber{c},
  166. {Group: appsv1.GroupName, Kind: "ReplicaSet"}: &ReplicaSetDescriber{c},
  167. {Group: certificatesv1beta1.GroupName, Kind: "CertificateSigningRequest"}: &CertificateSigningRequestDescriber{c},
  168. {Group: storagev1.GroupName, Kind: "StorageClass"}: &StorageClassDescriber{c},
  169. {Group: policyv1beta1.GroupName, Kind: "PodDisruptionBudget"}: &PodDisruptionBudgetDescriber{c},
  170. {Group: rbacv1.GroupName, Kind: "Role"}: &RoleDescriber{c},
  171. {Group: rbacv1.GroupName, Kind: "ClusterRole"}: &ClusterRoleDescriber{c},
  172. {Group: rbacv1.GroupName, Kind: "RoleBinding"}: &RoleBindingDescriber{c},
  173. {Group: rbacv1.GroupName, Kind: "ClusterRoleBinding"}: &ClusterRoleBindingDescriber{c},
  174. {Group: networkingv1.GroupName, Kind: "NetworkPolicy"}: &NetworkPolicyDescriber{c},
  175. {Group: schedulingv1.GroupName, Kind: "PriorityClass"}: &PriorityClassDescriber{c},
  176. }
  177. return m, nil
  178. }
  179. // DescriberFor returns the default describe functions for each of the standard
  180. // Kubernetes types.
  181. func DescriberFor(kind schema.GroupKind, clientConfig *rest.Config) (describe.Describer, bool) {
  182. describers, err := describerMap(clientConfig)
  183. if err != nil {
  184. klog.V(1).Info(err)
  185. return nil, false
  186. }
  187. f, ok := describers[kind]
  188. return f, ok
  189. }
  190. // GenericDescriberFor returns a generic describer for the specified mapping
  191. // that uses only information available from runtime.Unstructured
  192. func GenericDescriberFor(mapping *meta.RESTMapping, clientConfig *rest.Config) (describe.Describer, bool) {
  193. // used to fetch the resource
  194. dynamicClient, err := dynamic.NewForConfig(clientConfig)
  195. if err != nil {
  196. return nil, false
  197. }
  198. // used to get events for the resource
  199. clientSet, err := clientset.NewForConfig(clientConfig)
  200. if err != nil {
  201. return nil, false
  202. }
  203. eventsClient := clientSet.CoreV1()
  204. return &genericDescriber{mapping, dynamicClient, eventsClient}, true
  205. }
  206. type genericDescriber struct {
  207. mapping *meta.RESTMapping
  208. dynamic dynamic.Interface
  209. events corev1client.EventsGetter
  210. }
  211. func (g *genericDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (output string, err error) {
  212. obj, err := g.dynamic.Resource(g.mapping.Resource).Namespace(namespace).Get(name, metav1.GetOptions{})
  213. if err != nil {
  214. return "", err
  215. }
  216. var events *corev1.EventList
  217. if describerSettings.ShowEvents {
  218. events, _ = g.events.Events(namespace).Search(scheme.Scheme, obj)
  219. }
  220. return tabbedString(func(out io.Writer) error {
  221. w := NewPrefixWriter(out)
  222. w.Write(LEVEL_0, "Name:\t%s\n", obj.GetName())
  223. w.Write(LEVEL_0, "Namespace:\t%s\n", obj.GetNamespace())
  224. printLabelsMultiline(w, "Labels", obj.GetLabels())
  225. printAnnotationsMultiline(w, "Annotations", obj.GetAnnotations())
  226. printUnstructuredContent(w, LEVEL_0, obj.UnstructuredContent(), "", ".metadata.name", ".metadata.namespace", ".metadata.labels", ".metadata.annotations")
  227. if events != nil {
  228. DescribeEvents(events, w)
  229. }
  230. return nil
  231. })
  232. }
  233. func printUnstructuredContent(w PrefixWriter, level int, content map[string]interface{}, skipPrefix string, skip ...string) {
  234. fields := []string{}
  235. for field := range content {
  236. fields = append(fields, field)
  237. }
  238. sort.Strings(fields)
  239. for _, field := range fields {
  240. value := content[field]
  241. switch typedValue := value.(type) {
  242. case map[string]interface{}:
  243. skipExpr := fmt.Sprintf("%s.%s", skipPrefix, field)
  244. if slice.ContainsString(skip, skipExpr, nil) {
  245. continue
  246. }
  247. w.Write(level, "%s:\n", smartLabelFor(field))
  248. printUnstructuredContent(w, level+1, typedValue, skipExpr, skip...)
  249. case []interface{}:
  250. skipExpr := fmt.Sprintf("%s.%s", skipPrefix, field)
  251. if slice.ContainsString(skip, skipExpr, nil) {
  252. continue
  253. }
  254. w.Write(level, "%s:\n", smartLabelFor(field))
  255. for _, child := range typedValue {
  256. switch typedChild := child.(type) {
  257. case map[string]interface{}:
  258. printUnstructuredContent(w, level+1, typedChild, skipExpr, skip...)
  259. default:
  260. w.Write(level+1, "%v\n", typedChild)
  261. }
  262. }
  263. default:
  264. skipExpr := fmt.Sprintf("%s.%s", skipPrefix, field)
  265. if slice.ContainsString(skip, skipExpr, nil) {
  266. continue
  267. }
  268. w.Write(level, "%s:\t%v\n", smartLabelFor(field), typedValue)
  269. }
  270. }
  271. }
  272. func smartLabelFor(field string) string {
  273. // skip creating smart label if field name contains
  274. // special characters other than '-'
  275. if strings.IndexFunc(field, func(r rune) bool {
  276. return !unicode.IsLetter(r) && r != '-'
  277. }) != -1 {
  278. return field
  279. }
  280. commonAcronyms := []string{"API", "URL", "UID", "OSB", "GUID"}
  281. parts := camelcase.Split(field)
  282. result := make([]string, 0, len(parts))
  283. for _, part := range parts {
  284. if part == "_" {
  285. continue
  286. }
  287. if slice.ContainsString(commonAcronyms, strings.ToUpper(part), nil) {
  288. part = strings.ToUpper(part)
  289. } else {
  290. part = strings.Title(part)
  291. }
  292. result = append(result, part)
  293. }
  294. return strings.Join(result, " ")
  295. }
  296. // DefaultObjectDescriber can describe the default Kubernetes objects.
  297. var DefaultObjectDescriber describe.ObjectDescriber
  298. func init() {
  299. d := &Describers{}
  300. err := d.Add(
  301. describeLimitRange,
  302. describeQuota,
  303. describePod,
  304. describeService,
  305. describeReplicationController,
  306. describeDaemonSet,
  307. describeNode,
  308. describeNamespace,
  309. )
  310. if err != nil {
  311. klog.Fatalf("Cannot register describers: %v", err)
  312. }
  313. DefaultObjectDescriber = d
  314. }
  315. // NamespaceDescriber generates information about a namespace
  316. type NamespaceDescriber struct {
  317. clientset.Interface
  318. }
  319. func (d *NamespaceDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  320. ns, err := d.CoreV1().Namespaces().Get(name, metav1.GetOptions{})
  321. if err != nil {
  322. return "", err
  323. }
  324. resourceQuotaList, err := d.CoreV1().ResourceQuotas(name).List(metav1.ListOptions{})
  325. if err != nil {
  326. if errors.IsNotFound(err) {
  327. // Server does not support resource quotas.
  328. // Not an error, will not show resource quotas information.
  329. resourceQuotaList = nil
  330. } else {
  331. return "", err
  332. }
  333. }
  334. limitRangeList, err := d.CoreV1().LimitRanges(name).List(metav1.ListOptions{})
  335. if err != nil {
  336. if errors.IsNotFound(err) {
  337. // Server does not support limit ranges.
  338. // Not an error, will not show limit ranges information.
  339. limitRangeList = nil
  340. } else {
  341. return "", err
  342. }
  343. }
  344. return describeNamespace(ns, resourceQuotaList, limitRangeList)
  345. }
  346. func describeNamespace(namespace *corev1.Namespace, resourceQuotaList *corev1.ResourceQuotaList, limitRangeList *corev1.LimitRangeList) (string, error) {
  347. return tabbedString(func(out io.Writer) error {
  348. w := NewPrefixWriter(out)
  349. w.Write(LEVEL_0, "Name:\t%s\n", namespace.Name)
  350. printLabelsMultiline(w, "Labels", namespace.Labels)
  351. printAnnotationsMultiline(w, "Annotations", namespace.Annotations)
  352. w.Write(LEVEL_0, "Status:\t%s\n", string(namespace.Status.Phase))
  353. if resourceQuotaList != nil {
  354. w.Write(LEVEL_0, "\n")
  355. DescribeResourceQuotas(resourceQuotaList, w)
  356. }
  357. if limitRangeList != nil {
  358. w.Write(LEVEL_0, "\n")
  359. DescribeLimitRanges(limitRangeList, w)
  360. }
  361. return nil
  362. })
  363. }
  364. func describeLimitRangeSpec(spec corev1.LimitRangeSpec, prefix string, w PrefixWriter) {
  365. for i := range spec.Limits {
  366. item := spec.Limits[i]
  367. maxResources := item.Max
  368. minResources := item.Min
  369. defaultLimitResources := item.Default
  370. defaultRequestResources := item.DefaultRequest
  371. ratio := item.MaxLimitRequestRatio
  372. set := map[corev1.ResourceName]bool{}
  373. for k := range maxResources {
  374. set[k] = true
  375. }
  376. for k := range minResources {
  377. set[k] = true
  378. }
  379. for k := range defaultLimitResources {
  380. set[k] = true
  381. }
  382. for k := range defaultRequestResources {
  383. set[k] = true
  384. }
  385. for k := range ratio {
  386. set[k] = true
  387. }
  388. for k := range set {
  389. // if no value is set, we output -
  390. maxValue := "-"
  391. minValue := "-"
  392. defaultLimitValue := "-"
  393. defaultRequestValue := "-"
  394. ratioValue := "-"
  395. maxQuantity, maxQuantityFound := maxResources[k]
  396. if maxQuantityFound {
  397. maxValue = maxQuantity.String()
  398. }
  399. minQuantity, minQuantityFound := minResources[k]
  400. if minQuantityFound {
  401. minValue = minQuantity.String()
  402. }
  403. defaultLimitQuantity, defaultLimitQuantityFound := defaultLimitResources[k]
  404. if defaultLimitQuantityFound {
  405. defaultLimitValue = defaultLimitQuantity.String()
  406. }
  407. defaultRequestQuantity, defaultRequestQuantityFound := defaultRequestResources[k]
  408. if defaultRequestQuantityFound {
  409. defaultRequestValue = defaultRequestQuantity.String()
  410. }
  411. ratioQuantity, ratioQuantityFound := ratio[k]
  412. if ratioQuantityFound {
  413. ratioValue = ratioQuantity.String()
  414. }
  415. msg := "%s%s\t%v\t%v\t%v\t%v\t%v\t%v\n"
  416. w.Write(LEVEL_0, msg, prefix, item.Type, k, minValue, maxValue, defaultRequestValue, defaultLimitValue, ratioValue)
  417. }
  418. }
  419. }
  420. // DescribeLimitRanges merges a set of limit range items into a single tabular description
  421. func DescribeLimitRanges(limitRanges *corev1.LimitRangeList, w PrefixWriter) {
  422. if len(limitRanges.Items) == 0 {
  423. w.Write(LEVEL_0, "No resource limits.\n")
  424. return
  425. }
  426. w.Write(LEVEL_0, "Resource Limits\n Type\tResource\tMin\tMax\tDefault Request\tDefault Limit\tMax Limit/Request Ratio\n")
  427. w.Write(LEVEL_0, " ----\t--------\t---\t---\t---------------\t-------------\t-----------------------\n")
  428. for _, limitRange := range limitRanges.Items {
  429. describeLimitRangeSpec(limitRange.Spec, " ", w)
  430. }
  431. }
  432. // DescribeResourceQuotas merges a set of quota items into a single tabular description of all quotas
  433. func DescribeResourceQuotas(quotas *corev1.ResourceQuotaList, w PrefixWriter) {
  434. if len(quotas.Items) == 0 {
  435. w.Write(LEVEL_0, "No resource quota.\n")
  436. return
  437. }
  438. sort.Sort(SortableResourceQuotas(quotas.Items))
  439. w.Write(LEVEL_0, "Resource Quotas")
  440. for _, q := range quotas.Items {
  441. w.Write(LEVEL_0, "\n Name:\t%s\n", q.Name)
  442. if len(q.Spec.Scopes) > 0 {
  443. scopes := make([]string, 0, len(q.Spec.Scopes))
  444. for _, scope := range q.Spec.Scopes {
  445. scopes = append(scopes, string(scope))
  446. }
  447. sort.Strings(scopes)
  448. w.Write(LEVEL_0, " Scopes:\t%s\n", strings.Join(scopes, ", "))
  449. for _, scope := range scopes {
  450. helpText := helpTextForResourceQuotaScope(corev1.ResourceQuotaScope(scope))
  451. if len(helpText) > 0 {
  452. w.Write(LEVEL_0, " * %s\n", helpText)
  453. }
  454. }
  455. }
  456. w.Write(LEVEL_0, " Resource\tUsed\tHard\n")
  457. w.Write(LEVEL_0, " --------\t---\t---\n")
  458. resources := make([]corev1.ResourceName, 0, len(q.Status.Hard))
  459. for resource := range q.Status.Hard {
  460. resources = append(resources, resource)
  461. }
  462. sort.Sort(SortableResourceNames(resources))
  463. for _, resource := range resources {
  464. hardQuantity := q.Status.Hard[resource]
  465. usedQuantity := q.Status.Used[resource]
  466. w.Write(LEVEL_0, " %s\t%s\t%s\n", string(resource), usedQuantity.String(), hardQuantity.String())
  467. }
  468. }
  469. }
  470. // LimitRangeDescriber generates information about a limit range
  471. type LimitRangeDescriber struct {
  472. clientset.Interface
  473. }
  474. func (d *LimitRangeDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  475. lr := d.CoreV1().LimitRanges(namespace)
  476. limitRange, err := lr.Get(name, metav1.GetOptions{})
  477. if err != nil {
  478. return "", err
  479. }
  480. return describeLimitRange(limitRange)
  481. }
  482. func describeLimitRange(limitRange *corev1.LimitRange) (string, error) {
  483. return tabbedString(func(out io.Writer) error {
  484. w := NewPrefixWriter(out)
  485. w.Write(LEVEL_0, "Name:\t%s\n", limitRange.Name)
  486. w.Write(LEVEL_0, "Namespace:\t%s\n", limitRange.Namespace)
  487. w.Write(LEVEL_0, "Type\tResource\tMin\tMax\tDefault Request\tDefault Limit\tMax Limit/Request Ratio\n")
  488. w.Write(LEVEL_0, "----\t--------\t---\t---\t---------------\t-------------\t-----------------------\n")
  489. describeLimitRangeSpec(limitRange.Spec, "", w)
  490. return nil
  491. })
  492. }
  493. // ResourceQuotaDescriber generates information about a resource quota
  494. type ResourceQuotaDescriber struct {
  495. clientset.Interface
  496. }
  497. func (d *ResourceQuotaDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  498. rq := d.CoreV1().ResourceQuotas(namespace)
  499. resourceQuota, err := rq.Get(name, metav1.GetOptions{})
  500. if err != nil {
  501. return "", err
  502. }
  503. return describeQuota(resourceQuota)
  504. }
  505. func helpTextForResourceQuotaScope(scope corev1.ResourceQuotaScope) string {
  506. switch scope {
  507. case corev1.ResourceQuotaScopeTerminating:
  508. return "Matches all pods that have an active deadline. These pods have a limited lifespan on a node before being actively terminated by the system."
  509. case corev1.ResourceQuotaScopeNotTerminating:
  510. return "Matches all pods that do not have an active deadline. These pods usually include long running pods whose container command is not expected to terminate."
  511. case corev1.ResourceQuotaScopeBestEffort:
  512. return "Matches all pods that do not have resource requirements set. These pods have a best effort quality of service."
  513. case corev1.ResourceQuotaScopeNotBestEffort:
  514. return "Matches all pods that have at least one resource requirement set. These pods have a burstable or guaranteed quality of service."
  515. default:
  516. return ""
  517. }
  518. }
  519. func describeQuota(resourceQuota *corev1.ResourceQuota) (string, error) {
  520. return tabbedString(func(out io.Writer) error {
  521. w := NewPrefixWriter(out)
  522. w.Write(LEVEL_0, "Name:\t%s\n", resourceQuota.Name)
  523. w.Write(LEVEL_0, "Namespace:\t%s\n", resourceQuota.Namespace)
  524. if len(resourceQuota.Spec.Scopes) > 0 {
  525. scopes := make([]string, 0, len(resourceQuota.Spec.Scopes))
  526. for _, scope := range resourceQuota.Spec.Scopes {
  527. scopes = append(scopes, string(scope))
  528. }
  529. sort.Strings(scopes)
  530. w.Write(LEVEL_0, "Scopes:\t%s\n", strings.Join(scopes, ", "))
  531. for _, scope := range scopes {
  532. helpText := helpTextForResourceQuotaScope(corev1.ResourceQuotaScope(scope))
  533. if len(helpText) > 0 {
  534. w.Write(LEVEL_0, " * %s\n", helpText)
  535. }
  536. }
  537. }
  538. w.Write(LEVEL_0, "Resource\tUsed\tHard\n")
  539. w.Write(LEVEL_0, "--------\t----\t----\n")
  540. resources := make([]corev1.ResourceName, 0, len(resourceQuota.Status.Hard))
  541. for resource := range resourceQuota.Status.Hard {
  542. resources = append(resources, resource)
  543. }
  544. sort.Sort(SortableResourceNames(resources))
  545. msg := "%v\t%v\t%v\n"
  546. for i := range resources {
  547. resource := resources[i]
  548. hardQuantity := resourceQuota.Status.Hard[resource]
  549. usedQuantity := resourceQuota.Status.Used[resource]
  550. w.Write(LEVEL_0, msg, resource, usedQuantity.String(), hardQuantity.String())
  551. }
  552. return nil
  553. })
  554. }
  555. // PodDescriber generates information about a pod and the replication controllers that
  556. // create it.
  557. type PodDescriber struct {
  558. clientset.Interface
  559. }
  560. func (d *PodDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  561. pod, err := d.CoreV1().Pods(namespace).Get(name, metav1.GetOptions{})
  562. if err != nil {
  563. if describerSettings.ShowEvents {
  564. eventsInterface := d.CoreV1().Events(namespace)
  565. selector := eventsInterface.GetFieldSelector(&name, &namespace, nil, nil)
  566. options := metav1.ListOptions{FieldSelector: selector.String()}
  567. events, err2 := eventsInterface.List(options)
  568. if describerSettings.ShowEvents && err2 == nil && len(events.Items) > 0 {
  569. return tabbedString(func(out io.Writer) error {
  570. w := NewPrefixWriter(out)
  571. w.Write(LEVEL_0, "Pod '%v': error '%v', but found events.\n", name, err)
  572. DescribeEvents(events, w)
  573. return nil
  574. })
  575. }
  576. }
  577. return "", err
  578. }
  579. var events *corev1.EventList
  580. if describerSettings.ShowEvents {
  581. if ref, err := reference.GetReference(scheme.Scheme, pod); err != nil {
  582. klog.Errorf("Unable to construct reference to '%#v': %v", pod, err)
  583. } else {
  584. ref.Kind = ""
  585. if _, isMirrorPod := pod.Annotations[corev1.MirrorPodAnnotationKey]; isMirrorPod {
  586. ref.UID = types.UID(pod.Annotations[corev1.MirrorPodAnnotationKey])
  587. }
  588. events, _ = d.CoreV1().Events(namespace).Search(scheme.Scheme, ref)
  589. }
  590. }
  591. return describePod(pod, events)
  592. }
  593. func describePod(pod *corev1.Pod, events *corev1.EventList) (string, error) {
  594. return tabbedString(func(out io.Writer) error {
  595. w := NewPrefixWriter(out)
  596. w.Write(LEVEL_0, "Name:\t%s\n", pod.Name)
  597. w.Write(LEVEL_0, "Namespace:\t%s\n", pod.Namespace)
  598. if pod.Spec.Priority != nil {
  599. w.Write(LEVEL_0, "Priority:\t%d\n", *pod.Spec.Priority)
  600. }
  601. if len(pod.Spec.PriorityClassName) > 0 {
  602. w.Write(LEVEL_0, "Priority Class Name:\t%s\n", stringOrNone(pod.Spec.PriorityClassName))
  603. }
  604. if pod.Spec.NodeName == "" {
  605. w.Write(LEVEL_0, "Node:\t<none>\n")
  606. } else {
  607. w.Write(LEVEL_0, "Node:\t%s\n", pod.Spec.NodeName+"/"+pod.Status.HostIP)
  608. }
  609. if pod.Status.StartTime != nil {
  610. w.Write(LEVEL_0, "Start Time:\t%s\n", pod.Status.StartTime.Time.Format(time.RFC1123Z))
  611. }
  612. printLabelsMultiline(w, "Labels", pod.Labels)
  613. printAnnotationsMultiline(w, "Annotations", pod.Annotations)
  614. if pod.DeletionTimestamp != nil {
  615. w.Write(LEVEL_0, "Status:\tTerminating (lasts %s)\n", translateTimestampSince(*pod.DeletionTimestamp))
  616. w.Write(LEVEL_0, "Termination Grace Period:\t%ds\n", *pod.DeletionGracePeriodSeconds)
  617. } else {
  618. w.Write(LEVEL_0, "Status:\t%s\n", string(pod.Status.Phase))
  619. }
  620. if len(pod.Status.Reason) > 0 {
  621. w.Write(LEVEL_0, "Reason:\t%s\n", pod.Status.Reason)
  622. }
  623. if len(pod.Status.Message) > 0 {
  624. w.Write(LEVEL_0, "Message:\t%s\n", pod.Status.Message)
  625. }
  626. w.Write(LEVEL_0, "IP:\t%s\n", pod.Status.PodIP)
  627. if controlledBy := printController(pod); len(controlledBy) > 0 {
  628. w.Write(LEVEL_0, "Controlled By:\t%s\n", controlledBy)
  629. }
  630. if len(pod.Status.NominatedNodeName) > 0 {
  631. w.Write(LEVEL_0, "NominatedNodeName:\t%s\n", pod.Status.NominatedNodeName)
  632. }
  633. if len(pod.Spec.InitContainers) > 0 {
  634. describeContainers("Init Containers", pod.Spec.InitContainers, pod.Status.InitContainerStatuses, EnvValueRetriever(pod), w, "")
  635. }
  636. describeContainers("Containers", pod.Spec.Containers, pod.Status.ContainerStatuses, EnvValueRetriever(pod), w, "")
  637. if len(pod.Spec.ReadinessGates) > 0 {
  638. w.Write(LEVEL_0, "Readiness Gates:\n Type\tStatus\n")
  639. for _, g := range pod.Spec.ReadinessGates {
  640. status := "<none>"
  641. for _, c := range pod.Status.Conditions {
  642. if c.Type == g.ConditionType {
  643. status = fmt.Sprintf("%v", c.Status)
  644. break
  645. }
  646. }
  647. w.Write(LEVEL_1, "%v \t%v \n",
  648. g.ConditionType,
  649. status)
  650. }
  651. }
  652. if len(pod.Status.Conditions) > 0 {
  653. w.Write(LEVEL_0, "Conditions:\n Type\tStatus\n")
  654. for _, c := range pod.Status.Conditions {
  655. w.Write(LEVEL_1, "%v \t%v \n",
  656. c.Type,
  657. c.Status)
  658. }
  659. }
  660. describeVolumes(pod.Spec.Volumes, w, "")
  661. if pod.Status.QOSClass != "" {
  662. w.Write(LEVEL_0, "QoS Class:\t%s\n", pod.Status.QOSClass)
  663. } else {
  664. w.Write(LEVEL_0, "QoS Class:\t%s\n", qos.GetPodQOS(pod))
  665. }
  666. printLabelsMultiline(w, "Node-Selectors", pod.Spec.NodeSelector)
  667. printPodTolerationsMultiline(w, "Tolerations", pod.Spec.Tolerations)
  668. if events != nil {
  669. DescribeEvents(events, w)
  670. }
  671. return nil
  672. })
  673. }
  674. func printController(controllee metav1.Object) string {
  675. if controllerRef := metav1.GetControllerOf(controllee); controllerRef != nil {
  676. return fmt.Sprintf("%s/%s", controllerRef.Kind, controllerRef.Name)
  677. }
  678. return ""
  679. }
  680. func describeVolumes(volumes []corev1.Volume, w PrefixWriter, space string) {
  681. if volumes == nil || len(volumes) == 0 {
  682. w.Write(LEVEL_0, "%sVolumes:\t<none>\n", space)
  683. return
  684. }
  685. w.Write(LEVEL_0, "%sVolumes:\n", space)
  686. for _, volume := range volumes {
  687. nameIndent := ""
  688. if len(space) > 0 {
  689. nameIndent = " "
  690. }
  691. w.Write(LEVEL_1, "%s%v:\n", nameIndent, volume.Name)
  692. switch {
  693. case volume.VolumeSource.HostPath != nil:
  694. printHostPathVolumeSource(volume.VolumeSource.HostPath, w)
  695. case volume.VolumeSource.EmptyDir != nil:
  696. printEmptyDirVolumeSource(volume.VolumeSource.EmptyDir, w)
  697. case volume.VolumeSource.GCEPersistentDisk != nil:
  698. printGCEPersistentDiskVolumeSource(volume.VolumeSource.GCEPersistentDisk, w)
  699. case volume.VolumeSource.AWSElasticBlockStore != nil:
  700. printAWSElasticBlockStoreVolumeSource(volume.VolumeSource.AWSElasticBlockStore, w)
  701. case volume.VolumeSource.GitRepo != nil:
  702. printGitRepoVolumeSource(volume.VolumeSource.GitRepo, w)
  703. case volume.VolumeSource.Secret != nil:
  704. printSecretVolumeSource(volume.VolumeSource.Secret, w)
  705. case volume.VolumeSource.ConfigMap != nil:
  706. printConfigMapVolumeSource(volume.VolumeSource.ConfigMap, w)
  707. case volume.VolumeSource.NFS != nil:
  708. printNFSVolumeSource(volume.VolumeSource.NFS, w)
  709. case volume.VolumeSource.ISCSI != nil:
  710. printISCSIVolumeSource(volume.VolumeSource.ISCSI, w)
  711. case volume.VolumeSource.Glusterfs != nil:
  712. printGlusterfsVolumeSource(volume.VolumeSource.Glusterfs, w)
  713. case volume.VolumeSource.PersistentVolumeClaim != nil:
  714. printPersistentVolumeClaimVolumeSource(volume.VolumeSource.PersistentVolumeClaim, w)
  715. case volume.VolumeSource.RBD != nil:
  716. printRBDVolumeSource(volume.VolumeSource.RBD, w)
  717. case volume.VolumeSource.Quobyte != nil:
  718. printQuobyteVolumeSource(volume.VolumeSource.Quobyte, w)
  719. case volume.VolumeSource.DownwardAPI != nil:
  720. printDownwardAPIVolumeSource(volume.VolumeSource.DownwardAPI, w)
  721. case volume.VolumeSource.AzureDisk != nil:
  722. printAzureDiskVolumeSource(volume.VolumeSource.AzureDisk, w)
  723. case volume.VolumeSource.VsphereVolume != nil:
  724. printVsphereVolumeSource(volume.VolumeSource.VsphereVolume, w)
  725. case volume.VolumeSource.Cinder != nil:
  726. printCinderVolumeSource(volume.VolumeSource.Cinder, w)
  727. case volume.VolumeSource.PhotonPersistentDisk != nil:
  728. printPhotonPersistentDiskVolumeSource(volume.VolumeSource.PhotonPersistentDisk, w)
  729. case volume.VolumeSource.PortworxVolume != nil:
  730. printPortworxVolumeSource(volume.VolumeSource.PortworxVolume, w)
  731. case volume.VolumeSource.ScaleIO != nil:
  732. printScaleIOVolumeSource(volume.VolumeSource.ScaleIO, w)
  733. case volume.VolumeSource.CephFS != nil:
  734. printCephFSVolumeSource(volume.VolumeSource.CephFS, w)
  735. case volume.VolumeSource.StorageOS != nil:
  736. printStorageOSVolumeSource(volume.VolumeSource.StorageOS, w)
  737. case volume.VolumeSource.FC != nil:
  738. printFCVolumeSource(volume.VolumeSource.FC, w)
  739. case volume.VolumeSource.AzureFile != nil:
  740. printAzureFileVolumeSource(volume.VolumeSource.AzureFile, w)
  741. case volume.VolumeSource.FlexVolume != nil:
  742. printFlexVolumeSource(volume.VolumeSource.FlexVolume, w)
  743. case volume.VolumeSource.Flocker != nil:
  744. printFlockerVolumeSource(volume.VolumeSource.Flocker, w)
  745. case volume.VolumeSource.Projected != nil:
  746. printProjectedVolumeSource(volume.VolumeSource.Projected, w)
  747. case volume.VolumeSource.CSI != nil:
  748. printCSIVolumeSource(volume.VolumeSource.CSI, w)
  749. default:
  750. w.Write(LEVEL_1, "<unknown>\n")
  751. }
  752. }
  753. }
  754. func printHostPathVolumeSource(hostPath *corev1.HostPathVolumeSource, w PrefixWriter) {
  755. hostPathType := "<none>"
  756. if hostPath.Type != nil {
  757. hostPathType = string(*hostPath.Type)
  758. }
  759. w.Write(LEVEL_2, "Type:\tHostPath (bare host directory volume)\n"+
  760. " Path:\t%v\n"+
  761. " HostPathType:\t%v\n",
  762. hostPath.Path, hostPathType)
  763. }
  764. func printEmptyDirVolumeSource(emptyDir *corev1.EmptyDirVolumeSource, w PrefixWriter) {
  765. var sizeLimit string
  766. if emptyDir.SizeLimit != nil && emptyDir.SizeLimit.Cmp(resource.Quantity{}) > 0 {
  767. sizeLimit = fmt.Sprintf("%v", emptyDir.SizeLimit)
  768. } else {
  769. sizeLimit = "<unset>"
  770. }
  771. w.Write(LEVEL_2, "Type:\tEmptyDir (a temporary directory that shares a pod's lifetime)\n"+
  772. " Medium:\t%v\n"+
  773. " SizeLimit:\t%v\n",
  774. emptyDir.Medium, sizeLimit)
  775. }
  776. func printGCEPersistentDiskVolumeSource(gce *corev1.GCEPersistentDiskVolumeSource, w PrefixWriter) {
  777. w.Write(LEVEL_2, "Type:\tGCEPersistentDisk (a Persistent Disk resource in Google Compute Engine)\n"+
  778. " PDName:\t%v\n"+
  779. " FSType:\t%v\n"+
  780. " Partition:\t%v\n"+
  781. " ReadOnly:\t%v\n",
  782. gce.PDName, gce.FSType, gce.Partition, gce.ReadOnly)
  783. }
  784. func printAWSElasticBlockStoreVolumeSource(aws *corev1.AWSElasticBlockStoreVolumeSource, w PrefixWriter) {
  785. w.Write(LEVEL_2, "Type:\tAWSElasticBlockStore (a Persistent Disk resource in AWS)\n"+
  786. " VolumeID:\t%v\n"+
  787. " FSType:\t%v\n"+
  788. " Partition:\t%v\n"+
  789. " ReadOnly:\t%v\n",
  790. aws.VolumeID, aws.FSType, aws.Partition, aws.ReadOnly)
  791. }
  792. func printGitRepoVolumeSource(git *corev1.GitRepoVolumeSource, w PrefixWriter) {
  793. w.Write(LEVEL_2, "Type:\tGitRepo (a volume that is pulled from git when the pod is created)\n"+
  794. " Repository:\t%v\n"+
  795. " Revision:\t%v\n",
  796. git.Repository, git.Revision)
  797. }
  798. func printSecretVolumeSource(secret *corev1.SecretVolumeSource, w PrefixWriter) {
  799. optional := secret.Optional != nil && *secret.Optional
  800. w.Write(LEVEL_2, "Type:\tSecret (a volume populated by a Secret)\n"+
  801. " SecretName:\t%v\n"+
  802. " Optional:\t%v\n",
  803. secret.SecretName, optional)
  804. }
  805. func printConfigMapVolumeSource(configMap *corev1.ConfigMapVolumeSource, w PrefixWriter) {
  806. optional := configMap.Optional != nil && *configMap.Optional
  807. w.Write(LEVEL_2, "Type:\tConfigMap (a volume populated by a ConfigMap)\n"+
  808. " Name:\t%v\n"+
  809. " Optional:\t%v\n",
  810. configMap.Name, optional)
  811. }
  812. func printProjectedVolumeSource(projected *corev1.ProjectedVolumeSource, w PrefixWriter) {
  813. w.Write(LEVEL_2, "Type:\tProjected (a volume that contains injected data from multiple sources)\n")
  814. for _, source := range projected.Sources {
  815. if source.Secret != nil {
  816. w.Write(LEVEL_2, "SecretName:\t%v\n"+
  817. " SecretOptionalName:\t%v\n",
  818. source.Secret.Name, source.Secret.Optional)
  819. } else if source.DownwardAPI != nil {
  820. w.Write(LEVEL_2, "DownwardAPI:\ttrue\n")
  821. } else if source.ConfigMap != nil {
  822. w.Write(LEVEL_2, "ConfigMapName:\t%v\n"+
  823. " ConfigMapOptional:\t%v\n",
  824. source.ConfigMap.Name, source.ConfigMap.Optional)
  825. } else if source.ServiceAccountToken != nil {
  826. w.Write(LEVEL_2, "TokenExpirationSeconds:\t%d\n",
  827. *source.ServiceAccountToken.ExpirationSeconds)
  828. }
  829. }
  830. }
  831. func printNFSVolumeSource(nfs *corev1.NFSVolumeSource, w PrefixWriter) {
  832. w.Write(LEVEL_2, "Type:\tNFS (an NFS mount that lasts the lifetime of a pod)\n"+
  833. " Server:\t%v\n"+
  834. " Path:\t%v\n"+
  835. " ReadOnly:\t%v\n",
  836. nfs.Server, nfs.Path, nfs.ReadOnly)
  837. }
  838. func printQuobyteVolumeSource(quobyte *corev1.QuobyteVolumeSource, w PrefixWriter) {
  839. w.Write(LEVEL_2, "Type:\tQuobyte (a Quobyte mount on the host that shares a pod's lifetime)\n"+
  840. " Registry:\t%v\n"+
  841. " Volume:\t%v\n"+
  842. " ReadOnly:\t%v\n",
  843. quobyte.Registry, quobyte.Volume, quobyte.ReadOnly)
  844. }
  845. func printPortworxVolumeSource(pwxVolume *corev1.PortworxVolumeSource, w PrefixWriter) {
  846. w.Write(LEVEL_2, "Type:\tPortworxVolume (a Portworx Volume resource)\n"+
  847. " VolumeID:\t%v\n",
  848. pwxVolume.VolumeID)
  849. }
  850. func printISCSIVolumeSource(iscsi *corev1.ISCSIVolumeSource, w PrefixWriter) {
  851. initiator := "<none>"
  852. if iscsi.InitiatorName != nil {
  853. initiator = *iscsi.InitiatorName
  854. }
  855. w.Write(LEVEL_2, "Type:\tISCSI (an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod)\n"+
  856. " TargetPortal:\t%v\n"+
  857. " IQN:\t%v\n"+
  858. " Lun:\t%v\n"+
  859. " ISCSIInterface\t%v\n"+
  860. " FSType:\t%v\n"+
  861. " ReadOnly:\t%v\n"+
  862. " Portals:\t%v\n"+
  863. " DiscoveryCHAPAuth:\t%v\n"+
  864. " SessionCHAPAuth:\t%v\n"+
  865. " SecretRef:\t%v\n"+
  866. " InitiatorName:\t%v\n",
  867. iscsi.TargetPortal, iscsi.IQN, iscsi.Lun, iscsi.ISCSIInterface, iscsi.FSType, iscsi.ReadOnly, iscsi.Portals, iscsi.DiscoveryCHAPAuth, iscsi.SessionCHAPAuth, iscsi.SecretRef, initiator)
  868. }
  869. func printISCSIPersistentVolumeSource(iscsi *corev1.ISCSIPersistentVolumeSource, w PrefixWriter) {
  870. initiatorName := "<none>"
  871. if iscsi.InitiatorName != nil {
  872. initiatorName = *iscsi.InitiatorName
  873. }
  874. w.Write(LEVEL_2, "Type:\tISCSI (an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod)\n"+
  875. " TargetPortal:\t%v\n"+
  876. " IQN:\t%v\n"+
  877. " Lun:\t%v\n"+
  878. " ISCSIInterface\t%v\n"+
  879. " FSType:\t%v\n"+
  880. " ReadOnly:\t%v\n"+
  881. " Portals:\t%v\n"+
  882. " DiscoveryCHAPAuth:\t%v\n"+
  883. " SessionCHAPAuth:\t%v\n"+
  884. " SecretRef:\t%v\n"+
  885. " InitiatorName:\t%v\n",
  886. iscsi.TargetPortal, iscsi.IQN, iscsi.Lun, iscsi.ISCSIInterface, iscsi.FSType, iscsi.ReadOnly, iscsi.Portals, iscsi.DiscoveryCHAPAuth, iscsi.SessionCHAPAuth, iscsi.SecretRef, initiatorName)
  887. }
  888. func printGlusterfsVolumeSource(glusterfs *corev1.GlusterfsVolumeSource, w PrefixWriter) {
  889. w.Write(LEVEL_2, "Type:\tGlusterfs (a Glusterfs mount on the host that shares a pod's lifetime)\n"+
  890. " EndpointsName:\t%v\n"+
  891. " Path:\t%v\n"+
  892. " ReadOnly:\t%v\n",
  893. glusterfs.EndpointsName, glusterfs.Path, glusterfs.ReadOnly)
  894. }
  895. func printGlusterfsPersistentVolumeSource(glusterfs *corev1.GlusterfsPersistentVolumeSource, w PrefixWriter) {
  896. w.Write(LEVEL_2, "Type:\tGlusterfs (a Glusterfs mount on the host that shares a pod's lifetime)\n"+
  897. " EndpointsName:\t%v\n"+
  898. " EndpointsNamespace:\t%v\n"+
  899. " Path:\t%v\n"+
  900. " ReadOnly:\t%v\n",
  901. glusterfs.EndpointsName, glusterfs.EndpointsNamespace, glusterfs.Path, glusterfs.ReadOnly)
  902. }
  903. func printPersistentVolumeClaimVolumeSource(claim *corev1.PersistentVolumeClaimVolumeSource, w PrefixWriter) {
  904. w.Write(LEVEL_2, "Type:\tPersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)\n"+
  905. " ClaimName:\t%v\n"+
  906. " ReadOnly:\t%v\n",
  907. claim.ClaimName, claim.ReadOnly)
  908. }
  909. func printRBDVolumeSource(rbd *corev1.RBDVolumeSource, w PrefixWriter) {
  910. w.Write(LEVEL_2, "Type:\tRBD (a Rados Block Device mount on the host that shares a pod's lifetime)\n"+
  911. " CephMonitors:\t%v\n"+
  912. " RBDImage:\t%v\n"+
  913. " FSType:\t%v\n"+
  914. " RBDPool:\t%v\n"+
  915. " RadosUser:\t%v\n"+
  916. " Keyring:\t%v\n"+
  917. " SecretRef:\t%v\n"+
  918. " ReadOnly:\t%v\n",
  919. rbd.CephMonitors, rbd.RBDImage, rbd.FSType, rbd.RBDPool, rbd.RadosUser, rbd.Keyring, rbd.SecretRef, rbd.ReadOnly)
  920. }
  921. func printRBDPersistentVolumeSource(rbd *corev1.RBDPersistentVolumeSource, w PrefixWriter) {
  922. w.Write(LEVEL_2, "Type:\tRBD (a Rados Block Device mount on the host that shares a pod's lifetime)\n"+
  923. " CephMonitors:\t%v\n"+
  924. " RBDImage:\t%v\n"+
  925. " FSType:\t%v\n"+
  926. " RBDPool:\t%v\n"+
  927. " RadosUser:\t%v\n"+
  928. " Keyring:\t%v\n"+
  929. " SecretRef:\t%v\n"+
  930. " ReadOnly:\t%v\n",
  931. rbd.CephMonitors, rbd.RBDImage, rbd.FSType, rbd.RBDPool, rbd.RadosUser, rbd.Keyring, rbd.SecretRef, rbd.ReadOnly)
  932. }
  933. func printDownwardAPIVolumeSource(d *corev1.DownwardAPIVolumeSource, w PrefixWriter) {
  934. w.Write(LEVEL_2, "Type:\tDownwardAPI (a volume populated by information about the pod)\n Items:\n")
  935. for _, mapping := range d.Items {
  936. if mapping.FieldRef != nil {
  937. w.Write(LEVEL_3, "%v -> %v\n", mapping.FieldRef.FieldPath, mapping.Path)
  938. }
  939. if mapping.ResourceFieldRef != nil {
  940. w.Write(LEVEL_3, "%v -> %v\n", mapping.ResourceFieldRef.Resource, mapping.Path)
  941. }
  942. }
  943. }
  944. func printAzureDiskVolumeSource(d *corev1.AzureDiskVolumeSource, w PrefixWriter) {
  945. w.Write(LEVEL_2, "Type:\tAzureDisk (an Azure Data Disk mount on the host and bind mount to the pod)\n"+
  946. " DiskName:\t%v\n"+
  947. " DiskURI:\t%v\n"+
  948. " Kind: \t%v\n"+
  949. " FSType:\t%v\n"+
  950. " CachingMode:\t%v\n"+
  951. " ReadOnly:\t%v\n",
  952. d.DiskName, d.DataDiskURI, *d.Kind, *d.FSType, *d.CachingMode, *d.ReadOnly)
  953. }
  954. func printVsphereVolumeSource(vsphere *corev1.VsphereVirtualDiskVolumeSource, w PrefixWriter) {
  955. w.Write(LEVEL_2, "Type:\tvSphereVolume (a Persistent Disk resource in vSphere)\n"+
  956. " VolumePath:\t%v\n"+
  957. " FSType:\t%v\n"+
  958. " StoragePolicyName:\t%v\n",
  959. vsphere.VolumePath, vsphere.FSType, vsphere.StoragePolicyName)
  960. }
  961. func printPhotonPersistentDiskVolumeSource(photon *corev1.PhotonPersistentDiskVolumeSource, w PrefixWriter) {
  962. w.Write(LEVEL_2, "Type:\tPhotonPersistentDisk (a Persistent Disk resource in photon platform)\n"+
  963. " PdID:\t%v\n"+
  964. " FSType:\t%v\n",
  965. photon.PdID, photon.FSType)
  966. }
  967. func printCinderVolumeSource(cinder *corev1.CinderVolumeSource, w PrefixWriter) {
  968. w.Write(LEVEL_2, "Type:\tCinder (a Persistent Disk resource in OpenStack)\n"+
  969. " VolumeID:\t%v\n"+
  970. " FSType:\t%v\n"+
  971. " ReadOnly:\t%v\n"+
  972. " SecretRef:\t%v\n",
  973. cinder.VolumeID, cinder.FSType, cinder.ReadOnly, cinder.SecretRef)
  974. }
  975. func printCinderPersistentVolumeSource(cinder *corev1.CinderPersistentVolumeSource, w PrefixWriter) {
  976. w.Write(LEVEL_2, "Type:\tCinder (a Persistent Disk resource in OpenStack)\n"+
  977. " VolumeID:\t%v\n"+
  978. " FSType:\t%v\n"+
  979. " ReadOnly:\t%v\n"+
  980. " SecretRef:\t%v\n",
  981. cinder.VolumeID, cinder.FSType, cinder.ReadOnly, cinder.SecretRef)
  982. }
  983. func printScaleIOVolumeSource(sio *corev1.ScaleIOVolumeSource, w PrefixWriter) {
  984. w.Write(LEVEL_2, "Type:\tScaleIO (a persistent volume backed by a block device in ScaleIO)\n"+
  985. " Gateway:\t%v\n"+
  986. " System:\t%v\n"+
  987. " Protection Domain:\t%v\n"+
  988. " Storage Pool:\t%v\n"+
  989. " Storage Mode:\t%v\n"+
  990. " VolumeName:\t%v\n"+
  991. " FSType:\t%v\n"+
  992. " ReadOnly:\t%v\n",
  993. sio.Gateway, sio.System, sio.ProtectionDomain, sio.StoragePool, sio.StorageMode, sio.VolumeName, sio.FSType, sio.ReadOnly)
  994. }
  995. func printScaleIOPersistentVolumeSource(sio *corev1.ScaleIOPersistentVolumeSource, w PrefixWriter) {
  996. var secretNS, secretName string
  997. if sio.SecretRef != nil {
  998. secretName = sio.SecretRef.Name
  999. secretNS = sio.SecretRef.Namespace
  1000. }
  1001. w.Write(LEVEL_2, "Type:\tScaleIO (a persistent volume backed by a block device in ScaleIO)\n"+
  1002. " Gateway:\t%v\n"+
  1003. " System:\t%v\n"+
  1004. " Protection Domain:\t%v\n"+
  1005. " Storage Pool:\t%v\n"+
  1006. " Storage Mode:\t%v\n"+
  1007. " VolumeName:\t%v\n"+
  1008. " SecretName:\t%v\n"+
  1009. " SecretNamespace:\t%v\n"+
  1010. " FSType:\t%v\n"+
  1011. " ReadOnly:\t%v\n",
  1012. sio.Gateway, sio.System, sio.ProtectionDomain, sio.StoragePool, sio.StorageMode, sio.VolumeName, secretName, secretNS, sio.FSType, sio.ReadOnly)
  1013. }
  1014. func printLocalVolumeSource(ls *corev1.LocalVolumeSource, w PrefixWriter) {
  1015. w.Write(LEVEL_2, "Type:\tLocalVolume (a persistent volume backed by local storage on a node)\n"+
  1016. " Path:\t%v\n",
  1017. ls.Path)
  1018. }
  1019. func printCephFSVolumeSource(cephfs *corev1.CephFSVolumeSource, w PrefixWriter) {
  1020. w.Write(LEVEL_2, "Type:\tCephFS (a CephFS mount on the host that shares a pod's lifetime)\n"+
  1021. " Monitors:\t%v\n"+
  1022. " Path:\t%v\n"+
  1023. " User:\t%v\n"+
  1024. " SecretFile:\t%v\n"+
  1025. " SecretRef:\t%v\n"+
  1026. " ReadOnly:\t%v\n",
  1027. cephfs.Monitors, cephfs.Path, cephfs.User, cephfs.SecretFile, cephfs.SecretRef, cephfs.ReadOnly)
  1028. }
  1029. func printCephFSPersistentVolumeSource(cephfs *corev1.CephFSPersistentVolumeSource, w PrefixWriter) {
  1030. w.Write(LEVEL_2, "Type:\tCephFS (a CephFS mount on the host that shares a pod's lifetime)\n"+
  1031. " Monitors:\t%v\n"+
  1032. " Path:\t%v\n"+
  1033. " User:\t%v\n"+
  1034. " SecretFile:\t%v\n"+
  1035. " SecretRef:\t%v\n"+
  1036. " ReadOnly:\t%v\n",
  1037. cephfs.Monitors, cephfs.Path, cephfs.User, cephfs.SecretFile, cephfs.SecretRef, cephfs.ReadOnly)
  1038. }
  1039. func printStorageOSVolumeSource(storageos *corev1.StorageOSVolumeSource, w PrefixWriter) {
  1040. w.Write(LEVEL_2, "Type:\tStorageOS (a StorageOS Persistent Disk resource)\n"+
  1041. " VolumeName:\t%v\n"+
  1042. " VolumeNamespace:\t%v\n"+
  1043. " FSType:\t%v\n"+
  1044. " ReadOnly:\t%v\n",
  1045. storageos.VolumeName, storageos.VolumeNamespace, storageos.FSType, storageos.ReadOnly)
  1046. }
  1047. func printStorageOSPersistentVolumeSource(storageos *corev1.StorageOSPersistentVolumeSource, w PrefixWriter) {
  1048. w.Write(LEVEL_2, "Type:\tStorageOS (a StorageOS Persistent Disk resource)\n"+
  1049. " VolumeName:\t%v\n"+
  1050. " VolumeNamespace:\t%v\n"+
  1051. " FSType:\t%v\n"+
  1052. " ReadOnly:\t%v\n",
  1053. storageos.VolumeName, storageos.VolumeNamespace, storageos.FSType, storageos.ReadOnly)
  1054. }
  1055. func printFCVolumeSource(fc *corev1.FCVolumeSource, w PrefixWriter) {
  1056. lun := "<none>"
  1057. if fc.Lun != nil {
  1058. lun = strconv.Itoa(int(*fc.Lun))
  1059. }
  1060. w.Write(LEVEL_2, "Type:\tFC (a Fibre Channel disk)\n"+
  1061. " TargetWWNs:\t%v\n"+
  1062. " LUN:\t%v\n"+
  1063. " FSType:\t%v\n"+
  1064. " ReadOnly:\t%v\n",
  1065. strings.Join(fc.TargetWWNs, ", "), lun, fc.FSType, fc.ReadOnly)
  1066. }
  1067. func printAzureFileVolumeSource(azureFile *corev1.AzureFileVolumeSource, w PrefixWriter) {
  1068. w.Write(LEVEL_2, "Type:\tAzureFile (an Azure File Service mount on the host and bind mount to the pod)\n"+
  1069. " SecretName:\t%v\n"+
  1070. " ShareName:\t%v\n"+
  1071. " ReadOnly:\t%v\n",
  1072. azureFile.SecretName, azureFile.ShareName, azureFile.ReadOnly)
  1073. }
  1074. func printAzureFilePersistentVolumeSource(azureFile *corev1.AzureFilePersistentVolumeSource, w PrefixWriter) {
  1075. ns := ""
  1076. if azureFile.SecretNamespace != nil {
  1077. ns = *azureFile.SecretNamespace
  1078. }
  1079. w.Write(LEVEL_2, "Type:\tAzureFile (an Azure File Service mount on the host and bind mount to the pod)\n"+
  1080. " SecretName:\t%v\n"+
  1081. " SecretNamespace:\t%v\n"+
  1082. " ShareName:\t%v\n"+
  1083. " ReadOnly:\t%v\n",
  1084. azureFile.SecretName, ns, azureFile.ShareName, azureFile.ReadOnly)
  1085. }
  1086. func printFlexPersistentVolumeSource(flex *corev1.FlexPersistentVolumeSource, w PrefixWriter) {
  1087. w.Write(LEVEL_2, "Type:\tFlexVolume (a generic volume resource that is provisioned/attached using an exec based plugin)\n"+
  1088. " Driver:\t%v\n"+
  1089. " FSType:\t%v\n"+
  1090. " SecretRef:\t%v\n"+
  1091. " ReadOnly:\t%v\n"+
  1092. " Options:\t%v\n",
  1093. flex.Driver, flex.FSType, flex.SecretRef, flex.ReadOnly, flex.Options)
  1094. }
  1095. func printFlexVolumeSource(flex *corev1.FlexVolumeSource, w PrefixWriter) {
  1096. w.Write(LEVEL_2, "Type:\tFlexVolume (a generic volume resource that is provisioned/attached using an exec based plugin)\n"+
  1097. " Driver:\t%v\n"+
  1098. " FSType:\t%v\n"+
  1099. " SecretRef:\t%v\n"+
  1100. " ReadOnly:\t%v\n"+
  1101. " Options:\t%v\n",
  1102. flex.Driver, flex.FSType, flex.SecretRef, flex.ReadOnly, flex.Options)
  1103. }
  1104. func printFlockerVolumeSource(flocker *corev1.FlockerVolumeSource, w PrefixWriter) {
  1105. w.Write(LEVEL_2, "Type:\tFlocker (a Flocker volume mounted by the Flocker agent)\n"+
  1106. " DatasetName:\t%v\n"+
  1107. " DatasetUUID:\t%v\n",
  1108. flocker.DatasetName, flocker.DatasetUUID)
  1109. }
  1110. func printCSIVolumeSource(csi *corev1.CSIVolumeSource, w PrefixWriter) {
  1111. var readOnly bool
  1112. var fsType string
  1113. if csi.ReadOnly != nil && *csi.ReadOnly {
  1114. readOnly = true
  1115. }
  1116. if csi.FSType != nil {
  1117. fsType = *csi.FSType
  1118. }
  1119. w.Write(LEVEL_2, "Type:\tCSI (a Container Storage Interface (CSI) volume source)\n"+
  1120. " Driver:\t%v\n"+
  1121. " FSType:\t%v\n"+
  1122. " ReadOnly:\t%v\n",
  1123. csi.Driver, fsType, readOnly)
  1124. printCSIPersistentVolumeAttributesMultiline(w, "VolumeAttributes", csi.VolumeAttributes)
  1125. }
  1126. func printCSIPersistentVolumeSource(csi *corev1.CSIPersistentVolumeSource, w PrefixWriter) {
  1127. w.Write(LEVEL_2, "Type:\tCSI (a Container Storage Interface (CSI) volume source)\n"+
  1128. " Driver:\t%v\n"+
  1129. " VolumeHandle:\t%v\n"+
  1130. " ReadOnly:\t%v\n",
  1131. csi.Driver, csi.VolumeHandle, csi.ReadOnly)
  1132. printCSIPersistentVolumeAttributesMultiline(w, "VolumeAttributes", csi.VolumeAttributes)
  1133. }
  1134. func printCSIPersistentVolumeAttributesMultiline(w PrefixWriter, title string, annotations map[string]string) {
  1135. printCSIPersistentVolumeAttributesMultilineIndent(w, "", title, "\t", annotations, sets.NewString())
  1136. }
  1137. func printCSIPersistentVolumeAttributesMultilineIndent(w PrefixWriter, initialIndent, title, innerIndent string, attributes map[string]string, skip sets.String) {
  1138. w.Write(LEVEL_2, "%s%s:%s", initialIndent, title, innerIndent)
  1139. if len(attributes) == 0 {
  1140. w.WriteLine("<none>")
  1141. return
  1142. }
  1143. // to print labels in the sorted order
  1144. keys := make([]string, 0, len(attributes))
  1145. for key := range attributes {
  1146. if skip.Has(key) {
  1147. continue
  1148. }
  1149. keys = append(keys, key)
  1150. }
  1151. if len(attributes) == 0 {
  1152. w.WriteLine("<none>")
  1153. return
  1154. }
  1155. sort.Strings(keys)
  1156. for i, key := range keys {
  1157. if i != 0 {
  1158. w.Write(LEVEL_2, initialIndent)
  1159. w.Write(LEVEL_2, innerIndent)
  1160. }
  1161. line := fmt.Sprintf("%s=%s", key, attributes[key])
  1162. if len(line) > maxAnnotationLen {
  1163. w.Write(LEVEL_2, "%s...\n", line[:maxAnnotationLen])
  1164. } else {
  1165. w.Write(LEVEL_2, "%s\n", line)
  1166. }
  1167. i++
  1168. }
  1169. }
  1170. type PersistentVolumeDescriber struct {
  1171. clientset.Interface
  1172. }
  1173. func (d *PersistentVolumeDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  1174. c := d.CoreV1().PersistentVolumes()
  1175. pv, err := c.Get(name, metav1.GetOptions{})
  1176. if err != nil {
  1177. return "", err
  1178. }
  1179. var events *corev1.EventList
  1180. if describerSettings.ShowEvents {
  1181. events, _ = d.CoreV1().Events(namespace).Search(scheme.Scheme, pv)
  1182. }
  1183. return describePersistentVolume(pv, events)
  1184. }
  1185. func printVolumeNodeAffinity(w PrefixWriter, affinity *corev1.VolumeNodeAffinity) {
  1186. w.Write(LEVEL_0, "Node Affinity:\t")
  1187. if affinity == nil || affinity.Required == nil {
  1188. w.WriteLine("<none>")
  1189. return
  1190. }
  1191. w.WriteLine("")
  1192. if affinity.Required != nil {
  1193. w.Write(LEVEL_1, "Required Terms:\t")
  1194. if len(affinity.Required.NodeSelectorTerms) == 0 {
  1195. w.WriteLine("<none>")
  1196. } else {
  1197. w.WriteLine("")
  1198. for i, term := range affinity.Required.NodeSelectorTerms {
  1199. printNodeSelectorTermsMultilineWithIndent(w, LEVEL_2, fmt.Sprintf("Term %v", i), "\t", term.MatchExpressions)
  1200. }
  1201. }
  1202. }
  1203. }
  1204. // printLabelsMultiline prints multiple labels with a user-defined alignment.
  1205. func printNodeSelectorTermsMultilineWithIndent(w PrefixWriter, indentLevel int, title, innerIndent string, reqs []corev1.NodeSelectorRequirement) {
  1206. w.Write(indentLevel, "%s:%s", title, innerIndent)
  1207. if len(reqs) == 0 {
  1208. w.WriteLine("<none>")
  1209. return
  1210. }
  1211. for i, req := range reqs {
  1212. if i != 0 {
  1213. w.Write(indentLevel, "%s", innerIndent)
  1214. }
  1215. exprStr := fmt.Sprintf("%s %s", req.Key, strings.ToLower(string(req.Operator)))
  1216. if len(req.Values) > 0 {
  1217. exprStr = fmt.Sprintf("%s [%s]", exprStr, strings.Join(req.Values, ", "))
  1218. }
  1219. w.Write(LEVEL_0, "%s\n", exprStr)
  1220. }
  1221. }
  1222. func describePersistentVolume(pv *corev1.PersistentVolume, events *corev1.EventList) (string, error) {
  1223. return tabbedString(func(out io.Writer) error {
  1224. w := NewPrefixWriter(out)
  1225. w.Write(LEVEL_0, "Name:\t%s\n", pv.Name)
  1226. printLabelsMultiline(w, "Labels", pv.ObjectMeta.Labels)
  1227. printAnnotationsMultiline(w, "Annotations", pv.ObjectMeta.Annotations)
  1228. w.Write(LEVEL_0, "Finalizers:\t%v\n", pv.ObjectMeta.Finalizers)
  1229. w.Write(LEVEL_0, "StorageClass:\t%s\n", storageutil.GetPersistentVolumeClass(pv))
  1230. if pv.ObjectMeta.DeletionTimestamp != nil {
  1231. w.Write(LEVEL_0, "Status:\tTerminating (lasts %s)\n", translateTimestampSince(*pv.ObjectMeta.DeletionTimestamp))
  1232. } else {
  1233. w.Write(LEVEL_0, "Status:\t%v\n", pv.Status.Phase)
  1234. }
  1235. if pv.Spec.ClaimRef != nil {
  1236. w.Write(LEVEL_0, "Claim:\t%s\n", pv.Spec.ClaimRef.Namespace+"/"+pv.Spec.ClaimRef.Name)
  1237. } else {
  1238. w.Write(LEVEL_0, "Claim:\t%s\n", "")
  1239. }
  1240. w.Write(LEVEL_0, "Reclaim Policy:\t%v\n", pv.Spec.PersistentVolumeReclaimPolicy)
  1241. w.Write(LEVEL_0, "Access Modes:\t%s\n", storageutil.GetAccessModesAsString(pv.Spec.AccessModes))
  1242. if pv.Spec.VolumeMode != nil {
  1243. w.Write(LEVEL_0, "VolumeMode:\t%v\n", *pv.Spec.VolumeMode)
  1244. }
  1245. storage := pv.Spec.Capacity[corev1.ResourceStorage]
  1246. w.Write(LEVEL_0, "Capacity:\t%s\n", storage.String())
  1247. printVolumeNodeAffinity(w, pv.Spec.NodeAffinity)
  1248. w.Write(LEVEL_0, "Message:\t%s\n", pv.Status.Message)
  1249. w.Write(LEVEL_0, "Source:\n")
  1250. switch {
  1251. case pv.Spec.HostPath != nil:
  1252. printHostPathVolumeSource(pv.Spec.HostPath, w)
  1253. case pv.Spec.GCEPersistentDisk != nil:
  1254. printGCEPersistentDiskVolumeSource(pv.Spec.GCEPersistentDisk, w)
  1255. case pv.Spec.AWSElasticBlockStore != nil:
  1256. printAWSElasticBlockStoreVolumeSource(pv.Spec.AWSElasticBlockStore, w)
  1257. case pv.Spec.NFS != nil:
  1258. printNFSVolumeSource(pv.Spec.NFS, w)
  1259. case pv.Spec.ISCSI != nil:
  1260. printISCSIPersistentVolumeSource(pv.Spec.ISCSI, w)
  1261. case pv.Spec.Glusterfs != nil:
  1262. printGlusterfsPersistentVolumeSource(pv.Spec.Glusterfs, w)
  1263. case pv.Spec.RBD != nil:
  1264. printRBDPersistentVolumeSource(pv.Spec.RBD, w)
  1265. case pv.Spec.Quobyte != nil:
  1266. printQuobyteVolumeSource(pv.Spec.Quobyte, w)
  1267. case pv.Spec.VsphereVolume != nil:
  1268. printVsphereVolumeSource(pv.Spec.VsphereVolume, w)
  1269. case pv.Spec.Cinder != nil:
  1270. printCinderPersistentVolumeSource(pv.Spec.Cinder, w)
  1271. case pv.Spec.AzureDisk != nil:
  1272. printAzureDiskVolumeSource(pv.Spec.AzureDisk, w)
  1273. case pv.Spec.PhotonPersistentDisk != nil:
  1274. printPhotonPersistentDiskVolumeSource(pv.Spec.PhotonPersistentDisk, w)
  1275. case pv.Spec.PortworxVolume != nil:
  1276. printPortworxVolumeSource(pv.Spec.PortworxVolume, w)
  1277. case pv.Spec.ScaleIO != nil:
  1278. printScaleIOPersistentVolumeSource(pv.Spec.ScaleIO, w)
  1279. case pv.Spec.Local != nil:
  1280. printLocalVolumeSource(pv.Spec.Local, w)
  1281. case pv.Spec.CephFS != nil:
  1282. printCephFSPersistentVolumeSource(pv.Spec.CephFS, w)
  1283. case pv.Spec.StorageOS != nil:
  1284. printStorageOSPersistentVolumeSource(pv.Spec.StorageOS, w)
  1285. case pv.Spec.FC != nil:
  1286. printFCVolumeSource(pv.Spec.FC, w)
  1287. case pv.Spec.AzureFile != nil:
  1288. printAzureFilePersistentVolumeSource(pv.Spec.AzureFile, w)
  1289. case pv.Spec.FlexVolume != nil:
  1290. printFlexPersistentVolumeSource(pv.Spec.FlexVolume, w)
  1291. case pv.Spec.Flocker != nil:
  1292. printFlockerVolumeSource(pv.Spec.Flocker, w)
  1293. case pv.Spec.CSI != nil:
  1294. printCSIPersistentVolumeSource(pv.Spec.CSI, w)
  1295. default:
  1296. w.Write(LEVEL_1, "<unknown>\n")
  1297. }
  1298. if events != nil {
  1299. DescribeEvents(events, w)
  1300. }
  1301. return nil
  1302. })
  1303. }
  1304. type PersistentVolumeClaimDescriber struct {
  1305. clientset.Interface
  1306. }
  1307. func (d *PersistentVolumeClaimDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  1308. c := d.CoreV1().PersistentVolumeClaims(namespace)
  1309. pvc, err := c.Get(name, metav1.GetOptions{})
  1310. if err != nil {
  1311. return "", err
  1312. }
  1313. pc := d.CoreV1().Pods(namespace)
  1314. mountPods, err := getMountPods(pc, pvc.Name)
  1315. if err != nil {
  1316. return "", err
  1317. }
  1318. events, _ := d.CoreV1().Events(namespace).Search(scheme.Scheme, pvc)
  1319. return describePersistentVolumeClaim(pvc, events, mountPods)
  1320. }
  1321. func getMountPods(c corev1client.PodInterface, pvcName string) ([]corev1.Pod, error) {
  1322. nsPods, err := c.List(metav1.ListOptions{})
  1323. if err != nil {
  1324. return []corev1.Pod{}, err
  1325. }
  1326. var pods []corev1.Pod
  1327. for _, pod := range nsPods.Items {
  1328. pvcs := getPvcs(pod.Spec.Volumes)
  1329. for _, pvc := range pvcs {
  1330. if pvc.PersistentVolumeClaim.ClaimName == pvcName {
  1331. pods = append(pods, pod)
  1332. }
  1333. }
  1334. }
  1335. return pods, nil
  1336. }
  1337. func getPvcs(volumes []corev1.Volume) []corev1.Volume {
  1338. var pvcs []corev1.Volume
  1339. for _, volume := range volumes {
  1340. if volume.VolumeSource.PersistentVolumeClaim != nil {
  1341. pvcs = append(pvcs, volume)
  1342. }
  1343. }
  1344. return pvcs
  1345. }
  1346. func describePersistentVolumeClaim(pvc *corev1.PersistentVolumeClaim, events *corev1.EventList, mountPods []corev1.Pod) (string, error) {
  1347. return tabbedString(func(out io.Writer) error {
  1348. w := NewPrefixWriter(out)
  1349. w.Write(LEVEL_0, "Name:\t%s\n", pvc.Name)
  1350. w.Write(LEVEL_0, "Namespace:\t%s\n", pvc.Namespace)
  1351. w.Write(LEVEL_0, "StorageClass:\t%s\n", storageutil.GetPersistentVolumeClaimClass(pvc))
  1352. if pvc.ObjectMeta.DeletionTimestamp != nil {
  1353. w.Write(LEVEL_0, "Status:\tTerminating (lasts %s)\n", translateTimestampSince(*pvc.ObjectMeta.DeletionTimestamp))
  1354. } else {
  1355. w.Write(LEVEL_0, "Status:\t%v\n", pvc.Status.Phase)
  1356. }
  1357. w.Write(LEVEL_0, "Volume:\t%s\n", pvc.Spec.VolumeName)
  1358. printLabelsMultiline(w, "Labels", pvc.Labels)
  1359. printAnnotationsMultiline(w, "Annotations", pvc.Annotations)
  1360. w.Write(LEVEL_0, "Finalizers:\t%v\n", pvc.ObjectMeta.Finalizers)
  1361. storage := pvc.Spec.Resources.Requests[corev1.ResourceStorage]
  1362. capacity := ""
  1363. accessModes := ""
  1364. if pvc.Spec.VolumeName != "" {
  1365. accessModes = storageutil.GetAccessModesAsString(pvc.Status.AccessModes)
  1366. storage = pvc.Status.Capacity[corev1.ResourceStorage]
  1367. capacity = storage.String()
  1368. }
  1369. w.Write(LEVEL_0, "Capacity:\t%s\n", capacity)
  1370. w.Write(LEVEL_0, "Access Modes:\t%s\n", accessModes)
  1371. if pvc.Spec.VolumeMode != nil {
  1372. w.Write(LEVEL_0, "VolumeMode:\t%v\n", *pvc.Spec.VolumeMode)
  1373. }
  1374. printPodsMultiline(w, "Mounted By", mountPods)
  1375. if len(pvc.Status.Conditions) > 0 {
  1376. w.Write(LEVEL_0, "Conditions:\n")
  1377. w.Write(LEVEL_1, "Type\tStatus\tLastProbeTime\tLastTransitionTime\tReason\tMessage\n")
  1378. w.Write(LEVEL_1, "----\t------\t-----------------\t------------------\t------\t-------\n")
  1379. for _, c := range pvc.Status.Conditions {
  1380. w.Write(LEVEL_1, "%v \t%v \t%s \t%s \t%v \t%v\n",
  1381. c.Type,
  1382. c.Status,
  1383. c.LastProbeTime.Time.Format(time.RFC1123Z),
  1384. c.LastTransitionTime.Time.Format(time.RFC1123Z),
  1385. c.Reason,
  1386. c.Message)
  1387. }
  1388. }
  1389. if events != nil {
  1390. DescribeEvents(events, w)
  1391. }
  1392. return nil
  1393. })
  1394. }
  1395. func describeContainers(label string, containers []corev1.Container, containerStatuses []corev1.ContainerStatus,
  1396. resolverFn EnvVarResolverFunc, w PrefixWriter, space string) {
  1397. statuses := map[string]corev1.ContainerStatus{}
  1398. for _, status := range containerStatuses {
  1399. statuses[status.Name] = status
  1400. }
  1401. describeContainersLabel(containers, label, space, w)
  1402. for _, container := range containers {
  1403. status, ok := statuses[container.Name]
  1404. describeContainerBasicInfo(container, status, ok, space, w)
  1405. describeContainerCommand(container, w)
  1406. if ok {
  1407. describeContainerState(status, w)
  1408. }
  1409. describeContainerResource(container, w)
  1410. describeContainerProbe(container, w)
  1411. if len(container.EnvFrom) > 0 {
  1412. describeContainerEnvFrom(container, resolverFn, w)
  1413. }
  1414. describeContainerEnvVars(container, resolverFn, w)
  1415. describeContainerVolumes(container, w)
  1416. }
  1417. }
  1418. func describeContainersLabel(containers []corev1.Container, label, space string, w PrefixWriter) {
  1419. none := ""
  1420. if len(containers) == 0 {
  1421. none = " <none>"
  1422. }
  1423. w.Write(LEVEL_0, "%s%s:%s\n", space, label, none)
  1424. }
  1425. func describeContainerBasicInfo(container corev1.Container, status corev1.ContainerStatus, ok bool, space string, w PrefixWriter) {
  1426. nameIndent := ""
  1427. if len(space) > 0 {
  1428. nameIndent = " "
  1429. }
  1430. w.Write(LEVEL_1, "%s%v:\n", nameIndent, container.Name)
  1431. if ok {
  1432. w.Write(LEVEL_2, "Container ID:\t%s\n", status.ContainerID)
  1433. }
  1434. w.Write(LEVEL_2, "Image:\t%s\n", container.Image)
  1435. if ok {
  1436. w.Write(LEVEL_2, "Image ID:\t%s\n", status.ImageID)
  1437. }
  1438. portString := describeContainerPorts(container.Ports)
  1439. if strings.Contains(portString, ",") {
  1440. w.Write(LEVEL_2, "Ports:\t%s\n", portString)
  1441. } else {
  1442. w.Write(LEVEL_2, "Port:\t%s\n", stringOrNone(portString))
  1443. }
  1444. hostPortString := describeContainerHostPorts(container.Ports)
  1445. if strings.Contains(hostPortString, ",") {
  1446. w.Write(LEVEL_2, "Host Ports:\t%s\n", hostPortString)
  1447. } else {
  1448. w.Write(LEVEL_2, "Host Port:\t%s\n", stringOrNone(hostPortString))
  1449. }
  1450. }
  1451. func describeContainerPorts(cPorts []corev1.ContainerPort) string {
  1452. ports := make([]string, 0, len(cPorts))
  1453. for _, cPort := range cPorts {
  1454. ports = append(ports, fmt.Sprintf("%d/%s", cPort.ContainerPort, cPort.Protocol))
  1455. }
  1456. return strings.Join(ports, ", ")
  1457. }
  1458. func describeContainerHostPorts(cPorts []corev1.ContainerPort) string {
  1459. ports := make([]string, 0, len(cPorts))
  1460. for _, cPort := range cPorts {
  1461. ports = append(ports, fmt.Sprintf("%d/%s", cPort.HostPort, cPort.Protocol))
  1462. }
  1463. return strings.Join(ports, ", ")
  1464. }
  1465. func describeContainerCommand(container corev1.Container, w PrefixWriter) {
  1466. if len(container.Command) > 0 {
  1467. w.Write(LEVEL_2, "Command:\n")
  1468. for _, c := range container.Command {
  1469. for _, s := range strings.Split(c, "\n") {
  1470. w.Write(LEVEL_3, "%s\n", s)
  1471. }
  1472. }
  1473. }
  1474. if len(container.Args) > 0 {
  1475. w.Write(LEVEL_2, "Args:\n")
  1476. for _, arg := range container.Args {
  1477. for _, s := range strings.Split(arg, "\n") {
  1478. w.Write(LEVEL_3, "%s\n", s)
  1479. }
  1480. }
  1481. }
  1482. }
  1483. func describeContainerResource(container corev1.Container, w PrefixWriter) {
  1484. resources := container.Resources
  1485. if len(resources.Limits) > 0 {
  1486. w.Write(LEVEL_2, "Limits:\n")
  1487. }
  1488. for _, name := range SortedResourceNames(resources.Limits) {
  1489. quantity := resources.Limits[name]
  1490. w.Write(LEVEL_3, "%s:\t%s\n", name, quantity.String())
  1491. }
  1492. if len(resources.Requests) > 0 {
  1493. w.Write(LEVEL_2, "Requests:\n")
  1494. }
  1495. for _, name := range SortedResourceNames(resources.Requests) {
  1496. quantity := resources.Requests[name]
  1497. w.Write(LEVEL_3, "%s:\t%s\n", name, quantity.String())
  1498. }
  1499. }
  1500. func describeContainerState(status corev1.ContainerStatus, w PrefixWriter) {
  1501. describeStatus("State", status.State, w)
  1502. if status.LastTerminationState.Terminated != nil {
  1503. describeStatus("Last State", status.LastTerminationState, w)
  1504. }
  1505. w.Write(LEVEL_2, "Ready:\t%v\n", printBool(status.Ready))
  1506. w.Write(LEVEL_2, "Restart Count:\t%d\n", status.RestartCount)
  1507. }
  1508. func describeContainerProbe(container corev1.Container, w PrefixWriter) {
  1509. if container.LivenessProbe != nil {
  1510. probe := DescribeProbe(container.LivenessProbe)
  1511. w.Write(LEVEL_2, "Liveness:\t%s\n", probe)
  1512. }
  1513. if container.ReadinessProbe != nil {
  1514. probe := DescribeProbe(container.ReadinessProbe)
  1515. w.Write(LEVEL_2, "Readiness:\t%s\n", probe)
  1516. }
  1517. }
  1518. func describeContainerVolumes(container corev1.Container, w PrefixWriter) {
  1519. // Show volumeMounts
  1520. none := ""
  1521. if len(container.VolumeMounts) == 0 {
  1522. none = "\t<none>"
  1523. }
  1524. w.Write(LEVEL_2, "Mounts:%s\n", none)
  1525. sort.Sort(SortableVolumeMounts(container.VolumeMounts))
  1526. for _, mount := range container.VolumeMounts {
  1527. flags := []string{}
  1528. if mount.ReadOnly {
  1529. flags = append(flags, "ro")
  1530. } else {
  1531. flags = append(flags, "rw")
  1532. }
  1533. if len(mount.SubPath) > 0 {
  1534. flags = append(flags, fmt.Sprintf("path=%q", mount.SubPath))
  1535. }
  1536. w.Write(LEVEL_3, "%s from %s (%s)\n", mount.MountPath, mount.Name, strings.Join(flags, ","))
  1537. }
  1538. // Show volumeDevices if exists
  1539. if len(container.VolumeDevices) > 0 {
  1540. w.Write(LEVEL_2, "Devices:%s\n", none)
  1541. sort.Sort(SortableVolumeDevices(container.VolumeDevices))
  1542. for _, device := range container.VolumeDevices {
  1543. w.Write(LEVEL_3, "%s from %s\n", device.DevicePath, device.Name)
  1544. }
  1545. }
  1546. }
  1547. func describeContainerEnvVars(container corev1.Container, resolverFn EnvVarResolverFunc, w PrefixWriter) {
  1548. none := ""
  1549. if len(container.Env) == 0 {
  1550. none = "\t<none>"
  1551. }
  1552. w.Write(LEVEL_2, "Environment:%s\n", none)
  1553. for _, e := range container.Env {
  1554. if e.ValueFrom == nil {
  1555. for i, s := range strings.Split(e.Value, "\n") {
  1556. if i == 0 {
  1557. w.Write(LEVEL_3, "%s:\t%s\n", e.Name, s)
  1558. } else {
  1559. w.Write(LEVEL_3, "\t%s\n", s)
  1560. }
  1561. }
  1562. continue
  1563. }
  1564. switch {
  1565. case e.ValueFrom.FieldRef != nil:
  1566. var valueFrom string
  1567. if resolverFn != nil {
  1568. valueFrom = resolverFn(e)
  1569. }
  1570. w.Write(LEVEL_3, "%s:\t%s (%s:%s)\n", e.Name, valueFrom, e.ValueFrom.FieldRef.APIVersion, e.ValueFrom.FieldRef.FieldPath)
  1571. case e.ValueFrom.ResourceFieldRef != nil:
  1572. valueFrom, err := resourcehelper.ExtractContainerResourceValue(e.ValueFrom.ResourceFieldRef, &container)
  1573. if err != nil {
  1574. valueFrom = ""
  1575. }
  1576. resource := e.ValueFrom.ResourceFieldRef.Resource
  1577. if valueFrom == "0" && (resource == "limits.cpu" || resource == "limits.memory") {
  1578. valueFrom = "node allocatable"
  1579. }
  1580. w.Write(LEVEL_3, "%s:\t%s (%s)\n", e.Name, valueFrom, resource)
  1581. case e.ValueFrom.SecretKeyRef != nil:
  1582. optional := e.ValueFrom.SecretKeyRef.Optional != nil && *e.ValueFrom.SecretKeyRef.Optional
  1583. w.Write(LEVEL_3, "%s:\t<set to the key '%s' in secret '%s'>\tOptional: %t\n", e.Name, e.ValueFrom.SecretKeyRef.Key, e.ValueFrom.SecretKeyRef.Name, optional)
  1584. case e.ValueFrom.ConfigMapKeyRef != nil:
  1585. optional := e.ValueFrom.ConfigMapKeyRef.Optional != nil && *e.ValueFrom.ConfigMapKeyRef.Optional
  1586. w.Write(LEVEL_3, "%s:\t<set to the key '%s' of config map '%s'>\tOptional: %t\n", e.Name, e.ValueFrom.ConfigMapKeyRef.Key, e.ValueFrom.ConfigMapKeyRef.Name, optional)
  1587. }
  1588. }
  1589. }
  1590. func describeContainerEnvFrom(container corev1.Container, resolverFn EnvVarResolverFunc, w PrefixWriter) {
  1591. none := ""
  1592. if len(container.EnvFrom) == 0 {
  1593. none = "\t<none>"
  1594. }
  1595. w.Write(LEVEL_2, "Environment Variables from:%s\n", none)
  1596. for _, e := range container.EnvFrom {
  1597. from := ""
  1598. name := ""
  1599. optional := false
  1600. if e.ConfigMapRef != nil {
  1601. from = "ConfigMap"
  1602. name = e.ConfigMapRef.Name
  1603. optional = e.ConfigMapRef.Optional != nil && *e.ConfigMapRef.Optional
  1604. } else if e.SecretRef != nil {
  1605. from = "Secret"
  1606. name = e.SecretRef.Name
  1607. optional = e.SecretRef.Optional != nil && *e.SecretRef.Optional
  1608. }
  1609. if len(e.Prefix) == 0 {
  1610. w.Write(LEVEL_3, "%s\t%s\tOptional: %t\n", name, from, optional)
  1611. } else {
  1612. w.Write(LEVEL_3, "%s\t%s with prefix '%s'\tOptional: %t\n", name, from, e.Prefix, optional)
  1613. }
  1614. }
  1615. }
  1616. // DescribeProbe is exported for consumers in other API groups that have probes
  1617. func DescribeProbe(probe *corev1.Probe) string {
  1618. attrs := fmt.Sprintf("delay=%ds timeout=%ds period=%ds #success=%d #failure=%d", probe.InitialDelaySeconds, probe.TimeoutSeconds, probe.PeriodSeconds, probe.SuccessThreshold, probe.FailureThreshold)
  1619. switch {
  1620. case probe.Exec != nil:
  1621. return fmt.Sprintf("exec %v %s", probe.Exec.Command, attrs)
  1622. case probe.HTTPGet != nil:
  1623. url := &url.URL{}
  1624. url.Scheme = strings.ToLower(string(probe.HTTPGet.Scheme))
  1625. if len(probe.HTTPGet.Port.String()) > 0 {
  1626. url.Host = net.JoinHostPort(probe.HTTPGet.Host, probe.HTTPGet.Port.String())
  1627. } else {
  1628. url.Host = probe.HTTPGet.Host
  1629. }
  1630. url.Path = probe.HTTPGet.Path
  1631. return fmt.Sprintf("http-get %s %s", url.String(), attrs)
  1632. case probe.TCPSocket != nil:
  1633. return fmt.Sprintf("tcp-socket %s:%s %s", probe.TCPSocket.Host, probe.TCPSocket.Port.String(), attrs)
  1634. }
  1635. return fmt.Sprintf("unknown %s", attrs)
  1636. }
  1637. type EnvVarResolverFunc func(e corev1.EnvVar) string
  1638. // EnvValueFrom is exported for use by describers in other packages
  1639. func EnvValueRetriever(pod *corev1.Pod) EnvVarResolverFunc {
  1640. return func(e corev1.EnvVar) string {
  1641. gv, err := schema.ParseGroupVersion(e.ValueFrom.FieldRef.APIVersion)
  1642. if err != nil {
  1643. return ""
  1644. }
  1645. gvk := gv.WithKind("Pod")
  1646. internalFieldPath, _, err := scheme.Scheme.ConvertFieldLabel(gvk, e.ValueFrom.FieldRef.FieldPath, "")
  1647. if err != nil {
  1648. return "" // pod validation should catch this on create
  1649. }
  1650. valueFrom, err := fieldpath.ExtractFieldPathAsString(pod, internalFieldPath)
  1651. if err != nil {
  1652. return "" // pod validation should catch this on create
  1653. }
  1654. return valueFrom
  1655. }
  1656. }
  1657. func describeStatus(stateName string, state corev1.ContainerState, w PrefixWriter) {
  1658. switch {
  1659. case state.Running != nil:
  1660. w.Write(LEVEL_2, "%s:\tRunning\n", stateName)
  1661. w.Write(LEVEL_3, "Started:\t%v\n", state.Running.StartedAt.Time.Format(time.RFC1123Z))
  1662. case state.Waiting != nil:
  1663. w.Write(LEVEL_2, "%s:\tWaiting\n", stateName)
  1664. if state.Waiting.Reason != "" {
  1665. w.Write(LEVEL_3, "Reason:\t%s\n", state.Waiting.Reason)
  1666. }
  1667. case state.Terminated != nil:
  1668. w.Write(LEVEL_2, "%s:\tTerminated\n", stateName)
  1669. if state.Terminated.Reason != "" {
  1670. w.Write(LEVEL_3, "Reason:\t%s\n", state.Terminated.Reason)
  1671. }
  1672. if state.Terminated.Message != "" {
  1673. w.Write(LEVEL_3, "Message:\t%s\n", state.Terminated.Message)
  1674. }
  1675. w.Write(LEVEL_3, "Exit Code:\t%d\n", state.Terminated.ExitCode)
  1676. if state.Terminated.Signal > 0 {
  1677. w.Write(LEVEL_3, "Signal:\t%d\n", state.Terminated.Signal)
  1678. }
  1679. w.Write(LEVEL_3, "Started:\t%s\n", state.Terminated.StartedAt.Time.Format(time.RFC1123Z))
  1680. w.Write(LEVEL_3, "Finished:\t%s\n", state.Terminated.FinishedAt.Time.Format(time.RFC1123Z))
  1681. default:
  1682. w.Write(LEVEL_2, "%s:\tWaiting\n", stateName)
  1683. }
  1684. }
  1685. func describeVolumeClaimTemplates(templates []corev1.PersistentVolumeClaim, w PrefixWriter) {
  1686. if len(templates) == 0 {
  1687. w.Write(LEVEL_0, "Volume Claims:\t<none>\n")
  1688. return
  1689. }
  1690. w.Write(LEVEL_0, "Volume Claims:\n")
  1691. for _, pvc := range templates {
  1692. w.Write(LEVEL_1, "Name:\t%s\n", pvc.Name)
  1693. w.Write(LEVEL_1, "StorageClass:\t%s\n", storageutil.GetPersistentVolumeClaimClass(&pvc))
  1694. printLabelsMultilineWithIndent(w, " ", "Labels", "\t", pvc.Labels, sets.NewString())
  1695. printLabelsMultilineWithIndent(w, " ", "Annotations", "\t", pvc.Annotations, sets.NewString())
  1696. if capacity, ok := pvc.Spec.Resources.Requests[corev1.ResourceStorage]; ok {
  1697. w.Write(LEVEL_1, "Capacity:\t%s\n", capacity.String())
  1698. } else {
  1699. w.Write(LEVEL_1, "Capacity:\t%s\n", "<default>")
  1700. }
  1701. w.Write(LEVEL_1, "Access Modes:\t%s\n", pvc.Spec.AccessModes)
  1702. }
  1703. }
  1704. func printBoolPtr(value *bool) string {
  1705. if value != nil {
  1706. return printBool(*value)
  1707. }
  1708. return "<unset>"
  1709. }
  1710. func printBool(value bool) string {
  1711. if value {
  1712. return "True"
  1713. }
  1714. return "False"
  1715. }
  1716. // ReplicationControllerDescriber generates information about a replication controller
  1717. // and the pods it has created.
  1718. type ReplicationControllerDescriber struct {
  1719. clientset.Interface
  1720. }
  1721. func (d *ReplicationControllerDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  1722. rc := d.CoreV1().ReplicationControllers(namespace)
  1723. pc := d.CoreV1().Pods(namespace)
  1724. controller, err := rc.Get(name, metav1.GetOptions{})
  1725. if err != nil {
  1726. return "", err
  1727. }
  1728. running, waiting, succeeded, failed, err := getPodStatusForController(pc, labels.SelectorFromSet(controller.Spec.Selector), controller.UID)
  1729. if err != nil {
  1730. return "", err
  1731. }
  1732. var events *corev1.EventList
  1733. if describerSettings.ShowEvents {
  1734. events, _ = d.CoreV1().Events(namespace).Search(scheme.Scheme, controller)
  1735. }
  1736. return describeReplicationController(controller, events, running, waiting, succeeded, failed)
  1737. }
  1738. func describeReplicationController(controller *corev1.ReplicationController, events *corev1.EventList, running, waiting, succeeded, failed int) (string, error) {
  1739. return tabbedString(func(out io.Writer) error {
  1740. w := NewPrefixWriter(out)
  1741. w.Write(LEVEL_0, "Name:\t%s\n", controller.Name)
  1742. w.Write(LEVEL_0, "Namespace:\t%s\n", controller.Namespace)
  1743. w.Write(LEVEL_0, "Selector:\t%s\n", labels.FormatLabels(controller.Spec.Selector))
  1744. printLabelsMultiline(w, "Labels", controller.Labels)
  1745. printAnnotationsMultiline(w, "Annotations", controller.Annotations)
  1746. w.Write(LEVEL_0, "Replicas:\t%d current / %d desired\n", controller.Status.Replicas, *controller.Spec.Replicas)
  1747. w.Write(LEVEL_0, "Pods Status:\t%d Running / %d Waiting / %d Succeeded / %d Failed\n", running, waiting, succeeded, failed)
  1748. DescribePodTemplate(controller.Spec.Template, w)
  1749. if len(controller.Status.Conditions) > 0 {
  1750. w.Write(LEVEL_0, "Conditions:\n Type\tStatus\tReason\n")
  1751. w.Write(LEVEL_1, "----\t------\t------\n")
  1752. for _, c := range controller.Status.Conditions {
  1753. w.Write(LEVEL_1, "%v \t%v\t%v\n", c.Type, c.Status, c.Reason)
  1754. }
  1755. }
  1756. if events != nil {
  1757. DescribeEvents(events, w)
  1758. }
  1759. return nil
  1760. })
  1761. }
  1762. func DescribePodTemplate(template *corev1.PodTemplateSpec, w PrefixWriter) {
  1763. w.Write(LEVEL_0, "Pod Template:\n")
  1764. if template == nil {
  1765. w.Write(LEVEL_1, "<unset>")
  1766. return
  1767. }
  1768. printLabelsMultiline(w, " Labels", template.Labels)
  1769. if len(template.Annotations) > 0 {
  1770. printAnnotationsMultiline(w, " Annotations", template.Annotations)
  1771. }
  1772. if len(template.Spec.ServiceAccountName) > 0 {
  1773. w.Write(LEVEL_1, "Service Account:\t%s\n", template.Spec.ServiceAccountName)
  1774. }
  1775. if len(template.Spec.InitContainers) > 0 {
  1776. describeContainers("Init Containers", template.Spec.InitContainers, nil, nil, w, " ")
  1777. }
  1778. describeContainers("Containers", template.Spec.Containers, nil, nil, w, " ")
  1779. describeVolumes(template.Spec.Volumes, w, " ")
  1780. if len(template.Spec.PriorityClassName) > 0 {
  1781. w.Write(LEVEL_1, "Priority Class Name:\t%s\n", template.Spec.PriorityClassName)
  1782. }
  1783. }
  1784. // ReplicaSetDescriber generates information about a ReplicaSet and the pods it has created.
  1785. type ReplicaSetDescriber struct {
  1786. clientset.Interface
  1787. }
  1788. func (d *ReplicaSetDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  1789. rsc := d.AppsV1().ReplicaSets(namespace)
  1790. pc := d.CoreV1().Pods(namespace)
  1791. rs, err := rsc.Get(name, metav1.GetOptions{})
  1792. if err != nil {
  1793. return "", err
  1794. }
  1795. selector, err := metav1.LabelSelectorAsSelector(rs.Spec.Selector)
  1796. if err != nil {
  1797. return "", err
  1798. }
  1799. running, waiting, succeeded, failed, getPodErr := getPodStatusForController(pc, selector, rs.UID)
  1800. var events *corev1.EventList
  1801. if describerSettings.ShowEvents {
  1802. events, _ = d.CoreV1().Events(namespace).Search(scheme.Scheme, rs)
  1803. }
  1804. return describeReplicaSet(rs, events, running, waiting, succeeded, failed, getPodErr)
  1805. }
  1806. func describeReplicaSet(rs *appsv1.ReplicaSet, events *corev1.EventList, running, waiting, succeeded, failed int, getPodErr error) (string, error) {
  1807. return tabbedString(func(out io.Writer) error {
  1808. w := NewPrefixWriter(out)
  1809. w.Write(LEVEL_0, "Name:\t%s\n", rs.Name)
  1810. w.Write(LEVEL_0, "Namespace:\t%s\n", rs.Namespace)
  1811. w.Write(LEVEL_0, "Selector:\t%s\n", metav1.FormatLabelSelector(rs.Spec.Selector))
  1812. printLabelsMultiline(w, "Labels", rs.Labels)
  1813. printAnnotationsMultiline(w, "Annotations", rs.Annotations)
  1814. if controlledBy := printController(rs); len(controlledBy) > 0 {
  1815. w.Write(LEVEL_0, "Controlled By:\t%s\n", controlledBy)
  1816. }
  1817. w.Write(LEVEL_0, "Replicas:\t%d current / %d desired\n", rs.Status.Replicas, *rs.Spec.Replicas)
  1818. w.Write(LEVEL_0, "Pods Status:\t")
  1819. if getPodErr != nil {
  1820. w.Write(LEVEL_0, "error in fetching pods: %s\n", getPodErr)
  1821. } else {
  1822. w.Write(LEVEL_0, "%d Running / %d Waiting / %d Succeeded / %d Failed\n", running, waiting, succeeded, failed)
  1823. }
  1824. DescribePodTemplate(&rs.Spec.Template, w)
  1825. if len(rs.Status.Conditions) > 0 {
  1826. w.Write(LEVEL_0, "Conditions:\n Type\tStatus\tReason\n")
  1827. w.Write(LEVEL_1, "----\t------\t------\n")
  1828. for _, c := range rs.Status.Conditions {
  1829. w.Write(LEVEL_1, "%v \t%v\t%v\n", c.Type, c.Status, c.Reason)
  1830. }
  1831. }
  1832. if events != nil {
  1833. DescribeEvents(events, w)
  1834. }
  1835. return nil
  1836. })
  1837. }
  1838. // JobDescriber generates information about a job and the pods it has created.
  1839. type JobDescriber struct {
  1840. clientset.Interface
  1841. }
  1842. func (d *JobDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  1843. job, err := d.BatchV1().Jobs(namespace).Get(name, metav1.GetOptions{})
  1844. if err != nil {
  1845. return "", err
  1846. }
  1847. var events *corev1.EventList
  1848. if describerSettings.ShowEvents {
  1849. events, _ = d.CoreV1().Events(namespace).Search(scheme.Scheme, job)
  1850. }
  1851. return describeJob(job, events)
  1852. }
  1853. func describeJob(job *batchv1.Job, events *corev1.EventList) (string, error) {
  1854. return tabbedString(func(out io.Writer) error {
  1855. w := NewPrefixWriter(out)
  1856. w.Write(LEVEL_0, "Name:\t%s\n", job.Name)
  1857. w.Write(LEVEL_0, "Namespace:\t%s\n", job.Namespace)
  1858. selector, _ := metav1.LabelSelectorAsSelector(job.Spec.Selector)
  1859. w.Write(LEVEL_0, "Selector:\t%s\n", selector)
  1860. printLabelsMultiline(w, "Labels", job.Labels)
  1861. printAnnotationsMultiline(w, "Annotations", job.Annotations)
  1862. if controlledBy := printController(job); len(controlledBy) > 0 {
  1863. w.Write(LEVEL_0, "Controlled By:\t%s\n", controlledBy)
  1864. }
  1865. w.Write(LEVEL_0, "Parallelism:\t%d\n", *job.Spec.Parallelism)
  1866. if job.Spec.Completions != nil {
  1867. w.Write(LEVEL_0, "Completions:\t%d\n", *job.Spec.Completions)
  1868. } else {
  1869. w.Write(LEVEL_0, "Completions:\t<unset>\n")
  1870. }
  1871. if job.Status.StartTime != nil {
  1872. w.Write(LEVEL_0, "Start Time:\t%s\n", job.Status.StartTime.Time.Format(time.RFC1123Z))
  1873. }
  1874. if job.Status.CompletionTime != nil {
  1875. w.Write(LEVEL_0, "Completed At:\t%s\n", job.Status.CompletionTime.Time.Format(time.RFC1123Z))
  1876. }
  1877. if job.Status.StartTime != nil && job.Status.CompletionTime != nil {
  1878. w.Write(LEVEL_0, "Duration:\t%s\n", duration.HumanDuration(job.Status.CompletionTime.Sub(job.Status.StartTime.Time)))
  1879. }
  1880. if job.Spec.ActiveDeadlineSeconds != nil {
  1881. w.Write(LEVEL_0, "Active Deadline Seconds:\t%ds\n", *job.Spec.ActiveDeadlineSeconds)
  1882. }
  1883. w.Write(LEVEL_0, "Pods Statuses:\t%d Running / %d Succeeded / %d Failed\n", job.Status.Active, job.Status.Succeeded, job.Status.Failed)
  1884. DescribePodTemplate(&job.Spec.Template, w)
  1885. if events != nil {
  1886. DescribeEvents(events, w)
  1887. }
  1888. return nil
  1889. })
  1890. }
  1891. // CronJobDescriber generates information about a cron job and the jobs it has created.
  1892. type CronJobDescriber struct {
  1893. client clientset.Interface
  1894. }
  1895. func (d *CronJobDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  1896. cronJob, err := d.client.BatchV1beta1().CronJobs(namespace).Get(name, metav1.GetOptions{})
  1897. if err != nil {
  1898. return "", err
  1899. }
  1900. var events *corev1.EventList
  1901. if describerSettings.ShowEvents {
  1902. events, _ = d.client.CoreV1().Events(namespace).Search(scheme.Scheme, cronJob)
  1903. }
  1904. return describeCronJob(cronJob, events)
  1905. }
  1906. func describeCronJob(cronJob *batchv1beta1.CronJob, events *corev1.EventList) (string, error) {
  1907. return tabbedString(func(out io.Writer) error {
  1908. w := NewPrefixWriter(out)
  1909. w.Write(LEVEL_0, "Name:\t%s\n", cronJob.Name)
  1910. w.Write(LEVEL_0, "Namespace:\t%s\n", cronJob.Namespace)
  1911. printLabelsMultiline(w, "Labels", cronJob.Labels)
  1912. printAnnotationsMultiline(w, "Annotations", cronJob.Annotations)
  1913. w.Write(LEVEL_0, "Schedule:\t%s\n", cronJob.Spec.Schedule)
  1914. w.Write(LEVEL_0, "Concurrency Policy:\t%s\n", cronJob.Spec.ConcurrencyPolicy)
  1915. w.Write(LEVEL_0, "Suspend:\t%s\n", printBoolPtr(cronJob.Spec.Suspend))
  1916. if cronJob.Spec.SuccessfulJobsHistoryLimit != nil {
  1917. w.Write(LEVEL_0, "Successful Job History Limit:\t%d\n", *cronJob.Spec.SuccessfulJobsHistoryLimit)
  1918. } else {
  1919. w.Write(LEVEL_0, "Successful Job History Limit:\t<unset>\n")
  1920. }
  1921. if cronJob.Spec.FailedJobsHistoryLimit != nil {
  1922. w.Write(LEVEL_0, "Failed Job History Limit:\t%d\n", *cronJob.Spec.FailedJobsHistoryLimit)
  1923. } else {
  1924. w.Write(LEVEL_0, "Failed Job History Limit:\t<unset>\n")
  1925. }
  1926. if cronJob.Spec.StartingDeadlineSeconds != nil {
  1927. w.Write(LEVEL_0, "Starting Deadline Seconds:\t%ds\n", *cronJob.Spec.StartingDeadlineSeconds)
  1928. } else {
  1929. w.Write(LEVEL_0, "Starting Deadline Seconds:\t<unset>\n")
  1930. }
  1931. describeJobTemplate(cronJob.Spec.JobTemplate, w)
  1932. if cronJob.Status.LastScheduleTime != nil {
  1933. w.Write(LEVEL_0, "Last Schedule Time:\t%s\n", cronJob.Status.LastScheduleTime.Time.Format(time.RFC1123Z))
  1934. } else {
  1935. w.Write(LEVEL_0, "Last Schedule Time:\t<unset>\n")
  1936. }
  1937. printActiveJobs(w, "Active Jobs", cronJob.Status.Active)
  1938. if events != nil {
  1939. DescribeEvents(events, w)
  1940. }
  1941. return nil
  1942. })
  1943. }
  1944. func describeJobTemplate(jobTemplate batchv1beta1.JobTemplateSpec, w PrefixWriter) {
  1945. if jobTemplate.Spec.Selector != nil {
  1946. selector, _ := metav1.LabelSelectorAsSelector(jobTemplate.Spec.Selector)
  1947. w.Write(LEVEL_0, "Selector:\t%s\n", selector)
  1948. } else {
  1949. w.Write(LEVEL_0, "Selector:\t<unset>\n")
  1950. }
  1951. if jobTemplate.Spec.Parallelism != nil {
  1952. w.Write(LEVEL_0, "Parallelism:\t%d\n", *jobTemplate.Spec.Parallelism)
  1953. } else {
  1954. w.Write(LEVEL_0, "Parallelism:\t<unset>\n")
  1955. }
  1956. if jobTemplate.Spec.Completions != nil {
  1957. w.Write(LEVEL_0, "Completions:\t%d\n", *jobTemplate.Spec.Completions)
  1958. } else {
  1959. w.Write(LEVEL_0, "Completions:\t<unset>\n")
  1960. }
  1961. if jobTemplate.Spec.ActiveDeadlineSeconds != nil {
  1962. w.Write(LEVEL_0, "Active Deadline Seconds:\t%ds\n", *jobTemplate.Spec.ActiveDeadlineSeconds)
  1963. }
  1964. DescribePodTemplate(&jobTemplate.Spec.Template, w)
  1965. }
  1966. func printActiveJobs(w PrefixWriter, title string, jobs []corev1.ObjectReference) {
  1967. w.Write(LEVEL_0, "%s:\t", title)
  1968. if len(jobs) == 0 {
  1969. w.WriteLine("<none>")
  1970. return
  1971. }
  1972. for i, job := range jobs {
  1973. if i != 0 {
  1974. w.Write(LEVEL_0, ", ")
  1975. }
  1976. w.Write(LEVEL_0, "%s", job.Name)
  1977. }
  1978. w.WriteLine("")
  1979. }
  1980. // DaemonSetDescriber generates information about a daemon set and the pods it has created.
  1981. type DaemonSetDescriber struct {
  1982. clientset.Interface
  1983. }
  1984. func (d *DaemonSetDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  1985. dc := d.AppsV1().DaemonSets(namespace)
  1986. pc := d.CoreV1().Pods(namespace)
  1987. daemon, err := dc.Get(name, metav1.GetOptions{})
  1988. if err != nil {
  1989. return "", err
  1990. }
  1991. selector, err := metav1.LabelSelectorAsSelector(daemon.Spec.Selector)
  1992. if err != nil {
  1993. return "", err
  1994. }
  1995. running, waiting, succeeded, failed, err := getPodStatusForController(pc, selector, daemon.UID)
  1996. if err != nil {
  1997. return "", err
  1998. }
  1999. var events *corev1.EventList
  2000. if describerSettings.ShowEvents {
  2001. events, _ = d.CoreV1().Events(namespace).Search(scheme.Scheme, daemon)
  2002. }
  2003. return describeDaemonSet(daemon, events, running, waiting, succeeded, failed)
  2004. }
  2005. func describeDaemonSet(daemon *appsv1.DaemonSet, events *corev1.EventList, running, waiting, succeeded, failed int) (string, error) {
  2006. return tabbedString(func(out io.Writer) error {
  2007. w := NewPrefixWriter(out)
  2008. w.Write(LEVEL_0, "Name:\t%s\n", daemon.Name)
  2009. selector, err := metav1.LabelSelectorAsSelector(daemon.Spec.Selector)
  2010. if err != nil {
  2011. // this shouldn't happen if LabelSelector passed validation
  2012. return err
  2013. }
  2014. w.Write(LEVEL_0, "Selector:\t%s\n", selector)
  2015. w.Write(LEVEL_0, "Node-Selector:\t%s\n", labels.FormatLabels(daemon.Spec.Template.Spec.NodeSelector))
  2016. printLabelsMultiline(w, "Labels", daemon.Labels)
  2017. printAnnotationsMultiline(w, "Annotations", daemon.Annotations)
  2018. w.Write(LEVEL_0, "Desired Number of Nodes Scheduled: %d\n", daemon.Status.DesiredNumberScheduled)
  2019. w.Write(LEVEL_0, "Current Number of Nodes Scheduled: %d\n", daemon.Status.CurrentNumberScheduled)
  2020. w.Write(LEVEL_0, "Number of Nodes Scheduled with Up-to-date Pods: %d\n", daemon.Status.UpdatedNumberScheduled)
  2021. w.Write(LEVEL_0, "Number of Nodes Scheduled with Available Pods: %d\n", daemon.Status.NumberAvailable)
  2022. w.Write(LEVEL_0, "Number of Nodes Misscheduled: %d\n", daemon.Status.NumberMisscheduled)
  2023. w.Write(LEVEL_0, "Pods Status:\t%d Running / %d Waiting / %d Succeeded / %d Failed\n", running, waiting, succeeded, failed)
  2024. DescribePodTemplate(&daemon.Spec.Template, w)
  2025. if events != nil {
  2026. DescribeEvents(events, w)
  2027. }
  2028. return nil
  2029. })
  2030. }
  2031. // SecretDescriber generates information about a secret
  2032. type SecretDescriber struct {
  2033. clientset.Interface
  2034. }
  2035. func (d *SecretDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  2036. c := d.CoreV1().Secrets(namespace)
  2037. secret, err := c.Get(name, metav1.GetOptions{})
  2038. if err != nil {
  2039. return "", err
  2040. }
  2041. return describeSecret(secret)
  2042. }
  2043. func describeSecret(secret *corev1.Secret) (string, error) {
  2044. return tabbedString(func(out io.Writer) error {
  2045. w := NewPrefixWriter(out)
  2046. w.Write(LEVEL_0, "Name:\t%s\n", secret.Name)
  2047. w.Write(LEVEL_0, "Namespace:\t%s\n", secret.Namespace)
  2048. printLabelsMultiline(w, "Labels", secret.Labels)
  2049. skipAnnotations := sets.NewString(corev1.LastAppliedConfigAnnotation)
  2050. printAnnotationsMultilineWithFilter(w, "Annotations", secret.Annotations, skipAnnotations)
  2051. w.Write(LEVEL_0, "\nType:\t%s\n", secret.Type)
  2052. w.Write(LEVEL_0, "\nData\n====\n")
  2053. for k, v := range secret.Data {
  2054. switch {
  2055. case k == corev1.ServiceAccountTokenKey && secret.Type == corev1.SecretTypeServiceAccountToken:
  2056. w.Write(LEVEL_0, "%s:\t%s\n", k, string(v))
  2057. default:
  2058. w.Write(LEVEL_0, "%s:\t%d bytes\n", k, len(v))
  2059. }
  2060. }
  2061. return nil
  2062. })
  2063. }
  2064. type IngressDescriber struct {
  2065. clientset.Interface
  2066. }
  2067. func (i *IngressDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  2068. c := i.NetworkingV1beta1().Ingresses(namespace)
  2069. ing, err := c.Get(name, metav1.GetOptions{})
  2070. if err != nil {
  2071. return "", err
  2072. }
  2073. return i.describeIngress(ing, describerSettings)
  2074. }
  2075. func (i *IngressDescriber) describeBackend(ns string, backend *networkingv1beta1.IngressBackend) string {
  2076. endpoints, _ := i.CoreV1().Endpoints(ns).Get(backend.ServiceName, metav1.GetOptions{})
  2077. service, _ := i.CoreV1().Services(ns).Get(backend.ServiceName, metav1.GetOptions{})
  2078. spName := ""
  2079. for i := range service.Spec.Ports {
  2080. sp := &service.Spec.Ports[i]
  2081. switch backend.ServicePort.Type {
  2082. case intstr.String:
  2083. if backend.ServicePort.StrVal == sp.Name {
  2084. spName = sp.Name
  2085. }
  2086. case intstr.Int:
  2087. if int32(backend.ServicePort.IntVal) == sp.Port {
  2088. spName = sp.Name
  2089. }
  2090. }
  2091. }
  2092. return formatEndpoints(endpoints, sets.NewString(spName))
  2093. }
  2094. func (i *IngressDescriber) describeIngress(ing *networkingv1beta1.Ingress, describerSettings describe.DescriberSettings) (string, error) {
  2095. return tabbedString(func(out io.Writer) error {
  2096. w := NewPrefixWriter(out)
  2097. w.Write(LEVEL_0, "Name:\t%v\n", ing.Name)
  2098. w.Write(LEVEL_0, "Namespace:\t%v\n", ing.Namespace)
  2099. w.Write(LEVEL_0, "Address:\t%v\n", loadBalancerStatusStringer(ing.Status.LoadBalancer, true))
  2100. def := ing.Spec.Backend
  2101. ns := ing.Namespace
  2102. if def == nil {
  2103. // Ingresses that don't specify a default backend inherit the
  2104. // default backend in the kube-system namespace.
  2105. def = &networkingv1beta1.IngressBackend{
  2106. ServiceName: "default-http-backend",
  2107. ServicePort: intstr.IntOrString{Type: intstr.Int, IntVal: 80},
  2108. }
  2109. ns = metav1.NamespaceSystem
  2110. }
  2111. w.Write(LEVEL_0, "Default backend:\t%s (%s)\n", backendStringer(def), i.describeBackend(ns, def))
  2112. if len(ing.Spec.TLS) != 0 {
  2113. describeIngressTLS(w, ing.Spec.TLS)
  2114. }
  2115. w.Write(LEVEL_0, "Rules:\n Host\tPath\tBackends\n")
  2116. w.Write(LEVEL_1, "----\t----\t--------\n")
  2117. count := 0
  2118. for _, rules := range ing.Spec.Rules {
  2119. if rules.HTTP == nil {
  2120. continue
  2121. }
  2122. count++
  2123. host := rules.Host
  2124. if len(host) == 0 {
  2125. host = "*"
  2126. }
  2127. w.Write(LEVEL_1, "%s\t\n", host)
  2128. for _, path := range rules.HTTP.Paths {
  2129. w.Write(LEVEL_2, "\t%s \t%s (%s)\n", path.Path, backendStringer(&path.Backend), i.describeBackend(ing.Namespace, &path.Backend))
  2130. }
  2131. }
  2132. if count == 0 {
  2133. w.Write(LEVEL_1, "%s\t%s \t%s (%s)\n", "*", "*", backendStringer(def), i.describeBackend(ns, def))
  2134. }
  2135. describeIngressAnnotations(w, ing.Annotations)
  2136. if describerSettings.ShowEvents {
  2137. events, _ := i.CoreV1().Events(ing.Namespace).Search(scheme.Scheme, ing)
  2138. if events != nil {
  2139. DescribeEvents(events, w)
  2140. }
  2141. }
  2142. return nil
  2143. })
  2144. }
  2145. func describeIngressTLS(w PrefixWriter, ingTLS []networkingv1beta1.IngressTLS) {
  2146. w.Write(LEVEL_0, "TLS:\n")
  2147. for _, t := range ingTLS {
  2148. if t.SecretName == "" {
  2149. w.Write(LEVEL_1, "SNI routes %v\n", strings.Join(t.Hosts, ","))
  2150. } else {
  2151. w.Write(LEVEL_1, "%v terminates %v\n", t.SecretName, strings.Join(t.Hosts, ","))
  2152. }
  2153. }
  2154. return
  2155. }
  2156. // TODO: Move from annotations into Ingress status.
  2157. func describeIngressAnnotations(w PrefixWriter, annotations map[string]string) {
  2158. w.Write(LEVEL_0, "Annotations:\n")
  2159. for k, v := range annotations {
  2160. w.Write(LEVEL_1, "%v:\t%s\n", k, v)
  2161. }
  2162. return
  2163. }
  2164. // ServiceDescriber generates information about a service.
  2165. type ServiceDescriber struct {
  2166. clientset.Interface
  2167. }
  2168. func (d *ServiceDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  2169. c := d.CoreV1().Services(namespace)
  2170. service, err := c.Get(name, metav1.GetOptions{})
  2171. if err != nil {
  2172. return "", err
  2173. }
  2174. endpoints, _ := d.CoreV1().Endpoints(namespace).Get(name, metav1.GetOptions{})
  2175. var events *corev1.EventList
  2176. if describerSettings.ShowEvents {
  2177. events, _ = d.CoreV1().Events(namespace).Search(scheme.Scheme, service)
  2178. }
  2179. return describeService(service, endpoints, events)
  2180. }
  2181. func buildIngressString(ingress []corev1.LoadBalancerIngress) string {
  2182. var buffer bytes.Buffer
  2183. for i := range ingress {
  2184. if i != 0 {
  2185. buffer.WriteString(", ")
  2186. }
  2187. if ingress[i].IP != "" {
  2188. buffer.WriteString(ingress[i].IP)
  2189. } else {
  2190. buffer.WriteString(ingress[i].Hostname)
  2191. }
  2192. }
  2193. return buffer.String()
  2194. }
  2195. func describeService(service *corev1.Service, endpoints *corev1.Endpoints, events *corev1.EventList) (string, error) {
  2196. if endpoints == nil {
  2197. endpoints = &corev1.Endpoints{}
  2198. }
  2199. return tabbedString(func(out io.Writer) error {
  2200. w := NewPrefixWriter(out)
  2201. w.Write(LEVEL_0, "Name:\t%s\n", service.Name)
  2202. w.Write(LEVEL_0, "Namespace:\t%s\n", service.Namespace)
  2203. printLabelsMultiline(w, "Labels", service.Labels)
  2204. printAnnotationsMultiline(w, "Annotations", service.Annotations)
  2205. w.Write(LEVEL_0, "Selector:\t%s\n", labels.FormatLabels(service.Spec.Selector))
  2206. w.Write(LEVEL_0, "Type:\t%s\n", service.Spec.Type)
  2207. w.Write(LEVEL_0, "IP:\t%s\n", service.Spec.ClusterIP)
  2208. if len(service.Spec.ExternalIPs) > 0 {
  2209. w.Write(LEVEL_0, "External IPs:\t%v\n", strings.Join(service.Spec.ExternalIPs, ","))
  2210. }
  2211. if service.Spec.LoadBalancerIP != "" {
  2212. w.Write(LEVEL_0, "IP:\t%s\n", service.Spec.LoadBalancerIP)
  2213. }
  2214. if service.Spec.ExternalName != "" {
  2215. w.Write(LEVEL_0, "External Name:\t%s\n", service.Spec.ExternalName)
  2216. }
  2217. if len(service.Status.LoadBalancer.Ingress) > 0 {
  2218. list := buildIngressString(service.Status.LoadBalancer.Ingress)
  2219. w.Write(LEVEL_0, "LoadBalancer Ingress:\t%s\n", list)
  2220. }
  2221. for i := range service.Spec.Ports {
  2222. sp := &service.Spec.Ports[i]
  2223. name := sp.Name
  2224. if name == "" {
  2225. name = "<unset>"
  2226. }
  2227. w.Write(LEVEL_0, "Port:\t%s\t%d/%s\n", name, sp.Port, sp.Protocol)
  2228. if sp.TargetPort.Type == intstr.Type(intstr.Int) {
  2229. w.Write(LEVEL_0, "TargetPort:\t%d/%s\n", sp.TargetPort.IntVal, sp.Protocol)
  2230. } else {
  2231. w.Write(LEVEL_0, "TargetPort:\t%s/%s\n", sp.TargetPort.StrVal, sp.Protocol)
  2232. }
  2233. if sp.NodePort != 0 {
  2234. w.Write(LEVEL_0, "NodePort:\t%s\t%d/%s\n", name, sp.NodePort, sp.Protocol)
  2235. }
  2236. w.Write(LEVEL_0, "Endpoints:\t%s\n", formatEndpoints(endpoints, sets.NewString(sp.Name)))
  2237. }
  2238. w.Write(LEVEL_0, "Session Affinity:\t%s\n", service.Spec.SessionAffinity)
  2239. if service.Spec.ExternalTrafficPolicy != "" {
  2240. w.Write(LEVEL_0, "External Traffic Policy:\t%s\n", service.Spec.ExternalTrafficPolicy)
  2241. }
  2242. if service.Spec.HealthCheckNodePort != 0 {
  2243. w.Write(LEVEL_0, "HealthCheck NodePort:\t%d\n", service.Spec.HealthCheckNodePort)
  2244. }
  2245. if len(service.Spec.LoadBalancerSourceRanges) > 0 {
  2246. w.Write(LEVEL_0, "LoadBalancer Source Ranges:\t%v\n", strings.Join(service.Spec.LoadBalancerSourceRanges, ","))
  2247. }
  2248. if events != nil {
  2249. DescribeEvents(events, w)
  2250. }
  2251. return nil
  2252. })
  2253. }
  2254. // EndpointsDescriber generates information about an Endpoint.
  2255. type EndpointsDescriber struct {
  2256. clientset.Interface
  2257. }
  2258. func (d *EndpointsDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  2259. c := d.CoreV1().Endpoints(namespace)
  2260. ep, err := c.Get(name, metav1.GetOptions{})
  2261. if err != nil {
  2262. return "", err
  2263. }
  2264. var events *corev1.EventList
  2265. if describerSettings.ShowEvents {
  2266. events, _ = d.CoreV1().Events(namespace).Search(scheme.Scheme, ep)
  2267. }
  2268. return describeEndpoints(ep, events)
  2269. }
  2270. func describeEndpoints(ep *corev1.Endpoints, events *corev1.EventList) (string, error) {
  2271. return tabbedString(func(out io.Writer) error {
  2272. w := NewPrefixWriter(out)
  2273. w.Write(LEVEL_0, "Name:\t%s\n", ep.Name)
  2274. w.Write(LEVEL_0, "Namespace:\t%s\n", ep.Namespace)
  2275. printLabelsMultiline(w, "Labels", ep.Labels)
  2276. printAnnotationsMultiline(w, "Annotations", ep.Annotations)
  2277. w.Write(LEVEL_0, "Subsets:\n")
  2278. for i := range ep.Subsets {
  2279. subset := &ep.Subsets[i]
  2280. addresses := make([]string, 0, len(subset.Addresses))
  2281. for _, addr := range subset.Addresses {
  2282. addresses = append(addresses, addr.IP)
  2283. }
  2284. addressesString := strings.Join(addresses, ",")
  2285. if len(addressesString) == 0 {
  2286. addressesString = "<none>"
  2287. }
  2288. w.Write(LEVEL_1, "Addresses:\t%s\n", addressesString)
  2289. notReadyAddresses := make([]string, 0, len(subset.NotReadyAddresses))
  2290. for _, addr := range subset.NotReadyAddresses {
  2291. notReadyAddresses = append(notReadyAddresses, addr.IP)
  2292. }
  2293. notReadyAddressesString := strings.Join(notReadyAddresses, ",")
  2294. if len(notReadyAddressesString) == 0 {
  2295. notReadyAddressesString = "<none>"
  2296. }
  2297. w.Write(LEVEL_1, "NotReadyAddresses:\t%s\n", notReadyAddressesString)
  2298. if len(subset.Ports) > 0 {
  2299. w.Write(LEVEL_1, "Ports:\n")
  2300. w.Write(LEVEL_2, "Name\tPort\tProtocol\n")
  2301. w.Write(LEVEL_2, "----\t----\t--------\n")
  2302. for _, port := range subset.Ports {
  2303. name := port.Name
  2304. if len(name) == 0 {
  2305. name = "<unset>"
  2306. }
  2307. w.Write(LEVEL_2, "%s\t%d\t%s\n", name, port.Port, port.Protocol)
  2308. }
  2309. }
  2310. w.Write(LEVEL_0, "\n")
  2311. }
  2312. if events != nil {
  2313. DescribeEvents(events, w)
  2314. }
  2315. return nil
  2316. })
  2317. }
  2318. // ServiceAccountDescriber generates information about a service.
  2319. type ServiceAccountDescriber struct {
  2320. clientset.Interface
  2321. }
  2322. func (d *ServiceAccountDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  2323. c := d.CoreV1().ServiceAccounts(namespace)
  2324. serviceAccount, err := c.Get(name, metav1.GetOptions{})
  2325. if err != nil {
  2326. return "", err
  2327. }
  2328. tokens := []corev1.Secret{}
  2329. // missingSecrets is the set of all secrets present in the
  2330. // serviceAccount but not present in the set of existing secrets.
  2331. missingSecrets := sets.NewString()
  2332. secrets, err := d.CoreV1().Secrets(namespace).List(metav1.ListOptions{})
  2333. // errors are tolerated here in order to describe the serviceAccount with all
  2334. // of the secrets that it references, even if those secrets cannot be fetched.
  2335. if err == nil {
  2336. // existingSecrets is the set of all secrets remaining on a
  2337. // service account that are not present in the "tokens" slice.
  2338. existingSecrets := sets.NewString()
  2339. for _, s := range secrets.Items {
  2340. if s.Type == corev1.SecretTypeServiceAccountToken {
  2341. name, _ := s.Annotations[corev1.ServiceAccountNameKey]
  2342. uid, _ := s.Annotations[corev1.ServiceAccountUIDKey]
  2343. if name == serviceAccount.Name && uid == string(serviceAccount.UID) {
  2344. tokens = append(tokens, s)
  2345. }
  2346. }
  2347. existingSecrets.Insert(s.Name)
  2348. }
  2349. for _, s := range serviceAccount.Secrets {
  2350. if !existingSecrets.Has(s.Name) {
  2351. missingSecrets.Insert(s.Name)
  2352. }
  2353. }
  2354. for _, s := range serviceAccount.ImagePullSecrets {
  2355. if !existingSecrets.Has(s.Name) {
  2356. missingSecrets.Insert(s.Name)
  2357. }
  2358. }
  2359. }
  2360. var events *corev1.EventList
  2361. if describerSettings.ShowEvents {
  2362. events, _ = d.CoreV1().Events(namespace).Search(scheme.Scheme, serviceAccount)
  2363. }
  2364. return describeServiceAccount(serviceAccount, tokens, missingSecrets, events)
  2365. }
  2366. func describeServiceAccount(serviceAccount *corev1.ServiceAccount, tokens []corev1.Secret, missingSecrets sets.String, events *corev1.EventList) (string, error) {
  2367. return tabbedString(func(out io.Writer) error {
  2368. w := NewPrefixWriter(out)
  2369. w.Write(LEVEL_0, "Name:\t%s\n", serviceAccount.Name)
  2370. w.Write(LEVEL_0, "Namespace:\t%s\n", serviceAccount.Namespace)
  2371. printLabelsMultiline(w, "Labels", serviceAccount.Labels)
  2372. printAnnotationsMultiline(w, "Annotations", serviceAccount.Annotations)
  2373. var (
  2374. emptyHeader = " "
  2375. pullHeader = "Image pull secrets:"
  2376. mountHeader = "Mountable secrets: "
  2377. tokenHeader = "Tokens: "
  2378. pullSecretNames = []string{}
  2379. mountSecretNames = []string{}
  2380. tokenSecretNames = []string{}
  2381. )
  2382. for _, s := range serviceAccount.ImagePullSecrets {
  2383. pullSecretNames = append(pullSecretNames, s.Name)
  2384. }
  2385. for _, s := range serviceAccount.Secrets {
  2386. mountSecretNames = append(mountSecretNames, s.Name)
  2387. }
  2388. for _, s := range tokens {
  2389. tokenSecretNames = append(tokenSecretNames, s.Name)
  2390. }
  2391. types := map[string][]string{
  2392. pullHeader: pullSecretNames,
  2393. mountHeader: mountSecretNames,
  2394. tokenHeader: tokenSecretNames,
  2395. }
  2396. for _, header := range sets.StringKeySet(types).List() {
  2397. names := types[header]
  2398. if len(names) == 0 {
  2399. w.Write(LEVEL_0, "%s\t<none>\n", header)
  2400. } else {
  2401. prefix := header
  2402. for _, name := range names {
  2403. if missingSecrets.Has(name) {
  2404. w.Write(LEVEL_0, "%s\t%s (not found)\n", prefix, name)
  2405. } else {
  2406. w.Write(LEVEL_0, "%s\t%s\n", prefix, name)
  2407. }
  2408. prefix = emptyHeader
  2409. }
  2410. }
  2411. }
  2412. if events != nil {
  2413. DescribeEvents(events, w)
  2414. }
  2415. return nil
  2416. })
  2417. }
  2418. // RoleDescriber generates information about a node.
  2419. type RoleDescriber struct {
  2420. clientset.Interface
  2421. }
  2422. func (d *RoleDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  2423. role, err := d.RbacV1().Roles(namespace).Get(name, metav1.GetOptions{})
  2424. if err != nil {
  2425. return "", err
  2426. }
  2427. breakdownRules := []rbacv1.PolicyRule{}
  2428. for _, rule := range role.Rules {
  2429. breakdownRules = append(breakdownRules, rbac.BreakdownRule(rule)...)
  2430. }
  2431. compactRules, err := rbac.CompactRules(breakdownRules)
  2432. if err != nil {
  2433. return "", err
  2434. }
  2435. sort.Stable(rbac.SortableRuleSlice(compactRules))
  2436. return tabbedString(func(out io.Writer) error {
  2437. w := NewPrefixWriter(out)
  2438. w.Write(LEVEL_0, "Name:\t%s\n", role.Name)
  2439. printLabelsMultiline(w, "Labels", role.Labels)
  2440. printAnnotationsMultiline(w, "Annotations", role.Annotations)
  2441. w.Write(LEVEL_0, "PolicyRule:\n")
  2442. w.Write(LEVEL_1, "Resources\tNon-Resource URLs\tResource Names\tVerbs\n")
  2443. w.Write(LEVEL_1, "---------\t-----------------\t--------------\t-----\n")
  2444. for _, r := range compactRules {
  2445. w.Write(LEVEL_1, "%s\t%v\t%v\t%v\n", CombineResourceGroup(r.Resources, r.APIGroups), r.NonResourceURLs, r.ResourceNames, r.Verbs)
  2446. }
  2447. return nil
  2448. })
  2449. }
  2450. // ClusterRoleDescriber generates information about a node.
  2451. type ClusterRoleDescriber struct {
  2452. clientset.Interface
  2453. }
  2454. func (d *ClusterRoleDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  2455. role, err := d.RbacV1().ClusterRoles().Get(name, metav1.GetOptions{})
  2456. if err != nil {
  2457. return "", err
  2458. }
  2459. breakdownRules := []rbacv1.PolicyRule{}
  2460. for _, rule := range role.Rules {
  2461. breakdownRules = append(breakdownRules, rbac.BreakdownRule(rule)...)
  2462. }
  2463. compactRules, err := rbac.CompactRules(breakdownRules)
  2464. if err != nil {
  2465. return "", err
  2466. }
  2467. sort.Stable(rbac.SortableRuleSlice(compactRules))
  2468. return tabbedString(func(out io.Writer) error {
  2469. w := NewPrefixWriter(out)
  2470. w.Write(LEVEL_0, "Name:\t%s\n", role.Name)
  2471. printLabelsMultiline(w, "Labels", role.Labels)
  2472. printAnnotationsMultiline(w, "Annotations", role.Annotations)
  2473. w.Write(LEVEL_0, "PolicyRule:\n")
  2474. w.Write(LEVEL_1, "Resources\tNon-Resource URLs\tResource Names\tVerbs\n")
  2475. w.Write(LEVEL_1, "---------\t-----------------\t--------------\t-----\n")
  2476. for _, r := range compactRules {
  2477. w.Write(LEVEL_1, "%s\t%v\t%v\t%v\n", CombineResourceGroup(r.Resources, r.APIGroups), r.NonResourceURLs, r.ResourceNames, r.Verbs)
  2478. }
  2479. return nil
  2480. })
  2481. }
  2482. func CombineResourceGroup(resource, group []string) string {
  2483. if len(resource) == 0 {
  2484. return ""
  2485. }
  2486. parts := strings.SplitN(resource[0], "/", 2)
  2487. combine := parts[0]
  2488. if len(group) > 0 && group[0] != "" {
  2489. combine = combine + "." + group[0]
  2490. }
  2491. if len(parts) == 2 {
  2492. combine = combine + "/" + parts[1]
  2493. }
  2494. return combine
  2495. }
  2496. // RoleBindingDescriber generates information about a node.
  2497. type RoleBindingDescriber struct {
  2498. clientset.Interface
  2499. }
  2500. func (d *RoleBindingDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  2501. binding, err := d.RbacV1().RoleBindings(namespace).Get(name, metav1.GetOptions{})
  2502. if err != nil {
  2503. return "", err
  2504. }
  2505. return tabbedString(func(out io.Writer) error {
  2506. w := NewPrefixWriter(out)
  2507. w.Write(LEVEL_0, "Name:\t%s\n", binding.Name)
  2508. printLabelsMultiline(w, "Labels", binding.Labels)
  2509. printAnnotationsMultiline(w, "Annotations", binding.Annotations)
  2510. w.Write(LEVEL_0, "Role:\n")
  2511. w.Write(LEVEL_1, "Kind:\t%s\n", binding.RoleRef.Kind)
  2512. w.Write(LEVEL_1, "Name:\t%s\n", binding.RoleRef.Name)
  2513. w.Write(LEVEL_0, "Subjects:\n")
  2514. w.Write(LEVEL_1, "Kind\tName\tNamespace\n")
  2515. w.Write(LEVEL_1, "----\t----\t---------\n")
  2516. for _, s := range binding.Subjects {
  2517. w.Write(LEVEL_1, "%s\t%s\t%s\n", s.Kind, s.Name, s.Namespace)
  2518. }
  2519. return nil
  2520. })
  2521. }
  2522. // ClusterRoleBindingDescriber generates information about a node.
  2523. type ClusterRoleBindingDescriber struct {
  2524. clientset.Interface
  2525. }
  2526. func (d *ClusterRoleBindingDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  2527. binding, err := d.RbacV1().ClusterRoleBindings().Get(name, metav1.GetOptions{})
  2528. if err != nil {
  2529. return "", err
  2530. }
  2531. return tabbedString(func(out io.Writer) error {
  2532. w := NewPrefixWriter(out)
  2533. w.Write(LEVEL_0, "Name:\t%s\n", binding.Name)
  2534. printLabelsMultiline(w, "Labels", binding.Labels)
  2535. printAnnotationsMultiline(w, "Annotations", binding.Annotations)
  2536. w.Write(LEVEL_0, "Role:\n")
  2537. w.Write(LEVEL_1, "Kind:\t%s\n", binding.RoleRef.Kind)
  2538. w.Write(LEVEL_1, "Name:\t%s\n", binding.RoleRef.Name)
  2539. w.Write(LEVEL_0, "Subjects:\n")
  2540. w.Write(LEVEL_1, "Kind\tName\tNamespace\n")
  2541. w.Write(LEVEL_1, "----\t----\t---------\n")
  2542. for _, s := range binding.Subjects {
  2543. w.Write(LEVEL_1, "%s\t%s\t%s\n", s.Kind, s.Name, s.Namespace)
  2544. }
  2545. return nil
  2546. })
  2547. }
  2548. // NodeDescriber generates information about a node.
  2549. type NodeDescriber struct {
  2550. clientset.Interface
  2551. }
  2552. func (d *NodeDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  2553. mc := d.CoreV1().Nodes()
  2554. node, err := mc.Get(name, metav1.GetOptions{})
  2555. if err != nil {
  2556. return "", err
  2557. }
  2558. fieldSelector, err := fields.ParseSelector("spec.nodeName=" + name + ",status.phase!=" + string(corev1.PodSucceeded) + ",status.phase!=" + string(corev1.PodFailed))
  2559. if err != nil {
  2560. return "", err
  2561. }
  2562. // in a policy aware setting, users may have access to a node, but not all pods
  2563. // in that case, we note that the user does not have access to the pods
  2564. canViewPods := true
  2565. nodeNonTerminatedPodsList, err := d.CoreV1().Pods(namespace).List(metav1.ListOptions{FieldSelector: fieldSelector.String()})
  2566. if err != nil {
  2567. if !errors.IsForbidden(err) {
  2568. return "", err
  2569. }
  2570. canViewPods = false
  2571. }
  2572. var events *corev1.EventList
  2573. if describerSettings.ShowEvents {
  2574. if ref, err := reference.GetReference(scheme.Scheme, node); err != nil {
  2575. klog.Errorf("Unable to construct reference to '%#v': %v", node, err)
  2576. } else {
  2577. // TODO: We haven't decided the namespace for Node object yet.
  2578. ref.UID = types.UID(ref.Name)
  2579. events, _ = d.CoreV1().Events("").Search(scheme.Scheme, ref)
  2580. }
  2581. }
  2582. return describeNode(node, nodeNonTerminatedPodsList, events, canViewPods)
  2583. }
  2584. func describeNode(node *corev1.Node, nodeNonTerminatedPodsList *corev1.PodList, events *corev1.EventList, canViewPods bool) (string, error) {
  2585. return tabbedString(func(out io.Writer) error {
  2586. w := NewPrefixWriter(out)
  2587. w.Write(LEVEL_0, "Name:\t%s\n", node.Name)
  2588. if roles := findNodeRoles(node); len(roles) > 0 {
  2589. w.Write(LEVEL_0, "Roles:\t%s\n", strings.Join(roles, ","))
  2590. } else {
  2591. w.Write(LEVEL_0, "Roles:\t%s\n", "<none>")
  2592. }
  2593. printLabelsMultiline(w, "Labels", node.Labels)
  2594. printAnnotationsMultiline(w, "Annotations", node.Annotations)
  2595. w.Write(LEVEL_0, "CreationTimestamp:\t%s\n", node.CreationTimestamp.Time.Format(time.RFC1123Z))
  2596. printNodeTaintsMultiline(w, "Taints", node.Spec.Taints)
  2597. w.Write(LEVEL_0, "Unschedulable:\t%v\n", node.Spec.Unschedulable)
  2598. if len(node.Status.Conditions) > 0 {
  2599. w.Write(LEVEL_0, "Conditions:\n Type\tStatus\tLastHeartbeatTime\tLastTransitionTime\tReason\tMessage\n")
  2600. w.Write(LEVEL_1, "----\t------\t-----------------\t------------------\t------\t-------\n")
  2601. for _, c := range node.Status.Conditions {
  2602. w.Write(LEVEL_1, "%v \t%v \t%s \t%s \t%v \t%v\n",
  2603. c.Type,
  2604. c.Status,
  2605. c.LastHeartbeatTime.Time.Format(time.RFC1123Z),
  2606. c.LastTransitionTime.Time.Format(time.RFC1123Z),
  2607. c.Reason,
  2608. c.Message)
  2609. }
  2610. }
  2611. w.Write(LEVEL_0, "Addresses:\n")
  2612. for _, address := range node.Status.Addresses {
  2613. w.Write(LEVEL_1, "%s:\t%s\n", address.Type, address.Address)
  2614. }
  2615. printResourceList := func(resourceList corev1.ResourceList) {
  2616. resources := make([]corev1.ResourceName, 0, len(resourceList))
  2617. for resource := range resourceList {
  2618. resources = append(resources, resource)
  2619. }
  2620. sort.Sort(SortableResourceNames(resources))
  2621. for _, resource := range resources {
  2622. value := resourceList[resource]
  2623. w.Write(LEVEL_0, " %s:\t%s\n", resource, value.String())
  2624. }
  2625. }
  2626. if len(node.Status.Capacity) > 0 {
  2627. w.Write(LEVEL_0, "Capacity:\n")
  2628. printResourceList(node.Status.Capacity)
  2629. }
  2630. if len(node.Status.Allocatable) > 0 {
  2631. w.Write(LEVEL_0, "Allocatable:\n")
  2632. printResourceList(node.Status.Allocatable)
  2633. }
  2634. w.Write(LEVEL_0, "System Info:\n")
  2635. w.Write(LEVEL_0, " Machine ID:\t%s\n", node.Status.NodeInfo.MachineID)
  2636. w.Write(LEVEL_0, " System UUID:\t%s\n", node.Status.NodeInfo.SystemUUID)
  2637. w.Write(LEVEL_0, " Boot ID:\t%s\n", node.Status.NodeInfo.BootID)
  2638. w.Write(LEVEL_0, " Kernel Version:\t%s\n", node.Status.NodeInfo.KernelVersion)
  2639. w.Write(LEVEL_0, " OS Image:\t%s\n", node.Status.NodeInfo.OSImage)
  2640. w.Write(LEVEL_0, " Operating System:\t%s\n", node.Status.NodeInfo.OperatingSystem)
  2641. w.Write(LEVEL_0, " Architecture:\t%s\n", node.Status.NodeInfo.Architecture)
  2642. w.Write(LEVEL_0, " Container Runtime Version:\t%s\n", node.Status.NodeInfo.ContainerRuntimeVersion)
  2643. w.Write(LEVEL_0, " Kubelet Version:\t%s\n", node.Status.NodeInfo.KubeletVersion)
  2644. w.Write(LEVEL_0, " Kube-Proxy Version:\t%s\n", node.Status.NodeInfo.KubeProxyVersion)
  2645. if len(node.Spec.PodCIDR) > 0 {
  2646. w.Write(LEVEL_0, "PodCIDR:\t%s\n", node.Spec.PodCIDR)
  2647. }
  2648. if len(node.Spec.ProviderID) > 0 {
  2649. w.Write(LEVEL_0, "ProviderID:\t%s\n", node.Spec.ProviderID)
  2650. }
  2651. if canViewPods && nodeNonTerminatedPodsList != nil {
  2652. describeNodeResource(nodeNonTerminatedPodsList, node, w)
  2653. } else {
  2654. w.Write(LEVEL_0, "Pods:\tnot authorized\n")
  2655. }
  2656. if events != nil {
  2657. DescribeEvents(events, w)
  2658. }
  2659. return nil
  2660. })
  2661. }
  2662. type StatefulSetDescriber struct {
  2663. client clientset.Interface
  2664. }
  2665. func (p *StatefulSetDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  2666. ps, err := p.client.AppsV1().StatefulSets(namespace).Get(name, metav1.GetOptions{})
  2667. if err != nil {
  2668. return "", err
  2669. }
  2670. pc := p.client.CoreV1().Pods(namespace)
  2671. selector, err := metav1.LabelSelectorAsSelector(ps.Spec.Selector)
  2672. if err != nil {
  2673. return "", err
  2674. }
  2675. running, waiting, succeeded, failed, err := getPodStatusForController(pc, selector, ps.UID)
  2676. if err != nil {
  2677. return "", err
  2678. }
  2679. var events *corev1.EventList
  2680. if describerSettings.ShowEvents {
  2681. events, _ = p.client.CoreV1().Events(namespace).Search(scheme.Scheme, ps)
  2682. }
  2683. return describeStatefulSet(ps, selector, events, running, waiting, succeeded, failed)
  2684. }
  2685. func describeStatefulSet(ps *appsv1.StatefulSet, selector labels.Selector, events *corev1.EventList, running, waiting, succeeded, failed int) (string, error) {
  2686. return tabbedString(func(out io.Writer) error {
  2687. w := NewPrefixWriter(out)
  2688. w.Write(LEVEL_0, "Name:\t%s\n", ps.ObjectMeta.Name)
  2689. w.Write(LEVEL_0, "Namespace:\t%s\n", ps.ObjectMeta.Namespace)
  2690. w.Write(LEVEL_0, "CreationTimestamp:\t%s\n", ps.CreationTimestamp.Time.Format(time.RFC1123Z))
  2691. w.Write(LEVEL_0, "Selector:\t%s\n", selector)
  2692. printLabelsMultiline(w, "Labels", ps.Labels)
  2693. printAnnotationsMultiline(w, "Annotations", ps.Annotations)
  2694. w.Write(LEVEL_0, "Replicas:\t%d desired | %d total\n", *ps.Spec.Replicas, ps.Status.Replicas)
  2695. w.Write(LEVEL_0, "Update Strategy:\t%s\n", ps.Spec.UpdateStrategy.Type)
  2696. if ps.Spec.UpdateStrategy.RollingUpdate != nil {
  2697. ru := ps.Spec.UpdateStrategy.RollingUpdate
  2698. if ru.Partition != nil {
  2699. w.Write(LEVEL_1, "Partition:\t%d\n", ru.Partition)
  2700. }
  2701. }
  2702. w.Write(LEVEL_0, "Pods Status:\t%d Running / %d Waiting / %d Succeeded / %d Failed\n", running, waiting, succeeded, failed)
  2703. DescribePodTemplate(&ps.Spec.Template, w)
  2704. describeVolumeClaimTemplates(ps.Spec.VolumeClaimTemplates, w)
  2705. if events != nil {
  2706. DescribeEvents(events, w)
  2707. }
  2708. return nil
  2709. })
  2710. }
  2711. type CertificateSigningRequestDescriber struct {
  2712. client clientset.Interface
  2713. }
  2714. func (p *CertificateSigningRequestDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  2715. csr, err := p.client.CertificatesV1beta1().CertificateSigningRequests().Get(name, metav1.GetOptions{})
  2716. if err != nil {
  2717. return "", err
  2718. }
  2719. cr, err := certificate.ParseCSR(csr)
  2720. if err != nil {
  2721. return "", fmt.Errorf("Error parsing CSR: %v", err)
  2722. }
  2723. status, err := extractCSRStatus(csr)
  2724. if err != nil {
  2725. return "", err
  2726. }
  2727. var events *corev1.EventList
  2728. if describerSettings.ShowEvents {
  2729. events, _ = p.client.CoreV1().Events(namespace).Search(scheme.Scheme, csr)
  2730. }
  2731. return describeCertificateSigningRequest(csr, cr, status, events)
  2732. }
  2733. func describeCertificateSigningRequest(csr *certificatesv1beta1.CertificateSigningRequest, cr *x509.CertificateRequest, status string, events *corev1.EventList) (string, error) {
  2734. printListHelper := func(w PrefixWriter, prefix, name string, values []string) {
  2735. if len(values) == 0 {
  2736. return
  2737. }
  2738. w.Write(LEVEL_0, prefix+name+":\t")
  2739. w.Write(LEVEL_0, strings.Join(values, "\n"+prefix+"\t"))
  2740. w.Write(LEVEL_0, "\n")
  2741. }
  2742. return tabbedString(func(out io.Writer) error {
  2743. w := NewPrefixWriter(out)
  2744. w.Write(LEVEL_0, "Name:\t%s\n", csr.Name)
  2745. w.Write(LEVEL_0, "Labels:\t%s\n", labels.FormatLabels(csr.Labels))
  2746. w.Write(LEVEL_0, "Annotations:\t%s\n", labels.FormatLabels(csr.Annotations))
  2747. w.Write(LEVEL_0, "CreationTimestamp:\t%s\n", csr.CreationTimestamp.Time.Format(time.RFC1123Z))
  2748. w.Write(LEVEL_0, "Requesting User:\t%s\n", csr.Spec.Username)
  2749. w.Write(LEVEL_0, "Status:\t%s\n", status)
  2750. w.Write(LEVEL_0, "Subject:\n")
  2751. w.Write(LEVEL_0, "\tCommon Name:\t%s\n", cr.Subject.CommonName)
  2752. w.Write(LEVEL_0, "\tSerial Number:\t%s\n", cr.Subject.SerialNumber)
  2753. printListHelper(w, "\t", "Organization", cr.Subject.Organization)
  2754. printListHelper(w, "\t", "Organizational Unit", cr.Subject.OrganizationalUnit)
  2755. printListHelper(w, "\t", "Country", cr.Subject.Country)
  2756. printListHelper(w, "\t", "Locality", cr.Subject.Locality)
  2757. printListHelper(w, "\t", "Province", cr.Subject.Province)
  2758. printListHelper(w, "\t", "StreetAddress", cr.Subject.StreetAddress)
  2759. printListHelper(w, "\t", "PostalCode", cr.Subject.PostalCode)
  2760. if len(cr.DNSNames)+len(cr.EmailAddresses)+len(cr.IPAddresses) > 0 {
  2761. w.Write(LEVEL_0, "Subject Alternative Names:\n")
  2762. printListHelper(w, "\t", "DNS Names", cr.DNSNames)
  2763. printListHelper(w, "\t", "Email Addresses", cr.EmailAddresses)
  2764. var ipaddrs []string
  2765. for _, ipaddr := range cr.IPAddresses {
  2766. ipaddrs = append(ipaddrs, ipaddr.String())
  2767. }
  2768. printListHelper(w, "\t", "IP Addresses", ipaddrs)
  2769. }
  2770. if events != nil {
  2771. DescribeEvents(events, w)
  2772. }
  2773. return nil
  2774. })
  2775. }
  2776. // HorizontalPodAutoscalerDescriber generates information about a horizontal pod autoscaler.
  2777. type HorizontalPodAutoscalerDescriber struct {
  2778. client clientset.Interface
  2779. }
  2780. func (d *HorizontalPodAutoscalerDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  2781. var events *corev1.EventList
  2782. // autoscaling/v2beta2 is introduced since v1.12 and autoscaling/v1 does not have full backward compatibility
  2783. // with autoscaling/v2beta2, so describer will try to get and describe hpa v2beta2 object firstly, if it fails,
  2784. // describer will fall back to do with hpa v1 object
  2785. hpaV2beta2, err := d.client.AutoscalingV2beta2().HorizontalPodAutoscalers(namespace).Get(name, metav1.GetOptions{})
  2786. if err == nil {
  2787. if describerSettings.ShowEvents {
  2788. events, _ = d.client.CoreV1().Events(namespace).Search(scheme.Scheme, hpaV2beta2)
  2789. }
  2790. return describeHorizontalPodAutoscalerV2beta2(hpaV2beta2, events, d)
  2791. }
  2792. hpaV1, err := d.client.AutoscalingV1().HorizontalPodAutoscalers(namespace).Get(name, metav1.GetOptions{})
  2793. if err == nil {
  2794. if describerSettings.ShowEvents {
  2795. events, _ = d.client.CoreV1().Events(namespace).Search(scheme.Scheme, hpaV1)
  2796. }
  2797. return describeHorizontalPodAutoscalerV1(hpaV1, events, d)
  2798. }
  2799. return "", err
  2800. }
  2801. func describeHorizontalPodAutoscalerV2beta2(hpa *autoscalingv2beta2.HorizontalPodAutoscaler, events *corev1.EventList, d *HorizontalPodAutoscalerDescriber) (string, error) {
  2802. return tabbedString(func(out io.Writer) error {
  2803. w := NewPrefixWriter(out)
  2804. w.Write(LEVEL_0, "Name:\t%s\n", hpa.Name)
  2805. w.Write(LEVEL_0, "Namespace:\t%s\n", hpa.Namespace)
  2806. printLabelsMultiline(w, "Labels", hpa.Labels)
  2807. printAnnotationsMultiline(w, "Annotations", hpa.Annotations)
  2808. w.Write(LEVEL_0, "CreationTimestamp:\t%s\n", hpa.CreationTimestamp.Time.Format(time.RFC1123Z))
  2809. w.Write(LEVEL_0, "Reference:\t%s/%s\n",
  2810. hpa.Spec.ScaleTargetRef.Kind,
  2811. hpa.Spec.ScaleTargetRef.Name)
  2812. w.Write(LEVEL_0, "Metrics:\t( current / target )\n")
  2813. for i, metric := range hpa.Spec.Metrics {
  2814. switch metric.Type {
  2815. case autoscalingv2beta2.ExternalMetricSourceType:
  2816. if metric.External.Target.AverageValue != nil {
  2817. current := "<unknown>"
  2818. if len(hpa.Status.CurrentMetrics) > i && hpa.Status.CurrentMetrics[i].External != nil &&
  2819. &hpa.Status.CurrentMetrics[i].External.Current.AverageValue != nil {
  2820. current = hpa.Status.CurrentMetrics[i].External.Current.AverageValue.String()
  2821. }
  2822. w.Write(LEVEL_1, "%q (target average value):\t%s / %s\n", metric.External.Metric.Name, current, metric.External.Target.AverageValue.String())
  2823. } else {
  2824. current := "<unknown>"
  2825. if len(hpa.Status.CurrentMetrics) > i && hpa.Status.CurrentMetrics[i].External != nil {
  2826. current = hpa.Status.CurrentMetrics[i].External.Current.Value.String()
  2827. }
  2828. w.Write(LEVEL_1, "%q (target value):\t%s / %s\n", metric.External.Metric.Name, current, metric.External.Target.Value.String())
  2829. }
  2830. case autoscalingv2beta2.PodsMetricSourceType:
  2831. current := "<unknown>"
  2832. if len(hpa.Status.CurrentMetrics) > i && hpa.Status.CurrentMetrics[i].Pods != nil {
  2833. current = hpa.Status.CurrentMetrics[i].Pods.Current.AverageValue.String()
  2834. }
  2835. w.Write(LEVEL_1, "%q on pods:\t%s / %s\n", metric.Pods.Metric.Name, current, metric.Pods.Target.AverageValue.String())
  2836. case autoscalingv2beta2.ObjectMetricSourceType:
  2837. w.Write(LEVEL_1, "\"%s\" on %s/%s ", metric.Object.Metric.Name, metric.Object.DescribedObject.Kind, metric.Object.DescribedObject.Name)
  2838. if metric.Object.Target.Type == autoscalingv2beta2.AverageValueMetricType {
  2839. current := "<unknown>"
  2840. if len(hpa.Status.CurrentMetrics) > i && hpa.Status.CurrentMetrics[i].Object != nil {
  2841. current = hpa.Status.CurrentMetrics[i].Object.Current.AverageValue.String()
  2842. }
  2843. w.Write(LEVEL_0, "(target average value):\t%s / %s\n", current, metric.Object.Target.AverageValue.String())
  2844. } else {
  2845. current := "<unknown>"
  2846. if len(hpa.Status.CurrentMetrics) > i && hpa.Status.CurrentMetrics[i].Object != nil {
  2847. current = hpa.Status.CurrentMetrics[i].Object.Current.Value.String()
  2848. }
  2849. w.Write(LEVEL_0, "(target value):\t%s / %s\n", current, metric.Object.Target.Value.String())
  2850. }
  2851. case autoscalingv2beta2.ResourceMetricSourceType:
  2852. w.Write(LEVEL_1, "resource %s on pods", string(metric.Resource.Name))
  2853. if metric.Resource.Target.AverageValue != nil {
  2854. current := "<unknown>"
  2855. if len(hpa.Status.CurrentMetrics) > i && hpa.Status.CurrentMetrics[i].Resource != nil {
  2856. current = hpa.Status.CurrentMetrics[i].Resource.Current.AverageValue.String()
  2857. }
  2858. w.Write(LEVEL_0, ":\t%s / %s\n", current, metric.Resource.Target.AverageValue.String())
  2859. } else {
  2860. current := "<unknown>"
  2861. if len(hpa.Status.CurrentMetrics) > i && hpa.Status.CurrentMetrics[i].Resource != nil && hpa.Status.CurrentMetrics[i].Resource.Current.AverageUtilization != nil {
  2862. current = fmt.Sprintf("%d%% (%s)", *hpa.Status.CurrentMetrics[i].Resource.Current.AverageUtilization, hpa.Status.CurrentMetrics[i].Resource.Current.AverageValue.String())
  2863. }
  2864. target := "<auto>"
  2865. if metric.Resource.Target.AverageUtilization != nil {
  2866. target = fmt.Sprintf("%d%%", *metric.Resource.Target.AverageUtilization)
  2867. }
  2868. w.Write(LEVEL_1, "(as a percentage of request):\t%s / %s\n", current, target)
  2869. }
  2870. default:
  2871. w.Write(LEVEL_1, "<unknown metric type %q>", string(metric.Type))
  2872. }
  2873. }
  2874. minReplicas := "<unset>"
  2875. if hpa.Spec.MinReplicas != nil {
  2876. minReplicas = fmt.Sprintf("%d", *hpa.Spec.MinReplicas)
  2877. }
  2878. w.Write(LEVEL_0, "Min replicas:\t%s\n", minReplicas)
  2879. w.Write(LEVEL_0, "Max replicas:\t%d\n", hpa.Spec.MaxReplicas)
  2880. w.Write(LEVEL_0, "%s pods:\t", hpa.Spec.ScaleTargetRef.Kind)
  2881. w.Write(LEVEL_0, "%d current / %d desired\n", hpa.Status.CurrentReplicas, hpa.Status.DesiredReplicas)
  2882. if len(hpa.Status.Conditions) > 0 {
  2883. w.Write(LEVEL_0, "Conditions:\n")
  2884. w.Write(LEVEL_1, "Type\tStatus\tReason\tMessage\n")
  2885. w.Write(LEVEL_1, "----\t------\t------\t-------\n")
  2886. for _, c := range hpa.Status.Conditions {
  2887. w.Write(LEVEL_1, "%v\t%v\t%v\t%v\n", c.Type, c.Status, c.Reason, c.Message)
  2888. }
  2889. }
  2890. if events != nil {
  2891. DescribeEvents(events, w)
  2892. }
  2893. return nil
  2894. })
  2895. }
  2896. func describeHorizontalPodAutoscalerV1(hpa *autoscalingv1.HorizontalPodAutoscaler, events *corev1.EventList, d *HorizontalPodAutoscalerDescriber) (string, error) {
  2897. return tabbedString(func(out io.Writer) error {
  2898. w := NewPrefixWriter(out)
  2899. w.Write(LEVEL_0, "Name:\t%s\n", hpa.Name)
  2900. w.Write(LEVEL_0, "Namespace:\t%s\n", hpa.Namespace)
  2901. printLabelsMultiline(w, "Labels", hpa.Labels)
  2902. printAnnotationsMultiline(w, "Annotations", hpa.Annotations)
  2903. w.Write(LEVEL_0, "CreationTimestamp:\t%s\n", hpa.CreationTimestamp.Time.Format(time.RFC1123Z))
  2904. w.Write(LEVEL_0, "Reference:\t%s/%s\n",
  2905. hpa.Spec.ScaleTargetRef.Kind,
  2906. hpa.Spec.ScaleTargetRef.Name)
  2907. if hpa.Spec.TargetCPUUtilizationPercentage != nil {
  2908. w.Write(LEVEL_0, "Target CPU utilization:\t%d%%\n", *hpa.Spec.TargetCPUUtilizationPercentage)
  2909. current := "<unknown>"
  2910. if hpa.Status.CurrentCPUUtilizationPercentage != nil {
  2911. current = fmt.Sprintf("%d", *hpa.Status.CurrentCPUUtilizationPercentage)
  2912. }
  2913. w.Write(LEVEL_0, "Current CPU utilization:\t%s%%\n", current)
  2914. }
  2915. minReplicas := "<unset>"
  2916. if hpa.Spec.MinReplicas != nil {
  2917. minReplicas = fmt.Sprintf("%d", *hpa.Spec.MinReplicas)
  2918. }
  2919. w.Write(LEVEL_0, "Min replicas:\t%s\n", minReplicas)
  2920. w.Write(LEVEL_0, "Max replicas:\t%d\n", hpa.Spec.MaxReplicas)
  2921. w.Write(LEVEL_0, "%s pods:\t", hpa.Spec.ScaleTargetRef.Kind)
  2922. w.Write(LEVEL_0, "%d current / %d desired\n", hpa.Status.CurrentReplicas, hpa.Status.DesiredReplicas)
  2923. if events != nil {
  2924. DescribeEvents(events, w)
  2925. }
  2926. return nil
  2927. })
  2928. }
  2929. func describeNodeResource(nodeNonTerminatedPodsList *corev1.PodList, node *corev1.Node, w PrefixWriter) {
  2930. w.Write(LEVEL_0, "Non-terminated Pods:\t(%d in total)\n", len(nodeNonTerminatedPodsList.Items))
  2931. w.Write(LEVEL_1, "Namespace\tName\t\tCPU Requests\tCPU Limits\tMemory Requests\tMemory Limits\tAGE\n")
  2932. w.Write(LEVEL_1, "---------\t----\t\t------------\t----------\t---------------\t-------------\t---\n")
  2933. allocatable := node.Status.Capacity
  2934. if len(node.Status.Allocatable) > 0 {
  2935. allocatable = node.Status.Allocatable
  2936. }
  2937. for _, pod := range nodeNonTerminatedPodsList.Items {
  2938. req, limit := resourcehelper.PodRequestsAndLimits(&pod)
  2939. cpuReq, cpuLimit, memoryReq, memoryLimit := req[corev1.ResourceCPU], limit[corev1.ResourceCPU], req[corev1.ResourceMemory], limit[corev1.ResourceMemory]
  2940. fractionCpuReq := float64(cpuReq.MilliValue()) / float64(allocatable.Cpu().MilliValue()) * 100
  2941. fractionCpuLimit := float64(cpuLimit.MilliValue()) / float64(allocatable.Cpu().MilliValue()) * 100
  2942. fractionMemoryReq := float64(memoryReq.Value()) / float64(allocatable.Memory().Value()) * 100
  2943. fractionMemoryLimit := float64(memoryLimit.Value()) / float64(allocatable.Memory().Value()) * 100
  2944. w.Write(LEVEL_1, "%s\t%s\t\t%s (%d%%)\t%s (%d%%)\t%s (%d%%)\t%s (%d%%)\t%s\n", pod.Namespace, pod.Name,
  2945. cpuReq.String(), int64(fractionCpuReq), cpuLimit.String(), int64(fractionCpuLimit),
  2946. memoryReq.String(), int64(fractionMemoryReq), memoryLimit.String(), int64(fractionMemoryLimit), translateTimestampSince(pod.CreationTimestamp))
  2947. }
  2948. w.Write(LEVEL_0, "Allocated resources:\n (Total limits may be over 100 percent, i.e., overcommitted.)\n")
  2949. w.Write(LEVEL_1, "Resource\tRequests\tLimits\n")
  2950. w.Write(LEVEL_1, "--------\t--------\t------\n")
  2951. reqs, limits := getPodsTotalRequestsAndLimits(nodeNonTerminatedPodsList)
  2952. cpuReqs, cpuLimits, memoryReqs, memoryLimits, ephemeralstorageReqs, ephemeralstorageLimits :=
  2953. reqs[corev1.ResourceCPU], limits[corev1.ResourceCPU], reqs[corev1.ResourceMemory], limits[corev1.ResourceMemory], reqs[corev1.ResourceEphemeralStorage], limits[corev1.ResourceEphemeralStorage]
  2954. fractionCpuReqs := float64(0)
  2955. fractionCpuLimits := float64(0)
  2956. if allocatable.Cpu().MilliValue() != 0 {
  2957. fractionCpuReqs = float64(cpuReqs.MilliValue()) / float64(allocatable.Cpu().MilliValue()) * 100
  2958. fractionCpuLimits = float64(cpuLimits.MilliValue()) / float64(allocatable.Cpu().MilliValue()) * 100
  2959. }
  2960. fractionMemoryReqs := float64(0)
  2961. fractionMemoryLimits := float64(0)
  2962. if allocatable.Memory().Value() != 0 {
  2963. fractionMemoryReqs = float64(memoryReqs.Value()) / float64(allocatable.Memory().Value()) * 100
  2964. fractionMemoryLimits = float64(memoryLimits.Value()) / float64(allocatable.Memory().Value()) * 100
  2965. }
  2966. fractionEphemeralStorageReqs := float64(0)
  2967. fractionEphemeralStorageLimits := float64(0)
  2968. if allocatable.StorageEphemeral().Value() != 0 {
  2969. fractionEphemeralStorageReqs = float64(ephemeralstorageReqs.Value()) / float64(allocatable.StorageEphemeral().Value()) * 100
  2970. fractionEphemeralStorageLimits = float64(ephemeralstorageLimits.Value()) / float64(allocatable.StorageEphemeral().Value()) * 100
  2971. }
  2972. w.Write(LEVEL_1, "%s\t%s (%d%%)\t%s (%d%%)\n",
  2973. corev1.ResourceCPU, cpuReqs.String(), int64(fractionCpuReqs), cpuLimits.String(), int64(fractionCpuLimits))
  2974. w.Write(LEVEL_1, "%s\t%s (%d%%)\t%s (%d%%)\n",
  2975. corev1.ResourceMemory, memoryReqs.String(), int64(fractionMemoryReqs), memoryLimits.String(), int64(fractionMemoryLimits))
  2976. w.Write(LEVEL_1, "%s\t%s (%d%%)\t%s (%d%%)\n",
  2977. corev1.ResourceEphemeralStorage, ephemeralstorageReqs.String(), int64(fractionEphemeralStorageReqs), ephemeralstorageLimits.String(), int64(fractionEphemeralStorageLimits))
  2978. extResources := make([]string, 0, len(allocatable))
  2979. for resource := range allocatable {
  2980. if !resourcehelper.IsStandardContainerResourceName(string(resource)) && resource != corev1.ResourcePods {
  2981. extResources = append(extResources, string(resource))
  2982. }
  2983. }
  2984. sort.Strings(extResources)
  2985. for _, ext := range extResources {
  2986. extRequests, extLimits := reqs[corev1.ResourceName(ext)], limits[corev1.ResourceName(ext)]
  2987. w.Write(LEVEL_1, "%s\t%s\t%s\n", ext, extRequests.String(), extLimits.String())
  2988. }
  2989. }
  2990. func getPodsTotalRequestsAndLimits(podList *corev1.PodList) (reqs map[corev1.ResourceName]resource.Quantity, limits map[corev1.ResourceName]resource.Quantity) {
  2991. reqs, limits = map[corev1.ResourceName]resource.Quantity{}, map[corev1.ResourceName]resource.Quantity{}
  2992. for _, pod := range podList.Items {
  2993. podReqs, podLimits := resourcehelper.PodRequestsAndLimits(&pod)
  2994. for podReqName, podReqValue := range podReqs {
  2995. if value, ok := reqs[podReqName]; !ok {
  2996. reqs[podReqName] = *podReqValue.Copy()
  2997. } else {
  2998. value.Add(podReqValue)
  2999. reqs[podReqName] = value
  3000. }
  3001. }
  3002. for podLimitName, podLimitValue := range podLimits {
  3003. if value, ok := limits[podLimitName]; !ok {
  3004. limits[podLimitName] = *podLimitValue.Copy()
  3005. } else {
  3006. value.Add(podLimitValue)
  3007. limits[podLimitName] = value
  3008. }
  3009. }
  3010. }
  3011. return
  3012. }
  3013. func DescribeEvents(el *corev1.EventList, w PrefixWriter) {
  3014. if len(el.Items) == 0 {
  3015. w.Write(LEVEL_0, "Events:\t<none>\n")
  3016. return
  3017. }
  3018. w.Flush()
  3019. sort.Sort(event.SortableEvents(el.Items))
  3020. w.Write(LEVEL_0, "Events:\n Type\tReason\tAge\tFrom\tMessage\n")
  3021. w.Write(LEVEL_1, "----\t------\t----\t----\t-------\n")
  3022. for _, e := range el.Items {
  3023. var interval string
  3024. if e.Count > 1 {
  3025. interval = fmt.Sprintf("%s (x%d over %s)", translateTimestampSince(e.LastTimestamp), e.Count, translateTimestampSince(e.FirstTimestamp))
  3026. } else {
  3027. interval = translateTimestampSince(e.FirstTimestamp)
  3028. }
  3029. w.Write(LEVEL_1, "%v\t%v\t%s\t%v\t%v\n",
  3030. e.Type,
  3031. e.Reason,
  3032. interval,
  3033. formatEventSource(e.Source),
  3034. strings.TrimSpace(e.Message),
  3035. )
  3036. }
  3037. }
  3038. // DeploymentDescriber generates information about a deployment.
  3039. type DeploymentDescriber struct {
  3040. client clientset.Interface
  3041. }
  3042. func (dd *DeploymentDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  3043. d, err := dd.client.AppsV1().Deployments(namespace).Get(name, metav1.GetOptions{})
  3044. if err != nil {
  3045. return "", err
  3046. }
  3047. selector, err := metav1.LabelSelectorAsSelector(d.Spec.Selector)
  3048. if err != nil {
  3049. return "", err
  3050. }
  3051. var events *corev1.EventList
  3052. if describerSettings.ShowEvents {
  3053. events, _ = dd.client.CoreV1().Events(namespace).Search(scheme.Scheme, d)
  3054. }
  3055. return describeDeployment(d, selector, d, events, dd)
  3056. }
  3057. func describeDeployment(d *appsv1.Deployment, selector labels.Selector, internalDeployment *appsv1.Deployment, events *corev1.EventList, dd *DeploymentDescriber) (string, error) {
  3058. return tabbedString(func(out io.Writer) error {
  3059. w := NewPrefixWriter(out)
  3060. w.Write(LEVEL_0, "Name:\t%s\n", d.ObjectMeta.Name)
  3061. w.Write(LEVEL_0, "Namespace:\t%s\n", d.ObjectMeta.Namespace)
  3062. w.Write(LEVEL_0, "CreationTimestamp:\t%s\n", d.CreationTimestamp.Time.Format(time.RFC1123Z))
  3063. printLabelsMultiline(w, "Labels", d.Labels)
  3064. printAnnotationsMultiline(w, "Annotations", d.Annotations)
  3065. w.Write(LEVEL_0, "Selector:\t%s\n", selector)
  3066. w.Write(LEVEL_0, "Replicas:\t%d desired | %d updated | %d total | %d available | %d unavailable\n", *(d.Spec.Replicas), d.Status.UpdatedReplicas, d.Status.Replicas, d.Status.AvailableReplicas, d.Status.UnavailableReplicas)
  3067. w.Write(LEVEL_0, "StrategyType:\t%s\n", d.Spec.Strategy.Type)
  3068. w.Write(LEVEL_0, "MinReadySeconds:\t%d\n", d.Spec.MinReadySeconds)
  3069. if d.Spec.Strategy.RollingUpdate != nil {
  3070. ru := d.Spec.Strategy.RollingUpdate
  3071. w.Write(LEVEL_0, "RollingUpdateStrategy:\t%s max unavailable, %s max surge\n", ru.MaxUnavailable.String(), ru.MaxSurge.String())
  3072. }
  3073. DescribePodTemplate(&internalDeployment.Spec.Template, w)
  3074. if len(d.Status.Conditions) > 0 {
  3075. w.Write(LEVEL_0, "Conditions:\n Type\tStatus\tReason\n")
  3076. w.Write(LEVEL_1, "----\t------\t------\n")
  3077. for _, c := range d.Status.Conditions {
  3078. w.Write(LEVEL_1, "%v \t%v\t%v\n", c.Type, c.Status, c.Reason)
  3079. }
  3080. }
  3081. oldRSs, _, newRS, err := deploymentutil.GetAllReplicaSets(d, dd.client.AppsV1())
  3082. if err == nil {
  3083. w.Write(LEVEL_0, "OldReplicaSets:\t%s\n", printReplicaSetsByLabels(oldRSs))
  3084. var newRSs []*appsv1.ReplicaSet
  3085. if newRS != nil {
  3086. newRSs = append(newRSs, newRS)
  3087. }
  3088. w.Write(LEVEL_0, "NewReplicaSet:\t%s\n", printReplicaSetsByLabels(newRSs))
  3089. }
  3090. if events != nil {
  3091. DescribeEvents(events, w)
  3092. }
  3093. return nil
  3094. })
  3095. }
  3096. func printReplicaSetsByLabels(matchingRSs []*appsv1.ReplicaSet) string {
  3097. // Format the matching ReplicaSets into strings.
  3098. rsStrings := make([]string, 0, len(matchingRSs))
  3099. for _, rs := range matchingRSs {
  3100. rsStrings = append(rsStrings, fmt.Sprintf("%s (%d/%d replicas created)", rs.Name, rs.Status.Replicas, *rs.Spec.Replicas))
  3101. }
  3102. list := strings.Join(rsStrings, ", ")
  3103. if list == "" {
  3104. return "<none>"
  3105. }
  3106. return list
  3107. }
  3108. func getPodStatusForController(c corev1client.PodInterface, selector labels.Selector, uid types.UID) (running, waiting, succeeded, failed int, err error) {
  3109. options := metav1.ListOptions{LabelSelector: selector.String()}
  3110. rcPods, err := c.List(options)
  3111. if err != nil {
  3112. return
  3113. }
  3114. for _, pod := range rcPods.Items {
  3115. controllerRef := metav1.GetControllerOf(&pod)
  3116. // Skip pods that are orphans or owned by other controllers.
  3117. if controllerRef == nil || controllerRef.UID != uid {
  3118. continue
  3119. }
  3120. switch pod.Status.Phase {
  3121. case corev1.PodRunning:
  3122. running++
  3123. case corev1.PodPending:
  3124. waiting++
  3125. case corev1.PodSucceeded:
  3126. succeeded++
  3127. case corev1.PodFailed:
  3128. failed++
  3129. }
  3130. }
  3131. return
  3132. }
  3133. // ConfigMapDescriber generates information about a ConfigMap
  3134. type ConfigMapDescriber struct {
  3135. clientset.Interface
  3136. }
  3137. func (d *ConfigMapDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  3138. c := d.CoreV1().ConfigMaps(namespace)
  3139. configMap, err := c.Get(name, metav1.GetOptions{})
  3140. if err != nil {
  3141. return "", err
  3142. }
  3143. return tabbedString(func(out io.Writer) error {
  3144. w := NewPrefixWriter(out)
  3145. w.Write(LEVEL_0, "Name:\t%s\n", configMap.Name)
  3146. w.Write(LEVEL_0, "Namespace:\t%s\n", configMap.Namespace)
  3147. printLabelsMultiline(w, "Labels", configMap.Labels)
  3148. printAnnotationsMultiline(w, "Annotations", configMap.Annotations)
  3149. w.Write(LEVEL_0, "\nData\n====\n")
  3150. for k, v := range configMap.Data {
  3151. w.Write(LEVEL_0, "%s:\n----\n", k)
  3152. w.Write(LEVEL_0, "%s\n", string(v))
  3153. }
  3154. if describerSettings.ShowEvents {
  3155. events, err := d.CoreV1().Events(namespace).Search(scheme.Scheme, configMap)
  3156. if err != nil {
  3157. return err
  3158. }
  3159. if events != nil {
  3160. DescribeEvents(events, w)
  3161. }
  3162. }
  3163. return nil
  3164. })
  3165. }
  3166. // NetworkPolicyDescriber generates information about a networkingv1.NetworkPolicy
  3167. type NetworkPolicyDescriber struct {
  3168. clientset.Interface
  3169. }
  3170. func (d *NetworkPolicyDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  3171. c := d.NetworkingV1().NetworkPolicies(namespace)
  3172. networkPolicy, err := c.Get(name, metav1.GetOptions{})
  3173. if err != nil {
  3174. return "", err
  3175. }
  3176. return describeNetworkPolicy(networkPolicy)
  3177. }
  3178. func describeNetworkPolicy(networkPolicy *networkingv1.NetworkPolicy) (string, error) {
  3179. return tabbedString(func(out io.Writer) error {
  3180. w := NewPrefixWriter(out)
  3181. w.Write(LEVEL_0, "Name:\t%s\n", networkPolicy.Name)
  3182. w.Write(LEVEL_0, "Namespace:\t%s\n", networkPolicy.Namespace)
  3183. w.Write(LEVEL_0, "Created on:\t%s\n", networkPolicy.CreationTimestamp)
  3184. printLabelsMultiline(w, "Labels", networkPolicy.Labels)
  3185. printAnnotationsMultiline(w, "Annotations", networkPolicy.Annotations)
  3186. describeNetworkPolicySpec(networkPolicy.Spec, w)
  3187. return nil
  3188. })
  3189. }
  3190. func describeNetworkPolicySpec(nps networkingv1.NetworkPolicySpec, w PrefixWriter) {
  3191. w.Write(LEVEL_0, "Spec:\n")
  3192. w.Write(LEVEL_1, "PodSelector: ")
  3193. if len(nps.PodSelector.MatchLabels) == 0 && len(nps.PodSelector.MatchExpressions) == 0 {
  3194. w.Write(LEVEL_2, "<none> (Allowing the specific traffic to all pods in this namespace)\n")
  3195. } else {
  3196. w.Write(LEVEL_2, "%s\n", metav1.FormatLabelSelector(&nps.PodSelector))
  3197. }
  3198. w.Write(LEVEL_1, "Allowing ingress traffic:\n")
  3199. printNetworkPolicySpecIngressFrom(nps.Ingress, " ", w)
  3200. w.Write(LEVEL_1, "Allowing egress traffic:\n")
  3201. printNetworkPolicySpecEgressTo(nps.Egress, " ", w)
  3202. w.Write(LEVEL_1, "Policy Types: %v\n", policyTypesToString(nps.PolicyTypes))
  3203. }
  3204. func printNetworkPolicySpecIngressFrom(npirs []networkingv1.NetworkPolicyIngressRule, initialIndent string, w PrefixWriter) {
  3205. if len(npirs) == 0 {
  3206. w.Write(LEVEL_0, "%s%s\n", initialIndent, "<none> (Selected pods are isolated for ingress connectivity)")
  3207. return
  3208. }
  3209. for i, npir := range npirs {
  3210. if len(npir.Ports) == 0 {
  3211. w.Write(LEVEL_0, "%s%s\n", initialIndent, "To Port: <any> (traffic allowed to all ports)")
  3212. } else {
  3213. for _, port := range npir.Ports {
  3214. var proto corev1.Protocol
  3215. if port.Protocol != nil {
  3216. proto = *port.Protocol
  3217. } else {
  3218. proto = corev1.ProtocolTCP
  3219. }
  3220. w.Write(LEVEL_0, "%s%s: %s/%s\n", initialIndent, "To Port", port.Port, proto)
  3221. }
  3222. }
  3223. if len(npir.From) == 0 {
  3224. w.Write(LEVEL_0, "%s%s\n", initialIndent, "From: <any> (traffic not restricted by source)")
  3225. } else {
  3226. for _, from := range npir.From {
  3227. w.Write(LEVEL_0, "%s%s\n", initialIndent, "From:")
  3228. if from.PodSelector != nil && from.NamespaceSelector != nil {
  3229. w.Write(LEVEL_1, "%s%s: %s\n", initialIndent, "NamespaceSelector", metav1.FormatLabelSelector(from.NamespaceSelector))
  3230. w.Write(LEVEL_1, "%s%s: %s\n", initialIndent, "PodSelector", metav1.FormatLabelSelector(from.PodSelector))
  3231. } else if from.PodSelector != nil {
  3232. w.Write(LEVEL_1, "%s%s: %s\n", initialIndent, "PodSelector", metav1.FormatLabelSelector(from.PodSelector))
  3233. } else if from.NamespaceSelector != nil {
  3234. w.Write(LEVEL_1, "%s%s: %s\n", initialIndent, "NamespaceSelector", metav1.FormatLabelSelector(from.NamespaceSelector))
  3235. } else if from.IPBlock != nil {
  3236. w.Write(LEVEL_1, "%sIPBlock:\n", initialIndent)
  3237. w.Write(LEVEL_2, "%sCIDR: %s\n", initialIndent, from.IPBlock.CIDR)
  3238. w.Write(LEVEL_2, "%sExcept: %v\n", initialIndent, strings.Join(from.IPBlock.Except, ", "))
  3239. }
  3240. }
  3241. }
  3242. if i != len(npirs)-1 {
  3243. w.Write(LEVEL_0, "%s%s\n", initialIndent, "----------")
  3244. }
  3245. }
  3246. }
  3247. func printNetworkPolicySpecEgressTo(npers []networkingv1.NetworkPolicyEgressRule, initialIndent string, w PrefixWriter) {
  3248. if len(npers) == 0 {
  3249. w.Write(LEVEL_0, "%s%s\n", initialIndent, "<none> (Selected pods are isolated for egress connectivity)")
  3250. return
  3251. }
  3252. for i, nper := range npers {
  3253. if len(nper.Ports) == 0 {
  3254. w.Write(LEVEL_0, "%s%s\n", initialIndent, "To Port: <any> (traffic allowed to all ports)")
  3255. } else {
  3256. for _, port := range nper.Ports {
  3257. var proto corev1.Protocol
  3258. if port.Protocol != nil {
  3259. proto = *port.Protocol
  3260. } else {
  3261. proto = corev1.ProtocolTCP
  3262. }
  3263. w.Write(LEVEL_0, "%s%s: %s/%s\n", initialIndent, "To Port", port.Port, proto)
  3264. }
  3265. }
  3266. if len(nper.To) == 0 {
  3267. w.Write(LEVEL_0, "%s%s\n", initialIndent, "To: <any> (traffic not restricted by source)")
  3268. } else {
  3269. for _, to := range nper.To {
  3270. w.Write(LEVEL_0, "%s%s\n", initialIndent, "To:")
  3271. if to.PodSelector != nil && to.NamespaceSelector != nil {
  3272. w.Write(LEVEL_1, "%s%s: %s\n", initialIndent, "NamespaceSelector", metav1.FormatLabelSelector(to.NamespaceSelector))
  3273. w.Write(LEVEL_1, "%s%s: %s\n", initialIndent, "PodSelector", metav1.FormatLabelSelector(to.PodSelector))
  3274. } else if to.PodSelector != nil {
  3275. w.Write(LEVEL_1, "%s%s: %s\n", initialIndent, "PodSelector", metav1.FormatLabelSelector(to.PodSelector))
  3276. } else if to.NamespaceSelector != nil {
  3277. w.Write(LEVEL_1, "%s%s: %s\n", initialIndent, "NamespaceSelector", metav1.FormatLabelSelector(to.NamespaceSelector))
  3278. } else if to.IPBlock != nil {
  3279. w.Write(LEVEL_1, "%sIPBlock:\n", initialIndent)
  3280. w.Write(LEVEL_2, "%sCIDR: %s\n", initialIndent, to.IPBlock.CIDR)
  3281. w.Write(LEVEL_2, "%sExcept: %v\n", initialIndent, strings.Join(to.IPBlock.Except, ", "))
  3282. }
  3283. }
  3284. }
  3285. if i != len(npers)-1 {
  3286. w.Write(LEVEL_0, "%s%s\n", initialIndent, "----------")
  3287. }
  3288. }
  3289. }
  3290. type StorageClassDescriber struct {
  3291. clientset.Interface
  3292. }
  3293. func (s *StorageClassDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  3294. sc, err := s.StorageV1().StorageClasses().Get(name, metav1.GetOptions{})
  3295. if err != nil {
  3296. return "", err
  3297. }
  3298. var events *corev1.EventList
  3299. if describerSettings.ShowEvents {
  3300. events, _ = s.CoreV1().Events(namespace).Search(scheme.Scheme, sc)
  3301. }
  3302. return describeStorageClass(sc, events)
  3303. }
  3304. func describeStorageClass(sc *storagev1.StorageClass, events *corev1.EventList) (string, error) {
  3305. return tabbedString(func(out io.Writer) error {
  3306. w := NewPrefixWriter(out)
  3307. w.Write(LEVEL_0, "Name:\t%s\n", sc.Name)
  3308. w.Write(LEVEL_0, "IsDefaultClass:\t%s\n", storageutil.IsDefaultAnnotationText(sc.ObjectMeta))
  3309. w.Write(LEVEL_0, "Annotations:\t%s\n", labels.FormatLabels(sc.Annotations))
  3310. w.Write(LEVEL_0, "Provisioner:\t%s\n", sc.Provisioner)
  3311. w.Write(LEVEL_0, "Parameters:\t%s\n", labels.FormatLabels(sc.Parameters))
  3312. w.Write(LEVEL_0, "AllowVolumeExpansion:\t%s\n", printBoolPtr(sc.AllowVolumeExpansion))
  3313. if len(sc.MountOptions) == 0 {
  3314. w.Write(LEVEL_0, "MountOptions:\t<none>\n")
  3315. } else {
  3316. w.Write(LEVEL_0, "MountOptions:\n")
  3317. for _, option := range sc.MountOptions {
  3318. w.Write(LEVEL_1, "%s\n", option)
  3319. }
  3320. }
  3321. if sc.ReclaimPolicy != nil {
  3322. w.Write(LEVEL_0, "ReclaimPolicy:\t%s\n", *sc.ReclaimPolicy)
  3323. }
  3324. if sc.VolumeBindingMode != nil {
  3325. w.Write(LEVEL_0, "VolumeBindingMode:\t%s\n", *sc.VolumeBindingMode)
  3326. }
  3327. if sc.AllowedTopologies != nil {
  3328. printAllowedTopologies(w, sc.AllowedTopologies)
  3329. }
  3330. if events != nil {
  3331. DescribeEvents(events, w)
  3332. }
  3333. return nil
  3334. })
  3335. }
  3336. func printAllowedTopologies(w PrefixWriter, topologies []corev1.TopologySelectorTerm) {
  3337. w.Write(LEVEL_0, "AllowedTopologies:\t")
  3338. if len(topologies) == 0 {
  3339. w.WriteLine("<none>")
  3340. return
  3341. }
  3342. w.WriteLine("")
  3343. for i, term := range topologies {
  3344. printTopologySelectorTermsMultilineWithIndent(w, LEVEL_1, fmt.Sprintf("Term %d", i), "\t", term.MatchLabelExpressions)
  3345. }
  3346. }
  3347. func printTopologySelectorTermsMultilineWithIndent(w PrefixWriter, indentLevel int, title, innerIndent string, reqs []corev1.TopologySelectorLabelRequirement) {
  3348. w.Write(indentLevel, "%s:%s", title, innerIndent)
  3349. if len(reqs) == 0 {
  3350. w.WriteLine("<none>")
  3351. return
  3352. }
  3353. for i, req := range reqs {
  3354. if i != 0 {
  3355. w.Write(indentLevel, "%s", innerIndent)
  3356. }
  3357. exprStr := fmt.Sprintf("%s %s", req.Key, "in")
  3358. if len(req.Values) > 0 {
  3359. exprStr = fmt.Sprintf("%s [%s]", exprStr, strings.Join(req.Values, ", "))
  3360. }
  3361. w.Write(LEVEL_0, "%s\n", exprStr)
  3362. }
  3363. }
  3364. type PodDisruptionBudgetDescriber struct {
  3365. clientset.Interface
  3366. }
  3367. func (p *PodDisruptionBudgetDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  3368. pdb, err := p.PolicyV1beta1().PodDisruptionBudgets(namespace).Get(name, metav1.GetOptions{})
  3369. if err != nil {
  3370. return "", err
  3371. }
  3372. var events *corev1.EventList
  3373. if describerSettings.ShowEvents {
  3374. events, _ = p.CoreV1().Events(namespace).Search(scheme.Scheme, pdb)
  3375. }
  3376. return describePodDisruptionBudget(pdb, events)
  3377. }
  3378. func describePodDisruptionBudget(pdb *policyv1beta1.PodDisruptionBudget, events *corev1.EventList) (string, error) {
  3379. return tabbedString(func(out io.Writer) error {
  3380. w := NewPrefixWriter(out)
  3381. w.Write(LEVEL_0, "Name:\t%s\n", pdb.Name)
  3382. w.Write(LEVEL_0, "Namespace:\t%s\n", pdb.Namespace)
  3383. if pdb.Spec.MinAvailable != nil {
  3384. w.Write(LEVEL_0, "Min available:\t%s\n", pdb.Spec.MinAvailable.String())
  3385. } else if pdb.Spec.MaxUnavailable != nil {
  3386. w.Write(LEVEL_0, "Max unavailable:\t%s\n", pdb.Spec.MaxUnavailable.String())
  3387. }
  3388. if pdb.Spec.Selector != nil {
  3389. w.Write(LEVEL_0, "Selector:\t%s\n", metav1.FormatLabelSelector(pdb.Spec.Selector))
  3390. } else {
  3391. w.Write(LEVEL_0, "Selector:\t<unset>\n")
  3392. }
  3393. w.Write(LEVEL_0, "Status:\n")
  3394. w.Write(LEVEL_2, "Allowed disruptions:\t%d\n", pdb.Status.PodDisruptionsAllowed)
  3395. w.Write(LEVEL_2, "Current:\t%d\n", pdb.Status.CurrentHealthy)
  3396. w.Write(LEVEL_2, "Desired:\t%d\n", pdb.Status.DesiredHealthy)
  3397. w.Write(LEVEL_2, "Total:\t%d\n", pdb.Status.ExpectedPods)
  3398. if events != nil {
  3399. DescribeEvents(events, w)
  3400. }
  3401. return nil
  3402. })
  3403. }
  3404. // PriorityClassDescriber generates information about a PriorityClass.
  3405. type PriorityClassDescriber struct {
  3406. clientset.Interface
  3407. }
  3408. func (s *PriorityClassDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  3409. pc, err := s.SchedulingV1().PriorityClasses().Get(name, metav1.GetOptions{})
  3410. if err != nil {
  3411. return "", err
  3412. }
  3413. var events *corev1.EventList
  3414. if describerSettings.ShowEvents {
  3415. events, _ = s.CoreV1().Events(namespace).Search(scheme.Scheme, pc)
  3416. }
  3417. return describePriorityClass(pc, events)
  3418. }
  3419. func describePriorityClass(pc *schedulingv1.PriorityClass, events *corev1.EventList) (string, error) {
  3420. return tabbedString(func(out io.Writer) error {
  3421. w := NewPrefixWriter(out)
  3422. w.Write(LEVEL_0, "Name:\t%s\n", pc.Name)
  3423. w.Write(LEVEL_0, "Value:\t%v\n", pc.Value)
  3424. w.Write(LEVEL_0, "GlobalDefault:\t%v\n", pc.GlobalDefault)
  3425. w.Write(LEVEL_0, "Description:\t%s\n", pc.Description)
  3426. w.Write(LEVEL_0, "Annotations:\t%s\n", labels.FormatLabels(pc.Annotations))
  3427. if events != nil {
  3428. DescribeEvents(events, w)
  3429. }
  3430. return nil
  3431. })
  3432. }
  3433. // PodSecurityPolicyDescriber generates information about a PodSecuritypolicyv1beta1.
  3434. type PodSecurityPolicyDescriber struct {
  3435. clientset.Interface
  3436. }
  3437. func (d *PodSecurityPolicyDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (string, error) {
  3438. psp, err := d.PolicyV1beta1().PodSecurityPolicies().Get(name, metav1.GetOptions{})
  3439. if err != nil {
  3440. return "", err
  3441. }
  3442. return describePodSecurityPolicy(psp)
  3443. }
  3444. func describePodSecurityPolicy(psp *policyv1beta1.PodSecurityPolicy) (string, error) {
  3445. return tabbedString(func(out io.Writer) error {
  3446. w := NewPrefixWriter(out)
  3447. w.Write(LEVEL_0, "Name:\t%s\n", psp.Name)
  3448. w.Write(LEVEL_0, "\nSettings:\n")
  3449. w.Write(LEVEL_1, "Allow Privileged:\t%t\n", psp.Spec.Privileged)
  3450. w.Write(LEVEL_1, "Allow Privilege Escalation:\t%v\n", psp.Spec.AllowPrivilegeEscalation)
  3451. w.Write(LEVEL_1, "Default Add Capabilities:\t%v\n", capsToString(psp.Spec.DefaultAddCapabilities))
  3452. w.Write(LEVEL_1, "Required Drop Capabilities:\t%s\n", capsToString(psp.Spec.RequiredDropCapabilities))
  3453. w.Write(LEVEL_1, "Allowed Capabilities:\t%s\n", capsToString(psp.Spec.AllowedCapabilities))
  3454. w.Write(LEVEL_1, "Allowed Volume Types:\t%s\n", fsTypeToString(psp.Spec.Volumes))
  3455. if len(psp.Spec.AllowedFlexVolumes) > 0 {
  3456. w.Write(LEVEL_1, "Allowed FlexVolume Types:\t%s\n", flexVolumesToString(psp.Spec.AllowedFlexVolumes))
  3457. }
  3458. if len(psp.Spec.AllowedCSIDrivers) > 0 {
  3459. w.Write(LEVEL_1, "Allowed CSI Drivers:\t%s\n", csiDriversToString(psp.Spec.AllowedCSIDrivers))
  3460. }
  3461. if len(psp.Spec.AllowedUnsafeSysctls) > 0 {
  3462. w.Write(LEVEL_1, "Allowed Unsafe Sysctls:\t%s\n", sysctlsToString(psp.Spec.AllowedUnsafeSysctls))
  3463. }
  3464. if len(psp.Spec.ForbiddenSysctls) > 0 {
  3465. w.Write(LEVEL_1, "Forbidden Sysctls:\t%s\n", sysctlsToString(psp.Spec.ForbiddenSysctls))
  3466. }
  3467. w.Write(LEVEL_1, "Allow Host Network:\t%t\n", psp.Spec.HostNetwork)
  3468. w.Write(LEVEL_1, "Allow Host Ports:\t%s\n", hostPortRangeToString(psp.Spec.HostPorts))
  3469. w.Write(LEVEL_1, "Allow Host PID:\t%t\n", psp.Spec.HostPID)
  3470. w.Write(LEVEL_1, "Allow Host IPC:\t%t\n", psp.Spec.HostIPC)
  3471. w.Write(LEVEL_1, "Read Only Root Filesystem:\t%v\n", psp.Spec.ReadOnlyRootFilesystem)
  3472. w.Write(LEVEL_1, "SELinux Context Strategy: %s\t\n", string(psp.Spec.SELinux.Rule))
  3473. var user, role, seLinuxType, level string
  3474. if psp.Spec.SELinux.SELinuxOptions != nil {
  3475. user = psp.Spec.SELinux.SELinuxOptions.User
  3476. role = psp.Spec.SELinux.SELinuxOptions.Role
  3477. seLinuxType = psp.Spec.SELinux.SELinuxOptions.Type
  3478. level = psp.Spec.SELinux.SELinuxOptions.Level
  3479. }
  3480. w.Write(LEVEL_2, "User:\t%s\n", stringOrNone(user))
  3481. w.Write(LEVEL_2, "Role:\t%s\n", stringOrNone(role))
  3482. w.Write(LEVEL_2, "Type:\t%s\n", stringOrNone(seLinuxType))
  3483. w.Write(LEVEL_2, "Level:\t%s\n", stringOrNone(level))
  3484. w.Write(LEVEL_1, "Run As User Strategy: %s\t\n", string(psp.Spec.RunAsUser.Rule))
  3485. w.Write(LEVEL_2, "Ranges:\t%s\n", idRangeToString(psp.Spec.RunAsUser.Ranges))
  3486. w.Write(LEVEL_1, "FSGroup Strategy: %s\t\n", string(psp.Spec.FSGroup.Rule))
  3487. w.Write(LEVEL_2, "Ranges:\t%s\n", idRangeToString(psp.Spec.FSGroup.Ranges))
  3488. w.Write(LEVEL_1, "Supplemental Groups Strategy: %s\t\n", string(psp.Spec.SupplementalGroups.Rule))
  3489. w.Write(LEVEL_2, "Ranges:\t%s\n", idRangeToString(psp.Spec.SupplementalGroups.Ranges))
  3490. return nil
  3491. })
  3492. }
  3493. func stringOrNone(s string) string {
  3494. return stringOrDefaultValue(s, "<none>")
  3495. }
  3496. func stringOrDefaultValue(s, defaultValue string) string {
  3497. if len(s) > 0 {
  3498. return s
  3499. }
  3500. return defaultValue
  3501. }
  3502. func fsTypeToString(volumes []policyv1beta1.FSType) string {
  3503. strVolumes := []string{}
  3504. for _, v := range volumes {
  3505. strVolumes = append(strVolumes, string(v))
  3506. }
  3507. return stringOrNone(strings.Join(strVolumes, ","))
  3508. }
  3509. func flexVolumesToString(flexVolumes []policyv1beta1.AllowedFlexVolume) string {
  3510. volumes := []string{}
  3511. for _, flexVolume := range flexVolumes {
  3512. volumes = append(volumes, "driver="+flexVolume.Driver)
  3513. }
  3514. return stringOrDefaultValue(strings.Join(volumes, ","), "<all>")
  3515. }
  3516. func csiDriversToString(csiDrivers []policyv1beta1.AllowedCSIDriver) string {
  3517. drivers := []string{}
  3518. for _, csiDriver := range csiDrivers {
  3519. drivers = append(drivers, "driver="+csiDriver.Name)
  3520. }
  3521. return stringOrDefaultValue(strings.Join(drivers, ","), "<all>")
  3522. }
  3523. func sysctlsToString(sysctls []string) string {
  3524. return stringOrNone(strings.Join(sysctls, ","))
  3525. }
  3526. func hostPortRangeToString(ranges []policyv1beta1.HostPortRange) string {
  3527. formattedString := ""
  3528. if ranges != nil {
  3529. strRanges := []string{}
  3530. for _, r := range ranges {
  3531. strRanges = append(strRanges, fmt.Sprintf("%d-%d", r.Min, r.Max))
  3532. }
  3533. formattedString = strings.Join(strRanges, ",")
  3534. }
  3535. return stringOrNone(formattedString)
  3536. }
  3537. func idRangeToString(ranges []policyv1beta1.IDRange) string {
  3538. formattedString := ""
  3539. if ranges != nil {
  3540. strRanges := []string{}
  3541. for _, r := range ranges {
  3542. strRanges = append(strRanges, fmt.Sprintf("%d-%d", r.Min, r.Max))
  3543. }
  3544. formattedString = strings.Join(strRanges, ",")
  3545. }
  3546. return stringOrNone(formattedString)
  3547. }
  3548. func capsToString(caps []corev1.Capability) string {
  3549. formattedString := ""
  3550. if caps != nil {
  3551. strCaps := []string{}
  3552. for _, c := range caps {
  3553. strCaps = append(strCaps, string(c))
  3554. }
  3555. formattedString = strings.Join(strCaps, ",")
  3556. }
  3557. return stringOrNone(formattedString)
  3558. }
  3559. func policyTypesToString(pts []networkingv1.PolicyType) string {
  3560. formattedString := ""
  3561. if pts != nil {
  3562. strPts := []string{}
  3563. for _, p := range pts {
  3564. strPts = append(strPts, string(p))
  3565. }
  3566. formattedString = strings.Join(strPts, ", ")
  3567. }
  3568. return stringOrNone(formattedString)
  3569. }
  3570. // newErrNoDescriber creates a new ErrNoDescriber with the names of the provided types.
  3571. func newErrNoDescriber(types ...reflect.Type) error {
  3572. names := make([]string, 0, len(types))
  3573. for _, t := range types {
  3574. names = append(names, t.String())
  3575. }
  3576. return describe.ErrNoDescriber{Types: names}
  3577. }
  3578. // Describers implements ObjectDescriber against functions registered via Add. Those functions can
  3579. // be strongly typed. Types are exactly matched (no conversion or assignable checks).
  3580. type Describers struct {
  3581. searchFns map[reflect.Type][]typeFunc
  3582. }
  3583. // DescribeObject implements ObjectDescriber and will attempt to print the provided object to a string,
  3584. // if at least one describer function has been registered with the exact types passed, or if any
  3585. // describer can print the exact object in its first argument (the remainder will be provided empty
  3586. // values). If no function registered with Add can satisfy the passed objects, an ErrNoDescriber will
  3587. // be returned
  3588. // TODO: reorder and partial match extra.
  3589. func (d *Describers) DescribeObject(exact interface{}, extra ...interface{}) (string, error) {
  3590. exactType := reflect.TypeOf(exact)
  3591. fns, ok := d.searchFns[exactType]
  3592. if !ok {
  3593. return "", newErrNoDescriber(exactType)
  3594. }
  3595. if len(extra) == 0 {
  3596. for _, typeFn := range fns {
  3597. if len(typeFn.Extra) == 0 {
  3598. return typeFn.Describe(exact, extra...)
  3599. }
  3600. }
  3601. typeFn := fns[0]
  3602. for _, t := range typeFn.Extra {
  3603. v := reflect.New(t).Elem()
  3604. extra = append(extra, v.Interface())
  3605. }
  3606. return fns[0].Describe(exact, extra...)
  3607. }
  3608. types := make([]reflect.Type, 0, len(extra))
  3609. for _, obj := range extra {
  3610. types = append(types, reflect.TypeOf(obj))
  3611. }
  3612. for _, typeFn := range fns {
  3613. if typeFn.Matches(types) {
  3614. return typeFn.Describe(exact, extra...)
  3615. }
  3616. }
  3617. return "", newErrNoDescriber(append([]reflect.Type{exactType}, types...)...)
  3618. }
  3619. // Add adds one or more describer functions to the describe.Describer. The passed function must
  3620. // match the signature:
  3621. //
  3622. // func(...) (string, error)
  3623. //
  3624. // Any number of arguments may be provided.
  3625. func (d *Describers) Add(fns ...interface{}) error {
  3626. for _, fn := range fns {
  3627. fv := reflect.ValueOf(fn)
  3628. ft := fv.Type()
  3629. if ft.Kind() != reflect.Func {
  3630. return fmt.Errorf("expected func, got: %v", ft)
  3631. }
  3632. numIn := ft.NumIn()
  3633. if numIn == 0 {
  3634. return fmt.Errorf("expected at least one 'in' params, got: %v", ft)
  3635. }
  3636. if ft.NumOut() != 2 {
  3637. return fmt.Errorf("expected two 'out' params - (string, error), got: %v", ft)
  3638. }
  3639. types := make([]reflect.Type, 0, numIn)
  3640. for i := 0; i < numIn; i++ {
  3641. types = append(types, ft.In(i))
  3642. }
  3643. if ft.Out(0) != reflect.TypeOf(string("")) {
  3644. return fmt.Errorf("expected string return, got: %v", ft)
  3645. }
  3646. var forErrorType error
  3647. // This convolution is necessary, otherwise TypeOf picks up on the fact
  3648. // that forErrorType is nil.
  3649. errorType := reflect.TypeOf(&forErrorType).Elem()
  3650. if ft.Out(1) != errorType {
  3651. return fmt.Errorf("expected error return, got: %v", ft)
  3652. }
  3653. exact := types[0]
  3654. extra := types[1:]
  3655. if d.searchFns == nil {
  3656. d.searchFns = make(map[reflect.Type][]typeFunc)
  3657. }
  3658. fns := d.searchFns[exact]
  3659. fn := typeFunc{Extra: extra, Fn: fv}
  3660. fns = append(fns, fn)
  3661. d.searchFns[exact] = fns
  3662. }
  3663. return nil
  3664. }
  3665. // typeFunc holds information about a describer function and the types it accepts
  3666. type typeFunc struct {
  3667. Extra []reflect.Type
  3668. Fn reflect.Value
  3669. }
  3670. // Matches returns true when the passed types exactly match the Extra list.
  3671. func (fn typeFunc) Matches(types []reflect.Type) bool {
  3672. if len(fn.Extra) != len(types) {
  3673. return false
  3674. }
  3675. // reorder the items in array types and fn.Extra
  3676. // convert the type into string and sort them, check if they are matched
  3677. varMap := make(map[reflect.Type]bool)
  3678. for i := range fn.Extra {
  3679. varMap[fn.Extra[i]] = true
  3680. }
  3681. for i := range types {
  3682. if _, found := varMap[types[i]]; !found {
  3683. return false
  3684. }
  3685. }
  3686. return true
  3687. }
  3688. // Describe invokes the nested function with the exact number of arguments.
  3689. func (fn typeFunc) Describe(exact interface{}, extra ...interface{}) (string, error) {
  3690. values := []reflect.Value{reflect.ValueOf(exact)}
  3691. for _, obj := range extra {
  3692. values = append(values, reflect.ValueOf(obj))
  3693. }
  3694. out := fn.Fn.Call(values)
  3695. s := out[0].Interface().(string)
  3696. var err error
  3697. if !out[1].IsNil() {
  3698. err = out[1].Interface().(error)
  3699. }
  3700. return s, err
  3701. }
  3702. // printLabelsMultiline prints multiple labels with a proper alignment.
  3703. func printLabelsMultiline(w PrefixWriter, title string, labels map[string]string) {
  3704. printLabelsMultilineWithIndent(w, "", title, "\t", labels, sets.NewString())
  3705. }
  3706. // printLabelsMultiline prints multiple labels with a user-defined alignment.
  3707. func printLabelsMultilineWithIndent(w PrefixWriter, initialIndent, title, innerIndent string, labels map[string]string, skip sets.String) {
  3708. w.Write(LEVEL_0, "%s%s:%s", initialIndent, title, innerIndent)
  3709. if labels == nil || len(labels) == 0 {
  3710. w.WriteLine("<none>")
  3711. return
  3712. }
  3713. // to print labels in the sorted order
  3714. keys := make([]string, 0, len(labels))
  3715. for key := range labels {
  3716. if skip.Has(key) {
  3717. continue
  3718. }
  3719. keys = append(keys, key)
  3720. }
  3721. if len(keys) == 0 {
  3722. w.WriteLine("<none>")
  3723. return
  3724. }
  3725. sort.Strings(keys)
  3726. for i, key := range keys {
  3727. if i != 0 {
  3728. w.Write(LEVEL_0, "%s", initialIndent)
  3729. w.Write(LEVEL_0, "%s", innerIndent)
  3730. }
  3731. w.Write(LEVEL_0, "%s=%s\n", key, labels[key])
  3732. i++
  3733. }
  3734. }
  3735. // printTaintsMultiline prints multiple taints with a proper alignment.
  3736. func printNodeTaintsMultiline(w PrefixWriter, title string, taints []corev1.Taint) {
  3737. printTaintsMultilineWithIndent(w, "", title, "\t", taints)
  3738. }
  3739. // printTaintsMultilineWithIndent prints multiple taints with a user-defined alignment.
  3740. func printTaintsMultilineWithIndent(w PrefixWriter, initialIndent, title, innerIndent string, taints []corev1.Taint) {
  3741. w.Write(LEVEL_0, "%s%s:%s", initialIndent, title, innerIndent)
  3742. if taints == nil || len(taints) == 0 {
  3743. w.WriteLine("<none>")
  3744. return
  3745. }
  3746. // to print taints in the sorted order
  3747. sort.Slice(taints, func(i, j int) bool {
  3748. cmpKey := func(taint corev1.Taint) string {
  3749. return string(taint.Effect) + "," + taint.Key
  3750. }
  3751. return cmpKey(taints[i]) < cmpKey(taints[j])
  3752. })
  3753. for i, taint := range taints {
  3754. if i != 0 {
  3755. w.Write(LEVEL_0, "%s", initialIndent)
  3756. w.Write(LEVEL_0, "%s", innerIndent)
  3757. }
  3758. w.Write(LEVEL_0, "%s\n", taint.ToString())
  3759. }
  3760. }
  3761. // printPodsMultiline prints multiple pods with a proper alignment.
  3762. func printPodsMultiline(w PrefixWriter, title string, pods []corev1.Pod) {
  3763. printPodsMultilineWithIndent(w, "", title, "\t", pods)
  3764. }
  3765. // printPodsMultilineWithIndent prints multiple pods with a user-defined alignment.
  3766. func printPodsMultilineWithIndent(w PrefixWriter, initialIndent, title, innerIndent string, pods []corev1.Pod) {
  3767. w.Write(LEVEL_0, "%s%s:%s", initialIndent, title, innerIndent)
  3768. if pods == nil || len(pods) == 0 {
  3769. w.WriteLine("<none>")
  3770. return
  3771. }
  3772. // to print pods in the sorted order
  3773. sort.Slice(pods, func(i, j int) bool {
  3774. cmpKey := func(pod corev1.Pod) string {
  3775. return pod.Name
  3776. }
  3777. return cmpKey(pods[i]) < cmpKey(pods[j])
  3778. })
  3779. for i, pod := range pods {
  3780. if i != 0 {
  3781. w.Write(LEVEL_0, "%s", initialIndent)
  3782. w.Write(LEVEL_0, "%s", innerIndent)
  3783. }
  3784. w.Write(LEVEL_0, "%s\n", pod.Name)
  3785. }
  3786. }
  3787. // printPodTolerationsMultiline prints multiple tolerations with a proper alignment.
  3788. func printPodTolerationsMultiline(w PrefixWriter, title string, tolerations []corev1.Toleration) {
  3789. printTolerationsMultilineWithIndent(w, "", title, "\t", tolerations)
  3790. }
  3791. // printTolerationsMultilineWithIndent prints multiple tolerations with a user-defined alignment.
  3792. func printTolerationsMultilineWithIndent(w PrefixWriter, initialIndent, title, innerIndent string, tolerations []corev1.Toleration) {
  3793. w.Write(LEVEL_0, "%s%s:%s", initialIndent, title, innerIndent)
  3794. if tolerations == nil || len(tolerations) == 0 {
  3795. w.WriteLine("<none>")
  3796. return
  3797. }
  3798. // to print tolerations in the sorted order
  3799. sort.Slice(tolerations, func(i, j int) bool {
  3800. return tolerations[i].Key < tolerations[j].Key
  3801. })
  3802. for i, toleration := range tolerations {
  3803. if i != 0 {
  3804. w.Write(LEVEL_0, "%s", initialIndent)
  3805. w.Write(LEVEL_0, "%s", innerIndent)
  3806. }
  3807. w.Write(LEVEL_0, "%s", toleration.Key)
  3808. if len(toleration.Value) != 0 {
  3809. w.Write(LEVEL_0, "=%s", toleration.Value)
  3810. }
  3811. if len(toleration.Effect) != 0 {
  3812. w.Write(LEVEL_0, ":%s", toleration.Effect)
  3813. }
  3814. if toleration.TolerationSeconds != nil {
  3815. w.Write(LEVEL_0, " for %ds", *toleration.TolerationSeconds)
  3816. }
  3817. w.Write(LEVEL_0, "\n")
  3818. }
  3819. }
  3820. type flusher interface {
  3821. Flush()
  3822. }
  3823. func tabbedString(f func(io.Writer) error) (string, error) {
  3824. out := new(tabwriter.Writer)
  3825. buf := &bytes.Buffer{}
  3826. out.Init(buf, 0, 8, 2, ' ', 0)
  3827. err := f(out)
  3828. if err != nil {
  3829. return "", err
  3830. }
  3831. out.Flush()
  3832. str := string(buf.String())
  3833. return str, nil
  3834. }
  3835. type SortableResourceNames []corev1.ResourceName
  3836. func (list SortableResourceNames) Len() int {
  3837. return len(list)
  3838. }
  3839. func (list SortableResourceNames) Swap(i, j int) {
  3840. list[i], list[j] = list[j], list[i]
  3841. }
  3842. func (list SortableResourceNames) Less(i, j int) bool {
  3843. return list[i] < list[j]
  3844. }
  3845. // SortedResourceNames returns the sorted resource names of a resource list.
  3846. func SortedResourceNames(list corev1.ResourceList) []corev1.ResourceName {
  3847. resources := make([]corev1.ResourceName, 0, len(list))
  3848. for res := range list {
  3849. resources = append(resources, res)
  3850. }
  3851. sort.Sort(SortableResourceNames(resources))
  3852. return resources
  3853. }
  3854. type SortableResourceQuotas []corev1.ResourceQuota
  3855. func (list SortableResourceQuotas) Len() int {
  3856. return len(list)
  3857. }
  3858. func (list SortableResourceQuotas) Swap(i, j int) {
  3859. list[i], list[j] = list[j], list[i]
  3860. }
  3861. func (list SortableResourceQuotas) Less(i, j int) bool {
  3862. return list[i].Name < list[j].Name
  3863. }
  3864. type SortableVolumeMounts []corev1.VolumeMount
  3865. func (list SortableVolumeMounts) Len() int {
  3866. return len(list)
  3867. }
  3868. func (list SortableVolumeMounts) Swap(i, j int) {
  3869. list[i], list[j] = list[j], list[i]
  3870. }
  3871. func (list SortableVolumeMounts) Less(i, j int) bool {
  3872. return list[i].MountPath < list[j].MountPath
  3873. }
  3874. type SortableVolumeDevices []corev1.VolumeDevice
  3875. func (list SortableVolumeDevices) Len() int {
  3876. return len(list)
  3877. }
  3878. func (list SortableVolumeDevices) Swap(i, j int) {
  3879. list[i], list[j] = list[j], list[i]
  3880. }
  3881. func (list SortableVolumeDevices) Less(i, j int) bool {
  3882. return list[i].DevicePath < list[j].DevicePath
  3883. }
  3884. var maxAnnotationLen = 140
  3885. // printAnnotationsMultilineWithFilter prints filtered multiple annotations with a proper alignment.
  3886. func printAnnotationsMultilineWithFilter(w PrefixWriter, title string, annotations map[string]string, skip sets.String) {
  3887. printAnnotationsMultilineWithIndent(w, "", title, "\t", annotations, skip)
  3888. }
  3889. // printAnnotationsMultiline prints multiple annotations with a proper alignment.
  3890. func printAnnotationsMultiline(w PrefixWriter, title string, annotations map[string]string) {
  3891. printAnnotationsMultilineWithIndent(w, "", title, "\t", annotations, sets.NewString())
  3892. }
  3893. // printAnnotationsMultilineWithIndent prints multiple annotations with a user-defined alignment.
  3894. // If annotation string is too long, we omit chars more than 200 length.
  3895. func printAnnotationsMultilineWithIndent(w PrefixWriter, initialIndent, title, innerIndent string, annotations map[string]string, skip sets.String) {
  3896. w.Write(LEVEL_0, "%s%s:%s", initialIndent, title, innerIndent)
  3897. if len(annotations) == 0 {
  3898. w.WriteLine("<none>")
  3899. return
  3900. }
  3901. // to print labels in the sorted order
  3902. keys := make([]string, 0, len(annotations))
  3903. for key := range annotations {
  3904. if skip.Has(key) {
  3905. continue
  3906. }
  3907. keys = append(keys, key)
  3908. }
  3909. if len(annotations) == 0 {
  3910. w.WriteLine("<none>")
  3911. return
  3912. }
  3913. sort.Strings(keys)
  3914. indent := initialIndent + innerIndent
  3915. for i, key := range keys {
  3916. if i != 0 {
  3917. w.Write(LEVEL_0, indent)
  3918. }
  3919. value := strings.TrimSuffix(annotations[key], "\n")
  3920. if (len(value)+len(key)+2) > maxAnnotationLen || strings.Contains(value, "\n") {
  3921. w.Write(LEVEL_0, "%s:\n", key)
  3922. for _, s := range strings.Split(value, "\n") {
  3923. w.Write(LEVEL_0, "%s %s\n", indent, shorten(s, maxAnnotationLen-2))
  3924. }
  3925. } else {
  3926. w.Write(LEVEL_0, "%s: %s\n", key, value)
  3927. }
  3928. i++
  3929. }
  3930. }
  3931. func shorten(s string, maxLength int) string {
  3932. if len(s) > maxLength {
  3933. return s[:maxLength] + "..."
  3934. }
  3935. return s
  3936. }
  3937. // translateTimestampSince returns the elapsed time since timestamp in
  3938. // human-readable approximation.
  3939. func translateTimestampSince(timestamp metav1.Time) string {
  3940. if timestamp.IsZero() {
  3941. return "<unknown>"
  3942. }
  3943. return duration.HumanDuration(time.Since(timestamp.Time))
  3944. }
  3945. // formatEventSource formats EventSource as a comma separated string excluding Host when empty
  3946. func formatEventSource(es corev1.EventSource) string {
  3947. EventSourceString := []string{es.Component}
  3948. if len(es.Host) > 0 {
  3949. EventSourceString = append(EventSourceString, es.Host)
  3950. }
  3951. return strings.Join(EventSourceString, ", ")
  3952. }
  3953. // Pass ports=nil for all ports.
  3954. func formatEndpoints(endpoints *corev1.Endpoints, ports sets.String) string {
  3955. if len(endpoints.Subsets) == 0 {
  3956. return "<none>"
  3957. }
  3958. list := []string{}
  3959. max := 3
  3960. more := false
  3961. count := 0
  3962. for i := range endpoints.Subsets {
  3963. ss := &endpoints.Subsets[i]
  3964. if len(ss.Ports) == 0 {
  3965. // It's possible to have headless services with no ports.
  3966. for i := range ss.Addresses {
  3967. if len(list) == max {
  3968. more = true
  3969. }
  3970. if !more {
  3971. list = append(list, ss.Addresses[i].IP)
  3972. }
  3973. count++
  3974. }
  3975. } else {
  3976. // "Normal" services with ports defined.
  3977. for i := range ss.Ports {
  3978. port := &ss.Ports[i]
  3979. if ports == nil || ports.Has(port.Name) {
  3980. for i := range ss.Addresses {
  3981. if len(list) == max {
  3982. more = true
  3983. }
  3984. addr := &ss.Addresses[i]
  3985. if !more {
  3986. hostPort := net.JoinHostPort(addr.IP, strconv.Itoa(int(port.Port)))
  3987. list = append(list, hostPort)
  3988. }
  3989. count++
  3990. }
  3991. }
  3992. }
  3993. }
  3994. }
  3995. ret := strings.Join(list, ",")
  3996. if more {
  3997. return fmt.Sprintf("%s + %d more...", ret, count-max)
  3998. }
  3999. return ret
  4000. }
  4001. func extractCSRStatus(csr *certificatesv1beta1.CertificateSigningRequest) (string, error) {
  4002. var approved, denied bool
  4003. for _, c := range csr.Status.Conditions {
  4004. switch c.Type {
  4005. case certificatesv1beta1.CertificateApproved:
  4006. approved = true
  4007. case certificatesv1beta1.CertificateDenied:
  4008. denied = true
  4009. default:
  4010. return "", fmt.Errorf("unknown csr condition %q", c)
  4011. }
  4012. }
  4013. var status string
  4014. // must be in order of presidence
  4015. if denied {
  4016. status += "Denied"
  4017. } else if approved {
  4018. status += "Approved"
  4019. } else {
  4020. status += "Pending"
  4021. }
  4022. if len(csr.Status.Certificate) > 0 {
  4023. status += ",Issued"
  4024. }
  4025. return status, nil
  4026. }
  4027. // backendStringer behaves just like a string interface and converts the given backend to a string.
  4028. func backendStringer(backend *networkingv1beta1.IngressBackend) string {
  4029. if backend == nil {
  4030. return ""
  4031. }
  4032. return fmt.Sprintf("%v:%v", backend.ServiceName, backend.ServicePort.String())
  4033. }
  4034. // findNodeRoles returns the roles of a given node.
  4035. // The roles are determined by looking for:
  4036. // * a node-role.kubernetes.io/<role>="" label
  4037. // * a kubernetes.io/role="<role>" label
  4038. func findNodeRoles(node *corev1.Node) []string {
  4039. roles := sets.NewString()
  4040. for k, v := range node.Labels {
  4041. switch {
  4042. case strings.HasPrefix(k, describe.LabelNodeRolePrefix):
  4043. if role := strings.TrimPrefix(k, describe.LabelNodeRolePrefix); len(role) > 0 {
  4044. roles.Insert(role)
  4045. }
  4046. case k == describe.NodeLabelRole && v != "":
  4047. roles.Insert(v)
  4048. }
  4049. }
  4050. return roles.List()
  4051. }
  4052. // loadBalancerStatusStringer behaves mostly like a string interface and converts the given status to a string.
  4053. // `wide` indicates whether the returned value is meant for --o=wide output. If not, it's clipped to 16 bytes.
  4054. func loadBalancerStatusStringer(s corev1.LoadBalancerStatus, wide bool) string {
  4055. ingress := s.Ingress
  4056. result := sets.NewString()
  4057. for i := range ingress {
  4058. if ingress[i].IP != "" {
  4059. result.Insert(ingress[i].IP)
  4060. } else if ingress[i].Hostname != "" {
  4061. result.Insert(ingress[i].Hostname)
  4062. }
  4063. }
  4064. r := strings.Join(result.List(), ",")
  4065. if !wide && len(r) > describe.LoadBalancerWidth {
  4066. r = r[0:(describe.LoadBalancerWidth-3)] + "..."
  4067. }
  4068. return r
  4069. }