12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179 |
- /*
- Copyright 2014 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package versioned
- import (
- "bytes"
- "fmt"
- "reflect"
- "regexp"
- "strings"
- "testing"
- "time"
- appsv1 "k8s.io/api/apps/v1"
- autoscalingv1 "k8s.io/api/autoscaling/v1"
- autoscalingv2beta2 "k8s.io/api/autoscaling/v2beta2"
- corev1 "k8s.io/api/core/v1"
- networkingv1 "k8s.io/api/networking/v1"
- policyv1beta1 "k8s.io/api/policy/v1beta1"
- storagev1 "k8s.io/api/storage/v1"
- apiequality "k8s.io/apimachinery/pkg/api/equality"
- "k8s.io/apimachinery/pkg/api/resource"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
- "k8s.io/apimachinery/pkg/util/intstr"
- "k8s.io/client-go/kubernetes"
- "k8s.io/client-go/kubernetes/fake"
- "k8s.io/kubernetes/pkg/kubectl/describe"
- utilpointer "k8s.io/utils/pointer"
- )
- type describeClient struct {
- T *testing.T
- Namespace string
- Err error
- kubernetes.Interface
- }
- func TestDescribePod(t *testing.T) {
- deletionTimestamp := metav1.Time{Time: time.Now().UTC().AddDate(-10, 0, 0)}
- gracePeriod := int64(1234)
- condition1 := corev1.PodConditionType("condition1")
- condition2 := corev1.PodConditionType("condition2")
- fake := fake.NewSimpleClientset(&corev1.Pod{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- Namespace: "foo",
- DeletionTimestamp: &deletionTimestamp,
- DeletionGracePeriodSeconds: &gracePeriod,
- },
- Spec: corev1.PodSpec{
- ReadinessGates: []corev1.PodReadinessGate{
- {
- ConditionType: condition1,
- },
- {
- ConditionType: condition2,
- },
- },
- },
- Status: corev1.PodStatus{
- Conditions: []corev1.PodCondition{
- {
- Type: condition1,
- Status: corev1.ConditionTrue,
- },
- },
- },
- })
- c := &describeClient{T: t, Namespace: "foo", Interface: fake}
- d := PodDescriber{c}
- out, err := d.Describe("foo", "bar", describe.DescriberSettings{ShowEvents: true})
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- if !strings.Contains(out, "bar") || !strings.Contains(out, "Status:") {
- t.Errorf("unexpected out: %s", out)
- }
- if !strings.Contains(out, "Terminating (lasts 10y)") || !strings.Contains(out, "1234s") {
- t.Errorf("unexpected out: %s", out)
- }
- }
- func TestDescribePodNode(t *testing.T) {
- fake := fake.NewSimpleClientset(&corev1.Pod{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- Namespace: "foo",
- },
- Spec: corev1.PodSpec{
- NodeName: "all-in-one",
- },
- Status: corev1.PodStatus{
- HostIP: "127.0.0.1",
- NominatedNodeName: "nodeA",
- },
- })
- c := &describeClient{T: t, Namespace: "foo", Interface: fake}
- d := PodDescriber{c}
- out, err := d.Describe("foo", "bar", describe.DescriberSettings{ShowEvents: true})
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- if !strings.Contains(out, "all-in-one/127.0.0.1") {
- t.Errorf("unexpected out: %s", out)
- }
- if !strings.Contains(out, "nodeA") {
- t.Errorf("unexpected out: %s", out)
- }
- }
- func TestDescribePodTolerations(t *testing.T) {
- fake := fake.NewSimpleClientset(&corev1.Pod{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- Namespace: "foo",
- },
- Spec: corev1.PodSpec{
- Tolerations: []corev1.Toleration{
- {Key: "key0", Operator: corev1.TolerationOpExists},
- {Key: "key1", Value: "value1"},
- {Key: "key2", Operator: corev1.TolerationOpEqual, Value: "value2", Effect: corev1.TaintEffectNoSchedule},
- {Key: "key3", Value: "value3", Effect: corev1.TaintEffectNoExecute, TolerationSeconds: &[]int64{300}[0]},
- {Key: "key4", Effect: corev1.TaintEffectNoExecute, TolerationSeconds: &[]int64{60}[0]},
- },
- },
- })
- c := &describeClient{T: t, Namespace: "foo", Interface: fake}
- d := PodDescriber{c}
- out, err := d.Describe("foo", "bar", describe.DescriberSettings{})
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- if !strings.Contains(out, "key0\n") ||
- !strings.Contains(out, "key1=value1\n") ||
- !strings.Contains(out, "key2=value2:NoSchedule\n") ||
- !strings.Contains(out, "key3=value3:NoExecute for 300s\n") ||
- !strings.Contains(out, "key4:NoExecute for 60s\n") ||
- !strings.Contains(out, "Tolerations:") {
- t.Errorf("unexpected out:\n%s", out)
- }
- }
- func TestDescribeSecret(t *testing.T) {
- fake := fake.NewSimpleClientset(&corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- Namespace: "foo",
- },
- Data: map[string][]byte{
- "username": []byte("YWRtaW4="),
- "password": []byte("MWYyZDFlMmU2N2Rm"),
- },
- })
- c := &describeClient{T: t, Namespace: "foo", Interface: fake}
- d := SecretDescriber{c}
- out, err := d.Describe("foo", "bar", describe.DescriberSettings{})
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- if !strings.Contains(out, "bar") || !strings.Contains(out, "foo") || !strings.Contains(out, "username") || !strings.Contains(out, "8 bytes") || !strings.Contains(out, "password") || !strings.Contains(out, "16 bytes") {
- t.Errorf("unexpected out: %s", out)
- }
- if strings.Contains(out, "YWRtaW4=") || strings.Contains(out, "MWYyZDFlMmU2N2Rm") {
- t.Errorf("sensitive data should not be shown, unexpected out: %s", out)
- }
- }
- func TestDescribeNamespace(t *testing.T) {
- fake := fake.NewSimpleClientset(&corev1.Namespace{
- ObjectMeta: metav1.ObjectMeta{
- Name: "myns",
- },
- })
- c := &describeClient{T: t, Namespace: "", Interface: fake}
- d := NamespaceDescriber{c}
- out, err := d.Describe("", "myns", describe.DescriberSettings{ShowEvents: true})
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- if !strings.Contains(out, "myns") {
- t.Errorf("unexpected out: %s", out)
- }
- }
- func TestDescribePodPriority(t *testing.T) {
- priority := int32(1000)
- fake := fake.NewSimpleClientset(&corev1.Pod{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- },
- Spec: corev1.PodSpec{
- PriorityClassName: "high-priority",
- Priority: &priority,
- },
- })
- c := &describeClient{T: t, Namespace: "", Interface: fake}
- d := PodDescriber{c}
- out, err := d.Describe("", "bar", describe.DescriberSettings{ShowEvents: true})
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- if !strings.Contains(out, "high-priority") || !strings.Contains(out, "1000") {
- t.Errorf("unexpected out: %s", out)
- }
- }
- func TestDescribeConfigMap(t *testing.T) {
- fake := fake.NewSimpleClientset(&corev1.ConfigMap{
- ObjectMeta: metav1.ObjectMeta{
- Name: "mycm",
- Namespace: "foo",
- },
- Data: map[string]string{
- "key1": "value1",
- "key2": "value2",
- },
- })
- c := &describeClient{T: t, Namespace: "foo", Interface: fake}
- d := ConfigMapDescriber{c}
- out, err := d.Describe("foo", "mycm", describe.DescriberSettings{ShowEvents: true})
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- if !strings.Contains(out, "foo") || !strings.Contains(out, "mycm") || !strings.Contains(out, "key1") || !strings.Contains(out, "value1") || !strings.Contains(out, "key2") || !strings.Contains(out, "value2") {
- t.Errorf("unexpected out: %s", out)
- }
- }
- func TestDescribeLimitRange(t *testing.T) {
- fake := fake.NewSimpleClientset(&corev1.LimitRange{
- ObjectMeta: metav1.ObjectMeta{
- Name: "mylr",
- Namespace: "foo",
- },
- Spec: corev1.LimitRangeSpec{
- Limits: []corev1.LimitRangeItem{
- {
- Type: corev1.LimitTypePod,
- Max: getResourceList("100m", "10000Mi"),
- Min: getResourceList("5m", "100Mi"),
- MaxLimitRequestRatio: getResourceList("10", ""),
- },
- {
- Type: corev1.LimitTypeContainer,
- Max: getResourceList("100m", "10000Mi"),
- Min: getResourceList("5m", "100Mi"),
- Default: getResourceList("50m", "500Mi"),
- DefaultRequest: getResourceList("10m", "200Mi"),
- MaxLimitRequestRatio: getResourceList("10", ""),
- },
- {
- Type: corev1.LimitTypePersistentVolumeClaim,
- Max: getStorageResourceList("10Gi"),
- Min: getStorageResourceList("5Gi"),
- },
- },
- },
- })
- c := &describeClient{T: t, Namespace: "foo", Interface: fake}
- d := LimitRangeDescriber{c}
- out, err := d.Describe("foo", "mylr", describe.DescriberSettings{ShowEvents: true})
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- checks := []string{"foo", "mylr", "Pod", "cpu", "5m", "100m", "memory", "100Mi", "10000Mi", "10", "Container", "cpu", "10m", "50m", "200Mi", "500Mi", "PersistentVolumeClaim", "storage", "5Gi", "10Gi"}
- for _, check := range checks {
- if !strings.Contains(out, check) {
- t.Errorf("unexpected out: %s", out)
- }
- }
- }
- func getStorageResourceList(storage string) corev1.ResourceList {
- res := corev1.ResourceList{}
- if storage != "" {
- res[corev1.ResourceStorage] = resource.MustParse(storage)
- }
- return res
- }
- func getResourceList(cpu, memory string) corev1.ResourceList {
- res := corev1.ResourceList{}
- if cpu != "" {
- res[corev1.ResourceCPU] = resource.MustParse(cpu)
- }
- if memory != "" {
- res[corev1.ResourceMemory] = resource.MustParse(memory)
- }
- return res
- }
- func TestDescribeService(t *testing.T) {
- testCases := []struct {
- name string
- service *corev1.Service
- expect []string
- }{
- {
- name: "test1",
- service: &corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- Namespace: "foo",
- },
- Spec: corev1.ServiceSpec{
- Type: corev1.ServiceTypeLoadBalancer,
- Ports: []corev1.ServicePort{{
- Name: "port-tcp",
- Port: 8080,
- Protocol: corev1.ProtocolTCP,
- TargetPort: intstr.FromInt(9527),
- NodePort: 31111,
- }},
- Selector: map[string]string{"blah": "heh"},
- ClusterIP: "1.2.3.4",
- LoadBalancerIP: "5.6.7.8",
- SessionAffinity: "None",
- ExternalTrafficPolicy: "Local",
- HealthCheckNodePort: 32222,
- },
- },
- expect: []string{
- "Name", "bar",
- "Namespace", "foo",
- "Selector", "blah=heh",
- "Type", "LoadBalancer",
- "IP", "1.2.3.4",
- "Port", "port-tcp", "8080/TCP",
- "TargetPort", "9527/TCP",
- "NodePort", "port-tcp", "31111/TCP",
- "Session Affinity", "None",
- "External Traffic Policy", "Local",
- "HealthCheck NodePort", "32222",
- },
- },
- {
- name: "test2",
- service: &corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- Namespace: "foo",
- },
- Spec: corev1.ServiceSpec{
- Type: corev1.ServiceTypeLoadBalancer,
- Ports: []corev1.ServicePort{{
- Name: "port-tcp",
- Port: 8080,
- Protocol: corev1.ProtocolTCP,
- TargetPort: intstr.FromString("targetPort"),
- NodePort: 31111,
- }},
- Selector: map[string]string{"blah": "heh"},
- ClusterIP: "1.2.3.4",
- LoadBalancerIP: "5.6.7.8",
- SessionAffinity: "None",
- ExternalTrafficPolicy: "Local",
- HealthCheckNodePort: 32222,
- },
- },
- expect: []string{
- "Name", "bar",
- "Namespace", "foo",
- "Selector", "blah=heh",
- "Type", "LoadBalancer",
- "IP", "1.2.3.4",
- "Port", "port-tcp", "8080/TCP",
- "TargetPort", "targetPort/TCP",
- "NodePort", "port-tcp", "31111/TCP",
- "Session Affinity", "None",
- "External Traffic Policy", "Local",
- "HealthCheck NodePort", "32222",
- },
- },
- }
- for _, testCase := range testCases {
- t.Run(testCase.name, func(t *testing.T) {
- fake := fake.NewSimpleClientset(testCase.service)
- c := &describeClient{T: t, Namespace: "foo", Interface: fake}
- d := ServiceDescriber{c}
- out, err := d.Describe("foo", "bar", describe.DescriberSettings{ShowEvents: true})
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- for _, expected := range testCase.expect {
- if !strings.Contains(out, expected) {
- t.Errorf("expected to find %q in output: %q", expected, out)
- }
- }
- })
- }
- }
- func TestPodDescribeResultsSorted(t *testing.T) {
- // Arrange
- fake := fake.NewSimpleClientset(
- &corev1.EventList{
- Items: []corev1.Event{
- {
- ObjectMeta: metav1.ObjectMeta{Name: "one"},
- Source: corev1.EventSource{Component: "kubelet"},
- Message: "Item 1",
- FirstTimestamp: metav1.NewTime(time.Date(2014, time.January, 15, 0, 0, 0, 0, time.UTC)),
- LastTimestamp: metav1.NewTime(time.Date(2014, time.January, 15, 0, 0, 0, 0, time.UTC)),
- Count: 1,
- Type: corev1.EventTypeNormal,
- },
- {
- ObjectMeta: metav1.ObjectMeta{Name: "two"},
- Source: corev1.EventSource{Component: "scheduler"},
- Message: "Item 2",
- FirstTimestamp: metav1.NewTime(time.Date(1987, time.June, 17, 0, 0, 0, 0, time.UTC)),
- LastTimestamp: metav1.NewTime(time.Date(1987, time.June, 17, 0, 0, 0, 0, time.UTC)),
- Count: 1,
- Type: corev1.EventTypeNormal,
- },
- {
- ObjectMeta: metav1.ObjectMeta{Name: "three"},
- Source: corev1.EventSource{Component: "kubelet"},
- Message: "Item 3",
- FirstTimestamp: metav1.NewTime(time.Date(2002, time.December, 25, 0, 0, 0, 0, time.UTC)),
- LastTimestamp: metav1.NewTime(time.Date(2002, time.December, 25, 0, 0, 0, 0, time.UTC)),
- Count: 1,
- Type: corev1.EventTypeNormal,
- },
- },
- },
- &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"}},
- )
- c := &describeClient{T: t, Namespace: "foo", Interface: fake}
- d := PodDescriber{c}
- // Act
- out, err := d.Describe("foo", "bar", describe.DescriberSettings{ShowEvents: true})
- // Assert
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- VerifyDatesInOrder(out, "\n" /* rowDelimiter */, "\t" /* columnDelimiter */, t)
- }
- // VerifyDatesInOrder checks the start of each line for a RFC1123Z date
- // and posts error if all subsequent dates are not equal or increasing
- func VerifyDatesInOrder(
- resultToTest, rowDelimiter, columnDelimiter string, t *testing.T) {
- lines := strings.Split(resultToTest, rowDelimiter)
- var previousTime time.Time
- for _, str := range lines {
- columns := strings.Split(str, columnDelimiter)
- if len(columns) > 0 {
- currentTime, err := time.Parse(time.RFC1123Z, columns[0])
- if err == nil {
- if previousTime.After(currentTime) {
- t.Errorf(
- "Output is not sorted by time. %s should be listed after %s. Complete output: %s",
- previousTime.Format(time.RFC1123Z),
- currentTime.Format(time.RFC1123Z),
- resultToTest)
- }
- previousTime = currentTime
- }
- }
- }
- }
- func TestDescribeContainers(t *testing.T) {
- trueVal := true
- testCases := []struct {
- container corev1.Container
- status corev1.ContainerStatus
- expectedElements []string
- }{
- // Running state.
- {
- container: corev1.Container{Name: "test", Image: "image"},
- status: corev1.ContainerStatus{
- Name: "test",
- State: corev1.ContainerState{
- Running: &corev1.ContainerStateRunning{
- StartedAt: metav1.NewTime(time.Now()),
- },
- },
- Ready: true,
- RestartCount: 7,
- },
- expectedElements: []string{"test", "State", "Running", "Ready", "True", "Restart Count", "7", "Image", "image", "Started"},
- },
- // Waiting state.
- {
- container: corev1.Container{Name: "test", Image: "image"},
- status: corev1.ContainerStatus{
- Name: "test",
- State: corev1.ContainerState{
- Waiting: &corev1.ContainerStateWaiting{
- Reason: "potato",
- },
- },
- Ready: true,
- RestartCount: 7,
- },
- expectedElements: []string{"test", "State", "Waiting", "Ready", "True", "Restart Count", "7", "Image", "image", "Reason", "potato"},
- },
- // Terminated state.
- {
- container: corev1.Container{Name: "test", Image: "image"},
- status: corev1.ContainerStatus{
- Name: "test",
- State: corev1.ContainerState{
- Terminated: &corev1.ContainerStateTerminated{
- StartedAt: metav1.NewTime(time.Now()),
- FinishedAt: metav1.NewTime(time.Now()),
- Reason: "potato",
- ExitCode: 2,
- },
- },
- Ready: true,
- RestartCount: 7,
- },
- expectedElements: []string{"test", "State", "Terminated", "Ready", "True", "Restart Count", "7", "Image", "image", "Reason", "potato", "Started", "Finished", "Exit Code", "2"},
- },
- // Last Terminated
- {
- container: corev1.Container{Name: "test", Image: "image"},
- status: corev1.ContainerStatus{
- Name: "test",
- State: corev1.ContainerState{
- Running: &corev1.ContainerStateRunning{
- StartedAt: metav1.NewTime(time.Now()),
- },
- },
- LastTerminationState: corev1.ContainerState{
- Terminated: &corev1.ContainerStateTerminated{
- StartedAt: metav1.NewTime(time.Now().Add(time.Second * 3)),
- FinishedAt: metav1.NewTime(time.Now()),
- Reason: "crashing",
- ExitCode: 3,
- },
- },
- Ready: true,
- RestartCount: 7,
- },
- expectedElements: []string{"test", "State", "Terminated", "Ready", "True", "Restart Count", "7", "Image", "image", "Started", "Finished", "Exit Code", "2", "crashing", "3"},
- },
- // No state defaults to waiting.
- {
- container: corev1.Container{Name: "test", Image: "image"},
- status: corev1.ContainerStatus{
- Name: "test",
- Ready: true,
- RestartCount: 7,
- },
- expectedElements: []string{"test", "State", "Waiting", "Ready", "True", "Restart Count", "7", "Image", "image"},
- },
- // Env
- {
- container: corev1.Container{Name: "test", Image: "image", Env: []corev1.EnvVar{{Name: "envname", Value: "xyz"}}, EnvFrom: []corev1.EnvFromSource{{ConfigMapRef: &corev1.ConfigMapEnvSource{LocalObjectReference: corev1.LocalObjectReference{Name: "a123"}}}}},
- status: corev1.ContainerStatus{
- Name: "test",
- Ready: true,
- RestartCount: 7,
- },
- expectedElements: []string{"test", "State", "Waiting", "Ready", "True", "Restart Count", "7", "Image", "image", "envname", "xyz", "a123\tConfigMap\tOptional: false"},
- },
- {
- container: corev1.Container{Name: "test", Image: "image", Env: []corev1.EnvVar{{Name: "envname", Value: "xyz"}}, EnvFrom: []corev1.EnvFromSource{{Prefix: "p_", ConfigMapRef: &corev1.ConfigMapEnvSource{LocalObjectReference: corev1.LocalObjectReference{Name: "a123"}}}}},
- status: corev1.ContainerStatus{
- Name: "test",
- Ready: true,
- RestartCount: 7,
- },
- expectedElements: []string{"test", "State", "Waiting", "Ready", "True", "Restart Count", "7", "Image", "image", "envname", "xyz", "a123\tConfigMap with prefix 'p_'\tOptional: false"},
- },
- {
- container: corev1.Container{Name: "test", Image: "image", Env: []corev1.EnvVar{{Name: "envname", Value: "xyz"}}, EnvFrom: []corev1.EnvFromSource{{ConfigMapRef: &corev1.ConfigMapEnvSource{Optional: &trueVal, LocalObjectReference: corev1.LocalObjectReference{Name: "a123"}}}}},
- status: corev1.ContainerStatus{
- Name: "test",
- Ready: true,
- RestartCount: 7,
- },
- expectedElements: []string{"test", "State", "Waiting", "Ready", "True", "Restart Count", "7", "Image", "image", "envname", "xyz", "a123\tConfigMap\tOptional: true"},
- },
- {
- container: corev1.Container{Name: "test", Image: "image", Env: []corev1.EnvVar{{Name: "envname", Value: "xyz"}}, EnvFrom: []corev1.EnvFromSource{{SecretRef: &corev1.SecretEnvSource{LocalObjectReference: corev1.LocalObjectReference{Name: "a123"}, Optional: &trueVal}}}},
- status: corev1.ContainerStatus{
- Name: "test",
- Ready: true,
- RestartCount: 7,
- },
- expectedElements: []string{"test", "State", "Waiting", "Ready", "True", "Restart Count", "7", "Image", "image", "envname", "xyz", "a123\tSecret\tOptional: true"},
- },
- {
- container: corev1.Container{Name: "test", Image: "image", Env: []corev1.EnvVar{{Name: "envname", Value: "xyz"}}, EnvFrom: []corev1.EnvFromSource{{Prefix: "p_", SecretRef: &corev1.SecretEnvSource{LocalObjectReference: corev1.LocalObjectReference{Name: "a123"}}}}},
- status: corev1.ContainerStatus{
- Name: "test",
- Ready: true,
- RestartCount: 7,
- },
- expectedElements: []string{"test", "State", "Waiting", "Ready", "True", "Restart Count", "7", "Image", "image", "envname", "xyz", "a123\tSecret with prefix 'p_'\tOptional: false"},
- },
- // Command
- {
- container: corev1.Container{Name: "test", Image: "image", Command: []string{"sleep", "1000"}},
- status: corev1.ContainerStatus{
- Name: "test",
- Ready: true,
- RestartCount: 7,
- },
- expectedElements: []string{"test", "State", "Waiting", "Ready", "True", "Restart Count", "7", "Image", "image", "sleep", "1000"},
- },
- // Command with newline
- {
- container: corev1.Container{Name: "test", Image: "image", Command: []string{"sleep", "1000\n2000"}},
- status: corev1.ContainerStatus{
- Name: "test",
- Ready: true,
- RestartCount: 7,
- },
- expectedElements: []string{"1000\n 2000"},
- },
- // Args
- {
- container: corev1.Container{Name: "test", Image: "image", Args: []string{"time", "1000"}},
- status: corev1.ContainerStatus{
- Name: "test",
- Ready: true,
- RestartCount: 7,
- },
- expectedElements: []string{"test", "State", "Waiting", "Ready", "True", "Restart Count", "7", "Image", "image", "time", "1000"},
- },
- // Args with newline
- {
- container: corev1.Container{Name: "test", Image: "image", Args: []string{"time", "1000\n2000"}},
- status: corev1.ContainerStatus{
- Name: "test",
- Ready: true,
- RestartCount: 7,
- },
- expectedElements: []string{"1000\n 2000"},
- },
- // Using limits.
- {
- container: corev1.Container{
- Name: "test",
- Image: "image",
- Resources: corev1.ResourceRequirements{
- Limits: corev1.ResourceList{
- corev1.ResourceName(corev1.ResourceCPU): resource.MustParse("1000"),
- corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("4G"),
- corev1.ResourceName(corev1.ResourceStorage): resource.MustParse("20G"),
- },
- },
- },
- status: corev1.ContainerStatus{
- Name: "test",
- Ready: true,
- RestartCount: 7,
- },
- expectedElements: []string{"cpu", "1k", "memory", "4G", "storage", "20G"},
- },
- // Using requests.
- {
- container: corev1.Container{
- Name: "test",
- Image: "image",
- Resources: corev1.ResourceRequirements{
- Requests: corev1.ResourceList{
- corev1.ResourceName(corev1.ResourceCPU): resource.MustParse("1000"),
- corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("4G"),
- corev1.ResourceName(corev1.ResourceStorage): resource.MustParse("20G"),
- },
- },
- },
- expectedElements: []string{"cpu", "1k", "memory", "4G", "storage", "20G"},
- },
- // volumeMounts read/write
- {
- container: corev1.Container{
- Name: "test",
- Image: "image",
- VolumeMounts: []corev1.VolumeMount{
- {
- Name: "mounted-volume",
- MountPath: "/opt/",
- },
- },
- },
- expectedElements: []string{"mounted-volume", "/opt/", "(rw)"},
- },
- // volumeMounts readonly
- {
- container: corev1.Container{
- Name: "test",
- Image: "image",
- VolumeMounts: []corev1.VolumeMount{
- {
- Name: "mounted-volume",
- MountPath: "/opt/",
- ReadOnly: true,
- },
- },
- },
- expectedElements: []string{"Mounts", "mounted-volume", "/opt/", "(ro)"},
- },
- // volumeMounts subPath
- {
- container: corev1.Container{
- Name: "test",
- Image: "image",
- VolumeMounts: []corev1.VolumeMount{
- {
- Name: "mounted-volume",
- MountPath: "/opt/",
- SubPath: "foo",
- },
- },
- },
- expectedElements: []string{"Mounts", "mounted-volume", "/opt/", "(rw,path=\"foo\")"},
- },
- // volumeDevices
- {
- container: corev1.Container{
- Name: "test",
- Image: "image",
- VolumeDevices: []corev1.VolumeDevice{
- {
- Name: "volume-device",
- DevicePath: "/dev/xvda",
- },
- },
- },
- expectedElements: []string{"Devices", "volume-device", "/dev/xvda"},
- },
- }
- for i, testCase := range testCases {
- t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
- out := new(bytes.Buffer)
- pod := corev1.Pod{
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{testCase.container},
- },
- Status: corev1.PodStatus{
- ContainerStatuses: []corev1.ContainerStatus{testCase.status},
- },
- }
- writer := NewPrefixWriter(out)
- describeContainers("Containers", pod.Spec.Containers, pod.Status.ContainerStatuses, EnvValueRetriever(&pod), writer, "")
- output := out.String()
- for _, expected := range testCase.expectedElements {
- if !strings.Contains(output, expected) {
- t.Errorf("Test case %d: expected to find %q in output: %q", i, expected, output)
- }
- }
- })
- }
- }
- func TestDescribers(t *testing.T) {
- first := &corev1.Event{}
- second := &corev1.Pod{}
- var third *corev1.Pod
- testErr := fmt.Errorf("test")
- d := Describers{}
- d.Add(
- func(e *corev1.Event, p *corev1.Pod) (string, error) {
- if e != first {
- t.Errorf("first argument not equal: %#v", e)
- }
- if p != second {
- t.Errorf("second argument not equal: %#v", p)
- }
- return "test", testErr
- },
- )
- if out, err := d.DescribeObject(first, second); out != "test" || err != testErr {
- t.Errorf("unexpected result: %s %v", out, err)
- }
- if out, err := d.DescribeObject(first, second, third); out != "" || err == nil {
- t.Errorf("unexpected result: %s %v", out, err)
- } else {
- if noDescriber, ok := err.(describe.ErrNoDescriber); ok {
- if !reflect.DeepEqual(noDescriber.Types, []string{"*v1.Event", "*v1.Pod", "*v1.Pod"}) {
- t.Errorf("unexpected describer: %v", err)
- }
- } else {
- t.Errorf("unexpected error type: %v", err)
- }
- }
- d.Add(
- func(e *corev1.Event) (string, error) {
- if e != first {
- t.Errorf("first argument not equal: %#v", e)
- }
- return "simpler", testErr
- },
- )
- if out, err := d.DescribeObject(first); out != "simpler" || err != testErr {
- t.Errorf("unexpected result: %s %v", out, err)
- }
- }
- func TestDefaultDescribers(t *testing.T) {
- out, err := DefaultObjectDescriber.DescribeObject(&corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- if !strings.Contains(out, "foo") {
- t.Errorf("unexpected output: %s", out)
- }
- out, err = DefaultObjectDescriber.DescribeObject(&corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- if !strings.Contains(out, "foo") {
- t.Errorf("unexpected output: %s", out)
- }
- out, err = DefaultObjectDescriber.DescribeObject(&corev1.ReplicationController{
- ObjectMeta: metav1.ObjectMeta{Name: "foo"},
- Spec: corev1.ReplicationControllerSpec{Replicas: utilpointer.Int32Ptr(1)},
- })
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- if !strings.Contains(out, "foo") {
- t.Errorf("unexpected output: %s", out)
- }
- out, err = DefaultObjectDescriber.DescribeObject(&corev1.Node{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- if !strings.Contains(out, "foo") {
- t.Errorf("unexpected output: %s", out)
- }
- }
- func TestGetPodsTotalRequests(t *testing.T) {
- testCases := []struct {
- name string
- pods *corev1.PodList
- expectedReqs map[corev1.ResourceName]resource.Quantity
- }{
- {
- name: "test1",
- pods: &corev1.PodList{
- Items: []corev1.Pod{
- {
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{
- {
- Resources: corev1.ResourceRequirements{
- Requests: corev1.ResourceList{
- corev1.ResourceName(corev1.ResourceCPU): resource.MustParse("1"),
- corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("300Mi"),
- corev1.ResourceName(corev1.ResourceStorage): resource.MustParse("1G"),
- },
- },
- },
- {
- Resources: corev1.ResourceRequirements{
- Requests: corev1.ResourceList{
- corev1.ResourceName(corev1.ResourceCPU): resource.MustParse("90m"),
- corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("120Mi"),
- corev1.ResourceName(corev1.ResourceStorage): resource.MustParse("200M"),
- },
- },
- },
- },
- },
- },
- {
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{
- {
- Resources: corev1.ResourceRequirements{
- Requests: corev1.ResourceList{
- corev1.ResourceName(corev1.ResourceCPU): resource.MustParse("60m"),
- corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("43Mi"),
- corev1.ResourceName(corev1.ResourceStorage): resource.MustParse("500M"),
- },
- },
- },
- {
- Resources: corev1.ResourceRequirements{
- Requests: corev1.ResourceList{
- corev1.ResourceName(corev1.ResourceCPU): resource.MustParse("34m"),
- corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("83Mi"),
- corev1.ResourceName(corev1.ResourceStorage): resource.MustParse("700M"),
- },
- },
- },
- },
- },
- },
- },
- },
- expectedReqs: map[corev1.ResourceName]resource.Quantity{
- corev1.ResourceName(corev1.ResourceCPU): resource.MustParse("1.184"),
- corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("546Mi"),
- corev1.ResourceName(corev1.ResourceStorage): resource.MustParse("2.4G"),
- },
- },
- }
- for _, testCase := range testCases {
- t.Run(testCase.name, func(t *testing.T) {
- reqs, _ := getPodsTotalRequestsAndLimits(testCase.pods)
- if !apiequality.Semantic.DeepEqual(reqs, testCase.expectedReqs) {
- t.Errorf("Expected %v, got %v", testCase.expectedReqs, reqs)
- }
- })
- }
- }
- func TestPersistentVolumeDescriber(t *testing.T) {
- block := corev1.PersistentVolumeBlock
- file := corev1.PersistentVolumeFilesystem
- deletionTimestamp := metav1.Time{Time: time.Now().UTC().AddDate(-10, 0, 0)}
- testCases := []struct {
- name string
- plugin string
- pv *corev1.PersistentVolume
- expectedElements []string
- unexpectedElements []string
- }{
- {
- name: "test0",
- plugin: "hostpath",
- pv: &corev1.PersistentVolume{
- ObjectMeta: metav1.ObjectMeta{Name: "bar"},
- Spec: corev1.PersistentVolumeSpec{
- PersistentVolumeSource: corev1.PersistentVolumeSource{
- HostPath: &corev1.HostPathVolumeSource{Type: new(corev1.HostPathType)},
- },
- },
- },
- unexpectedElements: []string{"VolumeMode", "Filesystem"},
- },
- {
- name: "test1",
- plugin: "gce",
- pv: &corev1.PersistentVolume{
- ObjectMeta: metav1.ObjectMeta{Name: "bar"},
- Spec: corev1.PersistentVolumeSpec{
- PersistentVolumeSource: corev1.PersistentVolumeSource{
- GCEPersistentDisk: &corev1.GCEPersistentDiskVolumeSource{},
- },
- VolumeMode: &file,
- },
- },
- expectedElements: []string{"VolumeMode", "Filesystem"},
- },
- {
- name: "test2",
- plugin: "ebs",
- pv: &corev1.PersistentVolume{
- ObjectMeta: metav1.ObjectMeta{Name: "bar"},
- Spec: corev1.PersistentVolumeSpec{
- PersistentVolumeSource: corev1.PersistentVolumeSource{
- AWSElasticBlockStore: &corev1.AWSElasticBlockStoreVolumeSource{},
- },
- },
- },
- unexpectedElements: []string{"VolumeMode", "Filesystem"},
- },
- {
- name: "test3",
- plugin: "nfs",
- pv: &corev1.PersistentVolume{
- ObjectMeta: metav1.ObjectMeta{Name: "bar"},
- Spec: corev1.PersistentVolumeSpec{
- PersistentVolumeSource: corev1.PersistentVolumeSource{
- NFS: &corev1.NFSVolumeSource{},
- },
- },
- },
- unexpectedElements: []string{"VolumeMode", "Filesystem"},
- },
- {
- name: "test4",
- plugin: "iscsi",
- pv: &corev1.PersistentVolume{
- ObjectMeta: metav1.ObjectMeta{Name: "bar"},
- Spec: corev1.PersistentVolumeSpec{
- PersistentVolumeSource: corev1.PersistentVolumeSource{
- ISCSI: &corev1.ISCSIPersistentVolumeSource{},
- },
- VolumeMode: &block,
- },
- },
- expectedElements: []string{"VolumeMode", "Block"},
- },
- {
- name: "test5",
- plugin: "gluster",
- pv: &corev1.PersistentVolume{
- ObjectMeta: metav1.ObjectMeta{Name: "bar"},
- Spec: corev1.PersistentVolumeSpec{
- PersistentVolumeSource: corev1.PersistentVolumeSource{
- Glusterfs: &corev1.GlusterfsPersistentVolumeSource{},
- },
- },
- },
- unexpectedElements: []string{"VolumeMode", "Filesystem"},
- },
- {
- name: "test6",
- plugin: "rbd",
- pv: &corev1.PersistentVolume{
- ObjectMeta: metav1.ObjectMeta{Name: "bar"},
- Spec: corev1.PersistentVolumeSpec{
- PersistentVolumeSource: corev1.PersistentVolumeSource{
- RBD: &corev1.RBDPersistentVolumeSource{},
- },
- },
- },
- unexpectedElements: []string{"VolumeMode", "Filesystem"},
- },
- {
- name: "test7",
- plugin: "quobyte",
- pv: &corev1.PersistentVolume{
- ObjectMeta: metav1.ObjectMeta{Name: "bar"},
- Spec: corev1.PersistentVolumeSpec{
- PersistentVolumeSource: corev1.PersistentVolumeSource{
- Quobyte: &corev1.QuobyteVolumeSource{},
- },
- },
- },
- unexpectedElements: []string{"VolumeMode", "Filesystem"},
- },
- {
- name: "test8",
- plugin: "cinder",
- pv: &corev1.PersistentVolume{
- ObjectMeta: metav1.ObjectMeta{Name: "bar"},
- Spec: corev1.PersistentVolumeSpec{
- PersistentVolumeSource: corev1.PersistentVolumeSource{
- Cinder: &corev1.CinderPersistentVolumeSource{},
- },
- },
- },
- unexpectedElements: []string{"VolumeMode", "Filesystem"},
- },
- {
- name: "test9",
- plugin: "fc",
- pv: &corev1.PersistentVolume{
- ObjectMeta: metav1.ObjectMeta{Name: "bar"},
- Spec: corev1.PersistentVolumeSpec{
- PersistentVolumeSource: corev1.PersistentVolumeSource{
- FC: &corev1.FCVolumeSource{},
- },
- VolumeMode: &block,
- },
- },
- expectedElements: []string{"VolumeMode", "Block"},
- },
- {
- name: "test10",
- plugin: "local",
- pv: &corev1.PersistentVolume{
- ObjectMeta: metav1.ObjectMeta{Name: "bar"},
- Spec: corev1.PersistentVolumeSpec{
- PersistentVolumeSource: corev1.PersistentVolumeSource{
- Local: &corev1.LocalVolumeSource{},
- },
- },
- },
- expectedElements: []string{"Node Affinity: <none>"},
- unexpectedElements: []string{"Required Terms", "Term "},
- },
- {
- name: "test11",
- plugin: "local",
- pv: &corev1.PersistentVolume{
- ObjectMeta: metav1.ObjectMeta{Name: "bar"},
- Spec: corev1.PersistentVolumeSpec{
- PersistentVolumeSource: corev1.PersistentVolumeSource{
- Local: &corev1.LocalVolumeSource{},
- },
- NodeAffinity: &corev1.VolumeNodeAffinity{},
- },
- },
- expectedElements: []string{"Node Affinity: <none>"},
- unexpectedElements: []string{"Required Terms", "Term "},
- },
- {
- name: "test12",
- plugin: "local",
- pv: &corev1.PersistentVolume{
- ObjectMeta: metav1.ObjectMeta{Name: "bar"},
- Spec: corev1.PersistentVolumeSpec{
- PersistentVolumeSource: corev1.PersistentVolumeSource{
- Local: &corev1.LocalVolumeSource{},
- },
- NodeAffinity: &corev1.VolumeNodeAffinity{
- Required: &corev1.NodeSelector{},
- },
- },
- },
- expectedElements: []string{"Node Affinity", "Required Terms: <none>"},
- unexpectedElements: []string{"Term "},
- },
- {
- name: "test13",
- plugin: "local",
- pv: &corev1.PersistentVolume{
- ObjectMeta: metav1.ObjectMeta{Name: "bar"},
- Spec: corev1.PersistentVolumeSpec{
- PersistentVolumeSource: corev1.PersistentVolumeSource{
- Local: &corev1.LocalVolumeSource{},
- },
- NodeAffinity: &corev1.VolumeNodeAffinity{
- Required: &corev1.NodeSelector{
- NodeSelectorTerms: []corev1.NodeSelectorTerm{
- {
- MatchExpressions: []corev1.NodeSelectorRequirement{},
- },
- {
- MatchExpressions: []corev1.NodeSelectorRequirement{},
- },
- },
- },
- },
- },
- },
- expectedElements: []string{"Node Affinity", "Required Terms", "Term 0", "Term 1"},
- },
- {
- name: "test14",
- plugin: "local",
- pv: &corev1.PersistentVolume{
- ObjectMeta: metav1.ObjectMeta{Name: "bar"},
- Spec: corev1.PersistentVolumeSpec{
- PersistentVolumeSource: corev1.PersistentVolumeSource{
- Local: &corev1.LocalVolumeSource{},
- },
- NodeAffinity: &corev1.VolumeNodeAffinity{
- Required: &corev1.NodeSelector{
- NodeSelectorTerms: []corev1.NodeSelectorTerm{
- {
- MatchExpressions: []corev1.NodeSelectorRequirement{
- {
- Key: "foo",
- Operator: "In",
- Values: []string{"val1", "val2"},
- },
- {
- Key: "foo",
- Operator: "Exists",
- },
- },
- },
- },
- },
- },
- },
- },
- expectedElements: []string{"Node Affinity", "Required Terms", "Term 0",
- "foo in [val1, val2]",
- "foo exists"},
- },
- {
- name: "test15",
- plugin: "local",
- pv: &corev1.PersistentVolume{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- DeletionTimestamp: &deletionTimestamp,
- },
- Spec: corev1.PersistentVolumeSpec{
- PersistentVolumeSource: corev1.PersistentVolumeSource{
- Local: &corev1.LocalVolumeSource{},
- },
- },
- },
- expectedElements: []string{"Terminating (lasts 10y)"},
- },
- {
- name: "test16",
- plugin: "local",
- pv: &corev1.PersistentVolume{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- GenerateName: "test-GenerateName",
- UID: "test-UID",
- CreationTimestamp: metav1.Time{Time: time.Now()},
- DeletionTimestamp: &metav1.Time{Time: time.Now()},
- DeletionGracePeriodSeconds: new(int64),
- Labels: map[string]string{"label1": "label1", "label2": "label2", "label3": "label3"},
- Annotations: map[string]string{"annotation1": "annotation1", "annotation2": "annotation2", "annotation3": "annotation3"},
- },
- Spec: corev1.PersistentVolumeSpec{
- PersistentVolumeSource: corev1.PersistentVolumeSource{
- Local: &corev1.LocalVolumeSource{},
- },
- NodeAffinity: &corev1.VolumeNodeAffinity{
- Required: &corev1.NodeSelector{
- NodeSelectorTerms: []corev1.NodeSelectorTerm{
- {
- MatchExpressions: []corev1.NodeSelectorRequirement{
- {
- Key: "foo",
- Operator: "In",
- Values: []string{"val1", "val2"},
- },
- {
- Key: "foo",
- Operator: "Exists",
- },
- },
- },
- },
- },
- },
- },
- },
- expectedElements: []string{"Node Affinity", "Required Terms", "Term 0",
- "foo in [val1, val2]",
- "foo exists"},
- },
- {
- name: "test17",
- plugin: "local",
- pv: &corev1.PersistentVolume{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- GenerateName: "test-GenerateName",
- UID: "test-UID",
- CreationTimestamp: metav1.Time{Time: time.Now()},
- DeletionTimestamp: &metav1.Time{Time: time.Now()},
- DeletionGracePeriodSeconds: new(int64),
- Labels: map[string]string{"label1": "label1", "label2": "label2", "label3": "label3"},
- Annotations: map[string]string{"annotation1": "annotation1", "annotation2": "annotation2", "annotation3": "annotation3"},
- },
- Spec: corev1.PersistentVolumeSpec{
- PersistentVolumeSource: corev1.PersistentVolumeSource{
- CSI: &corev1.CSIPersistentVolumeSource{
- Driver: "drive",
- VolumeHandle: "handler",
- ReadOnly: true,
- VolumeAttributes: map[string]string{
- "Attribute1": "Value1",
- "Attribute2": "Value2",
- "Attribute3": "Value3",
- },
- },
- },
- },
- },
- expectedElements: []string{"Driver", "VolumeHandle", "ReadOnly", "VolumeAttributes"},
- },
- }
- for _, test := range testCases {
- t.Run(test.name, func(t *testing.T) {
- fake := fake.NewSimpleClientset(test.pv)
- c := PersistentVolumeDescriber{fake}
- str, err := c.Describe("foo", "bar", describe.DescriberSettings{ShowEvents: true})
- if err != nil {
- t.Errorf("Unexpected error for test %s: %v", test.plugin, err)
- }
- if str == "" {
- t.Errorf("Unexpected empty string for test %s. Expected PV Describer output", test.plugin)
- }
- for _, expected := range test.expectedElements {
- if !strings.Contains(str, expected) {
- t.Errorf("expected to find %q in output: %q", expected, str)
- }
- }
- for _, unexpected := range test.unexpectedElements {
- if strings.Contains(str, unexpected) {
- t.Errorf("unexpected to find %q in output: %q", unexpected, str)
- }
- }
- })
- }
- }
- func TestPersistentVolumeClaimDescriber(t *testing.T) {
- block := corev1.PersistentVolumeBlock
- file := corev1.PersistentVolumeFilesystem
- goldClassName := "gold"
- now := time.Now()
- deletionTimestamp := metav1.Time{Time: time.Now().UTC().AddDate(-10, 0, 0)}
- testCases := []struct {
- name string
- pvc *corev1.PersistentVolumeClaim
- expectedElements []string
- unexpectedElements []string
- }{
- {
- name: "default",
- pvc: &corev1.PersistentVolumeClaim{
- ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"},
- Spec: corev1.PersistentVolumeClaimSpec{
- VolumeName: "volume1",
- StorageClassName: &goldClassName,
- },
- Status: corev1.PersistentVolumeClaimStatus{
- Phase: corev1.ClaimBound,
- },
- },
- unexpectedElements: []string{"VolumeMode", "Filesystem"},
- },
- {
- name: "filesystem",
- pvc: &corev1.PersistentVolumeClaim{
- ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"},
- Spec: corev1.PersistentVolumeClaimSpec{
- VolumeName: "volume2",
- StorageClassName: &goldClassName,
- VolumeMode: &file,
- },
- Status: corev1.PersistentVolumeClaimStatus{
- Phase: corev1.ClaimBound,
- },
- },
- expectedElements: []string{"VolumeMode", "Filesystem"},
- },
- {
- name: "block",
- pvc: &corev1.PersistentVolumeClaim{
- ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"},
- Spec: corev1.PersistentVolumeClaimSpec{
- VolumeName: "volume3",
- StorageClassName: &goldClassName,
- VolumeMode: &block,
- },
- Status: corev1.PersistentVolumeClaimStatus{
- Phase: corev1.ClaimBound,
- },
- },
- expectedElements: []string{"VolumeMode", "Block"},
- },
- // Tests for Status.Condition.
- {
- name: "condition-type",
- pvc: &corev1.PersistentVolumeClaim{
- ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"},
- Spec: corev1.PersistentVolumeClaimSpec{
- VolumeName: "volume4",
- StorageClassName: &goldClassName,
- },
- Status: corev1.PersistentVolumeClaimStatus{
- Conditions: []corev1.PersistentVolumeClaimCondition{
- {Type: corev1.PersistentVolumeClaimResizing},
- },
- },
- },
- expectedElements: []string{"Conditions", "Type", "Resizing"},
- },
- {
- name: "condition-status",
- pvc: &corev1.PersistentVolumeClaim{
- ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"},
- Spec: corev1.PersistentVolumeClaimSpec{
- VolumeName: "volume5",
- StorageClassName: &goldClassName,
- },
- Status: corev1.PersistentVolumeClaimStatus{
- Conditions: []corev1.PersistentVolumeClaimCondition{
- {Status: corev1.ConditionTrue},
- },
- },
- },
- expectedElements: []string{"Conditions", "Status", "True"},
- },
- {
- name: "condition-last-probe-time",
- pvc: &corev1.PersistentVolumeClaim{
- ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"},
- Spec: corev1.PersistentVolumeClaimSpec{
- VolumeName: "volume6",
- StorageClassName: &goldClassName,
- },
- Status: corev1.PersistentVolumeClaimStatus{
- Conditions: []corev1.PersistentVolumeClaimCondition{
- {LastProbeTime: metav1.Time{Time: now}},
- },
- },
- },
- expectedElements: []string{"Conditions", "LastProbeTime", now.Format(time.RFC1123Z)},
- },
- {
- name: "condition-last-transition-time",
- pvc: &corev1.PersistentVolumeClaim{
- ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"},
- Spec: corev1.PersistentVolumeClaimSpec{
- VolumeName: "volume7",
- StorageClassName: &goldClassName,
- },
- Status: corev1.PersistentVolumeClaimStatus{
- Conditions: []corev1.PersistentVolumeClaimCondition{
- {LastTransitionTime: metav1.Time{Time: now}},
- },
- },
- },
- expectedElements: []string{"Conditions", "LastTransitionTime", now.Format(time.RFC1123Z)},
- },
- {
- name: "condition-reason",
- pvc: &corev1.PersistentVolumeClaim{
- ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"},
- Spec: corev1.PersistentVolumeClaimSpec{
- VolumeName: "volume8",
- StorageClassName: &goldClassName,
- },
- Status: corev1.PersistentVolumeClaimStatus{
- Conditions: []corev1.PersistentVolumeClaimCondition{
- {Reason: "OfflineResize"},
- },
- },
- },
- expectedElements: []string{"Conditions", "Reason", "OfflineResize"},
- },
- {
- name: "condition-message",
- pvc: &corev1.PersistentVolumeClaim{
- ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"},
- Spec: corev1.PersistentVolumeClaimSpec{
- VolumeName: "volume9",
- StorageClassName: &goldClassName,
- },
- Status: corev1.PersistentVolumeClaimStatus{
- Conditions: []corev1.PersistentVolumeClaimCondition{
- {Message: "User request resize"},
- },
- },
- },
- expectedElements: []string{"Conditions", "Message", "User request resize"},
- },
- {
- name: "deletion-timestamp",
- pvc: &corev1.PersistentVolumeClaim{
- ObjectMeta: metav1.ObjectMeta{
- Namespace: "foo",
- Name: "bar",
- DeletionTimestamp: &deletionTimestamp,
- },
- Spec: corev1.PersistentVolumeClaimSpec{
- VolumeName: "volume10",
- StorageClassName: &goldClassName,
- },
- Status: corev1.PersistentVolumeClaimStatus{},
- },
- expectedElements: []string{"Terminating (lasts 10y)"},
- },
- }
- for _, test := range testCases {
- t.Run(test.name, func(t *testing.T) {
- fake := fake.NewSimpleClientset(test.pvc)
- c := PersistentVolumeClaimDescriber{fake}
- str, err := c.Describe("foo", "bar", describe.DescriberSettings{ShowEvents: true})
- if err != nil {
- t.Errorf("Unexpected error for test %s: %v", test.name, err)
- }
- if str == "" {
- t.Errorf("Unexpected empty string for test %s. Expected PVC Describer output", test.name)
- }
- for _, expected := range test.expectedElements {
- if !strings.Contains(str, expected) {
- t.Errorf("expected to find %q in output: %q", expected, str)
- }
- }
- for _, unexpected := range test.unexpectedElements {
- if strings.Contains(str, unexpected) {
- t.Errorf("unexpected to find %q in output: %q", unexpected, str)
- }
- }
- })
- }
- }
- func TestDescribeDeployment(t *testing.T) {
- fakeClient := fake.NewSimpleClientset(&appsv1.Deployment{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- Namespace: "foo",
- },
- Spec: appsv1.DeploymentSpec{
- Replicas: utilpointer.Int32Ptr(1),
- Selector: &metav1.LabelSelector{},
- Template: corev1.PodTemplateSpec{
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{
- {Image: "mytest-image:latest"},
- },
- },
- },
- },
- })
- d := DeploymentDescriber{fakeClient}
- out, err := d.Describe("foo", "bar", describe.DescriberSettings{ShowEvents: true})
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- if !strings.Contains(out, "bar") || !strings.Contains(out, "foo") || !strings.Contains(out, "Containers:") || !strings.Contains(out, "mytest-image:latest") {
- t.Errorf("unexpected out: %s", out)
- }
- }
- func TestDescribeStorageClass(t *testing.T) {
- reclaimPolicy := corev1.PersistentVolumeReclaimRetain
- bindingMode := storagev1.VolumeBindingMode("bindingmode")
- f := fake.NewSimpleClientset(&storagev1.StorageClass{
- ObjectMeta: metav1.ObjectMeta{
- Name: "foo",
- ResourceVersion: "4",
- Annotations: map[string]string{
- "name": "foo",
- },
- },
- Provisioner: "my-provisioner",
- Parameters: map[string]string{
- "param1": "value1",
- "param2": "value2",
- },
- ReclaimPolicy: &reclaimPolicy,
- VolumeBindingMode: &bindingMode,
- AllowedTopologies: []corev1.TopologySelectorTerm{
- {
- MatchLabelExpressions: []corev1.TopologySelectorLabelRequirement{
- {
- Key: "failure-domain.beta.kubernetes.io/zone",
- Values: []string{"zone1"},
- },
- {
- Key: "kubernetes.io/hostname",
- Values: []string{"node1"},
- },
- },
- },
- {
- MatchLabelExpressions: []corev1.TopologySelectorLabelRequirement{
- {
- Key: "failure-domain.beta.kubernetes.io/zone",
- Values: []string{"zone2"},
- },
- {
- Key: "kubernetes.io/hostname",
- Values: []string{"node2"},
- },
- },
- },
- },
- })
- s := StorageClassDescriber{f}
- out, err := s.Describe("", "foo", describe.DescriberSettings{ShowEvents: true})
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- if !strings.Contains(out, "foo") ||
- !strings.Contains(out, "my-provisioner") ||
- !strings.Contains(out, "param1") ||
- !strings.Contains(out, "param2") ||
- !strings.Contains(out, "value1") ||
- !strings.Contains(out, "value2") ||
- !strings.Contains(out, "Retain") ||
- !strings.Contains(out, "bindingmode") ||
- !strings.Contains(out, "failure-domain.beta.kubernetes.io/zone") ||
- !strings.Contains(out, "zone1") ||
- !strings.Contains(out, "kubernetes.io/hostname") ||
- !strings.Contains(out, "node1") ||
- !strings.Contains(out, "zone2") ||
- !strings.Contains(out, "node2") {
- t.Errorf("unexpected out: %s", out)
- }
- }
- func TestDescribePodDisruptionBudget(t *testing.T) {
- minAvailable := intstr.FromInt(22)
- f := fake.NewSimpleClientset(&policyv1beta1.PodDisruptionBudget{
- ObjectMeta: metav1.ObjectMeta{
- Namespace: "ns1",
- Name: "pdb1",
- CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
- },
- Spec: policyv1beta1.PodDisruptionBudgetSpec{
- MinAvailable: &minAvailable,
- },
- Status: policyv1beta1.PodDisruptionBudgetStatus{
- PodDisruptionsAllowed: 5,
- },
- })
- s := PodDisruptionBudgetDescriber{f}
- out, err := s.Describe("ns1", "pdb1", describe.DescriberSettings{ShowEvents: true})
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- if !strings.Contains(out, "pdb1") ||
- !strings.Contains(out, "ns1") ||
- !strings.Contains(out, "22") ||
- !strings.Contains(out, "5") {
- t.Errorf("unexpected out: %s", out)
- }
- }
- func TestDescribeHorizontalPodAutoscaler(t *testing.T) {
- minReplicasVal := int32(2)
- targetUtilizationVal := int32(80)
- currentUtilizationVal := int32(50)
- metricLabelSelector, err := metav1.ParseToLabelSelector("label=value")
- if err != nil {
- t.Errorf("unable to parse label selector: %v", err)
- }
- testsV2beta2 := []struct {
- name string
- hpa autoscalingv2beta2.HorizontalPodAutoscaler
- }{
- {
- "minReplicas unset",
- autoscalingv2beta2.HorizontalPodAutoscaler{
- Spec: autoscalingv2beta2.HorizontalPodAutoscalerSpec{
- ScaleTargetRef: autoscalingv2beta2.CrossVersionObjectReference{
- Name: "some-rc",
- Kind: "ReplicationController",
- },
- MaxReplicas: 10,
- },
- Status: autoscalingv2beta2.HorizontalPodAutoscalerStatus{
- CurrentReplicas: 4,
- DesiredReplicas: 5,
- },
- },
- },
- {
- "external source type, target average value (no current)",
- autoscalingv2beta2.HorizontalPodAutoscaler{
- Spec: autoscalingv2beta2.HorizontalPodAutoscalerSpec{
- ScaleTargetRef: autoscalingv2beta2.CrossVersionObjectReference{
- Name: "some-rc",
- Kind: "ReplicationController",
- },
- MinReplicas: &minReplicasVal,
- MaxReplicas: 10,
- Metrics: []autoscalingv2beta2.MetricSpec{
- {
- Type: autoscalingv2beta2.ExternalMetricSourceType,
- External: &autoscalingv2beta2.ExternalMetricSource{
- Metric: autoscalingv2beta2.MetricIdentifier{
- Name: "some-external-metric",
- Selector: metricLabelSelector,
- },
- Target: autoscalingv2beta2.MetricTarget{
- Type: autoscalingv2beta2.AverageValueMetricType,
- AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
- },
- },
- },
- },
- },
- Status: autoscalingv2beta2.HorizontalPodAutoscalerStatus{
- CurrentReplicas: 4,
- DesiredReplicas: 5,
- },
- },
- },
- {
- "external source type, target average value (with current)",
- autoscalingv2beta2.HorizontalPodAutoscaler{
- Spec: autoscalingv2beta2.HorizontalPodAutoscalerSpec{
- ScaleTargetRef: autoscalingv2beta2.CrossVersionObjectReference{
- Name: "some-rc",
- Kind: "ReplicationController",
- },
- MinReplicas: &minReplicasVal,
- MaxReplicas: 10,
- Metrics: []autoscalingv2beta2.MetricSpec{
- {
- Type: autoscalingv2beta2.ExternalMetricSourceType,
- External: &autoscalingv2beta2.ExternalMetricSource{
- Metric: autoscalingv2beta2.MetricIdentifier{
- Name: "some-external-metric",
- Selector: metricLabelSelector,
- },
- Target: autoscalingv2beta2.MetricTarget{
- Type: autoscalingv2beta2.AverageValueMetricType,
- AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
- },
- },
- },
- },
- },
- Status: autoscalingv2beta2.HorizontalPodAutoscalerStatus{
- CurrentReplicas: 4,
- DesiredReplicas: 5,
- CurrentMetrics: []autoscalingv2beta2.MetricStatus{
- {
- Type: autoscalingv2beta2.ExternalMetricSourceType,
- External: &autoscalingv2beta2.ExternalMetricStatus{
- Metric: autoscalingv2beta2.MetricIdentifier{
- Name: "some-external-metric",
- Selector: metricLabelSelector,
- },
- Current: autoscalingv2beta2.MetricValueStatus{
- AverageValue: resource.NewMilliQuantity(50, resource.DecimalSI),
- },
- },
- },
- },
- },
- },
- },
- {
- "external source type, target value (no current)",
- autoscalingv2beta2.HorizontalPodAutoscaler{
- Spec: autoscalingv2beta2.HorizontalPodAutoscalerSpec{
- ScaleTargetRef: autoscalingv2beta2.CrossVersionObjectReference{
- Name: "some-rc",
- Kind: "ReplicationController",
- },
- MinReplicas: &minReplicasVal,
- MaxReplicas: 10,
- Metrics: []autoscalingv2beta2.MetricSpec{
- {
- Type: autoscalingv2beta2.ExternalMetricSourceType,
- External: &autoscalingv2beta2.ExternalMetricSource{
- Metric: autoscalingv2beta2.MetricIdentifier{
- Name: "some-external-metric",
- Selector: metricLabelSelector,
- },
- Target: autoscalingv2beta2.MetricTarget{
- Type: autoscalingv2beta2.ValueMetricType,
- Value: resource.NewMilliQuantity(100, resource.DecimalSI),
- },
- },
- },
- },
- },
- Status: autoscalingv2beta2.HorizontalPodAutoscalerStatus{
- CurrentReplicas: 4,
- DesiredReplicas: 5,
- },
- },
- },
- {
- "external source type, target value (with current)",
- autoscalingv2beta2.HorizontalPodAutoscaler{
- Spec: autoscalingv2beta2.HorizontalPodAutoscalerSpec{
- ScaleTargetRef: autoscalingv2beta2.CrossVersionObjectReference{
- Name: "some-rc",
- Kind: "ReplicationController",
- },
- MinReplicas: &minReplicasVal,
- MaxReplicas: 10,
- Metrics: []autoscalingv2beta2.MetricSpec{
- {
- Type: autoscalingv2beta2.ExternalMetricSourceType,
- External: &autoscalingv2beta2.ExternalMetricSource{
- Metric: autoscalingv2beta2.MetricIdentifier{
- Name: "some-external-metric",
- Selector: metricLabelSelector,
- },
- Target: autoscalingv2beta2.MetricTarget{
- Type: autoscalingv2beta2.ValueMetricType,
- Value: resource.NewMilliQuantity(100, resource.DecimalSI),
- },
- },
- },
- },
- },
- Status: autoscalingv2beta2.HorizontalPodAutoscalerStatus{
- CurrentReplicas: 4,
- DesiredReplicas: 5,
- CurrentMetrics: []autoscalingv2beta2.MetricStatus{
- {
- Type: autoscalingv2beta2.ExternalMetricSourceType,
- External: &autoscalingv2beta2.ExternalMetricStatus{
- Metric: autoscalingv2beta2.MetricIdentifier{
- Name: "some-external-metric",
- Selector: metricLabelSelector,
- },
- Current: autoscalingv2beta2.MetricValueStatus{
- Value: resource.NewMilliQuantity(50, resource.DecimalSI),
- },
- },
- },
- },
- },
- },
- },
- {
- "pods source type (no current)",
- autoscalingv2beta2.HorizontalPodAutoscaler{
- Spec: autoscalingv2beta2.HorizontalPodAutoscalerSpec{
- ScaleTargetRef: autoscalingv2beta2.CrossVersionObjectReference{
- Name: "some-rc",
- Kind: "ReplicationController",
- },
- MinReplicas: &minReplicasVal,
- MaxReplicas: 10,
- Metrics: []autoscalingv2beta2.MetricSpec{
- {
- Type: autoscalingv2beta2.PodsMetricSourceType,
- Pods: &autoscalingv2beta2.PodsMetricSource{
- Metric: autoscalingv2beta2.MetricIdentifier{
- Name: "some-pods-metric",
- },
- Target: autoscalingv2beta2.MetricTarget{
- Type: autoscalingv2beta2.AverageValueMetricType,
- AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
- },
- },
- },
- },
- },
- Status: autoscalingv2beta2.HorizontalPodAutoscalerStatus{
- CurrentReplicas: 4,
- DesiredReplicas: 5,
- },
- },
- },
- {
- "pods source type (with current)",
- autoscalingv2beta2.HorizontalPodAutoscaler{
- Spec: autoscalingv2beta2.HorizontalPodAutoscalerSpec{
- ScaleTargetRef: autoscalingv2beta2.CrossVersionObjectReference{
- Name: "some-rc",
- Kind: "ReplicationController",
- },
- MinReplicas: &minReplicasVal,
- MaxReplicas: 10,
- Metrics: []autoscalingv2beta2.MetricSpec{
- {
- Type: autoscalingv2beta2.PodsMetricSourceType,
- Pods: &autoscalingv2beta2.PodsMetricSource{
- Metric: autoscalingv2beta2.MetricIdentifier{
- Name: "some-pods-metric",
- },
- Target: autoscalingv2beta2.MetricTarget{
- Type: autoscalingv2beta2.AverageValueMetricType,
- AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
- },
- },
- },
- },
- },
- Status: autoscalingv2beta2.HorizontalPodAutoscalerStatus{
- CurrentReplicas: 4,
- DesiredReplicas: 5,
- CurrentMetrics: []autoscalingv2beta2.MetricStatus{
- {
- Type: autoscalingv2beta2.PodsMetricSourceType,
- Pods: &autoscalingv2beta2.PodsMetricStatus{
- Metric: autoscalingv2beta2.MetricIdentifier{
- Name: "some-pods-metric",
- },
- Current: autoscalingv2beta2.MetricValueStatus{
- AverageValue: resource.NewMilliQuantity(50, resource.DecimalSI),
- },
- },
- },
- },
- },
- },
- },
- {
- "object source type target average value (no current)",
- autoscalingv2beta2.HorizontalPodAutoscaler{
- Spec: autoscalingv2beta2.HorizontalPodAutoscalerSpec{
- ScaleTargetRef: autoscalingv2beta2.CrossVersionObjectReference{
- Name: "some-rc",
- Kind: "ReplicationController",
- },
- MinReplicas: &minReplicasVal,
- MaxReplicas: 10,
- Metrics: []autoscalingv2beta2.MetricSpec{
- {
- Type: autoscalingv2beta2.ObjectMetricSourceType,
- Object: &autoscalingv2beta2.ObjectMetricSource{
- DescribedObject: autoscalingv2beta2.CrossVersionObjectReference{
- Name: "some-service",
- Kind: "Service",
- },
- Metric: autoscalingv2beta2.MetricIdentifier{
- Name: "some-service-metric",
- },
- Target: autoscalingv2beta2.MetricTarget{
- Type: autoscalingv2beta2.AverageValueMetricType,
- AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
- },
- },
- },
- },
- },
- Status: autoscalingv2beta2.HorizontalPodAutoscalerStatus{
- CurrentReplicas: 4,
- DesiredReplicas: 5,
- },
- },
- },
- {
- "object source type target average value (with current)",
- autoscalingv2beta2.HorizontalPodAutoscaler{
- Spec: autoscalingv2beta2.HorizontalPodAutoscalerSpec{
- ScaleTargetRef: autoscalingv2beta2.CrossVersionObjectReference{
- Name: "some-rc",
- Kind: "ReplicationController",
- },
- MinReplicas: &minReplicasVal,
- MaxReplicas: 10,
- Metrics: []autoscalingv2beta2.MetricSpec{
- {
- Type: autoscalingv2beta2.ObjectMetricSourceType,
- Object: &autoscalingv2beta2.ObjectMetricSource{
- DescribedObject: autoscalingv2beta2.CrossVersionObjectReference{
- Name: "some-service",
- Kind: "Service",
- },
- Metric: autoscalingv2beta2.MetricIdentifier{
- Name: "some-service-metric",
- },
- Target: autoscalingv2beta2.MetricTarget{
- Type: autoscalingv2beta2.AverageValueMetricType,
- AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
- },
- },
- },
- },
- },
- Status: autoscalingv2beta2.HorizontalPodAutoscalerStatus{
- CurrentReplicas: 4,
- DesiredReplicas: 5,
- CurrentMetrics: []autoscalingv2beta2.MetricStatus{
- {
- Type: autoscalingv2beta2.ObjectMetricSourceType,
- Object: &autoscalingv2beta2.ObjectMetricStatus{
- DescribedObject: autoscalingv2beta2.CrossVersionObjectReference{
- Name: "some-service",
- Kind: "Service",
- },
- Metric: autoscalingv2beta2.MetricIdentifier{
- Name: "some-service-metric",
- },
- Current: autoscalingv2beta2.MetricValueStatus{
- AverageValue: resource.NewMilliQuantity(50, resource.DecimalSI),
- },
- },
- },
- },
- },
- },
- },
- {
- "object source type target value (no current)",
- autoscalingv2beta2.HorizontalPodAutoscaler{
- Spec: autoscalingv2beta2.HorizontalPodAutoscalerSpec{
- ScaleTargetRef: autoscalingv2beta2.CrossVersionObjectReference{
- Name: "some-rc",
- Kind: "ReplicationController",
- },
- MinReplicas: &minReplicasVal,
- MaxReplicas: 10,
- Metrics: []autoscalingv2beta2.MetricSpec{
- {
- Type: autoscalingv2beta2.ObjectMetricSourceType,
- Object: &autoscalingv2beta2.ObjectMetricSource{
- DescribedObject: autoscalingv2beta2.CrossVersionObjectReference{
- Name: "some-service",
- Kind: "Service",
- },
- Metric: autoscalingv2beta2.MetricIdentifier{
- Name: "some-service-metric",
- },
- Target: autoscalingv2beta2.MetricTarget{
- Type: autoscalingv2beta2.ValueMetricType,
- Value: resource.NewMilliQuantity(100, resource.DecimalSI),
- },
- },
- },
- },
- },
- Status: autoscalingv2beta2.HorizontalPodAutoscalerStatus{
- CurrentReplicas: 4,
- DesiredReplicas: 5,
- },
- },
- },
- {
- "object source type target value (with current)",
- autoscalingv2beta2.HorizontalPodAutoscaler{
- Spec: autoscalingv2beta2.HorizontalPodAutoscalerSpec{
- ScaleTargetRef: autoscalingv2beta2.CrossVersionObjectReference{
- Name: "some-rc",
- Kind: "ReplicationController",
- },
- MinReplicas: &minReplicasVal,
- MaxReplicas: 10,
- Metrics: []autoscalingv2beta2.MetricSpec{
- {
- Type: autoscalingv2beta2.ObjectMetricSourceType,
- Object: &autoscalingv2beta2.ObjectMetricSource{
- DescribedObject: autoscalingv2beta2.CrossVersionObjectReference{
- Name: "some-service",
- Kind: "Service",
- },
- Metric: autoscalingv2beta2.MetricIdentifier{
- Name: "some-service-metric",
- },
- Target: autoscalingv2beta2.MetricTarget{
- Type: autoscalingv2beta2.ValueMetricType,
- Value: resource.NewMilliQuantity(100, resource.DecimalSI),
- },
- },
- },
- },
- },
- Status: autoscalingv2beta2.HorizontalPodAutoscalerStatus{
- CurrentReplicas: 4,
- DesiredReplicas: 5,
- CurrentMetrics: []autoscalingv2beta2.MetricStatus{
- {
- Type: autoscalingv2beta2.ObjectMetricSourceType,
- Object: &autoscalingv2beta2.ObjectMetricStatus{
- DescribedObject: autoscalingv2beta2.CrossVersionObjectReference{
- Name: "some-service",
- Kind: "Service",
- },
- Metric: autoscalingv2beta2.MetricIdentifier{
- Name: "some-service-metric",
- },
- Current: autoscalingv2beta2.MetricValueStatus{
- Value: resource.NewMilliQuantity(50, resource.DecimalSI),
- },
- },
- },
- },
- },
- },
- },
- {
- "resource source type, target average value (no current)",
- autoscalingv2beta2.HorizontalPodAutoscaler{
- Spec: autoscalingv2beta2.HorizontalPodAutoscalerSpec{
- ScaleTargetRef: autoscalingv2beta2.CrossVersionObjectReference{
- Name: "some-rc",
- Kind: "ReplicationController",
- },
- MinReplicas: &minReplicasVal,
- MaxReplicas: 10,
- Metrics: []autoscalingv2beta2.MetricSpec{
- {
- Type: autoscalingv2beta2.ResourceMetricSourceType,
- Resource: &autoscalingv2beta2.ResourceMetricSource{
- Name: corev1.ResourceCPU,
- Target: autoscalingv2beta2.MetricTarget{
- Type: autoscalingv2beta2.AverageValueMetricType,
- AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
- },
- },
- },
- },
- },
- Status: autoscalingv2beta2.HorizontalPodAutoscalerStatus{
- CurrentReplicas: 4,
- DesiredReplicas: 5,
- },
- },
- },
- {
- "resource source type, target average value (with current)",
- autoscalingv2beta2.HorizontalPodAutoscaler{
- Spec: autoscalingv2beta2.HorizontalPodAutoscalerSpec{
- ScaleTargetRef: autoscalingv2beta2.CrossVersionObjectReference{
- Name: "some-rc",
- Kind: "ReplicationController",
- },
- MinReplicas: &minReplicasVal,
- MaxReplicas: 10,
- Metrics: []autoscalingv2beta2.MetricSpec{
- {
- Type: autoscalingv2beta2.ResourceMetricSourceType,
- Resource: &autoscalingv2beta2.ResourceMetricSource{
- Name: corev1.ResourceCPU,
- Target: autoscalingv2beta2.MetricTarget{
- Type: autoscalingv2beta2.AverageValueMetricType,
- AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
- },
- },
- },
- },
- },
- Status: autoscalingv2beta2.HorizontalPodAutoscalerStatus{
- CurrentReplicas: 4,
- DesiredReplicas: 5,
- CurrentMetrics: []autoscalingv2beta2.MetricStatus{
- {
- Type: autoscalingv2beta2.ResourceMetricSourceType,
- Resource: &autoscalingv2beta2.ResourceMetricStatus{
- Name: corev1.ResourceCPU,
- Current: autoscalingv2beta2.MetricValueStatus{
- AverageValue: resource.NewMilliQuantity(50, resource.DecimalSI),
- },
- },
- },
- },
- },
- },
- },
- {
- "resource source type, target utilization (no current)",
- autoscalingv2beta2.HorizontalPodAutoscaler{
- Spec: autoscalingv2beta2.HorizontalPodAutoscalerSpec{
- ScaleTargetRef: autoscalingv2beta2.CrossVersionObjectReference{
- Name: "some-rc",
- Kind: "ReplicationController",
- },
- MinReplicas: &minReplicasVal,
- MaxReplicas: 10,
- Metrics: []autoscalingv2beta2.MetricSpec{
- {
- Type: autoscalingv2beta2.ResourceMetricSourceType,
- Resource: &autoscalingv2beta2.ResourceMetricSource{
- Name: corev1.ResourceCPU,
- Target: autoscalingv2beta2.MetricTarget{
- Type: autoscalingv2beta2.UtilizationMetricType,
- AverageUtilization: &targetUtilizationVal,
- },
- },
- },
- },
- },
- Status: autoscalingv2beta2.HorizontalPodAutoscalerStatus{
- CurrentReplicas: 4,
- DesiredReplicas: 5,
- },
- },
- },
- {
- "resource source type, target utilization (with current)",
- autoscalingv2beta2.HorizontalPodAutoscaler{
- Spec: autoscalingv2beta2.HorizontalPodAutoscalerSpec{
- ScaleTargetRef: autoscalingv2beta2.CrossVersionObjectReference{
- Name: "some-rc",
- Kind: "ReplicationController",
- },
- MinReplicas: &minReplicasVal,
- MaxReplicas: 10,
- Metrics: []autoscalingv2beta2.MetricSpec{
- {
- Type: autoscalingv2beta2.ResourceMetricSourceType,
- Resource: &autoscalingv2beta2.ResourceMetricSource{
- Name: corev1.ResourceCPU,
- Target: autoscalingv2beta2.MetricTarget{
- Type: autoscalingv2beta2.UtilizationMetricType,
- AverageUtilization: &targetUtilizationVal,
- },
- },
- },
- },
- },
- Status: autoscalingv2beta2.HorizontalPodAutoscalerStatus{
- CurrentReplicas: 4,
- DesiredReplicas: 5,
- CurrentMetrics: []autoscalingv2beta2.MetricStatus{
- {
- Type: autoscalingv2beta2.ResourceMetricSourceType,
- Resource: &autoscalingv2beta2.ResourceMetricStatus{
- Name: corev1.ResourceCPU,
- Current: autoscalingv2beta2.MetricValueStatus{
- AverageUtilization: ¤tUtilizationVal,
- AverageValue: resource.NewMilliQuantity(40, resource.DecimalSI),
- },
- },
- },
- },
- },
- },
- },
- {
- "multiple metrics",
- autoscalingv2beta2.HorizontalPodAutoscaler{
- Spec: autoscalingv2beta2.HorizontalPodAutoscalerSpec{
- ScaleTargetRef: autoscalingv2beta2.CrossVersionObjectReference{
- Name: "some-rc",
- Kind: "ReplicationController",
- },
- MinReplicas: &minReplicasVal,
- MaxReplicas: 10,
- Metrics: []autoscalingv2beta2.MetricSpec{
- {
- Type: autoscalingv2beta2.PodsMetricSourceType,
- Pods: &autoscalingv2beta2.PodsMetricSource{
- Metric: autoscalingv2beta2.MetricIdentifier{
- Name: "some-pods-metric",
- },
- Target: autoscalingv2beta2.MetricTarget{
- Type: autoscalingv2beta2.AverageValueMetricType,
- AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
- },
- },
- },
- {
- Type: autoscalingv2beta2.ResourceMetricSourceType,
- Resource: &autoscalingv2beta2.ResourceMetricSource{
- Name: corev1.ResourceCPU,
- Target: autoscalingv2beta2.MetricTarget{
- Type: autoscalingv2beta2.UtilizationMetricType,
- AverageUtilization: &targetUtilizationVal,
- },
- },
- },
- {
- Type: autoscalingv2beta2.PodsMetricSourceType,
- Pods: &autoscalingv2beta2.PodsMetricSource{
- Metric: autoscalingv2beta2.MetricIdentifier{
- Name: "other-pods-metric",
- },
- Target: autoscalingv2beta2.MetricTarget{
- Type: autoscalingv2beta2.AverageValueMetricType,
- AverageValue: resource.NewMilliQuantity(400, resource.DecimalSI),
- },
- },
- },
- },
- },
- Status: autoscalingv2beta2.HorizontalPodAutoscalerStatus{
- CurrentReplicas: 4,
- DesiredReplicas: 5,
- CurrentMetrics: []autoscalingv2beta2.MetricStatus{
- {
- Type: autoscalingv2beta2.PodsMetricSourceType,
- Pods: &autoscalingv2beta2.PodsMetricStatus{
- Metric: autoscalingv2beta2.MetricIdentifier{
- Name: "some-pods-metric",
- },
- Current: autoscalingv2beta2.MetricValueStatus{
- AverageValue: resource.NewMilliQuantity(50, resource.DecimalSI),
- },
- },
- },
- {
- Type: autoscalingv2beta2.ResourceMetricSourceType,
- Resource: &autoscalingv2beta2.ResourceMetricStatus{
- Name: corev1.ResourceCPU,
- Current: autoscalingv2beta2.MetricValueStatus{
- AverageUtilization: ¤tUtilizationVal,
- AverageValue: resource.NewMilliQuantity(40, resource.DecimalSI),
- },
- },
- },
- },
- },
- },
- },
- }
- for _, test := range testsV2beta2 {
- t.Run(test.name, func(t *testing.T) {
- test.hpa.ObjectMeta = metav1.ObjectMeta{
- Name: "bar",
- Namespace: "foo",
- }
- fake := fake.NewSimpleClientset(&test.hpa)
- desc := HorizontalPodAutoscalerDescriber{fake}
- str, err := desc.Describe("foo", "bar", describe.DescriberSettings{ShowEvents: true})
- if err != nil {
- t.Errorf("Unexpected error for test %s: %v", test.name, err)
- }
- if str == "" {
- t.Errorf("Unexpected empty string for test %s. Expected HPA Describer output", test.name)
- }
- t.Logf("Description for %q:\n%s", test.name, str)
- })
- }
- testsV1 := []struct {
- name string
- hpa autoscalingv1.HorizontalPodAutoscaler
- }{
- {
- "minReplicas unset",
- autoscalingv1.HorizontalPodAutoscaler{
- Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
- ScaleTargetRef: autoscalingv1.CrossVersionObjectReference{
- Name: "some-rc",
- Kind: "ReplicationController",
- },
- MaxReplicas: 10,
- },
- Status: autoscalingv1.HorizontalPodAutoscalerStatus{
- CurrentReplicas: 4,
- DesiredReplicas: 5,
- },
- },
- },
- {
- "minReplicas set",
- autoscalingv1.HorizontalPodAutoscaler{
- Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
- ScaleTargetRef: autoscalingv1.CrossVersionObjectReference{
- Name: "some-rc",
- Kind: "ReplicationController",
- },
- MinReplicas: &minReplicasVal,
- MaxReplicas: 10,
- },
- Status: autoscalingv1.HorizontalPodAutoscalerStatus{
- CurrentReplicas: 4,
- DesiredReplicas: 5,
- },
- },
- },
- {
- "with target no current",
- autoscalingv1.HorizontalPodAutoscaler{
- Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
- ScaleTargetRef: autoscalingv1.CrossVersionObjectReference{
- Name: "some-rc",
- Kind: "ReplicationController",
- },
- MinReplicas: &minReplicasVal,
- MaxReplicas: 10,
- TargetCPUUtilizationPercentage: &targetUtilizationVal,
- },
- Status: autoscalingv1.HorizontalPodAutoscalerStatus{
- CurrentReplicas: 4,
- DesiredReplicas: 5,
- },
- },
- },
- {
- "with target and current",
- autoscalingv1.HorizontalPodAutoscaler{
- Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
- ScaleTargetRef: autoscalingv1.CrossVersionObjectReference{
- Name: "some-rc",
- Kind: "ReplicationController",
- },
- MinReplicas: &minReplicasVal,
- MaxReplicas: 10,
- TargetCPUUtilizationPercentage: &targetUtilizationVal,
- },
- Status: autoscalingv1.HorizontalPodAutoscalerStatus{
- CurrentReplicas: 4,
- DesiredReplicas: 5,
- CurrentCPUUtilizationPercentage: ¤tUtilizationVal,
- },
- },
- },
- }
- for _, test := range testsV1 {
- t.Run(test.name, func(t *testing.T) {
- test.hpa.ObjectMeta = metav1.ObjectMeta{
- Name: "bar",
- Namespace: "foo",
- }
- fake := fake.NewSimpleClientset(&test.hpa)
- desc := HorizontalPodAutoscalerDescriber{fake}
- str, err := desc.Describe("foo", "bar", describe.DescriberSettings{ShowEvents: true})
- if err != nil {
- t.Errorf("Unexpected error for test %s: %v", test.name, err)
- }
- if str == "" {
- t.Errorf("Unexpected empty string for test %s. Expected HPA Describer output", test.name)
- }
- t.Logf("Description for %q:\n%s", test.name, str)
- })
- }
- }
- func TestDescribeEvents(t *testing.T) {
- events := &corev1.EventList{
- Items: []corev1.Event{
- {
- ObjectMeta: metav1.ObjectMeta{
- Namespace: "foo",
- },
- Source: corev1.EventSource{Component: "kubelet"},
- Message: "Item 1",
- FirstTimestamp: metav1.NewTime(time.Date(2014, time.January, 15, 0, 0, 0, 0, time.UTC)),
- LastTimestamp: metav1.NewTime(time.Date(2014, time.January, 15, 0, 0, 0, 0, time.UTC)),
- Count: 1,
- Type: corev1.EventTypeNormal,
- },
- },
- }
- m := map[string]describe.Describer{
- "DaemonSetDescriber": &DaemonSetDescriber{
- fake.NewSimpleClientset(&appsv1.DaemonSet{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- Namespace: "foo",
- },
- }, events),
- },
- "DeploymentDescriber": &DeploymentDescriber{
- fake.NewSimpleClientset(&appsv1.Deployment{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- Namespace: "foo",
- },
- Spec: appsv1.DeploymentSpec{
- Replicas: utilpointer.Int32Ptr(1),
- Selector: &metav1.LabelSelector{},
- },
- }, events),
- },
- "EndpointsDescriber": &EndpointsDescriber{
- fake.NewSimpleClientset(&corev1.Endpoints{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- Namespace: "foo",
- },
- }, events),
- },
- // TODO(jchaloup): add tests for:
- // - IngressDescriber
- // - JobDescriber
- "NodeDescriber": &NodeDescriber{
- fake.NewSimpleClientset(&corev1.Node{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- SelfLink: "url/url/url/url",
- },
- }, events),
- },
- "PersistentVolumeDescriber": &PersistentVolumeDescriber{
- fake.NewSimpleClientset(&corev1.PersistentVolume{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- SelfLink: "url/url/url/url",
- },
- }, events),
- },
- "PodDescriber": &PodDescriber{
- fake.NewSimpleClientset(&corev1.Pod{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- Namespace: "foo",
- SelfLink: "url/url/url/url",
- },
- }, events),
- },
- "ReplicaSetDescriber": &ReplicaSetDescriber{
- fake.NewSimpleClientset(&appsv1.ReplicaSet{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- Namespace: "foo",
- },
- Spec: appsv1.ReplicaSetSpec{
- Replicas: utilpointer.Int32Ptr(1),
- },
- }, events),
- },
- "ReplicationControllerDescriber": &ReplicationControllerDescriber{
- fake.NewSimpleClientset(&corev1.ReplicationController{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- Namespace: "foo",
- },
- Spec: corev1.ReplicationControllerSpec{
- Replicas: utilpointer.Int32Ptr(1),
- },
- }, events),
- },
- "Service": &ServiceDescriber{
- fake.NewSimpleClientset(&corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- Namespace: "foo",
- },
- }, events),
- },
- "StorageClass": &StorageClassDescriber{
- fake.NewSimpleClientset(&storagev1.StorageClass{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- },
- }, events),
- },
- "HorizontalPodAutoscaler": &HorizontalPodAutoscalerDescriber{
- fake.NewSimpleClientset(&autoscalingv2beta2.HorizontalPodAutoscaler{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- Namespace: "foo",
- },
- }, events),
- },
- "ConfigMap": &ConfigMapDescriber{
- fake.NewSimpleClientset(&corev1.ConfigMap{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- Namespace: "foo",
- },
- }, events),
- },
- }
- for name, d := range m {
- t.Run(name, func(t *testing.T) {
- out, err := d.Describe("foo", "bar", describe.DescriberSettings{ShowEvents: true})
- if err != nil {
- t.Errorf("unexpected error for %q: %v", name, err)
- }
- if !strings.Contains(out, "bar") {
- t.Errorf("unexpected out for %q: %s", name, out)
- }
- if !strings.Contains(out, "Events:") {
- t.Errorf("events not found for %q when ShowEvents=true: %s", name, out)
- }
- out, err = d.Describe("foo", "bar", describe.DescriberSettings{ShowEvents: false})
- if err != nil {
- t.Errorf("unexpected error for %q: %s", name, err)
- }
- if !strings.Contains(out, "bar") {
- t.Errorf("unexpected out for %q: %s", name, out)
- }
- if strings.Contains(out, "Events:") {
- t.Errorf("events found for %q when ShowEvents=false: %s", name, out)
- }
- })
- }
- }
- func TestPrintLabelsMultiline(t *testing.T) {
- key := "MaxLenAnnotation"
- value := strings.Repeat("a", maxAnnotationLen-len(key)-2)
- testCases := []struct {
- annotations map[string]string
- expectPrint string
- }{
- {
- annotations: map[string]string{"col1": "asd", "COL2": "zxc"},
- expectPrint: "Annotations:\tCOL2: zxc\n\tcol1: asd\n",
- },
- {
- annotations: map[string]string{"MaxLenAnnotation": value},
- expectPrint: fmt.Sprintf("Annotations:\t%s: %s\n", key, value),
- },
- {
- annotations: map[string]string{"MaxLenAnnotation": value + "1"},
- expectPrint: fmt.Sprintf("Annotations:\t%s:\n\t %s\n", key, value+"1"),
- },
- {
- annotations: map[string]string{"MaxLenAnnotation": value + value},
- expectPrint: fmt.Sprintf("Annotations:\t%s:\n\t %s\n", key, strings.Repeat("a", maxAnnotationLen-2)+"..."),
- },
- {
- annotations: map[string]string{"key": "value\nwith\nnewlines\n"},
- expectPrint: "Annotations:\tkey:\n\t value\n\t with\n\t newlines\n",
- },
- {
- annotations: map[string]string{},
- expectPrint: "Annotations:\t<none>\n",
- },
- }
- for i, testCase := range testCases {
- t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
- out := new(bytes.Buffer)
- writer := NewPrefixWriter(out)
- printAnnotationsMultiline(writer, "Annotations", testCase.annotations)
- output := out.String()
- if output != testCase.expectPrint {
- t.Errorf("Test case %d: expected to match:\n%q\nin output:\n%q", i, testCase.expectPrint, output)
- }
- })
- }
- }
- func TestDescribeUnstructuredContent(t *testing.T) {
- testCases := []struct {
- expected string
- unexpected string
- }{
- {
- expected: `API Version: v1
- Dummy - Dummy: present
- dummy-dummy@dummy: present
- dummy/dummy: present
- dummy2: present
- Dummy Dummy: present
- Items:
- Item Bool: true
- Item Int: 42
- Kind: Test
- Metadata:
- Creation Timestamp: 2017-04-01T00:00:00Z
- Name: MyName
- Namespace: MyNamespace
- Resource Version: 123
- UID: 00000000-0000-0000-0000-000000000001
- Status: ok
- URL: http://localhost
- `,
- },
- {
- unexpected: "\nDummy 1:\tpresent\n",
- },
- {
- unexpected: "Dummy 1",
- },
- {
- unexpected: "Dummy 3",
- },
- {
- unexpected: "Dummy3",
- },
- {
- unexpected: "dummy3",
- },
- {
- unexpected: "dummy 3",
- },
- }
- out := new(bytes.Buffer)
- w := NewPrefixWriter(out)
- obj := &unstructured.Unstructured{
- Object: map[string]interface{}{
- "apiVersion": "v1",
- "kind": "Test",
- "dummyDummy": "present",
- "dummy/dummy": "present",
- "dummy-dummy@dummy": "present",
- "dummy-dummy": "present",
- "dummy1": "present",
- "dummy2": "present",
- "metadata": map[string]interface{}{
- "name": "MyName",
- "namespace": "MyNamespace",
- "creationTimestamp": "2017-04-01T00:00:00Z",
- "resourceVersion": 123,
- "uid": "00000000-0000-0000-0000-000000000001",
- "dummy3": "present",
- },
- "items": []interface{}{
- map[string]interface{}{
- "itemBool": true,
- "itemInt": 42,
- },
- },
- "url": "http://localhost",
- "status": "ok",
- },
- }
- printUnstructuredContent(w, LEVEL_0, obj.UnstructuredContent(), "", ".dummy1", ".metadata.dummy3")
- output := out.String()
- for _, test := range testCases {
- if len(test.expected) > 0 {
- if !strings.Contains(output, test.expected) {
- t.Errorf("Expected to find %q in: %q", test.expected, output)
- }
- }
- if len(test.unexpected) > 0 {
- if strings.Contains(output, test.unexpected) {
- t.Errorf("Didn't expect to find %q in: %q", test.unexpected, output)
- }
- }
- }
- }
- func TestDescribePodSecurityPolicy(t *testing.T) {
- expected := []string{
- "Name:\\s*mypsp",
- "Allow Privileged:\\s*false",
- "Default Add Capabilities:\\s*<none>",
- "Required Drop Capabilities:\\s*<none>",
- "Allowed Capabilities:\\s*<none>",
- "Allowed Volume Types:\\s*<none>",
- "Allowed Unsafe Sysctls:\\s*kernel\\.\\*,net\\.ipv4.ip_local_port_range",
- "Forbidden Sysctls:\\s*net\\.ipv4\\.ip_default_ttl",
- "Allow Host Network:\\s*false",
- "Allow Host Ports:\\s*<none>",
- "Allow Host PID:\\s*false",
- "Allow Host IPC:\\s*false",
- "Read Only Root Filesystem:\\s*false",
- "SELinux Context Strategy: RunAsAny",
- "User:\\s*<none>",
- "Role:\\s*<none>",
- "Type:\\s*<none>",
- "Level:\\s*<none>",
- "Run As User Strategy: RunAsAny",
- "FSGroup Strategy: RunAsAny",
- "Supplemental Groups Strategy: RunAsAny",
- }
- fake := fake.NewSimpleClientset(&policyv1beta1.PodSecurityPolicy{
- ObjectMeta: metav1.ObjectMeta{
- Name: "mypsp",
- },
- Spec: policyv1beta1.PodSecurityPolicySpec{
- AllowedUnsafeSysctls: []string{"kernel.*", "net.ipv4.ip_local_port_range"},
- ForbiddenSysctls: []string{"net.ipv4.ip_default_ttl"},
- SELinux: policyv1beta1.SELinuxStrategyOptions{
- Rule: policyv1beta1.SELinuxStrategyRunAsAny,
- },
- RunAsUser: policyv1beta1.RunAsUserStrategyOptions{
- Rule: policyv1beta1.RunAsUserStrategyRunAsAny,
- },
- FSGroup: policyv1beta1.FSGroupStrategyOptions{
- Rule: policyv1beta1.FSGroupStrategyRunAsAny,
- },
- SupplementalGroups: policyv1beta1.SupplementalGroupsStrategyOptions{
- Rule: policyv1beta1.SupplementalGroupsStrategyRunAsAny,
- },
- },
- })
- c := &describeClient{T: t, Namespace: "", Interface: fake}
- d := PodSecurityPolicyDescriber{c}
- out, err := d.Describe("", "mypsp", describe.DescriberSettings{})
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- for _, item := range expected {
- if matched, _ := regexp.MatchString(item, out); !matched {
- t.Errorf("Expected to find %q in: %q", item, out)
- }
- }
- }
- func TestDescribeResourceQuota(t *testing.T) {
- fake := fake.NewSimpleClientset(&corev1.ResourceQuota{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- Namespace: "foo",
- },
- Status: corev1.ResourceQuotaStatus{
- Hard: corev1.ResourceList{
- corev1.ResourceName(corev1.ResourceCPU): resource.MustParse("1"),
- corev1.ResourceName(corev1.ResourceLimitsCPU): resource.MustParse("2"),
- corev1.ResourceName(corev1.ResourceLimitsMemory): resource.MustParse("2G"),
- corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("1G"),
- corev1.ResourceName(corev1.ResourceRequestsCPU): resource.MustParse("1"),
- corev1.ResourceName(corev1.ResourceRequestsMemory): resource.MustParse("1G"),
- },
- Used: corev1.ResourceList{
- corev1.ResourceName(corev1.ResourceCPU): resource.MustParse("0"),
- corev1.ResourceName(corev1.ResourceLimitsCPU): resource.MustParse("0"),
- corev1.ResourceName(corev1.ResourceLimitsMemory): resource.MustParse("0G"),
- corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("0G"),
- corev1.ResourceName(corev1.ResourceRequestsCPU): resource.MustParse("0"),
- corev1.ResourceName(corev1.ResourceRequestsMemory): resource.MustParse("0G"),
- },
- },
- })
- c := &describeClient{T: t, Namespace: "foo", Interface: fake}
- d := ResourceQuotaDescriber{c}
- out, err := d.Describe("foo", "bar", describe.DescriberSettings{ShowEvents: true})
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- expectedOut := []string{"bar", "foo", "limits.cpu", "2", "limits.memory", "2G", "requests.cpu", "1", "requests.memory", "1G"}
- for _, expected := range expectedOut {
- if !strings.Contains(out, expected) {
- t.Errorf("expected to find %q in output: %q", expected, out)
- }
- }
- }
- func TestDescribeNetworkPolicies(t *testing.T) {
- expectedTime, err := time.Parse("2006-01-02 15:04:05 Z0700 MST", "2017-06-04 21:45:56 -0700 PDT")
- if err != nil {
- t.Errorf("unable to parse time %q error: %s", "2017-06-04 21:45:56 -0700 PDT", err)
- }
- expectedOut := `Name: network-policy-1
- Namespace: default
- Created on: 2017-06-04 21:45:56 -0700 PDT
- Labels: <none>
- Annotations: <none>
- Spec:
- PodSelector: foo in (bar1,bar2),foo2 notin (bar1,bar2),id1=app1,id2=app2
- Allowing ingress traffic:
- To Port: 80/TCP
- To Port: 82/TCP
- From:
- NamespaceSelector: id=ns1,id2=ns2
- PodSelector: id=pod1,id2=pod2
- From:
- PodSelector: id=app2,id2=app3
- From:
- NamespaceSelector: id=app2,id2=app3
- From:
- NamespaceSelector: foo in (bar1,bar2),id=app2,id2=app3
- From:
- IPBlock:
- CIDR: 192.168.0.0/16
- Except: 192.168.3.0/24, 192.168.4.0/24
- ----------
- To Port: <any> (traffic allowed to all ports)
- From: <any> (traffic not restricted by source)
- Allowing egress traffic:
- To Port: 80/TCP
- To Port: 82/TCP
- To:
- NamespaceSelector: id=ns1,id2=ns2
- PodSelector: id=pod1,id2=pod2
- To:
- PodSelector: id=app2,id2=app3
- To:
- NamespaceSelector: id=app2,id2=app3
- To:
- NamespaceSelector: foo in (bar1,bar2),id=app2,id2=app3
- To:
- IPBlock:
- CIDR: 192.168.0.0/16
- Except: 192.168.3.0/24, 192.168.4.0/24
- ----------
- To Port: <any> (traffic allowed to all ports)
- To: <any> (traffic not restricted by source)
- Policy Types: Ingress, Egress
- `
- port80 := intstr.FromInt(80)
- port82 := intstr.FromInt(82)
- protoTCP := corev1.ProtocolTCP
- versionedFake := fake.NewSimpleClientset(&networkingv1.NetworkPolicy{
- ObjectMeta: metav1.ObjectMeta{
- Name: "network-policy-1",
- Namespace: "default",
- CreationTimestamp: metav1.NewTime(expectedTime),
- },
- Spec: networkingv1.NetworkPolicySpec{
- PodSelector: metav1.LabelSelector{
- MatchLabels: map[string]string{
- "id1": "app1",
- "id2": "app2",
- },
- MatchExpressions: []metav1.LabelSelectorRequirement{
- {Key: "foo", Operator: "In", Values: []string{"bar1", "bar2"}},
- {Key: "foo2", Operator: "NotIn", Values: []string{"bar1", "bar2"}},
- },
- },
- Ingress: []networkingv1.NetworkPolicyIngressRule{
- {
- Ports: []networkingv1.NetworkPolicyPort{
- {Port: &port80},
- {Port: &port82, Protocol: &protoTCP},
- },
- From: []networkingv1.NetworkPolicyPeer{
- {
- PodSelector: &metav1.LabelSelector{
- MatchLabels: map[string]string{
- "id": "pod1",
- "id2": "pod2",
- },
- },
- NamespaceSelector: &metav1.LabelSelector{
- MatchLabels: map[string]string{
- "id": "ns1",
- "id2": "ns2",
- },
- },
- },
- {
- PodSelector: &metav1.LabelSelector{
- MatchLabels: map[string]string{
- "id": "app2",
- "id2": "app3",
- },
- },
- },
- {
- NamespaceSelector: &metav1.LabelSelector{
- MatchLabels: map[string]string{
- "id": "app2",
- "id2": "app3",
- },
- },
- },
- {
- NamespaceSelector: &metav1.LabelSelector{
- MatchLabels: map[string]string{
- "id": "app2",
- "id2": "app3",
- },
- MatchExpressions: []metav1.LabelSelectorRequirement{
- {Key: "foo", Operator: "In", Values: []string{"bar1", "bar2"}},
- },
- },
- },
- {
- IPBlock: &networkingv1.IPBlock{
- CIDR: "192.168.0.0/16",
- Except: []string{"192.168.3.0/24", "192.168.4.0/24"},
- },
- },
- },
- },
- {},
- },
- Egress: []networkingv1.NetworkPolicyEgressRule{
- {
- Ports: []networkingv1.NetworkPolicyPort{
- {Port: &port80},
- {Port: &port82, Protocol: &protoTCP},
- },
- To: []networkingv1.NetworkPolicyPeer{
- {
- PodSelector: &metav1.LabelSelector{
- MatchLabels: map[string]string{
- "id": "pod1",
- "id2": "pod2",
- },
- },
- NamespaceSelector: &metav1.LabelSelector{
- MatchLabels: map[string]string{
- "id": "ns1",
- "id2": "ns2",
- },
- },
- },
- {
- PodSelector: &metav1.LabelSelector{
- MatchLabels: map[string]string{
- "id": "app2",
- "id2": "app3",
- },
- },
- },
- {
- NamespaceSelector: &metav1.LabelSelector{
- MatchLabels: map[string]string{
- "id": "app2",
- "id2": "app3",
- },
- },
- },
- {
- NamespaceSelector: &metav1.LabelSelector{
- MatchLabels: map[string]string{
- "id": "app2",
- "id2": "app3",
- },
- MatchExpressions: []metav1.LabelSelectorRequirement{
- {Key: "foo", Operator: "In", Values: []string{"bar1", "bar2"}},
- },
- },
- },
- {
- IPBlock: &networkingv1.IPBlock{
- CIDR: "192.168.0.0/16",
- Except: []string{"192.168.3.0/24", "192.168.4.0/24"},
- },
- },
- },
- },
- {},
- },
- PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress, networkingv1.PolicyTypeEgress},
- },
- })
- d := NetworkPolicyDescriber{versionedFake}
- out, err := d.Describe("", "network-policy-1", describe.DescriberSettings{})
- if err != nil {
- t.Errorf("unexpected error: %s", err)
- }
- if out != expectedOut {
- t.Errorf("want:\n%s\ngot:\n%s", expectedOut, out)
- }
- }
- func TestDescribeServiceAccount(t *testing.T) {
- fake := fake.NewSimpleClientset(&corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- Namespace: "foo",
- },
- Secrets: []corev1.ObjectReference{
- {
- Name: "test-objectref",
- },
- },
- ImagePullSecrets: []corev1.LocalObjectReference{
- {
- Name: "test-local-ref",
- },
- },
- })
- c := &describeClient{T: t, Namespace: "foo", Interface: fake}
- d := ServiceAccountDescriber{c}
- out, err := d.Describe("foo", "bar", describe.DescriberSettings{ShowEvents: true})
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- expectedOut := `Name: bar
- Namespace: foo
- Labels: <none>
- Annotations: <none>
- Image pull secrets: test-local-ref (not found)
- Mountable secrets: test-objectref (not found)
- Tokens: <none>
- Events: <none>` + "\n"
- if out != expectedOut {
- t.Errorf("expected : %q\n but got output:\n %q", expectedOut, out)
- }
- }
- func TestDescribeNode(t *testing.T) {
- fake := fake.NewSimpleClientset(&corev1.Node{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- Namespace: "foo",
- },
- Spec: corev1.NodeSpec{
- Unschedulable: true,
- },
- })
- c := &describeClient{T: t, Namespace: "foo", Interface: fake}
- d := NodeDescriber{c}
- out, err := d.Describe("foo", "bar", describe.DescriberSettings{ShowEvents: true})
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- expectedOut := []string{"Unschedulable", "true"}
- for _, expected := range expectedOut {
- if !strings.Contains(out, expected) {
- t.Errorf("expected to find %q in output: %q", expected, out)
- }
- }
- }
- func TestDescribeStatefulSet(t *testing.T) {
- var partition int32 = 2
- var replicas int32 = 1
- fake := fake.NewSimpleClientset(&appsv1.StatefulSet{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- Namespace: "foo",
- },
- Spec: appsv1.StatefulSetSpec{
- Replicas: &replicas,
- Selector: &metav1.LabelSelector{},
- Template: corev1.PodTemplateSpec{
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{
- {Image: "mytest-image:latest"},
- },
- },
- },
- UpdateStrategy: appsv1.StatefulSetUpdateStrategy{
- Type: appsv1.RollingUpdateStatefulSetStrategyType,
- RollingUpdate: &appsv1.RollingUpdateStatefulSetStrategy{
- Partition: &partition,
- },
- },
- },
- })
- d := StatefulSetDescriber{fake}
- out, err := d.Describe("foo", "bar", describe.DescriberSettings{ShowEvents: true})
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- expectedOutputs := []string{
- "bar", "foo", "Containers:", "mytest-image:latest", "Update Strategy", "RollingUpdate", "Partition",
- }
- for _, o := range expectedOutputs {
- if !strings.Contains(out, o) {
- t.Errorf("unexpected out: %s", out)
- break
- }
- }
- }
- func TestControllerRef(t *testing.T) {
- var replicas int32 = 1
- f := fake.NewSimpleClientset(
- &corev1.ReplicationController{
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- Namespace: "foo",
- UID: "123456",
- },
- TypeMeta: metav1.TypeMeta{
- Kind: "ReplicationController",
- },
- Spec: corev1.ReplicationControllerSpec{
- Replicas: &replicas,
- Selector: map[string]string{"abc": "xyz"},
- Template: &corev1.PodTemplateSpec{
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{
- {Image: "mytest-image:latest"},
- },
- },
- },
- },
- },
- &corev1.Pod{
- ObjectMeta: metav1.ObjectMeta{
- Name: "barpod",
- Namespace: "foo",
- Labels: map[string]string{"abc": "xyz"},
- OwnerReferences: []metav1.OwnerReference{{Name: "bar", UID: "123456", Controller: utilpointer.BoolPtr(true)}},
- },
- TypeMeta: metav1.TypeMeta{
- Kind: "Pod",
- },
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{
- {Image: "mytest-image:latest"},
- },
- },
- Status: corev1.PodStatus{
- Phase: corev1.PodRunning,
- },
- },
- &corev1.Pod{
- ObjectMeta: metav1.ObjectMeta{
- Name: "orphan",
- Namespace: "foo",
- Labels: map[string]string{"abc": "xyz"},
- },
- TypeMeta: metav1.TypeMeta{
- Kind: "Pod",
- },
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{
- {Image: "mytest-image:latest"},
- },
- },
- Status: corev1.PodStatus{
- Phase: corev1.PodRunning,
- },
- },
- &corev1.Pod{
- ObjectMeta: metav1.ObjectMeta{
- Name: "buzpod",
- Namespace: "foo",
- Labels: map[string]string{"abc": "xyz"},
- OwnerReferences: []metav1.OwnerReference{{Name: "buz", UID: "654321", Controller: utilpointer.BoolPtr(true)}},
- },
- TypeMeta: metav1.TypeMeta{
- Kind: "Pod",
- },
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{
- {Image: "mytest-image:latest"},
- },
- },
- Status: corev1.PodStatus{
- Phase: corev1.PodRunning,
- },
- })
- d := ReplicationControllerDescriber{f}
- out, err := d.Describe("foo", "bar", describe.DescriberSettings{ShowEvents: false})
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- if !strings.Contains(out, "1 Running") {
- t.Errorf("unexpected out: %s", out)
- }
- }
|