util.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788
  1. /*
  2. Copyright 2015 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 pod
  14. import (
  15. "strings"
  16. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  17. utilfeature "k8s.io/apiserver/pkg/util/feature"
  18. api "k8s.io/kubernetes/pkg/apis/core"
  19. "k8s.io/kubernetes/pkg/features"
  20. "k8s.io/kubernetes/pkg/security/apparmor"
  21. )
  22. // ContainerVisitor is called with each container spec, and returns true
  23. // if visiting should continue.
  24. type ContainerVisitor func(container *api.Container) (shouldContinue bool)
  25. // VisitContainers invokes the visitor function with a pointer to the container
  26. // spec of every container in the given pod spec. If visitor returns false,
  27. // visiting is short-circuited. VisitContainers returns true if visiting completes,
  28. // false if visiting was short-circuited.
  29. func VisitContainers(podSpec *api.PodSpec, visitor ContainerVisitor) bool {
  30. for i := range podSpec.InitContainers {
  31. if !visitor(&podSpec.InitContainers[i]) {
  32. return false
  33. }
  34. }
  35. for i := range podSpec.Containers {
  36. if !visitor(&podSpec.Containers[i]) {
  37. return false
  38. }
  39. }
  40. if utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers) {
  41. for i := range podSpec.EphemeralContainers {
  42. if !visitor((*api.Container)(&podSpec.EphemeralContainers[i].EphemeralContainerCommon)) {
  43. return false
  44. }
  45. }
  46. }
  47. return true
  48. }
  49. // Visitor is called with each object name, and returns true if visiting should continue
  50. type Visitor func(name string) (shouldContinue bool)
  51. // VisitPodSecretNames invokes the visitor function with the name of every secret
  52. // referenced by the pod spec. If visitor returns false, visiting is short-circuited.
  53. // Transitive references (e.g. pod -> pvc -> pv -> secret) are not visited.
  54. // Returns true if visiting completed, false if visiting was short-circuited.
  55. func VisitPodSecretNames(pod *api.Pod, visitor Visitor) bool {
  56. for _, reference := range pod.Spec.ImagePullSecrets {
  57. if !visitor(reference.Name) {
  58. return false
  59. }
  60. }
  61. VisitContainers(&pod.Spec, func(c *api.Container) bool {
  62. return visitContainerSecretNames(c, visitor)
  63. })
  64. var source *api.VolumeSource
  65. for i := range pod.Spec.Volumes {
  66. source = &pod.Spec.Volumes[i].VolumeSource
  67. switch {
  68. case source.AzureFile != nil:
  69. if len(source.AzureFile.SecretName) > 0 && !visitor(source.AzureFile.SecretName) {
  70. return false
  71. }
  72. case source.CephFS != nil:
  73. if source.CephFS.SecretRef != nil && !visitor(source.CephFS.SecretRef.Name) {
  74. return false
  75. }
  76. case source.Cinder != nil:
  77. if source.Cinder.SecretRef != nil && !visitor(source.Cinder.SecretRef.Name) {
  78. return false
  79. }
  80. case source.FlexVolume != nil:
  81. if source.FlexVolume.SecretRef != nil && !visitor(source.FlexVolume.SecretRef.Name) {
  82. return false
  83. }
  84. case source.Projected != nil:
  85. for j := range source.Projected.Sources {
  86. if source.Projected.Sources[j].Secret != nil {
  87. if !visitor(source.Projected.Sources[j].Secret.Name) {
  88. return false
  89. }
  90. }
  91. }
  92. case source.RBD != nil:
  93. if source.RBD.SecretRef != nil && !visitor(source.RBD.SecretRef.Name) {
  94. return false
  95. }
  96. case source.Secret != nil:
  97. if !visitor(source.Secret.SecretName) {
  98. return false
  99. }
  100. case source.ScaleIO != nil:
  101. if source.ScaleIO.SecretRef != nil && !visitor(source.ScaleIO.SecretRef.Name) {
  102. return false
  103. }
  104. case source.ISCSI != nil:
  105. if source.ISCSI.SecretRef != nil && !visitor(source.ISCSI.SecretRef.Name) {
  106. return false
  107. }
  108. case source.StorageOS != nil:
  109. if source.StorageOS.SecretRef != nil && !visitor(source.StorageOS.SecretRef.Name) {
  110. return false
  111. }
  112. case source.CSI != nil:
  113. if source.CSI.NodePublishSecretRef != nil && !visitor(source.CSI.NodePublishSecretRef.Name) {
  114. return false
  115. }
  116. }
  117. }
  118. return true
  119. }
  120. func visitContainerSecretNames(container *api.Container, visitor Visitor) bool {
  121. for _, env := range container.EnvFrom {
  122. if env.SecretRef != nil {
  123. if !visitor(env.SecretRef.Name) {
  124. return false
  125. }
  126. }
  127. }
  128. for _, envVar := range container.Env {
  129. if envVar.ValueFrom != nil && envVar.ValueFrom.SecretKeyRef != nil {
  130. if !visitor(envVar.ValueFrom.SecretKeyRef.Name) {
  131. return false
  132. }
  133. }
  134. }
  135. return true
  136. }
  137. // VisitPodConfigmapNames invokes the visitor function with the name of every configmap
  138. // referenced by the pod spec. If visitor returns false, visiting is short-circuited.
  139. // Transitive references (e.g. pod -> pvc -> pv -> secret) are not visited.
  140. // Returns true if visiting completed, false if visiting was short-circuited.
  141. func VisitPodConfigmapNames(pod *api.Pod, visitor Visitor) bool {
  142. VisitContainers(&pod.Spec, func(c *api.Container) bool {
  143. return visitContainerConfigmapNames(c, visitor)
  144. })
  145. var source *api.VolumeSource
  146. for i := range pod.Spec.Volumes {
  147. source = &pod.Spec.Volumes[i].VolumeSource
  148. switch {
  149. case source.Projected != nil:
  150. for j := range source.Projected.Sources {
  151. if source.Projected.Sources[j].ConfigMap != nil {
  152. if !visitor(source.Projected.Sources[j].ConfigMap.Name) {
  153. return false
  154. }
  155. }
  156. }
  157. case source.ConfigMap != nil:
  158. if !visitor(source.ConfigMap.Name) {
  159. return false
  160. }
  161. }
  162. }
  163. return true
  164. }
  165. func visitContainerConfigmapNames(container *api.Container, visitor Visitor) bool {
  166. for _, env := range container.EnvFrom {
  167. if env.ConfigMapRef != nil {
  168. if !visitor(env.ConfigMapRef.Name) {
  169. return false
  170. }
  171. }
  172. }
  173. for _, envVar := range container.Env {
  174. if envVar.ValueFrom != nil && envVar.ValueFrom.ConfigMapKeyRef != nil {
  175. if !visitor(envVar.ValueFrom.ConfigMapKeyRef.Name) {
  176. return false
  177. }
  178. }
  179. }
  180. return true
  181. }
  182. // IsPodReady returns true if a pod is ready; false otherwise.
  183. func IsPodReady(pod *api.Pod) bool {
  184. return IsPodReadyConditionTrue(pod.Status)
  185. }
  186. // IsPodReadyConditionTrue returns true if a pod is ready; false otherwise.
  187. func IsPodReadyConditionTrue(status api.PodStatus) bool {
  188. condition := GetPodReadyCondition(status)
  189. return condition != nil && condition.Status == api.ConditionTrue
  190. }
  191. // GetPodReadyCondition extracts the pod ready condition from the given status and returns that.
  192. // Returns nil if the condition is not present.
  193. func GetPodReadyCondition(status api.PodStatus) *api.PodCondition {
  194. _, condition := GetPodCondition(&status, api.PodReady)
  195. return condition
  196. }
  197. // GetPodCondition extracts the provided condition from the given status and returns that.
  198. // Returns nil and -1 if the condition is not present, and the index of the located condition.
  199. func GetPodCondition(status *api.PodStatus, conditionType api.PodConditionType) (int, *api.PodCondition) {
  200. if status == nil {
  201. return -1, nil
  202. }
  203. for i := range status.Conditions {
  204. if status.Conditions[i].Type == conditionType {
  205. return i, &status.Conditions[i]
  206. }
  207. }
  208. return -1, nil
  209. }
  210. // UpdatePodCondition updates existing pod condition or creates a new one. Sets LastTransitionTime to now if the
  211. // status has changed.
  212. // Returns true if pod condition has changed or has been added.
  213. func UpdatePodCondition(status *api.PodStatus, condition *api.PodCondition) bool {
  214. condition.LastTransitionTime = metav1.Now()
  215. // Try to find this pod condition.
  216. conditionIndex, oldCondition := GetPodCondition(status, condition.Type)
  217. if oldCondition == nil {
  218. // We are adding new pod condition.
  219. status.Conditions = append(status.Conditions, *condition)
  220. return true
  221. }
  222. // We are updating an existing condition, so we need to check if it has changed.
  223. if condition.Status == oldCondition.Status {
  224. condition.LastTransitionTime = oldCondition.LastTransitionTime
  225. }
  226. isEqual := condition.Status == oldCondition.Status &&
  227. condition.Reason == oldCondition.Reason &&
  228. condition.Message == oldCondition.Message &&
  229. condition.LastProbeTime.Equal(&oldCondition.LastProbeTime) &&
  230. condition.LastTransitionTime.Equal(&oldCondition.LastTransitionTime)
  231. status.Conditions[conditionIndex] = *condition
  232. // Return true if one of the fields have changed.
  233. return !isEqual
  234. }
  235. // DropDisabledTemplateFields removes disabled fields from the pod template metadata and spec.
  236. // This should be called from PrepareForCreate/PrepareForUpdate for all resources containing a PodTemplateSpec
  237. func DropDisabledTemplateFields(podTemplate, oldPodTemplate *api.PodTemplateSpec) {
  238. var (
  239. podSpec *api.PodSpec
  240. podAnnotations map[string]string
  241. oldPodSpec *api.PodSpec
  242. oldPodAnnotations map[string]string
  243. )
  244. if podTemplate != nil {
  245. podSpec = &podTemplate.Spec
  246. podAnnotations = podTemplate.Annotations
  247. }
  248. if oldPodTemplate != nil {
  249. oldPodSpec = &oldPodTemplate.Spec
  250. oldPodAnnotations = oldPodTemplate.Annotations
  251. }
  252. dropDisabledFields(podSpec, podAnnotations, oldPodSpec, oldPodAnnotations)
  253. }
  254. // DropDisabledPodFields removes disabled fields from the pod metadata and spec.
  255. // This should be called from PrepareForCreate/PrepareForUpdate for all resources containing a Pod
  256. func DropDisabledPodFields(pod, oldPod *api.Pod) {
  257. var (
  258. podSpec *api.PodSpec
  259. podAnnotations map[string]string
  260. oldPodSpec *api.PodSpec
  261. oldPodAnnotations map[string]string
  262. podStatus *api.PodStatus
  263. oldPodStatus *api.PodStatus
  264. )
  265. if pod != nil {
  266. podSpec = &pod.Spec
  267. podAnnotations = pod.Annotations
  268. podStatus = &pod.Status
  269. }
  270. if oldPod != nil {
  271. oldPodSpec = &oldPod.Spec
  272. oldPodAnnotations = oldPod.Annotations
  273. oldPodStatus = &oldPod.Status
  274. }
  275. dropDisabledFields(podSpec, podAnnotations, oldPodSpec, oldPodAnnotations)
  276. dropPodStatusDisabledFields(podStatus, oldPodStatus)
  277. }
  278. // dropPodStatusDisabledFields removes disabled fields from the pod status
  279. func dropPodStatusDisabledFields(podStatus *api.PodStatus, oldPodStatus *api.PodStatus) {
  280. // trim PodIPs down to only one entry (non dual stack).
  281. if !utilfeature.DefaultFeatureGate.Enabled(features.IPv6DualStack) &&
  282. !multiplePodIPsInUse(oldPodStatus) {
  283. if len(podStatus.PodIPs) != 0 {
  284. podStatus.PodIPs = podStatus.PodIPs[0:1]
  285. }
  286. }
  287. }
  288. // dropDisabledFields removes disabled fields from the pod metadata and spec.
  289. func dropDisabledFields(
  290. podSpec *api.PodSpec, podAnnotations map[string]string,
  291. oldPodSpec *api.PodSpec, oldPodAnnotations map[string]string,
  292. ) {
  293. // the new spec must always be non-nil
  294. if podSpec == nil {
  295. podSpec = &api.PodSpec{}
  296. }
  297. if !utilfeature.DefaultFeatureGate.Enabled(features.TokenRequestProjection) &&
  298. !tokenRequestProjectionInUse(oldPodSpec) {
  299. for i := range podSpec.Volumes {
  300. if podSpec.Volumes[i].Projected != nil {
  301. for j := range podSpec.Volumes[i].Projected.Sources {
  302. podSpec.Volumes[i].Projected.Sources[j].ServiceAccountToken = nil
  303. }
  304. }
  305. }
  306. }
  307. if !utilfeature.DefaultFeatureGate.Enabled(features.AppArmor) && !appArmorInUse(oldPodAnnotations) {
  308. for k := range podAnnotations {
  309. if strings.HasPrefix(k, apparmor.ContainerAnnotationKeyPrefix) {
  310. delete(podAnnotations, k)
  311. }
  312. }
  313. }
  314. if !utilfeature.DefaultFeatureGate.Enabled(features.Sysctls) && !sysctlsInUse(oldPodSpec) {
  315. if podSpec.SecurityContext != nil {
  316. podSpec.SecurityContext.Sysctls = nil
  317. }
  318. }
  319. if !utilfeature.DefaultFeatureGate.Enabled(features.LocalStorageCapacityIsolation) && !emptyDirSizeLimitInUse(oldPodSpec) {
  320. for i := range podSpec.Volumes {
  321. if podSpec.Volumes[i].EmptyDir != nil {
  322. podSpec.Volumes[i].EmptyDir.SizeLimit = nil
  323. }
  324. }
  325. }
  326. if !utilfeature.DefaultFeatureGate.Enabled(features.VolumeSubpath) && !subpathInUse(oldPodSpec) {
  327. // drop subpath from the pod if the feature is disabled and the old spec did not specify subpaths
  328. VisitContainers(podSpec, func(c *api.Container) bool {
  329. for i := range c.VolumeMounts {
  330. c.VolumeMounts[i].SubPath = ""
  331. }
  332. return true
  333. })
  334. }
  335. if !utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers) && !ephemeralContainersInUse(oldPodSpec) {
  336. podSpec.EphemeralContainers = nil
  337. }
  338. if (!utilfeature.DefaultFeatureGate.Enabled(features.VolumeSubpath) || !utilfeature.DefaultFeatureGate.Enabled(features.VolumeSubpathEnvExpansion)) && !subpathExprInUse(oldPodSpec) {
  339. // drop subpath env expansion from the pod if either of the subpath features is disabled and the old spec did not specify subpath env expansion
  340. VisitContainers(podSpec, func(c *api.Container) bool {
  341. for i := range c.VolumeMounts {
  342. c.VolumeMounts[i].SubPathExpr = ""
  343. }
  344. return true
  345. })
  346. }
  347. if !utilfeature.DefaultFeatureGate.Enabled(features.StartupProbe) && !startupProbeInUse(oldPodSpec) {
  348. // drop startupProbe from all containers if the feature is disabled
  349. VisitContainers(podSpec, func(c *api.Container) bool {
  350. c.StartupProbe = nil
  351. return true
  352. })
  353. }
  354. dropDisabledVolumeDevicesFields(podSpec, oldPodSpec)
  355. dropDisabledRunAsGroupField(podSpec, oldPodSpec)
  356. dropDisabledGMSAFields(podSpec, oldPodSpec)
  357. if !utilfeature.DefaultFeatureGate.Enabled(features.RuntimeClass) && !runtimeClassInUse(oldPodSpec) {
  358. // Set RuntimeClassName to nil only if feature is disabled and it is not used
  359. podSpec.RuntimeClassName = nil
  360. }
  361. if !utilfeature.DefaultFeatureGate.Enabled(features.PodOverhead) && !overheadInUse(oldPodSpec) {
  362. // Set Overhead to nil only if the feature is disabled and it is not used
  363. podSpec.Overhead = nil
  364. }
  365. dropDisabledProcMountField(podSpec, oldPodSpec)
  366. dropDisabledCSIVolumeSourceAlphaFields(podSpec, oldPodSpec)
  367. if !utilfeature.DefaultFeatureGate.Enabled(features.NonPreemptingPriority) &&
  368. !podPriorityInUse(oldPodSpec) {
  369. // Set to nil pod's PreemptionPolicy fields if the feature is disabled and the old pod
  370. // does not specify any values for these fields.
  371. podSpec.PreemptionPolicy = nil
  372. }
  373. if !utilfeature.DefaultFeatureGate.Enabled(features.EvenPodsSpread) && !topologySpreadConstraintsInUse(oldPodSpec) {
  374. // Set TopologySpreadConstraints to nil only if feature is disabled and it is not used
  375. podSpec.TopologySpreadConstraints = nil
  376. }
  377. }
  378. // dropDisabledRunAsGroupField removes disabled fields from PodSpec related
  379. // to RunAsGroup
  380. func dropDisabledRunAsGroupField(podSpec, oldPodSpec *api.PodSpec) {
  381. if !utilfeature.DefaultFeatureGate.Enabled(features.RunAsGroup) && !runAsGroupInUse(oldPodSpec) {
  382. if podSpec.SecurityContext != nil {
  383. podSpec.SecurityContext.RunAsGroup = nil
  384. }
  385. VisitContainers(podSpec, func(c *api.Container) bool {
  386. if c.SecurityContext != nil {
  387. c.SecurityContext.RunAsGroup = nil
  388. }
  389. return true
  390. })
  391. }
  392. }
  393. // dropDisabledGMSAFields removes disabled fields related to Windows GMSA
  394. // from the given PodSpec.
  395. func dropDisabledGMSAFields(podSpec, oldPodSpec *api.PodSpec) {
  396. if utilfeature.DefaultFeatureGate.Enabled(features.WindowsGMSA) ||
  397. gMSAFieldsInUse(oldPodSpec) {
  398. return
  399. }
  400. if podSpec.SecurityContext != nil {
  401. dropDisabledGMSAFieldsFromWindowsSecurityOptions(podSpec.SecurityContext.WindowsOptions)
  402. }
  403. dropDisabledGMSAFieldsFromContainers(podSpec.Containers)
  404. dropDisabledGMSAFieldsFromContainers(podSpec.InitContainers)
  405. }
  406. // dropDisabledGMSAFieldsFromWindowsSecurityOptions removes disabled fields
  407. // related to Windows GMSA from the given WindowsSecurityContextOptions.
  408. func dropDisabledGMSAFieldsFromWindowsSecurityOptions(windowsOptions *api.WindowsSecurityContextOptions) {
  409. if windowsOptions != nil {
  410. windowsOptions.GMSACredentialSpecName = nil
  411. windowsOptions.GMSACredentialSpec = nil
  412. }
  413. }
  414. // dropDisabledGMSAFieldsFromContainers removes disabled fields
  415. func dropDisabledGMSAFieldsFromContainers(containers []api.Container) {
  416. for i := range containers {
  417. if containers[i].SecurityContext != nil {
  418. dropDisabledGMSAFieldsFromWindowsSecurityOptions(containers[i].SecurityContext.WindowsOptions)
  419. }
  420. }
  421. }
  422. // dropDisabledProcMountField removes disabled fields from PodSpec related
  423. // to ProcMount only if it is not already used by the old spec
  424. func dropDisabledProcMountField(podSpec, oldPodSpec *api.PodSpec) {
  425. if !utilfeature.DefaultFeatureGate.Enabled(features.ProcMountType) && !procMountInUse(oldPodSpec) {
  426. defaultProcMount := api.DefaultProcMount
  427. VisitContainers(podSpec, func(c *api.Container) bool {
  428. if c.SecurityContext != nil && c.SecurityContext.ProcMount != nil {
  429. // The ProcMount field was improperly forced to non-nil in 1.12.
  430. // If the feature is disabled, and the existing object is not using any non-default values, and the ProcMount field is present in the incoming object, force to the default value.
  431. // Note: we cannot force the field to nil when the feature is disabled because it causes a diff against previously persisted data.
  432. c.SecurityContext.ProcMount = &defaultProcMount
  433. }
  434. return true
  435. })
  436. }
  437. }
  438. // dropDisabledVolumeDevicesFields removes disabled fields from []VolumeDevice if it has not been already populated.
  439. // This should be called from PrepareForCreate/PrepareForUpdate for all resources containing a VolumeDevice
  440. func dropDisabledVolumeDevicesFields(podSpec, oldPodSpec *api.PodSpec) {
  441. if !utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) && !volumeDevicesInUse(oldPodSpec) {
  442. VisitContainers(podSpec, func(c *api.Container) bool {
  443. c.VolumeDevices = nil
  444. return true
  445. })
  446. }
  447. }
  448. // dropDisabledCSIVolumeSourceAlphaFields removes disabled alpha fields from []CSIVolumeSource.
  449. // This should be called from PrepareForCreate/PrepareForUpdate for all pod specs resources containing a CSIVolumeSource
  450. func dropDisabledCSIVolumeSourceAlphaFields(podSpec, oldPodSpec *api.PodSpec) {
  451. if !utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume) && !csiInUse(oldPodSpec) {
  452. for i := range podSpec.Volumes {
  453. podSpec.Volumes[i].CSI = nil
  454. }
  455. }
  456. }
  457. func ephemeralContainersInUse(podSpec *api.PodSpec) bool {
  458. if podSpec == nil {
  459. return false
  460. }
  461. return len(podSpec.EphemeralContainers) > 0
  462. }
  463. // subpathInUse returns true if the pod spec is non-nil and has a volume mount that makes use of the subPath feature
  464. func subpathInUse(podSpec *api.PodSpec) bool {
  465. if podSpec == nil {
  466. return false
  467. }
  468. var inUse bool
  469. VisitContainers(podSpec, func(c *api.Container) bool {
  470. for i := range c.VolumeMounts {
  471. if len(c.VolumeMounts[i].SubPath) > 0 {
  472. inUse = true
  473. return false
  474. }
  475. }
  476. return true
  477. })
  478. return inUse
  479. }
  480. // runtimeClassInUse returns true if the pod spec is non-nil and has a RuntimeClassName set
  481. func runtimeClassInUse(podSpec *api.PodSpec) bool {
  482. if podSpec == nil {
  483. return false
  484. }
  485. if podSpec.RuntimeClassName != nil {
  486. return true
  487. }
  488. return false
  489. }
  490. // overheadInUse returns true if the pod spec is non-nil and has Overhead set
  491. func overheadInUse(podSpec *api.PodSpec) bool {
  492. if podSpec == nil {
  493. return false
  494. }
  495. if podSpec.Overhead != nil {
  496. return true
  497. }
  498. return false
  499. }
  500. // topologySpreadConstraintsInUse returns true if the pod spec is non-nil and has a TopologySpreadConstraints slice
  501. func topologySpreadConstraintsInUse(podSpec *api.PodSpec) bool {
  502. if podSpec == nil {
  503. return false
  504. }
  505. return len(podSpec.TopologySpreadConstraints) > 0
  506. }
  507. // procMountInUse returns true if the pod spec is non-nil and has a SecurityContext's ProcMount field set to a non-default value
  508. func procMountInUse(podSpec *api.PodSpec) bool {
  509. if podSpec == nil {
  510. return false
  511. }
  512. var inUse bool
  513. VisitContainers(podSpec, func(c *api.Container) bool {
  514. if c.SecurityContext == nil || c.SecurityContext.ProcMount == nil {
  515. return true
  516. }
  517. if *c.SecurityContext.ProcMount != api.DefaultProcMount {
  518. inUse = true
  519. return false
  520. }
  521. return true
  522. })
  523. return inUse
  524. }
  525. // appArmorInUse returns true if the pod has apparmor related information
  526. func appArmorInUse(podAnnotations map[string]string) bool {
  527. for k := range podAnnotations {
  528. if strings.HasPrefix(k, apparmor.ContainerAnnotationKeyPrefix) {
  529. return true
  530. }
  531. }
  532. return false
  533. }
  534. func tokenRequestProjectionInUse(podSpec *api.PodSpec) bool {
  535. if podSpec == nil {
  536. return false
  537. }
  538. for _, v := range podSpec.Volumes {
  539. if v.Projected == nil {
  540. continue
  541. }
  542. for _, s := range v.Projected.Sources {
  543. if s.ServiceAccountToken != nil {
  544. return true
  545. }
  546. }
  547. }
  548. return false
  549. }
  550. // podPriorityInUse returns true if the pod spec is non-nil and has Priority or PriorityClassName set.
  551. func podPriorityInUse(podSpec *api.PodSpec) bool {
  552. if podSpec == nil {
  553. return false
  554. }
  555. if podSpec.Priority != nil || podSpec.PriorityClassName != "" {
  556. return true
  557. }
  558. return false
  559. }
  560. func sysctlsInUse(podSpec *api.PodSpec) bool {
  561. if podSpec == nil {
  562. return false
  563. }
  564. if podSpec.SecurityContext != nil && podSpec.SecurityContext.Sysctls != nil {
  565. return true
  566. }
  567. return false
  568. }
  569. // emptyDirSizeLimitInUse returns true if any pod's EmptyDir volumes use SizeLimit.
  570. func emptyDirSizeLimitInUse(podSpec *api.PodSpec) bool {
  571. if podSpec == nil {
  572. return false
  573. }
  574. for i := range podSpec.Volumes {
  575. if podSpec.Volumes[i].EmptyDir != nil {
  576. if podSpec.Volumes[i].EmptyDir.SizeLimit != nil {
  577. return true
  578. }
  579. }
  580. }
  581. return false
  582. }
  583. // volumeDevicesInUse returns true if the pod spec is non-nil and has VolumeDevices set.
  584. func volumeDevicesInUse(podSpec *api.PodSpec) bool {
  585. if podSpec == nil {
  586. return false
  587. }
  588. var inUse bool
  589. VisitContainers(podSpec, func(c *api.Container) bool {
  590. if c.VolumeDevices != nil {
  591. inUse = true
  592. return false
  593. }
  594. return true
  595. })
  596. return inUse
  597. }
  598. // runAsGroupInUse returns true if the pod spec is non-nil and has a SecurityContext's RunAsGroup field set
  599. func runAsGroupInUse(podSpec *api.PodSpec) bool {
  600. if podSpec == nil {
  601. return false
  602. }
  603. if podSpec.SecurityContext != nil && podSpec.SecurityContext.RunAsGroup != nil {
  604. return true
  605. }
  606. var inUse bool
  607. VisitContainers(podSpec, func(c *api.Container) bool {
  608. if c.SecurityContext != nil && c.SecurityContext.RunAsGroup != nil {
  609. inUse = true
  610. return false
  611. }
  612. return true
  613. })
  614. return inUse
  615. }
  616. // gMSAFieldsInUse returns true if the pod spec is non-nil and has one of any
  617. // SecurityContext's GMSACredentialSpecName or GMSACredentialSpec fields set.
  618. func gMSAFieldsInUse(podSpec *api.PodSpec) bool {
  619. if podSpec == nil {
  620. return false
  621. }
  622. if podSpec.SecurityContext != nil && gMSAFieldsInUseInWindowsSecurityOptions(podSpec.SecurityContext.WindowsOptions) {
  623. return true
  624. }
  625. return gMSAFieldsInUseInAnyContainer(podSpec.Containers) ||
  626. gMSAFieldsInUseInAnyContainer(podSpec.InitContainers)
  627. }
  628. // gMSAFieldsInUseInWindowsSecurityOptions returns true if the given WindowsSecurityContextOptions is
  629. // non-nil and one of its GMSACredentialSpecName or GMSACredentialSpec fields is set.
  630. func gMSAFieldsInUseInWindowsSecurityOptions(windowsOptions *api.WindowsSecurityContextOptions) bool {
  631. if windowsOptions == nil {
  632. return false
  633. }
  634. return windowsOptions.GMSACredentialSpecName != nil ||
  635. windowsOptions.GMSACredentialSpec != nil
  636. }
  637. // gMSAFieldsInUseInAnyContainer returns true if any of the given Containers has its
  638. // SecurityContext's GMSACredentialSpecName or GMSACredentialSpec fields set.
  639. func gMSAFieldsInUseInAnyContainer(containers []api.Container) bool {
  640. for _, container := range containers {
  641. if container.SecurityContext != nil && gMSAFieldsInUseInWindowsSecurityOptions(container.SecurityContext.WindowsOptions) {
  642. return true
  643. }
  644. }
  645. return false
  646. }
  647. // subpathExprInUse returns true if the pod spec is non-nil and has a volume mount that makes use of the subPathExpr feature
  648. func subpathExprInUse(podSpec *api.PodSpec) bool {
  649. if podSpec == nil {
  650. return false
  651. }
  652. var inUse bool
  653. VisitContainers(podSpec, func(c *api.Container) bool {
  654. for i := range c.VolumeMounts {
  655. if len(c.VolumeMounts[i].SubPathExpr) > 0 {
  656. inUse = true
  657. return false
  658. }
  659. }
  660. return true
  661. })
  662. return inUse
  663. }
  664. // startupProbeInUse returns true if the pod spec is non-nil and has a container that has a startupProbe defined
  665. func startupProbeInUse(podSpec *api.PodSpec) bool {
  666. if podSpec == nil {
  667. return false
  668. }
  669. var inUse bool
  670. VisitContainers(podSpec, func(c *api.Container) bool {
  671. if c.StartupProbe != nil {
  672. inUse = true
  673. return false
  674. }
  675. return true
  676. })
  677. return inUse
  678. }
  679. // csiInUse returns true if any pod's spec include inline CSI volumes.
  680. func csiInUse(podSpec *api.PodSpec) bool {
  681. if podSpec == nil {
  682. return false
  683. }
  684. for i := range podSpec.Volumes {
  685. if podSpec.Volumes[i].CSI != nil {
  686. return true
  687. }
  688. }
  689. return false
  690. }
  691. // podPriorityInUse returns true if status is not nil and number of PodIPs is greater than one
  692. func multiplePodIPsInUse(podStatus *api.PodStatus) bool {
  693. if podStatus == nil {
  694. return false
  695. }
  696. if len(podStatus.PodIPs) > 1 {
  697. return true
  698. }
  699. return false
  700. }