validation.go 148 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599
  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. "net"
  18. "os"
  19. "path"
  20. "reflect"
  21. "regexp"
  22. "strings"
  23. "github.com/golang/glog"
  24. "k8s.io/kubernetes/pkg/api"
  25. "k8s.io/kubernetes/pkg/api/endpoints"
  26. utilpod "k8s.io/kubernetes/pkg/api/pod"
  27. "k8s.io/kubernetes/pkg/api/resource"
  28. apiservice "k8s.io/kubernetes/pkg/api/service"
  29. "k8s.io/kubernetes/pkg/api/unversioned"
  30. unversionedvalidation "k8s.io/kubernetes/pkg/api/unversioned/validation"
  31. "k8s.io/kubernetes/pkg/api/v1"
  32. "k8s.io/kubernetes/pkg/capabilities"
  33. "k8s.io/kubernetes/pkg/labels"
  34. "k8s.io/kubernetes/pkg/security/apparmor"
  35. utilconfig "k8s.io/kubernetes/pkg/util/config"
  36. "k8s.io/kubernetes/pkg/util/intstr"
  37. "k8s.io/kubernetes/pkg/util/sets"
  38. "k8s.io/kubernetes/pkg/util/validation"
  39. "k8s.io/kubernetes/pkg/util/validation/field"
  40. )
  41. // TODO: delete this global variable when we enable the validation of common
  42. // fields by default.
  43. var RepairMalformedUpdates bool = true
  44. const isNegativeErrorMsg string = `must be greater than or equal to 0`
  45. const isInvalidQuotaResource string = `must be a standard resource for quota`
  46. const fieldImmutableErrorMsg string = `field is immutable`
  47. const isNotIntegerErrorMsg string = `must be an integer`
  48. var pdPartitionErrorMsg string = validation.InclusiveRangeError(1, 255)
  49. var volumeModeErrorMsg string = "must be a number between 0 and 0777 (octal), both inclusive"
  50. const totalAnnotationSizeLimitB int = 256 * (1 << 10) // 256 kB
  51. // BannedOwners is a black list of object that are not allowed to be owners.
  52. var BannedOwners = map[unversioned.GroupVersionKind]struct{}{
  53. v1.SchemeGroupVersion.WithKind("Event"): {},
  54. }
  55. // ValidateHasLabel requires that api.ObjectMeta has a Label with key and expectedValue
  56. func ValidateHasLabel(meta api.ObjectMeta, fldPath *field.Path, key, expectedValue string) field.ErrorList {
  57. allErrs := field.ErrorList{}
  58. actualValue, found := meta.Labels[key]
  59. if !found {
  60. allErrs = append(allErrs, field.Required(fldPath.Child("labels").Key(key),
  61. fmt.Sprintf("must be '%s'", expectedValue)))
  62. return allErrs
  63. }
  64. if actualValue != expectedValue {
  65. allErrs = append(allErrs, field.Invalid(fldPath.Child("labels").Key(key), meta.Labels,
  66. fmt.Sprintf("must be '%s'", expectedValue)))
  67. }
  68. return allErrs
  69. }
  70. // ValidateAnnotations validates that a set of annotations are correctly defined.
  71. func ValidateAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
  72. allErrs := field.ErrorList{}
  73. var totalSize int64
  74. for k, v := range annotations {
  75. for _, msg := range validation.IsQualifiedName(strings.ToLower(k)) {
  76. allErrs = append(allErrs, field.Invalid(fldPath, k, msg))
  77. }
  78. totalSize += (int64)(len(k)) + (int64)(len(v))
  79. }
  80. if totalSize > (int64)(totalAnnotationSizeLimitB) {
  81. allErrs = append(allErrs, field.TooLong(fldPath, "", totalAnnotationSizeLimitB))
  82. }
  83. return allErrs
  84. }
  85. func ValidateDNS1123Label(value string, fldPath *field.Path) field.ErrorList {
  86. allErrs := field.ErrorList{}
  87. for _, msg := range validation.IsDNS1123Label(value) {
  88. allErrs = append(allErrs, field.Invalid(fldPath, value, msg))
  89. }
  90. return allErrs
  91. }
  92. // ValidateDNS1123Subdomain validates that a name is a proper DNS subdomain.
  93. func ValidateDNS1123Subdomain(value string, fldPath *field.Path) field.ErrorList {
  94. allErrs := field.ErrorList{}
  95. for _, msg := range validation.IsDNS1123Subdomain(value) {
  96. allErrs = append(allErrs, field.Invalid(fldPath, value, msg))
  97. }
  98. return allErrs
  99. }
  100. func ValidatePodSpecificAnnotations(annotations map[string]string, spec *api.PodSpec, fldPath *field.Path) field.ErrorList {
  101. allErrs := field.ErrorList{}
  102. if annotations[api.AffinityAnnotationKey] != "" {
  103. allErrs = append(allErrs, ValidateAffinityInPodAnnotations(annotations, fldPath)...)
  104. }
  105. if annotations[api.TolerationsAnnotationKey] != "" {
  106. allErrs = append(allErrs, ValidateTolerationsInPodAnnotations(annotations, fldPath)...)
  107. }
  108. // TODO: remove these after we EOL the annotations.
  109. if hostname, exists := annotations[utilpod.PodHostnameAnnotation]; exists {
  110. allErrs = append(allErrs, ValidateDNS1123Label(hostname, fldPath.Key(utilpod.PodHostnameAnnotation))...)
  111. }
  112. if subdomain, exists := annotations[utilpod.PodSubdomainAnnotation]; exists {
  113. allErrs = append(allErrs, ValidateDNS1123Label(subdomain, fldPath.Key(utilpod.PodSubdomainAnnotation))...)
  114. }
  115. allErrs = append(allErrs, ValidateSeccompPodAnnotations(annotations, fldPath)...)
  116. allErrs = append(allErrs, ValidateAppArmorPodAnnotations(annotations, spec, fldPath)...)
  117. sysctls, err := api.SysctlsFromPodAnnotation(annotations[api.SysctlsPodAnnotationKey])
  118. if err != nil {
  119. allErrs = append(allErrs, field.Invalid(fldPath.Key(api.SysctlsPodAnnotationKey), annotations[api.SysctlsPodAnnotationKey], err.Error()))
  120. } else {
  121. allErrs = append(allErrs, validateSysctls(sysctls, fldPath.Key(api.SysctlsPodAnnotationKey))...)
  122. }
  123. unsafeSysctls, err := api.SysctlsFromPodAnnotation(annotations[api.UnsafeSysctlsPodAnnotationKey])
  124. if err != nil {
  125. allErrs = append(allErrs, field.Invalid(fldPath.Key(api.UnsafeSysctlsPodAnnotationKey), annotations[api.UnsafeSysctlsPodAnnotationKey], err.Error()))
  126. } else {
  127. allErrs = append(allErrs, validateSysctls(unsafeSysctls, fldPath.Key(api.UnsafeSysctlsPodAnnotationKey))...)
  128. }
  129. inBoth := sysctlIntersection(sysctls, unsafeSysctls)
  130. if len(inBoth) > 0 {
  131. allErrs = append(allErrs, field.Invalid(fldPath.Key(api.UnsafeSysctlsPodAnnotationKey), strings.Join(inBoth, ", "), "can not be safe and unsafe"))
  132. }
  133. return allErrs
  134. }
  135. func ValidatePodSpecificAnnotationUpdates(newPod, oldPod *api.Pod, fldPath *field.Path) field.ErrorList {
  136. allErrs := field.ErrorList{}
  137. newAnnotations := newPod.Annotations
  138. oldAnnotations := oldPod.Annotations
  139. for k, oldVal := range oldAnnotations {
  140. if newAnnotations[k] == oldVal {
  141. continue // No change.
  142. }
  143. if strings.HasPrefix(k, apparmor.ContainerAnnotationKeyPrefix) {
  144. allErrs = append(allErrs, field.Forbidden(fldPath.Key(k), "may not update AppArmor annotations"))
  145. }
  146. }
  147. // Check for removals.
  148. for k := range newAnnotations {
  149. if _, ok := oldAnnotations[k]; ok {
  150. continue // No change.
  151. }
  152. if strings.HasPrefix(k, apparmor.ContainerAnnotationKeyPrefix) {
  153. allErrs = append(allErrs, field.Forbidden(fldPath.Key(k), "may not remove AppArmor annotations"))
  154. }
  155. }
  156. allErrs = append(allErrs, ValidatePodSpecificAnnotations(newAnnotations, &newPod.Spec, fldPath)...)
  157. return allErrs
  158. }
  159. func ValidateEndpointsSpecificAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
  160. allErrs := field.ErrorList{}
  161. // TODO: remove this after we EOL the annotation.
  162. hostnamesMap, exists := annotations[endpoints.PodHostnamesAnnotation]
  163. if exists && !isValidHostnamesMap(hostnamesMap) {
  164. allErrs = append(allErrs, field.Invalid(fldPath, endpoints.PodHostnamesAnnotation,
  165. `must be a valid json representation of map[string(IP)][HostRecord] e.g. "{"10.245.1.6":{"HostName":"my-webserver"}}"`))
  166. }
  167. return allErrs
  168. }
  169. func validateOwnerReference(ownerReference api.OwnerReference, fldPath *field.Path) field.ErrorList {
  170. allErrs := field.ErrorList{}
  171. gvk := unversioned.FromAPIVersionAndKind(ownerReference.APIVersion, ownerReference.Kind)
  172. // gvk.Group is empty for the legacy group.
  173. if len(gvk.Version) == 0 {
  174. allErrs = append(allErrs, field.Invalid(fldPath.Child("apiVersion"), ownerReference.APIVersion, "version must not be empty"))
  175. }
  176. if len(gvk.Kind) == 0 {
  177. allErrs = append(allErrs, field.Invalid(fldPath.Child("kind"), ownerReference.Kind, "kind must not be empty"))
  178. }
  179. if len(ownerReference.Name) == 0 {
  180. allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), ownerReference.Name, "name must not be empty"))
  181. }
  182. if len(ownerReference.UID) == 0 {
  183. allErrs = append(allErrs, field.Invalid(fldPath.Child("uid"), ownerReference.UID, "uid must not be empty"))
  184. }
  185. if _, ok := BannedOwners[gvk]; ok {
  186. allErrs = append(allErrs, field.Invalid(fldPath, ownerReference, fmt.Sprintf("%s is disallowed from being an owner", gvk)))
  187. }
  188. return allErrs
  189. }
  190. func ValidateOwnerReferences(ownerReferences []api.OwnerReference, fldPath *field.Path) field.ErrorList {
  191. allErrs := field.ErrorList{}
  192. controllerName := ""
  193. for _, ref := range ownerReferences {
  194. allErrs = append(allErrs, validateOwnerReference(ref, fldPath)...)
  195. if ref.Controller != nil && *ref.Controller {
  196. if controllerName != "" {
  197. allErrs = append(allErrs, field.Invalid(fldPath, ownerReferences,
  198. fmt.Sprintf("Only one reference can have Controller set to true. Found \"true\" in references for %v and %v", controllerName, ref.Name)))
  199. } else {
  200. controllerName = ref.Name
  201. }
  202. }
  203. }
  204. return allErrs
  205. }
  206. // ValidateNameFunc validates that the provided name is valid for a given resource type.
  207. // Not all resources have the same validation rules for names. Prefix is true
  208. // if the name will have a value appended to it. If the name is not valid,
  209. // this returns a list of descriptions of individual characteristics of the
  210. // value that were not valid. Otherwise this returns an empty list or nil.
  211. type ValidateNameFunc func(name string, prefix bool) []string
  212. // maskTrailingDash replaces the final character of a string with a subdomain safe
  213. // value if is a dash.
  214. func maskTrailingDash(name string) string {
  215. if strings.HasSuffix(name, "-") {
  216. return name[:len(name)-2] + "a"
  217. }
  218. return name
  219. }
  220. // ValidatePodName can be used to check whether the given pod name is valid.
  221. // Prefix indicates this name will be used as part of generation, in which case
  222. // trailing dashes are allowed.
  223. var ValidatePodName = NameIsDNSSubdomain
  224. // ValidateReplicationControllerName can be used to check whether the given replication
  225. // controller name is valid.
  226. // Prefix indicates this name will be used as part of generation, in which case
  227. // trailing dashes are allowed.
  228. var ValidateReplicationControllerName = NameIsDNSSubdomain
  229. // ValidateServiceName can be used to check whether the given service name is valid.
  230. // Prefix indicates this name will be used as part of generation, in which case
  231. // trailing dashes are allowed.
  232. var ValidateServiceName = NameIsDNS1035Label
  233. // ValidateNodeName can be used to check whether the given node name is valid.
  234. // Prefix indicates this name will be used as part of generation, in which case
  235. // trailing dashes are allowed.
  236. var ValidateNodeName = NameIsDNSSubdomain
  237. // ValidateNamespaceName can be used to check whether the given namespace name is valid.
  238. // Prefix indicates this name will be used as part of generation, in which case
  239. // trailing dashes are allowed.
  240. var ValidateNamespaceName = NameIsDNSLabel
  241. // ValidateLimitRangeName can be used to check whether the given limit range name is valid.
  242. // Prefix indicates this name will be used as part of generation, in which case
  243. // trailing dashes are allowed.
  244. var ValidateLimitRangeName = NameIsDNSSubdomain
  245. // ValidateResourceQuotaName can be used to check whether the given
  246. // resource quota name is valid.
  247. // Prefix indicates this name will be used as part of generation, in which case
  248. // trailing dashes are allowed.
  249. var ValidateResourceQuotaName = NameIsDNSSubdomain
  250. // ValidateSecretName can be used to check whether the given secret name is valid.
  251. // Prefix indicates this name will be used as part of generation, in which case
  252. // trailing dashes are allowed.
  253. var ValidateSecretName = NameIsDNSSubdomain
  254. // ValidateServiceAccountName can be used to check whether the given service account name is valid.
  255. // Prefix indicates this name will be used as part of generation, in which case
  256. // trailing dashes are allowed.
  257. var ValidateServiceAccountName = NameIsDNSSubdomain
  258. // ValidateEndpointsName can be used to check whether the given endpoints name is valid.
  259. // Prefix indicates this name will be used as part of generation, in which case
  260. // trailing dashes are allowed.
  261. var ValidateEndpointsName = NameIsDNSSubdomain
  262. // ValidateClusterName can be used to check whether the given cluster name is valid.
  263. var ValidateClusterName = NameIsDNS1035Label
  264. // NameIsDNSSubdomain is a ValidateNameFunc for names that must be a DNS subdomain.
  265. func NameIsDNSSubdomain(name string, prefix bool) []string {
  266. if prefix {
  267. name = maskTrailingDash(name)
  268. }
  269. return validation.IsDNS1123Subdomain(name)
  270. }
  271. // NameIsDNSLabel is a ValidateNameFunc for names that must be a DNS 1123 label.
  272. func NameIsDNSLabel(name string, prefix bool) []string {
  273. if prefix {
  274. name = maskTrailingDash(name)
  275. }
  276. return validation.IsDNS1123Label(name)
  277. }
  278. // NameIsDNS1035Label is a ValidateNameFunc for names that must be a DNS 952 label.
  279. func NameIsDNS1035Label(name string, prefix bool) []string {
  280. if prefix {
  281. name = maskTrailingDash(name)
  282. }
  283. return validation.IsDNS1035Label(name)
  284. }
  285. // Validates that given value is not negative.
  286. func ValidateNonnegativeField(value int64, fldPath *field.Path) field.ErrorList {
  287. allErrs := field.ErrorList{}
  288. if value < 0 {
  289. allErrs = append(allErrs, field.Invalid(fldPath, value, isNegativeErrorMsg))
  290. }
  291. return allErrs
  292. }
  293. // Validates that a Quantity is not negative
  294. func ValidateNonnegativeQuantity(value resource.Quantity, fldPath *field.Path) field.ErrorList {
  295. allErrs := field.ErrorList{}
  296. if value.Cmp(resource.Quantity{}) < 0 {
  297. allErrs = append(allErrs, field.Invalid(fldPath, value.String(), isNegativeErrorMsg))
  298. }
  299. return allErrs
  300. }
  301. func ValidateImmutableField(newVal, oldVal interface{}, fldPath *field.Path) field.ErrorList {
  302. allErrs := field.ErrorList{}
  303. if !api.Semantic.DeepEqual(oldVal, newVal) {
  304. allErrs = append(allErrs, field.Invalid(fldPath, newVal, fieldImmutableErrorMsg))
  305. }
  306. return allErrs
  307. }
  308. // ValidateObjectMeta validates an object's metadata on creation. It expects that name generation has already
  309. // been performed.
  310. // It doesn't return an error for rootscoped resources with namespace, because namespace should already be cleared before.
  311. // TODO: Remove calls to this method scattered in validations of specific resources, e.g., ValidatePodUpdate.
  312. func ValidateObjectMeta(meta *api.ObjectMeta, requiresNamespace bool, nameFn ValidateNameFunc, fldPath *field.Path) field.ErrorList {
  313. allErrs := field.ErrorList{}
  314. if len(meta.GenerateName) != 0 {
  315. for _, msg := range nameFn(meta.GenerateName, true) {
  316. allErrs = append(allErrs, field.Invalid(fldPath.Child("generateName"), meta.GenerateName, msg))
  317. }
  318. }
  319. // If the generated name validates, but the calculated value does not, it's a problem with generation, and we
  320. // report it here. This may confuse users, but indicates a programming bug and still must be validated.
  321. // If there are multiple fields out of which one is required then add an or as a separator
  322. if len(meta.Name) == 0 {
  323. allErrs = append(allErrs, field.Required(fldPath.Child("name"), "name or generateName is required"))
  324. } else {
  325. for _, msg := range nameFn(meta.Name, false) {
  326. allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), meta.Name, msg))
  327. }
  328. }
  329. if requiresNamespace {
  330. if len(meta.Namespace) == 0 {
  331. allErrs = append(allErrs, field.Required(fldPath.Child("namespace"), ""))
  332. } else {
  333. for _, msg := range ValidateNamespaceName(meta.Namespace, false) {
  334. allErrs = append(allErrs, field.Invalid(fldPath.Child("namespace"), meta.Namespace, msg))
  335. }
  336. }
  337. } else {
  338. if len(meta.Namespace) != 0 {
  339. allErrs = append(allErrs, field.Forbidden(fldPath.Child("namespace"), "not allowed on this type"))
  340. }
  341. }
  342. if len(meta.ClusterName) != 0 {
  343. for _, msg := range ValidateClusterName(meta.ClusterName, false) {
  344. allErrs = append(allErrs, field.Invalid(fldPath.Child("clusterName"), meta.ClusterName, msg))
  345. }
  346. }
  347. allErrs = append(allErrs, ValidateNonnegativeField(meta.Generation, fldPath.Child("generation"))...)
  348. allErrs = append(allErrs, unversionedvalidation.ValidateLabels(meta.Labels, fldPath.Child("labels"))...)
  349. allErrs = append(allErrs, ValidateAnnotations(meta.Annotations, fldPath.Child("annotations"))...)
  350. allErrs = append(allErrs, ValidateOwnerReferences(meta.OwnerReferences, fldPath.Child("ownerReferences"))...)
  351. for _, finalizer := range meta.Finalizers {
  352. allErrs = append(allErrs, validateFinalizerName(finalizer, fldPath.Child("finalizers"))...)
  353. }
  354. return allErrs
  355. }
  356. // ValidateObjectMetaUpdate validates an object's metadata when updated
  357. func ValidateObjectMetaUpdate(newMeta, oldMeta *api.ObjectMeta, fldPath *field.Path) field.ErrorList {
  358. allErrs := field.ErrorList{}
  359. if !RepairMalformedUpdates && newMeta.UID != oldMeta.UID {
  360. allErrs = append(allErrs, field.Invalid(fldPath.Child("uid"), newMeta.UID, "field is immutable"))
  361. }
  362. // in the event it is left empty, set it, to allow clients more flexibility
  363. // TODO: remove the following code that repairs the update request when we retire the clients that modify the immutable fields.
  364. // Please do not copy this pattern elsewhere; validation functions should not be modifying the objects they are passed!
  365. if RepairMalformedUpdates {
  366. if len(newMeta.UID) == 0 {
  367. newMeta.UID = oldMeta.UID
  368. }
  369. // ignore changes to timestamp
  370. if oldMeta.CreationTimestamp.IsZero() {
  371. oldMeta.CreationTimestamp = newMeta.CreationTimestamp
  372. } else {
  373. newMeta.CreationTimestamp = oldMeta.CreationTimestamp
  374. }
  375. // an object can never remove a deletion timestamp or clear/change grace period seconds
  376. if !oldMeta.DeletionTimestamp.IsZero() {
  377. newMeta.DeletionTimestamp = oldMeta.DeletionTimestamp
  378. }
  379. if oldMeta.DeletionGracePeriodSeconds != nil && newMeta.DeletionGracePeriodSeconds == nil {
  380. newMeta.DeletionGracePeriodSeconds = oldMeta.DeletionGracePeriodSeconds
  381. }
  382. }
  383. // TODO: needs to check if newMeta==nil && oldMeta !=nil after the repair logic is removed.
  384. if newMeta.DeletionGracePeriodSeconds != nil && (oldMeta.DeletionGracePeriodSeconds == nil || *newMeta.DeletionGracePeriodSeconds != *oldMeta.DeletionGracePeriodSeconds) {
  385. allErrs = append(allErrs, field.Invalid(fldPath.Child("deletionGracePeriodSeconds"), newMeta.DeletionGracePeriodSeconds, "field is immutable; may only be changed via deletion"))
  386. }
  387. if newMeta.DeletionTimestamp != nil && (oldMeta.DeletionTimestamp == nil || !newMeta.DeletionTimestamp.Equal(*oldMeta.DeletionTimestamp)) {
  388. allErrs = append(allErrs, field.Invalid(fldPath.Child("deletionTimestamp"), newMeta.DeletionTimestamp, "field is immutable; may only be changed via deletion"))
  389. }
  390. // Reject updates that don't specify a resource version
  391. if len(newMeta.ResourceVersion) == 0 {
  392. allErrs = append(allErrs, field.Invalid(fldPath.Child("resourceVersion"), newMeta.ResourceVersion, "must be specified for an update"))
  393. }
  394. // Generation shouldn't be decremented
  395. if newMeta.Generation < oldMeta.Generation {
  396. allErrs = append(allErrs, field.Invalid(fldPath.Child("generation"), newMeta.Generation, "must not be decremented"))
  397. }
  398. allErrs = append(allErrs, ValidateImmutableField(newMeta.Name, oldMeta.Name, fldPath.Child("name"))...)
  399. allErrs = append(allErrs, ValidateImmutableField(newMeta.Namespace, oldMeta.Namespace, fldPath.Child("namespace"))...)
  400. allErrs = append(allErrs, ValidateImmutableField(newMeta.UID, oldMeta.UID, fldPath.Child("uid"))...)
  401. allErrs = append(allErrs, ValidateImmutableField(newMeta.CreationTimestamp, oldMeta.CreationTimestamp, fldPath.Child("creationTimestamp"))...)
  402. allErrs = append(allErrs, ValidateImmutableField(newMeta.ClusterName, oldMeta.ClusterName, fldPath.Child("clusterName"))...)
  403. allErrs = append(allErrs, unversionedvalidation.ValidateLabels(newMeta.Labels, fldPath.Child("labels"))...)
  404. allErrs = append(allErrs, ValidateAnnotations(newMeta.Annotations, fldPath.Child("annotations"))...)
  405. allErrs = append(allErrs, ValidateOwnerReferences(newMeta.OwnerReferences, fldPath.Child("ownerReferences"))...)
  406. return allErrs
  407. }
  408. func validateVolumes(volumes []api.Volume, fldPath *field.Path) (sets.String, field.ErrorList) {
  409. allErrs := field.ErrorList{}
  410. allNames := sets.String{}
  411. for i, vol := range volumes {
  412. idxPath := fldPath.Index(i)
  413. namePath := idxPath.Child("name")
  414. el := validateVolumeSource(&vol.VolumeSource, idxPath)
  415. if len(vol.Name) == 0 {
  416. el = append(el, field.Required(namePath, ""))
  417. } else {
  418. el = append(el, ValidateDNS1123Label(vol.Name, namePath)...)
  419. }
  420. if allNames.Has(vol.Name) {
  421. el = append(el, field.Duplicate(namePath, vol.Name))
  422. }
  423. if len(el) == 0 {
  424. allNames.Insert(vol.Name)
  425. } else {
  426. allErrs = append(allErrs, el...)
  427. }
  428. }
  429. return allNames, allErrs
  430. }
  431. func validateVolumeSource(source *api.VolumeSource, fldPath *field.Path) field.ErrorList {
  432. numVolumes := 0
  433. allErrs := field.ErrorList{}
  434. if source.EmptyDir != nil {
  435. numVolumes++
  436. // EmptyDirs have nothing to validate
  437. }
  438. if source.HostPath != nil {
  439. if numVolumes > 0 {
  440. allErrs = append(allErrs, field.Forbidden(fldPath.Child("hostPath"), "may not specify more than 1 volume type"))
  441. } else {
  442. numVolumes++
  443. allErrs = append(allErrs, validateHostPathVolumeSource(source.HostPath, fldPath.Child("hostPath"))...)
  444. }
  445. }
  446. if source.GitRepo != nil {
  447. if numVolumes > 0 {
  448. allErrs = append(allErrs, field.Forbidden(fldPath.Child("gitRepo"), "may not specify more than 1 volume type"))
  449. } else {
  450. numVolumes++
  451. allErrs = append(allErrs, validateGitRepoVolumeSource(source.GitRepo, fldPath.Child("gitRepo"))...)
  452. }
  453. }
  454. if source.GCEPersistentDisk != nil {
  455. if numVolumes > 0 {
  456. allErrs = append(allErrs, field.Forbidden(fldPath.Child("gcePersistentDisk"), "may not specify more than 1 volume type"))
  457. } else {
  458. numVolumes++
  459. allErrs = append(allErrs, validateGCEPersistentDiskVolumeSource(source.GCEPersistentDisk, fldPath.Child("persistentDisk"))...)
  460. }
  461. }
  462. if source.AWSElasticBlockStore != nil {
  463. if numVolumes > 0 {
  464. allErrs = append(allErrs, field.Forbidden(fldPath.Child("awsElasticBlockStore"), "may not specify more than 1 volume type"))
  465. } else {
  466. numVolumes++
  467. allErrs = append(allErrs, validateAWSElasticBlockStoreVolumeSource(source.AWSElasticBlockStore, fldPath.Child("awsElasticBlockStore"))...)
  468. }
  469. }
  470. if source.Secret != nil {
  471. if numVolumes > 0 {
  472. allErrs = append(allErrs, field.Forbidden(fldPath.Child("secret"), "may not specify more than 1 volume type"))
  473. } else {
  474. numVolumes++
  475. allErrs = append(allErrs, validateSecretVolumeSource(source.Secret, fldPath.Child("secret"))...)
  476. }
  477. }
  478. if source.NFS != nil {
  479. if numVolumes > 0 {
  480. allErrs = append(allErrs, field.Forbidden(fldPath.Child("nfs"), "may not specify more than 1 volume type"))
  481. } else {
  482. numVolumes++
  483. allErrs = append(allErrs, validateNFSVolumeSource(source.NFS, fldPath.Child("nfs"))...)
  484. }
  485. }
  486. if source.ISCSI != nil {
  487. if numVolumes > 0 {
  488. allErrs = append(allErrs, field.Forbidden(fldPath.Child("iscsi"), "may not specify more than 1 volume type"))
  489. } else {
  490. numVolumes++
  491. allErrs = append(allErrs, validateISCSIVolumeSource(source.ISCSI, fldPath.Child("iscsi"))...)
  492. }
  493. }
  494. if source.Glusterfs != nil {
  495. if numVolumes > 0 {
  496. allErrs = append(allErrs, field.Forbidden(fldPath.Child("glusterfs"), "may not specify more than 1 volume type"))
  497. } else {
  498. numVolumes++
  499. allErrs = append(allErrs, validateGlusterfs(source.Glusterfs, fldPath.Child("glusterfs"))...)
  500. }
  501. }
  502. if source.Flocker != nil {
  503. if numVolumes > 0 {
  504. allErrs = append(allErrs, field.Forbidden(fldPath.Child("flocker"), "may not specify more than 1 volume type"))
  505. } else {
  506. numVolumes++
  507. allErrs = append(allErrs, validateFlockerVolumeSource(source.Flocker, fldPath.Child("flocker"))...)
  508. }
  509. }
  510. if source.PersistentVolumeClaim != nil {
  511. if numVolumes > 0 {
  512. allErrs = append(allErrs, field.Forbidden(fldPath.Child("persistentVolumeClaim"), "may not specify more than 1 volume type"))
  513. } else {
  514. numVolumes++
  515. allErrs = append(allErrs, validatePersistentClaimVolumeSource(source.PersistentVolumeClaim, fldPath.Child("persistentVolumeClaim"))...)
  516. }
  517. }
  518. if source.RBD != nil {
  519. if numVolumes > 0 {
  520. allErrs = append(allErrs, field.Forbidden(fldPath.Child("rbd"), "may not specify more than 1 volume type"))
  521. } else {
  522. numVolumes++
  523. allErrs = append(allErrs, validateRBDVolumeSource(source.RBD, fldPath.Child("rbd"))...)
  524. }
  525. }
  526. if source.Cinder != nil {
  527. if numVolumes > 0 {
  528. allErrs = append(allErrs, field.Forbidden(fldPath.Child("cinder"), "may not specify more than 1 volume type"))
  529. } else {
  530. numVolumes++
  531. allErrs = append(allErrs, validateCinderVolumeSource(source.Cinder, fldPath.Child("cinder"))...)
  532. }
  533. }
  534. if source.CephFS != nil {
  535. if numVolumes > 0 {
  536. allErrs = append(allErrs, field.Forbidden(fldPath.Child("cephFS"), "may not specify more than 1 volume type"))
  537. } else {
  538. numVolumes++
  539. allErrs = append(allErrs, validateCephFSVolumeSource(source.CephFS, fldPath.Child("cephfs"))...)
  540. }
  541. }
  542. if source.Quobyte != nil {
  543. if numVolumes > 0 {
  544. allErrs = append(allErrs, field.Forbidden(fldPath.Child("quobyte"), "may not specify more than 1 volume type"))
  545. } else {
  546. numVolumes++
  547. allErrs = append(allErrs, validateQuobyteVolumeSource(source.Quobyte, fldPath.Child("quobyte"))...)
  548. }
  549. }
  550. if source.DownwardAPI != nil {
  551. if numVolumes > 0 {
  552. allErrs = append(allErrs, field.Forbidden(fldPath.Child("downwarAPI"), "may not specify more than 1 volume type"))
  553. } else {
  554. numVolumes++
  555. allErrs = append(allErrs, validateDownwardAPIVolumeSource(source.DownwardAPI, fldPath.Child("downwardAPI"))...)
  556. }
  557. }
  558. if source.FC != nil {
  559. if numVolumes > 0 {
  560. allErrs = append(allErrs, field.Forbidden(fldPath.Child("fc"), "may not specify more than 1 volume type"))
  561. } else {
  562. numVolumes++
  563. allErrs = append(allErrs, validateFCVolumeSource(source.FC, fldPath.Child("fc"))...)
  564. }
  565. }
  566. if source.FlexVolume != nil {
  567. if numVolumes > 0 {
  568. allErrs = append(allErrs, field.Forbidden(fldPath.Child("flexVolume"), "may not specify more than 1 volume type"))
  569. } else {
  570. numVolumes++
  571. allErrs = append(allErrs, validateFlexVolumeSource(source.FlexVolume, fldPath.Child("flexVolume"))...)
  572. }
  573. }
  574. if source.ConfigMap != nil {
  575. if numVolumes > 0 {
  576. allErrs = append(allErrs, field.Forbidden(fldPath.Child("configMap"), "may not specify more than 1 volume type"))
  577. } else {
  578. numVolumes++
  579. allErrs = append(allErrs, validateConfigMapVolumeSource(source.ConfigMap, fldPath.Child("configMap"))...)
  580. }
  581. }
  582. if source.AzureFile != nil {
  583. numVolumes++
  584. allErrs = append(allErrs, validateAzureFile(source.AzureFile, fldPath.Child("azureFile"))...)
  585. }
  586. if source.VsphereVolume != nil {
  587. if numVolumes > 0 {
  588. allErrs = append(allErrs, field.Forbidden(fldPath.Child("vsphereVolume"), "may not specify more than 1 volume type"))
  589. } else {
  590. numVolumes++
  591. allErrs = append(allErrs, validateVsphereVolumeSource(source.VsphereVolume, fldPath.Child("vsphereVolume"))...)
  592. }
  593. }
  594. if source.AzureDisk != nil {
  595. numVolumes++
  596. allErrs = append(allErrs, validateAzureDisk(source.AzureDisk, fldPath.Child("azureDisk"))...)
  597. }
  598. if numVolumes == 0 {
  599. allErrs = append(allErrs, field.Required(fldPath, "must specify a volume type"))
  600. }
  601. return allErrs
  602. }
  603. func validateHostPathVolumeSource(hostPath *api.HostPathVolumeSource, fldPath *field.Path) field.ErrorList {
  604. allErrs := field.ErrorList{}
  605. if len(hostPath.Path) == 0 {
  606. allErrs = append(allErrs, field.Required(fldPath.Child("path"), ""))
  607. }
  608. return allErrs
  609. }
  610. func validateGitRepoVolumeSource(gitRepo *api.GitRepoVolumeSource, fldPath *field.Path) field.ErrorList {
  611. allErrs := field.ErrorList{}
  612. if len(gitRepo.Repository) == 0 {
  613. allErrs = append(allErrs, field.Required(fldPath.Child("repository"), ""))
  614. }
  615. pathErrs := validateLocalDescendingPath(gitRepo.Directory, fldPath.Child("directory"))
  616. allErrs = append(allErrs, pathErrs...)
  617. return allErrs
  618. }
  619. func validateISCSIVolumeSource(iscsi *api.ISCSIVolumeSource, fldPath *field.Path) field.ErrorList {
  620. allErrs := field.ErrorList{}
  621. if len(iscsi.TargetPortal) == 0 {
  622. allErrs = append(allErrs, field.Required(fldPath.Child("targetPortal"), ""))
  623. }
  624. if len(iscsi.IQN) == 0 {
  625. allErrs = append(allErrs, field.Required(fldPath.Child("iqn"), ""))
  626. }
  627. if iscsi.Lun < 0 || iscsi.Lun > 255 {
  628. allErrs = append(allErrs, field.Invalid(fldPath.Child("lun"), iscsi.Lun, validation.InclusiveRangeError(0, 255)))
  629. }
  630. return allErrs
  631. }
  632. func validateFCVolumeSource(fc *api.FCVolumeSource, fldPath *field.Path) field.ErrorList {
  633. allErrs := field.ErrorList{}
  634. if len(fc.TargetWWNs) < 1 {
  635. allErrs = append(allErrs, field.Required(fldPath.Child("targetWWNs"), ""))
  636. }
  637. if fc.Lun == nil {
  638. allErrs = append(allErrs, field.Required(fldPath.Child("lun"), ""))
  639. } else {
  640. if *fc.Lun < 0 || *fc.Lun > 255 {
  641. allErrs = append(allErrs, field.Invalid(fldPath.Child("lun"), fc.Lun, validation.InclusiveRangeError(0, 255)))
  642. }
  643. }
  644. return allErrs
  645. }
  646. func validateGCEPersistentDiskVolumeSource(pd *api.GCEPersistentDiskVolumeSource, fldPath *field.Path) field.ErrorList {
  647. allErrs := field.ErrorList{}
  648. if len(pd.PDName) == 0 {
  649. allErrs = append(allErrs, field.Required(fldPath.Child("pdName"), ""))
  650. }
  651. if pd.Partition < 0 || pd.Partition > 255 {
  652. allErrs = append(allErrs, field.Invalid(fldPath.Child("partition"), pd.Partition, pdPartitionErrorMsg))
  653. }
  654. return allErrs
  655. }
  656. func validateAWSElasticBlockStoreVolumeSource(PD *api.AWSElasticBlockStoreVolumeSource, fldPath *field.Path) field.ErrorList {
  657. allErrs := field.ErrorList{}
  658. if len(PD.VolumeID) == 0 {
  659. allErrs = append(allErrs, field.Required(fldPath.Child("volumeID"), ""))
  660. }
  661. if PD.Partition < 0 || PD.Partition > 255 {
  662. allErrs = append(allErrs, field.Invalid(fldPath.Child("partition"), PD.Partition, pdPartitionErrorMsg))
  663. }
  664. return allErrs
  665. }
  666. func validateSecretVolumeSource(secretSource *api.SecretVolumeSource, fldPath *field.Path) field.ErrorList {
  667. allErrs := field.ErrorList{}
  668. if len(secretSource.SecretName) == 0 {
  669. allErrs = append(allErrs, field.Required(fldPath.Child("secretName"), ""))
  670. }
  671. secretMode := secretSource.DefaultMode
  672. if secretMode != nil && (*secretMode > 0777 || *secretMode < 0) {
  673. allErrs = append(allErrs, field.Invalid(fldPath.Child("defaultMode"), *secretMode, volumeModeErrorMsg))
  674. }
  675. itemsPath := fldPath.Child("items")
  676. for i, kp := range secretSource.Items {
  677. itemPath := itemsPath.Index(i)
  678. allErrs = append(allErrs, validateKeyToPath(&kp, itemPath)...)
  679. }
  680. return allErrs
  681. }
  682. func validateConfigMapVolumeSource(configMapSource *api.ConfigMapVolumeSource, fldPath *field.Path) field.ErrorList {
  683. allErrs := field.ErrorList{}
  684. if len(configMapSource.Name) == 0 {
  685. allErrs = append(allErrs, field.Required(fldPath.Child("name"), ""))
  686. }
  687. configMapMode := configMapSource.DefaultMode
  688. if configMapMode != nil && (*configMapMode > 0777 || *configMapMode < 0) {
  689. allErrs = append(allErrs, field.Invalid(fldPath.Child("defaultMode"), *configMapMode, volumeModeErrorMsg))
  690. }
  691. itemsPath := fldPath.Child("items")
  692. for i, kp := range configMapSource.Items {
  693. itemPath := itemsPath.Index(i)
  694. allErrs = append(allErrs, validateKeyToPath(&kp, itemPath)...)
  695. }
  696. return allErrs
  697. }
  698. func validateKeyToPath(kp *api.KeyToPath, fldPath *field.Path) field.ErrorList {
  699. allErrs := field.ErrorList{}
  700. if len(kp.Key) == 0 {
  701. allErrs = append(allErrs, field.Required(fldPath.Child("key"), ""))
  702. }
  703. if len(kp.Path) == 0 {
  704. allErrs = append(allErrs, field.Required(fldPath.Child("path"), ""))
  705. }
  706. allErrs = append(allErrs, validateLocalNonReservedPath(kp.Path, fldPath.Child("path"))...)
  707. if kp.Mode != nil && (*kp.Mode > 0777 || *kp.Mode < 0) {
  708. allErrs = append(allErrs, field.Invalid(fldPath.Child("mode"), *kp.Mode, volumeModeErrorMsg))
  709. }
  710. return allErrs
  711. }
  712. func validatePersistentClaimVolumeSource(claim *api.PersistentVolumeClaimVolumeSource, fldPath *field.Path) field.ErrorList {
  713. allErrs := field.ErrorList{}
  714. if len(claim.ClaimName) == 0 {
  715. allErrs = append(allErrs, field.Required(fldPath.Child("claimName"), ""))
  716. }
  717. return allErrs
  718. }
  719. func validateNFSVolumeSource(nfs *api.NFSVolumeSource, fldPath *field.Path) field.ErrorList {
  720. allErrs := field.ErrorList{}
  721. if len(nfs.Server) == 0 {
  722. allErrs = append(allErrs, field.Required(fldPath.Child("server"), ""))
  723. }
  724. if len(nfs.Path) == 0 {
  725. allErrs = append(allErrs, field.Required(fldPath.Child("path"), ""))
  726. }
  727. if !path.IsAbs(nfs.Path) {
  728. allErrs = append(allErrs, field.Invalid(fldPath.Child("path"), nfs.Path, "must be an absolute path"))
  729. }
  730. return allErrs
  731. }
  732. func validateQuobyteVolumeSource(quobyte *api.QuobyteVolumeSource, fldPath *field.Path) field.ErrorList {
  733. allErrs := field.ErrorList{}
  734. if len(quobyte.Registry) == 0 {
  735. allErrs = append(allErrs, field.Required(fldPath.Child("registry"), "must be a host:port pair or multiple pairs separated by commas"))
  736. } else {
  737. for _, hostPortPair := range strings.Split(quobyte.Registry, ",") {
  738. if _, _, err := net.SplitHostPort(hostPortPair); err != nil {
  739. allErrs = append(allErrs, field.Invalid(fldPath.Child("registry"), quobyte.Registry, "must be a host:port pair or multiple pairs separated by commas"))
  740. }
  741. }
  742. }
  743. if len(quobyte.Volume) == 0 {
  744. allErrs = append(allErrs, field.Required(fldPath.Child("volume"), ""))
  745. }
  746. return allErrs
  747. }
  748. func validateGlusterfs(glusterfs *api.GlusterfsVolumeSource, fldPath *field.Path) field.ErrorList {
  749. allErrs := field.ErrorList{}
  750. if len(glusterfs.EndpointsName) == 0 {
  751. allErrs = append(allErrs, field.Required(fldPath.Child("endpoints"), ""))
  752. }
  753. if len(glusterfs.Path) == 0 {
  754. allErrs = append(allErrs, field.Required(fldPath.Child("path"), ""))
  755. }
  756. return allErrs
  757. }
  758. func validateFlockerVolumeSource(flocker *api.FlockerVolumeSource, fldPath *field.Path) field.ErrorList {
  759. allErrs := field.ErrorList{}
  760. if len(flocker.DatasetName) == 0 {
  761. allErrs = append(allErrs, field.Required(fldPath.Child("datasetName"), ""))
  762. }
  763. if strings.Contains(flocker.DatasetName, "/") {
  764. allErrs = append(allErrs, field.Invalid(fldPath.Child("datasetName"), flocker.DatasetName, "must not contain '/'"))
  765. }
  766. return allErrs
  767. }
  768. var validDownwardAPIFieldPathExpressions = sets.NewString(
  769. "metadata.name",
  770. "metadata.namespace",
  771. "metadata.labels",
  772. "metadata.annotations")
  773. func validateDownwardAPIVolumeSource(downwardAPIVolume *api.DownwardAPIVolumeSource, fldPath *field.Path) field.ErrorList {
  774. allErrs := field.ErrorList{}
  775. downwardAPIMode := downwardAPIVolume.DefaultMode
  776. if downwardAPIMode != nil && (*downwardAPIMode > 0777 || *downwardAPIMode < 0) {
  777. allErrs = append(allErrs, field.Invalid(fldPath.Child("defaultMode"), *downwardAPIMode, volumeModeErrorMsg))
  778. }
  779. for _, file := range downwardAPIVolume.Items {
  780. if len(file.Path) == 0 {
  781. allErrs = append(allErrs, field.Required(fldPath.Child("path"), ""))
  782. }
  783. allErrs = append(allErrs, validateLocalNonReservedPath(file.Path, fldPath.Child("path"))...)
  784. if file.FieldRef != nil {
  785. allErrs = append(allErrs, validateObjectFieldSelector(file.FieldRef, &validDownwardAPIFieldPathExpressions, fldPath.Child("fieldRef"))...)
  786. if file.ResourceFieldRef != nil {
  787. allErrs = append(allErrs, field.Invalid(fldPath, "resource", "fieldRef and resourceFieldRef can not be specified simultaneously"))
  788. }
  789. } else if file.ResourceFieldRef != nil {
  790. allErrs = append(allErrs, validateContainerResourceFieldSelector(file.ResourceFieldRef, &validContainerResourceFieldPathExpressions, fldPath.Child("resourceFieldRef"), true)...)
  791. } else {
  792. allErrs = append(allErrs, field.Required(fldPath, "one of fieldRef and resourceFieldRef is required"))
  793. }
  794. if file.Mode != nil && (*file.Mode > 0777 || *file.Mode < 0) {
  795. allErrs = append(allErrs, field.Invalid(fldPath.Child("mode"), *file.Mode, volumeModeErrorMsg))
  796. }
  797. }
  798. return allErrs
  799. }
  800. // This validate will make sure targetPath:
  801. // 1. is not abs path
  802. // 2. does not have any element which is ".."
  803. func validateLocalDescendingPath(targetPath string, fldPath *field.Path) field.ErrorList {
  804. allErrs := field.ErrorList{}
  805. if path.IsAbs(targetPath) {
  806. allErrs = append(allErrs, field.Invalid(fldPath, targetPath, "must be a relative path"))
  807. }
  808. // TODO: this assumes the OS of apiserver & nodes are the same
  809. parts := strings.Split(targetPath, string(os.PathSeparator))
  810. for _, item := range parts {
  811. if item == ".." {
  812. allErrs = append(allErrs, field.Invalid(fldPath, targetPath, "must not contain '..'"))
  813. break // even for `../../..`, one error is sufficient to make the point
  814. }
  815. }
  816. return allErrs
  817. }
  818. // This validate will make sure targetPath:
  819. // 1. is not abs path
  820. // 2. does not contain any '..' elements
  821. // 3. does not start with '..'
  822. func validateLocalNonReservedPath(targetPath string, fldPath *field.Path) field.ErrorList {
  823. allErrs := field.ErrorList{}
  824. allErrs = append(allErrs, validateLocalDescendingPath(targetPath, fldPath)...)
  825. // Don't report this error if the check for .. elements already caught it.
  826. if strings.HasPrefix(targetPath, "..") && !strings.HasPrefix(targetPath, "../") {
  827. allErrs = append(allErrs, field.Invalid(fldPath, targetPath, "must not start with '..'"))
  828. }
  829. return allErrs
  830. }
  831. func validateRBDVolumeSource(rbd *api.RBDVolumeSource, fldPath *field.Path) field.ErrorList {
  832. allErrs := field.ErrorList{}
  833. if len(rbd.CephMonitors) == 0 {
  834. allErrs = append(allErrs, field.Required(fldPath.Child("monitors"), ""))
  835. }
  836. if len(rbd.RBDImage) == 0 {
  837. allErrs = append(allErrs, field.Required(fldPath.Child("image"), ""))
  838. }
  839. return allErrs
  840. }
  841. func validateCinderVolumeSource(cd *api.CinderVolumeSource, fldPath *field.Path) field.ErrorList {
  842. allErrs := field.ErrorList{}
  843. if len(cd.VolumeID) == 0 {
  844. allErrs = append(allErrs, field.Required(fldPath.Child("volumeID"), ""))
  845. }
  846. return allErrs
  847. }
  848. func validateCephFSVolumeSource(cephfs *api.CephFSVolumeSource, fldPath *field.Path) field.ErrorList {
  849. allErrs := field.ErrorList{}
  850. if len(cephfs.Monitors) == 0 {
  851. allErrs = append(allErrs, field.Required(fldPath.Child("monitors"), ""))
  852. }
  853. return allErrs
  854. }
  855. func validateFlexVolumeSource(fv *api.FlexVolumeSource, fldPath *field.Path) field.ErrorList {
  856. allErrs := field.ErrorList{}
  857. if len(fv.Driver) == 0 {
  858. allErrs = append(allErrs, field.Required(fldPath.Child("driver"), ""))
  859. }
  860. return allErrs
  861. }
  862. func validateAzureFile(azure *api.AzureFileVolumeSource, fldPath *field.Path) field.ErrorList {
  863. allErrs := field.ErrorList{}
  864. if azure.SecretName == "" {
  865. allErrs = append(allErrs, field.Required(fldPath.Child("secretName"), ""))
  866. }
  867. if azure.ShareName == "" {
  868. allErrs = append(allErrs, field.Required(fldPath.Child("shareName"), ""))
  869. }
  870. return allErrs
  871. }
  872. var supportedCachingModes = sets.NewString(string(api.AzureDataDiskCachingNone), string(api.AzureDataDiskCachingReadOnly), string(api.AzureDataDiskCachingReadWrite))
  873. func validateAzureDisk(azure *api.AzureDiskVolumeSource, fldPath *field.Path) field.ErrorList {
  874. allErrs := field.ErrorList{}
  875. if azure.DiskName == "" {
  876. allErrs = append(allErrs, field.Required(fldPath.Child("diskName"), ""))
  877. }
  878. if azure.DataDiskURI == "" {
  879. allErrs = append(allErrs, field.Required(fldPath.Child("diskURI"), ""))
  880. }
  881. if azure.CachingMode != nil && !supportedCachingModes.Has(string(*azure.CachingMode)) {
  882. allErrs = append(allErrs, field.NotSupported(fldPath.Child("cachingMode"), *azure.CachingMode, supportedCachingModes.List()))
  883. }
  884. return allErrs
  885. }
  886. func validateVsphereVolumeSource(cd *api.VsphereVirtualDiskVolumeSource, fldPath *field.Path) field.ErrorList {
  887. allErrs := field.ErrorList{}
  888. if len(cd.VolumePath) == 0 {
  889. allErrs = append(allErrs, field.Required(fldPath.Child("volumePath"), ""))
  890. }
  891. return allErrs
  892. }
  893. // ValidatePersistentVolumeName checks that a name is appropriate for a
  894. // PersistentVolumeName object.
  895. var ValidatePersistentVolumeName = NameIsDNSSubdomain
  896. var supportedAccessModes = sets.NewString(string(api.ReadWriteOnce), string(api.ReadOnlyMany), string(api.ReadWriteMany))
  897. var supportedReclaimPolicy = sets.NewString(string(api.PersistentVolumeReclaimDelete), string(api.PersistentVolumeReclaimRecycle), string(api.PersistentVolumeReclaimRetain))
  898. func ValidatePersistentVolume(pv *api.PersistentVolume) field.ErrorList {
  899. allErrs := ValidateObjectMeta(&pv.ObjectMeta, false, ValidatePersistentVolumeName, field.NewPath("metadata"))
  900. specPath := field.NewPath("spec")
  901. if len(pv.Spec.AccessModes) == 0 {
  902. allErrs = append(allErrs, field.Required(specPath.Child("accessModes"), ""))
  903. }
  904. for _, mode := range pv.Spec.AccessModes {
  905. if !supportedAccessModes.Has(string(mode)) {
  906. allErrs = append(allErrs, field.NotSupported(specPath.Child("accessModes"), mode, supportedAccessModes.List()))
  907. }
  908. }
  909. if len(pv.Spec.Capacity) == 0 {
  910. allErrs = append(allErrs, field.Required(specPath.Child("capacity"), ""))
  911. }
  912. if _, ok := pv.Spec.Capacity[api.ResourceStorage]; !ok || len(pv.Spec.Capacity) > 1 {
  913. allErrs = append(allErrs, field.NotSupported(specPath.Child("capacity"), pv.Spec.Capacity, []string{string(api.ResourceStorage)}))
  914. }
  915. capPath := specPath.Child("capacity")
  916. for r, qty := range pv.Spec.Capacity {
  917. allErrs = append(allErrs, validateBasicResource(qty, capPath.Key(string(r)))...)
  918. }
  919. if len(string(pv.Spec.PersistentVolumeReclaimPolicy)) > 0 {
  920. if !supportedReclaimPolicy.Has(string(pv.Spec.PersistentVolumeReclaimPolicy)) {
  921. allErrs = append(allErrs, field.NotSupported(specPath.Child("persistentVolumeReclaimPolicy"), pv.Spec.PersistentVolumeReclaimPolicy, supportedReclaimPolicy.List()))
  922. }
  923. }
  924. numVolumes := 0
  925. if pv.Spec.HostPath != nil {
  926. if numVolumes > 0 {
  927. allErrs = append(allErrs, field.Forbidden(specPath.Child("hostPath"), "may not specify more than 1 volume type"))
  928. } else {
  929. numVolumes++
  930. allErrs = append(allErrs, validateHostPathVolumeSource(pv.Spec.HostPath, specPath.Child("hostPath"))...)
  931. }
  932. }
  933. if pv.Spec.GCEPersistentDisk != nil {
  934. if numVolumes > 0 {
  935. allErrs = append(allErrs, field.Forbidden(specPath.Child("gcePersistentDisk"), "may not specify more than 1 volume type"))
  936. } else {
  937. numVolumes++
  938. allErrs = append(allErrs, validateGCEPersistentDiskVolumeSource(pv.Spec.GCEPersistentDisk, specPath.Child("persistentDisk"))...)
  939. }
  940. }
  941. if pv.Spec.AWSElasticBlockStore != nil {
  942. if numVolumes > 0 {
  943. allErrs = append(allErrs, field.Forbidden(specPath.Child("awsElasticBlockStore"), "may not specify more than 1 volume type"))
  944. } else {
  945. numVolumes++
  946. allErrs = append(allErrs, validateAWSElasticBlockStoreVolumeSource(pv.Spec.AWSElasticBlockStore, specPath.Child("awsElasticBlockStore"))...)
  947. }
  948. }
  949. if pv.Spec.Glusterfs != nil {
  950. if numVolumes > 0 {
  951. allErrs = append(allErrs, field.Forbidden(specPath.Child("glusterfs"), "may not specify more than 1 volume type"))
  952. } else {
  953. numVolumes++
  954. allErrs = append(allErrs, validateGlusterfs(pv.Spec.Glusterfs, specPath.Child("glusterfs"))...)
  955. }
  956. }
  957. if pv.Spec.Flocker != nil {
  958. if numVolumes > 0 {
  959. allErrs = append(allErrs, field.Forbidden(specPath.Child("flocker"), "may not specify more than 1 volume type"))
  960. } else {
  961. numVolumes++
  962. allErrs = append(allErrs, validateFlockerVolumeSource(pv.Spec.Flocker, specPath.Child("flocker"))...)
  963. }
  964. }
  965. if pv.Spec.NFS != nil {
  966. if numVolumes > 0 {
  967. allErrs = append(allErrs, field.Forbidden(specPath.Child("nfs"), "may not specify more than 1 volume type"))
  968. } else {
  969. numVolumes++
  970. allErrs = append(allErrs, validateNFSVolumeSource(pv.Spec.NFS, specPath.Child("nfs"))...)
  971. }
  972. }
  973. if pv.Spec.RBD != nil {
  974. if numVolumes > 0 {
  975. allErrs = append(allErrs, field.Forbidden(specPath.Child("rbd"), "may not specify more than 1 volume type"))
  976. } else {
  977. numVolumes++
  978. allErrs = append(allErrs, validateRBDVolumeSource(pv.Spec.RBD, specPath.Child("rbd"))...)
  979. }
  980. }
  981. if pv.Spec.Quobyte != nil {
  982. if numVolumes > 0 {
  983. allErrs = append(allErrs, field.Forbidden(specPath.Child("quobyte"), "may not specify more than 1 volume type"))
  984. } else {
  985. numVolumes++
  986. allErrs = append(allErrs, validateQuobyteVolumeSource(pv.Spec.Quobyte, specPath.Child("quobyte"))...)
  987. }
  988. }
  989. if pv.Spec.CephFS != nil {
  990. if numVolumes > 0 {
  991. allErrs = append(allErrs, field.Forbidden(specPath.Child("cephFS"), "may not specify more than 1 volume type"))
  992. } else {
  993. numVolumes++
  994. allErrs = append(allErrs, validateCephFSVolumeSource(pv.Spec.CephFS, specPath.Child("cephfs"))...)
  995. }
  996. }
  997. if pv.Spec.ISCSI != nil {
  998. if numVolumes > 0 {
  999. allErrs = append(allErrs, field.Forbidden(specPath.Child("iscsi"), "may not specify more than 1 volume type"))
  1000. } else {
  1001. numVolumes++
  1002. allErrs = append(allErrs, validateISCSIVolumeSource(pv.Spec.ISCSI, specPath.Child("iscsi"))...)
  1003. }
  1004. }
  1005. if pv.Spec.Cinder != nil {
  1006. if numVolumes > 0 {
  1007. allErrs = append(allErrs, field.Forbidden(specPath.Child("cinder"), "may not specify more than 1 volume type"))
  1008. } else {
  1009. numVolumes++
  1010. allErrs = append(allErrs, validateCinderVolumeSource(pv.Spec.Cinder, specPath.Child("cinder"))...)
  1011. }
  1012. }
  1013. if pv.Spec.FC != nil {
  1014. if numVolumes > 0 {
  1015. allErrs = append(allErrs, field.Forbidden(specPath.Child("fc"), "may not specify more than 1 volume type"))
  1016. } else {
  1017. numVolumes++
  1018. allErrs = append(allErrs, validateFCVolumeSource(pv.Spec.FC, specPath.Child("fc"))...)
  1019. }
  1020. }
  1021. if pv.Spec.FlexVolume != nil {
  1022. numVolumes++
  1023. allErrs = append(allErrs, validateFlexVolumeSource(pv.Spec.FlexVolume, specPath.Child("flexVolume"))...)
  1024. }
  1025. if pv.Spec.AzureFile != nil {
  1026. numVolumes++
  1027. allErrs = append(allErrs, validateAzureFile(pv.Spec.AzureFile, specPath.Child("azureFile"))...)
  1028. }
  1029. if pv.Spec.VsphereVolume != nil {
  1030. if numVolumes > 0 {
  1031. allErrs = append(allErrs, field.Forbidden(specPath.Child("vsphereVolume"), "may not specify more than 1 volume type"))
  1032. } else {
  1033. numVolumes++
  1034. allErrs = append(allErrs, validateVsphereVolumeSource(pv.Spec.VsphereVolume, specPath.Child("vsphereVolume"))...)
  1035. }
  1036. }
  1037. if pv.Spec.AzureDisk != nil {
  1038. numVolumes++
  1039. allErrs = append(allErrs, validateAzureDisk(pv.Spec.AzureDisk, specPath.Child("azureDisk"))...)
  1040. }
  1041. if numVolumes == 0 {
  1042. allErrs = append(allErrs, field.Required(specPath, "must specify a volume type"))
  1043. }
  1044. // do not allow hostPath mounts of '/' to have a 'recycle' reclaim policy
  1045. if pv.Spec.HostPath != nil && path.Clean(pv.Spec.HostPath.Path) == "/" && pv.Spec.PersistentVolumeReclaimPolicy == api.PersistentVolumeReclaimRecycle {
  1046. allErrs = append(allErrs, field.Forbidden(specPath.Child("persistentVolumeReclaimPolicy"), "may not be 'recycle' for a hostPath mount of '/'"))
  1047. }
  1048. return allErrs
  1049. }
  1050. // ValidatePersistentVolumeUpdate tests to see if the update is legal for an end user to make.
  1051. // newPv is updated with fields that cannot be changed.
  1052. func ValidatePersistentVolumeUpdate(newPv, oldPv *api.PersistentVolume) field.ErrorList {
  1053. allErrs := field.ErrorList{}
  1054. allErrs = ValidatePersistentVolume(newPv)
  1055. newPv.Status = oldPv.Status
  1056. return allErrs
  1057. }
  1058. // ValidatePersistentVolumeStatusUpdate tests to see if the status update is legal for an end user to make.
  1059. // newPv is updated with fields that cannot be changed.
  1060. func ValidatePersistentVolumeStatusUpdate(newPv, oldPv *api.PersistentVolume) field.ErrorList {
  1061. allErrs := ValidateObjectMetaUpdate(&newPv.ObjectMeta, &oldPv.ObjectMeta, field.NewPath("metadata"))
  1062. if len(newPv.ResourceVersion) == 0 {
  1063. allErrs = append(allErrs, field.Required(field.NewPath("resourceVersion"), ""))
  1064. }
  1065. newPv.Spec = oldPv.Spec
  1066. return allErrs
  1067. }
  1068. // ValidatePersistentVolumeClaim validates a PersistentVolumeClaim
  1069. func ValidatePersistentVolumeClaim(pvc *api.PersistentVolumeClaim) field.ErrorList {
  1070. allErrs := ValidateObjectMeta(&pvc.ObjectMeta, true, ValidatePersistentVolumeName, field.NewPath("metadata"))
  1071. allErrs = append(allErrs, ValidatePersistentVolumeClaimSpec(&pvc.Spec, field.NewPath("spec"))...)
  1072. return allErrs
  1073. }
  1074. // ValidatePersistentVolumeClaimSpec validates a PersistentVolumeClaimSpec
  1075. func ValidatePersistentVolumeClaimSpec(spec *api.PersistentVolumeClaimSpec, fldPath *field.Path) field.ErrorList {
  1076. allErrs := field.ErrorList{}
  1077. if len(spec.AccessModes) == 0 {
  1078. allErrs = append(allErrs, field.Required(fldPath.Child("accessModes"), "at least 1 access mode is required"))
  1079. }
  1080. if spec.Selector != nil {
  1081. allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(spec.Selector, fldPath.Child("selector"))...)
  1082. }
  1083. for _, mode := range spec.AccessModes {
  1084. if mode != api.ReadWriteOnce && mode != api.ReadOnlyMany && mode != api.ReadWriteMany {
  1085. allErrs = append(allErrs, field.NotSupported(fldPath.Child("accessModes"), mode, supportedAccessModes.List()))
  1086. }
  1087. }
  1088. storageValue, ok := spec.Resources.Requests[api.ResourceStorage]
  1089. if !ok {
  1090. allErrs = append(allErrs, field.Required(fldPath.Child("resources").Key(string(api.ResourceStorage)), ""))
  1091. } else {
  1092. allErrs = append(allErrs, ValidateResourceQuantityValue(string(api.ResourceStorage), storageValue, fldPath.Child("resources").Key(string(api.ResourceStorage)))...)
  1093. }
  1094. return allErrs
  1095. }
  1096. // ValidatePersistentVolumeClaimUpdate validates an update to a PeristentVolumeClaim
  1097. func ValidatePersistentVolumeClaimUpdate(newPvc, oldPvc *api.PersistentVolumeClaim) field.ErrorList {
  1098. allErrs := ValidateObjectMetaUpdate(&newPvc.ObjectMeta, &oldPvc.ObjectMeta, field.NewPath("metadata"))
  1099. allErrs = append(allErrs, ValidatePersistentVolumeClaim(newPvc)...)
  1100. // PVController needs to update PVC.Spec w/ VolumeName.
  1101. // Claims are immutable in order to enforce quota, range limits, etc. without gaming the system.
  1102. if len(oldPvc.Spec.VolumeName) == 0 {
  1103. // volumeName changes are allowed once.
  1104. // Reset back to empty string after equality check
  1105. oldPvc.Spec.VolumeName = newPvc.Spec.VolumeName
  1106. defer func() { oldPvc.Spec.VolumeName = "" }()
  1107. }
  1108. // changes to Spec are not allowed, but updates to label/annotations are OK.
  1109. // no-op updates pass validation.
  1110. if !api.Semantic.DeepEqual(newPvc.Spec, oldPvc.Spec) {
  1111. allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "field is immutable after creation"))
  1112. }
  1113. newPvc.Status = oldPvc.Status
  1114. return allErrs
  1115. }
  1116. // ValidatePersistentVolumeClaimStatusUpdate validates an update to status of a PeristentVolumeClaim
  1117. func ValidatePersistentVolumeClaimStatusUpdate(newPvc, oldPvc *api.PersistentVolumeClaim) field.ErrorList {
  1118. allErrs := ValidateObjectMetaUpdate(&newPvc.ObjectMeta, &oldPvc.ObjectMeta, field.NewPath("metadata"))
  1119. if len(newPvc.ResourceVersion) == 0 {
  1120. allErrs = append(allErrs, field.Required(field.NewPath("resourceVersion"), ""))
  1121. }
  1122. if len(newPvc.Spec.AccessModes) == 0 {
  1123. allErrs = append(allErrs, field.Required(field.NewPath("Spec", "accessModes"), ""))
  1124. }
  1125. capPath := field.NewPath("status", "capacity")
  1126. for r, qty := range newPvc.Status.Capacity {
  1127. allErrs = append(allErrs, validateBasicResource(qty, capPath.Key(string(r)))...)
  1128. }
  1129. newPvc.Spec = oldPvc.Spec
  1130. return allErrs
  1131. }
  1132. var supportedPortProtocols = sets.NewString(string(api.ProtocolTCP), string(api.ProtocolUDP))
  1133. func validateContainerPorts(ports []api.ContainerPort, fldPath *field.Path) field.ErrorList {
  1134. allErrs := field.ErrorList{}
  1135. allNames := sets.String{}
  1136. for i, port := range ports {
  1137. idxPath := fldPath.Index(i)
  1138. if len(port.Name) > 0 {
  1139. if msgs := validation.IsValidPortName(port.Name); len(msgs) != 0 {
  1140. for i = range msgs {
  1141. allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), port.Name, msgs[i]))
  1142. }
  1143. } else if allNames.Has(port.Name) {
  1144. allErrs = append(allErrs, field.Duplicate(idxPath.Child("name"), port.Name))
  1145. } else {
  1146. allNames.Insert(port.Name)
  1147. }
  1148. }
  1149. if port.ContainerPort == 0 {
  1150. allErrs = append(allErrs, field.Required(idxPath.Child("containerPort"), ""))
  1151. } else {
  1152. for _, msg := range validation.IsValidPortNum(int(port.ContainerPort)) {
  1153. allErrs = append(allErrs, field.Invalid(idxPath.Child("containerPort"), port.ContainerPort, msg))
  1154. }
  1155. }
  1156. if port.HostPort != 0 {
  1157. for _, msg := range validation.IsValidPortNum(int(port.HostPort)) {
  1158. allErrs = append(allErrs, field.Invalid(idxPath.Child("hostPort"), port.HostPort, msg))
  1159. }
  1160. }
  1161. if len(port.Protocol) == 0 {
  1162. allErrs = append(allErrs, field.Required(idxPath.Child("protocol"), ""))
  1163. } else if !supportedPortProtocols.Has(string(port.Protocol)) {
  1164. allErrs = append(allErrs, field.NotSupported(idxPath.Child("protocol"), port.Protocol, supportedPortProtocols.List()))
  1165. }
  1166. }
  1167. return allErrs
  1168. }
  1169. func validateEnv(vars []api.EnvVar, fldPath *field.Path) field.ErrorList {
  1170. allErrs := field.ErrorList{}
  1171. for i, ev := range vars {
  1172. idxPath := fldPath.Index(i)
  1173. if len(ev.Name) == 0 {
  1174. allErrs = append(allErrs, field.Required(idxPath.Child("name"), ""))
  1175. } else {
  1176. for _, msg := range validation.IsCIdentifier(ev.Name) {
  1177. allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), ev.Name, msg))
  1178. }
  1179. }
  1180. allErrs = append(allErrs, validateEnvVarValueFrom(ev, idxPath.Child("valueFrom"))...)
  1181. }
  1182. return allErrs
  1183. }
  1184. var validFieldPathExpressionsEnv = sets.NewString("metadata.name", "metadata.namespace", "spec.nodeName", "spec.serviceAccountName", "status.podIP")
  1185. var validContainerResourceFieldPathExpressions = sets.NewString("limits.cpu", "limits.memory", "requests.cpu", "requests.memory")
  1186. func validateEnvVarValueFrom(ev api.EnvVar, fldPath *field.Path) field.ErrorList {
  1187. allErrs := field.ErrorList{}
  1188. if ev.ValueFrom == nil {
  1189. return allErrs
  1190. }
  1191. numSources := 0
  1192. if ev.ValueFrom.FieldRef != nil {
  1193. numSources++
  1194. allErrs = append(allErrs, validateObjectFieldSelector(ev.ValueFrom.FieldRef, &validFieldPathExpressionsEnv, fldPath.Child("fieldRef"))...)
  1195. }
  1196. if ev.ValueFrom.ResourceFieldRef != nil {
  1197. numSources++
  1198. allErrs = append(allErrs, validateContainerResourceFieldSelector(ev.ValueFrom.ResourceFieldRef, &validContainerResourceFieldPathExpressions, fldPath.Child("resourceFieldRef"), false)...)
  1199. }
  1200. if ev.ValueFrom.ConfigMapKeyRef != nil {
  1201. numSources++
  1202. allErrs = append(allErrs, validateConfigMapKeySelector(ev.ValueFrom.ConfigMapKeyRef, fldPath.Child("configMapKeyRef"))...)
  1203. }
  1204. if ev.ValueFrom.SecretKeyRef != nil {
  1205. numSources++
  1206. allErrs = append(allErrs, validateSecretKeySelector(ev.ValueFrom.SecretKeyRef, fldPath.Child("secretKeyRef"))...)
  1207. }
  1208. if len(ev.Value) != 0 {
  1209. if numSources != 0 {
  1210. allErrs = append(allErrs, field.Invalid(fldPath, "", "may not be specified when `value` is not empty"))
  1211. }
  1212. } else if numSources != 1 {
  1213. allErrs = append(allErrs, field.Invalid(fldPath, "", "may not have more than one field specified at a time"))
  1214. }
  1215. return allErrs
  1216. }
  1217. func validateObjectFieldSelector(fs *api.ObjectFieldSelector, expressions *sets.String, fldPath *field.Path) field.ErrorList {
  1218. allErrs := field.ErrorList{}
  1219. if len(fs.APIVersion) == 0 {
  1220. allErrs = append(allErrs, field.Required(fldPath.Child("apiVersion"), ""))
  1221. } else if len(fs.FieldPath) == 0 {
  1222. allErrs = append(allErrs, field.Required(fldPath.Child("fieldPath"), ""))
  1223. } else {
  1224. internalFieldPath, _, err := api.Scheme.ConvertFieldLabel(fs.APIVersion, "Pod", fs.FieldPath, "")
  1225. if err != nil {
  1226. allErrs = append(allErrs, field.Invalid(fldPath.Child("fieldPath"), fs.FieldPath, fmt.Sprintf("error converting fieldPath: %v", err)))
  1227. } else if !expressions.Has(internalFieldPath) {
  1228. allErrs = append(allErrs, field.NotSupported(fldPath.Child("fieldPath"), internalFieldPath, expressions.List()))
  1229. }
  1230. }
  1231. return allErrs
  1232. }
  1233. func validateContainerResourceFieldSelector(fs *api.ResourceFieldSelector, expressions *sets.String, fldPath *field.Path, volume bool) field.ErrorList {
  1234. allErrs := field.ErrorList{}
  1235. if volume && len(fs.ContainerName) == 0 {
  1236. allErrs = append(allErrs, field.Required(fldPath.Child("containerName"), ""))
  1237. } else if len(fs.Resource) == 0 {
  1238. allErrs = append(allErrs, field.Required(fldPath.Child("resource"), ""))
  1239. } else if !expressions.Has(fs.Resource) {
  1240. allErrs = append(allErrs, field.NotSupported(fldPath.Child("resource"), fs.Resource, expressions.List()))
  1241. }
  1242. allErrs = append(allErrs, validateContainerResourceDivisor(fs.Resource, fs.Divisor, fldPath)...)
  1243. return allErrs
  1244. }
  1245. var validContainerResourceDivisorForCPU = sets.NewString("1m", "1")
  1246. var validContainerResourceDivisorForMemory = sets.NewString("1", "1k", "1M", "1G", "1T", "1P", "1E", "1Ki", "1Mi", "1Gi", "1Ti", "1Pi", "1Ei")
  1247. func validateContainerResourceDivisor(rName string, divisor resource.Quantity, fldPath *field.Path) field.ErrorList {
  1248. allErrs := field.ErrorList{}
  1249. unsetDivisor := resource.Quantity{}
  1250. if unsetDivisor.Cmp(divisor) == 0 {
  1251. return allErrs
  1252. }
  1253. switch rName {
  1254. case "limits.cpu", "requests.cpu":
  1255. if !validContainerResourceDivisorForCPU.Has(divisor.String()) {
  1256. allErrs = append(allErrs, field.Invalid(fldPath.Child("divisor"), rName, "only divisor's values 1m and 1 are supported with the cpu resource"))
  1257. }
  1258. case "limits.memory", "requests.memory":
  1259. if !validContainerResourceDivisorForMemory.Has(divisor.String()) {
  1260. 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"))
  1261. }
  1262. }
  1263. return allErrs
  1264. }
  1265. func validateConfigMapKeySelector(s *api.ConfigMapKeySelector, fldPath *field.Path) field.ErrorList {
  1266. allErrs := field.ErrorList{}
  1267. if len(s.Name) == 0 {
  1268. allErrs = append(allErrs, field.Required(fldPath.Child("name"), ""))
  1269. }
  1270. if len(s.Key) == 0 {
  1271. allErrs = append(allErrs, field.Required(fldPath.Child("key"), ""))
  1272. } else {
  1273. for _, msg := range validation.IsConfigMapKey(s.Key) {
  1274. allErrs = append(allErrs, field.Invalid(fldPath.Child("key"), s.Key, msg))
  1275. }
  1276. }
  1277. return allErrs
  1278. }
  1279. func validateSecretKeySelector(s *api.SecretKeySelector, fldPath *field.Path) field.ErrorList {
  1280. allErrs := field.ErrorList{}
  1281. if len(s.Name) == 0 {
  1282. allErrs = append(allErrs, field.Required(fldPath.Child("name"), ""))
  1283. }
  1284. if len(s.Key) == 0 {
  1285. allErrs = append(allErrs, field.Required(fldPath.Child("key"), ""))
  1286. } else {
  1287. for _, msg := range validation.IsConfigMapKey(s.Key) {
  1288. allErrs = append(allErrs, field.Invalid(fldPath.Child("key"), s.Key, msg))
  1289. }
  1290. }
  1291. return allErrs
  1292. }
  1293. func validateVolumeMounts(mounts []api.VolumeMount, volumes sets.String, fldPath *field.Path) field.ErrorList {
  1294. allErrs := field.ErrorList{}
  1295. mountpoints := sets.NewString()
  1296. for i, mnt := range mounts {
  1297. idxPath := fldPath.Index(i)
  1298. if len(mnt.Name) == 0 {
  1299. allErrs = append(allErrs, field.Required(idxPath.Child("name"), ""))
  1300. } else if !volumes.Has(mnt.Name) {
  1301. allErrs = append(allErrs, field.NotFound(idxPath.Child("name"), mnt.Name))
  1302. }
  1303. if len(mnt.MountPath) == 0 {
  1304. allErrs = append(allErrs, field.Required(idxPath.Child("mountPath"), ""))
  1305. } else if strings.Contains(mnt.MountPath, ":") {
  1306. allErrs = append(allErrs, field.Invalid(idxPath.Child("mountPath"), mnt.MountPath, "must not contain ':'"))
  1307. }
  1308. if mountpoints.Has(mnt.MountPath) {
  1309. allErrs = append(allErrs, field.Invalid(idxPath.Child("mountPath"), mnt.MountPath, "must be unique"))
  1310. }
  1311. mountpoints.Insert(mnt.MountPath)
  1312. if len(mnt.SubPath) > 0 {
  1313. allErrs = append(allErrs, validateLocalDescendingPath(mnt.SubPath, fldPath.Child("subPath"))...)
  1314. }
  1315. }
  1316. return allErrs
  1317. }
  1318. func validateProbe(probe *api.Probe, fldPath *field.Path) field.ErrorList {
  1319. allErrs := field.ErrorList{}
  1320. if probe == nil {
  1321. return allErrs
  1322. }
  1323. allErrs = append(allErrs, validateHandler(&probe.Handler, fldPath)...)
  1324. allErrs = append(allErrs, ValidateNonnegativeField(int64(probe.InitialDelaySeconds), fldPath.Child("initialDelaySeconds"))...)
  1325. allErrs = append(allErrs, ValidateNonnegativeField(int64(probe.TimeoutSeconds), fldPath.Child("timeoutSeconds"))...)
  1326. allErrs = append(allErrs, ValidateNonnegativeField(int64(probe.PeriodSeconds), fldPath.Child("periodSeconds"))...)
  1327. allErrs = append(allErrs, ValidateNonnegativeField(int64(probe.SuccessThreshold), fldPath.Child("successThreshold"))...)
  1328. allErrs = append(allErrs, ValidateNonnegativeField(int64(probe.FailureThreshold), fldPath.Child("failureThreshold"))...)
  1329. return allErrs
  1330. }
  1331. // AccumulateUniqueHostPorts extracts each HostPort of each Container,
  1332. // accumulating the results and returning an error if any ports conflict.
  1333. func AccumulateUniqueHostPorts(containers []api.Container, accumulator *sets.String, fldPath *field.Path) field.ErrorList {
  1334. allErrs := field.ErrorList{}
  1335. for ci, ctr := range containers {
  1336. idxPath := fldPath.Index(ci)
  1337. portsPath := idxPath.Child("ports")
  1338. for pi := range ctr.Ports {
  1339. idxPath := portsPath.Index(pi)
  1340. port := ctr.Ports[pi].HostPort
  1341. if port == 0 {
  1342. continue
  1343. }
  1344. str := fmt.Sprintf("%d/%s", port, ctr.Ports[pi].Protocol)
  1345. if accumulator.Has(str) {
  1346. allErrs = append(allErrs, field.Duplicate(idxPath.Child("hostPort"), str))
  1347. } else {
  1348. accumulator.Insert(str)
  1349. }
  1350. }
  1351. }
  1352. return allErrs
  1353. }
  1354. // checkHostPortConflicts checks for colliding Port.HostPort values across
  1355. // a slice of containers.
  1356. func checkHostPortConflicts(containers []api.Container, fldPath *field.Path) field.ErrorList {
  1357. allPorts := sets.String{}
  1358. return AccumulateUniqueHostPorts(containers, &allPorts, fldPath)
  1359. }
  1360. func validateExecAction(exec *api.ExecAction, fldPath *field.Path) field.ErrorList {
  1361. allErrors := field.ErrorList{}
  1362. if len(exec.Command) == 0 {
  1363. allErrors = append(allErrors, field.Required(fldPath.Child("command"), ""))
  1364. }
  1365. return allErrors
  1366. }
  1367. var supportedHTTPSchemes = sets.NewString(string(api.URISchemeHTTP), string(api.URISchemeHTTPS))
  1368. func validateHTTPGetAction(http *api.HTTPGetAction, fldPath *field.Path) field.ErrorList {
  1369. allErrors := field.ErrorList{}
  1370. if len(http.Path) == 0 {
  1371. allErrors = append(allErrors, field.Required(fldPath.Child("path"), ""))
  1372. }
  1373. allErrors = append(allErrors, ValidatePortNumOrName(http.Port, fldPath.Child("port"))...)
  1374. if !supportedHTTPSchemes.Has(string(http.Scheme)) {
  1375. allErrors = append(allErrors, field.NotSupported(fldPath.Child("scheme"), http.Scheme, supportedHTTPSchemes.List()))
  1376. }
  1377. for _, header := range http.HTTPHeaders {
  1378. for _, msg := range validation.IsHTTPHeaderName(header.Name) {
  1379. allErrors = append(allErrors, field.Invalid(fldPath.Child("httpHeaders"), header.Name, msg))
  1380. }
  1381. }
  1382. return allErrors
  1383. }
  1384. func ValidatePortNumOrName(port intstr.IntOrString, fldPath *field.Path) field.ErrorList {
  1385. allErrs := field.ErrorList{}
  1386. if port.Type == intstr.Int {
  1387. for _, msg := range validation.IsValidPortNum(port.IntValue()) {
  1388. allErrs = append(allErrs, field.Invalid(fldPath, port.IntValue(), msg))
  1389. }
  1390. } else if port.Type == intstr.String {
  1391. for _, msg := range validation.IsValidPortName(port.StrVal) {
  1392. allErrs = append(allErrs, field.Invalid(fldPath, port.StrVal, msg))
  1393. }
  1394. } else {
  1395. allErrs = append(allErrs, field.InternalError(fldPath, fmt.Errorf("unknown type: %v", port.Type)))
  1396. }
  1397. return allErrs
  1398. }
  1399. func validateTCPSocketAction(tcp *api.TCPSocketAction, fldPath *field.Path) field.ErrorList {
  1400. return ValidatePortNumOrName(tcp.Port, fldPath.Child("port"))
  1401. }
  1402. func validateHandler(handler *api.Handler, fldPath *field.Path) field.ErrorList {
  1403. numHandlers := 0
  1404. allErrors := field.ErrorList{}
  1405. if handler.Exec != nil {
  1406. if numHandlers > 0 {
  1407. allErrors = append(allErrors, field.Forbidden(fldPath.Child("exec"), "may not specify more than 1 handler type"))
  1408. } else {
  1409. numHandlers++
  1410. allErrors = append(allErrors, validateExecAction(handler.Exec, fldPath.Child("exec"))...)
  1411. }
  1412. }
  1413. if handler.HTTPGet != nil {
  1414. if numHandlers > 0 {
  1415. allErrors = append(allErrors, field.Forbidden(fldPath.Child("httpGet"), "may not specify more than 1 handler type"))
  1416. } else {
  1417. numHandlers++
  1418. allErrors = append(allErrors, validateHTTPGetAction(handler.HTTPGet, fldPath.Child("httpGet"))...)
  1419. }
  1420. }
  1421. if handler.TCPSocket != nil {
  1422. if numHandlers > 0 {
  1423. allErrors = append(allErrors, field.Forbidden(fldPath.Child("tcpSocket"), "may not specify more than 1 handler type"))
  1424. } else {
  1425. numHandlers++
  1426. allErrors = append(allErrors, validateTCPSocketAction(handler.TCPSocket, fldPath.Child("tcpSocket"))...)
  1427. }
  1428. }
  1429. if numHandlers == 0 {
  1430. allErrors = append(allErrors, field.Required(fldPath, "must specify a handler type"))
  1431. }
  1432. return allErrors
  1433. }
  1434. func validateLifecycle(lifecycle *api.Lifecycle, fldPath *field.Path) field.ErrorList {
  1435. allErrs := field.ErrorList{}
  1436. if lifecycle.PostStart != nil {
  1437. allErrs = append(allErrs, validateHandler(lifecycle.PostStart, fldPath.Child("postStart"))...)
  1438. }
  1439. if lifecycle.PreStop != nil {
  1440. allErrs = append(allErrs, validateHandler(lifecycle.PreStop, fldPath.Child("preStop"))...)
  1441. }
  1442. return allErrs
  1443. }
  1444. var supportedPullPolicies = sets.NewString(string(api.PullAlways), string(api.PullIfNotPresent), string(api.PullNever))
  1445. func validatePullPolicy(policy api.PullPolicy, fldPath *field.Path) field.ErrorList {
  1446. allErrors := field.ErrorList{}
  1447. switch policy {
  1448. case api.PullAlways, api.PullIfNotPresent, api.PullNever:
  1449. break
  1450. case "":
  1451. allErrors = append(allErrors, field.Required(fldPath, ""))
  1452. default:
  1453. allErrors = append(allErrors, field.NotSupported(fldPath, policy, supportedPullPolicies.List()))
  1454. }
  1455. return allErrors
  1456. }
  1457. func validateInitContainers(containers, otherContainers []api.Container, volumes sets.String, fldPath *field.Path) field.ErrorList {
  1458. var allErrs field.ErrorList
  1459. if len(containers) > 0 {
  1460. allErrs = append(allErrs, validateContainers(containers, volumes, fldPath)...)
  1461. }
  1462. allNames := sets.String{}
  1463. for _, ctr := range otherContainers {
  1464. allNames.Insert(ctr.Name)
  1465. }
  1466. for i, ctr := range containers {
  1467. idxPath := fldPath.Index(i)
  1468. if allNames.Has(ctr.Name) {
  1469. allErrs = append(allErrs, field.Duplicate(idxPath.Child("name"), ctr.Name))
  1470. }
  1471. if len(ctr.Name) > 0 {
  1472. allNames.Insert(ctr.Name)
  1473. }
  1474. if ctr.Lifecycle != nil {
  1475. allErrs = append(allErrs, field.Invalid(idxPath.Child("lifecycle"), ctr.Lifecycle, "must not be set for init containers"))
  1476. }
  1477. if ctr.LivenessProbe != nil {
  1478. allErrs = append(allErrs, field.Invalid(idxPath.Child("livenessProbe"), ctr.LivenessProbe, "must not be set for init containers"))
  1479. }
  1480. if ctr.ReadinessProbe != nil {
  1481. allErrs = append(allErrs, field.Invalid(idxPath.Child("readinessProbe"), ctr.ReadinessProbe, "must not be set for init containers"))
  1482. }
  1483. }
  1484. return allErrs
  1485. }
  1486. func validateContainers(containers []api.Container, volumes sets.String, fldPath *field.Path) field.ErrorList {
  1487. allErrs := field.ErrorList{}
  1488. if len(containers) == 0 {
  1489. return append(allErrs, field.Required(fldPath, ""))
  1490. }
  1491. allNames := sets.String{}
  1492. for i, ctr := range containers {
  1493. idxPath := fldPath.Index(i)
  1494. namePath := idxPath.Child("name")
  1495. if len(ctr.Name) == 0 {
  1496. allErrs = append(allErrs, field.Required(namePath, ""))
  1497. } else {
  1498. allErrs = append(allErrs, ValidateDNS1123Label(ctr.Name, namePath)...)
  1499. }
  1500. if allNames.Has(ctr.Name) {
  1501. allErrs = append(allErrs, field.Duplicate(namePath, ctr.Name))
  1502. } else {
  1503. allNames.Insert(ctr.Name)
  1504. }
  1505. if len(ctr.Image) == 0 {
  1506. allErrs = append(allErrs, field.Required(idxPath.Child("image"), ""))
  1507. }
  1508. if ctr.Lifecycle != nil {
  1509. allErrs = append(allErrs, validateLifecycle(ctr.Lifecycle, idxPath.Child("lifecycle"))...)
  1510. }
  1511. allErrs = append(allErrs, validateProbe(ctr.LivenessProbe, idxPath.Child("livenessProbe"))...)
  1512. // Liveness-specific validation
  1513. if ctr.LivenessProbe != nil && ctr.LivenessProbe.SuccessThreshold != 1 {
  1514. allErrs = append(allErrs, field.Invalid(idxPath.Child("livenessProbe", "successThreshold"), ctr.LivenessProbe.SuccessThreshold, "must be 1"))
  1515. }
  1516. allErrs = append(allErrs, validateProbe(ctr.ReadinessProbe, idxPath.Child("readinessProbe"))...)
  1517. allErrs = append(allErrs, validateContainerPorts(ctr.Ports, idxPath.Child("ports"))...)
  1518. allErrs = append(allErrs, validateEnv(ctr.Env, idxPath.Child("env"))...)
  1519. allErrs = append(allErrs, validateVolumeMounts(ctr.VolumeMounts, volumes, idxPath.Child("volumeMounts"))...)
  1520. allErrs = append(allErrs, validatePullPolicy(ctr.ImagePullPolicy, idxPath.Child("imagePullPolicy"))...)
  1521. allErrs = append(allErrs, ValidateResourceRequirements(&ctr.Resources, idxPath.Child("resources"))...)
  1522. allErrs = append(allErrs, ValidateSecurityContext(ctr.SecurityContext, idxPath.Child("securityContext"))...)
  1523. }
  1524. // Check for colliding ports across all containers.
  1525. allErrs = append(allErrs, checkHostPortConflicts(containers, fldPath)...)
  1526. return allErrs
  1527. }
  1528. func validateRestartPolicy(restartPolicy *api.RestartPolicy, fldPath *field.Path) field.ErrorList {
  1529. allErrors := field.ErrorList{}
  1530. switch *restartPolicy {
  1531. case api.RestartPolicyAlways, api.RestartPolicyOnFailure, api.RestartPolicyNever:
  1532. break
  1533. case "":
  1534. allErrors = append(allErrors, field.Required(fldPath, ""))
  1535. default:
  1536. validValues := []string{string(api.RestartPolicyAlways), string(api.RestartPolicyOnFailure), string(api.RestartPolicyNever)}
  1537. allErrors = append(allErrors, field.NotSupported(fldPath, *restartPolicy, validValues))
  1538. }
  1539. return allErrors
  1540. }
  1541. func validateDNSPolicy(dnsPolicy *api.DNSPolicy, fldPath *field.Path) field.ErrorList {
  1542. allErrors := field.ErrorList{}
  1543. switch *dnsPolicy {
  1544. case api.DNSClusterFirst, api.DNSDefault:
  1545. break
  1546. case "":
  1547. allErrors = append(allErrors, field.Required(fldPath, ""))
  1548. default:
  1549. validValues := []string{string(api.DNSClusterFirst), string(api.DNSDefault)}
  1550. allErrors = append(allErrors, field.NotSupported(fldPath, dnsPolicy, validValues))
  1551. }
  1552. return allErrors
  1553. }
  1554. func validateHostNetwork(hostNetwork bool, containers []api.Container, fldPath *field.Path) field.ErrorList {
  1555. allErrors := field.ErrorList{}
  1556. if hostNetwork {
  1557. for i, container := range containers {
  1558. portsPath := fldPath.Index(i).Child("ports")
  1559. for i, port := range container.Ports {
  1560. idxPath := portsPath.Index(i)
  1561. if port.HostPort != port.ContainerPort {
  1562. allErrors = append(allErrors, field.Invalid(idxPath.Child("containerPort"), port.ContainerPort, "must match `hostPort` when `hostNetwork` is true"))
  1563. }
  1564. }
  1565. }
  1566. }
  1567. return allErrors
  1568. }
  1569. // validateImagePullSecrets checks to make sure the pull secrets are well
  1570. // formed. Right now, we only expect name to be set (it's the only field). If
  1571. // this ever changes and someone decides to set those fields, we'd like to
  1572. // know.
  1573. func validateImagePullSecrets(imagePullSecrets []api.LocalObjectReference, fldPath *field.Path) field.ErrorList {
  1574. allErrors := field.ErrorList{}
  1575. for i, currPullSecret := range imagePullSecrets {
  1576. idxPath := fldPath.Index(i)
  1577. strippedRef := api.LocalObjectReference{Name: currPullSecret.Name}
  1578. if !reflect.DeepEqual(strippedRef, currPullSecret) {
  1579. allErrors = append(allErrors, field.Invalid(idxPath, currPullSecret, "only name may be set"))
  1580. }
  1581. }
  1582. return allErrors
  1583. }
  1584. func validateTaintEffect(effect *api.TaintEffect, allowEmpty bool, fldPath *field.Path) field.ErrorList {
  1585. if !allowEmpty && len(*effect) == 0 {
  1586. return field.ErrorList{field.Required(fldPath, "")}
  1587. }
  1588. allErrors := field.ErrorList{}
  1589. switch *effect {
  1590. // TODO: Replace next line with subsequent commented-out line when implement TaintEffectNoScheduleNoAdmit, TaintEffectNoScheduleNoAdmitNoExecute.
  1591. case api.TaintEffectNoSchedule, api.TaintEffectPreferNoSchedule:
  1592. // case api.TaintEffectNoSchedule, api.TaintEffectPreferNoSchedule, api.TaintEffectNoScheduleNoAdmit, api.TaintEffectNoScheduleNoAdmitNoExecute:
  1593. default:
  1594. validValues := []string{
  1595. string(api.TaintEffectNoSchedule),
  1596. string(api.TaintEffectPreferNoSchedule),
  1597. // TODO: Uncomment this block when implement TaintEffectNoScheduleNoAdmit, TaintEffectNoScheduleNoAdmitNoExecute.
  1598. // string(api.TaintEffectNoScheduleNoAdmit),
  1599. // string(api.TaintEffectNoScheduleNoAdmitNoExecute),
  1600. }
  1601. allErrors = append(allErrors, field.NotSupported(fldPath, effect, validValues))
  1602. }
  1603. return allErrors
  1604. }
  1605. // validateTolerations tests if given tolerations have valid data.
  1606. func validateTolerations(tolerations []api.Toleration, fldPath *field.Path) field.ErrorList {
  1607. allErrors := field.ErrorList{}
  1608. for i, toleration := range tolerations {
  1609. idxPath := fldPath.Index(i)
  1610. // validate the toleration key
  1611. allErrors = append(allErrors, unversionedvalidation.ValidateLabelName(toleration.Key, idxPath.Child("key"))...)
  1612. // validate toleration operator and value
  1613. switch toleration.Operator {
  1614. case api.TolerationOpEqual, "":
  1615. if errs := validation.IsValidLabelValue(toleration.Value); len(errs) != 0 {
  1616. allErrors = append(allErrors, field.Invalid(idxPath.Child("operator"), toleration.Value, strings.Join(errs, ";")))
  1617. }
  1618. case api.TolerationOpExists:
  1619. if len(toleration.Value) > 0 {
  1620. allErrors = append(allErrors, field.Invalid(idxPath.Child("operator"), toleration, "value must be empty when `operator` is 'Exists'"))
  1621. }
  1622. default:
  1623. validValues := []string{string(api.TolerationOpEqual), string(api.TolerationOpExists)}
  1624. allErrors = append(allErrors, field.NotSupported(idxPath.Child("operator"), toleration.Operator, validValues))
  1625. }
  1626. // validate toleration effect
  1627. if len(toleration.Effect) > 0 {
  1628. allErrors = append(allErrors, validateTaintEffect(&toleration.Effect, true, idxPath.Child("effect"))...)
  1629. }
  1630. }
  1631. return allErrors
  1632. }
  1633. // ValidatePod tests if required fields in the pod are set.
  1634. func ValidatePod(pod *api.Pod) field.ErrorList {
  1635. fldPath := field.NewPath("metadata")
  1636. allErrs := ValidateObjectMeta(&pod.ObjectMeta, true, ValidatePodName, fldPath)
  1637. allErrs = append(allErrs, ValidatePodSpecificAnnotations(pod.ObjectMeta.Annotations, &pod.Spec, fldPath.Child("annotations"))...)
  1638. allErrs = append(allErrs, ValidatePodSpec(&pod.Spec, field.NewPath("spec"))...)
  1639. return allErrs
  1640. }
  1641. // ValidatePodSpec tests that the specified PodSpec has valid data.
  1642. // This includes checking formatting and uniqueness. It also canonicalizes the
  1643. // structure by setting default values and implementing any backwards-compatibility
  1644. // tricks.
  1645. func ValidatePodSpec(spec *api.PodSpec, fldPath *field.Path) field.ErrorList {
  1646. allErrs := field.ErrorList{}
  1647. allVolumes, vErrs := validateVolumes(spec.Volumes, fldPath.Child("volumes"))
  1648. allErrs = append(allErrs, vErrs...)
  1649. allErrs = append(allErrs, validateContainers(spec.Containers, allVolumes, fldPath.Child("containers"))...)
  1650. allErrs = append(allErrs, validateInitContainers(spec.InitContainers, spec.Containers, allVolumes, fldPath.Child("initContainers"))...)
  1651. allErrs = append(allErrs, validateRestartPolicy(&spec.RestartPolicy, fldPath.Child("restartPolicy"))...)
  1652. allErrs = append(allErrs, validateDNSPolicy(&spec.DNSPolicy, fldPath.Child("dnsPolicy"))...)
  1653. allErrs = append(allErrs, unversionedvalidation.ValidateLabels(spec.NodeSelector, fldPath.Child("nodeSelector"))...)
  1654. allErrs = append(allErrs, ValidatePodSecurityContext(spec.SecurityContext, spec, fldPath, fldPath.Child("securityContext"))...)
  1655. allErrs = append(allErrs, validateImagePullSecrets(spec.ImagePullSecrets, fldPath.Child("imagePullSecrets"))...)
  1656. if len(spec.ServiceAccountName) > 0 {
  1657. for _, msg := range ValidateServiceAccountName(spec.ServiceAccountName, false) {
  1658. allErrs = append(allErrs, field.Invalid(fldPath.Child("serviceAccountName"), spec.ServiceAccountName, msg))
  1659. }
  1660. }
  1661. if len(spec.NodeName) > 0 {
  1662. for _, msg := range ValidateNodeName(spec.NodeName, false) {
  1663. allErrs = append(allErrs, field.Invalid(fldPath.Child("nodeName"), spec.NodeName, msg))
  1664. }
  1665. }
  1666. if spec.ActiveDeadlineSeconds != nil {
  1667. if *spec.ActiveDeadlineSeconds <= 0 {
  1668. allErrs = append(allErrs, field.Invalid(fldPath.Child("activeDeadlineSeconds"), spec.ActiveDeadlineSeconds, "must be greater than 0"))
  1669. }
  1670. }
  1671. if len(spec.Hostname) > 0 {
  1672. allErrs = append(allErrs, ValidateDNS1123Label(spec.Hostname, fldPath.Child("hostname"))...)
  1673. }
  1674. if len(spec.Subdomain) > 0 {
  1675. allErrs = append(allErrs, ValidateDNS1123Label(spec.Subdomain, fldPath.Child("subdomain"))...)
  1676. }
  1677. return allErrs
  1678. }
  1679. // ValidateNodeSelectorRequirement tests that the specified NodeSelectorRequirement fields has valid data
  1680. func ValidateNodeSelectorRequirement(rq api.NodeSelectorRequirement, fldPath *field.Path) field.ErrorList {
  1681. allErrs := field.ErrorList{}
  1682. switch rq.Operator {
  1683. case api.NodeSelectorOpIn, api.NodeSelectorOpNotIn:
  1684. if len(rq.Values) == 0 {
  1685. allErrs = append(allErrs, field.Required(fldPath.Child("values"), "must be specified when `operator` is 'In' or 'NotIn'"))
  1686. }
  1687. case api.NodeSelectorOpExists, api.NodeSelectorOpDoesNotExist:
  1688. if len(rq.Values) > 0 {
  1689. allErrs = append(allErrs, field.Forbidden(fldPath.Child("values"), "may not be specified when `operator` is 'Exists' or 'DoesNotExist'"))
  1690. }
  1691. case api.NodeSelectorOpGt, api.NodeSelectorOpLt:
  1692. if len(rq.Values) != 1 {
  1693. allErrs = append(allErrs, field.Required(fldPath.Child("values"), "must be specified single value when `operator` is 'Lt' or 'Gt'"))
  1694. }
  1695. default:
  1696. allErrs = append(allErrs, field.Invalid(fldPath.Child("operator"), rq.Operator, "not a valid selector operator"))
  1697. }
  1698. allErrs = append(allErrs, unversionedvalidation.ValidateLabelName(rq.Key, fldPath.Child("key"))...)
  1699. return allErrs
  1700. }
  1701. // ValidateNodeSelectorTerm tests that the specified node selector term has valid data
  1702. func ValidateNodeSelectorTerm(term api.NodeSelectorTerm, fldPath *field.Path) field.ErrorList {
  1703. allErrs := field.ErrorList{}
  1704. if len(term.MatchExpressions) == 0 {
  1705. return append(allErrs, field.Required(fldPath.Child("matchExpressions"), "must have at least one node selector requirement"))
  1706. }
  1707. for j, req := range term.MatchExpressions {
  1708. allErrs = append(allErrs, ValidateNodeSelectorRequirement(req, fldPath.Child("matchExpressions").Index(j))...)
  1709. }
  1710. return allErrs
  1711. }
  1712. // ValidateNodeSelector tests that the specified nodeSelector fields has valid data
  1713. func ValidateNodeSelector(nodeSelector *api.NodeSelector, fldPath *field.Path) field.ErrorList {
  1714. allErrs := field.ErrorList{}
  1715. termFldPath := fldPath.Child("nodeSelectorTerms")
  1716. if len(nodeSelector.NodeSelectorTerms) == 0 {
  1717. return append(allErrs, field.Required(termFldPath, "must have at least one node selector term"))
  1718. }
  1719. for i, term := range nodeSelector.NodeSelectorTerms {
  1720. allErrs = append(allErrs, ValidateNodeSelectorTerm(term, termFldPath.Index(i))...)
  1721. }
  1722. return allErrs
  1723. }
  1724. // ValidateAvoidPodsInNodeAnnotations tests that the serialized AvoidPods in Node.Annotations has valid data
  1725. func ValidateAvoidPodsInNodeAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
  1726. allErrs := field.ErrorList{}
  1727. avoids, err := api.GetAvoidPodsFromNodeAnnotations(annotations)
  1728. if err != nil {
  1729. allErrs = append(allErrs, field.Invalid(fldPath.Child("AvoidPods"), api.PreferAvoidPodsAnnotationKey, err.Error()))
  1730. return allErrs
  1731. }
  1732. if len(avoids.PreferAvoidPods) != 0 {
  1733. for i, pa := range avoids.PreferAvoidPods {
  1734. idxPath := fldPath.Child(api.PreferAvoidPodsAnnotationKey).Index(i)
  1735. allErrs = append(allErrs, validatePreferAvoidPodsEntry(pa, idxPath)...)
  1736. }
  1737. }
  1738. return allErrs
  1739. }
  1740. // validatePreferAvoidPodsEntry tests if given PreferAvoidPodsEntry has valid data.
  1741. func validatePreferAvoidPodsEntry(avoidPodEntry api.PreferAvoidPodsEntry, fldPath *field.Path) field.ErrorList {
  1742. allErrors := field.ErrorList{}
  1743. if avoidPodEntry.PodSignature.PodController == nil {
  1744. allErrors = append(allErrors, field.Required(fldPath.Child("PodSignature"), ""))
  1745. } else {
  1746. if *(avoidPodEntry.PodSignature.PodController.Controller) != true {
  1747. allErrors = append(allErrors,
  1748. field.Invalid(fldPath.Child("PodSignature").Child("PodController").Child("Controller"),
  1749. *(avoidPodEntry.PodSignature.PodController.Controller), "must point to a controller"))
  1750. }
  1751. }
  1752. return allErrors
  1753. }
  1754. // ValidatePreferredSchedulingTerms tests that the specified SoftNodeAffinity fields has valid data
  1755. func ValidatePreferredSchedulingTerms(terms []api.PreferredSchedulingTerm, fldPath *field.Path) field.ErrorList {
  1756. allErrs := field.ErrorList{}
  1757. for i, term := range terms {
  1758. if term.Weight <= 0 || term.Weight > 100 {
  1759. allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("weight"), term.Weight, "must be in the range 1-100"))
  1760. }
  1761. allErrs = append(allErrs, ValidateNodeSelectorTerm(term.Preference, fldPath.Index(i).Child("preference"))...)
  1762. }
  1763. return allErrs
  1764. }
  1765. // validatePodAffinityTerm tests that the specified podAffinityTerm fields have valid data
  1766. func validatePodAffinityTerm(podAffinityTerm api.PodAffinityTerm, allowEmptyTopologyKey bool, fldPath *field.Path) field.ErrorList {
  1767. allErrs := field.ErrorList{}
  1768. allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(podAffinityTerm.LabelSelector, fldPath.Child("matchExpressions"))...)
  1769. for _, name := range podAffinityTerm.Namespaces {
  1770. for _, msg := range ValidateNamespaceName(name, false) {
  1771. allErrs = append(allErrs, field.Invalid(fldPath.Child("namespace"), name, msg))
  1772. }
  1773. }
  1774. if !allowEmptyTopologyKey && len(podAffinityTerm.TopologyKey) == 0 {
  1775. allErrs = append(allErrs, field.Required(fldPath.Child("topologyKey"), "can only be empty for PreferredDuringScheduling pod anti affinity"))
  1776. }
  1777. if len(podAffinityTerm.TopologyKey) != 0 {
  1778. allErrs = append(allErrs, unversionedvalidation.ValidateLabelName(podAffinityTerm.TopologyKey, fldPath.Child("topologyKey"))...)
  1779. }
  1780. return allErrs
  1781. }
  1782. // validatePodAffinityTerms tests that the specified podAffinityTerms fields have valid data
  1783. func validatePodAffinityTerms(podAffinityTerms []api.PodAffinityTerm, allowEmptyTopologyKey bool, fldPath *field.Path) field.ErrorList {
  1784. allErrs := field.ErrorList{}
  1785. for i, podAffinityTerm := range podAffinityTerms {
  1786. allErrs = append(allErrs, validatePodAffinityTerm(podAffinityTerm, allowEmptyTopologyKey, fldPath.Index(i))...)
  1787. }
  1788. return allErrs
  1789. }
  1790. // validateWeightedPodAffinityTerms tests that the specified weightedPodAffinityTerms fields have valid data
  1791. func validateWeightedPodAffinityTerms(weightedPodAffinityTerms []api.WeightedPodAffinityTerm, allowEmptyTopologyKey bool, fldPath *field.Path) field.ErrorList {
  1792. allErrs := field.ErrorList{}
  1793. for j, weightedTerm := range weightedPodAffinityTerms {
  1794. if weightedTerm.Weight <= 0 || weightedTerm.Weight > 100 {
  1795. allErrs = append(allErrs, field.Invalid(fldPath.Index(j).Child("weight"), weightedTerm.Weight, "must be in the range 1-100"))
  1796. }
  1797. allErrs = append(allErrs, validatePodAffinityTerm(weightedTerm.PodAffinityTerm, allowEmptyTopologyKey, fldPath.Index(j).Child("podAffinityTerm"))...)
  1798. }
  1799. return allErrs
  1800. }
  1801. // validatePodAntiAffinity tests that the specified podAntiAffinity fields have valid data
  1802. func validatePodAntiAffinity(podAntiAffinity *api.PodAntiAffinity, fldPath *field.Path) field.ErrorList {
  1803. allErrs := field.ErrorList{}
  1804. // TODO:Uncomment below code once RequiredDuringSchedulingRequiredDuringExecution is implemented.
  1805. // if podAntiAffinity.RequiredDuringSchedulingRequiredDuringExecution != nil {
  1806. // allErrs = append(allErrs, validatePodAffinityTerms(podAntiAffinity.RequiredDuringSchedulingRequiredDuringExecution, false,
  1807. // fldPath.Child("requiredDuringSchedulingRequiredDuringExecution"))...)
  1808. //}
  1809. if podAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution != nil {
  1810. // empty topologyKey is not allowed for hard pod anti-affinity
  1811. allErrs = append(allErrs, validatePodAffinityTerms(podAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution, false,
  1812. fldPath.Child("requiredDuringSchedulingIgnoredDuringExecution"))...)
  1813. }
  1814. if podAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution != nil {
  1815. // empty topologyKey is allowed for soft pod anti-affinity
  1816. allErrs = append(allErrs, validateWeightedPodAffinityTerms(podAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution, true,
  1817. fldPath.Child("preferredDuringSchedulingIgnoredDuringExecution"))...)
  1818. }
  1819. return allErrs
  1820. }
  1821. // validatePodAffinity tests that the specified podAffinity fields have valid data
  1822. func validatePodAffinity(podAffinity *api.PodAffinity, fldPath *field.Path) field.ErrorList {
  1823. allErrs := field.ErrorList{}
  1824. // TODO:Uncomment below code once RequiredDuringSchedulingRequiredDuringExecution is implemented.
  1825. // if podAffinity.RequiredDuringSchedulingRequiredDuringExecution != nil {
  1826. // allErrs = append(allErrs, validatePodAffinityTerms(podAffinity.RequiredDuringSchedulingRequiredDuringExecution, false,
  1827. // fldPath.Child("requiredDuringSchedulingRequiredDuringExecution"))...)
  1828. //}
  1829. if podAffinity.RequiredDuringSchedulingIgnoredDuringExecution != nil {
  1830. // empty topologyKey is not allowed for hard pod affinity
  1831. allErrs = append(allErrs, validatePodAffinityTerms(podAffinity.RequiredDuringSchedulingIgnoredDuringExecution, false,
  1832. fldPath.Child("requiredDuringSchedulingIgnoredDuringExecution"))...)
  1833. }
  1834. if podAffinity.PreferredDuringSchedulingIgnoredDuringExecution != nil {
  1835. // empty topologyKey is not allowed for soft pod affinity
  1836. allErrs = append(allErrs, validateWeightedPodAffinityTerms(podAffinity.PreferredDuringSchedulingIgnoredDuringExecution, false,
  1837. fldPath.Child("preferredDuringSchedulingIgnoredDuringExecution"))...)
  1838. }
  1839. return allErrs
  1840. }
  1841. // ValidateAffinityInPodAnnotations tests that the serialized Affinity in Pod.Annotations has valid data
  1842. func ValidateAffinityInPodAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
  1843. allErrs := field.ErrorList{}
  1844. affinity, err := api.GetAffinityFromPodAnnotations(annotations)
  1845. if err != nil {
  1846. allErrs = append(allErrs, field.Invalid(fldPath, api.AffinityAnnotationKey, err.Error()))
  1847. return allErrs
  1848. }
  1849. if affinity == nil {
  1850. return allErrs
  1851. }
  1852. affinityFldPath := fldPath.Child(api.AffinityAnnotationKey)
  1853. if affinity.NodeAffinity != nil {
  1854. na := affinity.NodeAffinity
  1855. naFldPath := affinityFldPath.Child("nodeAffinity")
  1856. // TODO: Uncomment the next three lines once RequiredDuringSchedulingRequiredDuringExecution is implemented.
  1857. // if na.RequiredDuringSchedulingRequiredDuringExecution != nil {
  1858. // allErrs = append(allErrs, ValidateNodeSelector(na.RequiredDuringSchedulingRequiredDuringExecution, naFldPath.Child("requiredDuringSchedulingRequiredDuringExecution"))...)
  1859. // }
  1860. if na.RequiredDuringSchedulingIgnoredDuringExecution != nil {
  1861. allErrs = append(allErrs, ValidateNodeSelector(na.RequiredDuringSchedulingIgnoredDuringExecution, naFldPath.Child("requiredDuringSchedulingIgnoredDuringExecution"))...)
  1862. }
  1863. if len(na.PreferredDuringSchedulingIgnoredDuringExecution) > 0 {
  1864. allErrs = append(allErrs, ValidatePreferredSchedulingTerms(na.PreferredDuringSchedulingIgnoredDuringExecution, naFldPath.Child("preferredDuringSchedulingIgnoredDuringExecution"))...)
  1865. }
  1866. }
  1867. if affinity.PodAffinity != nil {
  1868. allErrs = append(allErrs, validatePodAffinity(affinity.PodAffinity, affinityFldPath.Child("podAffinity"))...)
  1869. }
  1870. if affinity.PodAntiAffinity != nil {
  1871. allErrs = append(allErrs, validatePodAntiAffinity(affinity.PodAntiAffinity, affinityFldPath.Child("podAntiAffinity"))...)
  1872. }
  1873. return allErrs
  1874. }
  1875. // ValidateTolerationsInPodAnnotations tests that the serialized tolerations in Pod.Annotations has valid data
  1876. func ValidateTolerationsInPodAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
  1877. allErrs := field.ErrorList{}
  1878. tolerations, err := api.GetTolerationsFromPodAnnotations(annotations)
  1879. if err != nil {
  1880. allErrs = append(allErrs, field.Invalid(fldPath, api.TolerationsAnnotationKey, err.Error()))
  1881. return allErrs
  1882. }
  1883. if len(tolerations) > 0 {
  1884. allErrs = append(allErrs, validateTolerations(tolerations, fldPath.Child(api.TolerationsAnnotationKey))...)
  1885. }
  1886. return allErrs
  1887. }
  1888. func validateSeccompProfile(p string, fldPath *field.Path) field.ErrorList {
  1889. if p == "docker/default" {
  1890. return nil
  1891. }
  1892. if p == "unconfined" {
  1893. return nil
  1894. }
  1895. if strings.HasPrefix(p, "localhost/") {
  1896. return validateLocalDescendingPath(strings.TrimPrefix(p, "localhost/"), fldPath)
  1897. }
  1898. return field.ErrorList{field.Invalid(fldPath, p, "must be a valid seccomp profile")}
  1899. }
  1900. func ValidateSeccompPodAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
  1901. allErrs := field.ErrorList{}
  1902. if p, exists := annotations[api.SeccompPodAnnotationKey]; exists {
  1903. allErrs = append(allErrs, validateSeccompProfile(p, fldPath.Child(api.SeccompPodAnnotationKey))...)
  1904. }
  1905. for k, p := range annotations {
  1906. if strings.HasPrefix(k, api.SeccompContainerAnnotationKeyPrefix) {
  1907. allErrs = append(allErrs, validateSeccompProfile(p, fldPath.Child(k))...)
  1908. }
  1909. }
  1910. return allErrs
  1911. }
  1912. func ValidateAppArmorPodAnnotations(annotations map[string]string, spec *api.PodSpec, fldPath *field.Path) field.ErrorList {
  1913. allErrs := field.ErrorList{}
  1914. for k, p := range annotations {
  1915. if !strings.HasPrefix(k, apparmor.ContainerAnnotationKeyPrefix) {
  1916. continue
  1917. }
  1918. if !utilconfig.DefaultFeatureGate.AppArmor() {
  1919. allErrs = append(allErrs, field.Forbidden(fldPath.Key(k), "AppArmor is disabled by feature-gate"))
  1920. continue
  1921. }
  1922. containerName := strings.TrimPrefix(k, apparmor.ContainerAnnotationKeyPrefix)
  1923. if !podSpecHasContainer(spec, containerName) {
  1924. allErrs = append(allErrs, field.Invalid(fldPath.Key(k), containerName, "container not found"))
  1925. }
  1926. if err := apparmor.ValidateProfileFormat(p); err != nil {
  1927. allErrs = append(allErrs, field.Invalid(fldPath.Key(k), p, err.Error()))
  1928. }
  1929. }
  1930. return allErrs
  1931. }
  1932. func podSpecHasContainer(spec *api.PodSpec, containerName string) bool {
  1933. for _, c := range spec.InitContainers {
  1934. if c.Name == containerName {
  1935. return true
  1936. }
  1937. }
  1938. for _, c := range spec.Containers {
  1939. if c.Name == containerName {
  1940. return true
  1941. }
  1942. }
  1943. return false
  1944. }
  1945. const (
  1946. // a sysctl segment regex, concatenated with dots to form a sysctl name
  1947. SysctlSegmentFmt string = "[a-z0-9]([-_a-z0-9]*[a-z0-9])?"
  1948. // a sysctl name regex
  1949. SysctlFmt string = "(" + SysctlSegmentFmt + "\\.)*" + SysctlSegmentFmt
  1950. // the maximal length of a sysctl name
  1951. SysctlMaxLength int = 253
  1952. )
  1953. var sysctlRegexp = regexp.MustCompile("^" + SysctlFmt + "$")
  1954. // IsValidSysctlName checks that the given string is a valid sysctl name,
  1955. // i.e. matches SysctlFmt.
  1956. func IsValidSysctlName(name string) bool {
  1957. if len(name) > SysctlMaxLength {
  1958. return false
  1959. }
  1960. return sysctlRegexp.MatchString(name)
  1961. }
  1962. func validateSysctls(sysctls []api.Sysctl, fldPath *field.Path) field.ErrorList {
  1963. allErrs := field.ErrorList{}
  1964. for i, s := range sysctls {
  1965. if len(s.Name) == 0 {
  1966. allErrs = append(allErrs, field.Required(fldPath.Index(i).Child("name"), ""))
  1967. } else if !IsValidSysctlName(s.Name) {
  1968. 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)))
  1969. }
  1970. }
  1971. return allErrs
  1972. }
  1973. // ValidatePodSecurityContext test that the specified PodSecurityContext has valid data.
  1974. func ValidatePodSecurityContext(securityContext *api.PodSecurityContext, spec *api.PodSpec, specPath, fldPath *field.Path) field.ErrorList {
  1975. allErrs := field.ErrorList{}
  1976. if securityContext != nil {
  1977. allErrs = append(allErrs, validateHostNetwork(securityContext.HostNetwork, spec.Containers, specPath.Child("containers"))...)
  1978. if securityContext.FSGroup != nil {
  1979. for _, msg := range validation.IsValidGroupId(*securityContext.FSGroup) {
  1980. allErrs = append(allErrs, field.Invalid(fldPath.Child("fsGroup"), *(securityContext.FSGroup), msg))
  1981. }
  1982. }
  1983. if securityContext.RunAsUser != nil {
  1984. for _, msg := range validation.IsValidUserId(*securityContext.RunAsUser) {
  1985. allErrs = append(allErrs, field.Invalid(fldPath.Child("runAsUser"), *(securityContext.RunAsUser), msg))
  1986. }
  1987. }
  1988. for g, gid := range securityContext.SupplementalGroups {
  1989. for _, msg := range validation.IsValidGroupId(gid) {
  1990. allErrs = append(allErrs, field.Invalid(fldPath.Child("supplementalGroups").Index(g), gid, msg))
  1991. }
  1992. }
  1993. }
  1994. return allErrs
  1995. }
  1996. func ValidateContainerUpdates(newContainers, oldContainers []api.Container, fldPath *field.Path) (allErrs field.ErrorList, stop bool) {
  1997. allErrs = field.ErrorList{}
  1998. if len(newContainers) != len(oldContainers) {
  1999. //TODO: Pinpoint the specific container that causes the invalid error after we have strategic merge diff
  2000. allErrs = append(allErrs, field.Forbidden(fldPath, "pod updates may not add or remove containers"))
  2001. return allErrs, true
  2002. }
  2003. // validate updated container images
  2004. for i, ctr := range newContainers {
  2005. if len(ctr.Image) == 0 {
  2006. allErrs = append(allErrs, field.Required(fldPath.Index(i).Child("image"), ""))
  2007. }
  2008. }
  2009. return allErrs, false
  2010. }
  2011. // ValidatePodUpdate tests to see if the update is legal for an end user to make. newPod is updated with fields
  2012. // that cannot be changed.
  2013. func ValidatePodUpdate(newPod, oldPod *api.Pod) field.ErrorList {
  2014. fldPath := field.NewPath("metadata")
  2015. allErrs := ValidateObjectMetaUpdate(&newPod.ObjectMeta, &oldPod.ObjectMeta, fldPath)
  2016. allErrs = append(allErrs, ValidatePodSpecificAnnotationUpdates(newPod, oldPod, fldPath.Child("annotations"))...)
  2017. specPath := field.NewPath("spec")
  2018. // validate updateable fields:
  2019. // 1. containers[*].image
  2020. // 2. initContainers[*].image
  2021. // 3. spec.activeDeadlineSeconds
  2022. containerErrs, stop := ValidateContainerUpdates(newPod.Spec.Containers, oldPod.Spec.Containers, specPath.Child("containers"))
  2023. allErrs = append(allErrs, containerErrs...)
  2024. if stop {
  2025. return allErrs
  2026. }
  2027. containerErrs, stop = ValidateContainerUpdates(newPod.Spec.InitContainers, oldPod.Spec.InitContainers, specPath.Child("initContainers"))
  2028. allErrs = append(allErrs, containerErrs...)
  2029. if stop {
  2030. return allErrs
  2031. }
  2032. // validate updated spec.activeDeadlineSeconds. two types of updates are allowed:
  2033. // 1. from nil to a positive value
  2034. // 2. from a positive value to a lesser, non-negative value
  2035. if newPod.Spec.ActiveDeadlineSeconds != nil {
  2036. newActiveDeadlineSeconds := *newPod.Spec.ActiveDeadlineSeconds
  2037. if newActiveDeadlineSeconds < 0 {
  2038. allErrs = append(allErrs, field.Invalid(specPath.Child("activeDeadlineSeconds"), newActiveDeadlineSeconds, isNegativeErrorMsg))
  2039. return allErrs
  2040. }
  2041. if oldPod.Spec.ActiveDeadlineSeconds != nil {
  2042. oldActiveDeadlineSeconds := *oldPod.Spec.ActiveDeadlineSeconds
  2043. if oldActiveDeadlineSeconds < newActiveDeadlineSeconds {
  2044. allErrs = append(allErrs, field.Invalid(specPath.Child("activeDeadlineSeconds"), newActiveDeadlineSeconds, "must be less than or equal to previous value"))
  2045. return allErrs
  2046. }
  2047. }
  2048. } else if oldPod.Spec.ActiveDeadlineSeconds != nil {
  2049. allErrs = append(allErrs, field.Invalid(specPath.Child("activeDeadlineSeconds"), newPod.Spec.ActiveDeadlineSeconds, "must not update from a positive integer to nil value"))
  2050. }
  2051. // handle updateable fields by munging those fields prior to deep equal comparison.
  2052. mungedPod := *newPod
  2053. // munge containers[*].image
  2054. var newContainers []api.Container
  2055. for ix, container := range mungedPod.Spec.Containers {
  2056. container.Image = oldPod.Spec.Containers[ix].Image
  2057. newContainers = append(newContainers, container)
  2058. }
  2059. mungedPod.Spec.Containers = newContainers
  2060. // munge initContainers[*].image
  2061. var newInitContainers []api.Container
  2062. for ix, container := range mungedPod.Spec.InitContainers {
  2063. container.Image = oldPod.Spec.InitContainers[ix].Image
  2064. newInitContainers = append(newInitContainers, container)
  2065. }
  2066. mungedPod.Spec.InitContainers = newInitContainers
  2067. // munge spec.activeDeadlineSeconds
  2068. mungedPod.Spec.ActiveDeadlineSeconds = nil
  2069. if oldPod.Spec.ActiveDeadlineSeconds != nil {
  2070. activeDeadlineSeconds := *oldPod.Spec.ActiveDeadlineSeconds
  2071. mungedPod.Spec.ActiveDeadlineSeconds = &activeDeadlineSeconds
  2072. }
  2073. if !api.Semantic.DeepEqual(mungedPod.Spec, oldPod.Spec) {
  2074. //TODO: Pinpoint the specific field that causes the invalid error after we have strategic merge diff
  2075. allErrs = append(allErrs, field.Forbidden(specPath, "pod updates may not change fields other than `containers[*].image` or `spec.activeDeadlineSeconds`"))
  2076. }
  2077. return allErrs
  2078. }
  2079. // ValidatePodStatusUpdate tests to see if the update is legal for an end user to make. newPod is updated with fields
  2080. // that cannot be changed.
  2081. func ValidatePodStatusUpdate(newPod, oldPod *api.Pod) field.ErrorList {
  2082. allErrs := ValidateObjectMetaUpdate(&newPod.ObjectMeta, &oldPod.ObjectMeta, field.NewPath("metadata"))
  2083. // TODO: allow change when bindings are properly decoupled from pods
  2084. if newPod.Spec.NodeName != oldPod.Spec.NodeName {
  2085. allErrs = append(allErrs, field.Forbidden(field.NewPath("status", "nodeName"), "may not be changed directly"))
  2086. }
  2087. // For status update we ignore changes to pod spec.
  2088. newPod.Spec = oldPod.Spec
  2089. return allErrs
  2090. }
  2091. // ValidatePodBinding tests if required fields in the pod binding are legal.
  2092. func ValidatePodBinding(binding *api.Binding) field.ErrorList {
  2093. allErrs := field.ErrorList{}
  2094. if len(binding.Target.Kind) != 0 && binding.Target.Kind != "Node" {
  2095. // TODO: When validation becomes versioned, this gets more complicated.
  2096. allErrs = append(allErrs, field.NotSupported(field.NewPath("target", "kind"), binding.Target.Kind, []string{"Node", "<empty>"}))
  2097. }
  2098. if len(binding.Target.Name) == 0 {
  2099. // TODO: When validation becomes versioned, this gets more complicated.
  2100. allErrs = append(allErrs, field.Required(field.NewPath("target", "name"), ""))
  2101. }
  2102. return allErrs
  2103. }
  2104. // ValidatePodTemplate tests if required fields in the pod template are set.
  2105. func ValidatePodTemplate(pod *api.PodTemplate) field.ErrorList {
  2106. allErrs := ValidateObjectMeta(&pod.ObjectMeta, true, ValidatePodName, field.NewPath("metadata"))
  2107. allErrs = append(allErrs, ValidatePodTemplateSpec(&pod.Template, field.NewPath("template"))...)
  2108. return allErrs
  2109. }
  2110. // ValidatePodTemplateUpdate tests to see if the update is legal for an end user to make. newPod is updated with fields
  2111. // that cannot be changed.
  2112. func ValidatePodTemplateUpdate(newPod, oldPod *api.PodTemplate) field.ErrorList {
  2113. allErrs := ValidateObjectMetaUpdate(&oldPod.ObjectMeta, &newPod.ObjectMeta, field.NewPath("metadata"))
  2114. allErrs = append(allErrs, ValidatePodTemplateSpec(&newPod.Template, field.NewPath("template"))...)
  2115. return allErrs
  2116. }
  2117. var supportedSessionAffinityType = sets.NewString(string(api.ServiceAffinityClientIP), string(api.ServiceAffinityNone))
  2118. var supportedServiceType = sets.NewString(string(api.ServiceTypeClusterIP), string(api.ServiceTypeNodePort),
  2119. string(api.ServiceTypeLoadBalancer), string(api.ServiceTypeExternalName))
  2120. // ValidateService tests if required fields in the service are set.
  2121. func ValidateService(service *api.Service) field.ErrorList {
  2122. allErrs := ValidateObjectMeta(&service.ObjectMeta, true, ValidateServiceName, field.NewPath("metadata"))
  2123. specPath := field.NewPath("spec")
  2124. isHeadlessService := service.Spec.ClusterIP == api.ClusterIPNone
  2125. if len(service.Spec.Ports) == 0 && !isHeadlessService && service.Spec.Type != api.ServiceTypeExternalName {
  2126. allErrs = append(allErrs, field.Required(specPath.Child("ports"), ""))
  2127. }
  2128. switch service.Spec.Type {
  2129. case api.ServiceTypeLoadBalancer:
  2130. for ix := range service.Spec.Ports {
  2131. port := &service.Spec.Ports[ix]
  2132. // This is a workaround for broken cloud environments that
  2133. // over-open firewalls. Hopefully it can go away when more clouds
  2134. // understand containers better.
  2135. if port.Port == 10250 {
  2136. portPath := specPath.Child("ports").Index(ix)
  2137. allErrs = append(allErrs, field.Invalid(portPath, port.Port, "may not expose port 10250 externally since it is used by kubelet"))
  2138. }
  2139. }
  2140. case api.ServiceTypeExternalName:
  2141. if service.Spec.ClusterIP != "" {
  2142. allErrs = append(allErrs, field.Invalid(specPath.Child("clusterIP"), service.Spec.ClusterIP, "must be empty for ExternalName services"))
  2143. }
  2144. if len(service.Spec.ExternalName) > 0 {
  2145. allErrs = append(allErrs, ValidateDNS1123Subdomain(service.Spec.ExternalName, specPath.Child("externalName"))...)
  2146. } else {
  2147. allErrs = append(allErrs, field.Required(specPath.Child("externalName"), ""))
  2148. }
  2149. }
  2150. allPortNames := sets.String{}
  2151. portsPath := specPath.Child("ports")
  2152. for i := range service.Spec.Ports {
  2153. portPath := portsPath.Index(i)
  2154. allErrs = append(allErrs, validateServicePort(&service.Spec.Ports[i], len(service.Spec.Ports) > 1, isHeadlessService, &allPortNames, portPath)...)
  2155. }
  2156. if service.Spec.Selector != nil {
  2157. allErrs = append(allErrs, unversionedvalidation.ValidateLabels(service.Spec.Selector, specPath.Child("selector"))...)
  2158. }
  2159. if len(service.Spec.SessionAffinity) == 0 {
  2160. allErrs = append(allErrs, field.Required(specPath.Child("sessionAffinity"), ""))
  2161. } else if !supportedSessionAffinityType.Has(string(service.Spec.SessionAffinity)) {
  2162. allErrs = append(allErrs, field.NotSupported(specPath.Child("sessionAffinity"), service.Spec.SessionAffinity, supportedSessionAffinityType.List()))
  2163. }
  2164. if api.IsServiceIPSet(service) {
  2165. if ip := net.ParseIP(service.Spec.ClusterIP); ip == nil {
  2166. allErrs = append(allErrs, field.Invalid(specPath.Child("clusterIP"), service.Spec.ClusterIP, "must be empty, 'None', or a valid IP address"))
  2167. }
  2168. }
  2169. ipPath := specPath.Child("externalIPs")
  2170. for i, ip := range service.Spec.ExternalIPs {
  2171. idxPath := ipPath.Index(i)
  2172. if msgs := validation.IsValidIP(ip); len(msgs) != 0 {
  2173. for i := range msgs {
  2174. allErrs = append(allErrs, field.Invalid(idxPath, ip, msgs[i]))
  2175. }
  2176. } else {
  2177. allErrs = append(allErrs, validateNonSpecialIP(ip, idxPath)...)
  2178. }
  2179. }
  2180. if len(service.Spec.Type) == 0 {
  2181. allErrs = append(allErrs, field.Required(specPath.Child("type"), ""))
  2182. } else if !supportedServiceType.Has(string(service.Spec.Type)) {
  2183. allErrs = append(allErrs, field.NotSupported(specPath.Child("type"), service.Spec.Type, supportedServiceType.List()))
  2184. }
  2185. if service.Spec.Type == api.ServiceTypeLoadBalancer {
  2186. portsPath := specPath.Child("ports")
  2187. includeProtocols := sets.NewString()
  2188. for i := range service.Spec.Ports {
  2189. portPath := portsPath.Index(i)
  2190. if !supportedPortProtocols.Has(string(service.Spec.Ports[i].Protocol)) {
  2191. allErrs = append(allErrs, field.Invalid(portPath.Child("protocol"), service.Spec.Ports[i].Protocol, "cannot create an external load balancer with non-TCP/UDP ports"))
  2192. } else {
  2193. includeProtocols.Insert(string(service.Spec.Ports[i].Protocol))
  2194. }
  2195. }
  2196. if includeProtocols.Len() > 1 {
  2197. allErrs = append(allErrs, field.Invalid(portsPath, service.Spec.Ports, "cannot create an external load balancer with mix protocols"))
  2198. }
  2199. }
  2200. if service.Spec.Type == api.ServiceTypeClusterIP {
  2201. portsPath := specPath.Child("ports")
  2202. for i := range service.Spec.Ports {
  2203. portPath := portsPath.Index(i)
  2204. if service.Spec.Ports[i].NodePort != 0 {
  2205. allErrs = append(allErrs, field.Invalid(portPath.Child("nodePort"), service.Spec.Ports[i].NodePort, "may not be used when `type` is 'ClusterIP'"))
  2206. }
  2207. }
  2208. }
  2209. // Check for duplicate NodePorts, considering (protocol,port) pairs
  2210. portsPath = specPath.Child("ports")
  2211. nodePorts := make(map[api.ServicePort]bool)
  2212. for i := range service.Spec.Ports {
  2213. port := &service.Spec.Ports[i]
  2214. if port.NodePort == 0 {
  2215. continue
  2216. }
  2217. portPath := portsPath.Index(i)
  2218. var key api.ServicePort
  2219. key.Protocol = port.Protocol
  2220. key.NodePort = port.NodePort
  2221. _, found := nodePorts[key]
  2222. if found {
  2223. allErrs = append(allErrs, field.Duplicate(portPath.Child("nodePort"), port.NodePort))
  2224. }
  2225. nodePorts[key] = true
  2226. }
  2227. // Validate SourceRange field and annotation
  2228. _, ok := service.Annotations[apiservice.AnnotationLoadBalancerSourceRangesKey]
  2229. if len(service.Spec.LoadBalancerSourceRanges) > 0 || ok {
  2230. var fieldPath *field.Path
  2231. var val string
  2232. if len(service.Spec.LoadBalancerSourceRanges) > 0 {
  2233. fieldPath = specPath.Child("LoadBalancerSourceRanges")
  2234. val = fmt.Sprintf("%v", service.Spec.LoadBalancerSourceRanges)
  2235. } else {
  2236. fieldPath = field.NewPath("metadata", "annotations").Key(apiservice.AnnotationLoadBalancerSourceRangesKey)
  2237. val = service.Annotations[apiservice.AnnotationLoadBalancerSourceRangesKey]
  2238. }
  2239. if service.Spec.Type != api.ServiceTypeLoadBalancer {
  2240. allErrs = append(allErrs, field.Invalid(fieldPath, "", "may only be used when `type` is 'LoadBalancer'"))
  2241. }
  2242. _, err := apiservice.GetLoadBalancerSourceRanges(service)
  2243. if err != nil {
  2244. 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 "))
  2245. }
  2246. }
  2247. return allErrs
  2248. }
  2249. func validateServicePort(sp *api.ServicePort, requireName, isHeadlessService bool, allNames *sets.String, fldPath *field.Path) field.ErrorList {
  2250. allErrs := field.ErrorList{}
  2251. if requireName && len(sp.Name) == 0 {
  2252. allErrs = append(allErrs, field.Required(fldPath.Child("name"), ""))
  2253. } else if len(sp.Name) != 0 {
  2254. allErrs = append(allErrs, ValidateDNS1123Label(sp.Name, fldPath.Child("name"))...)
  2255. if allNames.Has(sp.Name) {
  2256. allErrs = append(allErrs, field.Duplicate(fldPath.Child("name"), sp.Name))
  2257. } else {
  2258. allNames.Insert(sp.Name)
  2259. }
  2260. }
  2261. for _, msg := range validation.IsValidPortNum(int(sp.Port)) {
  2262. allErrs = append(allErrs, field.Invalid(fldPath.Child("port"), sp.Port, msg))
  2263. }
  2264. if len(sp.Protocol) == 0 {
  2265. allErrs = append(allErrs, field.Required(fldPath.Child("protocol"), ""))
  2266. } else if !supportedPortProtocols.Has(string(sp.Protocol)) {
  2267. allErrs = append(allErrs, field.NotSupported(fldPath.Child("protocol"), sp.Protocol, supportedPortProtocols.List()))
  2268. }
  2269. allErrs = append(allErrs, ValidatePortNumOrName(sp.TargetPort, fldPath.Child("targetPort"))...)
  2270. // in the v1 API, targetPorts on headless services were tolerated.
  2271. // once we have version-specific validation, we can reject this on newer API versions, but until then, we have to tolerate it for compatibility.
  2272. //
  2273. // if isHeadlessService {
  2274. // if sp.TargetPort.Type == intstr.String || (sp.TargetPort.Type == intstr.Int && sp.Port != sp.TargetPort.IntValue()) {
  2275. // allErrs = append(allErrs, field.Invalid(fldPath.Child("targetPort"), sp.TargetPort, "must be equal to the value of 'port' when clusterIP = None"))
  2276. // }
  2277. // }
  2278. return allErrs
  2279. }
  2280. // ValidateServiceUpdate tests if required fields in the service are set during an update
  2281. func ValidateServiceUpdate(service, oldService *api.Service) field.ErrorList {
  2282. allErrs := ValidateObjectMetaUpdate(&service.ObjectMeta, &oldService.ObjectMeta, field.NewPath("metadata"))
  2283. if api.IsServiceIPSet(oldService) {
  2284. allErrs = append(allErrs, ValidateImmutableField(service.Spec.ClusterIP, oldService.Spec.ClusterIP, field.NewPath("spec", "clusterIP"))...)
  2285. }
  2286. allErrs = append(allErrs, ValidateService(service)...)
  2287. return allErrs
  2288. }
  2289. // ValidateServiceStatusUpdate tests if required fields in the Service are set when updating status.
  2290. func ValidateServiceStatusUpdate(service, oldService *api.Service) field.ErrorList {
  2291. allErrs := ValidateObjectMetaUpdate(&service.ObjectMeta, &oldService.ObjectMeta, field.NewPath("metadata"))
  2292. allErrs = append(allErrs, ValidateLoadBalancerStatus(&service.Status.LoadBalancer, field.NewPath("status", "loadBalancer"))...)
  2293. return allErrs
  2294. }
  2295. // ValidateReplicationController tests if required fields in the replication controller are set.
  2296. func ValidateReplicationController(controller *api.ReplicationController) field.ErrorList {
  2297. allErrs := ValidateObjectMeta(&controller.ObjectMeta, true, ValidateReplicationControllerName, field.NewPath("metadata"))
  2298. allErrs = append(allErrs, ValidateReplicationControllerSpec(&controller.Spec, field.NewPath("spec"))...)
  2299. return allErrs
  2300. }
  2301. // ValidateReplicationControllerUpdate tests if required fields in the replication controller are set.
  2302. func ValidateReplicationControllerUpdate(controller, oldController *api.ReplicationController) field.ErrorList {
  2303. allErrs := ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, field.NewPath("metadata"))
  2304. allErrs = append(allErrs, ValidateReplicationControllerSpec(&controller.Spec, field.NewPath("spec"))...)
  2305. return allErrs
  2306. }
  2307. // ValidateReplicationControllerStatusUpdate tests if required fields in the replication controller are set.
  2308. func ValidateReplicationControllerStatusUpdate(controller, oldController *api.ReplicationController) field.ErrorList {
  2309. allErrs := ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, field.NewPath("metadata"))
  2310. statusPath := field.NewPath("status")
  2311. allErrs = append(allErrs, ValidateNonnegativeField(int64(controller.Status.Replicas), statusPath.Child("replicas"))...)
  2312. allErrs = append(allErrs, ValidateNonnegativeField(int64(controller.Status.FullyLabeledReplicas), statusPath.Child("fullyLabeledReplicas"))...)
  2313. allErrs = append(allErrs, ValidateNonnegativeField(int64(controller.Status.ObservedGeneration), statusPath.Child("observedGeneration"))...)
  2314. return allErrs
  2315. }
  2316. // Validates that the given selector is non-empty.
  2317. func ValidateNonEmptySelector(selectorMap map[string]string, fldPath *field.Path) field.ErrorList {
  2318. allErrs := field.ErrorList{}
  2319. selector := labels.Set(selectorMap).AsSelector()
  2320. if selector.Empty() {
  2321. allErrs = append(allErrs, field.Required(fldPath, ""))
  2322. }
  2323. return allErrs
  2324. }
  2325. // Validates the given template and ensures that it is in accordance with the desired selector and replicas.
  2326. func ValidatePodTemplateSpecForRC(template *api.PodTemplateSpec, selectorMap map[string]string, replicas int32, fldPath *field.Path) field.ErrorList {
  2327. allErrs := field.ErrorList{}
  2328. if template == nil {
  2329. allErrs = append(allErrs, field.Required(fldPath, ""))
  2330. } else {
  2331. selector := labels.Set(selectorMap).AsSelector()
  2332. if !selector.Empty() {
  2333. // Verify that the RC selector matches the labels in template.
  2334. labels := labels.Set(template.Labels)
  2335. if !selector.Matches(labels) {
  2336. allErrs = append(allErrs, field.Invalid(fldPath.Child("metadata", "labels"), template.Labels, "`selector` does not match template `labels`"))
  2337. }
  2338. }
  2339. allErrs = append(allErrs, ValidatePodTemplateSpec(template, fldPath)...)
  2340. if replicas > 1 {
  2341. allErrs = append(allErrs, ValidateReadOnlyPersistentDisks(template.Spec.Volumes, fldPath.Child("spec", "volumes"))...)
  2342. }
  2343. // RestartPolicy has already been first-order validated as per ValidatePodTemplateSpec().
  2344. if template.Spec.RestartPolicy != api.RestartPolicyAlways {
  2345. allErrs = append(allErrs, field.NotSupported(fldPath.Child("spec", "restartPolicy"), template.Spec.RestartPolicy, []string{string(api.RestartPolicyAlways)}))
  2346. }
  2347. }
  2348. return allErrs
  2349. }
  2350. // ValidateReplicationControllerSpec tests if required fields in the replication controller spec are set.
  2351. func ValidateReplicationControllerSpec(spec *api.ReplicationControllerSpec, fldPath *field.Path) field.ErrorList {
  2352. allErrs := field.ErrorList{}
  2353. allErrs = append(allErrs, ValidateNonEmptySelector(spec.Selector, fldPath.Child("selector"))...)
  2354. allErrs = append(allErrs, ValidateNonnegativeField(int64(spec.Replicas), fldPath.Child("replicas"))...)
  2355. allErrs = append(allErrs, ValidatePodTemplateSpecForRC(spec.Template, spec.Selector, spec.Replicas, fldPath.Child("template"))...)
  2356. return allErrs
  2357. }
  2358. // ValidatePodTemplateSpec validates the spec of a pod template
  2359. func ValidatePodTemplateSpec(spec *api.PodTemplateSpec, fldPath *field.Path) field.ErrorList {
  2360. allErrs := field.ErrorList{}
  2361. allErrs = append(allErrs, unversionedvalidation.ValidateLabels(spec.Labels, fldPath.Child("labels"))...)
  2362. allErrs = append(allErrs, ValidateAnnotations(spec.Annotations, fldPath.Child("annotations"))...)
  2363. allErrs = append(allErrs, ValidatePodSpecificAnnotations(spec.Annotations, &spec.Spec, fldPath.Child("annotations"))...)
  2364. allErrs = append(allErrs, ValidatePodSpec(&spec.Spec, fldPath.Child("spec"))...)
  2365. return allErrs
  2366. }
  2367. func ValidateReadOnlyPersistentDisks(volumes []api.Volume, fldPath *field.Path) field.ErrorList {
  2368. allErrs := field.ErrorList{}
  2369. for i := range volumes {
  2370. vol := &volumes[i]
  2371. idxPath := fldPath.Index(i)
  2372. if vol.GCEPersistentDisk != nil {
  2373. if vol.GCEPersistentDisk.ReadOnly == false {
  2374. 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"))
  2375. }
  2376. }
  2377. // TODO: What to do for AWS? It doesn't support replicas
  2378. }
  2379. return allErrs
  2380. }
  2381. // validateTaints tests if given taints have valid data.
  2382. func validateTaints(taints []api.Taint, fldPath *field.Path) field.ErrorList {
  2383. allErrors := field.ErrorList{}
  2384. uniqueTaints := map[api.TaintEffect]sets.String{}
  2385. for i, currTaint := range taints {
  2386. idxPath := fldPath.Index(i)
  2387. // validate the taint key
  2388. allErrors = append(allErrors, unversionedvalidation.ValidateLabelName(currTaint.Key, idxPath.Child("key"))...)
  2389. // validate the taint value
  2390. if errs := validation.IsValidLabelValue(currTaint.Value); len(errs) != 0 {
  2391. allErrors = append(allErrors, field.Invalid(idxPath.Child("value"), currTaint.Value, strings.Join(errs, ";")))
  2392. }
  2393. // validate the taint effect
  2394. allErrors = append(allErrors, validateTaintEffect(&currTaint.Effect, false, idxPath.Child("effect"))...)
  2395. // validate if taint is unique by <key, effect>
  2396. if len(uniqueTaints[currTaint.Effect]) > 0 && uniqueTaints[currTaint.Effect].Has(currTaint.Key) {
  2397. duplicatedError := field.Duplicate(idxPath, currTaint)
  2398. duplicatedError.Detail = "taints must be unique by key and effect pair"
  2399. allErrors = append(allErrors, duplicatedError)
  2400. continue
  2401. }
  2402. // add taint to existingTaints for uniqueness check
  2403. if len(uniqueTaints[currTaint.Effect]) == 0 {
  2404. uniqueTaints[currTaint.Effect] = sets.String{}
  2405. }
  2406. uniqueTaints[currTaint.Effect].Insert(currTaint.Key)
  2407. }
  2408. return allErrors
  2409. }
  2410. // ValidateTaintsInNodeAnnotations tests that the serialized taints in Node.Annotations has valid data
  2411. func ValidateTaintsInNodeAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
  2412. allErrs := field.ErrorList{}
  2413. taints, err := api.GetTaintsFromNodeAnnotations(annotations)
  2414. if err != nil {
  2415. allErrs = append(allErrs, field.Invalid(fldPath, api.TaintsAnnotationKey, err.Error()))
  2416. return allErrs
  2417. }
  2418. if len(taints) > 0 {
  2419. allErrs = append(allErrs, validateTaints(taints, fldPath.Child(api.TaintsAnnotationKey))...)
  2420. }
  2421. return allErrs
  2422. }
  2423. func ValidateNodeSpecificAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
  2424. allErrs := field.ErrorList{}
  2425. if annotations[api.PreferAvoidPodsAnnotationKey] != "" {
  2426. allErrs = append(allErrs, ValidateAvoidPodsInNodeAnnotations(annotations, fldPath)...)
  2427. }
  2428. if annotations[api.TaintsAnnotationKey] != "" {
  2429. allErrs = append(allErrs, ValidateTaintsInNodeAnnotations(annotations, fldPath)...)
  2430. }
  2431. return allErrs
  2432. }
  2433. // ValidateNode tests if required fields in the node are set.
  2434. func ValidateNode(node *api.Node) field.ErrorList {
  2435. fldPath := field.NewPath("metadata")
  2436. allErrs := ValidateObjectMeta(&node.ObjectMeta, false, ValidateNodeName, fldPath)
  2437. allErrs = append(allErrs, ValidateNodeSpecificAnnotations(node.ObjectMeta.Annotations, fldPath.Child("annotations"))...)
  2438. // Only validate spec. All status fields are optional and can be updated later.
  2439. // external ID is required.
  2440. if len(node.Spec.ExternalID) == 0 {
  2441. allErrs = append(allErrs, field.Required(field.NewPath("spec", "externalID"), ""))
  2442. }
  2443. // TODO(rjnagal): Ignore PodCIDR till its completely implemented.
  2444. return allErrs
  2445. }
  2446. // ValidateNodeUpdate tests to make sure a node update can be applied. Modifies oldNode.
  2447. func ValidateNodeUpdate(node, oldNode *api.Node) field.ErrorList {
  2448. fldPath := field.NewPath("metadata")
  2449. allErrs := ValidateObjectMetaUpdate(&node.ObjectMeta, &oldNode.ObjectMeta, fldPath)
  2450. allErrs = append(allErrs, ValidateNodeSpecificAnnotations(node.ObjectMeta.Annotations, fldPath.Child("annotations"))...)
  2451. // TODO: Enable the code once we have better api object.status update model. Currently,
  2452. // anyone can update node status.
  2453. // if !api.Semantic.DeepEqual(node.Status, api.NodeStatus{}) {
  2454. // allErrs = append(allErrs, field.Invalid("status", node.Status, "must be empty"))
  2455. // }
  2456. // Validte no duplicate addresses in node status.
  2457. addresses := make(map[api.NodeAddress]bool)
  2458. for i, address := range node.Status.Addresses {
  2459. if _, ok := addresses[address]; ok {
  2460. allErrs = append(allErrs, field.Duplicate(field.NewPath("status", "addresses").Index(i), address))
  2461. }
  2462. addresses[address] = true
  2463. }
  2464. if len(oldNode.Spec.PodCIDR) == 0 {
  2465. // Allow the controller manager to assign a CIDR to a node if it doesn't have one.
  2466. oldNode.Spec.PodCIDR = node.Spec.PodCIDR
  2467. } else {
  2468. if oldNode.Spec.PodCIDR != node.Spec.PodCIDR {
  2469. allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "podCIDR"), "node updates may not change podCIDR except from \"\" to valid"))
  2470. }
  2471. }
  2472. // TODO: move reset function to its own location
  2473. // Ignore metadata changes now that they have been tested
  2474. oldNode.ObjectMeta = node.ObjectMeta
  2475. // Allow users to update capacity
  2476. oldNode.Status.Capacity = node.Status.Capacity
  2477. // Allow users to unschedule node
  2478. oldNode.Spec.Unschedulable = node.Spec.Unschedulable
  2479. // Clear status
  2480. oldNode.Status = node.Status
  2481. // TODO: Add a 'real' error type for this error and provide print actual diffs.
  2482. if !api.Semantic.DeepEqual(oldNode, node) {
  2483. glog.V(4).Infof("Update failed validation %#v vs %#v", oldNode, node)
  2484. allErrs = append(allErrs, field.Forbidden(field.NewPath(""), "node updates may only change labels or capacity"))
  2485. }
  2486. return allErrs
  2487. }
  2488. // Validate compute resource typename.
  2489. // Refer to docs/design/resources.md for more details.
  2490. func validateResourceName(value string, fldPath *field.Path) field.ErrorList {
  2491. allErrs := field.ErrorList{}
  2492. for _, msg := range validation.IsQualifiedName(value) {
  2493. allErrs = append(allErrs, field.Invalid(fldPath, value, msg))
  2494. }
  2495. if len(allErrs) != 0 {
  2496. return allErrs
  2497. }
  2498. if len(strings.Split(value, "/")) == 1 {
  2499. if !api.IsStandardResourceName(value) {
  2500. return append(allErrs, field.Invalid(fldPath, value, "must be a standard resource type or fully qualified"))
  2501. }
  2502. }
  2503. return field.ErrorList{}
  2504. }
  2505. // Validate container resource name
  2506. // Refer to docs/design/resources.md for more details.
  2507. func validateContainerResourceName(value string, fldPath *field.Path) field.ErrorList {
  2508. allErrs := validateResourceName(value, fldPath)
  2509. if len(strings.Split(value, "/")) == 1 {
  2510. if !api.IsStandardContainerResourceName(value) {
  2511. return append(allErrs, field.Invalid(fldPath, value, "must be a standard resource for containers"))
  2512. }
  2513. }
  2514. return field.ErrorList{}
  2515. }
  2516. // Validate resource names that can go in a resource quota
  2517. // Refer to docs/design/resources.md for more details.
  2518. func ValidateResourceQuotaResourceName(value string, fldPath *field.Path) field.ErrorList {
  2519. allErrs := validateResourceName(value, fldPath)
  2520. if len(strings.Split(value, "/")) == 1 {
  2521. if !api.IsStandardQuotaResourceName(value) {
  2522. return append(allErrs, field.Invalid(fldPath, value, isInvalidQuotaResource))
  2523. }
  2524. }
  2525. return field.ErrorList{}
  2526. }
  2527. // Validate limit range types
  2528. func validateLimitRangeTypeName(value string, fldPath *field.Path) field.ErrorList {
  2529. allErrs := field.ErrorList{}
  2530. for _, msg := range validation.IsQualifiedName(value) {
  2531. allErrs = append(allErrs, field.Invalid(fldPath, value, msg))
  2532. }
  2533. if len(allErrs) != 0 {
  2534. return allErrs
  2535. }
  2536. if len(strings.Split(value, "/")) == 1 {
  2537. if !api.IsStandardLimitRangeType(value) {
  2538. return append(allErrs, field.Invalid(fldPath, value, "must be a standard limit type or fully qualified"))
  2539. }
  2540. }
  2541. return allErrs
  2542. }
  2543. // Validate limit range resource name
  2544. // limit types (other than Pod/Container) could contain storage not just cpu or memory
  2545. func validateLimitRangeResourceName(limitType api.LimitType, value string, fldPath *field.Path) field.ErrorList {
  2546. switch limitType {
  2547. case api.LimitTypePod, api.LimitTypeContainer:
  2548. return validateContainerResourceName(value, fldPath)
  2549. default:
  2550. return validateResourceName(value, fldPath)
  2551. }
  2552. }
  2553. // ValidateLimitRange tests if required fields in the LimitRange are set.
  2554. func ValidateLimitRange(limitRange *api.LimitRange) field.ErrorList {
  2555. allErrs := ValidateObjectMeta(&limitRange.ObjectMeta, true, ValidateLimitRangeName, field.NewPath("metadata"))
  2556. // ensure resource names are properly qualified per docs/design/resources.md
  2557. limitTypeSet := map[api.LimitType]bool{}
  2558. fldPath := field.NewPath("spec", "limits")
  2559. for i := range limitRange.Spec.Limits {
  2560. idxPath := fldPath.Index(i)
  2561. limit := &limitRange.Spec.Limits[i]
  2562. allErrs = append(allErrs, validateLimitRangeTypeName(string(limit.Type), idxPath.Child("type"))...)
  2563. _, found := limitTypeSet[limit.Type]
  2564. if found {
  2565. allErrs = append(allErrs, field.Duplicate(idxPath.Child("type"), limit.Type))
  2566. }
  2567. limitTypeSet[limit.Type] = true
  2568. keys := sets.String{}
  2569. min := map[string]resource.Quantity{}
  2570. max := map[string]resource.Quantity{}
  2571. defaults := map[string]resource.Quantity{}
  2572. defaultRequests := map[string]resource.Quantity{}
  2573. maxLimitRequestRatios := map[string]resource.Quantity{}
  2574. for k, q := range limit.Max {
  2575. allErrs = append(allErrs, validateLimitRangeResourceName(limit.Type, string(k), idxPath.Child("max").Key(string(k)))...)
  2576. keys.Insert(string(k))
  2577. max[string(k)] = q
  2578. }
  2579. for k, q := range limit.Min {
  2580. allErrs = append(allErrs, validateLimitRangeResourceName(limit.Type, string(k), idxPath.Child("min").Key(string(k)))...)
  2581. keys.Insert(string(k))
  2582. min[string(k)] = q
  2583. }
  2584. if limit.Type == api.LimitTypePod {
  2585. if len(limit.Default) > 0 {
  2586. allErrs = append(allErrs, field.Forbidden(idxPath.Child("default"), "may not be specified when `type` is 'Pod'"))
  2587. }
  2588. if len(limit.DefaultRequest) > 0 {
  2589. allErrs = append(allErrs, field.Forbidden(idxPath.Child("defaultRequest"), "may not be specified when `type` is 'Pod'"))
  2590. }
  2591. } else {
  2592. for k, q := range limit.Default {
  2593. allErrs = append(allErrs, validateLimitRangeResourceName(limit.Type, string(k), idxPath.Child("default").Key(string(k)))...)
  2594. keys.Insert(string(k))
  2595. defaults[string(k)] = q
  2596. }
  2597. for k, q := range limit.DefaultRequest {
  2598. allErrs = append(allErrs, validateLimitRangeResourceName(limit.Type, string(k), idxPath.Child("defaultRequest").Key(string(k)))...)
  2599. keys.Insert(string(k))
  2600. defaultRequests[string(k)] = q
  2601. }
  2602. }
  2603. for k, q := range limit.MaxLimitRequestRatio {
  2604. allErrs = append(allErrs, validateLimitRangeResourceName(limit.Type, string(k), idxPath.Child("maxLimitRequestRatio").Key(string(k)))...)
  2605. keys.Insert(string(k))
  2606. maxLimitRequestRatios[string(k)] = q
  2607. }
  2608. for k := range keys {
  2609. minQuantity, minQuantityFound := min[k]
  2610. maxQuantity, maxQuantityFound := max[k]
  2611. defaultQuantity, defaultQuantityFound := defaults[k]
  2612. defaultRequestQuantity, defaultRequestQuantityFound := defaultRequests[k]
  2613. maxRatio, maxRatioFound := maxLimitRequestRatios[k]
  2614. if minQuantityFound && maxQuantityFound && minQuantity.Cmp(maxQuantity) > 0 {
  2615. 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())))
  2616. }
  2617. if defaultRequestQuantityFound && minQuantityFound && minQuantity.Cmp(defaultRequestQuantity) > 0 {
  2618. 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())))
  2619. }
  2620. if defaultRequestQuantityFound && maxQuantityFound && defaultRequestQuantity.Cmp(maxQuantity) > 0 {
  2621. 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())))
  2622. }
  2623. if defaultRequestQuantityFound && defaultQuantityFound && defaultRequestQuantity.Cmp(defaultQuantity) > 0 {
  2624. 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())))
  2625. }
  2626. if defaultQuantityFound && minQuantityFound && minQuantity.Cmp(defaultQuantity) > 0 {
  2627. 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())))
  2628. }
  2629. if defaultQuantityFound && maxQuantityFound && defaultQuantity.Cmp(maxQuantity) > 0 {
  2630. 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())))
  2631. }
  2632. if maxRatioFound && maxRatio.Cmp(*resource.NewQuantity(1, resource.DecimalSI)) < 0 {
  2633. allErrs = append(allErrs, field.Invalid(idxPath.Child("maxLimitRequestRatio").Key(string(k)), maxRatio, fmt.Sprintf("ratio %s is less than 1", maxRatio.String())))
  2634. }
  2635. if maxRatioFound && minQuantityFound && maxQuantityFound {
  2636. maxRatioValue := float64(maxRatio.Value())
  2637. minQuantityValue := minQuantity.Value()
  2638. maxQuantityValue := maxQuantity.Value()
  2639. if maxRatio.Value() < resource.MaxMilliValue && minQuantityValue < resource.MaxMilliValue && maxQuantityValue < resource.MaxMilliValue {
  2640. maxRatioValue = float64(maxRatio.MilliValue()) / 1000
  2641. minQuantityValue = minQuantity.MilliValue()
  2642. maxQuantityValue = maxQuantity.MilliValue()
  2643. }
  2644. maxRatioLimit := float64(maxQuantityValue) / float64(minQuantityValue)
  2645. if maxRatioValue > maxRatioLimit {
  2646. 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)))
  2647. }
  2648. }
  2649. }
  2650. }
  2651. return allErrs
  2652. }
  2653. // ValidateServiceAccount tests if required fields in the ServiceAccount are set.
  2654. func ValidateServiceAccount(serviceAccount *api.ServiceAccount) field.ErrorList {
  2655. allErrs := ValidateObjectMeta(&serviceAccount.ObjectMeta, true, ValidateServiceAccountName, field.NewPath("metadata"))
  2656. return allErrs
  2657. }
  2658. // ValidateServiceAccountUpdate tests if required fields in the ServiceAccount are set.
  2659. func ValidateServiceAccountUpdate(newServiceAccount, oldServiceAccount *api.ServiceAccount) field.ErrorList {
  2660. allErrs := ValidateObjectMetaUpdate(&newServiceAccount.ObjectMeta, &oldServiceAccount.ObjectMeta, field.NewPath("metadata"))
  2661. allErrs = append(allErrs, ValidateServiceAccount(newServiceAccount)...)
  2662. return allErrs
  2663. }
  2664. // ValidateSecret tests if required fields in the Secret are set.
  2665. func ValidateSecret(secret *api.Secret) field.ErrorList {
  2666. allErrs := ValidateObjectMeta(&secret.ObjectMeta, true, ValidateSecretName, field.NewPath("metadata"))
  2667. dataPath := field.NewPath("data")
  2668. totalSize := 0
  2669. for key, value := range secret.Data {
  2670. for _, msg := range validation.IsConfigMapKey(key) {
  2671. allErrs = append(allErrs, field.Invalid(dataPath.Key(key), key, msg))
  2672. }
  2673. totalSize += len(value)
  2674. }
  2675. if totalSize > api.MaxSecretSize {
  2676. allErrs = append(allErrs, field.TooLong(dataPath, "", api.MaxSecretSize))
  2677. }
  2678. switch secret.Type {
  2679. case api.SecretTypeServiceAccountToken:
  2680. // Only require Annotations[kubernetes.io/service-account.name]
  2681. // Additional fields (like Annotations[kubernetes.io/service-account.uid] and Data[token]) might be contributed later by a controller loop
  2682. if value := secret.Annotations[api.ServiceAccountNameKey]; len(value) == 0 {
  2683. allErrs = append(allErrs, field.Required(field.NewPath("metadata", "annotations").Key(api.ServiceAccountNameKey), ""))
  2684. }
  2685. case api.SecretTypeOpaque, "":
  2686. // no-op
  2687. case api.SecretTypeDockercfg:
  2688. dockercfgBytes, exists := secret.Data[api.DockerConfigKey]
  2689. if !exists {
  2690. allErrs = append(allErrs, field.Required(dataPath.Key(api.DockerConfigKey), ""))
  2691. break
  2692. }
  2693. // make sure that the content is well-formed json.
  2694. if err := json.Unmarshal(dockercfgBytes, &map[string]interface{}{}); err != nil {
  2695. allErrs = append(allErrs, field.Invalid(dataPath.Key(api.DockerConfigKey), "<secret contents redacted>", err.Error()))
  2696. }
  2697. case api.SecretTypeDockerConfigJson:
  2698. dockerConfigJsonBytes, exists := secret.Data[api.DockerConfigJsonKey]
  2699. if !exists {
  2700. allErrs = append(allErrs, field.Required(dataPath.Key(api.DockerConfigJsonKey), ""))
  2701. break
  2702. }
  2703. // make sure that the content is well-formed json.
  2704. if err := json.Unmarshal(dockerConfigJsonBytes, &map[string]interface{}{}); err != nil {
  2705. allErrs = append(allErrs, field.Invalid(dataPath.Key(api.DockerConfigJsonKey), "<secret contents redacted>", err.Error()))
  2706. }
  2707. case api.SecretTypeBasicAuth:
  2708. _, usernameFieldExists := secret.Data[api.BasicAuthUsernameKey]
  2709. _, passwordFieldExists := secret.Data[api.BasicAuthPasswordKey]
  2710. // username or password might be empty, but the field must be present
  2711. if !usernameFieldExists && !passwordFieldExists {
  2712. allErrs = append(allErrs, field.Required(field.NewPath("data[%s]").Key(api.BasicAuthUsernameKey), ""))
  2713. allErrs = append(allErrs, field.Required(field.NewPath("data[%s]").Key(api.BasicAuthPasswordKey), ""))
  2714. break
  2715. }
  2716. case api.SecretTypeSSHAuth:
  2717. if len(secret.Data[api.SSHAuthPrivateKey]) == 0 {
  2718. allErrs = append(allErrs, field.Required(field.NewPath("data[%s]").Key(api.SSHAuthPrivateKey), ""))
  2719. break
  2720. }
  2721. case api.SecretTypeTLS:
  2722. if _, exists := secret.Data[api.TLSCertKey]; !exists {
  2723. allErrs = append(allErrs, field.Required(dataPath.Key(api.TLSCertKey), ""))
  2724. }
  2725. if _, exists := secret.Data[api.TLSPrivateKeyKey]; !exists {
  2726. allErrs = append(allErrs, field.Required(dataPath.Key(api.TLSPrivateKeyKey), ""))
  2727. }
  2728. // TODO: Verify that the key matches the cert.
  2729. default:
  2730. // no-op
  2731. }
  2732. return allErrs
  2733. }
  2734. // ValidateSecretUpdate tests if required fields in the Secret are set.
  2735. func ValidateSecretUpdate(newSecret, oldSecret *api.Secret) field.ErrorList {
  2736. allErrs := ValidateObjectMetaUpdate(&newSecret.ObjectMeta, &oldSecret.ObjectMeta, field.NewPath("metadata"))
  2737. if len(newSecret.Type) == 0 {
  2738. newSecret.Type = oldSecret.Type
  2739. }
  2740. allErrs = append(allErrs, ValidateImmutableField(newSecret.Type, oldSecret.Type, field.NewPath("type"))...)
  2741. allErrs = append(allErrs, ValidateSecret(newSecret)...)
  2742. return allErrs
  2743. }
  2744. // ValidateConfigMapName can be used to check whether the given ConfigMap name is valid.
  2745. // Prefix indicates this name will be used as part of generation, in which case
  2746. // trailing dashes are allowed.
  2747. var ValidateConfigMapName = NameIsDNSSubdomain
  2748. // ValidateConfigMap tests whether required fields in the ConfigMap are set.
  2749. func ValidateConfigMap(cfg *api.ConfigMap) field.ErrorList {
  2750. allErrs := field.ErrorList{}
  2751. allErrs = append(allErrs, ValidateObjectMeta(&cfg.ObjectMeta, true, ValidateConfigMapName, field.NewPath("metadata"))...)
  2752. totalSize := 0
  2753. for key, value := range cfg.Data {
  2754. for _, msg := range validation.IsConfigMapKey(key) {
  2755. allErrs = append(allErrs, field.Invalid(field.NewPath("data").Key(key), key, msg))
  2756. }
  2757. totalSize += len(value)
  2758. }
  2759. if totalSize > api.MaxSecretSize {
  2760. allErrs = append(allErrs, field.TooLong(field.NewPath("data"), "", api.MaxSecretSize))
  2761. }
  2762. return allErrs
  2763. }
  2764. // ValidateConfigMapUpdate tests if required fields in the ConfigMap are set.
  2765. func ValidateConfigMapUpdate(newCfg, oldCfg *api.ConfigMap) field.ErrorList {
  2766. allErrs := field.ErrorList{}
  2767. allErrs = append(allErrs, ValidateObjectMetaUpdate(&newCfg.ObjectMeta, &oldCfg.ObjectMeta, field.NewPath("metadata"))...)
  2768. allErrs = append(allErrs, ValidateConfigMap(newCfg)...)
  2769. return allErrs
  2770. }
  2771. func validateBasicResource(quantity resource.Quantity, fldPath *field.Path) field.ErrorList {
  2772. if quantity.Value() < 0 {
  2773. return field.ErrorList{field.Invalid(fldPath, quantity.Value(), "must be a valid resource quantity")}
  2774. }
  2775. return field.ErrorList{}
  2776. }
  2777. // Validates resource requirement spec.
  2778. func ValidateResourceRequirements(requirements *api.ResourceRequirements, fldPath *field.Path) field.ErrorList {
  2779. allErrs := field.ErrorList{}
  2780. limPath := fldPath.Child("limits")
  2781. reqPath := fldPath.Child("requests")
  2782. for resourceName, quantity := range requirements.Limits {
  2783. fldPath := limPath.Key(string(resourceName))
  2784. // Validate resource name.
  2785. allErrs = append(allErrs, validateContainerResourceName(string(resourceName), fldPath)...)
  2786. if api.IsStandardResourceName(string(resourceName)) {
  2787. allErrs = append(allErrs, validateBasicResource(quantity, fldPath.Key(string(resourceName)))...)
  2788. }
  2789. // Check that request <= limit.
  2790. requestQuantity, exists := requirements.Requests[resourceName]
  2791. if exists {
  2792. // For GPUs, not only requests can't exceed limits, they also can't be lower, i.e. must be equal.
  2793. if resourceName == api.ResourceNvidiaGPU && quantity.Cmp(requestQuantity) != 0 {
  2794. allErrs = append(allErrs, field.Invalid(reqPath, requestQuantity.String(), fmt.Sprintf("must be equal to %s limit", api.ResourceNvidiaGPU)))
  2795. } else if quantity.Cmp(requestQuantity) < 0 {
  2796. allErrs = append(allErrs, field.Invalid(limPath, quantity.String(), fmt.Sprintf("must be greater than or equal to %s request", resourceName)))
  2797. }
  2798. }
  2799. }
  2800. for resourceName, quantity := range requirements.Requests {
  2801. fldPath := reqPath.Key(string(resourceName))
  2802. // Validate resource name.
  2803. allErrs = append(allErrs, validateContainerResourceName(string(resourceName), fldPath)...)
  2804. if api.IsStandardResourceName(string(resourceName)) {
  2805. allErrs = append(allErrs, validateBasicResource(quantity, fldPath.Key(string(resourceName)))...)
  2806. }
  2807. }
  2808. return allErrs
  2809. }
  2810. // validateResourceQuotaScopes ensures that each enumerated hard resource constraint is valid for set of scopes
  2811. func validateResourceQuotaScopes(resourceQuotaSpec *api.ResourceQuotaSpec, fld *field.Path) field.ErrorList {
  2812. allErrs := field.ErrorList{}
  2813. if len(resourceQuotaSpec.Scopes) == 0 {
  2814. return allErrs
  2815. }
  2816. hardLimits := sets.NewString()
  2817. for k := range resourceQuotaSpec.Hard {
  2818. hardLimits.Insert(string(k))
  2819. }
  2820. fldPath := fld.Child("scopes")
  2821. scopeSet := sets.NewString()
  2822. for _, scope := range resourceQuotaSpec.Scopes {
  2823. if !api.IsStandardResourceQuotaScope(string(scope)) {
  2824. allErrs = append(allErrs, field.Invalid(fldPath, resourceQuotaSpec.Scopes, "unsupported scope"))
  2825. }
  2826. for _, k := range hardLimits.List() {
  2827. if api.IsStandardQuotaResourceName(k) && !api.IsResourceQuotaScopeValidForResource(scope, k) {
  2828. allErrs = append(allErrs, field.Invalid(fldPath, resourceQuotaSpec.Scopes, "unsupported scope applied to resource"))
  2829. }
  2830. }
  2831. scopeSet.Insert(string(scope))
  2832. }
  2833. invalidScopePairs := []sets.String{
  2834. sets.NewString(string(api.ResourceQuotaScopeBestEffort), string(api.ResourceQuotaScopeNotBestEffort)),
  2835. sets.NewString(string(api.ResourceQuotaScopeTerminating), string(api.ResourceQuotaScopeNotTerminating)),
  2836. }
  2837. for _, invalidScopePair := range invalidScopePairs {
  2838. if scopeSet.HasAll(invalidScopePair.List()...) {
  2839. allErrs = append(allErrs, field.Invalid(fldPath, resourceQuotaSpec.Scopes, "conflicting scopes"))
  2840. }
  2841. }
  2842. return allErrs
  2843. }
  2844. // ValidateResourceQuota tests if required fields in the ResourceQuota are set.
  2845. func ValidateResourceQuota(resourceQuota *api.ResourceQuota) field.ErrorList {
  2846. allErrs := ValidateObjectMeta(&resourceQuota.ObjectMeta, true, ValidateResourceQuotaName, field.NewPath("metadata"))
  2847. allErrs = append(allErrs, ValidateResourceQuotaSpec(&resourceQuota.Spec, field.NewPath("spec"))...)
  2848. allErrs = append(allErrs, ValidateResourceQuotaStatus(&resourceQuota.Status, field.NewPath("status"))...)
  2849. return allErrs
  2850. }
  2851. func ValidateResourceQuotaStatus(status *api.ResourceQuotaStatus, fld *field.Path) field.ErrorList {
  2852. allErrs := field.ErrorList{}
  2853. fldPath := fld.Child("hard")
  2854. for k, v := range status.Hard {
  2855. resPath := fldPath.Key(string(k))
  2856. allErrs = append(allErrs, ValidateResourceQuotaResourceName(string(k), resPath)...)
  2857. allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...)
  2858. }
  2859. fldPath = fld.Child("used")
  2860. for k, v := range status.Used {
  2861. resPath := fldPath.Key(string(k))
  2862. allErrs = append(allErrs, ValidateResourceQuotaResourceName(string(k), resPath)...)
  2863. allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...)
  2864. }
  2865. return allErrs
  2866. }
  2867. func ValidateResourceQuotaSpec(resourceQuotaSpec *api.ResourceQuotaSpec, fld *field.Path) field.ErrorList {
  2868. allErrs := field.ErrorList{}
  2869. fldPath := fld.Child("hard")
  2870. for k, v := range resourceQuotaSpec.Hard {
  2871. resPath := fldPath.Key(string(k))
  2872. allErrs = append(allErrs, ValidateResourceQuotaResourceName(string(k), resPath)...)
  2873. allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...)
  2874. }
  2875. allErrs = append(allErrs, validateResourceQuotaScopes(resourceQuotaSpec, fld)...)
  2876. return allErrs
  2877. }
  2878. // ValidateResourceQuantityValue enforces that specified quantity is valid for specified resource
  2879. func ValidateResourceQuantityValue(resource string, value resource.Quantity, fldPath *field.Path) field.ErrorList {
  2880. allErrs := field.ErrorList{}
  2881. allErrs = append(allErrs, ValidateNonnegativeQuantity(value, fldPath)...)
  2882. if api.IsIntegerResourceName(resource) {
  2883. if value.MilliValue()%int64(1000) != int64(0) {
  2884. allErrs = append(allErrs, field.Invalid(fldPath, value, isNotIntegerErrorMsg))
  2885. }
  2886. }
  2887. return allErrs
  2888. }
  2889. // ValidateResourceQuotaUpdate tests to see if the update is legal for an end user to make.
  2890. // newResourceQuota is updated with fields that cannot be changed.
  2891. func ValidateResourceQuotaUpdate(newResourceQuota, oldResourceQuota *api.ResourceQuota) field.ErrorList {
  2892. allErrs := ValidateObjectMetaUpdate(&newResourceQuota.ObjectMeta, &oldResourceQuota.ObjectMeta, field.NewPath("metadata"))
  2893. allErrs = append(allErrs, ValidateResourceQuotaSpec(&newResourceQuota.Spec, field.NewPath("spec"))...)
  2894. // ensure scopes cannot change, and that resources are still valid for scope
  2895. fldPath := field.NewPath("spec", "scopes")
  2896. oldScopes := sets.NewString()
  2897. newScopes := sets.NewString()
  2898. for _, scope := range newResourceQuota.Spec.Scopes {
  2899. newScopes.Insert(string(scope))
  2900. }
  2901. for _, scope := range oldResourceQuota.Spec.Scopes {
  2902. oldScopes.Insert(string(scope))
  2903. }
  2904. if !oldScopes.Equal(newScopes) {
  2905. allErrs = append(allErrs, field.Invalid(fldPath, newResourceQuota.Spec.Scopes, "field is immutable"))
  2906. }
  2907. newResourceQuota.Status = oldResourceQuota.Status
  2908. return allErrs
  2909. }
  2910. // ValidateResourceQuotaStatusUpdate tests to see if the status update is legal for an end user to make.
  2911. // newResourceQuota is updated with fields that cannot be changed.
  2912. func ValidateResourceQuotaStatusUpdate(newResourceQuota, oldResourceQuota *api.ResourceQuota) field.ErrorList {
  2913. allErrs := ValidateObjectMetaUpdate(&newResourceQuota.ObjectMeta, &oldResourceQuota.ObjectMeta, field.NewPath("metadata"))
  2914. if len(newResourceQuota.ResourceVersion) == 0 {
  2915. allErrs = append(allErrs, field.Required(field.NewPath("resourceVersion"), ""))
  2916. }
  2917. fldPath := field.NewPath("status", "hard")
  2918. for k, v := range newResourceQuota.Status.Hard {
  2919. resPath := fldPath.Key(string(k))
  2920. allErrs = append(allErrs, ValidateResourceQuotaResourceName(string(k), resPath)...)
  2921. allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...)
  2922. }
  2923. fldPath = field.NewPath("status", "used")
  2924. for k, v := range newResourceQuota.Status.Used {
  2925. resPath := fldPath.Key(string(k))
  2926. allErrs = append(allErrs, ValidateResourceQuotaResourceName(string(k), resPath)...)
  2927. allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...)
  2928. }
  2929. newResourceQuota.Spec = oldResourceQuota.Spec
  2930. return allErrs
  2931. }
  2932. // ValidateNamespace tests if required fields are set.
  2933. func ValidateNamespace(namespace *api.Namespace) field.ErrorList {
  2934. allErrs := ValidateObjectMeta(&namespace.ObjectMeta, false, ValidateNamespaceName, field.NewPath("metadata"))
  2935. for i := range namespace.Spec.Finalizers {
  2936. allErrs = append(allErrs, validateFinalizerName(string(namespace.Spec.Finalizers[i]), field.NewPath("spec", "finalizers"))...)
  2937. }
  2938. return allErrs
  2939. }
  2940. // Validate finalizer names
  2941. func validateFinalizerName(stringValue string, fldPath *field.Path) field.ErrorList {
  2942. allErrs := field.ErrorList{}
  2943. for _, msg := range validation.IsQualifiedName(stringValue) {
  2944. allErrs = append(allErrs, field.Invalid(fldPath, stringValue, msg))
  2945. }
  2946. if len(allErrs) != 0 {
  2947. return allErrs
  2948. }
  2949. if len(strings.Split(stringValue, "/")) == 1 {
  2950. if !api.IsStandardFinalizerName(stringValue) {
  2951. return append(allErrs, field.Invalid(fldPath, stringValue, "name is neither a standard finalizer name nor is it fully qualified"))
  2952. }
  2953. }
  2954. return field.ErrorList{}
  2955. }
  2956. // ValidateNamespaceUpdate tests to make sure a namespace update can be applied.
  2957. // newNamespace is updated with fields that cannot be changed
  2958. func ValidateNamespaceUpdate(newNamespace *api.Namespace, oldNamespace *api.Namespace) field.ErrorList {
  2959. allErrs := ValidateObjectMetaUpdate(&newNamespace.ObjectMeta, &oldNamespace.ObjectMeta, field.NewPath("metadata"))
  2960. newNamespace.Spec.Finalizers = oldNamespace.Spec.Finalizers
  2961. newNamespace.Status = oldNamespace.Status
  2962. return allErrs
  2963. }
  2964. // ValidateNamespaceStatusUpdate tests to see if the update is legal for an end user to make. newNamespace is updated with fields
  2965. // that cannot be changed.
  2966. func ValidateNamespaceStatusUpdate(newNamespace, oldNamespace *api.Namespace) field.ErrorList {
  2967. allErrs := ValidateObjectMetaUpdate(&newNamespace.ObjectMeta, &oldNamespace.ObjectMeta, field.NewPath("metadata"))
  2968. newNamespace.Spec = oldNamespace.Spec
  2969. if newNamespace.DeletionTimestamp.IsZero() {
  2970. if newNamespace.Status.Phase != api.NamespaceActive {
  2971. allErrs = append(allErrs, field.Invalid(field.NewPath("status", "Phase"), newNamespace.Status.Phase, "may only be 'Active' if `deletionTimestamp` is empty"))
  2972. }
  2973. } else {
  2974. if newNamespace.Status.Phase != api.NamespaceTerminating {
  2975. allErrs = append(allErrs, field.Invalid(field.NewPath("status", "Phase"), newNamespace.Status.Phase, "may only be 'Terminating' if `deletionTimestamp` is not empty"))
  2976. }
  2977. }
  2978. return allErrs
  2979. }
  2980. // ValidateNamespaceFinalizeUpdate tests to see if the update is legal for an end user to make.
  2981. // newNamespace is updated with fields that cannot be changed.
  2982. func ValidateNamespaceFinalizeUpdate(newNamespace, oldNamespace *api.Namespace) field.ErrorList {
  2983. allErrs := ValidateObjectMetaUpdate(&newNamespace.ObjectMeta, &oldNamespace.ObjectMeta, field.NewPath("metadata"))
  2984. fldPath := field.NewPath("spec", "finalizers")
  2985. for i := range newNamespace.Spec.Finalizers {
  2986. idxPath := fldPath.Index(i)
  2987. allErrs = append(allErrs, validateFinalizerName(string(newNamespace.Spec.Finalizers[i]), idxPath)...)
  2988. }
  2989. newNamespace.Status = oldNamespace.Status
  2990. return allErrs
  2991. }
  2992. // Construct lookup map of old subset IPs to NodeNames.
  2993. func updateEpAddrToNodeNameMap(ipToNodeName map[string]string, addresses []api.EndpointAddress) {
  2994. for n := range addresses {
  2995. if addresses[n].NodeName == nil {
  2996. continue
  2997. }
  2998. ipToNodeName[addresses[n].IP] = *addresses[n].NodeName
  2999. }
  3000. }
  3001. // Build a map across all subsets of IP -> NodeName
  3002. func buildEndpointAddressNodeNameMap(subsets []api.EndpointSubset) map[string]string {
  3003. ipToNodeName := make(map[string]string)
  3004. for i := range subsets {
  3005. updateEpAddrToNodeNameMap(ipToNodeName, subsets[i].Addresses)
  3006. updateEpAddrToNodeNameMap(ipToNodeName, subsets[i].NotReadyAddresses)
  3007. }
  3008. return ipToNodeName
  3009. }
  3010. func validateEpAddrNodeNameTransition(addr *api.EndpointAddress, ipToNodeName map[string]string, fldPath *field.Path) field.ErrorList {
  3011. errList := field.ErrorList{}
  3012. existingNodeName, found := ipToNodeName[addr.IP]
  3013. if !found {
  3014. return errList
  3015. }
  3016. if addr.NodeName == nil || *addr.NodeName == existingNodeName {
  3017. return errList
  3018. }
  3019. // NodeName entry found for this endpoint IP, but user is attempting to change NodeName
  3020. return append(errList, field.Forbidden(fldPath, fmt.Sprintf("Cannot change NodeName for %s to %s", addr.IP, *addr.NodeName)))
  3021. }
  3022. // ValidateEndpoints tests if required fields are set.
  3023. func ValidateEndpoints(endpoints *api.Endpoints) field.ErrorList {
  3024. allErrs := ValidateObjectMeta(&endpoints.ObjectMeta, true, ValidateEndpointsName, field.NewPath("metadata"))
  3025. allErrs = append(allErrs, ValidateEndpointsSpecificAnnotations(endpoints.Annotations, field.NewPath("annotations"))...)
  3026. allErrs = append(allErrs, validateEndpointSubsets(endpoints.Subsets, []api.EndpointSubset{}, field.NewPath("subsets"))...)
  3027. return allErrs
  3028. }
  3029. func validateEndpointSubsets(subsets []api.EndpointSubset, oldSubsets []api.EndpointSubset, fldPath *field.Path) field.ErrorList {
  3030. allErrs := field.ErrorList{}
  3031. ipToNodeName := buildEndpointAddressNodeNameMap(oldSubsets)
  3032. for i := range subsets {
  3033. ss := &subsets[i]
  3034. idxPath := fldPath.Index(i)
  3035. if len(ss.Addresses) == 0 && len(ss.NotReadyAddresses) == 0 {
  3036. //TODO: consider adding a RequiredOneOf() error for this and similar cases
  3037. allErrs = append(allErrs, field.Required(idxPath, "must specify `addresses` or `notReadyAddresses`"))
  3038. }
  3039. if len(ss.Ports) == 0 {
  3040. allErrs = append(allErrs, field.Required(idxPath.Child("ports"), ""))
  3041. }
  3042. for addr := range ss.Addresses {
  3043. allErrs = append(allErrs, validateEndpointAddress(&ss.Addresses[addr], idxPath.Child("addresses").Index(addr), ipToNodeName)...)
  3044. }
  3045. for addr := range ss.NotReadyAddresses {
  3046. allErrs = append(allErrs, validateEndpointAddress(&ss.NotReadyAddresses[addr], idxPath.Child("notReadyAddresses").Index(addr), ipToNodeName)...)
  3047. }
  3048. for port := range ss.Ports {
  3049. allErrs = append(allErrs, validateEndpointPort(&ss.Ports[port], len(ss.Ports) > 1, idxPath.Child("ports").Index(port))...)
  3050. }
  3051. }
  3052. return allErrs
  3053. }
  3054. func validateEndpointAddress(address *api.EndpointAddress, fldPath *field.Path, ipToNodeName map[string]string) field.ErrorList {
  3055. allErrs := field.ErrorList{}
  3056. for _, msg := range validation.IsValidIP(address.IP) {
  3057. allErrs = append(allErrs, field.Invalid(fldPath.Child("ip"), address.IP, msg))
  3058. }
  3059. if len(address.Hostname) > 0 {
  3060. allErrs = append(allErrs, ValidateDNS1123Label(address.Hostname, fldPath.Child("hostname"))...)
  3061. }
  3062. // During endpoint update, validate NodeName is DNS1123 compliant and transition rules allow the update
  3063. if address.NodeName != nil {
  3064. allErrs = append(allErrs, ValidateDNS1123Label(*address.NodeName, fldPath.Child("nodeName"))...)
  3065. }
  3066. allErrs = append(allErrs, validateEpAddrNodeNameTransition(address, ipToNodeName, fldPath.Child("nodeName"))...)
  3067. if len(allErrs) > 0 {
  3068. return allErrs
  3069. }
  3070. allErrs = append(allErrs, validateNonSpecialIP(address.IP, fldPath.Child("ip"))...)
  3071. return allErrs
  3072. }
  3073. func validateNonSpecialIP(ipAddress string, fldPath *field.Path) field.ErrorList {
  3074. // We disallow some IPs as endpoints or external-ips. Specifically,
  3075. // unspecified and loopback addresses are nonsensical and link-local
  3076. // addresses tend to be used for node-centric purposes (e.g. metadata
  3077. // service).
  3078. allErrs := field.ErrorList{}
  3079. ip := net.ParseIP(ipAddress)
  3080. if ip == nil {
  3081. allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "must be a valid IP address"))
  3082. return allErrs
  3083. }
  3084. if ip.IsUnspecified() {
  3085. allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "may not be unspecified (0.0.0.0)"))
  3086. }
  3087. if ip.IsLoopback() {
  3088. allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "may not be in the loopback range (127.0.0.0/8)"))
  3089. }
  3090. if ip.IsLinkLocalUnicast() {
  3091. allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "may not be in the link-local range (169.254.0.0/16)"))
  3092. }
  3093. if ip.IsLinkLocalMulticast() {
  3094. allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "may not be in the link-local multicast range (224.0.0.0/24)"))
  3095. }
  3096. return allErrs
  3097. }
  3098. func validateEndpointPort(port *api.EndpointPort, requireName bool, fldPath *field.Path) field.ErrorList {
  3099. allErrs := field.ErrorList{}
  3100. if requireName && len(port.Name) == 0 {
  3101. allErrs = append(allErrs, field.Required(fldPath.Child("name"), ""))
  3102. } else if len(port.Name) != 0 {
  3103. allErrs = append(allErrs, ValidateDNS1123Label(port.Name, fldPath.Child("name"))...)
  3104. }
  3105. for _, msg := range validation.IsValidPortNum(int(port.Port)) {
  3106. allErrs = append(allErrs, field.Invalid(fldPath.Child("port"), port.Port, msg))
  3107. }
  3108. if len(port.Protocol) == 0 {
  3109. allErrs = append(allErrs, field.Required(fldPath.Child("protocol"), ""))
  3110. } else if !supportedPortProtocols.Has(string(port.Protocol)) {
  3111. allErrs = append(allErrs, field.NotSupported(fldPath.Child("protocol"), port.Protocol, supportedPortProtocols.List()))
  3112. }
  3113. return allErrs
  3114. }
  3115. // ValidateEndpointsUpdate tests to make sure an endpoints update can be applied.
  3116. func ValidateEndpointsUpdate(newEndpoints, oldEndpoints *api.Endpoints) field.ErrorList {
  3117. allErrs := ValidateObjectMetaUpdate(&newEndpoints.ObjectMeta, &oldEndpoints.ObjectMeta, field.NewPath("metadata"))
  3118. allErrs = append(allErrs, validateEndpointSubsets(newEndpoints.Subsets, oldEndpoints.Subsets, field.NewPath("subsets"))...)
  3119. allErrs = append(allErrs, ValidateEndpointsSpecificAnnotations(newEndpoints.Annotations, field.NewPath("annotations"))...)
  3120. return allErrs
  3121. }
  3122. // ValidateSecurityContext ensure the security context contains valid settings
  3123. func ValidateSecurityContext(sc *api.SecurityContext, fldPath *field.Path) field.ErrorList {
  3124. allErrs := field.ErrorList{}
  3125. //this should only be true for testing since SecurityContext is defaulted by the api
  3126. if sc == nil {
  3127. return allErrs
  3128. }
  3129. if sc.Privileged != nil {
  3130. if *sc.Privileged && !capabilities.Get().AllowPrivileged {
  3131. allErrs = append(allErrs, field.Forbidden(fldPath.Child("privileged"), "disallowed by policy"))
  3132. }
  3133. }
  3134. if sc.RunAsUser != nil {
  3135. if *sc.RunAsUser < 0 {
  3136. allErrs = append(allErrs, field.Invalid(fldPath.Child("runAsUser"), *sc.RunAsUser, isNegativeErrorMsg))
  3137. }
  3138. }
  3139. return allErrs
  3140. }
  3141. func ValidatePodLogOptions(opts *api.PodLogOptions) field.ErrorList {
  3142. allErrs := field.ErrorList{}
  3143. if opts.TailLines != nil && *opts.TailLines < 0 {
  3144. allErrs = append(allErrs, field.Invalid(field.NewPath("tailLines"), *opts.TailLines, isNegativeErrorMsg))
  3145. }
  3146. if opts.LimitBytes != nil && *opts.LimitBytes < 1 {
  3147. allErrs = append(allErrs, field.Invalid(field.NewPath("limitBytes"), *opts.LimitBytes, "must be greater than 0"))
  3148. }
  3149. switch {
  3150. case opts.SinceSeconds != nil && opts.SinceTime != nil:
  3151. allErrs = append(allErrs, field.Forbidden(field.NewPath(""), "at most one of `sinceTime` or `sinceSeconds` may be specified"))
  3152. case opts.SinceSeconds != nil:
  3153. if *opts.SinceSeconds < 1 {
  3154. allErrs = append(allErrs, field.Invalid(field.NewPath("sinceSeconds"), *opts.SinceSeconds, "must be greater than 0"))
  3155. }
  3156. }
  3157. return allErrs
  3158. }
  3159. // ValidateLoadBalancerStatus validates required fields on a LoadBalancerStatus
  3160. func ValidateLoadBalancerStatus(status *api.LoadBalancerStatus, fldPath *field.Path) field.ErrorList {
  3161. allErrs := field.ErrorList{}
  3162. for i, ingress := range status.Ingress {
  3163. idxPath := fldPath.Child("ingress").Index(i)
  3164. if len(ingress.IP) > 0 {
  3165. if isIP := (net.ParseIP(ingress.IP) != nil); !isIP {
  3166. allErrs = append(allErrs, field.Invalid(idxPath.Child("ip"), ingress.IP, "must be a valid IP address"))
  3167. }
  3168. }
  3169. if len(ingress.Hostname) > 0 {
  3170. for _, msg := range validation.IsDNS1123Subdomain(ingress.Hostname) {
  3171. allErrs = append(allErrs, field.Invalid(idxPath.Child("hostname"), ingress.Hostname, msg))
  3172. }
  3173. if isIP := (net.ParseIP(ingress.Hostname) != nil); isIP {
  3174. allErrs = append(allErrs, field.Invalid(idxPath.Child("hostname"), ingress.Hostname, "must be a DNS name, not an IP address"))
  3175. }
  3176. }
  3177. }
  3178. return allErrs
  3179. }
  3180. // TODO: remove this after we EOL the annotation that carries it.
  3181. func isValidHostnamesMap(serializedPodHostNames string) bool {
  3182. if len(serializedPodHostNames) == 0 {
  3183. return false
  3184. }
  3185. podHostNames := map[string]endpoints.HostRecord{}
  3186. err := json.Unmarshal([]byte(serializedPodHostNames), &podHostNames)
  3187. if err != nil {
  3188. return false
  3189. }
  3190. for ip, hostRecord := range podHostNames {
  3191. if len(validation.IsDNS1123Label(hostRecord.HostName)) != 0 {
  3192. return false
  3193. }
  3194. if net.ParseIP(ip) == nil {
  3195. return false
  3196. }
  3197. }
  3198. return true
  3199. }
  3200. func sysctlIntersection(a []api.Sysctl, b []api.Sysctl) []string {
  3201. lookup := make(map[string]struct{}, len(a))
  3202. result := []string{}
  3203. for i := range a {
  3204. lookup[a[i].Name] = struct{}{}
  3205. }
  3206. for i := range b {
  3207. if _, found := lookup[b[i].Name]; found {
  3208. result = append(result, b[i].Name)
  3209. }
  3210. }
  3211. return result
  3212. }