k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/api/pod/util.go (about)

     1  /*
     2  Copyright 2015 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package pod
    18  
    19  import (
    20  	"strings"
    21  
    22  	"github.com/google/go-cmp/cmp"
    23  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    24  	metavalidation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
    25  	"k8s.io/apimachinery/pkg/util/sets"
    26  	"k8s.io/apimachinery/pkg/util/validation"
    27  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    28  	api "k8s.io/kubernetes/pkg/apis/core"
    29  	"k8s.io/kubernetes/pkg/apis/core/helper"
    30  	apivalidation "k8s.io/kubernetes/pkg/apis/core/validation"
    31  	"k8s.io/kubernetes/pkg/features"
    32  )
    33  
    34  // ContainerType signifies container type
    35  type ContainerType int
    36  
    37  const (
    38  	// Containers is for normal containers
    39  	Containers ContainerType = 1 << iota
    40  	// InitContainers is for init containers
    41  	InitContainers
    42  	// EphemeralContainers is for ephemeral containers
    43  	EphemeralContainers
    44  )
    45  
    46  // AllContainers specifies that all containers be visited
    47  const AllContainers ContainerType = (InitContainers | Containers | EphemeralContainers)
    48  
    49  // AllFeatureEnabledContainers returns a ContainerType mask which includes all container
    50  // types except for the ones guarded by feature gate.
    51  func AllFeatureEnabledContainers() ContainerType {
    52  	return AllContainers
    53  }
    54  
    55  // ContainerVisitor is called with each container spec, and returns true
    56  // if visiting should continue.
    57  type ContainerVisitor func(container *api.Container, containerType ContainerType) (shouldContinue bool)
    58  
    59  // VisitContainers invokes the visitor function with a pointer to every container
    60  // spec in the given pod spec with type set in mask. If visitor returns false,
    61  // visiting is short-circuited. VisitContainers returns true if visiting completes,
    62  // false if visiting was short-circuited.
    63  func VisitContainers(podSpec *api.PodSpec, mask ContainerType, visitor ContainerVisitor) bool {
    64  	if mask&InitContainers != 0 {
    65  		for i := range podSpec.InitContainers {
    66  			if !visitor(&podSpec.InitContainers[i], InitContainers) {
    67  				return false
    68  			}
    69  		}
    70  	}
    71  	if mask&Containers != 0 {
    72  		for i := range podSpec.Containers {
    73  			if !visitor(&podSpec.Containers[i], Containers) {
    74  				return false
    75  			}
    76  		}
    77  	}
    78  	if mask&EphemeralContainers != 0 {
    79  		for i := range podSpec.EphemeralContainers {
    80  			if !visitor((*api.Container)(&podSpec.EphemeralContainers[i].EphemeralContainerCommon), EphemeralContainers) {
    81  				return false
    82  			}
    83  		}
    84  	}
    85  	return true
    86  }
    87  
    88  // Visitor is called with each object name, and returns true if visiting should continue
    89  type Visitor func(name string) (shouldContinue bool)
    90  
    91  func skipEmptyNames(visitor Visitor) Visitor {
    92  	return func(name string) bool {
    93  		if len(name) == 0 {
    94  			// continue visiting
    95  			return true
    96  		}
    97  		// delegate to visitor
    98  		return visitor(name)
    99  	}
   100  }
   101  
   102  // VisitPodSecretNames invokes the visitor function with the name of every secret
   103  // referenced by the pod spec. If visitor returns false, visiting is short-circuited.
   104  // Transitive references (e.g. pod -> pvc -> pv -> secret) are not visited.
   105  // Returns true if visiting completed, false if visiting was short-circuited.
   106  func VisitPodSecretNames(pod *api.Pod, visitor Visitor, containerType ContainerType) bool {
   107  	visitor = skipEmptyNames(visitor)
   108  	for _, reference := range pod.Spec.ImagePullSecrets {
   109  		if !visitor(reference.Name) {
   110  			return false
   111  		}
   112  	}
   113  	VisitContainers(&pod.Spec, containerType, func(c *api.Container, containerType ContainerType) bool {
   114  		return visitContainerSecretNames(c, visitor)
   115  	})
   116  	var source *api.VolumeSource
   117  	for i := range pod.Spec.Volumes {
   118  		source = &pod.Spec.Volumes[i].VolumeSource
   119  		switch {
   120  		case source.AzureFile != nil:
   121  			if len(source.AzureFile.SecretName) > 0 && !visitor(source.AzureFile.SecretName) {
   122  				return false
   123  			}
   124  		case source.CephFS != nil:
   125  			if source.CephFS.SecretRef != nil && !visitor(source.CephFS.SecretRef.Name) {
   126  				return false
   127  			}
   128  		case source.Cinder != nil:
   129  			if source.Cinder.SecretRef != nil && !visitor(source.Cinder.SecretRef.Name) {
   130  				return false
   131  			}
   132  		case source.FlexVolume != nil:
   133  			if source.FlexVolume.SecretRef != nil && !visitor(source.FlexVolume.SecretRef.Name) {
   134  				return false
   135  			}
   136  		case source.Projected != nil:
   137  			for j := range source.Projected.Sources {
   138  				if source.Projected.Sources[j].Secret != nil {
   139  					if !visitor(source.Projected.Sources[j].Secret.Name) {
   140  						return false
   141  					}
   142  				}
   143  			}
   144  		case source.RBD != nil:
   145  			if source.RBD.SecretRef != nil && !visitor(source.RBD.SecretRef.Name) {
   146  				return false
   147  			}
   148  		case source.Secret != nil:
   149  			if !visitor(source.Secret.SecretName) {
   150  				return false
   151  			}
   152  		case source.ScaleIO != nil:
   153  			if source.ScaleIO.SecretRef != nil && !visitor(source.ScaleIO.SecretRef.Name) {
   154  				return false
   155  			}
   156  		case source.ISCSI != nil:
   157  			if source.ISCSI.SecretRef != nil && !visitor(source.ISCSI.SecretRef.Name) {
   158  				return false
   159  			}
   160  		case source.StorageOS != nil:
   161  			if source.StorageOS.SecretRef != nil && !visitor(source.StorageOS.SecretRef.Name) {
   162  				return false
   163  			}
   164  		case source.CSI != nil:
   165  			if source.CSI.NodePublishSecretRef != nil && !visitor(source.CSI.NodePublishSecretRef.Name) {
   166  				return false
   167  			}
   168  		}
   169  	}
   170  	return true
   171  }
   172  
   173  func visitContainerSecretNames(container *api.Container, visitor Visitor) bool {
   174  	for _, env := range container.EnvFrom {
   175  		if env.SecretRef != nil {
   176  			if !visitor(env.SecretRef.Name) {
   177  				return false
   178  			}
   179  		}
   180  	}
   181  	for _, envVar := range container.Env {
   182  		if envVar.ValueFrom != nil && envVar.ValueFrom.SecretKeyRef != nil {
   183  			if !visitor(envVar.ValueFrom.SecretKeyRef.Name) {
   184  				return false
   185  			}
   186  		}
   187  	}
   188  	return true
   189  }
   190  
   191  // VisitPodConfigmapNames invokes the visitor function with the name of every configmap
   192  // referenced by the pod spec. If visitor returns false, visiting is short-circuited.
   193  // Transitive references (e.g. pod -> pvc -> pv -> secret) are not visited.
   194  // Returns true if visiting completed, false if visiting was short-circuited.
   195  func VisitPodConfigmapNames(pod *api.Pod, visitor Visitor, containerType ContainerType) bool {
   196  	visitor = skipEmptyNames(visitor)
   197  	VisitContainers(&pod.Spec, containerType, func(c *api.Container, containerType ContainerType) bool {
   198  		return visitContainerConfigmapNames(c, visitor)
   199  	})
   200  	var source *api.VolumeSource
   201  	for i := range pod.Spec.Volumes {
   202  		source = &pod.Spec.Volumes[i].VolumeSource
   203  		switch {
   204  		case source.Projected != nil:
   205  			for j := range source.Projected.Sources {
   206  				if source.Projected.Sources[j].ConfigMap != nil {
   207  					if !visitor(source.Projected.Sources[j].ConfigMap.Name) {
   208  						return false
   209  					}
   210  				}
   211  			}
   212  		case source.ConfigMap != nil:
   213  			if !visitor(source.ConfigMap.Name) {
   214  				return false
   215  			}
   216  		}
   217  	}
   218  	return true
   219  }
   220  
   221  func visitContainerConfigmapNames(container *api.Container, visitor Visitor) bool {
   222  	for _, env := range container.EnvFrom {
   223  		if env.ConfigMapRef != nil {
   224  			if !visitor(env.ConfigMapRef.Name) {
   225  				return false
   226  			}
   227  		}
   228  	}
   229  	for _, envVar := range container.Env {
   230  		if envVar.ValueFrom != nil && envVar.ValueFrom.ConfigMapKeyRef != nil {
   231  			if !visitor(envVar.ValueFrom.ConfigMapKeyRef.Name) {
   232  				return false
   233  			}
   234  		}
   235  	}
   236  	return true
   237  }
   238  
   239  // IsPodReady returns true if a pod is ready; false otherwise.
   240  func IsPodReady(pod *api.Pod) bool {
   241  	return IsPodReadyConditionTrue(pod.Status)
   242  }
   243  
   244  // IsPodReadyConditionTrue returns true if a pod is ready; false otherwise.
   245  func IsPodReadyConditionTrue(status api.PodStatus) bool {
   246  	condition := GetPodReadyCondition(status)
   247  	return condition != nil && condition.Status == api.ConditionTrue
   248  }
   249  
   250  // GetPodReadyCondition extracts the pod ready condition from the given status and returns that.
   251  // Returns nil if the condition is not present.
   252  func GetPodReadyCondition(status api.PodStatus) *api.PodCondition {
   253  	_, condition := GetPodCondition(&status, api.PodReady)
   254  	return condition
   255  }
   256  
   257  // GetPodCondition extracts the provided condition from the given status and returns that.
   258  // Returns nil and -1 if the condition is not present, and the index of the located condition.
   259  func GetPodCondition(status *api.PodStatus, conditionType api.PodConditionType) (int, *api.PodCondition) {
   260  	if status == nil {
   261  		return -1, nil
   262  	}
   263  	for i := range status.Conditions {
   264  		if status.Conditions[i].Type == conditionType {
   265  			return i, &status.Conditions[i]
   266  		}
   267  	}
   268  	return -1, nil
   269  }
   270  
   271  // UpdatePodCondition updates existing pod condition or creates a new one. Sets LastTransitionTime to now if the
   272  // status has changed.
   273  // Returns true if pod condition has changed or has been added.
   274  func UpdatePodCondition(status *api.PodStatus, condition *api.PodCondition) bool {
   275  	condition.LastTransitionTime = metav1.Now()
   276  	// Try to find this pod condition.
   277  	conditionIndex, oldCondition := GetPodCondition(status, condition.Type)
   278  
   279  	if oldCondition == nil {
   280  		// We are adding new pod condition.
   281  		status.Conditions = append(status.Conditions, *condition)
   282  		return true
   283  	}
   284  	// We are updating an existing condition, so we need to check if it has changed.
   285  	if condition.Status == oldCondition.Status {
   286  		condition.LastTransitionTime = oldCondition.LastTransitionTime
   287  	}
   288  
   289  	isEqual := condition.Status == oldCondition.Status &&
   290  		condition.Reason == oldCondition.Reason &&
   291  		condition.Message == oldCondition.Message &&
   292  		condition.LastProbeTime.Equal(&oldCondition.LastProbeTime) &&
   293  		condition.LastTransitionTime.Equal(&oldCondition.LastTransitionTime)
   294  
   295  	status.Conditions[conditionIndex] = *condition
   296  	// Return true if one of the fields have changed.
   297  	return !isEqual
   298  }
   299  
   300  func checkContainerUseIndivisibleHugePagesValues(container api.Container) bool {
   301  	for resourceName, quantity := range container.Resources.Limits {
   302  		if helper.IsHugePageResourceName(resourceName) {
   303  			if !helper.IsHugePageResourceValueDivisible(resourceName, quantity) {
   304  				return true
   305  			}
   306  		}
   307  	}
   308  
   309  	for resourceName, quantity := range container.Resources.Requests {
   310  		if helper.IsHugePageResourceName(resourceName) {
   311  			if !helper.IsHugePageResourceValueDivisible(resourceName, quantity) {
   312  				return true
   313  			}
   314  		}
   315  	}
   316  
   317  	return false
   318  }
   319  
   320  // usesIndivisibleHugePagesValues returns true if the one of the containers uses non-integer multiple
   321  // of huge page unit size
   322  func usesIndivisibleHugePagesValues(podSpec *api.PodSpec) bool {
   323  	foundIndivisibleHugePagesValue := false
   324  	VisitContainers(podSpec, AllContainers, func(c *api.Container, containerType ContainerType) bool {
   325  		if checkContainerUseIndivisibleHugePagesValues(*c) {
   326  			foundIndivisibleHugePagesValue = true
   327  		}
   328  		return !foundIndivisibleHugePagesValue // continue visiting if we haven't seen an invalid value yet
   329  	})
   330  
   331  	if foundIndivisibleHugePagesValue {
   332  		return true
   333  	}
   334  
   335  	for resourceName, quantity := range podSpec.Overhead {
   336  		if helper.IsHugePageResourceName(resourceName) {
   337  			if !helper.IsHugePageResourceValueDivisible(resourceName, quantity) {
   338  				return true
   339  			}
   340  		}
   341  	}
   342  
   343  	return false
   344  }
   345  
   346  // hasInvalidTopologySpreadConstraintLabelSelector return true if spec.TopologySpreadConstraints have any entry with invalid labelSelector
   347  func hasInvalidTopologySpreadConstraintLabelSelector(spec *api.PodSpec) bool {
   348  	for _, constraint := range spec.TopologySpreadConstraints {
   349  		errs := metavalidation.ValidateLabelSelector(constraint.LabelSelector, metavalidation.LabelSelectorValidationOptions{AllowInvalidLabelValueInSelector: false}, nil)
   350  		if len(errs) != 0 {
   351  			return true
   352  		}
   353  	}
   354  	return false
   355  }
   356  
   357  // hasNonLocalProjectedTokenPath return true if spec.Volumes have any entry with non-local projected token path
   358  func hasNonLocalProjectedTokenPath(spec *api.PodSpec) bool {
   359  	for _, volume := range spec.Volumes {
   360  		if volume.Projected != nil {
   361  			for _, source := range volume.Projected.Sources {
   362  				if source.ServiceAccountToken == nil {
   363  					continue
   364  				}
   365  				errs := apivalidation.ValidateLocalNonReservedPath(source.ServiceAccountToken.Path, nil)
   366  				if len(errs) != 0 {
   367  					return true
   368  				}
   369  			}
   370  		}
   371  	}
   372  	return false
   373  }
   374  
   375  // GetValidationOptionsFromPodSpecAndMeta returns validation options based on pod specs and metadata
   376  func GetValidationOptionsFromPodSpecAndMeta(podSpec, oldPodSpec *api.PodSpec, podMeta, oldPodMeta *metav1.ObjectMeta) apivalidation.PodValidationOptions {
   377  	// default pod validation options based on feature gate
   378  	opts := apivalidation.PodValidationOptions{
   379  		AllowInvalidPodDeletionCost: !utilfeature.DefaultFeatureGate.Enabled(features.PodDeletionCost),
   380  		// Allow pod spec to use status.hostIPs in downward API if feature is enabled
   381  		AllowHostIPsField: utilfeature.DefaultFeatureGate.Enabled(features.PodHostIPs),
   382  		// Do not allow pod spec to use non-integer multiple of huge page unit size default
   383  		AllowIndivisibleHugePagesValues:                   false,
   384  		AllowInvalidLabelValueInSelector:                  false,
   385  		AllowInvalidTopologySpreadConstraintLabelSelector: false,
   386  		AllowNamespacedSysctlsForHostNetAndHostIPC:        false,
   387  		AllowNonLocalProjectedTokenPath:                   false,
   388  	}
   389  
   390  	// If old spec uses relaxed validation or enabled the RelaxedEnvironmentVariableValidation feature gate,
   391  	// we must allow it
   392  	opts.AllowRelaxedEnvironmentVariableValidation = useRelaxedEnvironmentVariableValidation(podSpec, oldPodSpec)
   393  
   394  	if oldPodSpec != nil {
   395  		// if old spec has status.hostIPs downwardAPI set, we must allow it
   396  		opts.AllowHostIPsField = opts.AllowHostIPsField || hasUsedDownwardAPIFieldPathWithPodSpec(oldPodSpec, "status.hostIPs")
   397  
   398  		// if old spec used non-integer multiple of huge page unit size, we must allow it
   399  		opts.AllowIndivisibleHugePagesValues = usesIndivisibleHugePagesValues(oldPodSpec)
   400  
   401  		opts.AllowInvalidLabelValueInSelector = hasInvalidLabelValueInAffinitySelector(oldPodSpec)
   402  		// if old spec has invalid labelSelector in topologySpreadConstraint, we must allow it
   403  		opts.AllowInvalidTopologySpreadConstraintLabelSelector = hasInvalidTopologySpreadConstraintLabelSelector(oldPodSpec)
   404  		// if old spec has an invalid projected token volume path, we must allow it
   405  		opts.AllowNonLocalProjectedTokenPath = hasNonLocalProjectedTokenPath(oldPodSpec)
   406  
   407  		// if old spec has invalid sysctl with hostNet or hostIPC, we must allow it when update
   408  		if oldPodSpec.SecurityContext != nil && len(oldPodSpec.SecurityContext.Sysctls) != 0 {
   409  			for _, s := range oldPodSpec.SecurityContext.Sysctls {
   410  				err := apivalidation.ValidateHostSysctl(s.Name, oldPodSpec.SecurityContext, nil)
   411  				if err != nil {
   412  					opts.AllowNamespacedSysctlsForHostNetAndHostIPC = true
   413  					break
   414  				}
   415  			}
   416  		}
   417  	}
   418  	if oldPodMeta != nil && !opts.AllowInvalidPodDeletionCost {
   419  		// This is an update, so validate only if the existing object was valid.
   420  		_, err := helper.GetDeletionCostFromPodAnnotations(oldPodMeta.Annotations)
   421  		opts.AllowInvalidPodDeletionCost = err != nil
   422  	}
   423  
   424  	return opts
   425  }
   426  
   427  func useRelaxedEnvironmentVariableValidation(podSpec, oldPodSpec *api.PodSpec) bool {
   428  	if utilfeature.DefaultFeatureGate.Enabled(features.RelaxedEnvironmentVariableValidation) {
   429  		return true
   430  	}
   431  
   432  	var oldPodEnvVarNames, podEnvVarNames sets.Set[string]
   433  	if oldPodSpec != nil {
   434  		oldPodEnvVarNames = gatherPodEnvVarNames(oldPodSpec)
   435  	}
   436  
   437  	if podSpec != nil {
   438  		podEnvVarNames = gatherPodEnvVarNames(podSpec)
   439  	}
   440  
   441  	for env := range podEnvVarNames {
   442  		if relaxedEnvVarUsed(env, oldPodEnvVarNames) {
   443  			return true
   444  		}
   445  	}
   446  
   447  	return false
   448  }
   449  
   450  func gatherPodEnvVarNames(podSpec *api.PodSpec) sets.Set[string] {
   451  	podEnvVarNames := sets.Set[string]{}
   452  
   453  	for _, c := range podSpec.Containers {
   454  		for _, env := range c.Env {
   455  			podEnvVarNames.Insert(env.Name)
   456  		}
   457  
   458  		for _, env := range c.EnvFrom {
   459  			podEnvVarNames.Insert(env.Prefix)
   460  		}
   461  	}
   462  
   463  	for _, c := range podSpec.InitContainers {
   464  		for _, env := range c.Env {
   465  			podEnvVarNames.Insert(env.Name)
   466  		}
   467  
   468  		for _, env := range c.EnvFrom {
   469  			podEnvVarNames.Insert(env.Prefix)
   470  		}
   471  	}
   472  
   473  	for _, c := range podSpec.EphemeralContainers {
   474  		for _, env := range c.Env {
   475  			podEnvVarNames.Insert(env.Name)
   476  		}
   477  
   478  		for _, env := range c.EnvFrom {
   479  			podEnvVarNames.Insert(env.Prefix)
   480  		}
   481  	}
   482  
   483  	return podEnvVarNames
   484  }
   485  
   486  func relaxedEnvVarUsed(name string, oldPodEnvVarNames sets.Set[string]) bool {
   487  	// A length of 0 means this is not an update request,
   488  	// or the old pod does not exist in the env.
   489  	// We will let the feature gate decide whether to use relaxed rules.
   490  	if oldPodEnvVarNames.Len() == 0 {
   491  		return false
   492  	}
   493  
   494  	if len(validation.IsEnvVarName(name)) == 0 || len(validation.IsRelaxedEnvVarName(name)) != 0 {
   495  		// It's either a valid name by strict rules or an invalid name under relaxed rules.
   496  		// Either way, we'll use strict rules to validate.
   497  		return false
   498  	}
   499  
   500  	// The name in question failed strict rules but passed relaxed rules.
   501  	if oldPodEnvVarNames.Has(name) {
   502  		// This relaxed-rules name was already in use.
   503  		return true
   504  	}
   505  
   506  	return false
   507  }
   508  
   509  func hasUsedDownwardAPIFieldPathWithPodSpec(podSpec *api.PodSpec, fieldPath string) bool {
   510  	if podSpec == nil {
   511  		return false
   512  	}
   513  	for _, vol := range podSpec.Volumes {
   514  		if hasUsedDownwardAPIFieldPathWithVolume(&vol, fieldPath) {
   515  			return true
   516  		}
   517  	}
   518  	for _, c := range podSpec.InitContainers {
   519  		if hasUsedDownwardAPIFieldPathWithContainer(&c, fieldPath) {
   520  			return true
   521  		}
   522  	}
   523  	for _, c := range podSpec.Containers {
   524  		if hasUsedDownwardAPIFieldPathWithContainer(&c, fieldPath) {
   525  			return true
   526  		}
   527  	}
   528  	return false
   529  }
   530  
   531  func hasUsedDownwardAPIFieldPathWithVolume(volume *api.Volume, fieldPath string) bool {
   532  	if volume == nil || volume.DownwardAPI == nil {
   533  		return false
   534  	}
   535  	for _, file := range volume.DownwardAPI.Items {
   536  		if file.FieldRef != nil &&
   537  			file.FieldRef.FieldPath == fieldPath {
   538  			return true
   539  		}
   540  	}
   541  	return false
   542  }
   543  
   544  func hasUsedDownwardAPIFieldPathWithContainer(container *api.Container, fieldPath string) bool {
   545  	if container == nil {
   546  		return false
   547  	}
   548  	for _, env := range container.Env {
   549  		if env.ValueFrom != nil &&
   550  			env.ValueFrom.FieldRef != nil &&
   551  			env.ValueFrom.FieldRef.FieldPath == fieldPath {
   552  			return true
   553  		}
   554  	}
   555  	return false
   556  }
   557  
   558  // GetValidationOptionsFromPodTemplate will return pod validation options for specified template.
   559  func GetValidationOptionsFromPodTemplate(podTemplate, oldPodTemplate *api.PodTemplateSpec) apivalidation.PodValidationOptions {
   560  	var newPodSpec, oldPodSpec *api.PodSpec
   561  	var newPodMeta, oldPodMeta *metav1.ObjectMeta
   562  	// we have to be careful about nil pointers here
   563  	// replication controller in particular is prone to passing nil
   564  	if podTemplate != nil {
   565  		newPodSpec = &podTemplate.Spec
   566  		newPodMeta = &podTemplate.ObjectMeta
   567  	}
   568  	if oldPodTemplate != nil {
   569  		oldPodSpec = &oldPodTemplate.Spec
   570  		oldPodMeta = &oldPodTemplate.ObjectMeta
   571  	}
   572  	return GetValidationOptionsFromPodSpecAndMeta(newPodSpec, oldPodSpec, newPodMeta, oldPodMeta)
   573  }
   574  
   575  // DropDisabledTemplateFields removes disabled fields from the pod template metadata and spec.
   576  // This should be called from PrepareForCreate/PrepareForUpdate for all resources containing a PodTemplateSpec
   577  func DropDisabledTemplateFields(podTemplate, oldPodTemplate *api.PodTemplateSpec) {
   578  	var (
   579  		podSpec           *api.PodSpec
   580  		podAnnotations    map[string]string
   581  		oldPodSpec        *api.PodSpec
   582  		oldPodAnnotations map[string]string
   583  	)
   584  	if podTemplate != nil {
   585  		podSpec = &podTemplate.Spec
   586  		podAnnotations = podTemplate.Annotations
   587  	}
   588  	if oldPodTemplate != nil {
   589  		oldPodSpec = &oldPodTemplate.Spec
   590  		oldPodAnnotations = oldPodTemplate.Annotations
   591  	}
   592  	dropDisabledFields(podSpec, podAnnotations, oldPodSpec, oldPodAnnotations)
   593  }
   594  
   595  // DropDisabledPodFields removes disabled fields from the pod metadata and spec.
   596  // This should be called from PrepareForCreate/PrepareForUpdate for all resources containing a Pod
   597  func DropDisabledPodFields(pod, oldPod *api.Pod) {
   598  	var (
   599  		podSpec           *api.PodSpec
   600  		podStatus         *api.PodStatus
   601  		podAnnotations    map[string]string
   602  		oldPodSpec        *api.PodSpec
   603  		oldPodStatus      *api.PodStatus
   604  		oldPodAnnotations map[string]string
   605  	)
   606  	if pod != nil {
   607  		podSpec = &pod.Spec
   608  		podStatus = &pod.Status
   609  		podAnnotations = pod.Annotations
   610  	}
   611  	if oldPod != nil {
   612  		oldPodSpec = &oldPod.Spec
   613  		oldPodStatus = &oldPod.Status
   614  		oldPodAnnotations = oldPod.Annotations
   615  	}
   616  	dropDisabledFields(podSpec, podAnnotations, oldPodSpec, oldPodAnnotations)
   617  	dropDisabledPodStatusFields(podStatus, oldPodStatus, podSpec, oldPodSpec)
   618  }
   619  
   620  // dropDisabledFields removes disabled fields from the pod metadata and spec.
   621  func dropDisabledFields(
   622  	podSpec *api.PodSpec, podAnnotations map[string]string,
   623  	oldPodSpec *api.PodSpec, oldPodAnnotations map[string]string,
   624  ) {
   625  	// the new spec must always be non-nil
   626  	if podSpec == nil {
   627  		podSpec = &api.PodSpec{}
   628  	}
   629  
   630  	if !utilfeature.DefaultFeatureGate.Enabled(features.AppArmor) && !appArmorAnnotationsInUse(oldPodAnnotations) {
   631  		for k := range podAnnotations {
   632  			if strings.HasPrefix(k, api.DeprecatedAppArmorAnnotationKeyPrefix) {
   633  				delete(podAnnotations, k)
   634  			}
   635  		}
   636  	}
   637  	if (!utilfeature.DefaultFeatureGate.Enabled(features.AppArmor) || !utilfeature.DefaultFeatureGate.Enabled(features.AppArmorFields)) && !appArmorFieldsInUse(oldPodSpec) {
   638  		if podSpec.SecurityContext != nil {
   639  			podSpec.SecurityContext.AppArmorProfile = nil
   640  		}
   641  		VisitContainers(podSpec, AllContainers, func(c *api.Container, _ ContainerType) bool {
   642  			if c.SecurityContext != nil {
   643  				c.SecurityContext.AppArmorProfile = nil
   644  			}
   645  			return true
   646  		})
   647  	}
   648  
   649  	// If the feature is disabled and not in use, drop the hostUsers field.
   650  	if !utilfeature.DefaultFeatureGate.Enabled(features.UserNamespacesSupport) && !hostUsersInUse(oldPodSpec) {
   651  		// Drop the field in podSpec only if SecurityContext is not nil.
   652  		// If it is nil, there is no need to set hostUsers=nil (it will be nil too).
   653  		if podSpec.SecurityContext != nil {
   654  			podSpec.SecurityContext.HostUsers = nil
   655  		}
   656  	}
   657  
   658  	dropDisabledProcMountField(podSpec, oldPodSpec)
   659  
   660  	dropDisabledNodeInclusionPolicyFields(podSpec, oldPodSpec)
   661  	dropDisabledMatchLabelKeysFieldInTopologySpread(podSpec, oldPodSpec)
   662  	dropDisabledMatchLabelKeysFieldInPodAffinity(podSpec, oldPodSpec)
   663  	dropDisabledDynamicResourceAllocationFields(podSpec, oldPodSpec)
   664  	dropDisabledClusterTrustBundleProjection(podSpec, oldPodSpec)
   665  
   666  	if !utilfeature.DefaultFeatureGate.Enabled(features.InPlacePodVerticalScaling) && !inPlacePodVerticalScalingInUse(oldPodSpec) {
   667  		// Drop ResizePolicy fields. Don't drop updates to Resources field as template.spec.resources
   668  		// field is mutable for certain controllers. Let ValidatePodUpdate handle it.
   669  		for i := range podSpec.Containers {
   670  			podSpec.Containers[i].ResizePolicy = nil
   671  		}
   672  		for i := range podSpec.InitContainers {
   673  			podSpec.InitContainers[i].ResizePolicy = nil
   674  		}
   675  		for i := range podSpec.EphemeralContainers {
   676  			podSpec.EphemeralContainers[i].ResizePolicy = nil
   677  		}
   678  	}
   679  
   680  	if !utilfeature.DefaultFeatureGate.Enabled(features.SidecarContainers) && !restartableInitContainersInUse(oldPodSpec) {
   681  		// Drop the RestartPolicy field of init containers.
   682  		for i := range podSpec.InitContainers {
   683  			podSpec.InitContainers[i].RestartPolicy = nil
   684  		}
   685  		// For other types of containers, validateContainers will handle them.
   686  	}
   687  
   688  	if !utilfeature.DefaultFeatureGate.Enabled(features.RecursiveReadOnlyMounts) && !rroInUse(oldPodSpec) {
   689  		for i := range podSpec.Containers {
   690  			for j := range podSpec.Containers[i].VolumeMounts {
   691  				podSpec.Containers[i].VolumeMounts[j].RecursiveReadOnly = nil
   692  			}
   693  		}
   694  		for i := range podSpec.InitContainers {
   695  			for j := range podSpec.InitContainers[i].VolumeMounts {
   696  				podSpec.InitContainers[i].VolumeMounts[j].RecursiveReadOnly = nil
   697  			}
   698  		}
   699  		for i := range podSpec.EphemeralContainers {
   700  			for j := range podSpec.EphemeralContainers[i].VolumeMounts {
   701  				podSpec.EphemeralContainers[i].VolumeMounts[j].RecursiveReadOnly = nil
   702  			}
   703  		}
   704  	}
   705  
   706  	dropPodLifecycleSleepAction(podSpec, oldPodSpec)
   707  }
   708  
   709  func dropPodLifecycleSleepAction(podSpec, oldPodSpec *api.PodSpec) {
   710  	if utilfeature.DefaultFeatureGate.Enabled(features.PodLifecycleSleepAction) || podLifecycleSleepActionInUse(oldPodSpec) {
   711  		return
   712  	}
   713  
   714  	adjustLifecycle := func(lifecycle *api.Lifecycle) {
   715  		if lifecycle.PreStop != nil && lifecycle.PreStop.Sleep != nil {
   716  			lifecycle.PreStop.Sleep = nil
   717  			if lifecycle.PreStop.Exec == nil && lifecycle.PreStop.HTTPGet == nil && lifecycle.PreStop.TCPSocket == nil {
   718  				lifecycle.PreStop = nil
   719  			}
   720  		}
   721  		if lifecycle.PostStart != nil && lifecycle.PostStart.Sleep != nil {
   722  			lifecycle.PostStart.Sleep = nil
   723  			if lifecycle.PostStart.Exec == nil && lifecycle.PostStart.HTTPGet == nil && lifecycle.PostStart.TCPSocket == nil {
   724  				lifecycle.PostStart = nil
   725  			}
   726  		}
   727  	}
   728  
   729  	for i := range podSpec.Containers {
   730  		if podSpec.Containers[i].Lifecycle == nil {
   731  			continue
   732  		}
   733  		adjustLifecycle(podSpec.Containers[i].Lifecycle)
   734  		if podSpec.Containers[i].Lifecycle.PreStop == nil && podSpec.Containers[i].Lifecycle.PostStart == nil {
   735  			podSpec.Containers[i].Lifecycle = nil
   736  		}
   737  	}
   738  
   739  	for i := range podSpec.InitContainers {
   740  		if podSpec.InitContainers[i].Lifecycle == nil {
   741  			continue
   742  		}
   743  		adjustLifecycle(podSpec.InitContainers[i].Lifecycle)
   744  		if podSpec.InitContainers[i].Lifecycle.PreStop == nil && podSpec.InitContainers[i].Lifecycle.PostStart == nil {
   745  			podSpec.InitContainers[i].Lifecycle = nil
   746  		}
   747  	}
   748  
   749  	for i := range podSpec.EphemeralContainers {
   750  		if podSpec.EphemeralContainers[i].Lifecycle == nil {
   751  			continue
   752  		}
   753  		adjustLifecycle(podSpec.EphemeralContainers[i].Lifecycle)
   754  		if podSpec.EphemeralContainers[i].Lifecycle.PreStop == nil && podSpec.EphemeralContainers[i].Lifecycle.PostStart == nil {
   755  			podSpec.EphemeralContainers[i].Lifecycle = nil
   756  		}
   757  	}
   758  }
   759  
   760  func podLifecycleSleepActionInUse(podSpec *api.PodSpec) bool {
   761  	if podSpec == nil {
   762  		return false
   763  	}
   764  	var inUse bool
   765  	VisitContainers(podSpec, AllContainers, func(c *api.Container, containerType ContainerType) bool {
   766  		if c.Lifecycle == nil {
   767  			return true
   768  		}
   769  		if c.Lifecycle.PreStop != nil && c.Lifecycle.PreStop.Sleep != nil {
   770  			inUse = true
   771  			return false
   772  		}
   773  		if c.Lifecycle.PostStart != nil && c.Lifecycle.PostStart.Sleep != nil {
   774  			inUse = true
   775  			return false
   776  		}
   777  		return true
   778  	})
   779  	return inUse
   780  }
   781  
   782  // dropDisabledPodStatusFields removes disabled fields from the pod status
   783  func dropDisabledPodStatusFields(podStatus, oldPodStatus *api.PodStatus, podSpec, oldPodSpec *api.PodSpec) {
   784  	// the new status is always be non-nil
   785  	if podStatus == nil {
   786  		podStatus = &api.PodStatus{}
   787  	}
   788  
   789  	if !utilfeature.DefaultFeatureGate.Enabled(features.InPlacePodVerticalScaling) && !inPlacePodVerticalScalingInUse(oldPodSpec) {
   790  		// Drop Resize, AllocatedResources, and Resources fields
   791  		dropResourcesFields := func(csl []api.ContainerStatus) {
   792  			for i := range csl {
   793  				csl[i].AllocatedResources = nil
   794  				csl[i].Resources = nil
   795  			}
   796  		}
   797  		dropResourcesFields(podStatus.ContainerStatuses)
   798  		dropResourcesFields(podStatus.InitContainerStatuses)
   799  		dropResourcesFields(podStatus.EphemeralContainerStatuses)
   800  		podStatus.Resize = ""
   801  	}
   802  
   803  	if !utilfeature.DefaultFeatureGate.Enabled(features.DynamicResourceAllocation) && !dynamicResourceAllocationInUse(oldPodSpec) {
   804  		podStatus.ResourceClaimStatuses = nil
   805  	}
   806  
   807  	// drop HostIPs to empty (disable PodHostIPs).
   808  	if !utilfeature.DefaultFeatureGate.Enabled(features.PodHostIPs) && !hostIPsInUse(oldPodStatus) {
   809  		podStatus.HostIPs = nil
   810  	}
   811  
   812  	if !utilfeature.DefaultFeatureGate.Enabled(features.RecursiveReadOnlyMounts) && !rroInUse(oldPodSpec) {
   813  		for i := range podStatus.ContainerStatuses {
   814  			podStatus.ContainerStatuses[i].VolumeMounts = nil
   815  		}
   816  		for i := range podStatus.InitContainerStatuses {
   817  			podStatus.InitContainerStatuses[i].VolumeMounts = nil
   818  		}
   819  		for i := range podStatus.EphemeralContainerStatuses {
   820  			podStatus.EphemeralContainerStatuses[i].VolumeMounts = nil
   821  		}
   822  	}
   823  }
   824  
   825  func hostIPsInUse(podStatus *api.PodStatus) bool {
   826  	if podStatus == nil {
   827  		return false
   828  	}
   829  	return len(podStatus.HostIPs) > 0
   830  }
   831  
   832  // dropDisabledDynamicResourceAllocationFields removes pod claim references from
   833  // container specs and pod-level resource claims unless they are already used
   834  // by the old pod spec.
   835  func dropDisabledDynamicResourceAllocationFields(podSpec, oldPodSpec *api.PodSpec) {
   836  	if !utilfeature.DefaultFeatureGate.Enabled(features.DynamicResourceAllocation) && !dynamicResourceAllocationInUse(oldPodSpec) {
   837  		dropResourceClaimRequests(podSpec.Containers)
   838  		dropResourceClaimRequests(podSpec.InitContainers)
   839  		dropEphemeralResourceClaimRequests(podSpec.EphemeralContainers)
   840  		podSpec.ResourceClaims = nil
   841  	}
   842  }
   843  
   844  func dynamicResourceAllocationInUse(podSpec *api.PodSpec) bool {
   845  	if podSpec == nil {
   846  		return false
   847  	}
   848  
   849  	// We only need to check this field because the containers cannot have
   850  	// resource requirements entries for claims without a corresponding
   851  	// entry at the pod spec level.
   852  	return len(podSpec.ResourceClaims) > 0
   853  }
   854  
   855  func dropResourceClaimRequests(containers []api.Container) {
   856  	for i := range containers {
   857  		containers[i].Resources.Claims = nil
   858  	}
   859  }
   860  
   861  func dropEphemeralResourceClaimRequests(containers []api.EphemeralContainer) {
   862  	for i := range containers {
   863  		containers[i].Resources.Claims = nil
   864  	}
   865  }
   866  
   867  // dropDisabledProcMountField removes disabled fields from PodSpec related
   868  // to ProcMount only if it is not already used by the old spec
   869  func dropDisabledProcMountField(podSpec, oldPodSpec *api.PodSpec) {
   870  	if !utilfeature.DefaultFeatureGate.Enabled(features.ProcMountType) && !procMountInUse(oldPodSpec) {
   871  		defaultProcMount := api.DefaultProcMount
   872  		VisitContainers(podSpec, AllContainers, func(c *api.Container, containerType ContainerType) bool {
   873  			if c.SecurityContext != nil && c.SecurityContext.ProcMount != nil {
   874  				// The ProcMount field was improperly forced to non-nil in 1.12.
   875  				// 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.
   876  				// Note: we cannot force the field to nil when the feature is disabled because it causes a diff against previously persisted data.
   877  				c.SecurityContext.ProcMount = &defaultProcMount
   878  			}
   879  			return true
   880  		})
   881  	}
   882  }
   883  
   884  // dropDisabledNodeInclusionPolicyFields removes disabled fields from PodSpec related
   885  // to NodeInclusionPolicy only if it is not used by the old spec.
   886  func dropDisabledNodeInclusionPolicyFields(podSpec, oldPodSpec *api.PodSpec) {
   887  	if !utilfeature.DefaultFeatureGate.Enabled(features.NodeInclusionPolicyInPodTopologySpread) && podSpec != nil {
   888  		if !nodeTaintsPolicyInUse(oldPodSpec) {
   889  			for i := range podSpec.TopologySpreadConstraints {
   890  				podSpec.TopologySpreadConstraints[i].NodeTaintsPolicy = nil
   891  			}
   892  		}
   893  		if !nodeAffinityPolicyInUse(oldPodSpec) {
   894  			for i := range podSpec.TopologySpreadConstraints {
   895  				podSpec.TopologySpreadConstraints[i].NodeAffinityPolicy = nil
   896  			}
   897  		}
   898  	}
   899  }
   900  
   901  // dropDisabledMatchLabelKeysFieldInPodAffinity removes disabled fields from PodSpec related
   902  // to MatchLabelKeys in required/preferred PodAffinity/PodAntiAffinity only if it is not already used by the old spec.
   903  func dropDisabledMatchLabelKeysFieldInPodAffinity(podSpec, oldPodSpec *api.PodSpec) {
   904  	if podSpec == nil || podSpec.Affinity == nil || utilfeature.DefaultFeatureGate.Enabled(features.MatchLabelKeysInPodAffinity) || matchLabelKeysFieldInPodAffinityInUse(oldPodSpec) {
   905  		return
   906  	}
   907  
   908  	if affinity := podSpec.Affinity.PodAffinity; affinity != nil {
   909  		dropMatchLabelKeysFieldInPodAffnityTerm(affinity.RequiredDuringSchedulingIgnoredDuringExecution)
   910  		dropMatchLabelKeysFieldInWeightedPodAffnityTerm(affinity.PreferredDuringSchedulingIgnoredDuringExecution)
   911  	}
   912  	if antiaffinity := podSpec.Affinity.PodAntiAffinity; antiaffinity != nil {
   913  		dropMatchLabelKeysFieldInPodAffnityTerm(antiaffinity.RequiredDuringSchedulingIgnoredDuringExecution)
   914  		dropMatchLabelKeysFieldInWeightedPodAffnityTerm(antiaffinity.PreferredDuringSchedulingIgnoredDuringExecution)
   915  	}
   916  }
   917  
   918  // dropDisabledMatchLabelKeysFieldInTopologySpread removes disabled fields from PodSpec related
   919  // to MatchLabelKeys in TopologySpread only if it is not already used by the old spec.
   920  func dropDisabledMatchLabelKeysFieldInTopologySpread(podSpec, oldPodSpec *api.PodSpec) {
   921  	if !utilfeature.DefaultFeatureGate.Enabled(features.MatchLabelKeysInPodTopologySpread) && !matchLabelKeysInTopologySpreadInUse(oldPodSpec) {
   922  		for i := range podSpec.TopologySpreadConstraints {
   923  			podSpec.TopologySpreadConstraints[i].MatchLabelKeys = nil
   924  		}
   925  	}
   926  }
   927  
   928  // dropMatchLabelKeysFieldInWeightedPodAffnityTerm removes MatchLabelKeys and MismatchLabelKeys fields from WeightedPodAffinityTerm
   929  func dropMatchLabelKeysFieldInWeightedPodAffnityTerm(terms []api.WeightedPodAffinityTerm) {
   930  	for i := range terms {
   931  		terms[i].PodAffinityTerm.MatchLabelKeys = nil
   932  		terms[i].PodAffinityTerm.MismatchLabelKeys = nil
   933  	}
   934  }
   935  
   936  // dropMatchLabelKeysFieldInPodAffnityTerm removes MatchLabelKeys and MismatchLabelKeys fields from PodAffinityTerm
   937  func dropMatchLabelKeysFieldInPodAffnityTerm(terms []api.PodAffinityTerm) {
   938  	for i := range terms {
   939  		terms[i].MatchLabelKeys = nil
   940  		terms[i].MismatchLabelKeys = nil
   941  	}
   942  }
   943  
   944  // matchLabelKeysFieldInPodAffinityInUse returns true if given affinityTerms have MatchLabelKeys field set.
   945  func matchLabelKeysFieldInPodAffinityInUse(podSpec *api.PodSpec) bool {
   946  	if podSpec == nil || podSpec.Affinity == nil {
   947  		return false
   948  	}
   949  
   950  	if affinity := podSpec.Affinity.PodAffinity; affinity != nil {
   951  		for _, c := range affinity.RequiredDuringSchedulingIgnoredDuringExecution {
   952  			if len(c.MatchLabelKeys) > 0 || len(c.MismatchLabelKeys) > 0 {
   953  				return true
   954  			}
   955  		}
   956  
   957  		for _, c := range affinity.PreferredDuringSchedulingIgnoredDuringExecution {
   958  			if len(c.PodAffinityTerm.MatchLabelKeys) > 0 || len(c.PodAffinityTerm.MismatchLabelKeys) > 0 {
   959  				return true
   960  			}
   961  		}
   962  	}
   963  
   964  	if antiAffinity := podSpec.Affinity.PodAntiAffinity; antiAffinity != nil {
   965  		for _, c := range antiAffinity.RequiredDuringSchedulingIgnoredDuringExecution {
   966  			if len(c.MatchLabelKeys) > 0 || len(c.MismatchLabelKeys) > 0 {
   967  				return true
   968  			}
   969  		}
   970  
   971  		for _, c := range antiAffinity.PreferredDuringSchedulingIgnoredDuringExecution {
   972  			if len(c.PodAffinityTerm.MatchLabelKeys) > 0 || len(c.PodAffinityTerm.MismatchLabelKeys) > 0 {
   973  				return true
   974  			}
   975  		}
   976  	}
   977  
   978  	return false
   979  }
   980  
   981  // matchLabelKeysInTopologySpreadInUse returns true if the pod spec is non-nil
   982  // and has MatchLabelKeys field set in TopologySpreadConstraints.
   983  func matchLabelKeysInTopologySpreadInUse(podSpec *api.PodSpec) bool {
   984  	if podSpec == nil {
   985  		return false
   986  	}
   987  
   988  	for _, c := range podSpec.TopologySpreadConstraints {
   989  		if len(c.MatchLabelKeys) > 0 {
   990  			return true
   991  		}
   992  	}
   993  	return false
   994  }
   995  
   996  // nodeAffinityPolicyInUse returns true if the pod spec is non-nil and has NodeAffinityPolicy field set
   997  // in TopologySpreadConstraints
   998  func nodeAffinityPolicyInUse(podSpec *api.PodSpec) bool {
   999  	if podSpec == nil {
  1000  		return false
  1001  	}
  1002  	for _, c := range podSpec.TopologySpreadConstraints {
  1003  		if c.NodeAffinityPolicy != nil {
  1004  			return true
  1005  		}
  1006  	}
  1007  	return false
  1008  }
  1009  
  1010  // nodeTaintsPolicyInUse returns true if the pod spec is non-nil and has NodeTaintsPolicy field set
  1011  // in TopologySpreadConstraints
  1012  func nodeTaintsPolicyInUse(podSpec *api.PodSpec) bool {
  1013  	if podSpec == nil {
  1014  		return false
  1015  	}
  1016  	for _, c := range podSpec.TopologySpreadConstraints {
  1017  		if c.NodeTaintsPolicy != nil {
  1018  			return true
  1019  		}
  1020  	}
  1021  	return false
  1022  }
  1023  
  1024  // hostUsersInUse returns true if the pod spec has spec.hostUsers field set.
  1025  func hostUsersInUse(podSpec *api.PodSpec) bool {
  1026  	if podSpec != nil && podSpec.SecurityContext != nil && podSpec.SecurityContext.HostUsers != nil {
  1027  		return true
  1028  	}
  1029  
  1030  	return false
  1031  }
  1032  
  1033  // inPlacePodVerticalScalingInUse returns true if pod spec is non-nil and ResizePolicy is set
  1034  func inPlacePodVerticalScalingInUse(podSpec *api.PodSpec) bool {
  1035  	if podSpec == nil {
  1036  		return false
  1037  	}
  1038  	var inUse bool
  1039  	VisitContainers(podSpec, Containers, func(c *api.Container, containerType ContainerType) bool {
  1040  		if len(c.ResizePolicy) > 0 {
  1041  			inUse = true
  1042  			return false
  1043  		}
  1044  		return true
  1045  	})
  1046  	return inUse
  1047  }
  1048  
  1049  // procMountInUse returns true if the pod spec is non-nil and has a SecurityContext's ProcMount field set to a non-default value
  1050  func procMountInUse(podSpec *api.PodSpec) bool {
  1051  	if podSpec == nil {
  1052  		return false
  1053  	}
  1054  
  1055  	var inUse bool
  1056  	VisitContainers(podSpec, AllContainers, func(c *api.Container, containerType ContainerType) bool {
  1057  		if c.SecurityContext == nil || c.SecurityContext.ProcMount == nil {
  1058  			return true
  1059  		}
  1060  		if *c.SecurityContext.ProcMount != api.DefaultProcMount {
  1061  			inUse = true
  1062  			return false
  1063  		}
  1064  		return true
  1065  	})
  1066  
  1067  	return inUse
  1068  }
  1069  
  1070  // appArmorAnnotationsInUse returns true if the pod has apparmor annotations
  1071  func appArmorAnnotationsInUse(podAnnotations map[string]string) bool {
  1072  	for k := range podAnnotations {
  1073  		if strings.HasPrefix(k, api.DeprecatedAppArmorAnnotationKeyPrefix) {
  1074  			return true
  1075  		}
  1076  	}
  1077  	return false
  1078  }
  1079  
  1080  // appArmorFieldsInUse returns true if the pod has apparmor fields set
  1081  func appArmorFieldsInUse(podSpec *api.PodSpec) bool {
  1082  	if podSpec == nil {
  1083  		return false
  1084  	}
  1085  	if podSpec.SecurityContext != nil && podSpec.SecurityContext.AppArmorProfile != nil {
  1086  		return true
  1087  	}
  1088  	hasAppArmorContainer := false
  1089  	VisitContainers(podSpec, AllContainers, func(c *api.Container, _ ContainerType) bool {
  1090  		if c.SecurityContext != nil && c.SecurityContext.AppArmorProfile != nil {
  1091  			hasAppArmorContainer = true
  1092  			return false
  1093  		}
  1094  		return true
  1095  	})
  1096  	return hasAppArmorContainer
  1097  }
  1098  
  1099  // restartableInitContainersInUse returns true if the pod spec is non-nil and
  1100  // it has any init container with ContainerRestartPolicyAlways.
  1101  func restartableInitContainersInUse(podSpec *api.PodSpec) bool {
  1102  	if podSpec == nil {
  1103  		return false
  1104  	}
  1105  	var inUse bool
  1106  	VisitContainers(podSpec, InitContainers, func(c *api.Container, containerType ContainerType) bool {
  1107  		if c.RestartPolicy != nil && *c.RestartPolicy == api.ContainerRestartPolicyAlways {
  1108  			inUse = true
  1109  			return false
  1110  		}
  1111  		return true
  1112  	})
  1113  	return inUse
  1114  }
  1115  
  1116  func clusterTrustBundleProjectionInUse(podSpec *api.PodSpec) bool {
  1117  	if podSpec == nil {
  1118  		return false
  1119  	}
  1120  	for _, v := range podSpec.Volumes {
  1121  		if v.Projected == nil {
  1122  			continue
  1123  		}
  1124  
  1125  		for _, s := range v.Projected.Sources {
  1126  			if s.ClusterTrustBundle != nil {
  1127  				return true
  1128  			}
  1129  		}
  1130  	}
  1131  
  1132  	return false
  1133  }
  1134  
  1135  func rroInUse(podSpec *api.PodSpec) bool {
  1136  	if podSpec == nil {
  1137  		return false
  1138  	}
  1139  	var inUse bool
  1140  	VisitContainers(podSpec, AllContainers, func(c *api.Container, _ ContainerType) bool {
  1141  		for _, f := range c.VolumeMounts {
  1142  			if f.RecursiveReadOnly != nil {
  1143  				inUse = true
  1144  				return false
  1145  			}
  1146  		}
  1147  		return true
  1148  	})
  1149  	return inUse
  1150  }
  1151  
  1152  func dropDisabledClusterTrustBundleProjection(podSpec, oldPodSpec *api.PodSpec) {
  1153  	if utilfeature.DefaultFeatureGate.Enabled(features.ClusterTrustBundleProjection) {
  1154  		return
  1155  	}
  1156  	if podSpec == nil {
  1157  		return
  1158  	}
  1159  
  1160  	// If the pod was already using it, it can keep using it.
  1161  	if clusterTrustBundleProjectionInUse(oldPodSpec) {
  1162  		return
  1163  	}
  1164  
  1165  	for i := range podSpec.Volumes {
  1166  		if podSpec.Volumes[i].Projected == nil {
  1167  			continue
  1168  		}
  1169  
  1170  		for j := range podSpec.Volumes[i].Projected.Sources {
  1171  			podSpec.Volumes[i].Projected.Sources[j].ClusterTrustBundle = nil
  1172  		}
  1173  	}
  1174  }
  1175  
  1176  func hasInvalidLabelValueInAffinitySelector(spec *api.PodSpec) bool {
  1177  	if spec.Affinity != nil {
  1178  		if spec.Affinity.PodAffinity != nil {
  1179  			for _, term := range spec.Affinity.PodAffinity.RequiredDuringSchedulingIgnoredDuringExecution {
  1180  				allErrs := apivalidation.ValidatePodAffinityTermSelector(term, false, nil)
  1181  				if len(allErrs) != 0 {
  1182  					return true
  1183  				}
  1184  			}
  1185  			for _, term := range spec.Affinity.PodAffinity.PreferredDuringSchedulingIgnoredDuringExecution {
  1186  				allErrs := apivalidation.ValidatePodAffinityTermSelector(term.PodAffinityTerm, false, nil)
  1187  				if len(allErrs) != 0 {
  1188  					return true
  1189  				}
  1190  			}
  1191  		}
  1192  		if spec.Affinity.PodAntiAffinity != nil {
  1193  			for _, term := range spec.Affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution {
  1194  				allErrs := apivalidation.ValidatePodAffinityTermSelector(term, false, nil)
  1195  				if len(allErrs) != 0 {
  1196  					return true
  1197  				}
  1198  			}
  1199  			for _, term := range spec.Affinity.PodAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution {
  1200  				allErrs := apivalidation.ValidatePodAffinityTermSelector(term.PodAffinityTerm, false, nil)
  1201  				if len(allErrs) != 0 {
  1202  					return true
  1203  				}
  1204  			}
  1205  		}
  1206  	}
  1207  	return false
  1208  }
  1209  
  1210  func MarkPodProposedForResize(oldPod, newPod *api.Pod) {
  1211  	for i, c := range newPod.Spec.Containers {
  1212  		if c.Resources.Requests == nil {
  1213  			continue
  1214  		}
  1215  		if cmp.Equal(oldPod.Spec.Containers[i].Resources, c.Resources) {
  1216  			continue
  1217  		}
  1218  		findContainerStatus := func(css []api.ContainerStatus, cName string) (api.ContainerStatus, bool) {
  1219  			for i := range css {
  1220  				if css[i].Name == cName {
  1221  					return css[i], true
  1222  				}
  1223  			}
  1224  			return api.ContainerStatus{}, false
  1225  		}
  1226  		if cs, ok := findContainerStatus(newPod.Status.ContainerStatuses, c.Name); ok {
  1227  			if !cmp.Equal(c.Resources.Requests, cs.AllocatedResources) {
  1228  				newPod.Status.Resize = api.PodResizeStatusProposed
  1229  				break
  1230  			}
  1231  		}
  1232  	}
  1233  }