validation.go 245 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package validation
  14. import (
  15. "encoding/json"
  16. "fmt"
  17. "math"
  18. "net"
  19. "path"
  20. "path/filepath"
  21. "reflect"
  22. "regexp"
  23. "strings"
  24. "unicode"
  25. "unicode/utf8"
  26. "k8s.io/klog"
  27. "k8s.io/api/core/v1"
  28. apiequality "k8s.io/apimachinery/pkg/api/equality"
  29. "k8s.io/apimachinery/pkg/api/resource"
  30. apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation"
  31. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  32. unversionedvalidation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
  33. "k8s.io/apimachinery/pkg/labels"
  34. "k8s.io/apimachinery/pkg/runtime/schema"
  35. "k8s.io/apimachinery/pkg/util/diff"
  36. "k8s.io/apimachinery/pkg/util/intstr"
  37. "k8s.io/apimachinery/pkg/util/sets"
  38. "k8s.io/apimachinery/pkg/util/validation"
  39. "k8s.io/apimachinery/pkg/util/validation/field"
  40. utilfeature "k8s.io/apiserver/pkg/util/feature"
  41. apiservice "k8s.io/kubernetes/pkg/api/service"
  42. "k8s.io/kubernetes/pkg/apis/core"
  43. "k8s.io/kubernetes/pkg/apis/core/helper"
  44. podshelper "k8s.io/kubernetes/pkg/apis/core/pods"
  45. corev1 "k8s.io/kubernetes/pkg/apis/core/v1"
  46. v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
  47. "k8s.io/kubernetes/pkg/capabilities"
  48. "k8s.io/kubernetes/pkg/features"
  49. "k8s.io/kubernetes/pkg/fieldpath"
  50. "k8s.io/kubernetes/pkg/master/ports"
  51. "k8s.io/kubernetes/pkg/security/apparmor"
  52. netutils "k8s.io/utils/net"
  53. )
  54. const isNegativeErrorMsg string = apimachineryvalidation.IsNegativeErrorMsg
  55. const isInvalidQuotaResource string = `must be a standard resource for quota`
  56. const fieldImmutableErrorMsg string = apimachineryvalidation.FieldImmutableErrorMsg
  57. const isNotIntegerErrorMsg string = `must be an integer`
  58. const isNotPositiveErrorMsg string = `must be greater than zero`
  59. var pdPartitionErrorMsg string = validation.InclusiveRangeError(1, 255)
  60. var fileModeErrorMsg = "must be a number between 0 and 0777 (octal), both inclusive"
  61. // BannedOwners is a black list of object that are not allowed to be owners.
  62. var BannedOwners = apimachineryvalidation.BannedOwners
  63. var iscsiInitiatorIqnRegex = regexp.MustCompile(`iqn\.\d{4}-\d{2}\.([[:alnum:]-.]+)(:[^,;*&$|\s]+)$`)
  64. var iscsiInitiatorEuiRegex = regexp.MustCompile(`^eui.[[:alnum:]]{16}$`)
  65. var iscsiInitiatorNaaRegex = regexp.MustCompile(`^naa.[[:alnum:]]{32}$`)
  66. var allowedEphemeralContainerFields = map[string]bool{
  67. "Name": true,
  68. "Image": true,
  69. "Command": true,
  70. "Args": true,
  71. "WorkingDir": true,
  72. "EnvFrom": true,
  73. "Env": true,
  74. "VolumeMounts": true,
  75. "TerminationMessagePath": true,
  76. "TerminationMessagePolicy": true,
  77. "ImagePullPolicy": true,
  78. "Stdin": true,
  79. "StdinOnce": true,
  80. "TTY": true,
  81. }
  82. // ValidateHasLabel requires that metav1.ObjectMeta has a Label with key and expectedValue
  83. func ValidateHasLabel(meta metav1.ObjectMeta, fldPath *field.Path, key, expectedValue string) field.ErrorList {
  84. allErrs := field.ErrorList{}
  85. actualValue, found := meta.Labels[key]
  86. if !found {
  87. allErrs = append(allErrs, field.Required(fldPath.Child("labels").Key(key),
  88. fmt.Sprintf("must be '%s'", expectedValue)))
  89. return allErrs
  90. }
  91. if actualValue != expectedValue {
  92. allErrs = append(allErrs, field.Invalid(fldPath.Child("labels").Key(key), meta.Labels,
  93. fmt.Sprintf("must be '%s'", expectedValue)))
  94. }
  95. return allErrs
  96. }
  97. // ValidateAnnotations validates that a set of annotations are correctly defined.
  98. func ValidateAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
  99. return apimachineryvalidation.ValidateAnnotations(annotations, fldPath)
  100. }
  101. func ValidateDNS1123Label(value string, fldPath *field.Path) field.ErrorList {
  102. allErrs := field.ErrorList{}
  103. for _, msg := range validation.IsDNS1123Label(value) {
  104. allErrs = append(allErrs, field.Invalid(fldPath, value, msg))
  105. }
  106. return allErrs
  107. }
  108. // ValidateDNS1123Subdomain validates that a name is a proper DNS subdomain.
  109. func ValidateDNS1123Subdomain(value string, fldPath *field.Path) field.ErrorList {
  110. allErrs := field.ErrorList{}
  111. for _, msg := range validation.IsDNS1123Subdomain(value) {
  112. allErrs = append(allErrs, field.Invalid(fldPath, value, msg))
  113. }
  114. return allErrs
  115. }
  116. func ValidatePodSpecificAnnotations(annotations map[string]string, spec *core.PodSpec, fldPath *field.Path) field.ErrorList {
  117. allErrs := field.ErrorList{}
  118. if value, isMirror := annotations[core.MirrorPodAnnotationKey]; isMirror {
  119. if len(spec.NodeName) == 0 {
  120. allErrs = append(allErrs, field.Invalid(fldPath.Key(core.MirrorPodAnnotationKey), value, "must set spec.nodeName if mirror pod annotation is set"))
  121. }
  122. }
  123. if annotations[core.TolerationsAnnotationKey] != "" {
  124. allErrs = append(allErrs, ValidateTolerationsInPodAnnotations(annotations, fldPath)...)
  125. }
  126. allErrs = append(allErrs, ValidateSeccompPodAnnotations(annotations, fldPath)...)
  127. allErrs = append(allErrs, ValidateAppArmorPodAnnotations(annotations, spec, fldPath)...)
  128. return allErrs
  129. }
  130. // ValidateTolerationsInPodAnnotations tests that the serialized tolerations in Pod.Annotations has valid data
  131. func ValidateTolerationsInPodAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
  132. allErrs := field.ErrorList{}
  133. tolerations, err := helper.GetTolerationsFromPodAnnotations(annotations)
  134. if err != nil {
  135. allErrs = append(allErrs, field.Invalid(fldPath, core.TolerationsAnnotationKey, err.Error()))
  136. return allErrs
  137. }
  138. if len(tolerations) > 0 {
  139. allErrs = append(allErrs, ValidateTolerations(tolerations, fldPath.Child(core.TolerationsAnnotationKey))...)
  140. }
  141. return allErrs
  142. }
  143. func ValidatePodSpecificAnnotationUpdates(newPod, oldPod *core.Pod, fldPath *field.Path) field.ErrorList {
  144. allErrs := field.ErrorList{}
  145. newAnnotations := newPod.Annotations
  146. oldAnnotations := oldPod.Annotations
  147. for k, oldVal := range oldAnnotations {
  148. if newVal, exists := newAnnotations[k]; exists && newVal == oldVal {
  149. continue // No change.
  150. }
  151. if strings.HasPrefix(k, apparmor.ContainerAnnotationKeyPrefix) {
  152. allErrs = append(allErrs, field.Forbidden(fldPath.Key(k), "may not remove or update AppArmor annotations"))
  153. }
  154. if k == core.MirrorPodAnnotationKey {
  155. allErrs = append(allErrs, field.Forbidden(fldPath.Key(k), "may not remove or update mirror pod annotation"))
  156. }
  157. }
  158. // Check for additions
  159. for k := range newAnnotations {
  160. if _, ok := oldAnnotations[k]; ok {
  161. continue // No change.
  162. }
  163. if strings.HasPrefix(k, apparmor.ContainerAnnotationKeyPrefix) {
  164. allErrs = append(allErrs, field.Forbidden(fldPath.Key(k), "may not add AppArmor annotations"))
  165. }
  166. if k == core.MirrorPodAnnotationKey {
  167. allErrs = append(allErrs, field.Forbidden(fldPath.Key(k), "may not add mirror pod annotation"))
  168. }
  169. }
  170. allErrs = append(allErrs, ValidatePodSpecificAnnotations(newAnnotations, &newPod.Spec, fldPath)...)
  171. return allErrs
  172. }
  173. func ValidateEndpointsSpecificAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
  174. allErrs := field.ErrorList{}
  175. return allErrs
  176. }
  177. // ValidateNameFunc validates that the provided name is valid for a given resource type.
  178. // Not all resources have the same validation rules for names. Prefix is true
  179. // if the name will have a value appended to it. If the name is not valid,
  180. // this returns a list of descriptions of individual characteristics of the
  181. // value that were not valid. Otherwise this returns an empty list or nil.
  182. type ValidateNameFunc apimachineryvalidation.ValidateNameFunc
  183. // ValidatePodName can be used to check whether the given pod name is valid.
  184. // Prefix indicates this name will be used as part of generation, in which case
  185. // trailing dashes are allowed.
  186. var ValidatePodName = apimachineryvalidation.NameIsDNSSubdomain
  187. // ValidateReplicationControllerName can be used to check whether the given replication
  188. // controller name is valid.
  189. // Prefix indicates this name will be used as part of generation, in which case
  190. // trailing dashes are allowed.
  191. var ValidateReplicationControllerName = apimachineryvalidation.NameIsDNSSubdomain
  192. // ValidateServiceName can be used to check whether the given service name is valid.
  193. // Prefix indicates this name will be used as part of generation, in which case
  194. // trailing dashes are allowed.
  195. var ValidateServiceName = apimachineryvalidation.NameIsDNS1035Label
  196. // ValidateNodeName can be used to check whether the given node name is valid.
  197. // Prefix indicates this name will be used as part of generation, in which case
  198. // trailing dashes are allowed.
  199. var ValidateNodeName = apimachineryvalidation.NameIsDNSSubdomain
  200. // ValidateNamespaceName can be used to check whether the given namespace name is valid.
  201. // Prefix indicates this name will be used as part of generation, in which case
  202. // trailing dashes are allowed.
  203. var ValidateNamespaceName = apimachineryvalidation.ValidateNamespaceName
  204. // ValidateLimitRangeName can be used to check whether the given limit range name is valid.
  205. // Prefix indicates this name will be used as part of generation, in which case
  206. // trailing dashes are allowed.
  207. var ValidateLimitRangeName = apimachineryvalidation.NameIsDNSSubdomain
  208. // ValidateResourceQuotaName can be used to check whether the given
  209. // resource quota name is valid.
  210. // Prefix indicates this name will be used as part of generation, in which case
  211. // trailing dashes are allowed.
  212. var ValidateResourceQuotaName = apimachineryvalidation.NameIsDNSSubdomain
  213. // ValidateSecretName can be used to check whether the given secret name is valid.
  214. // Prefix indicates this name will be used as part of generation, in which case
  215. // trailing dashes are allowed.
  216. var ValidateSecretName = apimachineryvalidation.NameIsDNSSubdomain
  217. // ValidateServiceAccountName can be used to check whether the given service account name is valid.
  218. // Prefix indicates this name will be used as part of generation, in which case
  219. // trailing dashes are allowed.
  220. var ValidateServiceAccountName = apimachineryvalidation.ValidateServiceAccountName
  221. // ValidateEndpointsName can be used to check whether the given endpoints name is valid.
  222. // Prefix indicates this name will be used as part of generation, in which case
  223. // trailing dashes are allowed.
  224. var ValidateEndpointsName = apimachineryvalidation.NameIsDNSSubdomain
  225. // ValidateClusterName can be used to check whether the given cluster name is valid.
  226. var ValidateClusterName = apimachineryvalidation.ValidateClusterName
  227. // ValidateClassName can be used to check whether the given class name is valid.
  228. // It is defined here to avoid import cycle between pkg/apis/storage/validation
  229. // (where it should be) and this file.
  230. var ValidateClassName = apimachineryvalidation.NameIsDNSSubdomain
  231. // ValidatePiorityClassName can be used to check whether the given priority
  232. // class name is valid.
  233. var ValidatePriorityClassName = apimachineryvalidation.NameIsDNSSubdomain
  234. // ValidateRuntimeClassName can be used to check whether the given RuntimeClass name is valid.
  235. // Prefix indicates this name will be used as part of generation, in which case
  236. // trailing dashes are allowed.
  237. func ValidateRuntimeClassName(name string, fldPath *field.Path) field.ErrorList {
  238. var allErrs field.ErrorList
  239. for _, msg := range apimachineryvalidation.NameIsDNSSubdomain(name, false) {
  240. allErrs = append(allErrs, field.Invalid(fldPath, name, msg))
  241. }
  242. return allErrs
  243. }
  244. // validateOverhead can be used to check whether the given Overhead is valid.
  245. func validateOverhead(overhead core.ResourceList, fldPath *field.Path) field.ErrorList {
  246. // reuse the ResourceRequirements validation logic
  247. return ValidateResourceRequirements(&core.ResourceRequirements{Limits: overhead}, fldPath)
  248. }
  249. // Validates that given value is not negative.
  250. func ValidateNonnegativeField(value int64, fldPath *field.Path) field.ErrorList {
  251. return apimachineryvalidation.ValidateNonnegativeField(value, fldPath)
  252. }
  253. // Validates that a Quantity is not negative
  254. func ValidateNonnegativeQuantity(value resource.Quantity, fldPath *field.Path) field.ErrorList {
  255. allErrs := field.ErrorList{}
  256. if value.Cmp(resource.Quantity{}) < 0 {
  257. allErrs = append(allErrs, field.Invalid(fldPath, value.String(), isNegativeErrorMsg))
  258. }
  259. return allErrs
  260. }
  261. // Validates that a Quantity is positive
  262. func ValidatePositiveQuantityValue(value resource.Quantity, fldPath *field.Path) field.ErrorList {
  263. allErrs := field.ErrorList{}
  264. if value.Cmp(resource.Quantity{}) <= 0 {
  265. allErrs = append(allErrs, field.Invalid(fldPath, value.String(), isNotPositiveErrorMsg))
  266. }
  267. return allErrs
  268. }
  269. func ValidateImmutableField(newVal, oldVal interface{}, fldPath *field.Path) field.ErrorList {
  270. return apimachineryvalidation.ValidateImmutableField(newVal, oldVal, fldPath)
  271. }
  272. func ValidateImmutableAnnotation(newVal string, oldVal string, annotation string, fldPath *field.Path) field.ErrorList {
  273. allErrs := field.ErrorList{}
  274. if oldVal != newVal {
  275. allErrs = append(allErrs, field.Invalid(fldPath.Child("annotations", annotation), newVal, fieldImmutableErrorMsg))
  276. }
  277. return allErrs
  278. }
  279. // ValidateObjectMeta validates an object's metadata on creation. It expects that name generation has already
  280. // been performed.
  281. // It doesn't return an error for rootscoped resources with namespace, because namespace should already be cleared before.
  282. // TODO: Remove calls to this method scattered in validations of specific resources, e.g., ValidatePodUpdate.
  283. func ValidateObjectMeta(meta *metav1.ObjectMeta, requiresNamespace bool, nameFn ValidateNameFunc, fldPath *field.Path) field.ErrorList {
  284. allErrs := apimachineryvalidation.ValidateObjectMeta(meta, requiresNamespace, apimachineryvalidation.ValidateNameFunc(nameFn), fldPath)
  285. // run additional checks for the finalizer name
  286. for i := range meta.Finalizers {
  287. allErrs = append(allErrs, validateKubeFinalizerName(string(meta.Finalizers[i]), fldPath.Child("finalizers").Index(i))...)
  288. }
  289. return allErrs
  290. }
  291. // ValidateObjectMetaUpdate validates an object's metadata when updated
  292. func ValidateObjectMetaUpdate(newMeta, oldMeta *metav1.ObjectMeta, fldPath *field.Path) field.ErrorList {
  293. allErrs := apimachineryvalidation.ValidateObjectMetaUpdate(newMeta, oldMeta, fldPath)
  294. // run additional checks for the finalizer name
  295. for i := range newMeta.Finalizers {
  296. allErrs = append(allErrs, validateKubeFinalizerName(string(newMeta.Finalizers[i]), fldPath.Child("finalizers").Index(i))...)
  297. }
  298. return allErrs
  299. }
  300. func ValidateVolumes(volumes []core.Volume, fldPath *field.Path) (map[string]core.VolumeSource, field.ErrorList) {
  301. allErrs := field.ErrorList{}
  302. allNames := sets.String{}
  303. vols := make(map[string]core.VolumeSource)
  304. for i, vol := range volumes {
  305. idxPath := fldPath.Index(i)
  306. namePath := idxPath.Child("name")
  307. el := validateVolumeSource(&vol.VolumeSource, idxPath, vol.Name)
  308. if len(vol.Name) == 0 {
  309. el = append(el, field.Required(namePath, ""))
  310. } else {
  311. el = append(el, ValidateDNS1123Label(vol.Name, namePath)...)
  312. }
  313. if allNames.Has(vol.Name) {
  314. el = append(el, field.Duplicate(namePath, vol.Name))
  315. }
  316. if len(el) == 0 {
  317. allNames.Insert(vol.Name)
  318. vols[vol.Name] = vol.VolumeSource
  319. } else {
  320. allErrs = append(allErrs, el...)
  321. }
  322. }
  323. return vols, allErrs
  324. }
  325. func IsMatchedVolume(name string, volumes map[string]core.VolumeSource) bool {
  326. if _, ok := volumes[name]; ok {
  327. return true
  328. }
  329. return false
  330. }
  331. func isMatchedDevice(name string, volumes map[string]core.VolumeSource) (bool, bool) {
  332. if source, ok := volumes[name]; ok {
  333. if source.PersistentVolumeClaim != nil {
  334. return true, true
  335. }
  336. return true, false
  337. }
  338. return false, false
  339. }
  340. func mountNameAlreadyExists(name string, devices map[string]string) bool {
  341. if _, ok := devices[name]; ok {
  342. return true
  343. }
  344. return false
  345. }
  346. func mountPathAlreadyExists(mountPath string, devices map[string]string) bool {
  347. for _, devPath := range devices {
  348. if mountPath == devPath {
  349. return true
  350. }
  351. }
  352. return false
  353. }
  354. func deviceNameAlreadyExists(name string, mounts map[string]string) bool {
  355. if _, ok := mounts[name]; ok {
  356. return true
  357. }
  358. return false
  359. }
  360. func devicePathAlreadyExists(devicePath string, mounts map[string]string) bool {
  361. for _, mountPath := range mounts {
  362. if mountPath == devicePath {
  363. return true
  364. }
  365. }
  366. return false
  367. }
  368. func validateVolumeSource(source *core.VolumeSource, fldPath *field.Path, volName string) field.ErrorList {
  369. numVolumes := 0
  370. allErrs := field.ErrorList{}
  371. if source.EmptyDir != nil {
  372. numVolumes++
  373. if source.EmptyDir.SizeLimit != nil && source.EmptyDir.SizeLimit.Cmp(resource.Quantity{}) < 0 {
  374. allErrs = append(allErrs, field.Forbidden(fldPath.Child("emptyDir").Child("sizeLimit"), "SizeLimit field must be a valid resource quantity"))
  375. }
  376. }
  377. if source.HostPath != nil {
  378. if numVolumes > 0 {
  379. allErrs = append(allErrs, field.Forbidden(fldPath.Child("hostPath"), "may not specify more than 1 volume type"))
  380. } else {
  381. numVolumes++
  382. allErrs = append(allErrs, validateHostPathVolumeSource(source.HostPath, fldPath.Child("hostPath"))...)
  383. }
  384. }
  385. if source.GitRepo != nil {
  386. if numVolumes > 0 {
  387. allErrs = append(allErrs, field.Forbidden(fldPath.Child("gitRepo"), "may not specify more than 1 volume type"))
  388. } else {
  389. numVolumes++
  390. allErrs = append(allErrs, validateGitRepoVolumeSource(source.GitRepo, fldPath.Child("gitRepo"))...)
  391. }
  392. }
  393. if source.GCEPersistentDisk != nil {
  394. if numVolumes > 0 {
  395. allErrs = append(allErrs, field.Forbidden(fldPath.Child("gcePersistentDisk"), "may not specify more than 1 volume type"))
  396. } else {
  397. numVolumes++
  398. allErrs = append(allErrs, validateGCEPersistentDiskVolumeSource(source.GCEPersistentDisk, fldPath.Child("persistentDisk"))...)
  399. }
  400. }
  401. if source.AWSElasticBlockStore != nil {
  402. if numVolumes > 0 {
  403. allErrs = append(allErrs, field.Forbidden(fldPath.Child("awsElasticBlockStore"), "may not specify more than 1 volume type"))
  404. } else {
  405. numVolumes++
  406. allErrs = append(allErrs, validateAWSElasticBlockStoreVolumeSource(source.AWSElasticBlockStore, fldPath.Child("awsElasticBlockStore"))...)
  407. }
  408. }
  409. if source.Secret != nil {
  410. if numVolumes > 0 {
  411. allErrs = append(allErrs, field.Forbidden(fldPath.Child("secret"), "may not specify more than 1 volume type"))
  412. } else {
  413. numVolumes++
  414. allErrs = append(allErrs, validateSecretVolumeSource(source.Secret, fldPath.Child("secret"))...)
  415. }
  416. }
  417. if source.NFS != nil {
  418. if numVolumes > 0 {
  419. allErrs = append(allErrs, field.Forbidden(fldPath.Child("nfs"), "may not specify more than 1 volume type"))
  420. } else {
  421. numVolumes++
  422. allErrs = append(allErrs, validateNFSVolumeSource(source.NFS, fldPath.Child("nfs"))...)
  423. }
  424. }
  425. if source.ISCSI != nil {
  426. if numVolumes > 0 {
  427. allErrs = append(allErrs, field.Forbidden(fldPath.Child("iscsi"), "may not specify more than 1 volume type"))
  428. } else {
  429. numVolumes++
  430. allErrs = append(allErrs, validateISCSIVolumeSource(source.ISCSI, fldPath.Child("iscsi"))...)
  431. }
  432. if source.ISCSI.InitiatorName != nil && len(volName+":"+source.ISCSI.TargetPortal) > 64 {
  433. tooLongErr := "Total length of <volume name>:<iscsi.targetPortal> must be under 64 characters if iscsi.initiatorName is specified."
  434. allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), volName, tooLongErr))
  435. }
  436. }
  437. if source.Glusterfs != nil {
  438. if numVolumes > 0 {
  439. allErrs = append(allErrs, field.Forbidden(fldPath.Child("glusterfs"), "may not specify more than 1 volume type"))
  440. } else {
  441. numVolumes++
  442. allErrs = append(allErrs, validateGlusterfsVolumeSource(source.Glusterfs, fldPath.Child("glusterfs"))...)
  443. }
  444. }
  445. if source.Flocker != nil {
  446. if numVolumes > 0 {
  447. allErrs = append(allErrs, field.Forbidden(fldPath.Child("flocker"), "may not specify more than 1 volume type"))
  448. } else {
  449. numVolumes++
  450. allErrs = append(allErrs, validateFlockerVolumeSource(source.Flocker, fldPath.Child("flocker"))...)
  451. }
  452. }
  453. if source.PersistentVolumeClaim != nil {
  454. if numVolumes > 0 {
  455. allErrs = append(allErrs, field.Forbidden(fldPath.Child("persistentVolumeClaim"), "may not specify more than 1 volume type"))
  456. } else {
  457. numVolumes++
  458. allErrs = append(allErrs, validatePersistentClaimVolumeSource(source.PersistentVolumeClaim, fldPath.Child("persistentVolumeClaim"))...)
  459. }
  460. }
  461. if source.RBD != nil {
  462. if numVolumes > 0 {
  463. allErrs = append(allErrs, field.Forbidden(fldPath.Child("rbd"), "may not specify more than 1 volume type"))
  464. } else {
  465. numVolumes++
  466. allErrs = append(allErrs, validateRBDVolumeSource(source.RBD, fldPath.Child("rbd"))...)
  467. }
  468. }
  469. if source.Cinder != nil {
  470. if numVolumes > 0 {
  471. allErrs = append(allErrs, field.Forbidden(fldPath.Child("cinder"), "may not specify more than 1 volume type"))
  472. } else {
  473. numVolumes++
  474. allErrs = append(allErrs, validateCinderVolumeSource(source.Cinder, fldPath.Child("cinder"))...)
  475. }
  476. }
  477. if source.CephFS != nil {
  478. if numVolumes > 0 {
  479. allErrs = append(allErrs, field.Forbidden(fldPath.Child("cephFS"), "may not specify more than 1 volume type"))
  480. } else {
  481. numVolumes++
  482. allErrs = append(allErrs, validateCephFSVolumeSource(source.CephFS, fldPath.Child("cephfs"))...)
  483. }
  484. }
  485. if source.Quobyte != nil {
  486. if numVolumes > 0 {
  487. allErrs = append(allErrs, field.Forbidden(fldPath.Child("quobyte"), "may not specify more than 1 volume type"))
  488. } else {
  489. numVolumes++
  490. allErrs = append(allErrs, validateQuobyteVolumeSource(source.Quobyte, fldPath.Child("quobyte"))...)
  491. }
  492. }
  493. if source.DownwardAPI != nil {
  494. if numVolumes > 0 {
  495. allErrs = append(allErrs, field.Forbidden(fldPath.Child("downwarAPI"), "may not specify more than 1 volume type"))
  496. } else {
  497. numVolumes++
  498. allErrs = append(allErrs, validateDownwardAPIVolumeSource(source.DownwardAPI, fldPath.Child("downwardAPI"))...)
  499. }
  500. }
  501. if source.FC != nil {
  502. if numVolumes > 0 {
  503. allErrs = append(allErrs, field.Forbidden(fldPath.Child("fc"), "may not specify more than 1 volume type"))
  504. } else {
  505. numVolumes++
  506. allErrs = append(allErrs, validateFCVolumeSource(source.FC, fldPath.Child("fc"))...)
  507. }
  508. }
  509. if source.FlexVolume != nil {
  510. if numVolumes > 0 {
  511. allErrs = append(allErrs, field.Forbidden(fldPath.Child("flexVolume"), "may not specify more than 1 volume type"))
  512. } else {
  513. numVolumes++
  514. allErrs = append(allErrs, validateFlexVolumeSource(source.FlexVolume, fldPath.Child("flexVolume"))...)
  515. }
  516. }
  517. if source.ConfigMap != nil {
  518. if numVolumes > 0 {
  519. allErrs = append(allErrs, field.Forbidden(fldPath.Child("configMap"), "may not specify more than 1 volume type"))
  520. } else {
  521. numVolumes++
  522. allErrs = append(allErrs, validateConfigMapVolumeSource(source.ConfigMap, fldPath.Child("configMap"))...)
  523. }
  524. }
  525. if source.AzureFile != nil {
  526. if numVolumes > 0 {
  527. allErrs = append(allErrs, field.Forbidden(fldPath.Child("azureFile"), "may not specify more than 1 volume type"))
  528. } else {
  529. numVolumes++
  530. allErrs = append(allErrs, validateAzureFile(source.AzureFile, fldPath.Child("azureFile"))...)
  531. }
  532. }
  533. if source.VsphereVolume != nil {
  534. if numVolumes > 0 {
  535. allErrs = append(allErrs, field.Forbidden(fldPath.Child("vsphereVolume"), "may not specify more than 1 volume type"))
  536. } else {
  537. numVolumes++
  538. allErrs = append(allErrs, validateVsphereVolumeSource(source.VsphereVolume, fldPath.Child("vsphereVolume"))...)
  539. }
  540. }
  541. if source.PhotonPersistentDisk != nil {
  542. if numVolumes > 0 {
  543. allErrs = append(allErrs, field.Forbidden(fldPath.Child("photonPersistentDisk"), "may not specify more than 1 volume type"))
  544. } else {
  545. numVolumes++
  546. allErrs = append(allErrs, validatePhotonPersistentDiskVolumeSource(source.PhotonPersistentDisk, fldPath.Child("photonPersistentDisk"))...)
  547. }
  548. }
  549. if source.PortworxVolume != nil {
  550. if numVolumes > 0 {
  551. allErrs = append(allErrs, field.Forbidden(fldPath.Child("portworxVolume"), "may not specify more than 1 volume type"))
  552. } else {
  553. numVolumes++
  554. allErrs = append(allErrs, validatePortworxVolumeSource(source.PortworxVolume, fldPath.Child("portworxVolume"))...)
  555. }
  556. }
  557. if source.AzureDisk != nil {
  558. if numVolumes > 0 {
  559. allErrs = append(allErrs, field.Forbidden(fldPath.Child("azureDisk"), "may not specify more than 1 volume type"))
  560. } else {
  561. numVolumes++
  562. allErrs = append(allErrs, validateAzureDisk(source.AzureDisk, fldPath.Child("azureDisk"))...)
  563. }
  564. }
  565. if source.StorageOS != nil {
  566. if numVolumes > 0 {
  567. allErrs = append(allErrs, field.Forbidden(fldPath.Child("storageos"), "may not specify more than 1 volume type"))
  568. } else {
  569. numVolumes++
  570. allErrs = append(allErrs, validateStorageOSVolumeSource(source.StorageOS, fldPath.Child("storageos"))...)
  571. }
  572. }
  573. if source.Projected != nil {
  574. if numVolumes > 0 {
  575. allErrs = append(allErrs, field.Forbidden(fldPath.Child("projected"), "may not specify more than 1 volume type"))
  576. } else {
  577. numVolumes++
  578. allErrs = append(allErrs, validateProjectedVolumeSource(source.Projected, fldPath.Child("projected"))...)
  579. }
  580. }
  581. if source.ScaleIO != nil {
  582. if numVolumes > 0 {
  583. allErrs = append(allErrs, field.Forbidden(fldPath.Child("scaleIO"), "may not specify more than 1 volume type"))
  584. } else {
  585. numVolumes++
  586. allErrs = append(allErrs, validateScaleIOVolumeSource(source.ScaleIO, fldPath.Child("scaleIO"))...)
  587. }
  588. }
  589. if source.CSI != nil {
  590. if numVolumes > 0 {
  591. allErrs = append(allErrs, field.Forbidden(fldPath.Child("csi"), "may not specify more than 1 volume type"))
  592. } else {
  593. numVolumes++
  594. allErrs = append(allErrs, validateCSIVolumeSource(source.CSI, fldPath.Child("csi"))...)
  595. }
  596. }
  597. if numVolumes == 0 {
  598. allErrs = append(allErrs, field.Required(fldPath, "must specify a volume type"))
  599. }
  600. return allErrs
  601. }
  602. func validateHostPathVolumeSource(hostPath *core.HostPathVolumeSource, fldPath *field.Path) field.ErrorList {
  603. allErrs := field.ErrorList{}
  604. if len(hostPath.Path) == 0 {
  605. allErrs = append(allErrs, field.Required(fldPath.Child("path"), ""))
  606. return allErrs
  607. }
  608. allErrs = append(allErrs, validatePathNoBacksteps(hostPath.Path, fldPath.Child("path"))...)
  609. allErrs = append(allErrs, validateHostPathType(hostPath.Type, fldPath.Child("type"))...)
  610. return allErrs
  611. }
  612. func validateGitRepoVolumeSource(gitRepo *core.GitRepoVolumeSource, fldPath *field.Path) field.ErrorList {
  613. allErrs := field.ErrorList{}
  614. if len(gitRepo.Repository) == 0 {
  615. allErrs = append(allErrs, field.Required(fldPath.Child("repository"), ""))
  616. }
  617. pathErrs := validateLocalDescendingPath(gitRepo.Directory, fldPath.Child("directory"))
  618. allErrs = append(allErrs, pathErrs...)
  619. return allErrs
  620. }
  621. func validateISCSIVolumeSource(iscsi *core.ISCSIVolumeSource, fldPath *field.Path) field.ErrorList {
  622. allErrs := field.ErrorList{}
  623. if len(iscsi.TargetPortal) == 0 {
  624. allErrs = append(allErrs, field.Required(fldPath.Child("targetPortal"), ""))
  625. }
  626. if len(iscsi.IQN) == 0 {
  627. allErrs = append(allErrs, field.Required(fldPath.Child("iqn"), ""))
  628. } else {
  629. if !strings.HasPrefix(iscsi.IQN, "iqn") && !strings.HasPrefix(iscsi.IQN, "eui") && !strings.HasPrefix(iscsi.IQN, "naa") {
  630. allErrs = append(allErrs, field.Invalid(fldPath.Child("iqn"), iscsi.IQN, "must be valid format starting with iqn, eui, or naa"))
  631. } else if strings.HasPrefix(iscsi.IQN, "iqn") && !iscsiInitiatorIqnRegex.MatchString(iscsi.IQN) {
  632. allErrs = append(allErrs, field.Invalid(fldPath.Child("iqn"), iscsi.IQN, "must be valid format"))
  633. } else if strings.HasPrefix(iscsi.IQN, "eui") && !iscsiInitiatorEuiRegex.MatchString(iscsi.IQN) {
  634. allErrs = append(allErrs, field.Invalid(fldPath.Child("iqn"), iscsi.IQN, "must be valid format"))
  635. } else if strings.HasPrefix(iscsi.IQN, "naa") && !iscsiInitiatorNaaRegex.MatchString(iscsi.IQN) {
  636. allErrs = append(allErrs, field.Invalid(fldPath.Child("iqn"), iscsi.IQN, "must be valid format"))
  637. }
  638. }
  639. if iscsi.Lun < 0 || iscsi.Lun > 255 {
  640. allErrs = append(allErrs, field.Invalid(fldPath.Child("lun"), iscsi.Lun, validation.InclusiveRangeError(0, 255)))
  641. }
  642. if (iscsi.DiscoveryCHAPAuth || iscsi.SessionCHAPAuth) && iscsi.SecretRef == nil {
  643. allErrs = append(allErrs, field.Required(fldPath.Child("secretRef"), ""))
  644. }
  645. if iscsi.InitiatorName != nil {
  646. initiator := *iscsi.InitiatorName
  647. if !strings.HasPrefix(initiator, "iqn") && !strings.HasPrefix(initiator, "eui") && !strings.HasPrefix(initiator, "naa") {
  648. allErrs = append(allErrs, field.Invalid(fldPath.Child("initiatorname"), initiator, "must be valid format starting with iqn, eui, or naa"))
  649. }
  650. if strings.HasPrefix(initiator, "iqn") && !iscsiInitiatorIqnRegex.MatchString(initiator) {
  651. allErrs = append(allErrs, field.Invalid(fldPath.Child("initiatorname"), initiator, "must be valid format"))
  652. } else if strings.HasPrefix(initiator, "eui") && !iscsiInitiatorEuiRegex.MatchString(initiator) {
  653. allErrs = append(allErrs, field.Invalid(fldPath.Child("initiatorname"), initiator, "must be valid format"))
  654. } else if strings.HasPrefix(initiator, "naa") && !iscsiInitiatorNaaRegex.MatchString(initiator) {
  655. allErrs = append(allErrs, field.Invalid(fldPath.Child("initiatorname"), initiator, "must be valid format"))
  656. }
  657. }
  658. return allErrs
  659. }
  660. func validateISCSIPersistentVolumeSource(iscsi *core.ISCSIPersistentVolumeSource, pvName string, fldPath *field.Path) field.ErrorList {
  661. allErrs := field.ErrorList{}
  662. if len(iscsi.TargetPortal) == 0 {
  663. allErrs = append(allErrs, field.Required(fldPath.Child("targetPortal"), ""))
  664. }
  665. if iscsi.InitiatorName != nil && len(pvName+":"+iscsi.TargetPortal) > 64 {
  666. tooLongErr := "Total length of <volume name>:<iscsi.targetPortal> must be under 64 characters if iscsi.initiatorName is specified."
  667. allErrs = append(allErrs, field.Invalid(fldPath.Child("targetportal"), iscsi.TargetPortal, tooLongErr))
  668. }
  669. if len(iscsi.IQN) == 0 {
  670. allErrs = append(allErrs, field.Required(fldPath.Child("iqn"), ""))
  671. } else {
  672. if !strings.HasPrefix(iscsi.IQN, "iqn") && !strings.HasPrefix(iscsi.IQN, "eui") && !strings.HasPrefix(iscsi.IQN, "naa") {
  673. allErrs = append(allErrs, field.Invalid(fldPath.Child("iqn"), iscsi.IQN, "must be valid format"))
  674. } else if strings.HasPrefix(iscsi.IQN, "iqn") && !iscsiInitiatorIqnRegex.MatchString(iscsi.IQN) {
  675. allErrs = append(allErrs, field.Invalid(fldPath.Child("iqn"), iscsi.IQN, "must be valid format"))
  676. } else if strings.HasPrefix(iscsi.IQN, "eui") && !iscsiInitiatorEuiRegex.MatchString(iscsi.IQN) {
  677. allErrs = append(allErrs, field.Invalid(fldPath.Child("iqn"), iscsi.IQN, "must be valid format"))
  678. } else if strings.HasPrefix(iscsi.IQN, "naa") && !iscsiInitiatorNaaRegex.MatchString(iscsi.IQN) {
  679. allErrs = append(allErrs, field.Invalid(fldPath.Child("iqn"), iscsi.IQN, "must be valid format"))
  680. }
  681. }
  682. if iscsi.Lun < 0 || iscsi.Lun > 255 {
  683. allErrs = append(allErrs, field.Invalid(fldPath.Child("lun"), iscsi.Lun, validation.InclusiveRangeError(0, 255)))
  684. }
  685. if (iscsi.DiscoveryCHAPAuth || iscsi.SessionCHAPAuth) && iscsi.SecretRef == nil {
  686. allErrs = append(allErrs, field.Required(fldPath.Child("secretRef"), ""))
  687. }
  688. if iscsi.SecretRef != nil {
  689. if len(iscsi.SecretRef.Name) == 0 {
  690. allErrs = append(allErrs, field.Required(fldPath.Child("secretRef", "name"), ""))
  691. }
  692. }
  693. if iscsi.InitiatorName != nil {
  694. initiator := *iscsi.InitiatorName
  695. if !strings.HasPrefix(initiator, "iqn") && !strings.HasPrefix(initiator, "eui") && !strings.HasPrefix(initiator, "naa") {
  696. allErrs = append(allErrs, field.Invalid(fldPath.Child("initiatorname"), initiator, "must be valid format"))
  697. }
  698. if strings.HasPrefix(initiator, "iqn") && !iscsiInitiatorIqnRegex.MatchString(initiator) {
  699. allErrs = append(allErrs, field.Invalid(fldPath.Child("initiatorname"), initiator, "must be valid format"))
  700. } else if strings.HasPrefix(initiator, "eui") && !iscsiInitiatorEuiRegex.MatchString(initiator) {
  701. allErrs = append(allErrs, field.Invalid(fldPath.Child("initiatorname"), initiator, "must be valid format"))
  702. } else if strings.HasPrefix(initiator, "naa") && !iscsiInitiatorNaaRegex.MatchString(initiator) {
  703. allErrs = append(allErrs, field.Invalid(fldPath.Child("initiatorname"), initiator, "must be valid format"))
  704. }
  705. }
  706. return allErrs
  707. }
  708. func validateFCVolumeSource(fc *core.FCVolumeSource, fldPath *field.Path) field.ErrorList {
  709. allErrs := field.ErrorList{}
  710. if len(fc.TargetWWNs) < 1 && len(fc.WWIDs) < 1 {
  711. allErrs = append(allErrs, field.Required(fldPath.Child("targetWWNs"), "must specify either targetWWNs or wwids, but not both"))
  712. }
  713. if len(fc.TargetWWNs) != 0 && len(fc.WWIDs) != 0 {
  714. allErrs = append(allErrs, field.Invalid(fldPath.Child("targetWWNs"), fc.TargetWWNs, "targetWWNs and wwids can not be specified simultaneously"))
  715. }
  716. if len(fc.TargetWWNs) != 0 {
  717. if fc.Lun == nil {
  718. allErrs = append(allErrs, field.Required(fldPath.Child("lun"), "lun is required if targetWWNs is specified"))
  719. } else {
  720. if *fc.Lun < 0 || *fc.Lun > 255 {
  721. allErrs = append(allErrs, field.Invalid(fldPath.Child("lun"), fc.Lun, validation.InclusiveRangeError(0, 255)))
  722. }
  723. }
  724. }
  725. return allErrs
  726. }
  727. func validateGCEPersistentDiskVolumeSource(pd *core.GCEPersistentDiskVolumeSource, fldPath *field.Path) field.ErrorList {
  728. allErrs := field.ErrorList{}
  729. if len(pd.PDName) == 0 {
  730. allErrs = append(allErrs, field.Required(fldPath.Child("pdName"), ""))
  731. }
  732. if pd.Partition < 0 || pd.Partition > 255 {
  733. allErrs = append(allErrs, field.Invalid(fldPath.Child("partition"), pd.Partition, pdPartitionErrorMsg))
  734. }
  735. return allErrs
  736. }
  737. func validateAWSElasticBlockStoreVolumeSource(PD *core.AWSElasticBlockStoreVolumeSource, fldPath *field.Path) field.ErrorList {
  738. allErrs := field.ErrorList{}
  739. if len(PD.VolumeID) == 0 {
  740. allErrs = append(allErrs, field.Required(fldPath.Child("volumeID"), ""))
  741. }
  742. if PD.Partition < 0 || PD.Partition > 255 {
  743. allErrs = append(allErrs, field.Invalid(fldPath.Child("partition"), PD.Partition, pdPartitionErrorMsg))
  744. }
  745. return allErrs
  746. }
  747. func validateSecretVolumeSource(secretSource *core.SecretVolumeSource, fldPath *field.Path) field.ErrorList {
  748. allErrs := field.ErrorList{}
  749. if len(secretSource.SecretName) == 0 {
  750. allErrs = append(allErrs, field.Required(fldPath.Child("secretName"), ""))
  751. }
  752. secretMode := secretSource.DefaultMode
  753. if secretMode != nil && (*secretMode > 0777 || *secretMode < 0) {
  754. allErrs = append(allErrs, field.Invalid(fldPath.Child("defaultMode"), *secretMode, fileModeErrorMsg))
  755. }
  756. itemsPath := fldPath.Child("items")
  757. for i, kp := range secretSource.Items {
  758. itemPath := itemsPath.Index(i)
  759. allErrs = append(allErrs, validateKeyToPath(&kp, itemPath)...)
  760. }
  761. return allErrs
  762. }
  763. func validateConfigMapVolumeSource(configMapSource *core.ConfigMapVolumeSource, fldPath *field.Path) field.ErrorList {
  764. allErrs := field.ErrorList{}
  765. if len(configMapSource.Name) == 0 {
  766. allErrs = append(allErrs, field.Required(fldPath.Child("name"), ""))
  767. }
  768. configMapMode := configMapSource.DefaultMode
  769. if configMapMode != nil && (*configMapMode > 0777 || *configMapMode < 0) {
  770. allErrs = append(allErrs, field.Invalid(fldPath.Child("defaultMode"), *configMapMode, fileModeErrorMsg))
  771. }
  772. itemsPath := fldPath.Child("items")
  773. for i, kp := range configMapSource.Items {
  774. itemPath := itemsPath.Index(i)
  775. allErrs = append(allErrs, validateKeyToPath(&kp, itemPath)...)
  776. }
  777. return allErrs
  778. }
  779. func validateKeyToPath(kp *core.KeyToPath, fldPath *field.Path) field.ErrorList {
  780. allErrs := field.ErrorList{}
  781. if len(kp.Key) == 0 {
  782. allErrs = append(allErrs, field.Required(fldPath.Child("key"), ""))
  783. }
  784. if len(kp.Path) == 0 {
  785. allErrs = append(allErrs, field.Required(fldPath.Child("path"), ""))
  786. }
  787. allErrs = append(allErrs, validateLocalNonReservedPath(kp.Path, fldPath.Child("path"))...)
  788. if kp.Mode != nil && (*kp.Mode > 0777 || *kp.Mode < 0) {
  789. allErrs = append(allErrs, field.Invalid(fldPath.Child("mode"), *kp.Mode, fileModeErrorMsg))
  790. }
  791. return allErrs
  792. }
  793. func validatePersistentClaimVolumeSource(claim *core.PersistentVolumeClaimVolumeSource, fldPath *field.Path) field.ErrorList {
  794. allErrs := field.ErrorList{}
  795. if len(claim.ClaimName) == 0 {
  796. allErrs = append(allErrs, field.Required(fldPath.Child("claimName"), ""))
  797. }
  798. return allErrs
  799. }
  800. func validateNFSVolumeSource(nfs *core.NFSVolumeSource, fldPath *field.Path) field.ErrorList {
  801. allErrs := field.ErrorList{}
  802. if len(nfs.Server) == 0 {
  803. allErrs = append(allErrs, field.Required(fldPath.Child("server"), ""))
  804. }
  805. if len(nfs.Path) == 0 {
  806. allErrs = append(allErrs, field.Required(fldPath.Child("path"), ""))
  807. }
  808. if !path.IsAbs(nfs.Path) {
  809. allErrs = append(allErrs, field.Invalid(fldPath.Child("path"), nfs.Path, "must be an absolute path"))
  810. }
  811. return allErrs
  812. }
  813. func validateQuobyteVolumeSource(quobyte *core.QuobyteVolumeSource, fldPath *field.Path) field.ErrorList {
  814. allErrs := field.ErrorList{}
  815. if len(quobyte.Registry) == 0 {
  816. allErrs = append(allErrs, field.Required(fldPath.Child("registry"), "must be a host:port pair or multiple pairs separated by commas"))
  817. } else if len(quobyte.Tenant) >= 65 {
  818. allErrs = append(allErrs, field.Required(fldPath.Child("tenant"), "must be a UUID and may not exceed a length of 64 characters"))
  819. } else {
  820. for _, hostPortPair := range strings.Split(quobyte.Registry, ",") {
  821. if _, _, err := net.SplitHostPort(hostPortPair); err != nil {
  822. allErrs = append(allErrs, field.Invalid(fldPath.Child("registry"), quobyte.Registry, "must be a host:port pair or multiple pairs separated by commas"))
  823. }
  824. }
  825. }
  826. if len(quobyte.Volume) == 0 {
  827. allErrs = append(allErrs, field.Required(fldPath.Child("volume"), ""))
  828. }
  829. return allErrs
  830. }
  831. func validateGlusterfsVolumeSource(glusterfs *core.GlusterfsVolumeSource, fldPath *field.Path) field.ErrorList {
  832. allErrs := field.ErrorList{}
  833. if len(glusterfs.EndpointsName) == 0 {
  834. allErrs = append(allErrs, field.Required(fldPath.Child("endpoints"), ""))
  835. }
  836. if len(glusterfs.Path) == 0 {
  837. allErrs = append(allErrs, field.Required(fldPath.Child("path"), ""))
  838. }
  839. return allErrs
  840. }
  841. func validateGlusterfsPersistentVolumeSource(glusterfs *core.GlusterfsPersistentVolumeSource, fldPath *field.Path) field.ErrorList {
  842. allErrs := field.ErrorList{}
  843. if len(glusterfs.EndpointsName) == 0 {
  844. allErrs = append(allErrs, field.Required(fldPath.Child("endpoints"), ""))
  845. }
  846. if len(glusterfs.Path) == 0 {
  847. allErrs = append(allErrs, field.Required(fldPath.Child("path"), ""))
  848. }
  849. if glusterfs.EndpointsNamespace != nil {
  850. endpointNs := glusterfs.EndpointsNamespace
  851. if *endpointNs == "" {
  852. allErrs = append(allErrs, field.Invalid(fldPath.Child("endpointsNamespace"), *endpointNs, "if the endpointnamespace is set, it must be a valid namespace name"))
  853. } else {
  854. for _, msg := range ValidateNamespaceName(*endpointNs, false) {
  855. allErrs = append(allErrs, field.Invalid(fldPath.Child("endpointsNamespace"), *endpointNs, msg))
  856. }
  857. }
  858. }
  859. return allErrs
  860. }
  861. func validateFlockerVolumeSource(flocker *core.FlockerVolumeSource, fldPath *field.Path) field.ErrorList {
  862. allErrs := field.ErrorList{}
  863. if len(flocker.DatasetName) == 0 && len(flocker.DatasetUUID) == 0 {
  864. //TODO: consider adding a RequiredOneOf() error for this and similar cases
  865. allErrs = append(allErrs, field.Required(fldPath, "one of datasetName and datasetUUID is required"))
  866. }
  867. if len(flocker.DatasetName) != 0 && len(flocker.DatasetUUID) != 0 {
  868. allErrs = append(allErrs, field.Invalid(fldPath, "resource", "datasetName and datasetUUID can not be specified simultaneously"))
  869. }
  870. if strings.Contains(flocker.DatasetName, "/") {
  871. allErrs = append(allErrs, field.Invalid(fldPath.Child("datasetName"), flocker.DatasetName, "must not contain '/'"))
  872. }
  873. return allErrs
  874. }
  875. var validVolumeDownwardAPIFieldPathExpressions = sets.NewString(
  876. "metadata.name",
  877. "metadata.namespace",
  878. "metadata.labels",
  879. "metadata.annotations",
  880. "metadata.uid")
  881. func validateDownwardAPIVolumeFile(file *core.DownwardAPIVolumeFile, fldPath *field.Path) field.ErrorList {
  882. allErrs := field.ErrorList{}
  883. if len(file.Path) == 0 {
  884. allErrs = append(allErrs, field.Required(fldPath.Child("path"), ""))
  885. }
  886. allErrs = append(allErrs, validateLocalNonReservedPath(file.Path, fldPath.Child("path"))...)
  887. if file.FieldRef != nil {
  888. allErrs = append(allErrs, validateObjectFieldSelector(file.FieldRef, &validVolumeDownwardAPIFieldPathExpressions, fldPath.Child("fieldRef"))...)
  889. if file.ResourceFieldRef != nil {
  890. allErrs = append(allErrs, field.Invalid(fldPath, "resource", "fieldRef and resourceFieldRef can not be specified simultaneously"))
  891. }
  892. } else if file.ResourceFieldRef != nil {
  893. allErrs = append(allErrs, validateContainerResourceFieldSelector(file.ResourceFieldRef, &validContainerResourceFieldPathExpressions, fldPath.Child("resourceFieldRef"), true)...)
  894. } else {
  895. allErrs = append(allErrs, field.Required(fldPath, "one of fieldRef and resourceFieldRef is required"))
  896. }
  897. if file.Mode != nil && (*file.Mode > 0777 || *file.Mode < 0) {
  898. allErrs = append(allErrs, field.Invalid(fldPath.Child("mode"), *file.Mode, fileModeErrorMsg))
  899. }
  900. return allErrs
  901. }
  902. func validateDownwardAPIVolumeSource(downwardAPIVolume *core.DownwardAPIVolumeSource, fldPath *field.Path) field.ErrorList {
  903. allErrs := field.ErrorList{}
  904. downwardAPIMode := downwardAPIVolume.DefaultMode
  905. if downwardAPIMode != nil && (*downwardAPIMode > 0777 || *downwardAPIMode < 0) {
  906. allErrs = append(allErrs, field.Invalid(fldPath.Child("defaultMode"), *downwardAPIMode, fileModeErrorMsg))
  907. }
  908. for _, file := range downwardAPIVolume.Items {
  909. allErrs = append(allErrs, validateDownwardAPIVolumeFile(&file, fldPath)...)
  910. }
  911. return allErrs
  912. }
  913. func validateProjectionSources(projection *core.ProjectedVolumeSource, projectionMode *int32, fldPath *field.Path) field.ErrorList {
  914. allErrs := field.ErrorList{}
  915. allPaths := sets.String{}
  916. for i, source := range projection.Sources {
  917. numSources := 0
  918. srcPath := fldPath.Child("sources").Index(i)
  919. if projPath := srcPath.Child("secret"); source.Secret != nil {
  920. numSources++
  921. if len(source.Secret.Name) == 0 {
  922. allErrs = append(allErrs, field.Required(projPath.Child("name"), ""))
  923. }
  924. itemsPath := projPath.Child("items")
  925. for i, kp := range source.Secret.Items {
  926. itemPath := itemsPath.Index(i)
  927. allErrs = append(allErrs, validateKeyToPath(&kp, itemPath)...)
  928. if len(kp.Path) > 0 {
  929. curPath := kp.Path
  930. if !allPaths.Has(curPath) {
  931. allPaths.Insert(curPath)
  932. } else {
  933. allErrs = append(allErrs, field.Invalid(fldPath, source.Secret.Name, "conflicting duplicate paths"))
  934. }
  935. }
  936. }
  937. }
  938. if projPath := srcPath.Child("configMap"); source.ConfigMap != nil {
  939. numSources++
  940. if len(source.ConfigMap.Name) == 0 {
  941. allErrs = append(allErrs, field.Required(projPath.Child("name"), ""))
  942. }
  943. itemsPath := projPath.Child("items")
  944. for i, kp := range source.ConfigMap.Items {
  945. itemPath := itemsPath.Index(i)
  946. allErrs = append(allErrs, validateKeyToPath(&kp, itemPath)...)
  947. if len(kp.Path) > 0 {
  948. curPath := kp.Path
  949. if !allPaths.Has(curPath) {
  950. allPaths.Insert(curPath)
  951. } else {
  952. allErrs = append(allErrs, field.Invalid(fldPath, source.ConfigMap.Name, "conflicting duplicate paths"))
  953. }
  954. }
  955. }
  956. }
  957. if projPath := srcPath.Child("downwardAPI"); source.DownwardAPI != nil {
  958. numSources++
  959. for _, file := range source.DownwardAPI.Items {
  960. allErrs = append(allErrs, validateDownwardAPIVolumeFile(&file, projPath)...)
  961. if len(file.Path) > 0 {
  962. curPath := file.Path
  963. if !allPaths.Has(curPath) {
  964. allPaths.Insert(curPath)
  965. } else {
  966. allErrs = append(allErrs, field.Invalid(fldPath, curPath, "conflicting duplicate paths"))
  967. }
  968. }
  969. }
  970. }
  971. if projPath := srcPath.Child("serviceAccountToken"); source.ServiceAccountToken != nil {
  972. numSources++
  973. if source.ServiceAccountToken.ExpirationSeconds < 10*60 {
  974. allErrs = append(allErrs, field.Invalid(projPath.Child("expirationSeconds"), source.ServiceAccountToken.ExpirationSeconds, "may not specify a duration less than 10 minutes"))
  975. }
  976. if source.ServiceAccountToken.ExpirationSeconds > 1<<32 {
  977. allErrs = append(allErrs, field.Invalid(projPath.Child("expirationSeconds"), source.ServiceAccountToken.ExpirationSeconds, "may not specify a duration larger than 2^32 seconds"))
  978. }
  979. if source.ServiceAccountToken.Path == "" {
  980. allErrs = append(allErrs, field.Required(fldPath.Child("path"), ""))
  981. }
  982. }
  983. if numSources > 1 {
  984. allErrs = append(allErrs, field.Forbidden(srcPath, "may not specify more than 1 volume type"))
  985. }
  986. }
  987. return allErrs
  988. }
  989. func validateProjectedVolumeSource(projection *core.ProjectedVolumeSource, fldPath *field.Path) field.ErrorList {
  990. allErrs := field.ErrorList{}
  991. projectionMode := projection.DefaultMode
  992. if projectionMode != nil && (*projectionMode > 0777 || *projectionMode < 0) {
  993. allErrs = append(allErrs, field.Invalid(fldPath.Child("defaultMode"), *projectionMode, fileModeErrorMsg))
  994. }
  995. allErrs = append(allErrs, validateProjectionSources(projection, projectionMode, fldPath)...)
  996. return allErrs
  997. }
  998. var supportedHostPathTypes = sets.NewString(
  999. string(core.HostPathUnset),
  1000. string(core.HostPathDirectoryOrCreate),
  1001. string(core.HostPathDirectory),
  1002. string(core.HostPathFileOrCreate),
  1003. string(core.HostPathFile),
  1004. string(core.HostPathSocket),
  1005. string(core.HostPathCharDev),
  1006. string(core.HostPathBlockDev))
  1007. func validateHostPathType(hostPathType *core.HostPathType, fldPath *field.Path) field.ErrorList {
  1008. allErrs := field.ErrorList{}
  1009. if hostPathType != nil && !supportedHostPathTypes.Has(string(*hostPathType)) {
  1010. allErrs = append(allErrs, field.NotSupported(fldPath, hostPathType, supportedHostPathTypes.List()))
  1011. }
  1012. return allErrs
  1013. }
  1014. // This validate will make sure targetPath:
  1015. // 1. is not abs path
  1016. // 2. does not have any element which is ".."
  1017. func validateLocalDescendingPath(targetPath string, fldPath *field.Path) field.ErrorList {
  1018. allErrs := field.ErrorList{}
  1019. if path.IsAbs(targetPath) {
  1020. allErrs = append(allErrs, field.Invalid(fldPath, targetPath, "must be a relative path"))
  1021. }
  1022. allErrs = append(allErrs, validatePathNoBacksteps(targetPath, fldPath)...)
  1023. return allErrs
  1024. }
  1025. // validatePathNoBacksteps makes sure the targetPath does not have any `..` path elements when split
  1026. //
  1027. // This assumes the OS of the apiserver and the nodes are the same. The same check should be done
  1028. // on the node to ensure there are no backsteps.
  1029. func validatePathNoBacksteps(targetPath string, fldPath *field.Path) field.ErrorList {
  1030. allErrs := field.ErrorList{}
  1031. parts := strings.Split(filepath.ToSlash(targetPath), "/")
  1032. for _, item := range parts {
  1033. if item == ".." {
  1034. allErrs = append(allErrs, field.Invalid(fldPath, targetPath, "must not contain '..'"))
  1035. break // even for `../../..`, one error is sufficient to make the point
  1036. }
  1037. }
  1038. return allErrs
  1039. }
  1040. // validateMountPropagation verifies that MountPropagation field is valid and
  1041. // allowed for given container.
  1042. func validateMountPropagation(mountPropagation *core.MountPropagationMode, container *core.Container, fldPath *field.Path) field.ErrorList {
  1043. allErrs := field.ErrorList{}
  1044. if mountPropagation == nil {
  1045. return allErrs
  1046. }
  1047. supportedMountPropagations := sets.NewString(string(core.MountPropagationBidirectional), string(core.MountPropagationHostToContainer), string(core.MountPropagationNone))
  1048. if !supportedMountPropagations.Has(string(*mountPropagation)) {
  1049. allErrs = append(allErrs, field.NotSupported(fldPath, *mountPropagation, supportedMountPropagations.List()))
  1050. }
  1051. if container == nil {
  1052. // The container is not available yet, e.g. during validation of
  1053. // PodPreset. Stop validation now, Pod validation will refuse final
  1054. // Pods with Bidirectional propagation in non-privileged containers.
  1055. return allErrs
  1056. }
  1057. privileged := container.SecurityContext != nil && container.SecurityContext.Privileged != nil && *container.SecurityContext.Privileged
  1058. if *mountPropagation == core.MountPropagationBidirectional && !privileged {
  1059. allErrs = append(allErrs, field.Forbidden(fldPath, "Bidirectional mount propagation is available only to privileged containers"))
  1060. }
  1061. return allErrs
  1062. }
  1063. // This validate will make sure targetPath:
  1064. // 1. is not abs path
  1065. // 2. does not contain any '..' elements
  1066. // 3. does not start with '..'
  1067. func validateLocalNonReservedPath(targetPath string, fldPath *field.Path) field.ErrorList {
  1068. allErrs := field.ErrorList{}
  1069. allErrs = append(allErrs, validateLocalDescendingPath(targetPath, fldPath)...)
  1070. // Don't report this error if the check for .. elements already caught it.
  1071. if strings.HasPrefix(targetPath, "..") && !strings.HasPrefix(targetPath, "../") {
  1072. allErrs = append(allErrs, field.Invalid(fldPath, targetPath, "must not start with '..'"))
  1073. }
  1074. return allErrs
  1075. }
  1076. func validateRBDVolumeSource(rbd *core.RBDVolumeSource, fldPath *field.Path) field.ErrorList {
  1077. allErrs := field.ErrorList{}
  1078. if len(rbd.CephMonitors) == 0 {
  1079. allErrs = append(allErrs, field.Required(fldPath.Child("monitors"), ""))
  1080. }
  1081. if len(rbd.RBDImage) == 0 {
  1082. allErrs = append(allErrs, field.Required(fldPath.Child("image"), ""))
  1083. }
  1084. return allErrs
  1085. }
  1086. func validateRBDPersistentVolumeSource(rbd *core.RBDPersistentVolumeSource, fldPath *field.Path) field.ErrorList {
  1087. allErrs := field.ErrorList{}
  1088. if len(rbd.CephMonitors) == 0 {
  1089. allErrs = append(allErrs, field.Required(fldPath.Child("monitors"), ""))
  1090. }
  1091. if len(rbd.RBDImage) == 0 {
  1092. allErrs = append(allErrs, field.Required(fldPath.Child("image"), ""))
  1093. }
  1094. return allErrs
  1095. }
  1096. func validateCinderVolumeSource(cd *core.CinderVolumeSource, fldPath *field.Path) field.ErrorList {
  1097. allErrs := field.ErrorList{}
  1098. if len(cd.VolumeID) == 0 {
  1099. allErrs = append(allErrs, field.Required(fldPath.Child("volumeID"), ""))
  1100. }
  1101. if cd.SecretRef != nil {
  1102. if len(cd.SecretRef.Name) == 0 {
  1103. allErrs = append(allErrs, field.Required(fldPath.Child("secretRef", "name"), ""))
  1104. }
  1105. }
  1106. return allErrs
  1107. }
  1108. func validateCinderPersistentVolumeSource(cd *core.CinderPersistentVolumeSource, fldPath *field.Path) field.ErrorList {
  1109. allErrs := field.ErrorList{}
  1110. if len(cd.VolumeID) == 0 {
  1111. allErrs = append(allErrs, field.Required(fldPath.Child("volumeID"), ""))
  1112. }
  1113. if cd.SecretRef != nil {
  1114. if len(cd.SecretRef.Name) == 0 {
  1115. allErrs = append(allErrs, field.Required(fldPath.Child("secretRef", "name"), ""))
  1116. }
  1117. if len(cd.SecretRef.Namespace) == 0 {
  1118. allErrs = append(allErrs, field.Required(fldPath.Child("secretRef", "namespace"), ""))
  1119. }
  1120. }
  1121. return allErrs
  1122. }
  1123. func validateCephFSVolumeSource(cephfs *core.CephFSVolumeSource, fldPath *field.Path) field.ErrorList {
  1124. allErrs := field.ErrorList{}
  1125. if len(cephfs.Monitors) == 0 {
  1126. allErrs = append(allErrs, field.Required(fldPath.Child("monitors"), ""))
  1127. }
  1128. return allErrs
  1129. }
  1130. func validateCephFSPersistentVolumeSource(cephfs *core.CephFSPersistentVolumeSource, fldPath *field.Path) field.ErrorList {
  1131. allErrs := field.ErrorList{}
  1132. if len(cephfs.Monitors) == 0 {
  1133. allErrs = append(allErrs, field.Required(fldPath.Child("monitors"), ""))
  1134. }
  1135. return allErrs
  1136. }
  1137. func validateFlexVolumeSource(fv *core.FlexVolumeSource, fldPath *field.Path) field.ErrorList {
  1138. allErrs := field.ErrorList{}
  1139. if len(fv.Driver) == 0 {
  1140. allErrs = append(allErrs, field.Required(fldPath.Child("driver"), ""))
  1141. }
  1142. // Make sure user-specified options don't use kubernetes namespaces
  1143. for k := range fv.Options {
  1144. namespace := k
  1145. if parts := strings.SplitN(k, "/", 2); len(parts) == 2 {
  1146. namespace = parts[0]
  1147. }
  1148. normalized := "." + strings.ToLower(namespace)
  1149. if strings.HasSuffix(normalized, ".kubernetes.io") || strings.HasSuffix(normalized, ".k8s.io") {
  1150. allErrs = append(allErrs, field.Invalid(fldPath.Child("options").Key(k), k, "kubernetes.io and k8s.io namespaces are reserved"))
  1151. }
  1152. }
  1153. return allErrs
  1154. }
  1155. func validateFlexPersistentVolumeSource(fv *core.FlexPersistentVolumeSource, fldPath *field.Path) field.ErrorList {
  1156. allErrs := field.ErrorList{}
  1157. if len(fv.Driver) == 0 {
  1158. allErrs = append(allErrs, field.Required(fldPath.Child("driver"), ""))
  1159. }
  1160. // Make sure user-specified options don't use kubernetes namespaces
  1161. for k := range fv.Options {
  1162. namespace := k
  1163. if parts := strings.SplitN(k, "/", 2); len(parts) == 2 {
  1164. namespace = parts[0]
  1165. }
  1166. normalized := "." + strings.ToLower(namespace)
  1167. if strings.HasSuffix(normalized, ".kubernetes.io") || strings.HasSuffix(normalized, ".k8s.io") {
  1168. allErrs = append(allErrs, field.Invalid(fldPath.Child("options").Key(k), k, "kubernetes.io and k8s.io namespaces are reserved"))
  1169. }
  1170. }
  1171. return allErrs
  1172. }
  1173. func validateAzureFile(azure *core.AzureFileVolumeSource, fldPath *field.Path) field.ErrorList {
  1174. allErrs := field.ErrorList{}
  1175. if azure.SecretName == "" {
  1176. allErrs = append(allErrs, field.Required(fldPath.Child("secretName"), ""))
  1177. }
  1178. if azure.ShareName == "" {
  1179. allErrs = append(allErrs, field.Required(fldPath.Child("shareName"), ""))
  1180. }
  1181. return allErrs
  1182. }
  1183. func validateAzureFilePV(azure *core.AzureFilePersistentVolumeSource, fldPath *field.Path) field.ErrorList {
  1184. allErrs := field.ErrorList{}
  1185. if azure.SecretName == "" {
  1186. allErrs = append(allErrs, field.Required(fldPath.Child("secretName"), ""))
  1187. }
  1188. if azure.ShareName == "" {
  1189. allErrs = append(allErrs, field.Required(fldPath.Child("shareName"), ""))
  1190. }
  1191. if azure.SecretNamespace != nil {
  1192. if len(*azure.SecretNamespace) == 0 {
  1193. allErrs = append(allErrs, field.Required(fldPath.Child("secretNamespace"), ""))
  1194. }
  1195. }
  1196. return allErrs
  1197. }
  1198. func validateAzureDisk(azure *core.AzureDiskVolumeSource, fldPath *field.Path) field.ErrorList {
  1199. var supportedCachingModes = sets.NewString(string(core.AzureDataDiskCachingNone), string(core.AzureDataDiskCachingReadOnly), string(core.AzureDataDiskCachingReadWrite))
  1200. var supportedDiskKinds = sets.NewString(string(core.AzureSharedBlobDisk), string(core.AzureDedicatedBlobDisk), string(core.AzureManagedDisk))
  1201. diskURISupportedManaged := []string{"/subscriptions/{sub-id}/resourcegroups/{group-name}/providers/microsoft.compute/disks/{disk-id}"}
  1202. diskURISupportedblob := []string{"https://{account-name}.blob.core.windows.net/{container-name}/{disk-name}.vhd"}
  1203. allErrs := field.ErrorList{}
  1204. if azure.DiskName == "" {
  1205. allErrs = append(allErrs, field.Required(fldPath.Child("diskName"), ""))
  1206. }
  1207. if azure.DataDiskURI == "" {
  1208. allErrs = append(allErrs, field.Required(fldPath.Child("diskURI"), ""))
  1209. }
  1210. if azure.CachingMode != nil && !supportedCachingModes.Has(string(*azure.CachingMode)) {
  1211. allErrs = append(allErrs, field.NotSupported(fldPath.Child("cachingMode"), *azure.CachingMode, supportedCachingModes.List()))
  1212. }
  1213. if azure.Kind != nil && !supportedDiskKinds.Has(string(*azure.Kind)) {
  1214. allErrs = append(allErrs, field.NotSupported(fldPath.Child("kind"), *azure.Kind, supportedDiskKinds.List()))
  1215. }
  1216. // validate that DiskUri is the correct format
  1217. if azure.Kind != nil && *azure.Kind == core.AzureManagedDisk && strings.Index(azure.DataDiskURI, "/subscriptions/") != 0 {
  1218. allErrs = append(allErrs, field.NotSupported(fldPath.Child("diskURI"), azure.DataDiskURI, diskURISupportedManaged))
  1219. }
  1220. if azure.Kind != nil && *azure.Kind != core.AzureManagedDisk && strings.Index(azure.DataDiskURI, "https://") != 0 {
  1221. allErrs = append(allErrs, field.NotSupported(fldPath.Child("diskURI"), azure.DataDiskURI, diskURISupportedblob))
  1222. }
  1223. return allErrs
  1224. }
  1225. func validateVsphereVolumeSource(cd *core.VsphereVirtualDiskVolumeSource, fldPath *field.Path) field.ErrorList {
  1226. allErrs := field.ErrorList{}
  1227. if len(cd.VolumePath) == 0 {
  1228. allErrs = append(allErrs, field.Required(fldPath.Child("volumePath"), ""))
  1229. }
  1230. return allErrs
  1231. }
  1232. func validatePhotonPersistentDiskVolumeSource(cd *core.PhotonPersistentDiskVolumeSource, fldPath *field.Path) field.ErrorList {
  1233. allErrs := field.ErrorList{}
  1234. if len(cd.PdID) == 0 {
  1235. allErrs = append(allErrs, field.Required(fldPath.Child("pdID"), ""))
  1236. }
  1237. return allErrs
  1238. }
  1239. func validatePortworxVolumeSource(pwx *core.PortworxVolumeSource, fldPath *field.Path) field.ErrorList {
  1240. allErrs := field.ErrorList{}
  1241. if len(pwx.VolumeID) == 0 {
  1242. allErrs = append(allErrs, field.Required(fldPath.Child("volumeID"), ""))
  1243. }
  1244. return allErrs
  1245. }
  1246. func validateScaleIOVolumeSource(sio *core.ScaleIOVolumeSource, fldPath *field.Path) field.ErrorList {
  1247. allErrs := field.ErrorList{}
  1248. if sio.Gateway == "" {
  1249. allErrs = append(allErrs, field.Required(fldPath.Child("gateway"), ""))
  1250. }
  1251. if sio.System == "" {
  1252. allErrs = append(allErrs, field.Required(fldPath.Child("system"), ""))
  1253. }
  1254. if sio.VolumeName == "" {
  1255. allErrs = append(allErrs, field.Required(fldPath.Child("volumeName"), ""))
  1256. }
  1257. return allErrs
  1258. }
  1259. func validateScaleIOPersistentVolumeSource(sio *core.ScaleIOPersistentVolumeSource, fldPath *field.Path) field.ErrorList {
  1260. allErrs := field.ErrorList{}
  1261. if sio.Gateway == "" {
  1262. allErrs = append(allErrs, field.Required(fldPath.Child("gateway"), ""))
  1263. }
  1264. if sio.System == "" {
  1265. allErrs = append(allErrs, field.Required(fldPath.Child("system"), ""))
  1266. }
  1267. if sio.VolumeName == "" {
  1268. allErrs = append(allErrs, field.Required(fldPath.Child("volumeName"), ""))
  1269. }
  1270. return allErrs
  1271. }
  1272. func validateLocalVolumeSource(ls *core.LocalVolumeSource, fldPath *field.Path) field.ErrorList {
  1273. allErrs := field.ErrorList{}
  1274. if ls.Path == "" {
  1275. allErrs = append(allErrs, field.Required(fldPath.Child("path"), ""))
  1276. return allErrs
  1277. }
  1278. allErrs = append(allErrs, validatePathNoBacksteps(ls.Path, fldPath.Child("path"))...)
  1279. return allErrs
  1280. }
  1281. func validateStorageOSVolumeSource(storageos *core.StorageOSVolumeSource, fldPath *field.Path) field.ErrorList {
  1282. allErrs := field.ErrorList{}
  1283. if len(storageos.VolumeName) == 0 {
  1284. allErrs = append(allErrs, field.Required(fldPath.Child("volumeName"), ""))
  1285. } else {
  1286. allErrs = append(allErrs, ValidateDNS1123Label(storageos.VolumeName, fldPath.Child("volumeName"))...)
  1287. }
  1288. if len(storageos.VolumeNamespace) > 0 {
  1289. allErrs = append(allErrs, ValidateDNS1123Label(storageos.VolumeNamespace, fldPath.Child("volumeNamespace"))...)
  1290. }
  1291. if storageos.SecretRef != nil {
  1292. if len(storageos.SecretRef.Name) == 0 {
  1293. allErrs = append(allErrs, field.Required(fldPath.Child("secretRef", "name"), ""))
  1294. }
  1295. }
  1296. return allErrs
  1297. }
  1298. func validateStorageOSPersistentVolumeSource(storageos *core.StorageOSPersistentVolumeSource, fldPath *field.Path) field.ErrorList {
  1299. allErrs := field.ErrorList{}
  1300. if len(storageos.VolumeName) == 0 {
  1301. allErrs = append(allErrs, field.Required(fldPath.Child("volumeName"), ""))
  1302. } else {
  1303. allErrs = append(allErrs, ValidateDNS1123Label(storageos.VolumeName, fldPath.Child("volumeName"))...)
  1304. }
  1305. if len(storageos.VolumeNamespace) > 0 {
  1306. allErrs = append(allErrs, ValidateDNS1123Label(storageos.VolumeNamespace, fldPath.Child("volumeNamespace"))...)
  1307. }
  1308. if storageos.SecretRef != nil {
  1309. if len(storageos.SecretRef.Name) == 0 {
  1310. allErrs = append(allErrs, field.Required(fldPath.Child("secretRef", "name"), ""))
  1311. }
  1312. if len(storageos.SecretRef.Namespace) == 0 {
  1313. allErrs = append(allErrs, field.Required(fldPath.Child("secretRef", "namespace"), ""))
  1314. }
  1315. }
  1316. return allErrs
  1317. }
  1318. func ValidateCSIDriverName(driverName string, fldPath *field.Path) field.ErrorList {
  1319. allErrs := field.ErrorList{}
  1320. if len(driverName) == 0 {
  1321. allErrs = append(allErrs, field.Required(fldPath, ""))
  1322. }
  1323. if len(driverName) > 63 {
  1324. allErrs = append(allErrs, field.TooLong(fldPath, driverName, 63))
  1325. }
  1326. for _, msg := range validation.IsDNS1123Subdomain(strings.ToLower(driverName)) {
  1327. allErrs = append(allErrs, field.Invalid(fldPath, driverName, msg))
  1328. }
  1329. return allErrs
  1330. }
  1331. func validateCSIPersistentVolumeSource(csi *core.CSIPersistentVolumeSource, fldPath *field.Path) field.ErrorList {
  1332. allErrs := field.ErrorList{}
  1333. allErrs = append(allErrs, ValidateCSIDriverName(csi.Driver, fldPath.Child("driver"))...)
  1334. if len(csi.VolumeHandle) == 0 {
  1335. allErrs = append(allErrs, field.Required(fldPath.Child("volumeHandle"), ""))
  1336. }
  1337. if csi.ControllerPublishSecretRef != nil {
  1338. if len(csi.ControllerPublishSecretRef.Name) == 0 {
  1339. allErrs = append(allErrs, field.Required(fldPath.Child("controllerPublishSecretRef", "name"), ""))
  1340. } else {
  1341. allErrs = append(allErrs, ValidateDNS1123Label(csi.ControllerPublishSecretRef.Name, fldPath.Child("name"))...)
  1342. }
  1343. if len(csi.ControllerPublishSecretRef.Namespace) == 0 {
  1344. allErrs = append(allErrs, field.Required(fldPath.Child("controllerPublishSecretRef", "namespace"), ""))
  1345. } else {
  1346. allErrs = append(allErrs, ValidateDNS1123Label(csi.ControllerPublishSecretRef.Namespace, fldPath.Child("namespace"))...)
  1347. }
  1348. }
  1349. if csi.ControllerExpandSecretRef != nil {
  1350. if len(csi.ControllerExpandSecretRef.Name) == 0 {
  1351. allErrs = append(allErrs, field.Required(fldPath.Child("controllerExpandSecretRef", "name"), ""))
  1352. } else {
  1353. allErrs = append(allErrs, ValidateDNS1123Label(csi.ControllerExpandSecretRef.Name, fldPath.Child("name"))...)
  1354. }
  1355. if len(csi.ControllerExpandSecretRef.Namespace) == 0 {
  1356. allErrs = append(allErrs, field.Required(fldPath.Child("controllerExpandSecretRef", "namespace"), ""))
  1357. } else {
  1358. allErrs = append(allErrs, ValidateDNS1123Label(csi.ControllerExpandSecretRef.Namespace, fldPath.Child("namespace"))...)
  1359. }
  1360. }
  1361. if csi.NodePublishSecretRef != nil {
  1362. if len(csi.NodePublishSecretRef.Name) == 0 {
  1363. allErrs = append(allErrs, field.Required(fldPath.Child("nodePublishSecretRef ", "name"), ""))
  1364. } else {
  1365. allErrs = append(allErrs, ValidateDNS1123Label(csi.NodePublishSecretRef.Name, fldPath.Child("name"))...)
  1366. }
  1367. if len(csi.NodePublishSecretRef.Namespace) == 0 {
  1368. allErrs = append(allErrs, field.Required(fldPath.Child("nodePublishSecretRef ", "namespace"), ""))
  1369. } else {
  1370. allErrs = append(allErrs, ValidateDNS1123Label(csi.NodePublishSecretRef.Namespace, fldPath.Child("namespace"))...)
  1371. }
  1372. }
  1373. return allErrs
  1374. }
  1375. func validateCSIVolumeSource(csi *core.CSIVolumeSource, fldPath *field.Path) field.ErrorList {
  1376. allErrs := field.ErrorList{}
  1377. allErrs = append(allErrs, ValidateCSIDriverName(csi.Driver, fldPath.Child("driver"))...)
  1378. if csi.NodePublishSecretRef != nil {
  1379. if len(csi.NodePublishSecretRef.Name) == 0 {
  1380. allErrs = append(allErrs, field.Required(fldPath.Child("nodePublishSecretRef ", "name"), ""))
  1381. } else {
  1382. for _, msg := range ValidateSecretName(csi.NodePublishSecretRef.Name, false) {
  1383. allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), csi.NodePublishSecretRef.Name, msg))
  1384. }
  1385. }
  1386. }
  1387. return allErrs
  1388. }
  1389. // ValidatePersistentVolumeName checks that a name is appropriate for a
  1390. // PersistentVolumeName object.
  1391. var ValidatePersistentVolumeName = apimachineryvalidation.NameIsDNSSubdomain
  1392. var supportedAccessModes = sets.NewString(string(core.ReadWriteOnce), string(core.ReadOnlyMany), string(core.ReadWriteMany))
  1393. var supportedReclaimPolicy = sets.NewString(string(core.PersistentVolumeReclaimDelete), string(core.PersistentVolumeReclaimRecycle), string(core.PersistentVolumeReclaimRetain))
  1394. var supportedVolumeModes = sets.NewString(string(core.PersistentVolumeBlock), string(core.PersistentVolumeFilesystem))
  1395. var supportedDataSourceAPIGroupKinds = map[schema.GroupKind]bool{
  1396. {Group: "snapshot.storage.k8s.io", Kind: "VolumeSnapshot"}: true,
  1397. {Group: "", Kind: "PersistentVolumeClaim"}: true,
  1398. }
  1399. func ValidatePersistentVolumeSpec(pvSpec *core.PersistentVolumeSpec, pvName string, validateInlinePersistentVolumeSpec bool, fldPath *field.Path) field.ErrorList {
  1400. allErrs := field.ErrorList{}
  1401. if validateInlinePersistentVolumeSpec {
  1402. if pvSpec.ClaimRef != nil {
  1403. allErrs = append(allErrs, field.Forbidden(fldPath.Child("claimRef"), "may not be specified in the context of inline volumes"))
  1404. }
  1405. if len(pvSpec.Capacity) != 0 {
  1406. allErrs = append(allErrs, field.Forbidden(fldPath.Child("capacity"), "may not be specified in the context of inline volumes"))
  1407. }
  1408. if pvSpec.CSI == nil {
  1409. allErrs = append(allErrs, field.Required(fldPath.Child("csi"), "has to be specified in the context of inline volumes"))
  1410. }
  1411. }
  1412. if len(pvSpec.AccessModes) == 0 {
  1413. allErrs = append(allErrs, field.Required(fldPath.Child("accessModes"), ""))
  1414. }
  1415. for _, mode := range pvSpec.AccessModes {
  1416. if !supportedAccessModes.Has(string(mode)) {
  1417. allErrs = append(allErrs, field.NotSupported(fldPath.Child("accessModes"), mode, supportedAccessModes.List()))
  1418. }
  1419. }
  1420. if !validateInlinePersistentVolumeSpec {
  1421. if len(pvSpec.Capacity) == 0 {
  1422. allErrs = append(allErrs, field.Required(fldPath.Child("capacity"), ""))
  1423. }
  1424. if _, ok := pvSpec.Capacity[core.ResourceStorage]; !ok || len(pvSpec.Capacity) > 1 {
  1425. allErrs = append(allErrs, field.NotSupported(fldPath.Child("capacity"), pvSpec.Capacity, []string{string(core.ResourceStorage)}))
  1426. }
  1427. capPath := fldPath.Child("capacity")
  1428. for r, qty := range pvSpec.Capacity {
  1429. allErrs = append(allErrs, validateBasicResource(qty, capPath.Key(string(r)))...)
  1430. allErrs = append(allErrs, ValidatePositiveQuantityValue(qty, capPath.Key(string(r)))...)
  1431. }
  1432. }
  1433. if len(string(pvSpec.PersistentVolumeReclaimPolicy)) > 0 {
  1434. if validateInlinePersistentVolumeSpec {
  1435. if pvSpec.PersistentVolumeReclaimPolicy != core.PersistentVolumeReclaimRetain {
  1436. allErrs = append(allErrs, field.Forbidden(fldPath.Child("persistentVolumeReclaimPolicy"), "may only be "+string(core.PersistentVolumeReclaimRetain)+" in the context of inline volumes"))
  1437. }
  1438. } else {
  1439. if !supportedReclaimPolicy.Has(string(pvSpec.PersistentVolumeReclaimPolicy)) {
  1440. allErrs = append(allErrs, field.NotSupported(fldPath.Child("persistentVolumeReclaimPolicy"), pvSpec.PersistentVolumeReclaimPolicy, supportedReclaimPolicy.List()))
  1441. }
  1442. }
  1443. }
  1444. var nodeAffinitySpecified bool
  1445. var errs field.ErrorList
  1446. if pvSpec.NodeAffinity != nil {
  1447. if validateInlinePersistentVolumeSpec {
  1448. allErrs = append(allErrs, field.Forbidden(fldPath.Child("nodeAffinity"), "may not be specified in the context of inline volumes"))
  1449. } else {
  1450. nodeAffinitySpecified, errs = validateVolumeNodeAffinity(pvSpec.NodeAffinity, fldPath.Child("nodeAffinity"))
  1451. allErrs = append(allErrs, errs...)
  1452. }
  1453. }
  1454. numVolumes := 0
  1455. if pvSpec.HostPath != nil {
  1456. if numVolumes > 0 {
  1457. allErrs = append(allErrs, field.Forbidden(fldPath.Child("hostPath"), "may not specify more than 1 volume type"))
  1458. } else {
  1459. numVolumes++
  1460. allErrs = append(allErrs, validateHostPathVolumeSource(pvSpec.HostPath, fldPath.Child("hostPath"))...)
  1461. }
  1462. }
  1463. if pvSpec.GCEPersistentDisk != nil {
  1464. if numVolumes > 0 {
  1465. allErrs = append(allErrs, field.Forbidden(fldPath.Child("gcePersistentDisk"), "may not specify more than 1 volume type"))
  1466. } else {
  1467. numVolumes++
  1468. allErrs = append(allErrs, validateGCEPersistentDiskVolumeSource(pvSpec.GCEPersistentDisk, fldPath.Child("persistentDisk"))...)
  1469. }
  1470. }
  1471. if pvSpec.AWSElasticBlockStore != nil {
  1472. if numVolumes > 0 {
  1473. allErrs = append(allErrs, field.Forbidden(fldPath.Child("awsElasticBlockStore"), "may not specify more than 1 volume type"))
  1474. } else {
  1475. numVolumes++
  1476. allErrs = append(allErrs, validateAWSElasticBlockStoreVolumeSource(pvSpec.AWSElasticBlockStore, fldPath.Child("awsElasticBlockStore"))...)
  1477. }
  1478. }
  1479. if pvSpec.Glusterfs != nil {
  1480. if numVolumes > 0 {
  1481. allErrs = append(allErrs, field.Forbidden(fldPath.Child("glusterfs"), "may not specify more than 1 volume type"))
  1482. } else {
  1483. numVolumes++
  1484. allErrs = append(allErrs, validateGlusterfsPersistentVolumeSource(pvSpec.Glusterfs, fldPath.Child("glusterfs"))...)
  1485. }
  1486. }
  1487. if pvSpec.Flocker != nil {
  1488. if numVolumes > 0 {
  1489. allErrs = append(allErrs, field.Forbidden(fldPath.Child("flocker"), "may not specify more than 1 volume type"))
  1490. } else {
  1491. numVolumes++
  1492. allErrs = append(allErrs, validateFlockerVolumeSource(pvSpec.Flocker, fldPath.Child("flocker"))...)
  1493. }
  1494. }
  1495. if pvSpec.NFS != nil {
  1496. if numVolumes > 0 {
  1497. allErrs = append(allErrs, field.Forbidden(fldPath.Child("nfs"), "may not specify more than 1 volume type"))
  1498. } else {
  1499. numVolumes++
  1500. allErrs = append(allErrs, validateNFSVolumeSource(pvSpec.NFS, fldPath.Child("nfs"))...)
  1501. }
  1502. }
  1503. if pvSpec.RBD != nil {
  1504. if numVolumes > 0 {
  1505. allErrs = append(allErrs, field.Forbidden(fldPath.Child("rbd"), "may not specify more than 1 volume type"))
  1506. } else {
  1507. numVolumes++
  1508. allErrs = append(allErrs, validateRBDPersistentVolumeSource(pvSpec.RBD, fldPath.Child("rbd"))...)
  1509. }
  1510. }
  1511. if pvSpec.Quobyte != nil {
  1512. if numVolumes > 0 {
  1513. allErrs = append(allErrs, field.Forbidden(fldPath.Child("quobyte"), "may not specify more than 1 volume type"))
  1514. } else {
  1515. numVolumes++
  1516. allErrs = append(allErrs, validateQuobyteVolumeSource(pvSpec.Quobyte, fldPath.Child("quobyte"))...)
  1517. }
  1518. }
  1519. if pvSpec.CephFS != nil {
  1520. if numVolumes > 0 {
  1521. allErrs = append(allErrs, field.Forbidden(fldPath.Child("cephFS"), "may not specify more than 1 volume type"))
  1522. } else {
  1523. numVolumes++
  1524. allErrs = append(allErrs, validateCephFSPersistentVolumeSource(pvSpec.CephFS, fldPath.Child("cephfs"))...)
  1525. }
  1526. }
  1527. if pvSpec.ISCSI != nil {
  1528. if numVolumes > 0 {
  1529. allErrs = append(allErrs, field.Forbidden(fldPath.Child("iscsi"), "may not specify more than 1 volume type"))
  1530. } else {
  1531. numVolumes++
  1532. allErrs = append(allErrs, validateISCSIPersistentVolumeSource(pvSpec.ISCSI, pvName, fldPath.Child("iscsi"))...)
  1533. }
  1534. }
  1535. if pvSpec.Cinder != nil {
  1536. if numVolumes > 0 {
  1537. allErrs = append(allErrs, field.Forbidden(fldPath.Child("cinder"), "may not specify more than 1 volume type"))
  1538. } else {
  1539. numVolumes++
  1540. allErrs = append(allErrs, validateCinderPersistentVolumeSource(pvSpec.Cinder, fldPath.Child("cinder"))...)
  1541. }
  1542. }
  1543. if pvSpec.FC != nil {
  1544. if numVolumes > 0 {
  1545. allErrs = append(allErrs, field.Forbidden(fldPath.Child("fc"), "may not specify more than 1 volume type"))
  1546. } else {
  1547. numVolumes++
  1548. allErrs = append(allErrs, validateFCVolumeSource(pvSpec.FC, fldPath.Child("fc"))...)
  1549. }
  1550. }
  1551. if pvSpec.FlexVolume != nil {
  1552. numVolumes++
  1553. allErrs = append(allErrs, validateFlexPersistentVolumeSource(pvSpec.FlexVolume, fldPath.Child("flexVolume"))...)
  1554. }
  1555. if pvSpec.AzureFile != nil {
  1556. if numVolumes > 0 {
  1557. allErrs = append(allErrs, field.Forbidden(fldPath.Child("azureFile"), "may not specify more than 1 volume type"))
  1558. } else {
  1559. numVolumes++
  1560. allErrs = append(allErrs, validateAzureFilePV(pvSpec.AzureFile, fldPath.Child("azureFile"))...)
  1561. }
  1562. }
  1563. if pvSpec.VsphereVolume != nil {
  1564. if numVolumes > 0 {
  1565. allErrs = append(allErrs, field.Forbidden(fldPath.Child("vsphereVolume"), "may not specify more than 1 volume type"))
  1566. } else {
  1567. numVolumes++
  1568. allErrs = append(allErrs, validateVsphereVolumeSource(pvSpec.VsphereVolume, fldPath.Child("vsphereVolume"))...)
  1569. }
  1570. }
  1571. if pvSpec.PhotonPersistentDisk != nil {
  1572. if numVolumes > 0 {
  1573. allErrs = append(allErrs, field.Forbidden(fldPath.Child("photonPersistentDisk"), "may not specify more than 1 volume type"))
  1574. } else {
  1575. numVolumes++
  1576. allErrs = append(allErrs, validatePhotonPersistentDiskVolumeSource(pvSpec.PhotonPersistentDisk, fldPath.Child("photonPersistentDisk"))...)
  1577. }
  1578. }
  1579. if pvSpec.PortworxVolume != nil {
  1580. if numVolumes > 0 {
  1581. allErrs = append(allErrs, field.Forbidden(fldPath.Child("portworxVolume"), "may not specify more than 1 volume type"))
  1582. } else {
  1583. numVolumes++
  1584. allErrs = append(allErrs, validatePortworxVolumeSource(pvSpec.PortworxVolume, fldPath.Child("portworxVolume"))...)
  1585. }
  1586. }
  1587. if pvSpec.AzureDisk != nil {
  1588. if numVolumes > 0 {
  1589. allErrs = append(allErrs, field.Forbidden(fldPath.Child("azureDisk"), "may not specify more than 1 volume type"))
  1590. } else {
  1591. numVolumes++
  1592. allErrs = append(allErrs, validateAzureDisk(pvSpec.AzureDisk, fldPath.Child("azureDisk"))...)
  1593. }
  1594. }
  1595. if pvSpec.ScaleIO != nil {
  1596. if numVolumes > 0 {
  1597. allErrs = append(allErrs, field.Forbidden(fldPath.Child("scaleIO"), "may not specify more than 1 volume type"))
  1598. } else {
  1599. numVolumes++
  1600. allErrs = append(allErrs, validateScaleIOPersistentVolumeSource(pvSpec.ScaleIO, fldPath.Child("scaleIO"))...)
  1601. }
  1602. }
  1603. if pvSpec.Local != nil {
  1604. if numVolumes > 0 {
  1605. allErrs = append(allErrs, field.Forbidden(fldPath.Child("local"), "may not specify more than 1 volume type"))
  1606. } else {
  1607. numVolumes++
  1608. allErrs = append(allErrs, validateLocalVolumeSource(pvSpec.Local, fldPath.Child("local"))...)
  1609. // NodeAffinity is required
  1610. if !nodeAffinitySpecified {
  1611. allErrs = append(allErrs, field.Required(fldPath.Child("nodeAffinity"), "Local volume requires node affinity"))
  1612. }
  1613. }
  1614. }
  1615. if pvSpec.StorageOS != nil {
  1616. if numVolumes > 0 {
  1617. allErrs = append(allErrs, field.Forbidden(fldPath.Child("storageos"), "may not specify more than 1 volume type"))
  1618. } else {
  1619. numVolumes++
  1620. allErrs = append(allErrs, validateStorageOSPersistentVolumeSource(pvSpec.StorageOS, fldPath.Child("storageos"))...)
  1621. }
  1622. }
  1623. if pvSpec.CSI != nil {
  1624. if numVolumes > 0 {
  1625. allErrs = append(allErrs, field.Forbidden(fldPath.Child("csi"), "may not specify more than 1 volume type"))
  1626. } else {
  1627. numVolumes++
  1628. allErrs = append(allErrs, validateCSIPersistentVolumeSource(pvSpec.CSI, fldPath.Child("csi"))...)
  1629. }
  1630. }
  1631. if numVolumes == 0 {
  1632. allErrs = append(allErrs, field.Required(fldPath, "must specify a volume type"))
  1633. }
  1634. // do not allow hostPath mounts of '/' to have a 'recycle' reclaim policy
  1635. if pvSpec.HostPath != nil && path.Clean(pvSpec.HostPath.Path) == "/" && pvSpec.PersistentVolumeReclaimPolicy == core.PersistentVolumeReclaimRecycle {
  1636. allErrs = append(allErrs, field.Forbidden(fldPath.Child("persistentVolumeReclaimPolicy"), "may not be 'recycle' for a hostPath mount of '/'"))
  1637. }
  1638. if len(pvSpec.StorageClassName) > 0 {
  1639. if validateInlinePersistentVolumeSpec {
  1640. allErrs = append(allErrs, field.Forbidden(fldPath.Child("storageClassName"), "may not be specified in the context of inline volumes"))
  1641. } else {
  1642. for _, msg := range ValidateClassName(pvSpec.StorageClassName, false) {
  1643. allErrs = append(allErrs, field.Invalid(fldPath.Child("storageClassName"), pvSpec.StorageClassName, msg))
  1644. }
  1645. }
  1646. }
  1647. if pvSpec.VolumeMode != nil {
  1648. if validateInlinePersistentVolumeSpec {
  1649. if *pvSpec.VolumeMode != core.PersistentVolumeFilesystem {
  1650. allErrs = append(allErrs, field.Forbidden(fldPath.Child("volumeMode"), "may not specify volumeMode other than "+string(core.PersistentVolumeFilesystem)+" in the context of inline volumes"))
  1651. }
  1652. } else {
  1653. if !supportedVolumeModes.Has(string(*pvSpec.VolumeMode)) {
  1654. allErrs = append(allErrs, field.NotSupported(fldPath.Child("volumeMode"), *pvSpec.VolumeMode, supportedVolumeModes.List()))
  1655. }
  1656. }
  1657. }
  1658. return allErrs
  1659. }
  1660. func ValidatePersistentVolume(pv *core.PersistentVolume) field.ErrorList {
  1661. metaPath := field.NewPath("metadata")
  1662. allErrs := ValidateObjectMeta(&pv.ObjectMeta, false, ValidatePersistentVolumeName, metaPath)
  1663. allErrs = append(allErrs, ValidatePersistentVolumeSpec(&pv.Spec, pv.ObjectMeta.Name, false, field.NewPath("spec"))...)
  1664. return allErrs
  1665. }
  1666. // ValidatePersistentVolumeUpdate tests to see if the update is legal for an end user to make.
  1667. // newPv is updated with fields that cannot be changed.
  1668. func ValidatePersistentVolumeUpdate(newPv, oldPv *core.PersistentVolume) field.ErrorList {
  1669. allErrs := ValidatePersistentVolume(newPv)
  1670. // if oldPV does not have ControllerExpandSecretRef then allow it to be set
  1671. if (oldPv.Spec.CSI != nil && oldPv.Spec.CSI.ControllerExpandSecretRef == nil) &&
  1672. (newPv.Spec.CSI != nil && newPv.Spec.CSI.ControllerExpandSecretRef != nil) {
  1673. newPv = newPv.DeepCopy()
  1674. newPv.Spec.CSI.ControllerExpandSecretRef = nil
  1675. }
  1676. // PersistentVolumeSource should be immutable after creation.
  1677. if !apiequality.Semantic.DeepEqual(newPv.Spec.PersistentVolumeSource, oldPv.Spec.PersistentVolumeSource) {
  1678. allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "persistentvolumesource"), "is immutable after creation"))
  1679. }
  1680. allErrs = append(allErrs, ValidateImmutableField(newPv.Spec.VolumeMode, oldPv.Spec.VolumeMode, field.NewPath("volumeMode"))...)
  1681. // Allow setting NodeAffinity if oldPv NodeAffinity was not set
  1682. if oldPv.Spec.NodeAffinity != nil {
  1683. allErrs = append(allErrs, ValidateImmutableField(newPv.Spec.NodeAffinity, oldPv.Spec.NodeAffinity, field.NewPath("nodeAffinity"))...)
  1684. }
  1685. return allErrs
  1686. }
  1687. // ValidatePersistentVolumeStatusUpdate tests to see if the status update is legal for an end user to make.
  1688. // newPv is updated with fields that cannot be changed.
  1689. func ValidatePersistentVolumeStatusUpdate(newPv, oldPv *core.PersistentVolume) field.ErrorList {
  1690. allErrs := ValidateObjectMetaUpdate(&newPv.ObjectMeta, &oldPv.ObjectMeta, field.NewPath("metadata"))
  1691. if len(newPv.ResourceVersion) == 0 {
  1692. allErrs = append(allErrs, field.Required(field.NewPath("resourceVersion"), ""))
  1693. }
  1694. newPv.Spec = oldPv.Spec
  1695. return allErrs
  1696. }
  1697. // ValidatePersistentVolumeClaim validates a PersistentVolumeClaim
  1698. func ValidatePersistentVolumeClaim(pvc *core.PersistentVolumeClaim) field.ErrorList {
  1699. allErrs := ValidateObjectMeta(&pvc.ObjectMeta, true, ValidatePersistentVolumeName, field.NewPath("metadata"))
  1700. allErrs = append(allErrs, ValidatePersistentVolumeClaimSpec(&pvc.Spec, field.NewPath("spec"))...)
  1701. return allErrs
  1702. }
  1703. // ValidatePersistentVolumeClaimSpec validates a PersistentVolumeClaimSpec
  1704. func ValidatePersistentVolumeClaimSpec(spec *core.PersistentVolumeClaimSpec, fldPath *field.Path) field.ErrorList {
  1705. allErrs := field.ErrorList{}
  1706. if len(spec.AccessModes) == 0 {
  1707. allErrs = append(allErrs, field.Required(fldPath.Child("accessModes"), "at least 1 access mode is required"))
  1708. }
  1709. if spec.Selector != nil {
  1710. allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(spec.Selector, fldPath.Child("selector"))...)
  1711. }
  1712. for _, mode := range spec.AccessModes {
  1713. if mode != core.ReadWriteOnce && mode != core.ReadOnlyMany && mode != core.ReadWriteMany {
  1714. allErrs = append(allErrs, field.NotSupported(fldPath.Child("accessModes"), mode, supportedAccessModes.List()))
  1715. }
  1716. }
  1717. storageValue, ok := spec.Resources.Requests[core.ResourceStorage]
  1718. if !ok {
  1719. allErrs = append(allErrs, field.Required(fldPath.Child("resources").Key(string(core.ResourceStorage)), ""))
  1720. } else if errs := ValidatePositiveQuantityValue(storageValue, fldPath.Child("resources").Key(string(core.ResourceStorage))); len(errs) > 0 {
  1721. allErrs = append(allErrs, errs...)
  1722. } else {
  1723. allErrs = append(allErrs, ValidateResourceQuantityValue(string(core.ResourceStorage), storageValue, fldPath.Child("resources").Key(string(core.ResourceStorage)))...)
  1724. }
  1725. if spec.StorageClassName != nil && len(*spec.StorageClassName) > 0 {
  1726. for _, msg := range ValidateClassName(*spec.StorageClassName, false) {
  1727. allErrs = append(allErrs, field.Invalid(fldPath.Child("storageClassName"), *spec.StorageClassName, msg))
  1728. }
  1729. }
  1730. if spec.VolumeMode != nil && !supportedVolumeModes.Has(string(*spec.VolumeMode)) {
  1731. allErrs = append(allErrs, field.NotSupported(fldPath.Child("volumeMode"), *spec.VolumeMode, supportedVolumeModes.List()))
  1732. }
  1733. if spec.DataSource != nil {
  1734. if len(spec.DataSource.Name) == 0 {
  1735. allErrs = append(allErrs, field.Required(fldPath.Child("dataSource", "name"), ""))
  1736. }
  1737. groupKind := schema.GroupKind{Group: "", Kind: spec.DataSource.Kind}
  1738. if spec.DataSource.APIGroup != nil {
  1739. groupKind.Group = string(*spec.DataSource.APIGroup)
  1740. }
  1741. groupKindList := make([]string, 0, len(supportedDataSourceAPIGroupKinds))
  1742. for grp := range supportedDataSourceAPIGroupKinds {
  1743. groupKindList = append(groupKindList, grp.String())
  1744. }
  1745. if !supportedDataSourceAPIGroupKinds[groupKind] {
  1746. allErrs = append(allErrs, field.NotSupported(fldPath.Child("dataSource"), groupKind.String(), groupKindList))
  1747. }
  1748. }
  1749. return allErrs
  1750. }
  1751. // ValidatePersistentVolumeClaimUpdate validates an update to a PersistentVolumeClaim
  1752. func ValidatePersistentVolumeClaimUpdate(newPvc, oldPvc *core.PersistentVolumeClaim) field.ErrorList {
  1753. allErrs := ValidateObjectMetaUpdate(&newPvc.ObjectMeta, &oldPvc.ObjectMeta, field.NewPath("metadata"))
  1754. allErrs = append(allErrs, ValidatePersistentVolumeClaim(newPvc)...)
  1755. newPvcClone := newPvc.DeepCopy()
  1756. oldPvcClone := oldPvc.DeepCopy()
  1757. // PVController needs to update PVC.Spec w/ VolumeName.
  1758. // Claims are immutable in order to enforce quota, range limits, etc. without gaming the system.
  1759. if len(oldPvc.Spec.VolumeName) == 0 {
  1760. // volumeName changes are allowed once.
  1761. oldPvcClone.Spec.VolumeName = newPvcClone.Spec.VolumeName
  1762. }
  1763. if validateStorageClassUpgrade(oldPvcClone.Annotations, newPvcClone.Annotations,
  1764. oldPvcClone.Spec.StorageClassName, newPvcClone.Spec.StorageClassName) {
  1765. newPvcClone.Spec.StorageClassName = nil
  1766. metav1.SetMetaDataAnnotation(&newPvcClone.ObjectMeta, core.BetaStorageClassAnnotation, oldPvcClone.Annotations[core.BetaStorageClassAnnotation])
  1767. } else {
  1768. // storageclass annotation should be immutable after creation
  1769. // TODO: remove Beta when no longer needed
  1770. allErrs = append(allErrs, ValidateImmutableAnnotation(newPvc.ObjectMeta.Annotations[v1.BetaStorageClassAnnotation], oldPvc.ObjectMeta.Annotations[v1.BetaStorageClassAnnotation], v1.BetaStorageClassAnnotation, field.NewPath("metadata"))...)
  1771. }
  1772. if utilfeature.DefaultFeatureGate.Enabled(features.ExpandPersistentVolumes) {
  1773. // lets make sure storage values are same.
  1774. if newPvc.Status.Phase == core.ClaimBound && newPvcClone.Spec.Resources.Requests != nil {
  1775. newPvcClone.Spec.Resources.Requests["storage"] = oldPvc.Spec.Resources.Requests["storage"]
  1776. }
  1777. oldSize := oldPvc.Spec.Resources.Requests["storage"]
  1778. newSize := newPvc.Spec.Resources.Requests["storage"]
  1779. if !apiequality.Semantic.DeepEqual(newPvcClone.Spec, oldPvcClone.Spec) {
  1780. allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "is immutable after creation except resources.requests for bound claims"))
  1781. }
  1782. if newSize.Cmp(oldSize) < 0 {
  1783. allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "resources", "requests", "storage"), "field can not be less than previous value"))
  1784. }
  1785. } else {
  1786. // changes to Spec are not allowed, but updates to label/and some annotations are OK.
  1787. // no-op updates pass validation.
  1788. if !apiequality.Semantic.DeepEqual(newPvcClone.Spec, oldPvcClone.Spec) {
  1789. allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "field is immutable after creation"))
  1790. }
  1791. }
  1792. allErrs = append(allErrs, ValidateImmutableField(newPvc.Spec.VolumeMode, oldPvc.Spec.VolumeMode, field.NewPath("volumeMode"))...)
  1793. return allErrs
  1794. }
  1795. // Provide an upgrade path from PVC with storage class specified in beta
  1796. // annotation to storage class specified in attribute. We allow update of
  1797. // StorageClassName only if following four conditions are met at the same time:
  1798. // 1. The old pvc's StorageClassAnnotation is set
  1799. // 2. The old pvc's StorageClassName is not set
  1800. // 3. The new pvc's StorageClassName is set and equal to the old value in annotation
  1801. // 4. If the new pvc's StorageClassAnnotation is set,it must be equal to the old pv/pvc's StorageClassAnnotation
  1802. func validateStorageClassUpgrade(oldAnnotations, newAnnotations map[string]string, oldScName, newScName *string) bool {
  1803. oldSc, oldAnnotationExist := oldAnnotations[core.BetaStorageClassAnnotation]
  1804. newScInAnnotation, newAnnotationExist := newAnnotations[core.BetaStorageClassAnnotation]
  1805. return oldAnnotationExist /* condition 1 */ &&
  1806. oldScName == nil /* condition 2*/ &&
  1807. (newScName != nil && *newScName == oldSc) /* condition 3 */ &&
  1808. (!newAnnotationExist || newScInAnnotation == oldSc) /* condition 4 */
  1809. }
  1810. // ValidatePersistentVolumeClaimStatusUpdate validates an update to status of a PersistentVolumeClaim
  1811. func ValidatePersistentVolumeClaimStatusUpdate(newPvc, oldPvc *core.PersistentVolumeClaim) field.ErrorList {
  1812. allErrs := ValidateObjectMetaUpdate(&newPvc.ObjectMeta, &oldPvc.ObjectMeta, field.NewPath("metadata"))
  1813. if len(newPvc.ResourceVersion) == 0 {
  1814. allErrs = append(allErrs, field.Required(field.NewPath("resourceVersion"), ""))
  1815. }
  1816. if len(newPvc.Spec.AccessModes) == 0 {
  1817. allErrs = append(allErrs, field.Required(field.NewPath("Spec", "accessModes"), ""))
  1818. }
  1819. capPath := field.NewPath("status", "capacity")
  1820. for r, qty := range newPvc.Status.Capacity {
  1821. allErrs = append(allErrs, validateBasicResource(qty, capPath.Key(string(r)))...)
  1822. }
  1823. newPvc.Spec = oldPvc.Spec
  1824. return allErrs
  1825. }
  1826. var supportedPortProtocols = sets.NewString(string(core.ProtocolTCP), string(core.ProtocolUDP), string(core.ProtocolSCTP))
  1827. func validateContainerPorts(ports []core.ContainerPort, fldPath *field.Path) field.ErrorList {
  1828. allErrs := field.ErrorList{}
  1829. allNames := sets.String{}
  1830. for i, port := range ports {
  1831. idxPath := fldPath.Index(i)
  1832. if len(port.Name) > 0 {
  1833. if msgs := validation.IsValidPortName(port.Name); len(msgs) != 0 {
  1834. for i = range msgs {
  1835. allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), port.Name, msgs[i]))
  1836. }
  1837. } else if allNames.Has(port.Name) {
  1838. allErrs = append(allErrs, field.Duplicate(idxPath.Child("name"), port.Name))
  1839. } else {
  1840. allNames.Insert(port.Name)
  1841. }
  1842. }
  1843. if port.ContainerPort == 0 {
  1844. allErrs = append(allErrs, field.Required(idxPath.Child("containerPort"), ""))
  1845. } else {
  1846. for _, msg := range validation.IsValidPortNum(int(port.ContainerPort)) {
  1847. allErrs = append(allErrs, field.Invalid(idxPath.Child("containerPort"), port.ContainerPort, msg))
  1848. }
  1849. }
  1850. if port.HostPort != 0 {
  1851. for _, msg := range validation.IsValidPortNum(int(port.HostPort)) {
  1852. allErrs = append(allErrs, field.Invalid(idxPath.Child("hostPort"), port.HostPort, msg))
  1853. }
  1854. }
  1855. if len(port.Protocol) == 0 {
  1856. allErrs = append(allErrs, field.Required(idxPath.Child("protocol"), ""))
  1857. } else if !supportedPortProtocols.Has(string(port.Protocol)) {
  1858. allErrs = append(allErrs, field.NotSupported(idxPath.Child("protocol"), port.Protocol, supportedPortProtocols.List()))
  1859. }
  1860. }
  1861. return allErrs
  1862. }
  1863. // ValidateEnv validates env vars
  1864. func ValidateEnv(vars []core.EnvVar, fldPath *field.Path) field.ErrorList {
  1865. allErrs := field.ErrorList{}
  1866. for i, ev := range vars {
  1867. idxPath := fldPath.Index(i)
  1868. if len(ev.Name) == 0 {
  1869. allErrs = append(allErrs, field.Required(idxPath.Child("name"), ""))
  1870. } else {
  1871. for _, msg := range validation.IsEnvVarName(ev.Name) {
  1872. allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), ev.Name, msg))
  1873. }
  1874. }
  1875. allErrs = append(allErrs, validateEnvVarValueFrom(ev, idxPath.Child("valueFrom"))...)
  1876. }
  1877. return allErrs
  1878. }
  1879. var validEnvDownwardAPIFieldPathExpressions = sets.NewString(
  1880. "metadata.name",
  1881. "metadata.namespace",
  1882. "metadata.uid",
  1883. "spec.nodeName",
  1884. "spec.serviceAccountName",
  1885. "status.hostIP",
  1886. "status.podIP",
  1887. // status.podIPs is populated even if IPv6DualStack feature gate
  1888. // is not enabled. This will work for single stack and dual stack.
  1889. "status.podIPs")
  1890. var validContainerResourceFieldPathExpressions = sets.NewString("limits.cpu", "limits.memory", "limits.ephemeral-storage", "requests.cpu", "requests.memory", "requests.ephemeral-storage")
  1891. func validateEnvVarValueFrom(ev core.EnvVar, fldPath *field.Path) field.ErrorList {
  1892. allErrs := field.ErrorList{}
  1893. if ev.ValueFrom == nil {
  1894. return allErrs
  1895. }
  1896. numSources := 0
  1897. if ev.ValueFrom.FieldRef != nil {
  1898. numSources++
  1899. allErrs = append(allErrs, validateObjectFieldSelector(ev.ValueFrom.FieldRef, &validEnvDownwardAPIFieldPathExpressions, fldPath.Child("fieldRef"))...)
  1900. }
  1901. if ev.ValueFrom.ResourceFieldRef != nil {
  1902. numSources++
  1903. allErrs = append(allErrs, validateContainerResourceFieldSelector(ev.ValueFrom.ResourceFieldRef, &validContainerResourceFieldPathExpressions, fldPath.Child("resourceFieldRef"), false)...)
  1904. }
  1905. if ev.ValueFrom.ConfigMapKeyRef != nil {
  1906. numSources++
  1907. allErrs = append(allErrs, validateConfigMapKeySelector(ev.ValueFrom.ConfigMapKeyRef, fldPath.Child("configMapKeyRef"))...)
  1908. }
  1909. if ev.ValueFrom.SecretKeyRef != nil {
  1910. numSources++
  1911. allErrs = append(allErrs, validateSecretKeySelector(ev.ValueFrom.SecretKeyRef, fldPath.Child("secretKeyRef"))...)
  1912. }
  1913. if numSources == 0 {
  1914. allErrs = append(allErrs, field.Invalid(fldPath, "", "must specify one of: `fieldRef`, `resourceFieldRef`, `configMapKeyRef` or `secretKeyRef`"))
  1915. } else if len(ev.Value) != 0 {
  1916. if numSources != 0 {
  1917. allErrs = append(allErrs, field.Invalid(fldPath, "", "may not be specified when `value` is not empty"))
  1918. }
  1919. } else if numSources > 1 {
  1920. allErrs = append(allErrs, field.Invalid(fldPath, "", "may not have more than one field specified at a time"))
  1921. }
  1922. return allErrs
  1923. }
  1924. func validateObjectFieldSelector(fs *core.ObjectFieldSelector, expressions *sets.String, fldPath *field.Path) field.ErrorList {
  1925. allErrs := field.ErrorList{}
  1926. if len(fs.APIVersion) == 0 {
  1927. allErrs = append(allErrs, field.Required(fldPath.Child("apiVersion"), ""))
  1928. return allErrs
  1929. }
  1930. if len(fs.FieldPath) == 0 {
  1931. allErrs = append(allErrs, field.Required(fldPath.Child("fieldPath"), ""))
  1932. return allErrs
  1933. }
  1934. internalFieldPath, _, err := podshelper.ConvertDownwardAPIFieldLabel(fs.APIVersion, fs.FieldPath, "")
  1935. if err != nil {
  1936. allErrs = append(allErrs, field.Invalid(fldPath.Child("fieldPath"), fs.FieldPath, fmt.Sprintf("error converting fieldPath: %v", err)))
  1937. return allErrs
  1938. }
  1939. if path, subscript, ok := fieldpath.SplitMaybeSubscriptedPath(internalFieldPath); ok {
  1940. switch path {
  1941. case "metadata.annotations":
  1942. for _, msg := range validation.IsQualifiedName(strings.ToLower(subscript)) {
  1943. allErrs = append(allErrs, field.Invalid(fldPath, subscript, msg))
  1944. }
  1945. case "metadata.labels":
  1946. for _, msg := range validation.IsQualifiedName(subscript) {
  1947. allErrs = append(allErrs, field.Invalid(fldPath, subscript, msg))
  1948. }
  1949. default:
  1950. allErrs = append(allErrs, field.Invalid(fldPath, path, "does not support subscript"))
  1951. }
  1952. } else if !expressions.Has(path) {
  1953. allErrs = append(allErrs, field.NotSupported(fldPath.Child("fieldPath"), path, expressions.List()))
  1954. return allErrs
  1955. }
  1956. return allErrs
  1957. }
  1958. func validateContainerResourceFieldSelector(fs *core.ResourceFieldSelector, expressions *sets.String, fldPath *field.Path, volume bool) field.ErrorList {
  1959. allErrs := field.ErrorList{}
  1960. if volume && len(fs.ContainerName) == 0 {
  1961. allErrs = append(allErrs, field.Required(fldPath.Child("containerName"), ""))
  1962. } else if len(fs.Resource) == 0 {
  1963. allErrs = append(allErrs, field.Required(fldPath.Child("resource"), ""))
  1964. } else if !expressions.Has(fs.Resource) {
  1965. allErrs = append(allErrs, field.NotSupported(fldPath.Child("resource"), fs.Resource, expressions.List()))
  1966. }
  1967. allErrs = append(allErrs, validateContainerResourceDivisor(fs.Resource, fs.Divisor, fldPath)...)
  1968. return allErrs
  1969. }
  1970. func ValidateEnvFrom(vars []core.EnvFromSource, fldPath *field.Path) field.ErrorList {
  1971. allErrs := field.ErrorList{}
  1972. for i, ev := range vars {
  1973. idxPath := fldPath.Index(i)
  1974. if len(ev.Prefix) > 0 {
  1975. for _, msg := range validation.IsEnvVarName(ev.Prefix) {
  1976. allErrs = append(allErrs, field.Invalid(idxPath.Child("prefix"), ev.Prefix, msg))
  1977. }
  1978. }
  1979. numSources := 0
  1980. if ev.ConfigMapRef != nil {
  1981. numSources++
  1982. allErrs = append(allErrs, validateConfigMapEnvSource(ev.ConfigMapRef, idxPath.Child("configMapRef"))...)
  1983. }
  1984. if ev.SecretRef != nil {
  1985. numSources++
  1986. allErrs = append(allErrs, validateSecretEnvSource(ev.SecretRef, idxPath.Child("secretRef"))...)
  1987. }
  1988. if numSources == 0 {
  1989. allErrs = append(allErrs, field.Invalid(fldPath, "", "must specify one of: `configMapRef` or `secretRef`"))
  1990. } else if numSources > 1 {
  1991. allErrs = append(allErrs, field.Invalid(fldPath, "", "may not have more than one field specified at a time"))
  1992. }
  1993. }
  1994. return allErrs
  1995. }
  1996. func validateConfigMapEnvSource(configMapSource *core.ConfigMapEnvSource, fldPath *field.Path) field.ErrorList {
  1997. allErrs := field.ErrorList{}
  1998. if len(configMapSource.Name) == 0 {
  1999. allErrs = append(allErrs, field.Required(fldPath.Child("name"), ""))
  2000. } else {
  2001. for _, msg := range ValidateConfigMapName(configMapSource.Name, true) {
  2002. allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), configMapSource.Name, msg))
  2003. }
  2004. }
  2005. return allErrs
  2006. }
  2007. func validateSecretEnvSource(secretSource *core.SecretEnvSource, fldPath *field.Path) field.ErrorList {
  2008. allErrs := field.ErrorList{}
  2009. if len(secretSource.Name) == 0 {
  2010. allErrs = append(allErrs, field.Required(fldPath.Child("name"), ""))
  2011. } else {
  2012. for _, msg := range ValidateSecretName(secretSource.Name, true) {
  2013. allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), secretSource.Name, msg))
  2014. }
  2015. }
  2016. return allErrs
  2017. }
  2018. var validContainerResourceDivisorForCPU = sets.NewString("1m", "1")
  2019. var validContainerResourceDivisorForMemory = sets.NewString("1", "1k", "1M", "1G", "1T", "1P", "1E", "1Ki", "1Mi", "1Gi", "1Ti", "1Pi", "1Ei")
  2020. var validContainerResourceDivisorForEphemeralStorage = sets.NewString("1", "1k", "1M", "1G", "1T", "1P", "1E", "1Ki", "1Mi", "1Gi", "1Ti", "1Pi", "1Ei")
  2021. func validateContainerResourceDivisor(rName string, divisor resource.Quantity, fldPath *field.Path) field.ErrorList {
  2022. allErrs := field.ErrorList{}
  2023. unsetDivisor := resource.Quantity{}
  2024. if unsetDivisor.Cmp(divisor) == 0 {
  2025. return allErrs
  2026. }
  2027. switch rName {
  2028. case "limits.cpu", "requests.cpu":
  2029. if !validContainerResourceDivisorForCPU.Has(divisor.String()) {
  2030. allErrs = append(allErrs, field.Invalid(fldPath.Child("divisor"), rName, "only divisor's values 1m and 1 are supported with the cpu resource"))
  2031. }
  2032. case "limits.memory", "requests.memory":
  2033. if !validContainerResourceDivisorForMemory.Has(divisor.String()) {
  2034. allErrs = append(allErrs, field.Invalid(fldPath.Child("divisor"), rName, "only divisor's values 1, 1k, 1M, 1G, 1T, 1P, 1E, 1Ki, 1Mi, 1Gi, 1Ti, 1Pi, 1Ei are supported with the memory resource"))
  2035. }
  2036. case "limits.ephemeral-storage", "requests.ephemeral-storage":
  2037. if !validContainerResourceDivisorForEphemeralStorage.Has(divisor.String()) {
  2038. allErrs = append(allErrs, field.Invalid(fldPath.Child("divisor"), rName, "only divisor's values 1, 1k, 1M, 1G, 1T, 1P, 1E, 1Ki, 1Mi, 1Gi, 1Ti, 1Pi, 1Ei are supported with the local ephemeral storage resource"))
  2039. }
  2040. }
  2041. return allErrs
  2042. }
  2043. func validateConfigMapKeySelector(s *core.ConfigMapKeySelector, fldPath *field.Path) field.ErrorList {
  2044. allErrs := field.ErrorList{}
  2045. nameFn := ValidateNameFunc(ValidateSecretName)
  2046. for _, msg := range nameFn(s.Name, false) {
  2047. allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), s.Name, msg))
  2048. }
  2049. if len(s.Key) == 0 {
  2050. allErrs = append(allErrs, field.Required(fldPath.Child("key"), ""))
  2051. } else {
  2052. for _, msg := range validation.IsConfigMapKey(s.Key) {
  2053. allErrs = append(allErrs, field.Invalid(fldPath.Child("key"), s.Key, msg))
  2054. }
  2055. }
  2056. return allErrs
  2057. }
  2058. func validateSecretKeySelector(s *core.SecretKeySelector, fldPath *field.Path) field.ErrorList {
  2059. allErrs := field.ErrorList{}
  2060. nameFn := ValidateNameFunc(ValidateSecretName)
  2061. for _, msg := range nameFn(s.Name, false) {
  2062. allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), s.Name, msg))
  2063. }
  2064. if len(s.Key) == 0 {
  2065. allErrs = append(allErrs, field.Required(fldPath.Child("key"), ""))
  2066. } else {
  2067. for _, msg := range validation.IsConfigMapKey(s.Key) {
  2068. allErrs = append(allErrs, field.Invalid(fldPath.Child("key"), s.Key, msg))
  2069. }
  2070. }
  2071. return allErrs
  2072. }
  2073. func GetVolumeMountMap(mounts []core.VolumeMount) map[string]string {
  2074. volmounts := make(map[string]string)
  2075. for _, mnt := range mounts {
  2076. volmounts[mnt.Name] = mnt.MountPath
  2077. }
  2078. return volmounts
  2079. }
  2080. func GetVolumeDeviceMap(devices []core.VolumeDevice) map[string]string {
  2081. voldevices := make(map[string]string)
  2082. for _, dev := range devices {
  2083. voldevices[dev.Name] = dev.DevicePath
  2084. }
  2085. return voldevices
  2086. }
  2087. func ValidateVolumeMounts(mounts []core.VolumeMount, voldevices map[string]string, volumes map[string]core.VolumeSource, container *core.Container, fldPath *field.Path) field.ErrorList {
  2088. allErrs := field.ErrorList{}
  2089. mountpoints := sets.NewString()
  2090. for i, mnt := range mounts {
  2091. idxPath := fldPath.Index(i)
  2092. if len(mnt.Name) == 0 {
  2093. allErrs = append(allErrs, field.Required(idxPath.Child("name"), ""))
  2094. }
  2095. if !IsMatchedVolume(mnt.Name, volumes) {
  2096. allErrs = append(allErrs, field.NotFound(idxPath.Child("name"), mnt.Name))
  2097. }
  2098. if len(mnt.MountPath) == 0 {
  2099. allErrs = append(allErrs, field.Required(idxPath.Child("mountPath"), ""))
  2100. }
  2101. if mountpoints.Has(mnt.MountPath) {
  2102. allErrs = append(allErrs, field.Invalid(idxPath.Child("mountPath"), mnt.MountPath, "must be unique"))
  2103. }
  2104. mountpoints.Insert(mnt.MountPath)
  2105. // check for overlap with VolumeDevice
  2106. if mountNameAlreadyExists(mnt.Name, voldevices) {
  2107. allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), mnt.Name, "must not already exist in volumeDevices"))
  2108. }
  2109. if mountPathAlreadyExists(mnt.MountPath, voldevices) {
  2110. allErrs = append(allErrs, field.Invalid(idxPath.Child("mountPath"), mnt.MountPath, "must not already exist as a path in volumeDevices"))
  2111. }
  2112. if len(mnt.SubPath) > 0 {
  2113. allErrs = append(allErrs, validateLocalDescendingPath(mnt.SubPath, fldPath.Child("subPath"))...)
  2114. }
  2115. if len(mnt.SubPathExpr) > 0 {
  2116. if len(mnt.SubPath) > 0 {
  2117. allErrs = append(allErrs, field.Invalid(idxPath.Child("subPathExpr"), mnt.SubPathExpr, "subPathExpr and subPath are mutually exclusive"))
  2118. }
  2119. allErrs = append(allErrs, validateLocalDescendingPath(mnt.SubPathExpr, fldPath.Child("subPathExpr"))...)
  2120. }
  2121. if mnt.MountPropagation != nil {
  2122. allErrs = append(allErrs, validateMountPropagation(mnt.MountPropagation, container, fldPath.Child("mountPropagation"))...)
  2123. }
  2124. }
  2125. return allErrs
  2126. }
  2127. func ValidateVolumeDevices(devices []core.VolumeDevice, volmounts map[string]string, volumes map[string]core.VolumeSource, fldPath *field.Path) field.ErrorList {
  2128. allErrs := field.ErrorList{}
  2129. devicepath := sets.NewString()
  2130. devicename := sets.NewString()
  2131. for i, dev := range devices {
  2132. idxPath := fldPath.Index(i)
  2133. devName := dev.Name
  2134. devPath := dev.DevicePath
  2135. didMatch, isPVC := isMatchedDevice(devName, volumes)
  2136. if len(devName) == 0 {
  2137. allErrs = append(allErrs, field.Required(idxPath.Child("name"), ""))
  2138. }
  2139. if devicename.Has(devName) {
  2140. allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), devName, "must be unique"))
  2141. }
  2142. // Must be PersistentVolumeClaim volume source
  2143. if didMatch && !isPVC {
  2144. allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), devName, "can only use volume source type of PersistentVolumeClaim for block mode"))
  2145. }
  2146. if !didMatch {
  2147. allErrs = append(allErrs, field.NotFound(idxPath.Child("name"), devName))
  2148. }
  2149. if len(devPath) == 0 {
  2150. allErrs = append(allErrs, field.Required(idxPath.Child("devicePath"), ""))
  2151. }
  2152. if devicepath.Has(devPath) {
  2153. allErrs = append(allErrs, field.Invalid(idxPath.Child("devicePath"), devPath, "must be unique"))
  2154. }
  2155. if len(devPath) > 0 && len(validatePathNoBacksteps(devPath, fldPath.Child("devicePath"))) > 0 {
  2156. allErrs = append(allErrs, field.Invalid(idxPath.Child("devicePath"), devPath, "can not contain backsteps ('..')"))
  2157. } else {
  2158. devicepath.Insert(devPath)
  2159. }
  2160. // check for overlap with VolumeMount
  2161. if deviceNameAlreadyExists(devName, volmounts) {
  2162. allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), devName, "must not already exist in volumeMounts"))
  2163. }
  2164. if devicePathAlreadyExists(devPath, volmounts) {
  2165. allErrs = append(allErrs, field.Invalid(idxPath.Child("devicePath"), devPath, "must not already exist as a path in volumeMounts"))
  2166. }
  2167. if len(devName) > 0 {
  2168. devicename.Insert(devName)
  2169. }
  2170. }
  2171. return allErrs
  2172. }
  2173. func validateProbe(probe *core.Probe, fldPath *field.Path) field.ErrorList {
  2174. allErrs := field.ErrorList{}
  2175. if probe == nil {
  2176. return allErrs
  2177. }
  2178. allErrs = append(allErrs, validateHandler(&probe.Handler, fldPath)...)
  2179. allErrs = append(allErrs, ValidateNonnegativeField(int64(probe.InitialDelaySeconds), fldPath.Child("initialDelaySeconds"))...)
  2180. allErrs = append(allErrs, ValidateNonnegativeField(int64(probe.TimeoutSeconds), fldPath.Child("timeoutSeconds"))...)
  2181. allErrs = append(allErrs, ValidateNonnegativeField(int64(probe.PeriodSeconds), fldPath.Child("periodSeconds"))...)
  2182. allErrs = append(allErrs, ValidateNonnegativeField(int64(probe.SuccessThreshold), fldPath.Child("successThreshold"))...)
  2183. allErrs = append(allErrs, ValidateNonnegativeField(int64(probe.FailureThreshold), fldPath.Child("failureThreshold"))...)
  2184. return allErrs
  2185. }
  2186. func validateClientIPAffinityConfig(config *core.SessionAffinityConfig, fldPath *field.Path) field.ErrorList {
  2187. allErrs := field.ErrorList{}
  2188. if config == nil {
  2189. allErrs = append(allErrs, field.Required(fldPath, fmt.Sprintf("when session affinity type is %s", core.ServiceAffinityClientIP)))
  2190. return allErrs
  2191. }
  2192. if config.ClientIP == nil {
  2193. allErrs = append(allErrs, field.Required(fldPath.Child("clientIP"), fmt.Sprintf("when session affinity type is %s", core.ServiceAffinityClientIP)))
  2194. return allErrs
  2195. }
  2196. if config.ClientIP.TimeoutSeconds == nil {
  2197. allErrs = append(allErrs, field.Required(fldPath.Child("clientIP").Child("timeoutSeconds"), fmt.Sprintf("when session affinity type is %s", core.ServiceAffinityClientIP)))
  2198. return allErrs
  2199. }
  2200. allErrs = append(allErrs, validateAffinityTimeout(config.ClientIP.TimeoutSeconds, fldPath.Child("clientIP").Child("timeoutSeconds"))...)
  2201. return allErrs
  2202. }
  2203. func validateAffinityTimeout(timeout *int32, fldPath *field.Path) field.ErrorList {
  2204. allErrs := field.ErrorList{}
  2205. if *timeout <= 0 || *timeout > core.MaxClientIPServiceAffinitySeconds {
  2206. allErrs = append(allErrs, field.Invalid(fldPath, timeout, fmt.Sprintf("must be greater than 0 and less than %d", core.MaxClientIPServiceAffinitySeconds)))
  2207. }
  2208. return allErrs
  2209. }
  2210. // AccumulateUniqueHostPorts extracts each HostPort of each Container,
  2211. // accumulating the results and returning an error if any ports conflict.
  2212. func AccumulateUniqueHostPorts(containers []core.Container, accumulator *sets.String, fldPath *field.Path) field.ErrorList {
  2213. allErrs := field.ErrorList{}
  2214. for ci, ctr := range containers {
  2215. idxPath := fldPath.Index(ci)
  2216. portsPath := idxPath.Child("ports")
  2217. for pi := range ctr.Ports {
  2218. idxPath := portsPath.Index(pi)
  2219. port := ctr.Ports[pi].HostPort
  2220. if port == 0 {
  2221. continue
  2222. }
  2223. str := fmt.Sprintf("%s/%s/%d", ctr.Ports[pi].Protocol, ctr.Ports[pi].HostIP, port)
  2224. if accumulator.Has(str) {
  2225. allErrs = append(allErrs, field.Duplicate(idxPath.Child("hostPort"), str))
  2226. } else {
  2227. accumulator.Insert(str)
  2228. }
  2229. }
  2230. }
  2231. return allErrs
  2232. }
  2233. // checkHostPortConflicts checks for colliding Port.HostPort values across
  2234. // a slice of containers.
  2235. func checkHostPortConflicts(containers []core.Container, fldPath *field.Path) field.ErrorList {
  2236. allPorts := sets.String{}
  2237. return AccumulateUniqueHostPorts(containers, &allPorts, fldPath)
  2238. }
  2239. func validateExecAction(exec *core.ExecAction, fldPath *field.Path) field.ErrorList {
  2240. allErrors := field.ErrorList{}
  2241. if len(exec.Command) == 0 {
  2242. allErrors = append(allErrors, field.Required(fldPath.Child("command"), ""))
  2243. }
  2244. return allErrors
  2245. }
  2246. var supportedHTTPSchemes = sets.NewString(string(core.URISchemeHTTP), string(core.URISchemeHTTPS))
  2247. func validateHTTPGetAction(http *core.HTTPGetAction, fldPath *field.Path) field.ErrorList {
  2248. allErrors := field.ErrorList{}
  2249. if len(http.Path) == 0 {
  2250. allErrors = append(allErrors, field.Required(fldPath.Child("path"), ""))
  2251. }
  2252. allErrors = append(allErrors, ValidatePortNumOrName(http.Port, fldPath.Child("port"))...)
  2253. if !supportedHTTPSchemes.Has(string(http.Scheme)) {
  2254. allErrors = append(allErrors, field.NotSupported(fldPath.Child("scheme"), http.Scheme, supportedHTTPSchemes.List()))
  2255. }
  2256. for _, header := range http.HTTPHeaders {
  2257. for _, msg := range validation.IsHTTPHeaderName(header.Name) {
  2258. allErrors = append(allErrors, field.Invalid(fldPath.Child("httpHeaders"), header.Name, msg))
  2259. }
  2260. }
  2261. return allErrors
  2262. }
  2263. func ValidatePortNumOrName(port intstr.IntOrString, fldPath *field.Path) field.ErrorList {
  2264. allErrs := field.ErrorList{}
  2265. if port.Type == intstr.Int {
  2266. for _, msg := range validation.IsValidPortNum(port.IntValue()) {
  2267. allErrs = append(allErrs, field.Invalid(fldPath, port.IntValue(), msg))
  2268. }
  2269. } else if port.Type == intstr.String {
  2270. for _, msg := range validation.IsValidPortName(port.StrVal) {
  2271. allErrs = append(allErrs, field.Invalid(fldPath, port.StrVal, msg))
  2272. }
  2273. } else {
  2274. allErrs = append(allErrs, field.InternalError(fldPath, fmt.Errorf("unknown type: %v", port.Type)))
  2275. }
  2276. return allErrs
  2277. }
  2278. func validateTCPSocketAction(tcp *core.TCPSocketAction, fldPath *field.Path) field.ErrorList {
  2279. return ValidatePortNumOrName(tcp.Port, fldPath.Child("port"))
  2280. }
  2281. func validateHandler(handler *core.Handler, fldPath *field.Path) field.ErrorList {
  2282. numHandlers := 0
  2283. allErrors := field.ErrorList{}
  2284. if handler.Exec != nil {
  2285. if numHandlers > 0 {
  2286. allErrors = append(allErrors, field.Forbidden(fldPath.Child("exec"), "may not specify more than 1 handler type"))
  2287. } else {
  2288. numHandlers++
  2289. allErrors = append(allErrors, validateExecAction(handler.Exec, fldPath.Child("exec"))...)
  2290. }
  2291. }
  2292. if handler.HTTPGet != nil {
  2293. if numHandlers > 0 {
  2294. allErrors = append(allErrors, field.Forbidden(fldPath.Child("httpGet"), "may not specify more than 1 handler type"))
  2295. } else {
  2296. numHandlers++
  2297. allErrors = append(allErrors, validateHTTPGetAction(handler.HTTPGet, fldPath.Child("httpGet"))...)
  2298. }
  2299. }
  2300. if handler.TCPSocket != nil {
  2301. if numHandlers > 0 {
  2302. allErrors = append(allErrors, field.Forbidden(fldPath.Child("tcpSocket"), "may not specify more than 1 handler type"))
  2303. } else {
  2304. numHandlers++
  2305. allErrors = append(allErrors, validateTCPSocketAction(handler.TCPSocket, fldPath.Child("tcpSocket"))...)
  2306. }
  2307. }
  2308. if numHandlers == 0 {
  2309. allErrors = append(allErrors, field.Required(fldPath, "must specify a handler type"))
  2310. }
  2311. return allErrors
  2312. }
  2313. func validateLifecycle(lifecycle *core.Lifecycle, fldPath *field.Path) field.ErrorList {
  2314. allErrs := field.ErrorList{}
  2315. if lifecycle.PostStart != nil {
  2316. allErrs = append(allErrs, validateHandler(lifecycle.PostStart, fldPath.Child("postStart"))...)
  2317. }
  2318. if lifecycle.PreStop != nil {
  2319. allErrs = append(allErrs, validateHandler(lifecycle.PreStop, fldPath.Child("preStop"))...)
  2320. }
  2321. return allErrs
  2322. }
  2323. var supportedPullPolicies = sets.NewString(string(core.PullAlways), string(core.PullIfNotPresent), string(core.PullNever))
  2324. func validatePullPolicy(policy core.PullPolicy, fldPath *field.Path) field.ErrorList {
  2325. allErrors := field.ErrorList{}
  2326. switch policy {
  2327. case core.PullAlways, core.PullIfNotPresent, core.PullNever:
  2328. break
  2329. case "":
  2330. allErrors = append(allErrors, field.Required(fldPath, ""))
  2331. default:
  2332. allErrors = append(allErrors, field.NotSupported(fldPath, policy, supportedPullPolicies.List()))
  2333. }
  2334. return allErrors
  2335. }
  2336. func validateEphemeralContainers(ephemeralContainers []core.EphemeralContainer, containers, initContainers []core.Container, volumes map[string]core.VolumeSource, fldPath *field.Path) field.ErrorList {
  2337. allErrs := field.ErrorList{}
  2338. if len(ephemeralContainers) == 0 {
  2339. return allErrs
  2340. }
  2341. allNames := sets.String{}
  2342. for _, c := range containers {
  2343. allNames.Insert(c.Name)
  2344. }
  2345. for _, c := range initContainers {
  2346. allNames.Insert(c.Name)
  2347. }
  2348. for i, ec := range ephemeralContainers {
  2349. idxPath := fldPath.Index(i)
  2350. if ec.TargetContainerName != "" && !allNames.Has(ec.TargetContainerName) {
  2351. allErrs = append(allErrs, field.NotFound(idxPath.Child("targetContainerName"), ec.TargetContainerName))
  2352. }
  2353. if ec.Name == "" {
  2354. allErrs = append(allErrs, field.Required(idxPath, "ephemeralContainer requires a name"))
  2355. continue
  2356. }
  2357. // Using validateContainers() here isn't ideal because it adds an index to the error message that
  2358. // doesn't really exist for EphemeralContainers (i.e. ephemeralContainers[0].spec[0].name instead
  2359. // of ephemeralContainers[0].spec.name)
  2360. // TODO(verb): factor a validateContainer() out of validateContainers() to be used here
  2361. c := core.Container(ec.EphemeralContainerCommon)
  2362. allErrs = append(allErrs, validateContainers([]core.Container{c}, false, volumes, idxPath)...)
  2363. // EphemeralContainers don't require the backwards-compatibility distinction between pod/podTemplate validation
  2364. allErrs = append(allErrs, validateContainersOnlyForPod([]core.Container{c}, idxPath)...)
  2365. if allNames.Has(ec.Name) {
  2366. allErrs = append(allErrs, field.Duplicate(idxPath.Child("name"), ec.Name))
  2367. } else {
  2368. allNames.Insert(ec.Name)
  2369. }
  2370. // Ephemeral Containers should not be relied upon for fundamental pod services, so fields such as
  2371. // Lifecycle, probes, resources and ports should be disallowed. This is implemented as a whitelist
  2372. // so that new fields will be given consideration prior to inclusion in Ephemeral Containers.
  2373. specType, specValue := reflect.TypeOf(ec.EphemeralContainerCommon), reflect.ValueOf(ec.EphemeralContainerCommon)
  2374. for i := 0; i < specType.NumField(); i++ {
  2375. f := specType.Field(i)
  2376. if allowedEphemeralContainerFields[f.Name] {
  2377. continue
  2378. }
  2379. // Compare the value of this field to its zero value to determine if it has been set
  2380. if !reflect.DeepEqual(specValue.Field(i).Interface(), reflect.Zero(f.Type).Interface()) {
  2381. r, n := utf8.DecodeRuneInString(f.Name)
  2382. lcName := string(unicode.ToLower(r)) + f.Name[n:]
  2383. allErrs = append(allErrs, field.Forbidden(idxPath.Child(lcName), "cannot be set for an Ephemeral Container"))
  2384. }
  2385. }
  2386. }
  2387. return allErrs
  2388. }
  2389. func validateInitContainers(containers, otherContainers []core.Container, deviceVolumes map[string]core.VolumeSource, fldPath *field.Path) field.ErrorList {
  2390. var allErrs field.ErrorList
  2391. if len(containers) > 0 {
  2392. allErrs = append(allErrs, validateContainers(containers, true, deviceVolumes, fldPath)...)
  2393. }
  2394. allNames := sets.String{}
  2395. for _, ctr := range otherContainers {
  2396. allNames.Insert(ctr.Name)
  2397. }
  2398. for i, ctr := range containers {
  2399. idxPath := fldPath.Index(i)
  2400. if allNames.Has(ctr.Name) {
  2401. allErrs = append(allErrs, field.Duplicate(idxPath.Child("name"), ctr.Name))
  2402. }
  2403. if len(ctr.Name) > 0 {
  2404. allNames.Insert(ctr.Name)
  2405. }
  2406. if ctr.Lifecycle != nil {
  2407. allErrs = append(allErrs, field.Invalid(idxPath.Child("lifecycle"), ctr.Lifecycle, "must not be set for init containers"))
  2408. }
  2409. if ctr.LivenessProbe != nil {
  2410. allErrs = append(allErrs, field.Invalid(idxPath.Child("livenessProbe"), ctr.LivenessProbe, "must not be set for init containers"))
  2411. }
  2412. if ctr.ReadinessProbe != nil {
  2413. allErrs = append(allErrs, field.Invalid(idxPath.Child("readinessProbe"), ctr.ReadinessProbe, "must not be set for init containers"))
  2414. }
  2415. if ctr.StartupProbe != nil {
  2416. allErrs = append(allErrs, field.Invalid(idxPath.Child("startupProbe"), ctr.StartupProbe, "must not be set for init containers"))
  2417. }
  2418. }
  2419. return allErrs
  2420. }
  2421. func validateContainers(containers []core.Container, isInitContainers bool, volumes map[string]core.VolumeSource, fldPath *field.Path) field.ErrorList {
  2422. allErrs := field.ErrorList{}
  2423. if len(containers) == 0 {
  2424. return append(allErrs, field.Required(fldPath, ""))
  2425. }
  2426. allNames := sets.String{}
  2427. for i, ctr := range containers {
  2428. idxPath := fldPath.Index(i)
  2429. namePath := idxPath.Child("name")
  2430. volMounts := GetVolumeMountMap(ctr.VolumeMounts)
  2431. volDevices := GetVolumeDeviceMap(ctr.VolumeDevices)
  2432. if len(ctr.Name) == 0 {
  2433. allErrs = append(allErrs, field.Required(namePath, ""))
  2434. } else {
  2435. allErrs = append(allErrs, ValidateDNS1123Label(ctr.Name, namePath)...)
  2436. }
  2437. if allNames.Has(ctr.Name) {
  2438. allErrs = append(allErrs, field.Duplicate(namePath, ctr.Name))
  2439. } else {
  2440. allNames.Insert(ctr.Name)
  2441. }
  2442. // TODO: do not validate leading and trailing whitespace to preserve backward compatibility.
  2443. // for example: https://github.com/openshift/origin/issues/14659 image = " " is special token in pod template
  2444. // others may have done similar
  2445. if len(ctr.Image) == 0 {
  2446. allErrs = append(allErrs, field.Required(idxPath.Child("image"), ""))
  2447. }
  2448. if ctr.Lifecycle != nil {
  2449. allErrs = append(allErrs, validateLifecycle(ctr.Lifecycle, idxPath.Child("lifecycle"))...)
  2450. }
  2451. allErrs = append(allErrs, validateProbe(ctr.LivenessProbe, idxPath.Child("livenessProbe"))...)
  2452. // Liveness-specific validation
  2453. if ctr.LivenessProbe != nil && ctr.LivenessProbe.SuccessThreshold != 1 {
  2454. allErrs = append(allErrs, field.Invalid(idxPath.Child("livenessProbe", "successThreshold"), ctr.LivenessProbe.SuccessThreshold, "must be 1"))
  2455. }
  2456. allErrs = append(allErrs, validateProbe(ctr.StartupProbe, idxPath.Child("startupProbe"))...)
  2457. // Startup-specific validation
  2458. if ctr.StartupProbe != nil && ctr.StartupProbe.SuccessThreshold != 1 {
  2459. allErrs = append(allErrs, field.Invalid(idxPath.Child("startupProbe", "successThreshold"), ctr.StartupProbe.SuccessThreshold, "must be 1"))
  2460. }
  2461. switch ctr.TerminationMessagePolicy {
  2462. case core.TerminationMessageReadFile, core.TerminationMessageFallbackToLogsOnError:
  2463. case "":
  2464. allErrs = append(allErrs, field.Required(idxPath.Child("terminationMessagePolicy"), "must be 'File' or 'FallbackToLogsOnError'"))
  2465. default:
  2466. allErrs = append(allErrs, field.Invalid(idxPath.Child("terminationMessagePolicy"), ctr.TerminationMessagePolicy, "must be 'File' or 'FallbackToLogsOnError'"))
  2467. }
  2468. allErrs = append(allErrs, validateProbe(ctr.ReadinessProbe, idxPath.Child("readinessProbe"))...)
  2469. allErrs = append(allErrs, validateContainerPorts(ctr.Ports, idxPath.Child("ports"))...)
  2470. allErrs = append(allErrs, ValidateEnv(ctr.Env, idxPath.Child("env"))...)
  2471. allErrs = append(allErrs, ValidateEnvFrom(ctr.EnvFrom, idxPath.Child("envFrom"))...)
  2472. allErrs = append(allErrs, ValidateVolumeMounts(ctr.VolumeMounts, volDevices, volumes, &ctr, idxPath.Child("volumeMounts"))...)
  2473. allErrs = append(allErrs, ValidateVolumeDevices(ctr.VolumeDevices, volMounts, volumes, idxPath.Child("volumeDevices"))...)
  2474. allErrs = append(allErrs, validatePullPolicy(ctr.ImagePullPolicy, idxPath.Child("imagePullPolicy"))...)
  2475. allErrs = append(allErrs, ValidateResourceRequirements(&ctr.Resources, idxPath.Child("resources"))...)
  2476. allErrs = append(allErrs, ValidateSecurityContext(ctr.SecurityContext, idxPath.Child("securityContext"))...)
  2477. }
  2478. if isInitContainers {
  2479. // check initContainers one by one since they are running in sequential order.
  2480. for _, initContainer := range containers {
  2481. allErrs = append(allErrs, checkHostPortConflicts([]core.Container{initContainer}, fldPath)...)
  2482. }
  2483. } else {
  2484. // Check for colliding ports across all containers.
  2485. allErrs = append(allErrs, checkHostPortConflicts(containers, fldPath)...)
  2486. }
  2487. return allErrs
  2488. }
  2489. func validateRestartPolicy(restartPolicy *core.RestartPolicy, fldPath *field.Path) field.ErrorList {
  2490. allErrors := field.ErrorList{}
  2491. switch *restartPolicy {
  2492. case core.RestartPolicyAlways, core.RestartPolicyOnFailure, core.RestartPolicyNever:
  2493. break
  2494. case "":
  2495. allErrors = append(allErrors, field.Required(fldPath, ""))
  2496. default:
  2497. validValues := []string{string(core.RestartPolicyAlways), string(core.RestartPolicyOnFailure), string(core.RestartPolicyNever)}
  2498. allErrors = append(allErrors, field.NotSupported(fldPath, *restartPolicy, validValues))
  2499. }
  2500. return allErrors
  2501. }
  2502. func ValidatePreemptionPolicy(preemptionPolicy *core.PreemptionPolicy, fldPath *field.Path) field.ErrorList {
  2503. allErrors := field.ErrorList{}
  2504. switch *preemptionPolicy {
  2505. case core.PreemptLowerPriority, core.PreemptNever:
  2506. case "":
  2507. allErrors = append(allErrors, field.Required(fldPath, ""))
  2508. default:
  2509. validValues := []string{string(core.PreemptLowerPriority), string(core.PreemptNever)}
  2510. allErrors = append(allErrors, field.NotSupported(fldPath, preemptionPolicy, validValues))
  2511. }
  2512. return allErrors
  2513. }
  2514. func validateDNSPolicy(dnsPolicy *core.DNSPolicy, fldPath *field.Path) field.ErrorList {
  2515. allErrors := field.ErrorList{}
  2516. switch *dnsPolicy {
  2517. case core.DNSClusterFirstWithHostNet, core.DNSClusterFirst, core.DNSDefault, core.DNSNone:
  2518. case "":
  2519. allErrors = append(allErrors, field.Required(fldPath, ""))
  2520. default:
  2521. validValues := []string{string(core.DNSClusterFirstWithHostNet), string(core.DNSClusterFirst), string(core.DNSDefault), string(core.DNSNone)}
  2522. allErrors = append(allErrors, field.NotSupported(fldPath, dnsPolicy, validValues))
  2523. }
  2524. return allErrors
  2525. }
  2526. const (
  2527. // Limits on various DNS parameters. These are derived from
  2528. // restrictions in Linux libc name resolution handling.
  2529. // Max number of DNS name servers.
  2530. MaxDNSNameservers = 3
  2531. // Max number of domains in search path.
  2532. MaxDNSSearchPaths = 6
  2533. // Max number of characters in search path.
  2534. MaxDNSSearchListChars = 256
  2535. )
  2536. func validateReadinessGates(readinessGates []core.PodReadinessGate, fldPath *field.Path) field.ErrorList {
  2537. allErrs := field.ErrorList{}
  2538. for i, value := range readinessGates {
  2539. for _, msg := range validation.IsQualifiedName(string(value.ConditionType)) {
  2540. allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("conditionType"), string(value.ConditionType), msg))
  2541. }
  2542. }
  2543. return allErrs
  2544. }
  2545. func validatePodDNSConfig(dnsConfig *core.PodDNSConfig, dnsPolicy *core.DNSPolicy, fldPath *field.Path) field.ErrorList {
  2546. allErrs := field.ErrorList{}
  2547. // Validate DNSNone case. Must provide at least one DNS name server.
  2548. if dnsPolicy != nil && *dnsPolicy == core.DNSNone {
  2549. if dnsConfig == nil {
  2550. return append(allErrs, field.Required(fldPath, fmt.Sprintf("must provide `dnsConfig` when `dnsPolicy` is %s", core.DNSNone)))
  2551. }
  2552. if len(dnsConfig.Nameservers) == 0 {
  2553. return append(allErrs, field.Required(fldPath.Child("nameservers"), fmt.Sprintf("must provide at least one DNS nameserver when `dnsPolicy` is %s", core.DNSNone)))
  2554. }
  2555. }
  2556. if dnsConfig != nil {
  2557. // Validate nameservers.
  2558. if len(dnsConfig.Nameservers) > MaxDNSNameservers {
  2559. allErrs = append(allErrs, field.Invalid(fldPath.Child("nameservers"), dnsConfig.Nameservers, fmt.Sprintf("must not have more than %v nameservers", MaxDNSNameservers)))
  2560. }
  2561. for i, ns := range dnsConfig.Nameservers {
  2562. if ip := net.ParseIP(ns); ip == nil {
  2563. allErrs = append(allErrs, field.Invalid(fldPath.Child("nameservers").Index(i), ns, "must be valid IP address"))
  2564. }
  2565. }
  2566. // Validate searches.
  2567. if len(dnsConfig.Searches) > MaxDNSSearchPaths {
  2568. allErrs = append(allErrs, field.Invalid(fldPath.Child("searches"), dnsConfig.Searches, fmt.Sprintf("must not have more than %v search paths", MaxDNSSearchPaths)))
  2569. }
  2570. // Include the space between search paths.
  2571. if len(strings.Join(dnsConfig.Searches, " ")) > MaxDNSSearchListChars {
  2572. allErrs = append(allErrs, field.Invalid(fldPath.Child("searches"), dnsConfig.Searches, "must not have more than 256 characters (including spaces) in the search list"))
  2573. }
  2574. for i, search := range dnsConfig.Searches {
  2575. // it is fine to have a trailing dot
  2576. if strings.HasSuffix(search, ".") {
  2577. search = search[0 : len(search)-1]
  2578. }
  2579. allErrs = append(allErrs, ValidateDNS1123Subdomain(search, fldPath.Child("searches").Index(i))...)
  2580. }
  2581. // Validate options.
  2582. for i, option := range dnsConfig.Options {
  2583. if len(option.Name) == 0 {
  2584. allErrs = append(allErrs, field.Required(fldPath.Child("options").Index(i), "must not be empty"))
  2585. }
  2586. }
  2587. }
  2588. return allErrs
  2589. }
  2590. func validateHostNetwork(hostNetwork bool, containers []core.Container, fldPath *field.Path) field.ErrorList {
  2591. allErrors := field.ErrorList{}
  2592. if hostNetwork {
  2593. for i, container := range containers {
  2594. portsPath := fldPath.Index(i).Child("ports")
  2595. for i, port := range container.Ports {
  2596. idxPath := portsPath.Index(i)
  2597. if port.HostPort != port.ContainerPort {
  2598. allErrors = append(allErrors, field.Invalid(idxPath.Child("containerPort"), port.ContainerPort, "must match `hostPort` when `hostNetwork` is true"))
  2599. }
  2600. }
  2601. }
  2602. }
  2603. return allErrors
  2604. }
  2605. // validateImagePullSecrets checks to make sure the pull secrets are well
  2606. // formed. Right now, we only expect name to be set (it's the only field). If
  2607. // this ever changes and someone decides to set those fields, we'd like to
  2608. // know.
  2609. func validateImagePullSecrets(imagePullSecrets []core.LocalObjectReference, fldPath *field.Path) field.ErrorList {
  2610. allErrors := field.ErrorList{}
  2611. for i, currPullSecret := range imagePullSecrets {
  2612. idxPath := fldPath.Index(i)
  2613. strippedRef := core.LocalObjectReference{Name: currPullSecret.Name}
  2614. if !reflect.DeepEqual(strippedRef, currPullSecret) {
  2615. allErrors = append(allErrors, field.Invalid(idxPath, currPullSecret, "only name may be set"))
  2616. }
  2617. }
  2618. return allErrors
  2619. }
  2620. // validateAffinity checks if given affinities are valid
  2621. func validateAffinity(affinity *core.Affinity, fldPath *field.Path) field.ErrorList {
  2622. allErrs := field.ErrorList{}
  2623. if affinity != nil {
  2624. if affinity.NodeAffinity != nil {
  2625. allErrs = append(allErrs, validateNodeAffinity(affinity.NodeAffinity, fldPath.Child("nodeAffinity"))...)
  2626. }
  2627. if affinity.PodAffinity != nil {
  2628. allErrs = append(allErrs, validatePodAffinity(affinity.PodAffinity, fldPath.Child("podAffinity"))...)
  2629. }
  2630. if affinity.PodAntiAffinity != nil {
  2631. allErrs = append(allErrs, validatePodAntiAffinity(affinity.PodAntiAffinity, fldPath.Child("podAntiAffinity"))...)
  2632. }
  2633. }
  2634. return allErrs
  2635. }
  2636. func validateTaintEffect(effect *core.TaintEffect, allowEmpty bool, fldPath *field.Path) field.ErrorList {
  2637. if !allowEmpty && len(*effect) == 0 {
  2638. return field.ErrorList{field.Required(fldPath, "")}
  2639. }
  2640. allErrors := field.ErrorList{}
  2641. switch *effect {
  2642. // TODO: Replace next line with subsequent commented-out line when implement TaintEffectNoScheduleNoAdmit.
  2643. case core.TaintEffectNoSchedule, core.TaintEffectPreferNoSchedule, core.TaintEffectNoExecute:
  2644. // case core.TaintEffectNoSchedule, core.TaintEffectPreferNoSchedule, core.TaintEffectNoScheduleNoAdmit, core.TaintEffectNoExecute:
  2645. default:
  2646. validValues := []string{
  2647. string(core.TaintEffectNoSchedule),
  2648. string(core.TaintEffectPreferNoSchedule),
  2649. string(core.TaintEffectNoExecute),
  2650. // TODO: Uncomment this block when implement TaintEffectNoScheduleNoAdmit.
  2651. // string(core.TaintEffectNoScheduleNoAdmit),
  2652. }
  2653. allErrors = append(allErrors, field.NotSupported(fldPath, *effect, validValues))
  2654. }
  2655. return allErrors
  2656. }
  2657. // validateOnlyAddedTolerations validates updated pod tolerations.
  2658. func validateOnlyAddedTolerations(newTolerations []core.Toleration, oldTolerations []core.Toleration, fldPath *field.Path) field.ErrorList {
  2659. allErrs := field.ErrorList{}
  2660. for _, old := range oldTolerations {
  2661. found := false
  2662. old.TolerationSeconds = nil
  2663. for _, new := range newTolerations {
  2664. new.TolerationSeconds = nil
  2665. if reflect.DeepEqual(old, new) {
  2666. found = true
  2667. break
  2668. }
  2669. }
  2670. if !found {
  2671. allErrs = append(allErrs, field.Forbidden(fldPath, "existing toleration can not be modified except its tolerationSeconds"))
  2672. return allErrs
  2673. }
  2674. }
  2675. allErrs = append(allErrs, ValidateTolerations(newTolerations, fldPath)...)
  2676. return allErrs
  2677. }
  2678. func ValidateHostAliases(hostAliases []core.HostAlias, fldPath *field.Path) field.ErrorList {
  2679. allErrs := field.ErrorList{}
  2680. for _, hostAlias := range hostAliases {
  2681. if ip := net.ParseIP(hostAlias.IP); ip == nil {
  2682. allErrs = append(allErrs, field.Invalid(fldPath.Child("ip"), hostAlias.IP, "must be valid IP address"))
  2683. }
  2684. for _, hostname := range hostAlias.Hostnames {
  2685. allErrs = append(allErrs, ValidateDNS1123Subdomain(hostname, fldPath.Child("hostnames"))...)
  2686. }
  2687. }
  2688. return allErrs
  2689. }
  2690. // ValidateTolerations tests if given tolerations have valid data.
  2691. func ValidateTolerations(tolerations []core.Toleration, fldPath *field.Path) field.ErrorList {
  2692. allErrors := field.ErrorList{}
  2693. for i, toleration := range tolerations {
  2694. idxPath := fldPath.Index(i)
  2695. // validate the toleration key
  2696. if len(toleration.Key) > 0 {
  2697. allErrors = append(allErrors, unversionedvalidation.ValidateLabelName(toleration.Key, idxPath.Child("key"))...)
  2698. }
  2699. // empty toleration key with Exists operator and empty value means match all taints
  2700. if len(toleration.Key) == 0 && toleration.Operator != core.TolerationOpExists {
  2701. allErrors = append(allErrors, field.Invalid(idxPath.Child("operator"), toleration.Operator,
  2702. "operator must be Exists when `key` is empty, which means \"match all values and all keys\""))
  2703. }
  2704. if toleration.TolerationSeconds != nil && toleration.Effect != core.TaintEffectNoExecute {
  2705. allErrors = append(allErrors, field.Invalid(idxPath.Child("effect"), toleration.Effect,
  2706. "effect must be 'NoExecute' when `tolerationSeconds` is set"))
  2707. }
  2708. // validate toleration operator and value
  2709. switch toleration.Operator {
  2710. // empty operator means Equal
  2711. case core.TolerationOpEqual, "":
  2712. if errs := validation.IsValidLabelValue(toleration.Value); len(errs) != 0 {
  2713. allErrors = append(allErrors, field.Invalid(idxPath.Child("operator"), toleration.Value, strings.Join(errs, ";")))
  2714. }
  2715. case core.TolerationOpExists:
  2716. if len(toleration.Value) > 0 {
  2717. allErrors = append(allErrors, field.Invalid(idxPath.Child("operator"), toleration, "value must be empty when `operator` is 'Exists'"))
  2718. }
  2719. default:
  2720. validValues := []string{string(core.TolerationOpEqual), string(core.TolerationOpExists)}
  2721. allErrors = append(allErrors, field.NotSupported(idxPath.Child("operator"), toleration.Operator, validValues))
  2722. }
  2723. // validate toleration effect, empty toleration effect means match all taint effects
  2724. if len(toleration.Effect) > 0 {
  2725. allErrors = append(allErrors, validateTaintEffect(&toleration.Effect, true, idxPath.Child("effect"))...)
  2726. }
  2727. }
  2728. return allErrors
  2729. }
  2730. func toResourceNames(resources core.ResourceList) []core.ResourceName {
  2731. result := []core.ResourceName{}
  2732. for resourceName := range resources {
  2733. result = append(result, resourceName)
  2734. }
  2735. return result
  2736. }
  2737. func toSet(resourceNames []core.ResourceName) sets.String {
  2738. result := sets.NewString()
  2739. for _, resourceName := range resourceNames {
  2740. result.Insert(string(resourceName))
  2741. }
  2742. return result
  2743. }
  2744. func toContainerResourcesSet(ctr *core.Container) sets.String {
  2745. resourceNames := toResourceNames(ctr.Resources.Requests)
  2746. resourceNames = append(resourceNames, toResourceNames(ctr.Resources.Limits)...)
  2747. return toSet(resourceNames)
  2748. }
  2749. // validateContainersOnlyForPod does additional validation for containers on a pod versus a pod template
  2750. // it only does additive validation of fields not covered in validateContainers
  2751. func validateContainersOnlyForPod(containers []core.Container, fldPath *field.Path) field.ErrorList {
  2752. allErrs := field.ErrorList{}
  2753. for i, ctr := range containers {
  2754. idxPath := fldPath.Index(i)
  2755. if len(ctr.Image) != len(strings.TrimSpace(ctr.Image)) {
  2756. allErrs = append(allErrs, field.Invalid(idxPath.Child("image"), ctr.Image, "must not have leading or trailing whitespace"))
  2757. }
  2758. }
  2759. return allErrs
  2760. }
  2761. // ValidatePod tests if required fields in the pod are set.
  2762. func ValidatePod(pod *core.Pod) field.ErrorList {
  2763. fldPath := field.NewPath("metadata")
  2764. allErrs := ValidateObjectMeta(&pod.ObjectMeta, true, ValidatePodName, fldPath)
  2765. allErrs = append(allErrs, ValidatePodSpecificAnnotations(pod.ObjectMeta.Annotations, &pod.Spec, fldPath.Child("annotations"))...)
  2766. allErrs = append(allErrs, ValidatePodSpec(&pod.Spec, field.NewPath("spec"))...)
  2767. // we do additional validation only pertinent for pods and not pod templates
  2768. // this was done to preserve backwards compatibility
  2769. specPath := field.NewPath("spec")
  2770. if pod.Spec.ServiceAccountName == "" {
  2771. for vi, volume := range pod.Spec.Volumes {
  2772. path := specPath.Child("volumes").Index(vi).Child("projected")
  2773. if volume.Projected != nil {
  2774. for si, source := range volume.Projected.Sources {
  2775. saPath := path.Child("sources").Index(si).Child("serviceAccountToken")
  2776. if source.ServiceAccountToken != nil {
  2777. allErrs = append(allErrs, field.Forbidden(saPath, "must not be specified when serviceAccountName is not set"))
  2778. }
  2779. }
  2780. }
  2781. }
  2782. }
  2783. allErrs = append(allErrs, validateContainersOnlyForPod(pod.Spec.Containers, specPath.Child("containers"))...)
  2784. allErrs = append(allErrs, validateContainersOnlyForPod(pod.Spec.InitContainers, specPath.Child("initContainers"))...)
  2785. hugePageResources := sets.NewString()
  2786. for i := range pod.Spec.Containers {
  2787. resourceSet := toContainerResourcesSet(&pod.Spec.Containers[i])
  2788. for resourceStr := range resourceSet {
  2789. if v1helper.IsHugePageResourceName(v1.ResourceName(resourceStr)) {
  2790. hugePageResources.Insert(resourceStr)
  2791. }
  2792. }
  2793. }
  2794. if len(hugePageResources) > 1 {
  2795. allErrs = append(allErrs, field.Invalid(specPath, hugePageResources, "must use a single hugepage size in a pod spec"))
  2796. }
  2797. podIPsField := field.NewPath("status", "podIPs")
  2798. // all PodIPs must be valid IPs
  2799. for i, podIP := range pod.Status.PodIPs {
  2800. for _, msg := range validation.IsValidIP(podIP.IP) {
  2801. allErrs = append(allErrs, field.Invalid(podIPsField.Index(i), podIP.IP, msg))
  2802. }
  2803. }
  2804. // if we have more than one Pod.PodIP then
  2805. // - validate for dual stack
  2806. // - validate for duplication
  2807. if len(pod.Status.PodIPs) > 1 {
  2808. podIPs := make([]string, 0, len(pod.Status.PodIPs))
  2809. for _, podIP := range pod.Status.PodIPs {
  2810. podIPs = append(podIPs, podIP.IP)
  2811. }
  2812. dualStack, err := netutils.IsDualStackIPStrings(podIPs)
  2813. if err != nil {
  2814. allErrs = append(allErrs, field.InternalError(podIPsField, fmt.Errorf("failed to check for dual stack with error:%v", err)))
  2815. }
  2816. // We only support one from each IP family (i.e. max two IPs in this list).
  2817. if !dualStack || len(podIPs) > 2 {
  2818. allErrs = append(allErrs, field.Invalid(podIPsField, pod.Status.PodIPs, "may specify no more than one IP for each IP family"))
  2819. }
  2820. // There should be no duplicates in list of Pod.PodIPs
  2821. seen := sets.String{} //:= make(map[string]int)
  2822. for i, podIP := range pod.Status.PodIPs {
  2823. if seen.Has(podIP.IP) {
  2824. allErrs = append(allErrs, field.Duplicate(podIPsField.Index(i), podIP))
  2825. }
  2826. seen.Insert(podIP.IP)
  2827. }
  2828. }
  2829. return allErrs
  2830. }
  2831. // ValidatePodSpec tests that the specified PodSpec has valid data.
  2832. // This includes checking formatting and uniqueness. It also canonicalizes the
  2833. // structure by setting default values and implementing any backwards-compatibility
  2834. // tricks.
  2835. func ValidatePodSpec(spec *core.PodSpec, fldPath *field.Path) field.ErrorList {
  2836. allErrs := field.ErrorList{}
  2837. vols, vErrs := ValidateVolumes(spec.Volumes, fldPath.Child("volumes"))
  2838. allErrs = append(allErrs, vErrs...)
  2839. allErrs = append(allErrs, validateContainers(spec.Containers, false, vols, fldPath.Child("containers"))...)
  2840. allErrs = append(allErrs, validateInitContainers(spec.InitContainers, spec.Containers, vols, fldPath.Child("initContainers"))...)
  2841. allErrs = append(allErrs, validateEphemeralContainers(spec.EphemeralContainers, spec.Containers, spec.InitContainers, vols, fldPath.Child("ephemeralContainers"))...)
  2842. allErrs = append(allErrs, validateRestartPolicy(&spec.RestartPolicy, fldPath.Child("restartPolicy"))...)
  2843. allErrs = append(allErrs, validateDNSPolicy(&spec.DNSPolicy, fldPath.Child("dnsPolicy"))...)
  2844. allErrs = append(allErrs, unversionedvalidation.ValidateLabels(spec.NodeSelector, fldPath.Child("nodeSelector"))...)
  2845. allErrs = append(allErrs, ValidatePodSecurityContext(spec.SecurityContext, spec, fldPath, fldPath.Child("securityContext"))...)
  2846. allErrs = append(allErrs, validateImagePullSecrets(spec.ImagePullSecrets, fldPath.Child("imagePullSecrets"))...)
  2847. allErrs = append(allErrs, validateAffinity(spec.Affinity, fldPath.Child("affinity"))...)
  2848. allErrs = append(allErrs, validatePodDNSConfig(spec.DNSConfig, &spec.DNSPolicy, fldPath.Child("dnsConfig"))...)
  2849. allErrs = append(allErrs, validateReadinessGates(spec.ReadinessGates, fldPath.Child("readinessGates"))...)
  2850. allErrs = append(allErrs, validateTopologySpreadConstraints(spec.TopologySpreadConstraints, fldPath.Child("topologySpreadConstraints"))...)
  2851. if len(spec.ServiceAccountName) > 0 {
  2852. for _, msg := range ValidateServiceAccountName(spec.ServiceAccountName, false) {
  2853. allErrs = append(allErrs, field.Invalid(fldPath.Child("serviceAccountName"), spec.ServiceAccountName, msg))
  2854. }
  2855. }
  2856. if len(spec.NodeName) > 0 {
  2857. for _, msg := range ValidateNodeName(spec.NodeName, false) {
  2858. allErrs = append(allErrs, field.Invalid(fldPath.Child("nodeName"), spec.NodeName, msg))
  2859. }
  2860. }
  2861. if spec.ActiveDeadlineSeconds != nil {
  2862. value := *spec.ActiveDeadlineSeconds
  2863. if value < 1 || value > math.MaxInt32 {
  2864. allErrs = append(allErrs, field.Invalid(fldPath.Child("activeDeadlineSeconds"), value, validation.InclusiveRangeError(1, math.MaxInt32)))
  2865. }
  2866. }
  2867. if len(spec.Hostname) > 0 {
  2868. allErrs = append(allErrs, ValidateDNS1123Label(spec.Hostname, fldPath.Child("hostname"))...)
  2869. }
  2870. if len(spec.Subdomain) > 0 {
  2871. allErrs = append(allErrs, ValidateDNS1123Label(spec.Subdomain, fldPath.Child("subdomain"))...)
  2872. }
  2873. if len(spec.Tolerations) > 0 {
  2874. allErrs = append(allErrs, ValidateTolerations(spec.Tolerations, fldPath.Child("tolerations"))...)
  2875. }
  2876. if len(spec.HostAliases) > 0 {
  2877. allErrs = append(allErrs, ValidateHostAliases(spec.HostAliases, fldPath.Child("hostAliases"))...)
  2878. }
  2879. if len(spec.PriorityClassName) > 0 {
  2880. for _, msg := range ValidatePriorityClassName(spec.PriorityClassName, false) {
  2881. allErrs = append(allErrs, field.Invalid(fldPath.Child("priorityClassName"), spec.PriorityClassName, msg))
  2882. }
  2883. }
  2884. if spec.RuntimeClassName != nil {
  2885. allErrs = append(allErrs, ValidateRuntimeClassName(*spec.RuntimeClassName, fldPath.Child("runtimeClassName"))...)
  2886. }
  2887. if spec.PreemptionPolicy != nil {
  2888. allErrs = append(allErrs, ValidatePreemptionPolicy(spec.PreemptionPolicy, fldPath.Child("preemptionPolicy"))...)
  2889. }
  2890. if spec.Overhead != nil {
  2891. allErrs = append(allErrs, validateOverhead(spec.Overhead, fldPath.Child("overhead"))...)
  2892. }
  2893. return allErrs
  2894. }
  2895. // ValidateNodeSelectorRequirement tests that the specified NodeSelectorRequirement fields has valid data
  2896. func ValidateNodeSelectorRequirement(rq core.NodeSelectorRequirement, fldPath *field.Path) field.ErrorList {
  2897. allErrs := field.ErrorList{}
  2898. switch rq.Operator {
  2899. case core.NodeSelectorOpIn, core.NodeSelectorOpNotIn:
  2900. if len(rq.Values) == 0 {
  2901. allErrs = append(allErrs, field.Required(fldPath.Child("values"), "must be specified when `operator` is 'In' or 'NotIn'"))
  2902. }
  2903. case core.NodeSelectorOpExists, core.NodeSelectorOpDoesNotExist:
  2904. if len(rq.Values) > 0 {
  2905. allErrs = append(allErrs, field.Forbidden(fldPath.Child("values"), "may not be specified when `operator` is 'Exists' or 'DoesNotExist'"))
  2906. }
  2907. case core.NodeSelectorOpGt, core.NodeSelectorOpLt:
  2908. if len(rq.Values) != 1 {
  2909. allErrs = append(allErrs, field.Required(fldPath.Child("values"), "must be specified single value when `operator` is 'Lt' or 'Gt'"))
  2910. }
  2911. default:
  2912. allErrs = append(allErrs, field.Invalid(fldPath.Child("operator"), rq.Operator, "not a valid selector operator"))
  2913. }
  2914. allErrs = append(allErrs, unversionedvalidation.ValidateLabelName(rq.Key, fldPath.Child("key"))...)
  2915. return allErrs
  2916. }
  2917. var nodeFieldSelectorValidators = map[string]func(string, bool) []string{
  2918. core.ObjectNameField: ValidateNodeName,
  2919. }
  2920. // ValidateNodeFieldSelectorRequirement tests that the specified NodeSelectorRequirement fields has valid data
  2921. func ValidateNodeFieldSelectorRequirement(req core.NodeSelectorRequirement, fldPath *field.Path) field.ErrorList {
  2922. allErrs := field.ErrorList{}
  2923. switch req.Operator {
  2924. case core.NodeSelectorOpIn, core.NodeSelectorOpNotIn:
  2925. if len(req.Values) != 1 {
  2926. allErrs = append(allErrs, field.Required(fldPath.Child("values"),
  2927. "must be only one value when `operator` is 'In' or 'NotIn' for node field selector"))
  2928. }
  2929. default:
  2930. allErrs = append(allErrs, field.Invalid(fldPath.Child("operator"), req.Operator, "not a valid selector operator"))
  2931. }
  2932. if vf, found := nodeFieldSelectorValidators[req.Key]; !found {
  2933. allErrs = append(allErrs, field.Invalid(fldPath.Child("key"), req.Key, "not a valid field selector key"))
  2934. } else {
  2935. for i, v := range req.Values {
  2936. for _, msg := range vf(v, false) {
  2937. allErrs = append(allErrs, field.Invalid(fldPath.Child("values").Index(i), v, msg))
  2938. }
  2939. }
  2940. }
  2941. return allErrs
  2942. }
  2943. // ValidateNodeSelectorTerm tests that the specified node selector term has valid data
  2944. func ValidateNodeSelectorTerm(term core.NodeSelectorTerm, fldPath *field.Path) field.ErrorList {
  2945. allErrs := field.ErrorList{}
  2946. for j, req := range term.MatchExpressions {
  2947. allErrs = append(allErrs, ValidateNodeSelectorRequirement(req, fldPath.Child("matchExpressions").Index(j))...)
  2948. }
  2949. for j, req := range term.MatchFields {
  2950. allErrs = append(allErrs, ValidateNodeFieldSelectorRequirement(req, fldPath.Child("matchFields").Index(j))...)
  2951. }
  2952. return allErrs
  2953. }
  2954. // ValidateNodeSelector tests that the specified nodeSelector fields has valid data
  2955. func ValidateNodeSelector(nodeSelector *core.NodeSelector, fldPath *field.Path) field.ErrorList {
  2956. allErrs := field.ErrorList{}
  2957. termFldPath := fldPath.Child("nodeSelectorTerms")
  2958. if len(nodeSelector.NodeSelectorTerms) == 0 {
  2959. return append(allErrs, field.Required(termFldPath, "must have at least one node selector term"))
  2960. }
  2961. for i, term := range nodeSelector.NodeSelectorTerms {
  2962. allErrs = append(allErrs, ValidateNodeSelectorTerm(term, termFldPath.Index(i))...)
  2963. }
  2964. return allErrs
  2965. }
  2966. // validateTopologySelectorLabelRequirement tests that the specified TopologySelectorLabelRequirement fields has valid data,
  2967. // and constructs a set containing all of its Values.
  2968. func validateTopologySelectorLabelRequirement(rq core.TopologySelectorLabelRequirement, fldPath *field.Path) (sets.String, field.ErrorList) {
  2969. allErrs := field.ErrorList{}
  2970. valueSet := make(sets.String)
  2971. valuesPath := fldPath.Child("values")
  2972. if len(rq.Values) == 0 {
  2973. allErrs = append(allErrs, field.Required(valuesPath, ""))
  2974. }
  2975. // Validate set property of Values field
  2976. for i, value := range rq.Values {
  2977. if valueSet.Has(value) {
  2978. allErrs = append(allErrs, field.Duplicate(valuesPath.Index(i), value))
  2979. }
  2980. valueSet.Insert(value)
  2981. }
  2982. allErrs = append(allErrs, unversionedvalidation.ValidateLabelName(rq.Key, fldPath.Child("key"))...)
  2983. return valueSet, allErrs
  2984. }
  2985. // ValidateTopologySelectorTerm tests that the specified topology selector term has valid data,
  2986. // and constructs a map representing the term in raw form.
  2987. func ValidateTopologySelectorTerm(term core.TopologySelectorTerm, fldPath *field.Path) (map[string]sets.String, field.ErrorList) {
  2988. allErrs := field.ErrorList{}
  2989. exprMap := make(map[string]sets.String)
  2990. exprPath := fldPath.Child("matchLabelExpressions")
  2991. // Allow empty MatchLabelExpressions, in case this field becomes optional in the future.
  2992. for i, req := range term.MatchLabelExpressions {
  2993. idxPath := exprPath.Index(i)
  2994. valueSet, exprErrs := validateTopologySelectorLabelRequirement(req, idxPath)
  2995. allErrs = append(allErrs, exprErrs...)
  2996. // Validate no duplicate keys exist.
  2997. if _, exists := exprMap[req.Key]; exists {
  2998. allErrs = append(allErrs, field.Duplicate(idxPath.Child("key"), req.Key))
  2999. }
  3000. exprMap[req.Key] = valueSet
  3001. }
  3002. return exprMap, allErrs
  3003. }
  3004. // ValidateAvoidPodsInNodeAnnotations tests that the serialized AvoidPods in Node.Annotations has valid data
  3005. func ValidateAvoidPodsInNodeAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
  3006. allErrs := field.ErrorList{}
  3007. v1Avoids, err := v1helper.GetAvoidPodsFromNodeAnnotations(annotations)
  3008. if err != nil {
  3009. allErrs = append(allErrs, field.Invalid(fldPath.Child("AvoidPods"), core.PreferAvoidPodsAnnotationKey, err.Error()))
  3010. return allErrs
  3011. }
  3012. var avoids core.AvoidPods
  3013. if err := corev1.Convert_v1_AvoidPods_To_core_AvoidPods(&v1Avoids, &avoids, nil); err != nil {
  3014. allErrs = append(allErrs, field.Invalid(fldPath.Child("AvoidPods"), core.PreferAvoidPodsAnnotationKey, err.Error()))
  3015. return allErrs
  3016. }
  3017. if len(avoids.PreferAvoidPods) != 0 {
  3018. for i, pa := range avoids.PreferAvoidPods {
  3019. idxPath := fldPath.Child(core.PreferAvoidPodsAnnotationKey).Index(i)
  3020. allErrs = append(allErrs, validatePreferAvoidPodsEntry(pa, idxPath)...)
  3021. }
  3022. }
  3023. return allErrs
  3024. }
  3025. // validatePreferAvoidPodsEntry tests if given PreferAvoidPodsEntry has valid data.
  3026. func validatePreferAvoidPodsEntry(avoidPodEntry core.PreferAvoidPodsEntry, fldPath *field.Path) field.ErrorList {
  3027. allErrors := field.ErrorList{}
  3028. if avoidPodEntry.PodSignature.PodController == nil {
  3029. allErrors = append(allErrors, field.Required(fldPath.Child("PodSignature"), ""))
  3030. } else {
  3031. if !*(avoidPodEntry.PodSignature.PodController.Controller) {
  3032. allErrors = append(allErrors,
  3033. field.Invalid(fldPath.Child("PodSignature").Child("PodController").Child("Controller"),
  3034. *(avoidPodEntry.PodSignature.PodController.Controller), "must point to a controller"))
  3035. }
  3036. }
  3037. return allErrors
  3038. }
  3039. // ValidatePreferredSchedulingTerms tests that the specified SoftNodeAffinity fields has valid data
  3040. func ValidatePreferredSchedulingTerms(terms []core.PreferredSchedulingTerm, fldPath *field.Path) field.ErrorList {
  3041. allErrs := field.ErrorList{}
  3042. for i, term := range terms {
  3043. if term.Weight <= 0 || term.Weight > 100 {
  3044. allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("weight"), term.Weight, "must be in the range 1-100"))
  3045. }
  3046. allErrs = append(allErrs, ValidateNodeSelectorTerm(term.Preference, fldPath.Index(i).Child("preference"))...)
  3047. }
  3048. return allErrs
  3049. }
  3050. // validatePodAffinityTerm tests that the specified podAffinityTerm fields have valid data
  3051. func validatePodAffinityTerm(podAffinityTerm core.PodAffinityTerm, fldPath *field.Path) field.ErrorList {
  3052. allErrs := field.ErrorList{}
  3053. allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(podAffinityTerm.LabelSelector, fldPath.Child("matchExpressions"))...)
  3054. for _, name := range podAffinityTerm.Namespaces {
  3055. for _, msg := range ValidateNamespaceName(name, false) {
  3056. allErrs = append(allErrs, field.Invalid(fldPath.Child("namespace"), name, msg))
  3057. }
  3058. }
  3059. if len(podAffinityTerm.TopologyKey) == 0 {
  3060. allErrs = append(allErrs, field.Required(fldPath.Child("topologyKey"), "can not be empty"))
  3061. }
  3062. return append(allErrs, unversionedvalidation.ValidateLabelName(podAffinityTerm.TopologyKey, fldPath.Child("topologyKey"))...)
  3063. }
  3064. // validatePodAffinityTerms tests that the specified podAffinityTerms fields have valid data
  3065. func validatePodAffinityTerms(podAffinityTerms []core.PodAffinityTerm, fldPath *field.Path) field.ErrorList {
  3066. allErrs := field.ErrorList{}
  3067. for i, podAffinityTerm := range podAffinityTerms {
  3068. allErrs = append(allErrs, validatePodAffinityTerm(podAffinityTerm, fldPath.Index(i))...)
  3069. }
  3070. return allErrs
  3071. }
  3072. // validateWeightedPodAffinityTerms tests that the specified weightedPodAffinityTerms fields have valid data
  3073. func validateWeightedPodAffinityTerms(weightedPodAffinityTerms []core.WeightedPodAffinityTerm, fldPath *field.Path) field.ErrorList {
  3074. allErrs := field.ErrorList{}
  3075. for j, weightedTerm := range weightedPodAffinityTerms {
  3076. if weightedTerm.Weight <= 0 || weightedTerm.Weight > 100 {
  3077. allErrs = append(allErrs, field.Invalid(fldPath.Index(j).Child("weight"), weightedTerm.Weight, "must be in the range 1-100"))
  3078. }
  3079. allErrs = append(allErrs, validatePodAffinityTerm(weightedTerm.PodAffinityTerm, fldPath.Index(j).Child("podAffinityTerm"))...)
  3080. }
  3081. return allErrs
  3082. }
  3083. // validatePodAntiAffinity tests that the specified podAntiAffinity fields have valid data
  3084. func validatePodAntiAffinity(podAntiAffinity *core.PodAntiAffinity, fldPath *field.Path) field.ErrorList {
  3085. allErrs := field.ErrorList{}
  3086. // TODO:Uncomment below code once RequiredDuringSchedulingRequiredDuringExecution is implemented.
  3087. // if podAntiAffinity.RequiredDuringSchedulingRequiredDuringExecution != nil {
  3088. // allErrs = append(allErrs, validatePodAffinityTerms(podAntiAffinity.RequiredDuringSchedulingRequiredDuringExecution, false,
  3089. // fldPath.Child("requiredDuringSchedulingRequiredDuringExecution"))...)
  3090. //}
  3091. if podAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution != nil {
  3092. allErrs = append(allErrs, validatePodAffinityTerms(podAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution,
  3093. fldPath.Child("requiredDuringSchedulingIgnoredDuringExecution"))...)
  3094. }
  3095. if podAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution != nil {
  3096. allErrs = append(allErrs, validateWeightedPodAffinityTerms(podAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution,
  3097. fldPath.Child("preferredDuringSchedulingIgnoredDuringExecution"))...)
  3098. }
  3099. return allErrs
  3100. }
  3101. // validateNodeAffinity tests that the specified nodeAffinity fields have valid data
  3102. func validateNodeAffinity(na *core.NodeAffinity, fldPath *field.Path) field.ErrorList {
  3103. allErrs := field.ErrorList{}
  3104. // TODO: Uncomment the next three lines once RequiredDuringSchedulingRequiredDuringExecution is implemented.
  3105. // if na.RequiredDuringSchedulingRequiredDuringExecution != nil {
  3106. // allErrs = append(allErrs, ValidateNodeSelector(na.RequiredDuringSchedulingRequiredDuringExecution, fldPath.Child("requiredDuringSchedulingRequiredDuringExecution"))...)
  3107. // }
  3108. if na.RequiredDuringSchedulingIgnoredDuringExecution != nil {
  3109. allErrs = append(allErrs, ValidateNodeSelector(na.RequiredDuringSchedulingIgnoredDuringExecution, fldPath.Child("requiredDuringSchedulingIgnoredDuringExecution"))...)
  3110. }
  3111. if len(na.PreferredDuringSchedulingIgnoredDuringExecution) > 0 {
  3112. allErrs = append(allErrs, ValidatePreferredSchedulingTerms(na.PreferredDuringSchedulingIgnoredDuringExecution, fldPath.Child("preferredDuringSchedulingIgnoredDuringExecution"))...)
  3113. }
  3114. return allErrs
  3115. }
  3116. // validatePodAffinity tests that the specified podAffinity fields have valid data
  3117. func validatePodAffinity(podAffinity *core.PodAffinity, fldPath *field.Path) field.ErrorList {
  3118. allErrs := field.ErrorList{}
  3119. // TODO:Uncomment below code once RequiredDuringSchedulingRequiredDuringExecution is implemented.
  3120. // if podAffinity.RequiredDuringSchedulingRequiredDuringExecution != nil {
  3121. // allErrs = append(allErrs, validatePodAffinityTerms(podAffinity.RequiredDuringSchedulingRequiredDuringExecution, false,
  3122. // fldPath.Child("requiredDuringSchedulingRequiredDuringExecution"))...)
  3123. //}
  3124. if podAffinity.RequiredDuringSchedulingIgnoredDuringExecution != nil {
  3125. allErrs = append(allErrs, validatePodAffinityTerms(podAffinity.RequiredDuringSchedulingIgnoredDuringExecution,
  3126. fldPath.Child("requiredDuringSchedulingIgnoredDuringExecution"))...)
  3127. }
  3128. if podAffinity.PreferredDuringSchedulingIgnoredDuringExecution != nil {
  3129. allErrs = append(allErrs, validateWeightedPodAffinityTerms(podAffinity.PreferredDuringSchedulingIgnoredDuringExecution,
  3130. fldPath.Child("preferredDuringSchedulingIgnoredDuringExecution"))...)
  3131. }
  3132. return allErrs
  3133. }
  3134. func ValidateSeccompProfile(p string, fldPath *field.Path) field.ErrorList {
  3135. if p == core.SeccompProfileRuntimeDefault || p == core.DeprecatedSeccompProfileDockerDefault {
  3136. return nil
  3137. }
  3138. if p == "unconfined" {
  3139. return nil
  3140. }
  3141. if strings.HasPrefix(p, "localhost/") {
  3142. return validateLocalDescendingPath(strings.TrimPrefix(p, "localhost/"), fldPath)
  3143. }
  3144. return field.ErrorList{field.Invalid(fldPath, p, "must be a valid seccomp profile")}
  3145. }
  3146. func ValidateSeccompPodAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
  3147. allErrs := field.ErrorList{}
  3148. if p, exists := annotations[core.SeccompPodAnnotationKey]; exists {
  3149. allErrs = append(allErrs, ValidateSeccompProfile(p, fldPath.Child(core.SeccompPodAnnotationKey))...)
  3150. }
  3151. for k, p := range annotations {
  3152. if strings.HasPrefix(k, core.SeccompContainerAnnotationKeyPrefix) {
  3153. allErrs = append(allErrs, ValidateSeccompProfile(p, fldPath.Child(k))...)
  3154. }
  3155. }
  3156. return allErrs
  3157. }
  3158. func ValidateAppArmorPodAnnotations(annotations map[string]string, spec *core.PodSpec, fldPath *field.Path) field.ErrorList {
  3159. allErrs := field.ErrorList{}
  3160. for k, p := range annotations {
  3161. if !strings.HasPrefix(k, apparmor.ContainerAnnotationKeyPrefix) {
  3162. continue
  3163. }
  3164. containerName := strings.TrimPrefix(k, apparmor.ContainerAnnotationKeyPrefix)
  3165. if !podSpecHasContainer(spec, containerName) {
  3166. allErrs = append(allErrs, field.Invalid(fldPath.Key(k), containerName, "container not found"))
  3167. }
  3168. if err := apparmor.ValidateProfileFormat(p); err != nil {
  3169. allErrs = append(allErrs, field.Invalid(fldPath.Key(k), p, err.Error()))
  3170. }
  3171. }
  3172. return allErrs
  3173. }
  3174. func podSpecHasContainer(spec *core.PodSpec, containerName string) bool {
  3175. var hasContainer bool
  3176. podshelper.VisitContainersWithPath(spec, func(c *core.Container, _ *field.Path) bool {
  3177. if c.Name == containerName {
  3178. hasContainer = true
  3179. return false
  3180. }
  3181. return true
  3182. })
  3183. return hasContainer
  3184. }
  3185. const (
  3186. // a sysctl segment regex, concatenated with dots to form a sysctl name
  3187. SysctlSegmentFmt string = "[a-z0-9]([-_a-z0-9]*[a-z0-9])?"
  3188. // a sysctl name regex
  3189. SysctlFmt string = "(" + SysctlSegmentFmt + "\\.)*" + SysctlSegmentFmt
  3190. // the maximal length of a sysctl name
  3191. SysctlMaxLength int = 253
  3192. )
  3193. var sysctlRegexp = regexp.MustCompile("^" + SysctlFmt + "$")
  3194. // IsValidSysctlName checks that the given string is a valid sysctl name,
  3195. // i.e. matches SysctlFmt.
  3196. func IsValidSysctlName(name string) bool {
  3197. if len(name) > SysctlMaxLength {
  3198. return false
  3199. }
  3200. return sysctlRegexp.MatchString(name)
  3201. }
  3202. func validateSysctls(sysctls []core.Sysctl, fldPath *field.Path) field.ErrorList {
  3203. allErrs := field.ErrorList{}
  3204. names := make(map[string]struct{})
  3205. for i, s := range sysctls {
  3206. if len(s.Name) == 0 {
  3207. allErrs = append(allErrs, field.Required(fldPath.Index(i).Child("name"), ""))
  3208. } else if !IsValidSysctlName(s.Name) {
  3209. allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("name"), s.Name, fmt.Sprintf("must have at most %d characters and match regex %s", SysctlMaxLength, SysctlFmt)))
  3210. } else if _, ok := names[s.Name]; ok {
  3211. allErrs = append(allErrs, field.Duplicate(fldPath.Index(i).Child("name"), s.Name))
  3212. }
  3213. names[s.Name] = struct{}{}
  3214. }
  3215. return allErrs
  3216. }
  3217. // ValidatePodSecurityContext test that the specified PodSecurityContext has valid data.
  3218. func ValidatePodSecurityContext(securityContext *core.PodSecurityContext, spec *core.PodSpec, specPath, fldPath *field.Path) field.ErrorList {
  3219. allErrs := field.ErrorList{}
  3220. if securityContext != nil {
  3221. allErrs = append(allErrs, validateHostNetwork(securityContext.HostNetwork, spec.Containers, specPath.Child("containers"))...)
  3222. if securityContext.FSGroup != nil {
  3223. for _, msg := range validation.IsValidGroupID(*securityContext.FSGroup) {
  3224. allErrs = append(allErrs, field.Invalid(fldPath.Child("fsGroup"), *(securityContext.FSGroup), msg))
  3225. }
  3226. }
  3227. if securityContext.RunAsUser != nil {
  3228. for _, msg := range validation.IsValidUserID(*securityContext.RunAsUser) {
  3229. allErrs = append(allErrs, field.Invalid(fldPath.Child("runAsUser"), *(securityContext.RunAsUser), msg))
  3230. }
  3231. }
  3232. if securityContext.RunAsGroup != nil {
  3233. for _, msg := range validation.IsValidGroupID(*securityContext.RunAsGroup) {
  3234. allErrs = append(allErrs, field.Invalid(fldPath.Child("runAsGroup"), *(securityContext.RunAsGroup), msg))
  3235. }
  3236. }
  3237. for g, gid := range securityContext.SupplementalGroups {
  3238. for _, msg := range validation.IsValidGroupID(gid) {
  3239. allErrs = append(allErrs, field.Invalid(fldPath.Child("supplementalGroups").Index(g), gid, msg))
  3240. }
  3241. }
  3242. if securityContext.ShareProcessNamespace != nil && securityContext.HostPID && *securityContext.ShareProcessNamespace {
  3243. allErrs = append(allErrs, field.Invalid(fldPath.Child("shareProcessNamespace"), *securityContext.ShareProcessNamespace, "ShareProcessNamespace and HostPID cannot both be enabled"))
  3244. }
  3245. if len(securityContext.Sysctls) != 0 {
  3246. allErrs = append(allErrs, validateSysctls(securityContext.Sysctls, fldPath.Child("sysctls"))...)
  3247. }
  3248. allErrs = append(allErrs, validateWindowsSecurityContextOptions(securityContext.WindowsOptions, fldPath.Child("windowsOptions"))...)
  3249. }
  3250. return allErrs
  3251. }
  3252. func ValidateContainerUpdates(newContainers, oldContainers []core.Container, fldPath *field.Path) (allErrs field.ErrorList, stop bool) {
  3253. allErrs = field.ErrorList{}
  3254. if len(newContainers) != len(oldContainers) {
  3255. //TODO: Pinpoint the specific container that causes the invalid error after we have strategic merge diff
  3256. allErrs = append(allErrs, field.Forbidden(fldPath, "pod updates may not add or remove containers"))
  3257. return allErrs, true
  3258. }
  3259. // validate updated container images
  3260. for i, ctr := range newContainers {
  3261. if len(ctr.Image) == 0 {
  3262. allErrs = append(allErrs, field.Required(fldPath.Index(i).Child("image"), ""))
  3263. }
  3264. // this is only called from ValidatePodUpdate so its safe to check leading/trailing whitespace.
  3265. if len(strings.TrimSpace(ctr.Image)) != len(ctr.Image) {
  3266. allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("image"), ctr.Image, "must not have leading or trailing whitespace"))
  3267. }
  3268. }
  3269. return allErrs, false
  3270. }
  3271. // ValidatePodCreate validates a pod in the context of its initial create
  3272. func ValidatePodCreate(pod *core.Pod) field.ErrorList {
  3273. allErrs := ValidatePod(pod)
  3274. fldPath := field.NewPath("spec")
  3275. // EphemeralContainers can only be set on update using the ephemeralcontainers subresource
  3276. if len(pod.Spec.EphemeralContainers) > 0 {
  3277. allErrs = append(allErrs, field.Forbidden(fldPath.Child("ephemeralContainers"), "cannot be set on create"))
  3278. }
  3279. return allErrs
  3280. }
  3281. // ValidatePodUpdate tests to see if the update is legal for an end user to make. newPod is updated with fields
  3282. // that cannot be changed.
  3283. func ValidatePodUpdate(newPod, oldPod *core.Pod) field.ErrorList {
  3284. fldPath := field.NewPath("metadata")
  3285. allErrs := ValidateObjectMetaUpdate(&newPod.ObjectMeta, &oldPod.ObjectMeta, fldPath)
  3286. allErrs = append(allErrs, ValidatePodSpecificAnnotationUpdates(newPod, oldPod, fldPath.Child("annotations"))...)
  3287. specPath := field.NewPath("spec")
  3288. // validate updateable fields:
  3289. // 1. spec.containers[*].image
  3290. // 2. spec.initContainers[*].image
  3291. // 3. spec.activeDeadlineSeconds
  3292. containerErrs, stop := ValidateContainerUpdates(newPod.Spec.Containers, oldPod.Spec.Containers, specPath.Child("containers"))
  3293. allErrs = append(allErrs, containerErrs...)
  3294. if stop {
  3295. return allErrs
  3296. }
  3297. containerErrs, stop = ValidateContainerUpdates(newPod.Spec.InitContainers, oldPod.Spec.InitContainers, specPath.Child("initContainers"))
  3298. allErrs = append(allErrs, containerErrs...)
  3299. if stop {
  3300. return allErrs
  3301. }
  3302. // validate updated spec.activeDeadlineSeconds. two types of updates are allowed:
  3303. // 1. from nil to a positive value
  3304. // 2. from a positive value to a lesser, non-negative value
  3305. if newPod.Spec.ActiveDeadlineSeconds != nil {
  3306. newActiveDeadlineSeconds := *newPod.Spec.ActiveDeadlineSeconds
  3307. if newActiveDeadlineSeconds < 0 || newActiveDeadlineSeconds > math.MaxInt32 {
  3308. allErrs = append(allErrs, field.Invalid(specPath.Child("activeDeadlineSeconds"), newActiveDeadlineSeconds, validation.InclusiveRangeError(0, math.MaxInt32)))
  3309. return allErrs
  3310. }
  3311. if oldPod.Spec.ActiveDeadlineSeconds != nil {
  3312. oldActiveDeadlineSeconds := *oldPod.Spec.ActiveDeadlineSeconds
  3313. if oldActiveDeadlineSeconds < newActiveDeadlineSeconds {
  3314. allErrs = append(allErrs, field.Invalid(specPath.Child("activeDeadlineSeconds"), newActiveDeadlineSeconds, "must be less than or equal to previous value"))
  3315. return allErrs
  3316. }
  3317. }
  3318. } else if oldPod.Spec.ActiveDeadlineSeconds != nil {
  3319. allErrs = append(allErrs, field.Invalid(specPath.Child("activeDeadlineSeconds"), newPod.Spec.ActiveDeadlineSeconds, "must not update from a positive integer to nil value"))
  3320. }
  3321. // handle updateable fields by munging those fields prior to deep equal comparison.
  3322. mungedPod := *newPod
  3323. // munge spec.containers[*].image
  3324. var newContainers []core.Container
  3325. for ix, container := range mungedPod.Spec.Containers {
  3326. container.Image = oldPod.Spec.Containers[ix].Image
  3327. newContainers = append(newContainers, container)
  3328. }
  3329. mungedPod.Spec.Containers = newContainers
  3330. // munge spec.initContainers[*].image
  3331. var newInitContainers []core.Container
  3332. for ix, container := range mungedPod.Spec.InitContainers {
  3333. container.Image = oldPod.Spec.InitContainers[ix].Image
  3334. newInitContainers = append(newInitContainers, container)
  3335. }
  3336. mungedPod.Spec.InitContainers = newInitContainers
  3337. // munge spec.activeDeadlineSeconds
  3338. mungedPod.Spec.ActiveDeadlineSeconds = nil
  3339. if oldPod.Spec.ActiveDeadlineSeconds != nil {
  3340. activeDeadlineSeconds := *oldPod.Spec.ActiveDeadlineSeconds
  3341. mungedPod.Spec.ActiveDeadlineSeconds = &activeDeadlineSeconds
  3342. }
  3343. // Allow only additions to tolerations updates.
  3344. mungedPod.Spec.Tolerations = oldPod.Spec.Tolerations
  3345. allErrs = append(allErrs, validateOnlyAddedTolerations(newPod.Spec.Tolerations, oldPod.Spec.Tolerations, specPath.Child("tolerations"))...)
  3346. if !apiequality.Semantic.DeepEqual(mungedPod.Spec, oldPod.Spec) {
  3347. // This diff isn't perfect, but it's a helluva lot better an "I'm not going to tell you what the difference is".
  3348. //TODO: Pinpoint the specific field that causes the invalid error after we have strategic merge diff
  3349. specDiff := diff.ObjectDiff(mungedPod.Spec, oldPod.Spec)
  3350. allErrs = append(allErrs, field.Forbidden(specPath, fmt.Sprintf("pod updates may not change fields other than `spec.containers[*].image`, `spec.initContainers[*].image`, `spec.activeDeadlineSeconds` or `spec.tolerations` (only additions to existing tolerations)\n%v", specDiff)))
  3351. }
  3352. return allErrs
  3353. }
  3354. // ValidateContainerStateTransition test to if any illegal container state transitions are being attempted
  3355. func ValidateContainerStateTransition(newStatuses, oldStatuses []core.ContainerStatus, fldpath *field.Path, restartPolicy core.RestartPolicy) field.ErrorList {
  3356. allErrs := field.ErrorList{}
  3357. // If we should always restart, containers are allowed to leave the terminated state
  3358. if restartPolicy == core.RestartPolicyAlways {
  3359. return allErrs
  3360. }
  3361. for i, oldStatus := range oldStatuses {
  3362. // Skip any container that is not terminated
  3363. if oldStatus.State.Terminated == nil {
  3364. continue
  3365. }
  3366. // Skip any container that failed but is allowed to restart
  3367. if oldStatus.State.Terminated.ExitCode != 0 && restartPolicy == core.RestartPolicyOnFailure {
  3368. continue
  3369. }
  3370. for _, newStatus := range newStatuses {
  3371. if oldStatus.Name == newStatus.Name && newStatus.State.Terminated == nil {
  3372. allErrs = append(allErrs, field.Forbidden(fldpath.Index(i).Child("state"), "may not be transitioned to non-terminated state"))
  3373. }
  3374. }
  3375. }
  3376. return allErrs
  3377. }
  3378. // ValidatePodStatusUpdate tests to see if the update is legal for an end user to make. newPod is updated with fields
  3379. // that cannot be changed.
  3380. func ValidatePodStatusUpdate(newPod, oldPod *core.Pod) field.ErrorList {
  3381. fldPath := field.NewPath("metadata")
  3382. allErrs := ValidateObjectMetaUpdate(&newPod.ObjectMeta, &oldPod.ObjectMeta, fldPath)
  3383. allErrs = append(allErrs, ValidatePodSpecificAnnotationUpdates(newPod, oldPod, fldPath.Child("annotations"))...)
  3384. allErrs = append(allErrs, validatePodConditions(newPod.Status.Conditions, fldPath.Child("conditions"))...)
  3385. fldPath = field.NewPath("status")
  3386. if newPod.Spec.NodeName != oldPod.Spec.NodeName {
  3387. allErrs = append(allErrs, field.Forbidden(fldPath.Child("nodeName"), "may not be changed directly"))
  3388. }
  3389. if newPod.Status.NominatedNodeName != oldPod.Status.NominatedNodeName && len(newPod.Status.NominatedNodeName) > 0 {
  3390. for _, msg := range ValidateNodeName(newPod.Status.NominatedNodeName, false) {
  3391. allErrs = append(allErrs, field.Invalid(fldPath.Child("nominatedNodeName"), newPod.Status.NominatedNodeName, msg))
  3392. }
  3393. }
  3394. // If pod should not restart, make sure the status update does not transition
  3395. // any terminated containers to a non-terminated state.
  3396. allErrs = append(allErrs, ValidateContainerStateTransition(newPod.Status.ContainerStatuses, oldPod.Status.ContainerStatuses, fldPath.Child("containerStatuses"), oldPod.Spec.RestartPolicy)...)
  3397. allErrs = append(allErrs, ValidateContainerStateTransition(newPod.Status.InitContainerStatuses, oldPod.Status.InitContainerStatuses, fldPath.Child("initContainerStatuses"), oldPod.Spec.RestartPolicy)...)
  3398. // For status update we ignore changes to pod spec.
  3399. newPod.Spec = oldPod.Spec
  3400. return allErrs
  3401. }
  3402. // validatePodConditions tests if the custom pod conditions are valid.
  3403. func validatePodConditions(conditions []core.PodCondition, fldPath *field.Path) field.ErrorList {
  3404. allErrs := field.ErrorList{}
  3405. systemConditions := sets.NewString(string(core.PodScheduled), string(core.PodReady), string(core.PodInitialized))
  3406. for i, condition := range conditions {
  3407. if systemConditions.Has(string(condition.Type)) {
  3408. continue
  3409. }
  3410. for _, msg := range validation.IsQualifiedName(string(condition.Type)) {
  3411. allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("Type"), string(condition.Type), msg))
  3412. }
  3413. }
  3414. return allErrs
  3415. }
  3416. // ValidatePodEphemeralContainersUpdate tests that a user update to EphemeralContainers is valid.
  3417. // newPod and oldPod must only differ in their EphemeralContainers.
  3418. func ValidatePodEphemeralContainersUpdate(newPod, oldPod *core.Pod) field.ErrorList {
  3419. spec := newPod.Spec
  3420. specPath := field.NewPath("spec").Child("ephemeralContainers")
  3421. vols := make(map[string]core.VolumeSource)
  3422. for _, vol := range spec.Volumes {
  3423. vols[vol.Name] = vol.VolumeSource
  3424. }
  3425. allErrs := validateEphemeralContainers(spec.EphemeralContainers, spec.Containers, spec.InitContainers, vols, specPath)
  3426. // Existing EphemeralContainers may not be changed. Order isn't preserved by patch, so check each individually.
  3427. newContainerIndex := make(map[string]*core.EphemeralContainer)
  3428. for i := range newPod.Spec.EphemeralContainers {
  3429. newContainerIndex[newPod.Spec.EphemeralContainers[i].Name] = &newPod.Spec.EphemeralContainers[i]
  3430. }
  3431. for _, old := range oldPod.Spec.EphemeralContainers {
  3432. if new, ok := newContainerIndex[old.Name]; !ok {
  3433. allErrs = append(allErrs, field.Forbidden(specPath, fmt.Sprintf("existing ephemeral containers %q may not be removed\n", old.Name)))
  3434. } else if !apiequality.Semantic.DeepEqual(old, *new) {
  3435. specDiff := diff.ObjectDiff(old, *new)
  3436. allErrs = append(allErrs, field.Forbidden(specPath, fmt.Sprintf("existing ephemeral containers %q may not be changed\n%v", old.Name, specDiff)))
  3437. }
  3438. }
  3439. return allErrs
  3440. }
  3441. // ValidatePodBinding tests if required fields in the pod binding are legal.
  3442. func ValidatePodBinding(binding *core.Binding) field.ErrorList {
  3443. allErrs := field.ErrorList{}
  3444. if len(binding.Target.Kind) != 0 && binding.Target.Kind != "Node" {
  3445. // TODO: When validation becomes versioned, this gets more complicated.
  3446. allErrs = append(allErrs, field.NotSupported(field.NewPath("target", "kind"), binding.Target.Kind, []string{"Node", "<empty>"}))
  3447. }
  3448. if len(binding.Target.Name) == 0 {
  3449. // TODO: When validation becomes versioned, this gets more complicated.
  3450. allErrs = append(allErrs, field.Required(field.NewPath("target", "name"), ""))
  3451. }
  3452. return allErrs
  3453. }
  3454. // ValidatePodTemplate tests if required fields in the pod template are set.
  3455. func ValidatePodTemplate(pod *core.PodTemplate) field.ErrorList {
  3456. allErrs := ValidateObjectMeta(&pod.ObjectMeta, true, ValidatePodName, field.NewPath("metadata"))
  3457. allErrs = append(allErrs, ValidatePodTemplateSpec(&pod.Template, field.NewPath("template"))...)
  3458. return allErrs
  3459. }
  3460. // ValidatePodTemplateUpdate tests to see if the update is legal for an end user to make. newPod is updated with fields
  3461. // that cannot be changed.
  3462. func ValidatePodTemplateUpdate(newPod, oldPod *core.PodTemplate) field.ErrorList {
  3463. allErrs := ValidateObjectMetaUpdate(&newPod.ObjectMeta, &oldPod.ObjectMeta, field.NewPath("metadata"))
  3464. allErrs = append(allErrs, ValidatePodTemplateSpec(&newPod.Template, field.NewPath("template"))...)
  3465. return allErrs
  3466. }
  3467. var supportedSessionAffinityType = sets.NewString(string(core.ServiceAffinityClientIP), string(core.ServiceAffinityNone))
  3468. var supportedServiceType = sets.NewString(string(core.ServiceTypeClusterIP), string(core.ServiceTypeNodePort),
  3469. string(core.ServiceTypeLoadBalancer), string(core.ServiceTypeExternalName))
  3470. var supportedServiceIPFamily = sets.NewString(string(core.IPv4Protocol), string(core.IPv6Protocol))
  3471. // ValidateService tests if required fields/annotations of a Service are valid.
  3472. func ValidateService(service *core.Service) field.ErrorList {
  3473. allErrs := ValidateObjectMeta(&service.ObjectMeta, true, ValidateServiceName, field.NewPath("metadata"))
  3474. specPath := field.NewPath("spec")
  3475. isHeadlessService := service.Spec.ClusterIP == core.ClusterIPNone
  3476. if len(service.Spec.Ports) == 0 && !isHeadlessService && service.Spec.Type != core.ServiceTypeExternalName {
  3477. allErrs = append(allErrs, field.Required(specPath.Child("ports"), ""))
  3478. }
  3479. switch service.Spec.Type {
  3480. case core.ServiceTypeLoadBalancer:
  3481. for ix := range service.Spec.Ports {
  3482. port := &service.Spec.Ports[ix]
  3483. // This is a workaround for broken cloud environments that
  3484. // over-open firewalls. Hopefully it can go away when more clouds
  3485. // understand containers better.
  3486. if port.Port == ports.KubeletPort {
  3487. portPath := specPath.Child("ports").Index(ix)
  3488. allErrs = append(allErrs, field.Invalid(portPath, port.Port, fmt.Sprintf("may not expose port %v externally since it is used by kubelet", ports.KubeletPort)))
  3489. }
  3490. }
  3491. if service.Spec.ClusterIP == "None" {
  3492. allErrs = append(allErrs, field.Invalid(specPath.Child("clusterIP"), service.Spec.ClusterIP, "may not be set to 'None' for LoadBalancer services"))
  3493. }
  3494. case core.ServiceTypeNodePort:
  3495. if service.Spec.ClusterIP == "None" {
  3496. allErrs = append(allErrs, field.Invalid(specPath.Child("clusterIP"), service.Spec.ClusterIP, "may not be set to 'None' for NodePort services"))
  3497. }
  3498. case core.ServiceTypeExternalName:
  3499. if service.Spec.ClusterIP != "" {
  3500. allErrs = append(allErrs, field.Forbidden(specPath.Child("clusterIP"), "must be empty for ExternalName services"))
  3501. }
  3502. // The value (a CNAME) may have a trailing dot to denote it as fully qualified
  3503. cname := strings.TrimSuffix(service.Spec.ExternalName, ".")
  3504. if len(cname) > 0 {
  3505. allErrs = append(allErrs, ValidateDNS1123Subdomain(cname, specPath.Child("externalName"))...)
  3506. } else {
  3507. allErrs = append(allErrs, field.Required(specPath.Child("externalName"), ""))
  3508. }
  3509. }
  3510. allPortNames := sets.String{}
  3511. portsPath := specPath.Child("ports")
  3512. for i := range service.Spec.Ports {
  3513. portPath := portsPath.Index(i)
  3514. allErrs = append(allErrs, validateServicePort(&service.Spec.Ports[i], len(service.Spec.Ports) > 1, isHeadlessService, &allPortNames, portPath)...)
  3515. }
  3516. if service.Spec.Selector != nil {
  3517. allErrs = append(allErrs, unversionedvalidation.ValidateLabels(service.Spec.Selector, specPath.Child("selector"))...)
  3518. }
  3519. if len(service.Spec.SessionAffinity) == 0 {
  3520. allErrs = append(allErrs, field.Required(specPath.Child("sessionAffinity"), ""))
  3521. } else if !supportedSessionAffinityType.Has(string(service.Spec.SessionAffinity)) {
  3522. allErrs = append(allErrs, field.NotSupported(specPath.Child("sessionAffinity"), service.Spec.SessionAffinity, supportedSessionAffinityType.List()))
  3523. }
  3524. if service.Spec.SessionAffinity == core.ServiceAffinityClientIP {
  3525. allErrs = append(allErrs, validateClientIPAffinityConfig(service.Spec.SessionAffinityConfig, specPath.Child("sessionAffinityConfig"))...)
  3526. } else if service.Spec.SessionAffinity == core.ServiceAffinityNone {
  3527. if service.Spec.SessionAffinityConfig != nil {
  3528. allErrs = append(allErrs, field.Forbidden(specPath.Child("sessionAffinityConfig"), fmt.Sprintf("must not be set when session affinity is %s", string(core.ServiceAffinityNone))))
  3529. }
  3530. }
  3531. if helper.IsServiceIPSet(service) {
  3532. if ip := net.ParseIP(service.Spec.ClusterIP); ip == nil {
  3533. allErrs = append(allErrs, field.Invalid(specPath.Child("clusterIP"), service.Spec.ClusterIP, "must be empty, 'None', or a valid IP address"))
  3534. }
  3535. }
  3536. ipPath := specPath.Child("externalIPs")
  3537. for i, ip := range service.Spec.ExternalIPs {
  3538. idxPath := ipPath.Index(i)
  3539. if msgs := validation.IsValidIP(ip); len(msgs) != 0 {
  3540. for i := range msgs {
  3541. allErrs = append(allErrs, field.Invalid(idxPath, ip, msgs[i]))
  3542. }
  3543. } else {
  3544. allErrs = append(allErrs, validateNonSpecialIP(ip, idxPath)...)
  3545. }
  3546. }
  3547. if len(service.Spec.Type) == 0 {
  3548. allErrs = append(allErrs, field.Required(specPath.Child("type"), ""))
  3549. } else if !supportedServiceType.Has(string(service.Spec.Type)) {
  3550. allErrs = append(allErrs, field.NotSupported(specPath.Child("type"), service.Spec.Type, supportedServiceType.List()))
  3551. }
  3552. if service.Spec.Type == core.ServiceTypeLoadBalancer {
  3553. portsPath := specPath.Child("ports")
  3554. includeProtocols := sets.NewString()
  3555. for i := range service.Spec.Ports {
  3556. portPath := portsPath.Index(i)
  3557. if !supportedPortProtocols.Has(string(service.Spec.Ports[i].Protocol)) {
  3558. allErrs = append(allErrs, field.Invalid(portPath.Child("protocol"), service.Spec.Ports[i].Protocol, "cannot create an external load balancer with non-TCP/UDP/SCTP ports"))
  3559. } else {
  3560. includeProtocols.Insert(string(service.Spec.Ports[i].Protocol))
  3561. }
  3562. }
  3563. if includeProtocols.Len() > 1 {
  3564. allErrs = append(allErrs, field.Invalid(portsPath, service.Spec.Ports, "cannot create an external load balancer with mix protocols"))
  3565. }
  3566. }
  3567. if service.Spec.Type == core.ServiceTypeClusterIP {
  3568. portsPath := specPath.Child("ports")
  3569. for i := range service.Spec.Ports {
  3570. portPath := portsPath.Index(i)
  3571. if service.Spec.Ports[i].NodePort != 0 {
  3572. allErrs = append(allErrs, field.Forbidden(portPath.Child("nodePort"), "may not be used when `type` is 'ClusterIP'"))
  3573. }
  3574. }
  3575. }
  3576. // Check for duplicate NodePorts, considering (protocol,port) pairs
  3577. portsPath = specPath.Child("ports")
  3578. nodePorts := make(map[core.ServicePort]bool)
  3579. for i := range service.Spec.Ports {
  3580. port := &service.Spec.Ports[i]
  3581. if port.NodePort == 0 {
  3582. continue
  3583. }
  3584. portPath := portsPath.Index(i)
  3585. var key core.ServicePort
  3586. key.Protocol = port.Protocol
  3587. key.NodePort = port.NodePort
  3588. _, found := nodePorts[key]
  3589. if found {
  3590. allErrs = append(allErrs, field.Duplicate(portPath.Child("nodePort"), port.NodePort))
  3591. }
  3592. nodePorts[key] = true
  3593. }
  3594. // Check for duplicate Ports, considering (protocol,port) pairs
  3595. portsPath = specPath.Child("ports")
  3596. ports := make(map[core.ServicePort]bool)
  3597. for i, port := range service.Spec.Ports {
  3598. portPath := portsPath.Index(i)
  3599. key := core.ServicePort{Protocol: port.Protocol, Port: port.Port}
  3600. _, found := ports[key]
  3601. if found {
  3602. allErrs = append(allErrs, field.Duplicate(portPath, key))
  3603. }
  3604. ports[key] = true
  3605. }
  3606. // Validate TopologyKeys
  3607. if len(service.Spec.TopologyKeys) > 0 {
  3608. topoPath := specPath.Child("topologyKeys")
  3609. // topologyKeys is mutually exclusive with 'externalTrafficPolicy=Local'
  3610. if service.Spec.ExternalTrafficPolicy == core.ServiceExternalTrafficPolicyTypeLocal {
  3611. allErrs = append(allErrs, field.Forbidden(topoPath, "may not be specified when `externalTrafficPolicy=Local`"))
  3612. }
  3613. if len(service.Spec.TopologyKeys) > core.MaxServiceTopologyKeys {
  3614. allErrs = append(allErrs, field.TooMany(topoPath, len(service.Spec.TopologyKeys), core.MaxServiceTopologyKeys))
  3615. }
  3616. topoKeys := sets.NewString()
  3617. for i, key := range service.Spec.TopologyKeys {
  3618. keyPath := topoPath.Index(i)
  3619. if topoKeys.Has(key) {
  3620. allErrs = append(allErrs, field.Duplicate(keyPath, key))
  3621. }
  3622. topoKeys.Insert(key)
  3623. // "Any" must be the last value specified
  3624. if key == v1.TopologyKeyAny && i != len(service.Spec.TopologyKeys)-1 {
  3625. allErrs = append(allErrs, field.Invalid(keyPath, key, `"*" must be the last value specified`))
  3626. }
  3627. if key != v1.TopologyKeyAny {
  3628. for _, msg := range validation.IsQualifiedName(key) {
  3629. allErrs = append(allErrs, field.Invalid(keyPath, service.Spec.TopologyKeys, msg))
  3630. }
  3631. }
  3632. }
  3633. }
  3634. // Validate SourceRange field and annotation
  3635. _, ok := service.Annotations[core.AnnotationLoadBalancerSourceRangesKey]
  3636. if len(service.Spec.LoadBalancerSourceRanges) > 0 || ok {
  3637. var fieldPath *field.Path
  3638. var val string
  3639. if len(service.Spec.LoadBalancerSourceRanges) > 0 {
  3640. fieldPath = specPath.Child("LoadBalancerSourceRanges")
  3641. val = fmt.Sprintf("%v", service.Spec.LoadBalancerSourceRanges)
  3642. } else {
  3643. fieldPath = field.NewPath("metadata", "annotations").Key(core.AnnotationLoadBalancerSourceRangesKey)
  3644. val = service.Annotations[core.AnnotationLoadBalancerSourceRangesKey]
  3645. }
  3646. if service.Spec.Type != core.ServiceTypeLoadBalancer {
  3647. allErrs = append(allErrs, field.Forbidden(fieldPath, "may only be used when `type` is 'LoadBalancer'"))
  3648. }
  3649. _, err := apiservice.GetLoadBalancerSourceRanges(service)
  3650. if err != nil {
  3651. allErrs = append(allErrs, field.Invalid(fieldPath, val, "must be a list of IP ranges. For example, 10.240.0.0/24,10.250.0.0/24 "))
  3652. }
  3653. }
  3654. //if an ipfamily provided then it has to be one of the supported values
  3655. // note:
  3656. // - we don't validate service.Spec.IPFamily is supported by the cluster
  3657. // - we don't validate service.Spec.ClusterIP is within a range supported by the cluster
  3658. // both of these validations are done by the ipallocator
  3659. // if the gate is on this field is required (and defaulted by REST if not provided by user)
  3660. if utilfeature.DefaultFeatureGate.Enabled(features.IPv6DualStack) && service.Spec.IPFamily == nil {
  3661. allErrs = append(allErrs, field.Required(specPath.Child("ipFamily"), ""))
  3662. }
  3663. if service.Spec.IPFamily != nil && !supportedServiceIPFamily.Has(string(*service.Spec.IPFamily)) {
  3664. allErrs = append(allErrs, field.NotSupported(specPath.Child("ipFamily"), service.Spec.IPFamily, supportedServiceIPFamily.List()))
  3665. }
  3666. allErrs = append(allErrs, validateServiceExternalTrafficFieldsValue(service)...)
  3667. return allErrs
  3668. }
  3669. func validateServicePort(sp *core.ServicePort, requireName, isHeadlessService bool, allNames *sets.String, fldPath *field.Path) field.ErrorList {
  3670. allErrs := field.ErrorList{}
  3671. if requireName && len(sp.Name) == 0 {
  3672. allErrs = append(allErrs, field.Required(fldPath.Child("name"), ""))
  3673. } else if len(sp.Name) != 0 {
  3674. allErrs = append(allErrs, ValidateDNS1123Label(sp.Name, fldPath.Child("name"))...)
  3675. if allNames.Has(sp.Name) {
  3676. allErrs = append(allErrs, field.Duplicate(fldPath.Child("name"), sp.Name))
  3677. } else {
  3678. allNames.Insert(sp.Name)
  3679. }
  3680. }
  3681. for _, msg := range validation.IsValidPortNum(int(sp.Port)) {
  3682. allErrs = append(allErrs, field.Invalid(fldPath.Child("port"), sp.Port, msg))
  3683. }
  3684. if len(sp.Protocol) == 0 {
  3685. allErrs = append(allErrs, field.Required(fldPath.Child("protocol"), ""))
  3686. } else if !supportedPortProtocols.Has(string(sp.Protocol)) {
  3687. allErrs = append(allErrs, field.NotSupported(fldPath.Child("protocol"), sp.Protocol, supportedPortProtocols.List()))
  3688. }
  3689. allErrs = append(allErrs, ValidatePortNumOrName(sp.TargetPort, fldPath.Child("targetPort"))...)
  3690. // in the v1 API, targetPorts on headless services were tolerated.
  3691. // once we have version-specific validation, we can reject this on newer API versions, but until then, we have to tolerate it for compatibility.
  3692. //
  3693. // if isHeadlessService {
  3694. // if sp.TargetPort.Type == intstr.String || (sp.TargetPort.Type == intstr.Int && sp.Port != sp.TargetPort.IntValue()) {
  3695. // allErrs = append(allErrs, field.Invalid(fldPath.Child("targetPort"), sp.TargetPort, "must be equal to the value of 'port' when clusterIP = None"))
  3696. // }
  3697. // }
  3698. return allErrs
  3699. }
  3700. // validateServiceExternalTrafficFieldsValue validates ExternalTraffic related annotations
  3701. // have legal value.
  3702. func validateServiceExternalTrafficFieldsValue(service *core.Service) field.ErrorList {
  3703. allErrs := field.ErrorList{}
  3704. // Check first class fields.
  3705. if service.Spec.ExternalTrafficPolicy != "" &&
  3706. service.Spec.ExternalTrafficPolicy != core.ServiceExternalTrafficPolicyTypeCluster &&
  3707. service.Spec.ExternalTrafficPolicy != core.ServiceExternalTrafficPolicyTypeLocal {
  3708. allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("externalTrafficPolicy"), service.Spec.ExternalTrafficPolicy,
  3709. fmt.Sprintf("ExternalTrafficPolicy must be empty, %v or %v", core.ServiceExternalTrafficPolicyTypeCluster, core.ServiceExternalTrafficPolicyTypeLocal)))
  3710. }
  3711. if service.Spec.HealthCheckNodePort < 0 {
  3712. allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("healthCheckNodePort"), service.Spec.HealthCheckNodePort,
  3713. "HealthCheckNodePort must be not less than 0"))
  3714. }
  3715. return allErrs
  3716. }
  3717. // ValidateServiceExternalTrafficFieldsCombination validates if ExternalTrafficPolicy,
  3718. // HealthCheckNodePort and Type combination are legal. For update, it should be called
  3719. // after clearing externalTraffic related fields for the ease of transitioning between
  3720. // different service types.
  3721. func ValidateServiceExternalTrafficFieldsCombination(service *core.Service) field.ErrorList {
  3722. allErrs := field.ErrorList{}
  3723. if service.Spec.Type != core.ServiceTypeLoadBalancer &&
  3724. service.Spec.Type != core.ServiceTypeNodePort &&
  3725. service.Spec.ExternalTrafficPolicy != "" {
  3726. allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "externalTrafficPolicy"), service.Spec.ExternalTrafficPolicy,
  3727. "ExternalTrafficPolicy can only be set on NodePort and LoadBalancer service"))
  3728. }
  3729. if !apiservice.NeedsHealthCheck(service) &&
  3730. service.Spec.HealthCheckNodePort != 0 {
  3731. allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "healthCheckNodePort"), service.Spec.HealthCheckNodePort,
  3732. "HealthCheckNodePort can only be set on LoadBalancer service with ExternalTrafficPolicy=Local"))
  3733. }
  3734. return allErrs
  3735. }
  3736. // ValidateServiceUpdate tests if required fields in the service are set during an update
  3737. func ValidateServiceUpdate(service, oldService *core.Service) field.ErrorList {
  3738. allErrs := ValidateObjectMetaUpdate(&service.ObjectMeta, &oldService.ObjectMeta, field.NewPath("metadata"))
  3739. // ClusterIP and IPFamily should be immutable for services using it (every type other than ExternalName)
  3740. // which do not have ClusterIP assigned yet (empty string value)
  3741. if service.Spec.Type != core.ServiceTypeExternalName {
  3742. if oldService.Spec.Type != core.ServiceTypeExternalName && oldService.Spec.ClusterIP != "" {
  3743. allErrs = append(allErrs, ValidateImmutableField(service.Spec.ClusterIP, oldService.Spec.ClusterIP, field.NewPath("spec", "clusterIP"))...)
  3744. }
  3745. // notes:
  3746. // we drop the IPFamily field when the Dualstack gate is off.
  3747. // once the gate is on, we start assigning default ipfamily according to cluster settings. in other words
  3748. // though the field is immutable, we allow (onetime) change from nil==> to value
  3749. if oldService.Spec.IPFamily != nil {
  3750. allErrs = append(allErrs, ValidateImmutableField(service.Spec.IPFamily, oldService.Spec.IPFamily, field.NewPath("spec", "ipFamily"))...)
  3751. }
  3752. }
  3753. allErrs = append(allErrs, ValidateService(service)...)
  3754. return allErrs
  3755. }
  3756. // ValidateServiceStatusUpdate tests if required fields in the Service are set when updating status.
  3757. func ValidateServiceStatusUpdate(service, oldService *core.Service) field.ErrorList {
  3758. allErrs := ValidateObjectMetaUpdate(&service.ObjectMeta, &oldService.ObjectMeta, field.NewPath("metadata"))
  3759. allErrs = append(allErrs, ValidateLoadBalancerStatus(&service.Status.LoadBalancer, field.NewPath("status", "loadBalancer"))...)
  3760. return allErrs
  3761. }
  3762. // ValidateReplicationController tests if required fields in the replication controller are set.
  3763. func ValidateReplicationController(controller *core.ReplicationController) field.ErrorList {
  3764. allErrs := ValidateObjectMeta(&controller.ObjectMeta, true, ValidateReplicationControllerName, field.NewPath("metadata"))
  3765. allErrs = append(allErrs, ValidateReplicationControllerSpec(&controller.Spec, field.NewPath("spec"))...)
  3766. return allErrs
  3767. }
  3768. // ValidateReplicationControllerUpdate tests if required fields in the replication controller are set.
  3769. func ValidateReplicationControllerUpdate(controller, oldController *core.ReplicationController) field.ErrorList {
  3770. allErrs := ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, field.NewPath("metadata"))
  3771. allErrs = append(allErrs, ValidateReplicationControllerSpec(&controller.Spec, field.NewPath("spec"))...)
  3772. return allErrs
  3773. }
  3774. // ValidateReplicationControllerStatusUpdate tests if required fields in the replication controller are set.
  3775. func ValidateReplicationControllerStatusUpdate(controller, oldController *core.ReplicationController) field.ErrorList {
  3776. allErrs := ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, field.NewPath("metadata"))
  3777. allErrs = append(allErrs, ValidateReplicationControllerStatus(controller.Status, field.NewPath("status"))...)
  3778. return allErrs
  3779. }
  3780. func ValidateReplicationControllerStatus(status core.ReplicationControllerStatus, statusPath *field.Path) field.ErrorList {
  3781. allErrs := field.ErrorList{}
  3782. allErrs = append(allErrs, ValidateNonnegativeField(int64(status.Replicas), statusPath.Child("replicas"))...)
  3783. allErrs = append(allErrs, ValidateNonnegativeField(int64(status.FullyLabeledReplicas), statusPath.Child("fullyLabeledReplicas"))...)
  3784. allErrs = append(allErrs, ValidateNonnegativeField(int64(status.ReadyReplicas), statusPath.Child("readyReplicas"))...)
  3785. allErrs = append(allErrs, ValidateNonnegativeField(int64(status.AvailableReplicas), statusPath.Child("availableReplicas"))...)
  3786. allErrs = append(allErrs, ValidateNonnegativeField(int64(status.ObservedGeneration), statusPath.Child("observedGeneration"))...)
  3787. msg := "cannot be greater than status.replicas"
  3788. if status.FullyLabeledReplicas > status.Replicas {
  3789. allErrs = append(allErrs, field.Invalid(statusPath.Child("fullyLabeledReplicas"), status.FullyLabeledReplicas, msg))
  3790. }
  3791. if status.ReadyReplicas > status.Replicas {
  3792. allErrs = append(allErrs, field.Invalid(statusPath.Child("readyReplicas"), status.ReadyReplicas, msg))
  3793. }
  3794. if status.AvailableReplicas > status.Replicas {
  3795. allErrs = append(allErrs, field.Invalid(statusPath.Child("availableReplicas"), status.AvailableReplicas, msg))
  3796. }
  3797. if status.AvailableReplicas > status.ReadyReplicas {
  3798. allErrs = append(allErrs, field.Invalid(statusPath.Child("availableReplicas"), status.AvailableReplicas, "cannot be greater than readyReplicas"))
  3799. }
  3800. return allErrs
  3801. }
  3802. // Validates that the given selector is non-empty.
  3803. func ValidateNonEmptySelector(selectorMap map[string]string, fldPath *field.Path) field.ErrorList {
  3804. allErrs := field.ErrorList{}
  3805. selector := labels.Set(selectorMap).AsSelector()
  3806. if selector.Empty() {
  3807. allErrs = append(allErrs, field.Required(fldPath, ""))
  3808. }
  3809. return allErrs
  3810. }
  3811. // Validates the given template and ensures that it is in accordance with the desired selector and replicas.
  3812. func ValidatePodTemplateSpecForRC(template *core.PodTemplateSpec, selectorMap map[string]string, replicas int32, fldPath *field.Path) field.ErrorList {
  3813. allErrs := field.ErrorList{}
  3814. if template == nil {
  3815. allErrs = append(allErrs, field.Required(fldPath, ""))
  3816. } else {
  3817. selector := labels.Set(selectorMap).AsSelector()
  3818. if !selector.Empty() {
  3819. // Verify that the RC selector matches the labels in template.
  3820. labels := labels.Set(template.Labels)
  3821. if !selector.Matches(labels) {
  3822. allErrs = append(allErrs, field.Invalid(fldPath.Child("metadata", "labels"), template.Labels, "`selector` does not match template `labels`"))
  3823. }
  3824. }
  3825. allErrs = append(allErrs, ValidatePodTemplateSpec(template, fldPath)...)
  3826. if replicas > 1 {
  3827. allErrs = append(allErrs, ValidateReadOnlyPersistentDisks(template.Spec.Volumes, fldPath.Child("spec", "volumes"))...)
  3828. }
  3829. // RestartPolicy has already been first-order validated as per ValidatePodTemplateSpec().
  3830. if template.Spec.RestartPolicy != core.RestartPolicyAlways {
  3831. allErrs = append(allErrs, field.NotSupported(fldPath.Child("spec", "restartPolicy"), template.Spec.RestartPolicy, []string{string(core.RestartPolicyAlways)}))
  3832. }
  3833. if template.Spec.ActiveDeadlineSeconds != nil {
  3834. allErrs = append(allErrs, field.Forbidden(fldPath.Child("spec", "activeDeadlineSeconds"), "activeDeadlineSeconds in ReplicationController is not Supported"))
  3835. }
  3836. }
  3837. return allErrs
  3838. }
  3839. // ValidateReplicationControllerSpec tests if required fields in the replication controller spec are set.
  3840. func ValidateReplicationControllerSpec(spec *core.ReplicationControllerSpec, fldPath *field.Path) field.ErrorList {
  3841. allErrs := field.ErrorList{}
  3842. allErrs = append(allErrs, ValidateNonnegativeField(int64(spec.MinReadySeconds), fldPath.Child("minReadySeconds"))...)
  3843. allErrs = append(allErrs, ValidateNonEmptySelector(spec.Selector, fldPath.Child("selector"))...)
  3844. allErrs = append(allErrs, ValidateNonnegativeField(int64(spec.Replicas), fldPath.Child("replicas"))...)
  3845. allErrs = append(allErrs, ValidatePodTemplateSpecForRC(spec.Template, spec.Selector, spec.Replicas, fldPath.Child("template"))...)
  3846. return allErrs
  3847. }
  3848. // ValidatePodTemplateSpec validates the spec of a pod template
  3849. func ValidatePodTemplateSpec(spec *core.PodTemplateSpec, fldPath *field.Path) field.ErrorList {
  3850. allErrs := field.ErrorList{}
  3851. allErrs = append(allErrs, unversionedvalidation.ValidateLabels(spec.Labels, fldPath.Child("labels"))...)
  3852. allErrs = append(allErrs, ValidateAnnotations(spec.Annotations, fldPath.Child("annotations"))...)
  3853. allErrs = append(allErrs, ValidatePodSpecificAnnotations(spec.Annotations, &spec.Spec, fldPath.Child("annotations"))...)
  3854. allErrs = append(allErrs, ValidatePodSpec(&spec.Spec, fldPath.Child("spec"))...)
  3855. if len(spec.Spec.EphemeralContainers) > 0 {
  3856. allErrs = append(allErrs, field.Forbidden(fldPath.Child("spec", "ephemeralContainers"), "ephemeral containers not allowed in pod template"))
  3857. }
  3858. return allErrs
  3859. }
  3860. func ValidateReadOnlyPersistentDisks(volumes []core.Volume, fldPath *field.Path) field.ErrorList {
  3861. allErrs := field.ErrorList{}
  3862. for i := range volumes {
  3863. vol := &volumes[i]
  3864. idxPath := fldPath.Index(i)
  3865. if vol.GCEPersistentDisk != nil {
  3866. if !vol.GCEPersistentDisk.ReadOnly {
  3867. allErrs = append(allErrs, field.Invalid(idxPath.Child("gcePersistentDisk", "readOnly"), false, "must be true for replicated pods > 1; GCE PD can only be mounted on multiple machines if it is read-only"))
  3868. }
  3869. }
  3870. // TODO: What to do for AWS? It doesn't support replicas
  3871. }
  3872. return allErrs
  3873. }
  3874. // ValidateTaintsInNodeAnnotations tests that the serialized taints in Node.Annotations has valid data
  3875. func ValidateTaintsInNodeAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
  3876. allErrs := field.ErrorList{}
  3877. taints, err := helper.GetTaintsFromNodeAnnotations(annotations)
  3878. if err != nil {
  3879. allErrs = append(allErrs, field.Invalid(fldPath, core.TaintsAnnotationKey, err.Error()))
  3880. return allErrs
  3881. }
  3882. if len(taints) > 0 {
  3883. allErrs = append(allErrs, validateNodeTaints(taints, fldPath.Child(core.TaintsAnnotationKey))...)
  3884. }
  3885. return allErrs
  3886. }
  3887. // validateNodeTaints tests if given taints have valid data.
  3888. func validateNodeTaints(taints []core.Taint, fldPath *field.Path) field.ErrorList {
  3889. allErrors := field.ErrorList{}
  3890. uniqueTaints := map[core.TaintEffect]sets.String{}
  3891. for i, currTaint := range taints {
  3892. idxPath := fldPath.Index(i)
  3893. // validate the taint key
  3894. allErrors = append(allErrors, unversionedvalidation.ValidateLabelName(currTaint.Key, idxPath.Child("key"))...)
  3895. // validate the taint value
  3896. if errs := validation.IsValidLabelValue(currTaint.Value); len(errs) != 0 {
  3897. allErrors = append(allErrors, field.Invalid(idxPath.Child("value"), currTaint.Value, strings.Join(errs, ";")))
  3898. }
  3899. // validate the taint effect
  3900. allErrors = append(allErrors, validateTaintEffect(&currTaint.Effect, false, idxPath.Child("effect"))...)
  3901. // validate if taint is unique by <key, effect>
  3902. if len(uniqueTaints[currTaint.Effect]) > 0 && uniqueTaints[currTaint.Effect].Has(currTaint.Key) {
  3903. duplicatedError := field.Duplicate(idxPath, currTaint)
  3904. duplicatedError.Detail = "taints must be unique by key and effect pair"
  3905. allErrors = append(allErrors, duplicatedError)
  3906. continue
  3907. }
  3908. // add taint to existingTaints for uniqueness check
  3909. if len(uniqueTaints[currTaint.Effect]) == 0 {
  3910. uniqueTaints[currTaint.Effect] = sets.String{}
  3911. }
  3912. uniqueTaints[currTaint.Effect].Insert(currTaint.Key)
  3913. }
  3914. return allErrors
  3915. }
  3916. func ValidateNodeSpecificAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
  3917. allErrs := field.ErrorList{}
  3918. if annotations[core.TaintsAnnotationKey] != "" {
  3919. allErrs = append(allErrs, ValidateTaintsInNodeAnnotations(annotations, fldPath)...)
  3920. }
  3921. if annotations[core.PreferAvoidPodsAnnotationKey] != "" {
  3922. allErrs = append(allErrs, ValidateAvoidPodsInNodeAnnotations(annotations, fldPath)...)
  3923. }
  3924. return allErrs
  3925. }
  3926. // NodeValidationOptions contains the different settings for node validation
  3927. type NodeValidationOptions struct {
  3928. // Should node a spec containing more than one huge page resource (with different sizes)
  3929. // with pre-allocated memory trigger validation errors
  3930. ValidateSingleHugePageResource bool
  3931. }
  3932. // ValidateNode tests if required fields in the node are set.
  3933. func ValidateNode(node *core.Node, opts NodeValidationOptions) field.ErrorList {
  3934. fldPath := field.NewPath("metadata")
  3935. allErrs := ValidateObjectMeta(&node.ObjectMeta, false, ValidateNodeName, fldPath)
  3936. allErrs = append(allErrs, ValidateNodeSpecificAnnotations(node.ObjectMeta.Annotations, fldPath.Child("annotations"))...)
  3937. if len(node.Spec.Taints) > 0 {
  3938. allErrs = append(allErrs, validateNodeTaints(node.Spec.Taints, fldPath.Child("taints"))...)
  3939. }
  3940. // Only validate spec.
  3941. // All status fields are optional and can be updated later.
  3942. // That said, if specified, we need to ensure they are valid.
  3943. allErrs = append(allErrs, ValidateNodeResources(node, opts)...)
  3944. // validate PodCIDRS only if we need to
  3945. if len(node.Spec.PodCIDRs) > 0 {
  3946. podCIDRsField := field.NewPath("spec", "podCIDRs")
  3947. // all PodCIDRs should be valid ones
  3948. for idx, value := range node.Spec.PodCIDRs {
  3949. if _, err := ValidateCIDR(value); err != nil {
  3950. allErrs = append(allErrs, field.Invalid(podCIDRsField.Index(idx), node.Spec.PodCIDRs, "must be valid CIDR"))
  3951. }
  3952. }
  3953. // if more than PodCIDR then
  3954. // - validate for dual stack
  3955. // - validate for duplication
  3956. if len(node.Spec.PodCIDRs) > 1 {
  3957. dualStack, err := netutils.IsDualStackCIDRStrings(node.Spec.PodCIDRs)
  3958. if err != nil {
  3959. allErrs = append(allErrs, field.InternalError(podCIDRsField, fmt.Errorf("invalid PodCIDRs. failed to check with dual stack with error:%v", err)))
  3960. }
  3961. if !dualStack || len(node.Spec.PodCIDRs) > 2 {
  3962. allErrs = append(allErrs, field.Invalid(podCIDRsField, node.Spec.PodCIDRs, "may specify no more than one CIDR for each IP family"))
  3963. }
  3964. // PodCIDRs must not contain duplicates
  3965. seen := sets.String{}
  3966. for i, value := range node.Spec.PodCIDRs {
  3967. if seen.Has(value) {
  3968. allErrs = append(allErrs, field.Duplicate(podCIDRsField.Index(i), value))
  3969. }
  3970. seen.Insert(value)
  3971. }
  3972. }
  3973. }
  3974. return allErrs
  3975. }
  3976. // ValidateNodeResources is used to make sure a node has valid capacity and allocatable values.
  3977. func ValidateNodeResources(node *core.Node, opts NodeValidationOptions) field.ErrorList {
  3978. allErrs := field.ErrorList{}
  3979. if opts.ValidateSingleHugePageResource {
  3980. allErrs = append(allErrs, ValidateNodeSingleHugePageResources(node)...)
  3981. }
  3982. // Validate resource quantities in capacity.
  3983. for k, v := range node.Status.Capacity {
  3984. resPath := field.NewPath("status", "capacity", string(k))
  3985. allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...)
  3986. }
  3987. // Validate resource quantities in allocatable.
  3988. for k, v := range node.Status.Allocatable {
  3989. resPath := field.NewPath("status", "allocatable", string(k))
  3990. allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...)
  3991. }
  3992. return allErrs
  3993. }
  3994. // ValidateNodeHugePageResources is used to make sure a node has valid capacity and allocatable values for the huge page resources.
  3995. func ValidateNodeSingleHugePageResources(node *core.Node) field.ErrorList {
  3996. allErrs := field.ErrorList{}
  3997. // Validate resource quantities in capacity.
  3998. hugePageSizes := sets.NewString()
  3999. for k, v := range node.Status.Capacity {
  4000. resPath := field.NewPath("status", "capacity", string(k))
  4001. // track any huge page size that has a positive value
  4002. if helper.IsHugePageResourceName(k) && v.Value() > int64(0) {
  4003. hugePageSizes.Insert(string(k))
  4004. }
  4005. if len(hugePageSizes) > 1 {
  4006. allErrs = append(allErrs, field.Invalid(resPath, v, "may not have pre-allocated hugepages for multiple page sizes"))
  4007. }
  4008. }
  4009. // Validate resource quantities in allocatable.
  4010. hugePageSizes = sets.NewString()
  4011. for k, v := range node.Status.Allocatable {
  4012. resPath := field.NewPath("status", "allocatable", string(k))
  4013. // track any huge page size that has a positive value
  4014. if helper.IsHugePageResourceName(k) && v.Value() > int64(0) {
  4015. hugePageSizes.Insert(string(k))
  4016. }
  4017. if len(hugePageSizes) > 1 {
  4018. allErrs = append(allErrs, field.Invalid(resPath, v, "may not have pre-allocated hugepages for multiple page sizes"))
  4019. }
  4020. }
  4021. return allErrs
  4022. }
  4023. // ValidateNodeUpdate tests to make sure a node update can be applied. Modifies oldNode.
  4024. func ValidateNodeUpdate(node, oldNode *core.Node, opts NodeValidationOptions) field.ErrorList {
  4025. fldPath := field.NewPath("metadata")
  4026. allErrs := ValidateObjectMetaUpdate(&node.ObjectMeta, &oldNode.ObjectMeta, fldPath)
  4027. allErrs = append(allErrs, ValidateNodeSpecificAnnotations(node.ObjectMeta.Annotations, fldPath.Child("annotations"))...)
  4028. // TODO: Enable the code once we have better core object.status update model. Currently,
  4029. // anyone can update node status.
  4030. // if !apiequality.Semantic.DeepEqual(node.Status, core.NodeStatus{}) {
  4031. // allErrs = append(allErrs, field.Invalid("status", node.Status, "must be empty"))
  4032. // }
  4033. allErrs = append(allErrs, ValidateNodeResources(node, opts)...)
  4034. // Validate no duplicate addresses in node status.
  4035. addresses := make(map[core.NodeAddress]bool)
  4036. for i, address := range node.Status.Addresses {
  4037. if _, ok := addresses[address]; ok {
  4038. allErrs = append(allErrs, field.Duplicate(field.NewPath("status", "addresses").Index(i), address))
  4039. }
  4040. addresses[address] = true
  4041. }
  4042. if len(oldNode.Spec.PodCIDRs) == 0 {
  4043. // Allow the controller manager to assign a CIDR to a node if it doesn't have one.
  4044. //this is a no op for a string slice.
  4045. oldNode.Spec.PodCIDRs = node.Spec.PodCIDRs
  4046. } else {
  4047. // compare the entire slice
  4048. if len(oldNode.Spec.PodCIDRs) != len(node.Spec.PodCIDRs) {
  4049. allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "podCIDRs"), "node updates may not change podCIDR except from \"\" to valid"))
  4050. } else {
  4051. for idx, value := range oldNode.Spec.PodCIDRs {
  4052. if value != node.Spec.PodCIDRs[idx] {
  4053. allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "podCIDRs"), "node updates may not change podCIDR except from \"\" to valid"))
  4054. }
  4055. }
  4056. }
  4057. }
  4058. // Allow controller manager updating provider ID when not set
  4059. if len(oldNode.Spec.ProviderID) == 0 {
  4060. oldNode.Spec.ProviderID = node.Spec.ProviderID
  4061. } else {
  4062. if oldNode.Spec.ProviderID != node.Spec.ProviderID {
  4063. allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "providerID"), "node updates may not change providerID except from \"\" to valid"))
  4064. }
  4065. }
  4066. if node.Spec.ConfigSource != nil {
  4067. allErrs = append(allErrs, validateNodeConfigSourceSpec(node.Spec.ConfigSource, field.NewPath("spec", "configSource"))...)
  4068. }
  4069. oldNode.Spec.ConfigSource = node.Spec.ConfigSource
  4070. if node.Status.Config != nil {
  4071. allErrs = append(allErrs, validateNodeConfigStatus(node.Status.Config, field.NewPath("status", "config"))...)
  4072. }
  4073. oldNode.Status.Config = node.Status.Config
  4074. // TODO: move reset function to its own location
  4075. // Ignore metadata changes now that they have been tested
  4076. oldNode.ObjectMeta = node.ObjectMeta
  4077. // Allow users to update capacity
  4078. oldNode.Status.Capacity = node.Status.Capacity
  4079. // Allow users to unschedule node
  4080. oldNode.Spec.Unschedulable = node.Spec.Unschedulable
  4081. // Clear status
  4082. oldNode.Status = node.Status
  4083. // update taints
  4084. if len(node.Spec.Taints) > 0 {
  4085. allErrs = append(allErrs, validateNodeTaints(node.Spec.Taints, fldPath.Child("taints"))...)
  4086. }
  4087. oldNode.Spec.Taints = node.Spec.Taints
  4088. // We made allowed changes to oldNode, and now we compare oldNode to node. Any remaining differences indicate changes to protected fields.
  4089. // TODO: Add a 'real' error type for this error and provide print actual diffs.
  4090. if !apiequality.Semantic.DeepEqual(oldNode, node) {
  4091. klog.V(4).Infof("Update failed validation %#v vs %#v", oldNode, node)
  4092. allErrs = append(allErrs, field.Forbidden(field.NewPath(""), "node updates may only change labels, taints, or capacity (or configSource, if the DynamicKubeletConfig feature gate is enabled)"))
  4093. }
  4094. return allErrs
  4095. }
  4096. // validation specific to Node.Spec.ConfigSource
  4097. func validateNodeConfigSourceSpec(source *core.NodeConfigSource, fldPath *field.Path) field.ErrorList {
  4098. allErrs := field.ErrorList{}
  4099. count := int(0)
  4100. if source.ConfigMap != nil {
  4101. count++
  4102. allErrs = append(allErrs, validateConfigMapNodeConfigSourceSpec(source.ConfigMap, fldPath.Child("configMap"))...)
  4103. }
  4104. // add more subfields here in the future as they are added to NodeConfigSource
  4105. // exactly one reference subfield must be non-nil
  4106. if count != 1 {
  4107. allErrs = append(allErrs, field.Invalid(fldPath, source, "exactly one reference subfield must be non-nil"))
  4108. }
  4109. return allErrs
  4110. }
  4111. // validation specific to Node.Spec.ConfigSource.ConfigMap
  4112. func validateConfigMapNodeConfigSourceSpec(source *core.ConfigMapNodeConfigSource, fldPath *field.Path) field.ErrorList {
  4113. allErrs := field.ErrorList{}
  4114. // uid and resourceVersion must not be set in spec
  4115. if string(source.UID) != "" {
  4116. allErrs = append(allErrs, field.Forbidden(fldPath.Child("uid"), "uid must not be set in spec"))
  4117. }
  4118. if source.ResourceVersion != "" {
  4119. allErrs = append(allErrs, field.Forbidden(fldPath.Child("resourceVersion"), "resourceVersion must not be set in spec"))
  4120. }
  4121. return append(allErrs, validateConfigMapNodeConfigSource(source, fldPath)...)
  4122. }
  4123. // validation specififc to Node.Status.Config
  4124. func validateNodeConfigStatus(status *core.NodeConfigStatus, fldPath *field.Path) field.ErrorList {
  4125. allErrs := field.ErrorList{}
  4126. if status.Assigned != nil {
  4127. allErrs = append(allErrs, validateNodeConfigSourceStatus(status.Assigned, fldPath.Child("assigned"))...)
  4128. }
  4129. if status.Active != nil {
  4130. allErrs = append(allErrs, validateNodeConfigSourceStatus(status.Active, fldPath.Child("active"))...)
  4131. }
  4132. if status.LastKnownGood != nil {
  4133. allErrs = append(allErrs, validateNodeConfigSourceStatus(status.LastKnownGood, fldPath.Child("lastKnownGood"))...)
  4134. }
  4135. return allErrs
  4136. }
  4137. // validation specific to Node.Status.Config.(Active|Assigned|LastKnownGood)
  4138. func validateNodeConfigSourceStatus(source *core.NodeConfigSource, fldPath *field.Path) field.ErrorList {
  4139. allErrs := field.ErrorList{}
  4140. count := int(0)
  4141. if source.ConfigMap != nil {
  4142. count++
  4143. allErrs = append(allErrs, validateConfigMapNodeConfigSourceStatus(source.ConfigMap, fldPath.Child("configMap"))...)
  4144. }
  4145. // add more subfields here in the future as they are added to NodeConfigSource
  4146. // exactly one reference subfield must be non-nil
  4147. if count != 1 {
  4148. allErrs = append(allErrs, field.Invalid(fldPath, source, "exactly one reference subfield must be non-nil"))
  4149. }
  4150. return allErrs
  4151. }
  4152. // validation specific to Node.Status.Config.(Active|Assigned|LastKnownGood).ConfigMap
  4153. func validateConfigMapNodeConfigSourceStatus(source *core.ConfigMapNodeConfigSource, fldPath *field.Path) field.ErrorList {
  4154. allErrs := field.ErrorList{}
  4155. // uid and resourceVersion must be set in status
  4156. if string(source.UID) == "" {
  4157. allErrs = append(allErrs, field.Required(fldPath.Child("uid"), "uid must be set in status"))
  4158. }
  4159. if source.ResourceVersion == "" {
  4160. allErrs = append(allErrs, field.Required(fldPath.Child("resourceVersion"), "resourceVersion must be set in status"))
  4161. }
  4162. return append(allErrs, validateConfigMapNodeConfigSource(source, fldPath)...)
  4163. }
  4164. // common validation
  4165. func validateConfigMapNodeConfigSource(source *core.ConfigMapNodeConfigSource, fldPath *field.Path) field.ErrorList {
  4166. allErrs := field.ErrorList{}
  4167. // validate target configmap namespace
  4168. if source.Namespace == "" {
  4169. allErrs = append(allErrs, field.Required(fldPath.Child("namespace"), "namespace must be set"))
  4170. } else {
  4171. for _, msg := range ValidateNameFunc(ValidateNamespaceName)(source.Namespace, false) {
  4172. allErrs = append(allErrs, field.Invalid(fldPath.Child("namespace"), source.Namespace, msg))
  4173. }
  4174. }
  4175. // validate target configmap name
  4176. if source.Name == "" {
  4177. allErrs = append(allErrs, field.Required(fldPath.Child("name"), "name must be set"))
  4178. } else {
  4179. for _, msg := range ValidateNameFunc(ValidateConfigMapName)(source.Name, false) {
  4180. allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), source.Name, msg))
  4181. }
  4182. }
  4183. // validate kubeletConfigKey against rules for configMap key names
  4184. if source.KubeletConfigKey == "" {
  4185. allErrs = append(allErrs, field.Required(fldPath.Child("kubeletConfigKey"), "kubeletConfigKey must be set"))
  4186. } else {
  4187. for _, msg := range validation.IsConfigMapKey(source.KubeletConfigKey) {
  4188. allErrs = append(allErrs, field.Invalid(fldPath.Child("kubeletConfigKey"), source.KubeletConfigKey, msg))
  4189. }
  4190. }
  4191. return allErrs
  4192. }
  4193. // Validate compute resource typename.
  4194. // Refer to docs/design/resources.md for more details.
  4195. func validateResourceName(value string, fldPath *field.Path) field.ErrorList {
  4196. allErrs := field.ErrorList{}
  4197. for _, msg := range validation.IsQualifiedName(value) {
  4198. allErrs = append(allErrs, field.Invalid(fldPath, value, msg))
  4199. }
  4200. if len(allErrs) != 0 {
  4201. return allErrs
  4202. }
  4203. if len(strings.Split(value, "/")) == 1 {
  4204. if !helper.IsStandardResourceName(value) {
  4205. return append(allErrs, field.Invalid(fldPath, value, "must be a standard resource type or fully qualified"))
  4206. }
  4207. }
  4208. return allErrs
  4209. }
  4210. // Validate container resource name
  4211. // Refer to docs/design/resources.md for more details.
  4212. func validateContainerResourceName(value string, fldPath *field.Path) field.ErrorList {
  4213. allErrs := validateResourceName(value, fldPath)
  4214. if len(strings.Split(value, "/")) == 1 {
  4215. if !helper.IsStandardContainerResourceName(value) {
  4216. return append(allErrs, field.Invalid(fldPath, value, "must be a standard resource for containers"))
  4217. }
  4218. } else if !helper.IsNativeResource(core.ResourceName(value)) {
  4219. if !helper.IsExtendedResourceName(core.ResourceName(value)) {
  4220. return append(allErrs, field.Invalid(fldPath, value, "doesn't follow extended resource name standard"))
  4221. }
  4222. }
  4223. return allErrs
  4224. }
  4225. // Validate resource names that can go in a resource quota
  4226. // Refer to docs/design/resources.md for more details.
  4227. func ValidateResourceQuotaResourceName(value string, fldPath *field.Path) field.ErrorList {
  4228. allErrs := validateResourceName(value, fldPath)
  4229. if len(strings.Split(value, "/")) == 1 {
  4230. if !helper.IsStandardQuotaResourceName(value) {
  4231. return append(allErrs, field.Invalid(fldPath, value, isInvalidQuotaResource))
  4232. }
  4233. }
  4234. return allErrs
  4235. }
  4236. // Validate limit range types
  4237. func validateLimitRangeTypeName(value string, fldPath *field.Path) field.ErrorList {
  4238. allErrs := field.ErrorList{}
  4239. for _, msg := range validation.IsQualifiedName(value) {
  4240. allErrs = append(allErrs, field.Invalid(fldPath, value, msg))
  4241. }
  4242. if len(allErrs) != 0 {
  4243. return allErrs
  4244. }
  4245. if len(strings.Split(value, "/")) == 1 {
  4246. if !helper.IsStandardLimitRangeType(value) {
  4247. return append(allErrs, field.Invalid(fldPath, value, "must be a standard limit type or fully qualified"))
  4248. }
  4249. }
  4250. return allErrs
  4251. }
  4252. // Validate limit range resource name
  4253. // limit types (other than Pod/Container) could contain storage not just cpu or memory
  4254. func validateLimitRangeResourceName(limitType core.LimitType, value string, fldPath *field.Path) field.ErrorList {
  4255. switch limitType {
  4256. case core.LimitTypePod, core.LimitTypeContainer:
  4257. return validateContainerResourceName(value, fldPath)
  4258. default:
  4259. return validateResourceName(value, fldPath)
  4260. }
  4261. }
  4262. // ValidateLimitRange tests if required fields in the LimitRange are set.
  4263. func ValidateLimitRange(limitRange *core.LimitRange) field.ErrorList {
  4264. allErrs := ValidateObjectMeta(&limitRange.ObjectMeta, true, ValidateLimitRangeName, field.NewPath("metadata"))
  4265. // ensure resource names are properly qualified per docs/design/resources.md
  4266. limitTypeSet := map[core.LimitType]bool{}
  4267. fldPath := field.NewPath("spec", "limits")
  4268. for i := range limitRange.Spec.Limits {
  4269. idxPath := fldPath.Index(i)
  4270. limit := &limitRange.Spec.Limits[i]
  4271. allErrs = append(allErrs, validateLimitRangeTypeName(string(limit.Type), idxPath.Child("type"))...)
  4272. _, found := limitTypeSet[limit.Type]
  4273. if found {
  4274. allErrs = append(allErrs, field.Duplicate(idxPath.Child("type"), limit.Type))
  4275. }
  4276. limitTypeSet[limit.Type] = true
  4277. keys := sets.String{}
  4278. min := map[string]resource.Quantity{}
  4279. max := map[string]resource.Quantity{}
  4280. defaults := map[string]resource.Quantity{}
  4281. defaultRequests := map[string]resource.Quantity{}
  4282. maxLimitRequestRatios := map[string]resource.Quantity{}
  4283. for k, q := range limit.Max {
  4284. allErrs = append(allErrs, validateLimitRangeResourceName(limit.Type, string(k), idxPath.Child("max").Key(string(k)))...)
  4285. keys.Insert(string(k))
  4286. max[string(k)] = q
  4287. }
  4288. for k, q := range limit.Min {
  4289. allErrs = append(allErrs, validateLimitRangeResourceName(limit.Type, string(k), idxPath.Child("min").Key(string(k)))...)
  4290. keys.Insert(string(k))
  4291. min[string(k)] = q
  4292. }
  4293. if limit.Type == core.LimitTypePod {
  4294. if len(limit.Default) > 0 {
  4295. allErrs = append(allErrs, field.Forbidden(idxPath.Child("default"), "may not be specified when `type` is 'Pod'"))
  4296. }
  4297. if len(limit.DefaultRequest) > 0 {
  4298. allErrs = append(allErrs, field.Forbidden(idxPath.Child("defaultRequest"), "may not be specified when `type` is 'Pod'"))
  4299. }
  4300. } else {
  4301. for k, q := range limit.Default {
  4302. allErrs = append(allErrs, validateLimitRangeResourceName(limit.Type, string(k), idxPath.Child("default").Key(string(k)))...)
  4303. keys.Insert(string(k))
  4304. defaults[string(k)] = q
  4305. }
  4306. for k, q := range limit.DefaultRequest {
  4307. allErrs = append(allErrs, validateLimitRangeResourceName(limit.Type, string(k), idxPath.Child("defaultRequest").Key(string(k)))...)
  4308. keys.Insert(string(k))
  4309. defaultRequests[string(k)] = q
  4310. }
  4311. }
  4312. if limit.Type == core.LimitTypePersistentVolumeClaim {
  4313. _, minQuantityFound := limit.Min[core.ResourceStorage]
  4314. _, maxQuantityFound := limit.Max[core.ResourceStorage]
  4315. if !minQuantityFound && !maxQuantityFound {
  4316. allErrs = append(allErrs, field.Required(idxPath.Child("limits"), "either minimum or maximum storage value is required, but neither was provided"))
  4317. }
  4318. }
  4319. for k, q := range limit.MaxLimitRequestRatio {
  4320. allErrs = append(allErrs, validateLimitRangeResourceName(limit.Type, string(k), idxPath.Child("maxLimitRequestRatio").Key(string(k)))...)
  4321. keys.Insert(string(k))
  4322. maxLimitRequestRatios[string(k)] = q
  4323. }
  4324. for k := range keys {
  4325. minQuantity, minQuantityFound := min[k]
  4326. maxQuantity, maxQuantityFound := max[k]
  4327. defaultQuantity, defaultQuantityFound := defaults[k]
  4328. defaultRequestQuantity, defaultRequestQuantityFound := defaultRequests[k]
  4329. maxRatio, maxRatioFound := maxLimitRequestRatios[k]
  4330. if minQuantityFound && maxQuantityFound && minQuantity.Cmp(maxQuantity) > 0 {
  4331. allErrs = append(allErrs, field.Invalid(idxPath.Child("min").Key(string(k)), minQuantity, fmt.Sprintf("min value %s is greater than max value %s", minQuantity.String(), maxQuantity.String())))
  4332. }
  4333. if defaultRequestQuantityFound && minQuantityFound && minQuantity.Cmp(defaultRequestQuantity) > 0 {
  4334. allErrs = append(allErrs, field.Invalid(idxPath.Child("defaultRequest").Key(string(k)), defaultRequestQuantity, fmt.Sprintf("min value %s is greater than default request value %s", minQuantity.String(), defaultRequestQuantity.String())))
  4335. }
  4336. if defaultRequestQuantityFound && maxQuantityFound && defaultRequestQuantity.Cmp(maxQuantity) > 0 {
  4337. allErrs = append(allErrs, field.Invalid(idxPath.Child("defaultRequest").Key(string(k)), defaultRequestQuantity, fmt.Sprintf("default request value %s is greater than max value %s", defaultRequestQuantity.String(), maxQuantity.String())))
  4338. }
  4339. if defaultRequestQuantityFound && defaultQuantityFound && defaultRequestQuantity.Cmp(defaultQuantity) > 0 {
  4340. allErrs = append(allErrs, field.Invalid(idxPath.Child("defaultRequest").Key(string(k)), defaultRequestQuantity, fmt.Sprintf("default request value %s is greater than default limit value %s", defaultRequestQuantity.String(), defaultQuantity.String())))
  4341. }
  4342. if defaultQuantityFound && minQuantityFound && minQuantity.Cmp(defaultQuantity) > 0 {
  4343. allErrs = append(allErrs, field.Invalid(idxPath.Child("default").Key(string(k)), minQuantity, fmt.Sprintf("min value %s is greater than default value %s", minQuantity.String(), defaultQuantity.String())))
  4344. }
  4345. if defaultQuantityFound && maxQuantityFound && defaultQuantity.Cmp(maxQuantity) > 0 {
  4346. allErrs = append(allErrs, field.Invalid(idxPath.Child("default").Key(string(k)), maxQuantity, fmt.Sprintf("default value %s is greater than max value %s", defaultQuantity.String(), maxQuantity.String())))
  4347. }
  4348. if maxRatioFound && maxRatio.Cmp(*resource.NewQuantity(1, resource.DecimalSI)) < 0 {
  4349. allErrs = append(allErrs, field.Invalid(idxPath.Child("maxLimitRequestRatio").Key(string(k)), maxRatio, fmt.Sprintf("ratio %s is less than 1", maxRatio.String())))
  4350. }
  4351. if maxRatioFound && minQuantityFound && maxQuantityFound {
  4352. maxRatioValue := float64(maxRatio.Value())
  4353. minQuantityValue := minQuantity.Value()
  4354. maxQuantityValue := maxQuantity.Value()
  4355. if maxRatio.Value() < resource.MaxMilliValue && minQuantityValue < resource.MaxMilliValue && maxQuantityValue < resource.MaxMilliValue {
  4356. maxRatioValue = float64(maxRatio.MilliValue()) / 1000
  4357. minQuantityValue = minQuantity.MilliValue()
  4358. maxQuantityValue = maxQuantity.MilliValue()
  4359. }
  4360. maxRatioLimit := float64(maxQuantityValue) / float64(minQuantityValue)
  4361. if maxRatioValue > maxRatioLimit {
  4362. allErrs = append(allErrs, field.Invalid(idxPath.Child("maxLimitRequestRatio").Key(string(k)), maxRatio, fmt.Sprintf("ratio %s is greater than max/min = %f", maxRatio.String(), maxRatioLimit)))
  4363. }
  4364. }
  4365. // for GPU, hugepages and other resources that are not allowed to overcommit,
  4366. // the default value and defaultRequest value must match if both are specified
  4367. if !helper.IsOvercommitAllowed(core.ResourceName(k)) && defaultQuantityFound && defaultRequestQuantityFound && defaultQuantity.Cmp(defaultRequestQuantity) != 0 {
  4368. allErrs = append(allErrs, field.Invalid(idxPath.Child("defaultRequest").Key(string(k)), defaultRequestQuantity, fmt.Sprintf("default value %s must equal to defaultRequest value %s in %s", defaultQuantity.String(), defaultRequestQuantity.String(), k)))
  4369. }
  4370. }
  4371. }
  4372. return allErrs
  4373. }
  4374. // ValidateServiceAccount tests if required fields in the ServiceAccount are set.
  4375. func ValidateServiceAccount(serviceAccount *core.ServiceAccount) field.ErrorList {
  4376. allErrs := ValidateObjectMeta(&serviceAccount.ObjectMeta, true, ValidateServiceAccountName, field.NewPath("metadata"))
  4377. return allErrs
  4378. }
  4379. // ValidateServiceAccountUpdate tests if required fields in the ServiceAccount are set.
  4380. func ValidateServiceAccountUpdate(newServiceAccount, oldServiceAccount *core.ServiceAccount) field.ErrorList {
  4381. allErrs := ValidateObjectMetaUpdate(&newServiceAccount.ObjectMeta, &oldServiceAccount.ObjectMeta, field.NewPath("metadata"))
  4382. allErrs = append(allErrs, ValidateServiceAccount(newServiceAccount)...)
  4383. return allErrs
  4384. }
  4385. // ValidateSecret tests if required fields in the Secret are set.
  4386. func ValidateSecret(secret *core.Secret) field.ErrorList {
  4387. allErrs := ValidateObjectMeta(&secret.ObjectMeta, true, ValidateSecretName, field.NewPath("metadata"))
  4388. dataPath := field.NewPath("data")
  4389. totalSize := 0
  4390. for key, value := range secret.Data {
  4391. for _, msg := range validation.IsConfigMapKey(key) {
  4392. allErrs = append(allErrs, field.Invalid(dataPath.Key(key), key, msg))
  4393. }
  4394. totalSize += len(value)
  4395. }
  4396. if totalSize > core.MaxSecretSize {
  4397. allErrs = append(allErrs, field.TooLong(dataPath, "", core.MaxSecretSize))
  4398. }
  4399. switch secret.Type {
  4400. case core.SecretTypeServiceAccountToken:
  4401. // Only require Annotations[kubernetes.io/service-account.name]
  4402. // Additional fields (like Annotations[kubernetes.io/service-account.uid] and Data[token]) might be contributed later by a controller loop
  4403. if value := secret.Annotations[core.ServiceAccountNameKey]; len(value) == 0 {
  4404. allErrs = append(allErrs, field.Required(field.NewPath("metadata", "annotations").Key(core.ServiceAccountNameKey), ""))
  4405. }
  4406. case core.SecretTypeOpaque, "":
  4407. // no-op
  4408. case core.SecretTypeDockercfg:
  4409. dockercfgBytes, exists := secret.Data[core.DockerConfigKey]
  4410. if !exists {
  4411. allErrs = append(allErrs, field.Required(dataPath.Key(core.DockerConfigKey), ""))
  4412. break
  4413. }
  4414. // make sure that the content is well-formed json.
  4415. if err := json.Unmarshal(dockercfgBytes, &map[string]interface{}{}); err != nil {
  4416. allErrs = append(allErrs, field.Invalid(dataPath.Key(core.DockerConfigKey), "<secret contents redacted>", err.Error()))
  4417. }
  4418. case core.SecretTypeDockerConfigJSON:
  4419. dockerConfigJSONBytes, exists := secret.Data[core.DockerConfigJSONKey]
  4420. if !exists {
  4421. allErrs = append(allErrs, field.Required(dataPath.Key(core.DockerConfigJSONKey), ""))
  4422. break
  4423. }
  4424. // make sure that the content is well-formed json.
  4425. if err := json.Unmarshal(dockerConfigJSONBytes, &map[string]interface{}{}); err != nil {
  4426. allErrs = append(allErrs, field.Invalid(dataPath.Key(core.DockerConfigJSONKey), "<secret contents redacted>", err.Error()))
  4427. }
  4428. case core.SecretTypeBasicAuth:
  4429. _, usernameFieldExists := secret.Data[core.BasicAuthUsernameKey]
  4430. _, passwordFieldExists := secret.Data[core.BasicAuthPasswordKey]
  4431. // username or password might be empty, but the field must be present
  4432. if !usernameFieldExists && !passwordFieldExists {
  4433. allErrs = append(allErrs, field.Required(field.NewPath("data[%s]").Key(core.BasicAuthUsernameKey), ""))
  4434. allErrs = append(allErrs, field.Required(field.NewPath("data[%s]").Key(core.BasicAuthPasswordKey), ""))
  4435. break
  4436. }
  4437. case core.SecretTypeSSHAuth:
  4438. if len(secret.Data[core.SSHAuthPrivateKey]) == 0 {
  4439. allErrs = append(allErrs, field.Required(field.NewPath("data[%s]").Key(core.SSHAuthPrivateKey), ""))
  4440. break
  4441. }
  4442. case core.SecretTypeTLS:
  4443. if _, exists := secret.Data[core.TLSCertKey]; !exists {
  4444. allErrs = append(allErrs, field.Required(dataPath.Key(core.TLSCertKey), ""))
  4445. }
  4446. if _, exists := secret.Data[core.TLSPrivateKeyKey]; !exists {
  4447. allErrs = append(allErrs, field.Required(dataPath.Key(core.TLSPrivateKeyKey), ""))
  4448. }
  4449. // TODO: Verify that the key matches the cert.
  4450. default:
  4451. // no-op
  4452. }
  4453. return allErrs
  4454. }
  4455. // ValidateSecretUpdate tests if required fields in the Secret are set.
  4456. func ValidateSecretUpdate(newSecret, oldSecret *core.Secret) field.ErrorList {
  4457. allErrs := ValidateObjectMetaUpdate(&newSecret.ObjectMeta, &oldSecret.ObjectMeta, field.NewPath("metadata"))
  4458. if len(newSecret.Type) == 0 {
  4459. newSecret.Type = oldSecret.Type
  4460. }
  4461. allErrs = append(allErrs, ValidateImmutableField(newSecret.Type, oldSecret.Type, field.NewPath("type"))...)
  4462. if oldSecret.Immutable != nil && *oldSecret.Immutable {
  4463. if newSecret.Immutable == nil || !*newSecret.Immutable {
  4464. allErrs = append(allErrs, field.Forbidden(field.NewPath("immutable"), "field is immutable when `immutable` is set"))
  4465. }
  4466. if !reflect.DeepEqual(newSecret.Data, oldSecret.Data) {
  4467. allErrs = append(allErrs, field.Forbidden(field.NewPath("data"), "field is immutable when `immutable` is set"))
  4468. }
  4469. // We don't validate StringData, as it was already converted back to Data
  4470. // before validation is happening.
  4471. }
  4472. allErrs = append(allErrs, ValidateSecret(newSecret)...)
  4473. return allErrs
  4474. }
  4475. // ValidateConfigMapName can be used to check whether the given ConfigMap name is valid.
  4476. // Prefix indicates this name will be used as part of generation, in which case
  4477. // trailing dashes are allowed.
  4478. var ValidateConfigMapName = apimachineryvalidation.NameIsDNSSubdomain
  4479. // ValidateConfigMap tests whether required fields in the ConfigMap are set.
  4480. func ValidateConfigMap(cfg *core.ConfigMap) field.ErrorList {
  4481. allErrs := field.ErrorList{}
  4482. allErrs = append(allErrs, ValidateObjectMeta(&cfg.ObjectMeta, true, ValidateConfigMapName, field.NewPath("metadata"))...)
  4483. totalSize := 0
  4484. for key, value := range cfg.Data {
  4485. for _, msg := range validation.IsConfigMapKey(key) {
  4486. allErrs = append(allErrs, field.Invalid(field.NewPath("data").Key(key), key, msg))
  4487. }
  4488. // check if we have a duplicate key in the other bag
  4489. if _, isValue := cfg.BinaryData[key]; isValue {
  4490. msg := "duplicate of key present in binaryData"
  4491. allErrs = append(allErrs, field.Invalid(field.NewPath("data").Key(key), key, msg))
  4492. }
  4493. totalSize += len(value)
  4494. }
  4495. for key, value := range cfg.BinaryData {
  4496. for _, msg := range validation.IsConfigMapKey(key) {
  4497. allErrs = append(allErrs, field.Invalid(field.NewPath("binaryData").Key(key), key, msg))
  4498. }
  4499. totalSize += len(value)
  4500. }
  4501. if totalSize > core.MaxSecretSize {
  4502. // pass back "" to indicate that the error refers to the whole object.
  4503. allErrs = append(allErrs, field.TooLong(field.NewPath(""), cfg, core.MaxSecretSize))
  4504. }
  4505. return allErrs
  4506. }
  4507. // ValidateConfigMapUpdate tests if required fields in the ConfigMap are set.
  4508. func ValidateConfigMapUpdate(newCfg, oldCfg *core.ConfigMap) field.ErrorList {
  4509. allErrs := field.ErrorList{}
  4510. allErrs = append(allErrs, ValidateObjectMetaUpdate(&newCfg.ObjectMeta, &oldCfg.ObjectMeta, field.NewPath("metadata"))...)
  4511. if oldCfg.Immutable != nil && *oldCfg.Immutable {
  4512. if newCfg.Immutable == nil || !*newCfg.Immutable {
  4513. allErrs = append(allErrs, field.Forbidden(field.NewPath("immutable"), "field is immutable when `immutable` is set"))
  4514. }
  4515. if !reflect.DeepEqual(newCfg.Data, oldCfg.Data) {
  4516. allErrs = append(allErrs, field.Forbidden(field.NewPath("data"), "field is immutable when `immutable` is set"))
  4517. }
  4518. if !reflect.DeepEqual(newCfg.BinaryData, oldCfg.BinaryData) {
  4519. allErrs = append(allErrs, field.Forbidden(field.NewPath("binaryData"), "field is immutable when `immutable` is set"))
  4520. }
  4521. }
  4522. allErrs = append(allErrs, ValidateConfigMap(newCfg)...)
  4523. return allErrs
  4524. }
  4525. func validateBasicResource(quantity resource.Quantity, fldPath *field.Path) field.ErrorList {
  4526. if quantity.Value() < 0 {
  4527. return field.ErrorList{field.Invalid(fldPath, quantity.Value(), "must be a valid resource quantity")}
  4528. }
  4529. return field.ErrorList{}
  4530. }
  4531. // Validates resource requirement spec.
  4532. func ValidateResourceRequirements(requirements *core.ResourceRequirements, fldPath *field.Path) field.ErrorList {
  4533. allErrs := field.ErrorList{}
  4534. limPath := fldPath.Child("limits")
  4535. reqPath := fldPath.Child("requests")
  4536. limContainsCPUOrMemory := false
  4537. reqContainsCPUOrMemory := false
  4538. limContainsHugePages := false
  4539. reqContainsHugePages := false
  4540. supportedQoSComputeResources := sets.NewString(string(core.ResourceCPU), string(core.ResourceMemory))
  4541. for resourceName, quantity := range requirements.Limits {
  4542. fldPath := limPath.Key(string(resourceName))
  4543. // Validate resource name.
  4544. allErrs = append(allErrs, validateContainerResourceName(string(resourceName), fldPath)...)
  4545. // Validate resource quantity.
  4546. allErrs = append(allErrs, ValidateResourceQuantityValue(string(resourceName), quantity, fldPath)...)
  4547. if helper.IsHugePageResourceName(resourceName) {
  4548. limContainsHugePages = true
  4549. }
  4550. if supportedQoSComputeResources.Has(string(resourceName)) {
  4551. limContainsCPUOrMemory = true
  4552. }
  4553. }
  4554. for resourceName, quantity := range requirements.Requests {
  4555. fldPath := reqPath.Key(string(resourceName))
  4556. // Validate resource name.
  4557. allErrs = append(allErrs, validateContainerResourceName(string(resourceName), fldPath)...)
  4558. // Validate resource quantity.
  4559. allErrs = append(allErrs, ValidateResourceQuantityValue(string(resourceName), quantity, fldPath)...)
  4560. // Check that request <= limit.
  4561. limitQuantity, exists := requirements.Limits[resourceName]
  4562. if exists {
  4563. // For non overcommitable resources, not only requests can't exceed limits, they also can't be lower, i.e. must be equal.
  4564. if quantity.Cmp(limitQuantity) != 0 && !helper.IsOvercommitAllowed(resourceName) {
  4565. allErrs = append(allErrs, field.Invalid(reqPath, quantity.String(), fmt.Sprintf("must be equal to %s limit", resourceName)))
  4566. } else if quantity.Cmp(limitQuantity) > 0 {
  4567. allErrs = append(allErrs, field.Invalid(reqPath, quantity.String(), fmt.Sprintf("must be less than or equal to %s limit", resourceName)))
  4568. }
  4569. } else if !helper.IsOvercommitAllowed(resourceName) {
  4570. allErrs = append(allErrs, field.Required(limPath, "Limit must be set for non overcommitable resources"))
  4571. }
  4572. if helper.IsHugePageResourceName(resourceName) {
  4573. reqContainsHugePages = true
  4574. }
  4575. if supportedQoSComputeResources.Has(string(resourceName)) {
  4576. reqContainsCPUOrMemory = true
  4577. }
  4578. }
  4579. if !limContainsCPUOrMemory && !reqContainsCPUOrMemory && (reqContainsHugePages || limContainsHugePages) {
  4580. allErrs = append(allErrs, field.Forbidden(fldPath, fmt.Sprintf("HugePages require cpu or memory")))
  4581. }
  4582. return allErrs
  4583. }
  4584. // validateResourceQuotaScopes ensures that each enumerated hard resource constraint is valid for set of scopes
  4585. func validateResourceQuotaScopes(resourceQuotaSpec *core.ResourceQuotaSpec, fld *field.Path) field.ErrorList {
  4586. allErrs := field.ErrorList{}
  4587. if len(resourceQuotaSpec.Scopes) == 0 {
  4588. return allErrs
  4589. }
  4590. hardLimits := sets.NewString()
  4591. for k := range resourceQuotaSpec.Hard {
  4592. hardLimits.Insert(string(k))
  4593. }
  4594. fldPath := fld.Child("scopes")
  4595. scopeSet := sets.NewString()
  4596. for _, scope := range resourceQuotaSpec.Scopes {
  4597. if !helper.IsStandardResourceQuotaScope(string(scope)) {
  4598. allErrs = append(allErrs, field.Invalid(fldPath, resourceQuotaSpec.Scopes, "unsupported scope"))
  4599. }
  4600. for _, k := range hardLimits.List() {
  4601. if helper.IsStandardQuotaResourceName(k) && !helper.IsResourceQuotaScopeValidForResource(scope, k) {
  4602. allErrs = append(allErrs, field.Invalid(fldPath, resourceQuotaSpec.Scopes, "unsupported scope applied to resource"))
  4603. }
  4604. }
  4605. scopeSet.Insert(string(scope))
  4606. }
  4607. invalidScopePairs := []sets.String{
  4608. sets.NewString(string(core.ResourceQuotaScopeBestEffort), string(core.ResourceQuotaScopeNotBestEffort)),
  4609. sets.NewString(string(core.ResourceQuotaScopeTerminating), string(core.ResourceQuotaScopeNotTerminating)),
  4610. }
  4611. for _, invalidScopePair := range invalidScopePairs {
  4612. if scopeSet.HasAll(invalidScopePair.List()...) {
  4613. allErrs = append(allErrs, field.Invalid(fldPath, resourceQuotaSpec.Scopes, "conflicting scopes"))
  4614. }
  4615. }
  4616. return allErrs
  4617. }
  4618. // validateScopedResourceSelectorRequirement tests that the match expressions has valid data
  4619. func validateScopedResourceSelectorRequirement(resourceQuotaSpec *core.ResourceQuotaSpec, fld *field.Path) field.ErrorList {
  4620. allErrs := field.ErrorList{}
  4621. hardLimits := sets.NewString()
  4622. for k := range resourceQuotaSpec.Hard {
  4623. hardLimits.Insert(string(k))
  4624. }
  4625. fldPath := fld.Child("matchExpressions")
  4626. scopeSet := sets.NewString()
  4627. for _, req := range resourceQuotaSpec.ScopeSelector.MatchExpressions {
  4628. if !helper.IsStandardResourceQuotaScope(string(req.ScopeName)) {
  4629. allErrs = append(allErrs, field.Invalid(fldPath.Child("scopeName"), req.ScopeName, "unsupported scope"))
  4630. }
  4631. for _, k := range hardLimits.List() {
  4632. if helper.IsStandardQuotaResourceName(k) && !helper.IsResourceQuotaScopeValidForResource(req.ScopeName, k) {
  4633. allErrs = append(allErrs, field.Invalid(fldPath, resourceQuotaSpec.ScopeSelector, "unsupported scope applied to resource"))
  4634. }
  4635. }
  4636. switch req.ScopeName {
  4637. case core.ResourceQuotaScopeBestEffort, core.ResourceQuotaScopeNotBestEffort, core.ResourceQuotaScopeTerminating, core.ResourceQuotaScopeNotTerminating:
  4638. if req.Operator != core.ScopeSelectorOpExists {
  4639. allErrs = append(allErrs, field.Invalid(fldPath.Child("operator"), req.Operator,
  4640. "must be 'Exist' only operator when scope is any of ResourceQuotaScopeTerminating, ResourceQuotaScopeNotTerminating, ResourceQuotaScopeBestEffort and ResourceQuotaScopeNotBestEffort"))
  4641. }
  4642. }
  4643. switch req.Operator {
  4644. case core.ScopeSelectorOpIn, core.ScopeSelectorOpNotIn:
  4645. if len(req.Values) == 0 {
  4646. allErrs = append(allErrs, field.Required(fldPath.Child("values"),
  4647. "must be at least one value when `operator` is 'In' or 'NotIn' for scope selector"))
  4648. }
  4649. case core.ScopeSelectorOpExists, core.ScopeSelectorOpDoesNotExist:
  4650. if len(req.Values) != 0 {
  4651. allErrs = append(allErrs, field.Invalid(fldPath.Child("values"), req.Values,
  4652. "must be no value when `operator` is 'Exist' or 'DoesNotExist' for scope selector"))
  4653. }
  4654. default:
  4655. allErrs = append(allErrs, field.Invalid(fldPath.Child("operator"), req.Operator, "not a valid selector operator"))
  4656. }
  4657. scopeSet.Insert(string(req.ScopeName))
  4658. }
  4659. invalidScopePairs := []sets.String{
  4660. sets.NewString(string(core.ResourceQuotaScopeBestEffort), string(core.ResourceQuotaScopeNotBestEffort)),
  4661. sets.NewString(string(core.ResourceQuotaScopeTerminating), string(core.ResourceQuotaScopeNotTerminating)),
  4662. }
  4663. for _, invalidScopePair := range invalidScopePairs {
  4664. if scopeSet.HasAll(invalidScopePair.List()...) {
  4665. allErrs = append(allErrs, field.Invalid(fldPath, resourceQuotaSpec.Scopes, "conflicting scopes"))
  4666. }
  4667. }
  4668. return allErrs
  4669. }
  4670. // validateScopeSelector tests that the specified scope selector has valid data
  4671. func validateScopeSelector(resourceQuotaSpec *core.ResourceQuotaSpec, fld *field.Path) field.ErrorList {
  4672. allErrs := field.ErrorList{}
  4673. if resourceQuotaSpec.ScopeSelector == nil {
  4674. return allErrs
  4675. }
  4676. allErrs = append(allErrs, validateScopedResourceSelectorRequirement(resourceQuotaSpec, fld.Child("scopeSelector"))...)
  4677. return allErrs
  4678. }
  4679. // ValidateResourceQuota tests if required fields in the ResourceQuota are set.
  4680. func ValidateResourceQuota(resourceQuota *core.ResourceQuota) field.ErrorList {
  4681. allErrs := ValidateObjectMeta(&resourceQuota.ObjectMeta, true, ValidateResourceQuotaName, field.NewPath("metadata"))
  4682. allErrs = append(allErrs, ValidateResourceQuotaSpec(&resourceQuota.Spec, field.NewPath("spec"))...)
  4683. allErrs = append(allErrs, ValidateResourceQuotaStatus(&resourceQuota.Status, field.NewPath("status"))...)
  4684. return allErrs
  4685. }
  4686. func ValidateResourceQuotaStatus(status *core.ResourceQuotaStatus, fld *field.Path) field.ErrorList {
  4687. allErrs := field.ErrorList{}
  4688. fldPath := fld.Child("hard")
  4689. for k, v := range status.Hard {
  4690. resPath := fldPath.Key(string(k))
  4691. allErrs = append(allErrs, ValidateResourceQuotaResourceName(string(k), resPath)...)
  4692. allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...)
  4693. }
  4694. fldPath = fld.Child("used")
  4695. for k, v := range status.Used {
  4696. resPath := fldPath.Key(string(k))
  4697. allErrs = append(allErrs, ValidateResourceQuotaResourceName(string(k), resPath)...)
  4698. allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...)
  4699. }
  4700. return allErrs
  4701. }
  4702. func ValidateResourceQuotaSpec(resourceQuotaSpec *core.ResourceQuotaSpec, fld *field.Path) field.ErrorList {
  4703. allErrs := field.ErrorList{}
  4704. fldPath := fld.Child("hard")
  4705. for k, v := range resourceQuotaSpec.Hard {
  4706. resPath := fldPath.Key(string(k))
  4707. allErrs = append(allErrs, ValidateResourceQuotaResourceName(string(k), resPath)...)
  4708. allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...)
  4709. }
  4710. allErrs = append(allErrs, validateResourceQuotaScopes(resourceQuotaSpec, fld)...)
  4711. allErrs = append(allErrs, validateScopeSelector(resourceQuotaSpec, fld)...)
  4712. return allErrs
  4713. }
  4714. // ValidateResourceQuantityValue enforces that specified quantity is valid for specified resource
  4715. func ValidateResourceQuantityValue(resource string, value resource.Quantity, fldPath *field.Path) field.ErrorList {
  4716. allErrs := field.ErrorList{}
  4717. allErrs = append(allErrs, ValidateNonnegativeQuantity(value, fldPath)...)
  4718. if helper.IsIntegerResourceName(resource) {
  4719. if value.MilliValue()%int64(1000) != int64(0) {
  4720. allErrs = append(allErrs, field.Invalid(fldPath, value, isNotIntegerErrorMsg))
  4721. }
  4722. }
  4723. return allErrs
  4724. }
  4725. // ValidateResourceQuotaUpdate tests to see if the update is legal for an end user to make.
  4726. // newResourceQuota is updated with fields that cannot be changed.
  4727. func ValidateResourceQuotaUpdate(newResourceQuota, oldResourceQuota *core.ResourceQuota) field.ErrorList {
  4728. allErrs := ValidateObjectMetaUpdate(&newResourceQuota.ObjectMeta, &oldResourceQuota.ObjectMeta, field.NewPath("metadata"))
  4729. allErrs = append(allErrs, ValidateResourceQuotaSpec(&newResourceQuota.Spec, field.NewPath("spec"))...)
  4730. // ensure scopes cannot change, and that resources are still valid for scope
  4731. fldPath := field.NewPath("spec", "scopes")
  4732. oldScopes := sets.NewString()
  4733. newScopes := sets.NewString()
  4734. for _, scope := range newResourceQuota.Spec.Scopes {
  4735. newScopes.Insert(string(scope))
  4736. }
  4737. for _, scope := range oldResourceQuota.Spec.Scopes {
  4738. oldScopes.Insert(string(scope))
  4739. }
  4740. if !oldScopes.Equal(newScopes) {
  4741. allErrs = append(allErrs, field.Invalid(fldPath, newResourceQuota.Spec.Scopes, fieldImmutableErrorMsg))
  4742. }
  4743. newResourceQuota.Status = oldResourceQuota.Status
  4744. return allErrs
  4745. }
  4746. // ValidateResourceQuotaStatusUpdate tests to see if the status update is legal for an end user to make.
  4747. // newResourceQuota is updated with fields that cannot be changed.
  4748. func ValidateResourceQuotaStatusUpdate(newResourceQuota, oldResourceQuota *core.ResourceQuota) field.ErrorList {
  4749. allErrs := ValidateObjectMetaUpdate(&newResourceQuota.ObjectMeta, &oldResourceQuota.ObjectMeta, field.NewPath("metadata"))
  4750. if len(newResourceQuota.ResourceVersion) == 0 {
  4751. allErrs = append(allErrs, field.Required(field.NewPath("resourceVersion"), ""))
  4752. }
  4753. fldPath := field.NewPath("status", "hard")
  4754. for k, v := range newResourceQuota.Status.Hard {
  4755. resPath := fldPath.Key(string(k))
  4756. allErrs = append(allErrs, ValidateResourceQuotaResourceName(string(k), resPath)...)
  4757. allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...)
  4758. }
  4759. fldPath = field.NewPath("status", "used")
  4760. for k, v := range newResourceQuota.Status.Used {
  4761. resPath := fldPath.Key(string(k))
  4762. allErrs = append(allErrs, ValidateResourceQuotaResourceName(string(k), resPath)...)
  4763. allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...)
  4764. }
  4765. newResourceQuota.Spec = oldResourceQuota.Spec
  4766. return allErrs
  4767. }
  4768. // ValidateNamespace tests if required fields are set.
  4769. func ValidateNamespace(namespace *core.Namespace) field.ErrorList {
  4770. allErrs := ValidateObjectMeta(&namespace.ObjectMeta, false, ValidateNamespaceName, field.NewPath("metadata"))
  4771. for i := range namespace.Spec.Finalizers {
  4772. allErrs = append(allErrs, validateFinalizerName(string(namespace.Spec.Finalizers[i]), field.NewPath("spec", "finalizers"))...)
  4773. }
  4774. return allErrs
  4775. }
  4776. // Validate finalizer names
  4777. func validateFinalizerName(stringValue string, fldPath *field.Path) field.ErrorList {
  4778. allErrs := apimachineryvalidation.ValidateFinalizerName(stringValue, fldPath)
  4779. allErrs = append(allErrs, validateKubeFinalizerName(stringValue, fldPath)...)
  4780. return allErrs
  4781. }
  4782. // validateKubeFinalizerName checks for "standard" names of legacy finalizer
  4783. func validateKubeFinalizerName(stringValue string, fldPath *field.Path) field.ErrorList {
  4784. allErrs := field.ErrorList{}
  4785. if len(strings.Split(stringValue, "/")) == 1 {
  4786. if !helper.IsStandardFinalizerName(stringValue) {
  4787. return append(allErrs, field.Invalid(fldPath, stringValue, "name is neither a standard finalizer name nor is it fully qualified"))
  4788. }
  4789. }
  4790. return allErrs
  4791. }
  4792. // ValidateNamespaceUpdate tests to make sure a namespace update can be applied.
  4793. // newNamespace is updated with fields that cannot be changed
  4794. func ValidateNamespaceUpdate(newNamespace *core.Namespace, oldNamespace *core.Namespace) field.ErrorList {
  4795. allErrs := ValidateObjectMetaUpdate(&newNamespace.ObjectMeta, &oldNamespace.ObjectMeta, field.NewPath("metadata"))
  4796. newNamespace.Spec.Finalizers = oldNamespace.Spec.Finalizers
  4797. newNamespace.Status = oldNamespace.Status
  4798. return allErrs
  4799. }
  4800. // ValidateNamespaceStatusUpdate tests to see if the update is legal for an end user to make. newNamespace is updated with fields
  4801. // that cannot be changed.
  4802. func ValidateNamespaceStatusUpdate(newNamespace, oldNamespace *core.Namespace) field.ErrorList {
  4803. allErrs := ValidateObjectMetaUpdate(&newNamespace.ObjectMeta, &oldNamespace.ObjectMeta, field.NewPath("metadata"))
  4804. newNamespace.Spec = oldNamespace.Spec
  4805. if newNamespace.DeletionTimestamp.IsZero() {
  4806. if newNamespace.Status.Phase != core.NamespaceActive {
  4807. allErrs = append(allErrs, field.Invalid(field.NewPath("status", "Phase"), newNamespace.Status.Phase, "may only be 'Active' if `deletionTimestamp` is empty"))
  4808. }
  4809. } else {
  4810. if newNamespace.Status.Phase != core.NamespaceTerminating {
  4811. allErrs = append(allErrs, field.Invalid(field.NewPath("status", "Phase"), newNamespace.Status.Phase, "may only be 'Terminating' if `deletionTimestamp` is not empty"))
  4812. }
  4813. }
  4814. return allErrs
  4815. }
  4816. // ValidateNamespaceFinalizeUpdate tests to see if the update is legal for an end user to make.
  4817. // newNamespace is updated with fields that cannot be changed.
  4818. func ValidateNamespaceFinalizeUpdate(newNamespace, oldNamespace *core.Namespace) field.ErrorList {
  4819. allErrs := ValidateObjectMetaUpdate(&newNamespace.ObjectMeta, &oldNamespace.ObjectMeta, field.NewPath("metadata"))
  4820. fldPath := field.NewPath("spec", "finalizers")
  4821. for i := range newNamespace.Spec.Finalizers {
  4822. idxPath := fldPath.Index(i)
  4823. allErrs = append(allErrs, validateFinalizerName(string(newNamespace.Spec.Finalizers[i]), idxPath)...)
  4824. }
  4825. newNamespace.Status = oldNamespace.Status
  4826. return allErrs
  4827. }
  4828. // ValidateEndpoints tests if required fields are set.
  4829. func ValidateEndpoints(endpoints *core.Endpoints) field.ErrorList {
  4830. allErrs := ValidateObjectMeta(&endpoints.ObjectMeta, true, ValidateEndpointsName, field.NewPath("metadata"))
  4831. allErrs = append(allErrs, ValidateEndpointsSpecificAnnotations(endpoints.Annotations, field.NewPath("annotations"))...)
  4832. allErrs = append(allErrs, validateEndpointSubsets(endpoints.Subsets, field.NewPath("subsets"))...)
  4833. return allErrs
  4834. }
  4835. func validateEndpointSubsets(subsets []core.EndpointSubset, fldPath *field.Path) field.ErrorList {
  4836. allErrs := field.ErrorList{}
  4837. for i := range subsets {
  4838. ss := &subsets[i]
  4839. idxPath := fldPath.Index(i)
  4840. // EndpointSubsets must include endpoint address. For headless service, we allow its endpoints not to have ports.
  4841. if len(ss.Addresses) == 0 && len(ss.NotReadyAddresses) == 0 {
  4842. //TODO: consider adding a RequiredOneOf() error for this and similar cases
  4843. allErrs = append(allErrs, field.Required(idxPath, "must specify `addresses` or `notReadyAddresses`"))
  4844. }
  4845. for addr := range ss.Addresses {
  4846. allErrs = append(allErrs, validateEndpointAddress(&ss.Addresses[addr], idxPath.Child("addresses").Index(addr))...)
  4847. }
  4848. for addr := range ss.NotReadyAddresses {
  4849. allErrs = append(allErrs, validateEndpointAddress(&ss.NotReadyAddresses[addr], idxPath.Child("notReadyAddresses").Index(addr))...)
  4850. }
  4851. for port := range ss.Ports {
  4852. allErrs = append(allErrs, validateEndpointPort(&ss.Ports[port], len(ss.Ports) > 1, idxPath.Child("ports").Index(port))...)
  4853. }
  4854. }
  4855. return allErrs
  4856. }
  4857. func validateEndpointAddress(address *core.EndpointAddress, fldPath *field.Path) field.ErrorList {
  4858. allErrs := field.ErrorList{}
  4859. for _, msg := range validation.IsValidIP(address.IP) {
  4860. allErrs = append(allErrs, field.Invalid(fldPath.Child("ip"), address.IP, msg))
  4861. }
  4862. if len(address.Hostname) > 0 {
  4863. allErrs = append(allErrs, ValidateDNS1123Label(address.Hostname, fldPath.Child("hostname"))...)
  4864. }
  4865. // During endpoint update, verify that NodeName is a DNS subdomain and transition rules allow the update
  4866. if address.NodeName != nil {
  4867. for _, msg := range ValidateNodeName(*address.NodeName, false) {
  4868. allErrs = append(allErrs, field.Invalid(fldPath.Child("nodeName"), *address.NodeName, msg))
  4869. }
  4870. }
  4871. allErrs = append(allErrs, validateNonSpecialIP(address.IP, fldPath.Child("ip"))...)
  4872. return allErrs
  4873. }
  4874. func validateNonSpecialIP(ipAddress string, fldPath *field.Path) field.ErrorList {
  4875. // We disallow some IPs as endpoints or external-ips. Specifically,
  4876. // unspecified and loopback addresses are nonsensical and link-local
  4877. // addresses tend to be used for node-centric purposes (e.g. metadata
  4878. // service).
  4879. allErrs := field.ErrorList{}
  4880. ip := net.ParseIP(ipAddress)
  4881. if ip == nil {
  4882. allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "must be a valid IP address"))
  4883. return allErrs
  4884. }
  4885. if ip.IsUnspecified() {
  4886. allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "may not be unspecified (0.0.0.0)"))
  4887. }
  4888. if ip.IsLoopback() {
  4889. allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "may not be in the loopback range (127.0.0.0/8)"))
  4890. }
  4891. if ip.IsLinkLocalUnicast() {
  4892. allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "may not be in the link-local range (169.254.0.0/16)"))
  4893. }
  4894. if ip.IsLinkLocalMulticast() {
  4895. allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "may not be in the link-local multicast range (224.0.0.0/24)"))
  4896. }
  4897. return allErrs
  4898. }
  4899. func validateEndpointPort(port *core.EndpointPort, requireName bool, fldPath *field.Path) field.ErrorList {
  4900. allErrs := field.ErrorList{}
  4901. if requireName && len(port.Name) == 0 {
  4902. allErrs = append(allErrs, field.Required(fldPath.Child("name"), ""))
  4903. } else if len(port.Name) != 0 {
  4904. allErrs = append(allErrs, ValidateDNS1123Label(port.Name, fldPath.Child("name"))...)
  4905. }
  4906. for _, msg := range validation.IsValidPortNum(int(port.Port)) {
  4907. allErrs = append(allErrs, field.Invalid(fldPath.Child("port"), port.Port, msg))
  4908. }
  4909. if len(port.Protocol) == 0 {
  4910. allErrs = append(allErrs, field.Required(fldPath.Child("protocol"), ""))
  4911. } else if !supportedPortProtocols.Has(string(port.Protocol)) {
  4912. allErrs = append(allErrs, field.NotSupported(fldPath.Child("protocol"), port.Protocol, supportedPortProtocols.List()))
  4913. }
  4914. return allErrs
  4915. }
  4916. // ValidateEndpointsUpdate tests to make sure an endpoints update can be applied.
  4917. // NodeName changes are allowed during update to accommodate the case where nodeIP or PodCIDR is reused.
  4918. // An existing endpoint ip will have a different nodeName if this happens.
  4919. func ValidateEndpointsUpdate(newEndpoints, oldEndpoints *core.Endpoints) field.ErrorList {
  4920. allErrs := ValidateObjectMetaUpdate(&newEndpoints.ObjectMeta, &oldEndpoints.ObjectMeta, field.NewPath("metadata"))
  4921. allErrs = append(allErrs, validateEndpointSubsets(newEndpoints.Subsets, field.NewPath("subsets"))...)
  4922. allErrs = append(allErrs, ValidateEndpointsSpecificAnnotations(newEndpoints.Annotations, field.NewPath("annotations"))...)
  4923. return allErrs
  4924. }
  4925. // ValidateSecurityContext ensures the security context contains valid settings
  4926. func ValidateSecurityContext(sc *core.SecurityContext, fldPath *field.Path) field.ErrorList {
  4927. allErrs := field.ErrorList{}
  4928. //this should only be true for testing since SecurityContext is defaulted by the core
  4929. if sc == nil {
  4930. return allErrs
  4931. }
  4932. if sc.Privileged != nil {
  4933. if *sc.Privileged && !capabilities.Get().AllowPrivileged {
  4934. allErrs = append(allErrs, field.Forbidden(fldPath.Child("privileged"), "disallowed by cluster policy"))
  4935. }
  4936. }
  4937. if sc.RunAsUser != nil {
  4938. for _, msg := range validation.IsValidUserID(*sc.RunAsUser) {
  4939. allErrs = append(allErrs, field.Invalid(fldPath.Child("runAsUser"), *sc.RunAsUser, msg))
  4940. }
  4941. }
  4942. if sc.RunAsGroup != nil {
  4943. for _, msg := range validation.IsValidGroupID(*sc.RunAsGroup) {
  4944. allErrs = append(allErrs, field.Invalid(fldPath.Child("runAsGroup"), *sc.RunAsGroup, msg))
  4945. }
  4946. }
  4947. if sc.ProcMount != nil {
  4948. if err := ValidateProcMountType(fldPath.Child("procMount"), *sc.ProcMount); err != nil {
  4949. allErrs = append(allErrs, err)
  4950. }
  4951. }
  4952. if sc.AllowPrivilegeEscalation != nil && !*sc.AllowPrivilegeEscalation {
  4953. if sc.Privileged != nil && *sc.Privileged {
  4954. allErrs = append(allErrs, field.Invalid(fldPath, sc, "cannot set `allowPrivilegeEscalation` to false and `privileged` to true"))
  4955. }
  4956. if sc.Capabilities != nil {
  4957. for _, cap := range sc.Capabilities.Add {
  4958. if string(cap) == "CAP_SYS_ADMIN" {
  4959. allErrs = append(allErrs, field.Invalid(fldPath, sc, "cannot set `allowPrivilegeEscalation` to false and `capabilities.Add` CAP_SYS_ADMIN"))
  4960. }
  4961. }
  4962. }
  4963. }
  4964. allErrs = append(allErrs, validateWindowsSecurityContextOptions(sc.WindowsOptions, fldPath.Child("windowsOptions"))...)
  4965. return allErrs
  4966. }
  4967. // maxGMSACredentialSpecLength is the max length, in bytes, for the actual contents
  4968. // of a GMSA cred spec. In general, those shouldn't be more than a few hundred bytes,
  4969. // so we want to give plenty of room here while still providing an upper bound.
  4970. // The runAsUserName field will be used to execute the given container's entrypoint, and
  4971. // it can be formatted as "DOMAIN/USER", where the DOMAIN is optional, maxRunAsUserNameDomainLength
  4972. // is the max character length for the user's DOMAIN, and maxRunAsUserNameUserLength
  4973. // is the max character length for the USER itself. Both the DOMAIN and USER have their
  4974. // own restrictions, and more information about them can be found here:
  4975. // https://support.microsoft.com/en-us/help/909264/naming-conventions-in-active-directory-for-computers-domains-sites-and
  4976. // https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/bb726984(v=technet.10)
  4977. const (
  4978. maxGMSACredentialSpecLengthInKiB = 64
  4979. maxGMSACredentialSpecLength = maxGMSACredentialSpecLengthInKiB * 1024
  4980. maxRunAsUserNameDomainLength = 256
  4981. maxRunAsUserNameUserLength = 104
  4982. )
  4983. var (
  4984. // control characters are not permitted in the runAsUserName field.
  4985. ctrlRegex = regexp.MustCompile(`[[:cntrl:]]+`)
  4986. // a valid NetBios Domain name cannot start with a dot, has at least 1 character,
  4987. // at most 15 characters, and it cannot the characters: \ / : * ? " < > |
  4988. validNetBiosRegex = regexp.MustCompile(`^[^\\/:\*\?"<>|\.][^\\/:\*\?"<>|]{0,14}$`)
  4989. // a valid DNS name contains only alphanumeric characters, dots, and dashes.
  4990. dnsLabelFormat = `[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?`
  4991. dnsSubdomainFormat = fmt.Sprintf(`^%s(?:\.%s)*$`, dnsLabelFormat, dnsLabelFormat)
  4992. validWindowsUserDomainDNSRegex = regexp.MustCompile(dnsSubdomainFormat)
  4993. // a username is invalid if it contains the characters: " / \ [ ] : ; | = , + * ? < > @
  4994. // or it contains only dots or spaces.
  4995. invalidUserNameCharsRegex = regexp.MustCompile(`["/\\:;|=,\+\*\?<>@\[\]]`)
  4996. invalidUserNameDotsSpacesRegex = regexp.MustCompile(`^[\. ]+$`)
  4997. )
  4998. func validateWindowsSecurityContextOptions(windowsOptions *core.WindowsSecurityContextOptions, fieldPath *field.Path) field.ErrorList {
  4999. allErrs := field.ErrorList{}
  5000. if windowsOptions == nil {
  5001. return allErrs
  5002. }
  5003. if windowsOptions.GMSACredentialSpecName != nil {
  5004. // gmsaCredentialSpecName must be the name of a custom resource
  5005. for _, msg := range validation.IsDNS1123Subdomain(*windowsOptions.GMSACredentialSpecName) {
  5006. allErrs = append(allErrs, field.Invalid(fieldPath.Child("gmsaCredentialSpecName"), windowsOptions.GMSACredentialSpecName, msg))
  5007. }
  5008. }
  5009. if windowsOptions.GMSACredentialSpec != nil {
  5010. if l := len(*windowsOptions.GMSACredentialSpec); l == 0 {
  5011. allErrs = append(allErrs, field.Invalid(fieldPath.Child("gmsaCredentialSpec"), windowsOptions.GMSACredentialSpec, "gmsaCredentialSpec cannot be an empty string"))
  5012. } else if l > maxGMSACredentialSpecLength {
  5013. errMsg := fmt.Sprintf("gmsaCredentialSpec size must be under %d KiB", maxGMSACredentialSpecLengthInKiB)
  5014. allErrs = append(allErrs, field.Invalid(fieldPath.Child("gmsaCredentialSpec"), windowsOptions.GMSACredentialSpec, errMsg))
  5015. }
  5016. }
  5017. if windowsOptions.RunAsUserName != nil {
  5018. if l := len(*windowsOptions.RunAsUserName); l == 0 {
  5019. allErrs = append(allErrs, field.Invalid(fieldPath.Child("runAsUserName"), windowsOptions.RunAsUserName, "runAsUserName cannot be an empty string"))
  5020. } else if ctrlRegex.MatchString(*windowsOptions.RunAsUserName) {
  5021. errMsg := fmt.Sprintf("runAsUserName cannot contain control characters")
  5022. allErrs = append(allErrs, field.Invalid(fieldPath.Child("runAsUserName"), windowsOptions.RunAsUserName, errMsg))
  5023. } else if parts := strings.Split(*windowsOptions.RunAsUserName, "\\"); len(parts) > 2 {
  5024. errMsg := fmt.Sprintf("runAsUserName cannot contain more than one backslash")
  5025. allErrs = append(allErrs, field.Invalid(fieldPath.Child("runAsUserName"), windowsOptions.RunAsUserName, errMsg))
  5026. } else {
  5027. var (
  5028. hasDomain = false
  5029. domain = ""
  5030. user string
  5031. )
  5032. if len(parts) == 1 {
  5033. user = parts[0]
  5034. } else {
  5035. hasDomain = true
  5036. domain = parts[0]
  5037. user = parts[1]
  5038. }
  5039. if len(domain) >= maxRunAsUserNameDomainLength {
  5040. errMsg := fmt.Sprintf("runAsUserName's Domain length must be under %d characters", maxRunAsUserNameDomainLength)
  5041. allErrs = append(allErrs, field.Invalid(fieldPath.Child("runAsUserName"), windowsOptions.RunAsUserName, errMsg))
  5042. }
  5043. if hasDomain && !(validNetBiosRegex.MatchString(domain) || validWindowsUserDomainDNSRegex.MatchString(domain)) {
  5044. errMsg := "runAsUserName's Domain doesn't match the NetBios nor the DNS format"
  5045. allErrs = append(allErrs, field.Invalid(fieldPath.Child("runAsUserName"), windowsOptions.RunAsUserName, errMsg))
  5046. }
  5047. if l := len(user); l == 0 {
  5048. errMsg := fmt.Sprintf("runAsUserName's User cannot be empty")
  5049. allErrs = append(allErrs, field.Invalid(fieldPath.Child("runAsUserName"), windowsOptions.RunAsUserName, errMsg))
  5050. } else if l > maxRunAsUserNameUserLength {
  5051. errMsg := fmt.Sprintf("runAsUserName's User length must not be longer than %d characters", maxRunAsUserNameUserLength)
  5052. allErrs = append(allErrs, field.Invalid(fieldPath.Child("runAsUserName"), windowsOptions.RunAsUserName, errMsg))
  5053. }
  5054. if invalidUserNameDotsSpacesRegex.MatchString(user) {
  5055. errMsg := `runAsUserName's User cannot contain only periods or spaces`
  5056. allErrs = append(allErrs, field.Invalid(fieldPath.Child("runAsUserName"), windowsOptions.RunAsUserName, errMsg))
  5057. }
  5058. if invalidUserNameCharsRegex.MatchString(user) {
  5059. errMsg := `runAsUserName's User cannot contain the following characters: "/\:;|=,+*?<>@[]`
  5060. allErrs = append(allErrs, field.Invalid(fieldPath.Child("runAsUserName"), windowsOptions.RunAsUserName, errMsg))
  5061. }
  5062. }
  5063. }
  5064. return allErrs
  5065. }
  5066. func ValidatePodLogOptions(opts *core.PodLogOptions) field.ErrorList {
  5067. allErrs := field.ErrorList{}
  5068. if opts.TailLines != nil && *opts.TailLines < 0 {
  5069. allErrs = append(allErrs, field.Invalid(field.NewPath("tailLines"), *opts.TailLines, isNegativeErrorMsg))
  5070. }
  5071. if opts.LimitBytes != nil && *opts.LimitBytes < 1 {
  5072. allErrs = append(allErrs, field.Invalid(field.NewPath("limitBytes"), *opts.LimitBytes, "must be greater than 0"))
  5073. }
  5074. switch {
  5075. case opts.SinceSeconds != nil && opts.SinceTime != nil:
  5076. allErrs = append(allErrs, field.Forbidden(field.NewPath(""), "at most one of `sinceTime` or `sinceSeconds` may be specified"))
  5077. case opts.SinceSeconds != nil:
  5078. if *opts.SinceSeconds < 1 {
  5079. allErrs = append(allErrs, field.Invalid(field.NewPath("sinceSeconds"), *opts.SinceSeconds, "must be greater than 0"))
  5080. }
  5081. }
  5082. return allErrs
  5083. }
  5084. // ValidateLoadBalancerStatus validates required fields on a LoadBalancerStatus
  5085. func ValidateLoadBalancerStatus(status *core.LoadBalancerStatus, fldPath *field.Path) field.ErrorList {
  5086. allErrs := field.ErrorList{}
  5087. for i, ingress := range status.Ingress {
  5088. idxPath := fldPath.Child("ingress").Index(i)
  5089. if len(ingress.IP) > 0 {
  5090. if isIP := (net.ParseIP(ingress.IP) != nil); !isIP {
  5091. allErrs = append(allErrs, field.Invalid(idxPath.Child("ip"), ingress.IP, "must be a valid IP address"))
  5092. }
  5093. }
  5094. if len(ingress.Hostname) > 0 {
  5095. for _, msg := range validation.IsDNS1123Subdomain(ingress.Hostname) {
  5096. allErrs = append(allErrs, field.Invalid(idxPath.Child("hostname"), ingress.Hostname, msg))
  5097. }
  5098. if isIP := (net.ParseIP(ingress.Hostname) != nil); isIP {
  5099. allErrs = append(allErrs, field.Invalid(idxPath.Child("hostname"), ingress.Hostname, "must be a DNS name, not an IP address"))
  5100. }
  5101. }
  5102. }
  5103. return allErrs
  5104. }
  5105. // validateVolumeNodeAffinity tests that the PersistentVolume.NodeAffinity has valid data
  5106. // returns:
  5107. // - true if volumeNodeAffinity is set
  5108. // - errorList if there are validation errors
  5109. func validateVolumeNodeAffinity(nodeAffinity *core.VolumeNodeAffinity, fldPath *field.Path) (bool, field.ErrorList) {
  5110. allErrs := field.ErrorList{}
  5111. if nodeAffinity == nil {
  5112. return false, allErrs
  5113. }
  5114. if nodeAffinity.Required != nil {
  5115. allErrs = append(allErrs, ValidateNodeSelector(nodeAffinity.Required, fldPath.Child("required"))...)
  5116. } else {
  5117. allErrs = append(allErrs, field.Required(fldPath.Child("required"), "must specify required node constraints"))
  5118. }
  5119. return true, allErrs
  5120. }
  5121. // ValidateCIDR validates whether a CIDR matches the conventions expected by net.ParseCIDR
  5122. func ValidateCIDR(cidr string) (*net.IPNet, error) {
  5123. _, net, err := net.ParseCIDR(cidr)
  5124. if err != nil {
  5125. return nil, err
  5126. }
  5127. return net, nil
  5128. }
  5129. func IsDecremented(update, old *int32) bool {
  5130. if update == nil && old != nil {
  5131. return true
  5132. }
  5133. if update == nil || old == nil {
  5134. return false
  5135. }
  5136. return *update < *old
  5137. }
  5138. // ValidateProcMountType tests that the argument is a valid ProcMountType.
  5139. func ValidateProcMountType(fldPath *field.Path, procMountType core.ProcMountType) *field.Error {
  5140. switch procMountType {
  5141. case core.DefaultProcMount, core.UnmaskedProcMount:
  5142. return nil
  5143. default:
  5144. return field.NotSupported(fldPath, procMountType, []string{string(core.DefaultProcMount), string(core.UnmaskedProcMount)})
  5145. }
  5146. }
  5147. var (
  5148. supportedScheduleActions = sets.NewString(string(core.DoNotSchedule), string(core.ScheduleAnyway))
  5149. )
  5150. // validateTopologySpreadConstraints validates given TopologySpreadConstraints.
  5151. func validateTopologySpreadConstraints(constraints []core.TopologySpreadConstraint, fldPath *field.Path) field.ErrorList {
  5152. allErrs := field.ErrorList{}
  5153. for i, constraint := range constraints {
  5154. subFldPath := fldPath.Index(i)
  5155. if err := ValidateMaxSkew(subFldPath.Child("maxSkew"), constraint.MaxSkew); err != nil {
  5156. allErrs = append(allErrs, err)
  5157. }
  5158. if err := ValidateTopologyKey(subFldPath.Child("topologyKey"), constraint.TopologyKey); err != nil {
  5159. allErrs = append(allErrs, err)
  5160. }
  5161. if err := ValidateWhenUnsatisfiable(subFldPath.Child("whenUnsatisfiable"), constraint.WhenUnsatisfiable); err != nil {
  5162. allErrs = append(allErrs, err)
  5163. }
  5164. // tuple {topologyKey, whenUnsatisfiable} denotes one kind of spread constraint
  5165. if err := ValidateSpreadConstraintNotRepeat(subFldPath.Child("{topologyKey, whenUnsatisfiable}"), constraint, constraints[i+1:]); err != nil {
  5166. allErrs = append(allErrs, err)
  5167. }
  5168. }
  5169. return allErrs
  5170. }
  5171. // ValidateMaxSkew tests that the argument is a valid MaxSkew.
  5172. func ValidateMaxSkew(fldPath *field.Path, maxSkew int32) *field.Error {
  5173. if maxSkew <= 0 {
  5174. return field.Invalid(fldPath, maxSkew, isNotPositiveErrorMsg)
  5175. }
  5176. return nil
  5177. }
  5178. // ValidateTopologyKey tests that the argument is a valid TopologyKey.
  5179. func ValidateTopologyKey(fldPath *field.Path, topologyKey string) *field.Error {
  5180. if len(topologyKey) == 0 {
  5181. return field.Required(fldPath, "can not be empty")
  5182. }
  5183. return nil
  5184. }
  5185. // ValidateWhenUnsatisfiable tests that the argument is a valid UnsatisfiableConstraintAction.
  5186. func ValidateWhenUnsatisfiable(fldPath *field.Path, action core.UnsatisfiableConstraintAction) *field.Error {
  5187. if !supportedScheduleActions.Has(string(action)) {
  5188. return field.NotSupported(fldPath, action, supportedScheduleActions.List())
  5189. }
  5190. return nil
  5191. }
  5192. // ValidateSpreadConstraintNotRepeat tests that if `constraint` duplicates with `existingConstraintPairs`
  5193. // on TopologyKey and WhenUnsatisfiable fields.
  5194. func ValidateSpreadConstraintNotRepeat(fldPath *field.Path, constraint core.TopologySpreadConstraint, restingConstraints []core.TopologySpreadConstraint) *field.Error {
  5195. for _, restingConstraint := range restingConstraints {
  5196. if constraint.TopologyKey == restingConstraint.TopologyKey &&
  5197. constraint.WhenUnsatisfiable == restingConstraint.WhenUnsatisfiable {
  5198. return field.Duplicate(fldPath, fmt.Sprintf("{%v, %v}", constraint.TopologyKey, constraint.WhenUnsatisfiable))
  5199. }
  5200. }
  5201. return nil
  5202. }