rebase: update kubernetes to 1.30

updating kubernetes to 1.30 release

Signed-off-by: Madhu Rajanna <madhupr007@gmail.com>
This commit is contained in:
Madhu Rajanna
2024-05-15 08:54:18 +02:00
committed by mergify[bot]
parent 62ddcf715b
commit e727bd351e
747 changed files with 73809 additions and 10436 deletions

View File

@ -51,6 +51,9 @@ const (
// to the pod, which don't count towards the backoff limit, according to the
// pod failure policy. When the annotation is absent zero is implied.
JobIndexIgnoredFailureCountAnnotation = labelPrefix + "job-index-ignored-failure-count"
// JobControllerName reserved value for the managedBy field for the built-in
// Job controller.
JobControllerName = "kubernetes.io/job-controller"
)
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
@ -256,6 +259,51 @@ type PodFailurePolicy struct {
Rules []PodFailurePolicyRule
}
// SuccessPolicy describes when a Job can be declared as succeeded based on the success of some indexes.
type SuccessPolicy struct {
// rules represents the list of alternative rules for the declaring the Jobs
// as successful before `.status.succeeded >= .spec.completions`. Once any of the rules are met,
// the "SucceededCriteriaMet" condition is added, and the lingering pods are removed.
// The terminal state for such a Job has the "Complete" condition.
// Additionally, these rules are evaluated in order; Once the Job meets one of the rules,
// other rules are ignored. At most 20 elements are allowed.
// +listType=atomic
Rules []SuccessPolicyRule
}
// SuccessPolicyRule describes rule for declaring a Job as succeeded.
// Each rule must have at least one of the "succeededIndexes" or "succeededCount" specified.
type SuccessPolicyRule struct {
// succeededIndexes specifies the set of indexes
// which need to be contained in the actual set of the succeeded indexes for the Job.
// The list of indexes must be within 0 to ".spec.completions-1" and
// must not contain duplicates. At least one element is required.
// The indexes are represented as intervals separated by commas.
// The intervals can be a decimal integer or a pair of decimal integers separated by a hyphen.
// The number are listed in represented by the first and last element of the series,
// separated by a hyphen.
// For example, if the completed indexes are 1, 3, 4, 5 and 7, they are
// represented as "1,3-5,7".
// When this field is null, this field doesn't default to any value
// and is never evaluated at any time.
//
// +optional
SucceededIndexes *string
// succeededCount specifies the minimal required size of the actual set of the succeeded indexes
// for the Job. When succeededCount is used along with succeededIndexes, the check is
// constrained only to the set of indexes specified by succeededIndexes.
// For example, given that succeededIndexes is "1-4", succeededCount is "3",
// and completed indexes are "1", "3", and "5", the Job isn't declared as succeeded
// because only "1" and "3" indexes are considered in that rules.
// When this field is null, this doesn't default to any value and
// is never evaluated at any time.
// When specified it needs to be a positive integer.
//
// +optional
SucceededCount *int32
}
// JobSpec describes how the job execution will look like.
type JobSpec struct {
@ -287,6 +335,17 @@ type JobSpec struct {
// +optional
PodFailurePolicy *PodFailurePolicy
// successPolicy specifies the policy when the Job can be declared as succeeded.
// If empty, the default behavior applies - the Job is declared as succeeded
// only when the number of succeeded pods equals to the completions.
// When the field is specified, it must be immutable and works only for the Indexed Jobs.
// Once the Job meets the SuccessPolicy, the lingering pods are terminated.
//
// This field is alpha-level. To use this field, you must enable the
// `JobSuccessPolicy` feature gate (disabled by default).
// +optional
SuccessPolicy *SuccessPolicy
// Specifies the duration in seconds relative to the startTime that the job
// may be continuously active before the system tries to terminate it; value
// must be positive integer. If a Job is suspended (at creation or through an
@ -409,6 +468,20 @@ type JobSpec struct {
// This is on by default.
// +optional
PodReplacementPolicy *PodReplacementPolicy
// ManagedBy field indicates the controller that manages a Job. The k8s Job
// controller reconciles jobs which don't have this field at all or the field
// value is the reserved string `kubernetes.io/job-controller`, but skips
// reconciling Jobs with a custom value for this field.
// The value must be a valid domain-prefixed path (e.g. acme.io/foo) -
// all characters before the first "/" must be a valid subdomain as defined
// by RFC 1123. All characters trailing the first "/" must be valid HTTP Path
// characters as defined by RFC 3986. The value cannot exceed 64 characters.
//
// This field is alpha-level. The job controller accepts setting the field
// when the feature gate JobManagedBy is enabled (disabled by default).
// +optional
ManagedBy *string
}
// JobStatus represents the current state of a Job.
@ -420,6 +493,12 @@ type JobStatus struct {
// status true; when the Job is resumed, the status of this condition will
// become false. When a Job is completed, one of the conditions will have
// type "Complete" and status true.
//
// A job is considered finished when it is in a terminal condition, either
// "Complete" or "Failed". A Job cannot have both the "Complete" and "Failed" conditions.
// Additionally, it cannot be in the "Complete" and "FailureTarget" conditions.
// The "Complete", "Failed" and "FailureTarget" conditions cannot be disabled.
//
// +optional
Conditions []JobCondition
@ -427,17 +506,25 @@ type JobStatus struct {
// Job is created in the suspended state, this field is not set until the
// first time it is resumed. This field is reset every time a Job is resumed
// from suspension. It is represented in RFC3339 form and is in UTC.
//
// Once set, the field can only be removed when the job is suspended.
// The field cannot be modified while the job is unsuspended or finished.
//
// +optional
StartTime *metav1.Time
// Represents time when the job was completed. It is not guaranteed to
// be set in happens-before order across separate operations.
// It is represented in RFC3339 form and is in UTC.
// The completion time is only set when the job finishes successfully.
// The completion time is set when the job finishes successfully, and only then.
// The value cannot be updated or removed. The value indicates the same or
// later point in time as the startTime field.
// +optional
CompletionTime *metav1.Time
// The number of pending and running pods.
// The number of pending and running pods which are not terminating (without
// a deletionTimestamp).
// The value is zero for finished jobs.
// +optional
Active int32
@ -454,10 +541,13 @@ type JobStatus struct {
Ready *int32
// The number of pods which reached phase Succeeded.
// The value increases monotonically for a given spec. However, it may
// decrease in reaction to scale down of elastic indexed jobs.
// +optional
Succeeded int32
// The number of pods which reached phase Failed.
// The value increases monotonically.
// +optional
Failed int32
@ -471,7 +561,7 @@ type JobStatus struct {
// +optional
CompletedIndexes string
// FailedIndexes holds the failed indexes when backoffLimitPerIndex=true.
// FailedIndexes holds the failed indexes when spec.backoffLimitPerIndex is set.
// The indexes are represented in the text format analogous as for the
// `completedIndexes` field, ie. they are kept as decimal integers
// separated by commas. The numbers are listed in increasing order. Three or
@ -479,6 +569,8 @@ type JobStatus struct {
// last element of the series, separated by a hyphen.
// For example, if the failed indexes are 1, 3, 4, 5 and 7, they are
// represented as "1,3-5,7".
// The set of failed indexes cannot overlap with the set of completed indexes.
//
// This field is beta-level. It can be used when the `JobBackoffLimitPerIndex`
// feature gate is enabled (enabled by default).
// +optional
@ -498,6 +590,7 @@ type JobStatus struct {
//
// Old jobs might not be tracked using this field, in which case the field
// remains null.
// The structure is empty for finished jobs.
// +optional
UncountedTerminatedPods *UncountedTerminatedPods
}
@ -529,6 +622,8 @@ const (
JobFailed JobConditionType = "Failed"
// FailureTarget means the job is about to fail its execution.
JobFailureTarget JobConditionType = "FailureTarget"
// JobSuccessCriteriaMet means the Job has reached a success state and will be marked as Completed
JobSuccessCriteriaMet JobConditionType = "SuccessCriteriaMet"
)
// JobCondition describes current state of a job.

View File

@ -257,6 +257,11 @@ func (in *JobSpec) DeepCopyInto(out *JobSpec) {
*out = new(PodFailurePolicy)
(*in).DeepCopyInto(*out)
}
if in.SuccessPolicy != nil {
in, out := &in.SuccessPolicy, &out.SuccessPolicy
*out = new(SuccessPolicy)
(*in).DeepCopyInto(*out)
}
if in.ActiveDeadlineSeconds != nil {
in, out := &in.ActiveDeadlineSeconds, &out.ActiveDeadlineSeconds
*out = new(int64)
@ -308,6 +313,11 @@ func (in *JobSpec) DeepCopyInto(out *JobSpec) {
*out = new(PodReplacementPolicy)
**out = **in
}
if in.ManagedBy != nil {
in, out := &in.ManagedBy, &out.ManagedBy
*out = new(string)
**out = **in
}
return
}
@ -481,6 +491,55 @@ func (in *PodFailurePolicyRule) DeepCopy() *PodFailurePolicyRule {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SuccessPolicy) DeepCopyInto(out *SuccessPolicy) {
*out = *in
if in.Rules != nil {
in, out := &in.Rules, &out.Rules
*out = make([]SuccessPolicyRule, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SuccessPolicy.
func (in *SuccessPolicy) DeepCopy() *SuccessPolicy {
if in == nil {
return nil
}
out := new(SuccessPolicy)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SuccessPolicyRule) DeepCopyInto(out *SuccessPolicyRule) {
*out = *in
if in.SucceededIndexes != nil {
in, out := &in.SucceededIndexes, &out.SucceededIndexes
*out = new(string)
**out = **in
}
if in.SucceededCount != nil {
in, out := &in.SucceededCount, &out.SucceededCount
*out = new(int32)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SuccessPolicyRule.
func (in *SuccessPolicyRule) DeepCopy() *SuccessPolicyRule {
if in == nil {
return nil
}
out := new(SuccessPolicyRule)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *UncountedTerminatedPods) DeepCopyInto(out *UncountedTerminatedPods) {
*out = *in

View File

@ -52,6 +52,19 @@ const (
// Deprecated: set a pod or container security context `seccompProfile` of type "RuntimeDefault" instead.
DeprecatedSeccompProfileDockerDefault string = "docker/default"
// DeprecatedAppArmorAnnotationKeyPrefix is the prefix to an annotation key specifying a container's apparmor profile.
// Deprecated: use a pod or container security context `appArmorProfile` field instead.
DeprecatedAppArmorAnnotationKeyPrefix = "container.apparmor.security.beta.kubernetes.io/"
// DeprecatedAppArmorAnnotationValueRuntimeDefault is the profile specifying the runtime default.
DeprecatedAppArmorAnnotationValueRuntimeDefault = "runtime/default"
// DeprecatedAppArmorAnnotationValueLocalhostPrefix is the prefix for specifying profiles loaded on the node.
DeprecatedAppArmorAnnotationValueLocalhostPrefix = "localhost/"
// DeprecatedAppArmorAnnotationValueUnconfined is the Unconfined AppArmor profile
DeprecatedAppArmorAnnotationValueUnconfined = "unconfined"
// PreferAvoidPodsAnnotationKey represents the key of preferAvoidPods data (json serialized)
// in the Annotations of a Node.
PreferAvoidPodsAnnotationKey string = "scheduler.alpha.kubernetes.io/preferAvoidPods"

View File

@ -508,7 +508,7 @@ type PersistentVolumeClaimSpec struct {
// If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be
// set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource
// exists.
// More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#volumeattributesclass
// More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/
// (Alpha) Using this field requires the VolumeAttributesClass feature gate to be enabled.
// +featureGate=VolumeAttributesClass
// +optional
@ -2011,6 +2011,26 @@ type VolumeMount struct {
// Optional: Defaults to false (read-write).
// +optional
ReadOnly bool
// RecursiveReadOnly specifies whether read-only mounts should be handled
// recursively.
//
// If ReadOnly is false, this field has no meaning and must be unspecified.
//
// If ReadOnly is true, and this field is set to Disabled, the mount is not made
// recursively read-only. If this field is set to IfPossible, the mount is made
// recursively read-only, if it is supported by the container runtime. If this
// field is set to Enabled, the mount is made recursively read-only if it is
// supported by the container runtime, otherwise the pod will not be started and
// an error will be generated to indicate the reason.
//
// If this field is set to IfPossible or Enabled, MountPropagation must be set to
// None (or be unspecified, which defaults to None).
//
// If this field is not specified, it is treated as an equivalent of Disabled.
//
// +featureGate=RecursiveReadOnlyMounts
// +optional
RecursiveReadOnly *RecursiveReadOnlyMode
// Required. If the path is not an absolute path (e.g. some/path) it
// will be prepended with the appropriate root prefix for the operating
// system. On Linux this is '/', on Windows this is 'C:\'.
@ -2023,6 +2043,8 @@ type VolumeMount struct {
// to container and the other way around.
// When not set, MountPropagationNone is used.
// This field is beta in 1.10.
// When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified
// (which defaults to None).
// +optional
MountPropagation *MountPropagationMode
// Expanded path within the volume from which the container's volume should be mounted.
@ -2058,6 +2080,18 @@ const (
MountPropagationBidirectional MountPropagationMode = "Bidirectional"
)
// RecursiveReadOnlyMode describes recursive-readonly mode.
type RecursiveReadOnlyMode string
const (
// RecursiveReadOnlyDisabled disables recursive-readonly mode.
RecursiveReadOnlyDisabled RecursiveReadOnlyMode = "Disabled"
// RecursiveReadOnlyIfPossible enables recursive-readonly mode if possible.
RecursiveReadOnlyIfPossible RecursiveReadOnlyMode = "IfPossible"
// RecursiveReadOnlyEnabled enables recursive-readonly mode, or raise an error.
RecursiveReadOnlyEnabled RecursiveReadOnlyMode = "Enabled"
)
// VolumeDevice describes a mapping of a raw block device within a container.
type VolumeDevice struct {
// name must match the name of a persistentVolumeClaim in the pod
@ -2068,7 +2102,11 @@ type VolumeDevice struct {
// EnvVar represents an environment variable present in a Container.
type EnvVar struct {
// Required: This must be a C_IDENTIFIER.
// Required: Name of the environment variable.
// When the RelaxedEnvironmentVariableValidation feature gate is disabled, this must consist of alphabetic characters,
// digits, '_', '-', or '.', and must not start with a digit.
// When the RelaxedEnvironmentVariableValidation feature gate is enabled,
// this may contain any printable ASCII characters except '='.
Name string
// Optional: no more than one of the following may be specified.
// Optional: Defaults to ""; variable references $(VAR_NAME) are expanded
@ -2698,6 +2736,11 @@ type ContainerStatus struct {
// +featureGate=InPlacePodVerticalScaling
// +optional
Resources *ResourceRequirements
// Status of volume mounts.
// +listType=atomic
// +optional
// +featureGate=RecursiveReadOnlyMounts
VolumeMounts []VolumeMountStatus
}
// PodPhase is a label for the condition of a pod at the current time.
@ -2771,6 +2814,23 @@ const (
PodResizeStatusInfeasible PodResizeStatus = "Infeasible"
)
// VolumeMountStatus shows status of volume mounts.
type VolumeMountStatus struct {
// Name corresponds to the name of the original VolumeMount.
Name string
// MountPath corresponds to the original VolumeMount.
MountPath string
// ReadOnly corresponds to the original VolumeMount.
// +optional
ReadOnly bool
// RecursiveReadOnly must be set to Disabled, Enabled, or unspecified (for non-readonly mounts).
// An IfPossible value in the original VolumeMount must be translated to Disabled or Enabled,
// depending on the mount result.
// +featureGate=RecursiveReadOnlyMounts
// +optional
RecursiveReadOnly *RecursiveReadOnlyMode
}
// RestartPolicy describes how the container should be restarted.
// Only one of the following restart policies may be specified.
// If none of the following policies is specified, the default one
@ -3255,7 +3315,7 @@ type PodSpec struct {
// +optional
Tolerations []Toleration
// HostAliases is an optional list of hosts and IPs that will be injected into the pod's hosts
// file if specified. This is only valid for non-hostNetwork pods.
// file if specified.
// +optional
HostAliases []HostAlias
// If specified, indicates the pod's priority. "system-node-critical" and
@ -3325,6 +3385,7 @@ type PodSpec struct {
// - spec.hostPID
// - spec.hostIPC
// - spec.hostUsers
// - spec.securityContext.appArmorProfile
// - spec.securityContext.seLinuxOptions
// - spec.securityContext.seccompProfile
// - spec.securityContext.fsGroup
@ -3334,6 +3395,7 @@ type PodSpec struct {
// - spec.securityContext.runAsUser
// - spec.securityContext.runAsGroup
// - spec.securityContext.supplementalGroups
// - spec.containers[*].securityContext.appArmorProfile
// - spec.containers[*].securityContext.seLinuxOptions
// - spec.containers[*].securityContext.seccompProfile
// - spec.containers[*].securityContext.capabilities
@ -3352,9 +3414,6 @@ type PodSpec struct {
//
// SchedulingGates can only be set at pod creation time, and be removed only afterwards.
//
// This is a beta feature enabled by the PodSchedulingReadiness feature gate.
//
// +featureGate=PodSchedulingReadiness
// +optional
SchedulingGates []PodSchedulingGate
// ResourceClaims defines which ResourceClaims must be allocated
@ -3601,6 +3660,10 @@ type PodSecurityContext struct {
// Note that this field cannot be set when spec.os.name is windows.
// +optional
SeccompProfile *SeccompProfile
// appArmorProfile is the AppArmor options to use by the containers in this pod.
// Note that this field cannot be set when spec.os.name is windows.
// +optional
AppArmorProfile *AppArmorProfile
}
// SeccompProfile defines a pod/container's seccomp profile settings.
@ -3628,6 +3691,38 @@ const (
SeccompProfileTypeLocalhost SeccompProfileType = "Localhost"
)
// AppArmorProfile defines a pod or container's AppArmor settings.
// +union
type AppArmorProfile struct {
// type indicates which kind of AppArmor profile will be applied.
// Valid options are:
// Localhost - a profile pre-loaded on the node.
// RuntimeDefault - the container runtime's default profile.
// Unconfined - no AppArmor enforcement.
// +unionDescriminator
Type AppArmorProfileType
// localhostProfile indicates a profile loaded on the node that should be used.
// The profile must be preconfigured on the node to work.
// Must match the loaded name of the profile.
// Must be set if and only if type is "Localhost".
// +optional
LocalhostProfile *string
}
// +enum
type AppArmorProfileType string
const (
// AppArmorProfileTypeUnconfined indicates that no AppArmor profile should be enforced.
AppArmorProfileTypeUnconfined AppArmorProfileType = "Unconfined"
// AppArmorProfileTypeRuntimeDefault indicates that the container runtime's default AppArmor
// profile should be used.
AppArmorProfileTypeRuntimeDefault AppArmorProfileType = "RuntimeDefault"
// AppArmorProfileTypeLocalhost indicates that a profile pre-loaded on the node should be used.
AppArmorProfileTypeLocalhost AppArmorProfileType = "Localhost"
)
// PodQOSClass defines the supported qos classes of Pods.
type PodQOSClass string
@ -4166,6 +4261,18 @@ const (
ServiceExternalTrafficPolicyLocal ServiceExternalTrafficPolicy = "Local"
)
// These are valid values for the TrafficDistribution field of a Service.
const (
// Indicates a preference for routing traffic to endpoints that are
// topologically proximate to the client. The interpretation of "topologically
// proximate" may vary across implementations and could encompass endpoints
// within the same node, rack, zone, or even region. Setting this value gives
// implementations permission to make different tradeoffs, e.g. optimizing for
// proximity rather than equal distribution of load. Users should not set this
// value if such tradeoffs are not acceptable.
ServiceTrafficDistributionPreferClose = "PreferClose"
)
// These are the valid conditions of a service.
const (
// LoadBalancerPortsError represents the condition of the requested ports
@ -4429,6 +4536,15 @@ type ServiceSpec struct {
// (possibly modified by topology and other features).
// +optional
InternalTrafficPolicy *ServiceInternalTrafficPolicy
// TrafficDistribution offers a way to express preferences for how traffic is
// distributed to Service endpoints. Implementations can use this field as a
// hint, but are not required to guarantee strict adherence. If the field is
// not set, the implementation will apply its default routing strategy. If set
// to "PreferClose", implementations should prioritize endpoints that are
// topologically close (e.g., same zone).
// +optional
TrafficDistribution *string
}
// ServicePort represents the port on which the service is exposed
@ -4717,6 +4833,26 @@ type NodeDaemonEndpoints struct {
KubeletEndpoint DaemonEndpoint
}
// NodeRuntimeHandlerFeatures is a set of runtime features.
type NodeRuntimeHandlerFeatures struct {
// RecursiveReadOnlyMounts is set to true if the runtime handler supports RecursiveReadOnlyMounts.
// +featureGate=RecursiveReadOnlyMounts
// +optional
RecursiveReadOnlyMounts *bool
// Reserved: UserNamespaces *bool
}
// NodeRuntimeHandler is a set of runtime handler information.
type NodeRuntimeHandler struct {
// Runtime handler name.
// Empty for the default runtime handler.
// +optional
Name string
// Supported features.
// +optional
Features *NodeRuntimeHandlerFeatures
}
// NodeSystemInfo is a set of ids/uuids to uniquely identify the node.
type NodeSystemInfo struct {
// MachineID reported by the node. For unique machine identification
@ -4827,6 +4963,10 @@ type NodeStatus struct {
// Status of the config assigned to the node via the dynamic Kubelet config feature.
// +optional
Config *NodeConfigStatus
// The available runtime handlers.
// +featureGate=RecursiveReadOnlyMounts
// +optional
RuntimeHandlers []NodeRuntimeHandler
}
// UniqueVolumeName defines the name of attached volume
@ -4900,9 +5040,8 @@ const (
// NodeConditionType defines node's condition
type NodeConditionType string
// These are valid conditions of node. Currently, we don't have enough information to decide
// node condition. In the future, we will add more. The proposed set of conditions are:
// NodeReady, NodeReachable
// These are valid but not exhaustive conditions of node. A cloud provider may set a condition not listed here.
// Relevant events contain "NodeReady", "NodeNotReady", "NodeSchedulable", and "NodeNotSchedulable".
const (
// NodeReady means kubelet is healthy and ready to accept pods.
NodeReady NodeConditionType = "Ready"
@ -4979,14 +5118,6 @@ type NodeAddress struct {
Address string
}
// NodeResources is an object for conveying resource information about a node.
// see https://kubernetes.io/docs/concepts/architecture/nodes/#capacity for more details.
type NodeResources struct {
// Capacity represents the available resources of a node
// +optional
Capacity ResourceList
}
// ResourceName is the name identifying various resources in a ResourceList.
type ResourceName string
@ -5003,7 +5134,6 @@ const (
// Volume size, in bytes (e,g. 5Gi = 5GiB = 5 * 1024 * 1024 * 1024)
ResourceStorage ResourceName = "storage"
// Local ephemeral storage, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)
// The resource name for ResourceEphemeralStorage is alpha and it can change across releases.
ResourceEphemeralStorage ResourceName = "ephemeral-storage"
)
@ -6020,6 +6150,11 @@ type SecurityContext struct {
// Note that this field cannot be set when spec.os.name is windows.
// +optional
SeccompProfile *SeccompProfile
// appArmorProfile is the AppArmor options to use by this container. If set, this profile
// overrides the pod's appArmorProfile.
// Note that this field cannot be set when spec.os.name is windows.
// +optional
AppArmorProfile *AppArmorProfile
}
// ProcMountType defines the type of proc mount
@ -6221,8 +6356,6 @@ type TopologySpreadConstraint struct {
// In this situation, new pod with the same labelSelector cannot be scheduled,
// because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones,
// it will violate MaxSkew.
//
// This is a beta field and requires the MinDomainsInPodTopologySpread feature gate to be enabled (enabled by default).
// +optional
MinDomains *int32
// NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector

View File

@ -62,6 +62,16 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1.AppArmorProfile)(nil), (*core.AppArmorProfile)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1_AppArmorProfile_To_core_AppArmorProfile(a.(*v1.AppArmorProfile), b.(*core.AppArmorProfile), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*core.AppArmorProfile)(nil), (*v1.AppArmorProfile)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_core_AppArmorProfile_To_v1_AppArmorProfile(a.(*core.AppArmorProfile), b.(*v1.AppArmorProfile), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1.AttachedVolume)(nil), (*core.AttachedVolume)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1_AttachedVolume_To_core_AttachedVolume(a.(*v1.AttachedVolume), b.(*core.AttachedVolume), scope)
}); err != nil {
@ -1052,13 +1062,23 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1.NodeResources)(nil), (*core.NodeResources)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1_NodeResources_To_core_NodeResources(a.(*v1.NodeResources), b.(*core.NodeResources), scope)
if err := s.AddGeneratedConversionFunc((*v1.NodeRuntimeHandler)(nil), (*core.NodeRuntimeHandler)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1_NodeRuntimeHandler_To_core_NodeRuntimeHandler(a.(*v1.NodeRuntimeHandler), b.(*core.NodeRuntimeHandler), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*core.NodeResources)(nil), (*v1.NodeResources)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_core_NodeResources_To_v1_NodeResources(a.(*core.NodeResources), b.(*v1.NodeResources), scope)
if err := s.AddGeneratedConversionFunc((*core.NodeRuntimeHandler)(nil), (*v1.NodeRuntimeHandler)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_core_NodeRuntimeHandler_To_v1_NodeRuntimeHandler(a.(*core.NodeRuntimeHandler), b.(*v1.NodeRuntimeHandler), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1.NodeRuntimeHandlerFeatures)(nil), (*core.NodeRuntimeHandlerFeatures)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1_NodeRuntimeHandlerFeatures_To_core_NodeRuntimeHandlerFeatures(a.(*v1.NodeRuntimeHandlerFeatures), b.(*core.NodeRuntimeHandlerFeatures), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*core.NodeRuntimeHandlerFeatures)(nil), (*v1.NodeRuntimeHandlerFeatures)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_core_NodeRuntimeHandlerFeatures_To_v1_NodeRuntimeHandlerFeatures(a.(*core.NodeRuntimeHandlerFeatures), b.(*v1.NodeRuntimeHandlerFeatures), scope)
}); err != nil {
return err
}
@ -2097,6 +2117,16 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1.VolumeMountStatus)(nil), (*core.VolumeMountStatus)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1_VolumeMountStatus_To_core_VolumeMountStatus(a.(*v1.VolumeMountStatus), b.(*core.VolumeMountStatus), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*core.VolumeMountStatus)(nil), (*v1.VolumeMountStatus)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_core_VolumeMountStatus_To_v1_VolumeMountStatus(a.(*core.VolumeMountStatus), b.(*v1.VolumeMountStatus), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1.VolumeNodeAffinity)(nil), (*core.VolumeNodeAffinity)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1_VolumeNodeAffinity_To_core_VolumeNodeAffinity(a.(*v1.VolumeNodeAffinity), b.(*core.VolumeNodeAffinity), scope)
}); err != nil {
@ -2385,6 +2415,28 @@ func Convert_core_Affinity_To_v1_Affinity(in *core.Affinity, out *v1.Affinity, s
return autoConvert_core_Affinity_To_v1_Affinity(in, out, s)
}
func autoConvert_v1_AppArmorProfile_To_core_AppArmorProfile(in *v1.AppArmorProfile, out *core.AppArmorProfile, s conversion.Scope) error {
out.Type = core.AppArmorProfileType(in.Type)
out.LocalhostProfile = (*string)(unsafe.Pointer(in.LocalhostProfile))
return nil
}
// Convert_v1_AppArmorProfile_To_core_AppArmorProfile is an autogenerated conversion function.
func Convert_v1_AppArmorProfile_To_core_AppArmorProfile(in *v1.AppArmorProfile, out *core.AppArmorProfile, s conversion.Scope) error {
return autoConvert_v1_AppArmorProfile_To_core_AppArmorProfile(in, out, s)
}
func autoConvert_core_AppArmorProfile_To_v1_AppArmorProfile(in *core.AppArmorProfile, out *v1.AppArmorProfile, s conversion.Scope) error {
out.Type = v1.AppArmorProfileType(in.Type)
out.LocalhostProfile = (*string)(unsafe.Pointer(in.LocalhostProfile))
return nil
}
// Convert_core_AppArmorProfile_To_v1_AppArmorProfile is an autogenerated conversion function.
func Convert_core_AppArmorProfile_To_v1_AppArmorProfile(in *core.AppArmorProfile, out *v1.AppArmorProfile, s conversion.Scope) error {
return autoConvert_core_AppArmorProfile_To_v1_AppArmorProfile(in, out, s)
}
func autoConvert_v1_AttachedVolume_To_core_AttachedVolume(in *v1.AttachedVolume, out *core.AttachedVolume, s conversion.Scope) error {
out.Name = core.UniqueVolumeName(in.Name)
out.DevicePath = in.DevicePath
@ -3317,6 +3369,7 @@ func autoConvert_v1_ContainerStatus_To_core_ContainerStatus(in *v1.ContainerStat
out.Started = (*bool)(unsafe.Pointer(in.Started))
out.AllocatedResources = *(*core.ResourceList)(unsafe.Pointer(&in.AllocatedResources))
out.Resources = (*core.ResourceRequirements)(unsafe.Pointer(in.Resources))
out.VolumeMounts = *(*[]core.VolumeMountStatus)(unsafe.Pointer(&in.VolumeMounts))
return nil
}
@ -3341,6 +3394,7 @@ func autoConvert_core_ContainerStatus_To_v1_ContainerStatus(in *core.ContainerSt
out.Started = (*bool)(unsafe.Pointer(in.Started))
out.AllocatedResources = *(*v1.ResourceList)(unsafe.Pointer(&in.AllocatedResources))
out.Resources = (*v1.ResourceRequirements)(unsafe.Pointer(in.Resources))
out.VolumeMounts = *(*[]v1.VolumeMountStatus)(unsafe.Pointer(&in.VolumeMounts))
return nil
}
@ -5049,24 +5103,46 @@ func Convert_url_Values_To_v1_NodeProxyOptions(in *url.Values, out *v1.NodeProxy
return autoConvert_url_Values_To_v1_NodeProxyOptions(in, out, s)
}
func autoConvert_v1_NodeResources_To_core_NodeResources(in *v1.NodeResources, out *core.NodeResources, s conversion.Scope) error {
out.Capacity = *(*core.ResourceList)(unsafe.Pointer(&in.Capacity))
func autoConvert_v1_NodeRuntimeHandler_To_core_NodeRuntimeHandler(in *v1.NodeRuntimeHandler, out *core.NodeRuntimeHandler, s conversion.Scope) error {
out.Name = in.Name
out.Features = (*core.NodeRuntimeHandlerFeatures)(unsafe.Pointer(in.Features))
return nil
}
// Convert_v1_NodeResources_To_core_NodeResources is an autogenerated conversion function.
func Convert_v1_NodeResources_To_core_NodeResources(in *v1.NodeResources, out *core.NodeResources, s conversion.Scope) error {
return autoConvert_v1_NodeResources_To_core_NodeResources(in, out, s)
// Convert_v1_NodeRuntimeHandler_To_core_NodeRuntimeHandler is an autogenerated conversion function.
func Convert_v1_NodeRuntimeHandler_To_core_NodeRuntimeHandler(in *v1.NodeRuntimeHandler, out *core.NodeRuntimeHandler, s conversion.Scope) error {
return autoConvert_v1_NodeRuntimeHandler_To_core_NodeRuntimeHandler(in, out, s)
}
func autoConvert_core_NodeResources_To_v1_NodeResources(in *core.NodeResources, out *v1.NodeResources, s conversion.Scope) error {
out.Capacity = *(*v1.ResourceList)(unsafe.Pointer(&in.Capacity))
func autoConvert_core_NodeRuntimeHandler_To_v1_NodeRuntimeHandler(in *core.NodeRuntimeHandler, out *v1.NodeRuntimeHandler, s conversion.Scope) error {
out.Name = in.Name
out.Features = (*v1.NodeRuntimeHandlerFeatures)(unsafe.Pointer(in.Features))
return nil
}
// Convert_core_NodeResources_To_v1_NodeResources is an autogenerated conversion function.
func Convert_core_NodeResources_To_v1_NodeResources(in *core.NodeResources, out *v1.NodeResources, s conversion.Scope) error {
return autoConvert_core_NodeResources_To_v1_NodeResources(in, out, s)
// Convert_core_NodeRuntimeHandler_To_v1_NodeRuntimeHandler is an autogenerated conversion function.
func Convert_core_NodeRuntimeHandler_To_v1_NodeRuntimeHandler(in *core.NodeRuntimeHandler, out *v1.NodeRuntimeHandler, s conversion.Scope) error {
return autoConvert_core_NodeRuntimeHandler_To_v1_NodeRuntimeHandler(in, out, s)
}
func autoConvert_v1_NodeRuntimeHandlerFeatures_To_core_NodeRuntimeHandlerFeatures(in *v1.NodeRuntimeHandlerFeatures, out *core.NodeRuntimeHandlerFeatures, s conversion.Scope) error {
out.RecursiveReadOnlyMounts = (*bool)(unsafe.Pointer(in.RecursiveReadOnlyMounts))
return nil
}
// Convert_v1_NodeRuntimeHandlerFeatures_To_core_NodeRuntimeHandlerFeatures is an autogenerated conversion function.
func Convert_v1_NodeRuntimeHandlerFeatures_To_core_NodeRuntimeHandlerFeatures(in *v1.NodeRuntimeHandlerFeatures, out *core.NodeRuntimeHandlerFeatures, s conversion.Scope) error {
return autoConvert_v1_NodeRuntimeHandlerFeatures_To_core_NodeRuntimeHandlerFeatures(in, out, s)
}
func autoConvert_core_NodeRuntimeHandlerFeatures_To_v1_NodeRuntimeHandlerFeatures(in *core.NodeRuntimeHandlerFeatures, out *v1.NodeRuntimeHandlerFeatures, s conversion.Scope) error {
out.RecursiveReadOnlyMounts = (*bool)(unsafe.Pointer(in.RecursiveReadOnlyMounts))
return nil
}
// Convert_core_NodeRuntimeHandlerFeatures_To_v1_NodeRuntimeHandlerFeatures is an autogenerated conversion function.
func Convert_core_NodeRuntimeHandlerFeatures_To_v1_NodeRuntimeHandlerFeatures(in *core.NodeRuntimeHandlerFeatures, out *v1.NodeRuntimeHandlerFeatures, s conversion.Scope) error {
return autoConvert_core_NodeRuntimeHandlerFeatures_To_v1_NodeRuntimeHandlerFeatures(in, out, s)
}
func autoConvert_v1_NodeSelector_To_core_NodeSelector(in *v1.NodeSelector, out *core.NodeSelector, s conversion.Scope) error {
@ -5172,6 +5248,7 @@ func autoConvert_v1_NodeStatus_To_core_NodeStatus(in *v1.NodeStatus, out *core.N
out.VolumesInUse = *(*[]core.UniqueVolumeName)(unsafe.Pointer(&in.VolumesInUse))
out.VolumesAttached = *(*[]core.AttachedVolume)(unsafe.Pointer(&in.VolumesAttached))
out.Config = (*core.NodeConfigStatus)(unsafe.Pointer(in.Config))
out.RuntimeHandlers = *(*[]core.NodeRuntimeHandler)(unsafe.Pointer(&in.RuntimeHandlers))
return nil
}
@ -5196,6 +5273,7 @@ func autoConvert_core_NodeStatus_To_v1_NodeStatus(in *core.NodeStatus, out *v1.N
out.VolumesInUse = *(*[]v1.UniqueVolumeName)(unsafe.Pointer(&in.VolumesInUse))
out.VolumesAttached = *(*[]v1.AttachedVolume)(unsafe.Pointer(&in.VolumesAttached))
out.Config = (*v1.NodeConfigStatus)(unsafe.Pointer(in.Config))
out.RuntimeHandlers = *(*[]v1.NodeRuntimeHandler)(unsafe.Pointer(&in.RuntimeHandlers))
return nil
}
@ -6412,6 +6490,7 @@ func autoConvert_v1_PodSecurityContext_To_core_PodSecurityContext(in *v1.PodSecu
out.Sysctls = *(*[]core.Sysctl)(unsafe.Pointer(&in.Sysctls))
out.FSGroupChangePolicy = (*core.PodFSGroupChangePolicy)(unsafe.Pointer(in.FSGroupChangePolicy))
out.SeccompProfile = (*core.SeccompProfile)(unsafe.Pointer(in.SeccompProfile))
out.AppArmorProfile = (*core.AppArmorProfile)(unsafe.Pointer(in.AppArmorProfile))
return nil
}
@ -6436,6 +6515,7 @@ func autoConvert_core_PodSecurityContext_To_v1_PodSecurityContext(in *core.PodSe
out.FSGroupChangePolicy = (*v1.PodFSGroupChangePolicy)(unsafe.Pointer(in.FSGroupChangePolicy))
out.Sysctls = *(*[]v1.Sysctl)(unsafe.Pointer(&in.Sysctls))
out.SeccompProfile = (*v1.SeccompProfile)(unsafe.Pointer(in.SeccompProfile))
out.AppArmorProfile = (*v1.AppArmorProfile)(unsafe.Pointer(in.AppArmorProfile))
return nil
}
@ -7789,6 +7869,7 @@ func autoConvert_v1_SecurityContext_To_core_SecurityContext(in *v1.SecurityConte
out.AllowPrivilegeEscalation = (*bool)(unsafe.Pointer(in.AllowPrivilegeEscalation))
out.ProcMount = (*core.ProcMountType)(unsafe.Pointer(in.ProcMount))
out.SeccompProfile = (*core.SeccompProfile)(unsafe.Pointer(in.SeccompProfile))
out.AppArmorProfile = (*core.AppArmorProfile)(unsafe.Pointer(in.AppArmorProfile))
return nil
}
@ -7809,6 +7890,7 @@ func autoConvert_core_SecurityContext_To_v1_SecurityContext(in *core.SecurityCon
out.AllowPrivilegeEscalation = (*bool)(unsafe.Pointer(in.AllowPrivilegeEscalation))
out.ProcMount = (*v1.ProcMountType)(unsafe.Pointer(in.ProcMount))
out.SeccompProfile = (*v1.SeccompProfile)(unsafe.Pointer(in.SeccompProfile))
out.AppArmorProfile = (*v1.AppArmorProfile)(unsafe.Pointer(in.AppArmorProfile))
return nil
}
@ -8079,6 +8161,7 @@ func autoConvert_v1_ServiceSpec_To_core_ServiceSpec(in *v1.ServiceSpec, out *cor
out.AllocateLoadBalancerNodePorts = (*bool)(unsafe.Pointer(in.AllocateLoadBalancerNodePorts))
out.LoadBalancerClass = (*string)(unsafe.Pointer(in.LoadBalancerClass))
out.InternalTrafficPolicy = (*core.ServiceInternalTrafficPolicy)(unsafe.Pointer(in.InternalTrafficPolicy))
out.TrafficDistribution = (*string)(unsafe.Pointer(in.TrafficDistribution))
return nil
}
@ -8107,6 +8190,7 @@ func autoConvert_core_ServiceSpec_To_v1_ServiceSpec(in *core.ServiceSpec, out *v
out.AllocateLoadBalancerNodePorts = (*bool)(unsafe.Pointer(in.AllocateLoadBalancerNodePorts))
out.LoadBalancerClass = (*string)(unsafe.Pointer(in.LoadBalancerClass))
out.InternalTrafficPolicy = (*v1.ServiceInternalTrafficPolicy)(unsafe.Pointer(in.InternalTrafficPolicy))
out.TrafficDistribution = (*string)(unsafe.Pointer(in.TrafficDistribution))
return nil
}
@ -8502,6 +8586,7 @@ func Convert_core_VolumeDevice_To_v1_VolumeDevice(in *core.VolumeDevice, out *v1
func autoConvert_v1_VolumeMount_To_core_VolumeMount(in *v1.VolumeMount, out *core.VolumeMount, s conversion.Scope) error {
out.Name = in.Name
out.ReadOnly = in.ReadOnly
out.RecursiveReadOnly = (*core.RecursiveReadOnlyMode)(unsafe.Pointer(in.RecursiveReadOnly))
out.MountPath = in.MountPath
out.SubPath = in.SubPath
out.MountPropagation = (*core.MountPropagationMode)(unsafe.Pointer(in.MountPropagation))
@ -8517,6 +8602,7 @@ func Convert_v1_VolumeMount_To_core_VolumeMount(in *v1.VolumeMount, out *core.Vo
func autoConvert_core_VolumeMount_To_v1_VolumeMount(in *core.VolumeMount, out *v1.VolumeMount, s conversion.Scope) error {
out.Name = in.Name
out.ReadOnly = in.ReadOnly
out.RecursiveReadOnly = (*v1.RecursiveReadOnlyMode)(unsafe.Pointer(in.RecursiveReadOnly))
out.MountPath = in.MountPath
out.SubPath = in.SubPath
out.MountPropagation = (*v1.MountPropagationMode)(unsafe.Pointer(in.MountPropagation))
@ -8529,6 +8615,32 @@ func Convert_core_VolumeMount_To_v1_VolumeMount(in *core.VolumeMount, out *v1.Vo
return autoConvert_core_VolumeMount_To_v1_VolumeMount(in, out, s)
}
func autoConvert_v1_VolumeMountStatus_To_core_VolumeMountStatus(in *v1.VolumeMountStatus, out *core.VolumeMountStatus, s conversion.Scope) error {
out.Name = in.Name
out.MountPath = in.MountPath
out.ReadOnly = in.ReadOnly
out.RecursiveReadOnly = (*core.RecursiveReadOnlyMode)(unsafe.Pointer(in.RecursiveReadOnly))
return nil
}
// Convert_v1_VolumeMountStatus_To_core_VolumeMountStatus is an autogenerated conversion function.
func Convert_v1_VolumeMountStatus_To_core_VolumeMountStatus(in *v1.VolumeMountStatus, out *core.VolumeMountStatus, s conversion.Scope) error {
return autoConvert_v1_VolumeMountStatus_To_core_VolumeMountStatus(in, out, s)
}
func autoConvert_core_VolumeMountStatus_To_v1_VolumeMountStatus(in *core.VolumeMountStatus, out *v1.VolumeMountStatus, s conversion.Scope) error {
out.Name = in.Name
out.MountPath = in.MountPath
out.ReadOnly = in.ReadOnly
out.RecursiveReadOnly = (*v1.RecursiveReadOnlyMode)(unsafe.Pointer(in.RecursiveReadOnly))
return nil
}
// Convert_core_VolumeMountStatus_To_v1_VolumeMountStatus is an autogenerated conversion function.
func Convert_core_VolumeMountStatus_To_v1_VolumeMountStatus(in *core.VolumeMountStatus, out *v1.VolumeMountStatus, s conversion.Scope) error {
return autoConvert_core_VolumeMountStatus_To_v1_VolumeMountStatus(in, out, s)
}
func autoConvert_v1_VolumeNodeAffinity_To_core_VolumeNodeAffinity(in *v1.VolumeNodeAffinity, out *core.VolumeNodeAffinity, s conversion.Scope) error {
out.Required = (*core.NodeSelector)(unsafe.Pointer(in.Required))
return nil

View File

@ -204,7 +204,7 @@ func ValidatePodSpecificAnnotationUpdates(newPod, oldPod *core.Pod, fldPath *fie
if newVal, exists := newAnnotations[k]; exists && newVal == oldVal {
continue // No change.
}
if strings.HasPrefix(k, v1.AppArmorBetaContainerAnnotationKeyPrefix) {
if strings.HasPrefix(k, v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix) {
allErrs = append(allErrs, field.Forbidden(fldPath.Key(k), "may not remove or update AppArmor annotations"))
}
if k == core.MirrorPodAnnotationKey {
@ -216,7 +216,7 @@ func ValidatePodSpecificAnnotationUpdates(newPod, oldPod *core.Pod, fldPath *fie
if _, ok := oldAnnotations[k]; ok {
continue // No change.
}
if strings.HasPrefix(k, v1.AppArmorBetaContainerAnnotationKeyPrefix) {
if strings.HasPrefix(k, v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix) {
allErrs = append(allErrs, field.Forbidden(fldPath.Key(k), "may not add AppArmor annotations"))
}
if k == core.MirrorPodAnnotationKey {
@ -942,7 +942,7 @@ func validateKeyToPath(kp *core.KeyToPath, fldPath *field.Path) field.ErrorList
if len(kp.Path) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("path"), ""))
}
allErrs = append(allErrs, validateLocalNonReservedPath(kp.Path, fldPath.Child("path"))...)
allErrs = append(allErrs, ValidateLocalNonReservedPath(kp.Path, fldPath.Child("path"))...)
if kp.Mode != nil && (*kp.Mode > 0777 || *kp.Mode < 0) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("mode"), *kp.Mode, fileModeErrorMsg))
}
@ -1050,7 +1050,7 @@ func validateDownwardAPIVolumeFile(file *core.DownwardAPIVolumeFile, fldPath *fi
if len(file.Path) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("path"), ""))
}
allErrs = append(allErrs, validateLocalNonReservedPath(file.Path, fldPath.Child("path"))...)
allErrs = append(allErrs, ValidateLocalNonReservedPath(file.Path, fldPath.Child("path"))...)
if file.FieldRef != nil {
allErrs = append(allErrs, validateObjectFieldSelector(file.FieldRef, &validVolumeDownwardAPIFieldPathExpressions, fldPath.Child("fieldRef"))...)
if file.ResourceFieldRef != nil {
@ -1153,6 +1153,8 @@ func validateProjectionSources(projection *core.ProjectedVolumeSource, projectio
}
if source.ServiceAccountToken.Path == "" {
allErrs = append(allErrs, field.Required(fldPath.Child("path"), ""))
} else if !opts.AllowNonLocalProjectedTokenPath {
allErrs = append(allErrs, ValidateLocalNonReservedPath(source.ServiceAccountToken.Path, fldPath.Child("path"))...)
}
}
if projPath := srcPath.Child("clusterTrustBundlePEM"); source.ClusterTrustBundle != nil {
@ -1209,7 +1211,7 @@ func validateProjectionSources(projection *core.ProjectedVolumeSource, projectio
allErrs = append(allErrs, field.Required(projPath.Child("path"), ""))
}
allErrs = append(allErrs, validateLocalNonReservedPath(source.ClusterTrustBundle.Path, projPath.Child("path"))...)
allErrs = append(allErrs, ValidateLocalNonReservedPath(source.ClusterTrustBundle.Path, projPath.Child("path"))...)
curPath := source.ClusterTrustBundle.Path
if !allPaths.Has(curPath) {
@ -1319,11 +1321,37 @@ func validateMountPropagation(mountPropagation *core.MountPropagationMode, conta
return allErrs
}
// This validate will make sure targetPath:
// validateMountRecursiveReadOnly validates RecursiveReadOnly mounts.
func validateMountRecursiveReadOnly(mount core.VolumeMount, fldPath *field.Path) field.ErrorList {
if mount.RecursiveReadOnly == nil {
return nil
}
allErrs := field.ErrorList{}
switch *mount.RecursiveReadOnly {
case core.RecursiveReadOnlyDisabled:
// NOP
case core.RecursiveReadOnlyEnabled, core.RecursiveReadOnlyIfPossible:
if !mount.ReadOnly {
allErrs = append(allErrs, field.Forbidden(fldPath, "may only be specified when readOnly is true"))
}
if mount.MountPropagation != nil && *mount.MountPropagation != core.MountPropagationNone {
allErrs = append(allErrs, field.Forbidden(fldPath, "may only be specified when mountPropagation is None or not specified"))
}
default:
supportedRRO := sets.New(
core.RecursiveReadOnlyDisabled,
core.RecursiveReadOnlyIfPossible,
core.RecursiveReadOnlyEnabled)
allErrs = append(allErrs, field.NotSupported(fldPath, *mount.RecursiveReadOnly, sets.List(supportedRRO)))
}
return allErrs
}
// ValidateLocalNonReservedPath makes sure targetPath:
// 1. is not abs path
// 2. does not contain any '..' elements
// 3. does not start with '..'
func validateLocalNonReservedPath(targetPath string, fldPath *field.Path) field.ErrorList {
func ValidateLocalNonReservedPath(targetPath string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, validateLocalDescendingPath(targetPath, fldPath)...)
// Don't report this error if the check for .. elements already caught it.
@ -2555,8 +2583,14 @@ func ValidateEnv(vars []core.EnvVar, fldPath *field.Path, opts PodValidationOpti
if len(ev.Name) == 0 {
allErrs = append(allErrs, field.Required(idxPath.Child("name"), ""))
} else {
for _, msg := range validation.IsEnvVarName(ev.Name) {
allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), ev.Name, msg))
if opts.AllowRelaxedEnvironmentVariableValidation {
for _, msg := range validation.IsRelaxedEnvVarName(ev.Name) {
allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), ev.Name, msg))
}
} else {
for _, msg := range validation.IsEnvVarName(ev.Name) {
allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), ev.Name, msg))
}
}
}
allErrs = append(allErrs, validateEnvVarValueFrom(ev, idxPath.Child("valueFrom"), opts)...)
@ -2701,13 +2735,19 @@ func validateContainerResourceFieldSelector(fs *core.ResourceFieldSelector, expr
return allErrs
}
func ValidateEnvFrom(vars []core.EnvFromSource, fldPath *field.Path) field.ErrorList {
func ValidateEnvFrom(vars []core.EnvFromSource, fldPath *field.Path, opts PodValidationOptions) field.ErrorList {
allErrs := field.ErrorList{}
for i, ev := range vars {
idxPath := fldPath.Index(i)
if len(ev.Prefix) > 0 {
for _, msg := range validation.IsEnvVarName(ev.Prefix) {
allErrs = append(allErrs, field.Invalid(idxPath.Child("prefix"), ev.Prefix, msg))
if opts.AllowRelaxedEnvironmentVariableValidation {
for _, msg := range validation.IsRelaxedEnvVarName(ev.Prefix) {
allErrs = append(allErrs, field.Invalid(idxPath.Child("prefix"), ev.Prefix, msg))
}
} else {
for _, msg := range validation.IsEnvVarName(ev.Prefix) {
allErrs = append(allErrs, field.Invalid(idxPath.Child("prefix"), ev.Prefix, msg))
}
}
}
@ -2895,6 +2935,7 @@ func ValidateVolumeMounts(mounts []core.VolumeMount, voldevices map[string]strin
if mnt.MountPropagation != nil {
allErrs = append(allErrs, validateMountPropagation(mnt.MountPropagation, container, fldPath.Child("mountPropagation"))...)
}
allErrs = append(allErrs, validateMountRecursiveReadOnly(mnt, fldPath.Child("recursiveReadOnly"))...)
}
return allErrs
}
@ -3348,7 +3389,7 @@ func validateResizePolicy(policyList []core.ContainerResizePolicy, fldPath *fiel
// validateEphemeralContainers is called by pod spec and template validation to validate the list of ephemeral containers.
// Note that this is called for pod template even though ephemeral containers aren't allowed in pod templates.
func validateEphemeralContainers(ephemeralContainers []core.EphemeralContainer, containers, initContainers []core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.Set[string], fldPath *field.Path, opts PodValidationOptions, podRestartPolicy *core.RestartPolicy) field.ErrorList {
func validateEphemeralContainers(ephemeralContainers []core.EphemeralContainer, containers, initContainers []core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.Set[string], fldPath *field.Path, opts PodValidationOptions, podRestartPolicy *core.RestartPolicy, hostUsers bool) field.ErrorList {
var allErrs field.ErrorList
if len(ephemeralContainers) == 0 {
@ -3369,7 +3410,7 @@ func validateEphemeralContainers(ephemeralContainers []core.EphemeralContainer,
idxPath := fldPath.Index(i)
c := (*core.Container)(&ec.EphemeralContainerCommon)
allErrs = append(allErrs, validateContainerCommon(c, volumes, podClaimNames, idxPath, opts, podRestartPolicy)...)
allErrs = append(allErrs, validateContainerCommon(c, volumes, podClaimNames, idxPath, opts, podRestartPolicy, hostUsers)...)
// Ephemeral containers don't need looser constraints for pod templates, so it's convenient to apply both validations
// here where we've already converted EphemeralContainerCommon to Container.
allErrs = append(allErrs, validateContainerOnlyForPod(c, idxPath)...)
@ -3431,7 +3472,7 @@ func validateFieldAllowList(value interface{}, allowedFields map[string]bool, er
}
// validateInitContainers is called by pod spec and template validation to validate the list of init containers
func validateInitContainers(containers []core.Container, regularContainers []core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.Set[string], gracePeriod int64, fldPath *field.Path, opts PodValidationOptions, podRestartPolicy *core.RestartPolicy) field.ErrorList {
func validateInitContainers(containers []core.Container, regularContainers []core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.Set[string], gracePeriod int64, fldPath *field.Path, opts PodValidationOptions, podRestartPolicy *core.RestartPolicy, hostUsers bool) field.ErrorList {
var allErrs field.ErrorList
allNames := sets.Set[string]{}
@ -3442,7 +3483,7 @@ func validateInitContainers(containers []core.Container, regularContainers []cor
idxPath := fldPath.Index(i)
// Apply the validation common to all container types
allErrs = append(allErrs, validateContainerCommon(&ctr, volumes, podClaimNames, idxPath, opts, podRestartPolicy)...)
allErrs = append(allErrs, validateContainerCommon(&ctr, volumes, podClaimNames, idxPath, opts, podRestartPolicy, hostUsers)...)
restartAlways := false
// Apply the validation specific to init containers
@ -3497,7 +3538,7 @@ func validateInitContainers(containers []core.Container, regularContainers []cor
// validateContainerCommon applies validation common to all container types. It's called by regular, init, and ephemeral
// container list validation to require a properly formatted name, image, etc.
func validateContainerCommon(ctr *core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.Set[string], path *field.Path, opts PodValidationOptions, podRestartPolicy *core.RestartPolicy) field.ErrorList {
func validateContainerCommon(ctr *core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.Set[string], path *field.Path, opts PodValidationOptions, podRestartPolicy *core.RestartPolicy, hostUsers bool) field.ErrorList {
var allErrs field.ErrorList
namePath := path.Child("name")
@ -3530,13 +3571,13 @@ func validateContainerCommon(ctr *core.Container, volumes map[string]core.Volume
volDevices := GetVolumeDeviceMap(ctr.VolumeDevices)
allErrs = append(allErrs, validateContainerPorts(ctr.Ports, path.Child("ports"))...)
allErrs = append(allErrs, ValidateEnv(ctr.Env, path.Child("env"), opts)...)
allErrs = append(allErrs, ValidateEnvFrom(ctr.EnvFrom, path.Child("envFrom"))...)
allErrs = append(allErrs, ValidateEnvFrom(ctr.EnvFrom, path.Child("envFrom"), opts)...)
allErrs = append(allErrs, ValidateVolumeMounts(ctr.VolumeMounts, volDevices, volumes, ctr, path.Child("volumeMounts"))...)
allErrs = append(allErrs, ValidateVolumeDevices(ctr.VolumeDevices, volMounts, volumes, path.Child("volumeDevices"))...)
allErrs = append(allErrs, validatePullPolicy(ctr.ImagePullPolicy, path.Child("imagePullPolicy"))...)
allErrs = append(allErrs, ValidateResourceRequirements(&ctr.Resources, podClaimNames, path.Child("resources"), opts)...)
allErrs = append(allErrs, validateResizePolicy(ctr.ResizePolicy, path.Child("resizePolicy"), podRestartPolicy)...)
allErrs = append(allErrs, ValidateSecurityContext(ctr.SecurityContext, path.Child("securityContext"))...)
allErrs = append(allErrs, ValidateSecurityContext(ctr.SecurityContext, path.Child("securityContext"), hostUsers)...)
return allErrs
}
@ -3569,7 +3610,7 @@ func validateHostUsers(spec *core.PodSpec, fldPath *field.Path) field.ErrorList
}
// validateContainers is called by pod spec and template validation to validate the list of regular containers.
func validateContainers(containers []core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.Set[string], gracePeriod int64, fldPath *field.Path, opts PodValidationOptions, podRestartPolicy *core.RestartPolicy) field.ErrorList {
func validateContainers(containers []core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.Set[string], gracePeriod int64, fldPath *field.Path, opts PodValidationOptions, podRestartPolicy *core.RestartPolicy, hostUsers bool) field.ErrorList {
allErrs := field.ErrorList{}
if len(containers) == 0 {
@ -3581,7 +3622,7 @@ func validateContainers(containers []core.Container, volumes map[string]core.Vol
path := fldPath.Index(i)
// Apply validation common to all containers
allErrs = append(allErrs, validateContainerCommon(&ctr, volumes, podClaimNames, path, opts, podRestartPolicy)...)
allErrs = append(allErrs, validateContainerCommon(&ctr, volumes, podClaimNames, path, opts, podRestartPolicy, hostUsers)...)
// Container names must be unique within the list of regular containers.
// Collisions with init or ephemeral container names will be detected by the init or ephemeral
@ -3718,9 +3759,7 @@ func validatePodDNSConfig(dnsConfig *core.PodDNSConfig, dnsPolicy *core.DNSPolic
allErrs = append(allErrs, field.Invalid(fldPath.Child("nameservers"), dnsConfig.Nameservers, fmt.Sprintf("must not have more than %v nameservers", MaxDNSNameservers)))
}
for i, ns := range dnsConfig.Nameservers {
if ip := netutils.ParseIPSloppy(ns); ip == nil {
allErrs = append(allErrs, field.Invalid(fldPath.Child("nameservers").Index(i), ns, "must be valid IP address"))
}
allErrs = append(allErrs, validation.IsValidIP(fldPath.Child("nameservers").Index(i), ns)...)
}
// Validate searches.
if len(dnsConfig.Searches) > MaxDNSSearchPaths {
@ -3887,12 +3926,10 @@ func validateOnlyDeletedSchedulingGates(newGates, oldGates []core.PodSchedulingG
func ValidateHostAliases(hostAliases []core.HostAlias, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
for _, hostAlias := range hostAliases {
if ip := netutils.ParseIPSloppy(hostAlias.IP); ip == nil {
allErrs = append(allErrs, field.Invalid(fldPath.Child("ip"), hostAlias.IP, "must be valid IP address"))
}
for _, hostname := range hostAlias.Hostnames {
allErrs = append(allErrs, ValidateDNS1123Subdomain(hostname, fldPath.Child("hostnames"))...)
for i, hostAlias := range hostAliases {
allErrs = append(allErrs, validation.IsValidIP(fldPath.Index(i).Child("ip"), hostAlias.IP)...)
for j, hostname := range hostAlias.Hostnames {
allErrs = append(allErrs, ValidateDNS1123Subdomain(hostname, fldPath.Index(i).Child("hostnames").Index(j))...)
}
}
return allErrs
@ -3976,13 +4013,15 @@ type PodValidationOptions struct {
AllowHostIPsField bool
// Allow invalid topologySpreadConstraint labelSelector for backward compatibility
AllowInvalidTopologySpreadConstraintLabelSelector bool
// Allow node selector additions for gated pods.
AllowMutableNodeSelectorAndNodeAffinity bool
// Allow projected token volumes with non-local paths
AllowNonLocalProjectedTokenPath bool
// Allow namespaced sysctls in hostNet and hostIPC pods
AllowNamespacedSysctlsForHostNetAndHostIPC bool
// The top-level resource being validated is a Pod, not just a PodSpec
// embedded in some other resource.
ResourceIsPod bool
// Allow relaxed validation of environment variable names
AllowRelaxedEnvironmentVariableValidation bool
}
// validatePodMetadataAndSpec tests if required fields in the pod.metadata and pod.spec are set,
@ -4027,9 +4066,7 @@ func validatePodIPs(pod *core.Pod) field.ErrorList {
// all PodIPs must be valid IPs
for i, podIP := range pod.Status.PodIPs {
for _, msg := range validation.IsValidIP(podIP.IP) {
allErrs = append(allErrs, field.Invalid(podIPsField.Index(i), podIP.IP, msg))
}
allErrs = append(allErrs, validation.IsValidIP(podIPsField.Index(i), podIP.IP)...)
}
// if we have more than one Pod.PodIP then
@ -4081,9 +4118,7 @@ func validateHostIPs(pod *core.Pod) field.ErrorList {
// all HostPs must be valid IPs
for i, hostIP := range pod.Status.HostIPs {
for _, msg := range validation.IsValidIP(hostIP.IP) {
allErrs = append(allErrs, field.Invalid(hostIPsField.Index(i), hostIP.IP, msg))
}
allErrs = append(allErrs, validation.IsValidIP(hostIPsField.Index(i), hostIP.IP)...)
}
// if we have more than one Pod.HostIP then
@ -4131,13 +4166,17 @@ func ValidatePodSpec(spec *core.PodSpec, podMeta *metav1.ObjectMeta, fldPath *fi
gracePeriod = *spec.TerminationGracePeriodSeconds
}
// The default for hostUsers is true, so a spec with no SecurityContext or no HostUsers field will be true.
// If the default ever changes, this condition will need to be changed.
hostUsers := spec.SecurityContext == nil || spec.SecurityContext.HostUsers == nil || *spec.SecurityContext.HostUsers
vols, vErrs := ValidateVolumes(spec.Volumes, podMeta, fldPath.Child("volumes"), opts)
allErrs = append(allErrs, vErrs...)
podClaimNames := gatherPodResourceClaimNames(spec.ResourceClaims)
allErrs = append(allErrs, validatePodResourceClaims(podMeta, spec.ResourceClaims, fldPath.Child("resourceClaims"))...)
allErrs = append(allErrs, validateContainers(spec.Containers, vols, podClaimNames, gracePeriod, fldPath.Child("containers"), opts, &spec.RestartPolicy)...)
allErrs = append(allErrs, validateInitContainers(spec.InitContainers, spec.Containers, vols, podClaimNames, gracePeriod, fldPath.Child("initContainers"), opts, &spec.RestartPolicy)...)
allErrs = append(allErrs, validateEphemeralContainers(spec.EphemeralContainers, spec.Containers, spec.InitContainers, vols, podClaimNames, fldPath.Child("ephemeralContainers"), opts, &spec.RestartPolicy)...)
allErrs = append(allErrs, validateContainers(spec.Containers, vols, podClaimNames, gracePeriod, fldPath.Child("containers"), opts, &spec.RestartPolicy, hostUsers)...)
allErrs = append(allErrs, validateInitContainers(spec.InitContainers, spec.Containers, vols, podClaimNames, gracePeriod, fldPath.Child("initContainers"), opts, &spec.RestartPolicy, hostUsers)...)
allErrs = append(allErrs, validateEphemeralContainers(spec.EphemeralContainers, spec.Containers, spec.InitContainers, vols, podClaimNames, fldPath.Child("ephemeralContainers"), opts, &spec.RestartPolicy, hostUsers)...)
allErrs = append(allErrs, validatePodHostNetworkDeps(spec, fldPath, opts)...)
allErrs = append(allErrs, validateRestartPolicy(&spec.RestartPolicy, fldPath.Child("restartPolicy"))...)
allErrs = append(allErrs, validateDNSPolicy(&spec.DNSPolicy, fldPath.Child("dnsPolicy"))...)
@ -4240,6 +4279,9 @@ func validateWindows(spec *core.PodSpec, fldPath *field.Path) field.ErrorList {
securityContext := spec.SecurityContext
// validate Pod SecurityContext
if securityContext != nil {
if securityContext.AppArmorProfile != nil {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("securityContext").Child("appArmorProfile"), "cannot be set for a windows pod"))
}
if securityContext.SELinuxOptions != nil {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("securityContext").Child("seLinuxOptions"), "cannot be set for a windows pod"))
}
@ -4286,6 +4328,9 @@ func validateWindows(spec *core.PodSpec, fldPath *field.Path) field.ErrorList {
// TODO: Think if we need to relax this restriction or some of the restrictions
if sc != nil {
fldPath := cFldPath.Child("securityContext")
if sc.AppArmorProfile != nil {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("appArmorProfile"), "cannot be set for a windows pod"))
}
if sc.SELinuxOptions != nil {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("seLinuxOptions"), "cannot be set for a windows pod"))
}
@ -4663,13 +4708,55 @@ func validateSeccompProfileType(fldPath *field.Path, seccompProfileType core.Sec
}
}
func ValidateAppArmorProfileField(profile *core.AppArmorProfile, fldPath *field.Path) field.ErrorList {
if profile == nil {
return nil
}
allErrs := field.ErrorList{}
switch profile.Type {
case core.AppArmorProfileTypeLocalhost:
if profile.LocalhostProfile == nil {
allErrs = append(allErrs, field.Required(fldPath.Child("localhostProfile"), "must be set when AppArmor type is Localhost"))
} else {
localhostProfile := strings.TrimSpace(*profile.LocalhostProfile)
if localhostProfile != *profile.LocalhostProfile {
allErrs = append(allErrs, field.Invalid(fldPath.Child("localhostProfile"), *profile.LocalhostProfile, "must not be padded with whitespace"))
} else if localhostProfile == "" {
allErrs = append(allErrs, field.Required(fldPath.Child("localhostProfile"), "must be set when AppArmor type is Localhost"))
}
const maxLocalhostProfileLength = 4095 // PATH_MAX - 1
if len(*profile.LocalhostProfile) > maxLocalhostProfileLength {
allErrs = append(allErrs, field.TooLongMaxLength(fldPath.Child("localhostProfile"), *profile.LocalhostProfile, maxLocalhostProfileLength))
}
}
case core.AppArmorProfileTypeRuntimeDefault, core.AppArmorProfileTypeUnconfined:
if profile.LocalhostProfile != nil {
allErrs = append(allErrs, field.Invalid(fldPath.Child("localhostProfile"), profile.LocalhostProfile, "can only be set when AppArmor type is Localhost"))
}
case "":
allErrs = append(allErrs, field.Required(fldPath.Child("type"), "type is required when appArmorProfile is set"))
default:
allErrs = append(allErrs, field.NotSupported(fldPath.Child("type"), profile.Type,
[]core.AppArmorProfileType{core.AppArmorProfileTypeLocalhost, core.AppArmorProfileTypeRuntimeDefault, core.AppArmorProfileTypeUnconfined}))
}
return allErrs
}
func ValidateAppArmorPodAnnotations(annotations map[string]string, spec *core.PodSpec, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
for k, p := range annotations {
if !strings.HasPrefix(k, v1.AppArmorBetaContainerAnnotationKeyPrefix) {
if !strings.HasPrefix(k, v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix) {
continue
}
containerName := strings.TrimPrefix(k, v1.AppArmorBetaContainerAnnotationKeyPrefix)
containerName := strings.TrimPrefix(k, v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix)
if !podSpecHasContainer(spec, containerName) {
allErrs = append(allErrs, field.Invalid(fldPath.Key(k), containerName, "container not found"))
}
@ -4683,15 +4770,70 @@ func ValidateAppArmorPodAnnotations(annotations map[string]string, spec *core.Po
}
func ValidateAppArmorProfileFormat(profile string) error {
if profile == "" || profile == v1.AppArmorBetaProfileRuntimeDefault || profile == v1.AppArmorBetaProfileNameUnconfined {
if profile == "" || profile == v1.DeprecatedAppArmorBetaProfileRuntimeDefault || profile == v1.DeprecatedAppArmorBetaProfileNameUnconfined {
return nil
}
if !strings.HasPrefix(profile, v1.AppArmorBetaProfileNamePrefix) {
if !strings.HasPrefix(profile, v1.DeprecatedAppArmorBetaProfileNamePrefix) {
return fmt.Errorf("invalid AppArmor profile name: %q", profile)
}
return nil
}
// validateAppArmorAnnotationsAndFieldsMatchOnCreate validates that AppArmor fields and annotations are consistent.
func validateAppArmorAnnotationsAndFieldsMatchOnCreate(objectMeta metav1.ObjectMeta, podSpec *core.PodSpec, specPath *field.Path) field.ErrorList {
if !utilfeature.DefaultFeatureGate.Enabled(features.AppArmorFields) {
return nil
}
if podSpec.OS != nil && podSpec.OS.Name == core.Windows {
// Skip consistency check for windows pods.
return nil
}
allErrs := field.ErrorList{}
var podProfile *core.AppArmorProfile
if podSpec.SecurityContext != nil {
podProfile = podSpec.SecurityContext.AppArmorProfile
}
podshelper.VisitContainersWithPath(podSpec, specPath, func(c *core.Container, cFldPath *field.Path) bool {
containerProfile := podProfile
if c.SecurityContext != nil && c.SecurityContext.AppArmorProfile != nil {
containerProfile = c.SecurityContext.AppArmorProfile
}
if containerProfile == nil {
return true
}
key := core.DeprecatedAppArmorAnnotationKeyPrefix + c.Name
if annotation, found := objectMeta.Annotations[key]; found {
apparmorPath := cFldPath.Child("securityContext").Child("appArmorProfile")
switch containerProfile.Type {
case core.AppArmorProfileTypeUnconfined:
if annotation != core.DeprecatedAppArmorAnnotationValueUnconfined {
allErrs = append(allErrs, field.Forbidden(apparmorPath.Child("type"), "apparmor type in annotation and field must match"))
}
case core.AppArmorProfileTypeRuntimeDefault:
if annotation != core.DeprecatedAppArmorAnnotationValueRuntimeDefault {
allErrs = append(allErrs, field.Forbidden(apparmorPath.Child("type"), "apparmor type in annotation and field must match"))
}
case core.AppArmorProfileTypeLocalhost:
if !strings.HasPrefix(annotation, core.DeprecatedAppArmorAnnotationValueLocalhostPrefix) {
allErrs = append(allErrs, field.Forbidden(apparmorPath.Child("type"), "apparmor type in annotation and field must match"))
} else if containerProfile.LocalhostProfile == nil || strings.TrimPrefix(annotation, core.DeprecatedAppArmorAnnotationValueLocalhostPrefix) != *containerProfile.LocalhostProfile {
allErrs = append(allErrs, field.Forbidden(apparmorPath.Child("localhostProfile"), "apparmor profile in annotation and field must match"))
}
}
}
return true
})
return allErrs
}
func podSpecHasContainer(spec *core.PodSpec, containerName string) bool {
var hasContainer bool
podshelper.VisitContainersWithPath(spec, field.NewPath("spec"), func(c *core.Container, _ *field.Path) bool {
@ -4805,6 +4947,7 @@ func validatePodSpecSecurityContext(securityContext *core.PodSecurityContext, sp
allErrs = append(allErrs, validateSeccompProfileField(securityContext.SeccompProfile, fldPath.Child("seccompProfile"))...)
allErrs = append(allErrs, validateWindowsSecurityContextOptions(securityContext.WindowsOptions, fldPath.Child("windowsOptions"))...)
allErrs = append(allErrs, ValidateAppArmorProfileField(securityContext.AppArmorProfile, fldPath.Child("appArmorProfile"))...)
}
return allErrs
@ -4845,6 +4988,7 @@ func ValidatePodCreate(pod *core.Pod, opts PodValidationOptions) field.ErrorList
allErrs = append(allErrs, field.Forbidden(fldPath.Child("nodeName"), "cannot be set until all schedulingGates have been cleared"))
}
allErrs = append(allErrs, validateSeccompAnnotationsAndFields(pod.ObjectMeta, &pod.Spec, fldPath)...)
allErrs = append(allErrs, validateAppArmorAnnotationsAndFieldsMatchOnCreate(pod.ObjectMeta, &pod.Spec, fldPath)...)
return allErrs
}
@ -5060,7 +5204,7 @@ func ValidatePodUpdate(newPod, oldPod *core.Pod, opts PodValidationOptions) fiel
// Handle validations specific to gated pods.
podIsGated := len(oldPod.Spec.SchedulingGates) > 0
if opts.AllowMutableNodeSelectorAndNodeAffinity && podIsGated {
if podIsGated {
// Additions to spec.nodeSelector are allowed (no deletions or mutations) for gated pods.
if !apiequality.Semantic.DeepEqual(mungedPodSpec.NodeSelector, oldPod.Spec.NodeSelector) {
allErrs = append(allErrs, validateNodeSelectorMutation(specPath.Child("nodeSelector"), mungedPodSpec.NodeSelector, oldPod.Spec.NodeSelector)...)
@ -5439,10 +5583,8 @@ func ValidateService(service *core.Service) field.ErrorList {
ipPath := specPath.Child("externalIPs")
for i, ip := range service.Spec.ExternalIPs {
idxPath := ipPath.Index(i)
if msgs := validation.IsValidIP(ip); len(msgs) != 0 {
for i := range msgs {
allErrs = append(allErrs, field.Invalid(idxPath, ip, msgs[i]))
}
if errs := validation.IsValidIP(idxPath, ip); len(errs) != 0 {
allErrs = append(allErrs, errs...)
} else {
allErrs = append(allErrs, ValidateNonSpecialIP(ip, idxPath)...)
}
@ -5496,24 +5638,32 @@ func ValidateService(service *core.Service) field.ErrorList {
ports[key] = true
}
// Validate SourceRange field and annotation
_, ok := service.Annotations[core.AnnotationLoadBalancerSourceRangesKey]
if len(service.Spec.LoadBalancerSourceRanges) > 0 || ok {
var fieldPath *field.Path
var val string
if len(service.Spec.LoadBalancerSourceRanges) > 0 {
fieldPath = specPath.Child("LoadBalancerSourceRanges")
val = fmt.Sprintf("%v", service.Spec.LoadBalancerSourceRanges)
} else {
fieldPath = field.NewPath("metadata", "annotations").Key(core.AnnotationLoadBalancerSourceRangesKey)
val = service.Annotations[core.AnnotationLoadBalancerSourceRangesKey]
}
// Validate SourceRanges field or annotation.
if len(service.Spec.LoadBalancerSourceRanges) > 0 {
fieldPath := specPath.Child("LoadBalancerSourceRanges")
if service.Spec.Type != core.ServiceTypeLoadBalancer {
allErrs = append(allErrs, field.Forbidden(fieldPath, "may only be used when `type` is 'LoadBalancer'"))
}
_, err := apiservice.GetLoadBalancerSourceRanges(service)
if err != nil {
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 "))
for idx, value := range service.Spec.LoadBalancerSourceRanges {
// Note: due to a historical accident around transition from the
// annotation value, these values are allowed to be space-padded.
value = strings.TrimSpace(value)
allErrs = append(allErrs, validation.IsValidCIDR(fieldPath.Index(idx), value)...)
}
} else if val, annotationSet := service.Annotations[core.AnnotationLoadBalancerSourceRangesKey]; annotationSet {
fieldPath := field.NewPath("metadata", "annotations").Key(core.AnnotationLoadBalancerSourceRangesKey)
if service.Spec.Type != core.ServiceTypeLoadBalancer {
allErrs = append(allErrs, field.Forbidden(fieldPath, "may only be used when `type` is 'LoadBalancer'"))
}
val = strings.TrimSpace(val)
if val != "" {
cidrs := strings.Split(val, ",")
for _, value := range cidrs {
value = strings.TrimSpace(value)
allErrs = append(allErrs, validation.IsValidCIDR(fieldPath, value)...)
}
}
}
@ -5534,6 +5684,9 @@ func ValidateService(service *core.Service) field.ErrorList {
// internal traffic policy field
allErrs = append(allErrs, validateServiceInternalTrafficFieldsValue(service)...)
// traffic distribution field
allErrs = append(allErrs, validateServiceTrafficDistribution(service)...)
return allErrs
}
@ -5651,6 +5804,22 @@ func validateServiceInternalTrafficFieldsValue(service *core.Service) field.Erro
return allErrs
}
// validateServiceTrafficDistribution validates the values for the
// trafficDistribution field.
func validateServiceTrafficDistribution(service *core.Service) field.ErrorList {
allErrs := field.ErrorList{}
if service.Spec.TrafficDistribution == nil {
return allErrs
}
if *service.Spec.TrafficDistribution != v1.ServiceTrafficDistributionPreferClose {
allErrs = append(allErrs, field.NotSupported(field.NewPath("spec").Child("trafficDistribution"), *service.Spec.TrafficDistribution, []string{v1.ServiceTrafficDistributionPreferClose}))
}
return allErrs
}
// ValidateServiceCreate validates Services as they are created.
func ValidateServiceCreate(service *core.Service) field.ErrorList {
return ValidateService(service)
@ -5797,6 +5966,7 @@ func ValidatePodTemplateSpec(spec *core.PodTemplateSpec, fldPath *field.Path, op
allErrs = append(allErrs, ValidatePodSpecificAnnotations(spec.Annotations, &spec.Spec, fldPath.Child("annotations"), opts)...)
allErrs = append(allErrs, ValidatePodSpec(&spec.Spec, nil, fldPath.Child("spec"), opts)...)
allErrs = append(allErrs, validateSeccompAnnotationsAndFields(spec.ObjectMeta, &spec.Spec, fldPath.Child("spec"))...)
allErrs = append(allErrs, validateAppArmorAnnotationsAndFieldsMatchOnCreate(spec.ObjectMeta, &spec.Spec, fldPath.Child("spec"))...)
if len(spec.Spec.EphemeralContainers) > 0 {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("spec", "ephemeralContainers"), "ephemeral containers not allowed in pod template"))
@ -5916,9 +6086,7 @@ func ValidateNode(node *core.Node) field.ErrorList {
// all PodCIDRs should be valid ones
for idx, value := range node.Spec.PodCIDRs {
if _, err := ValidateCIDR(value); err != nil {
allErrs = append(allErrs, field.Invalid(podCIDRsField.Index(idx), node.Spec.PodCIDRs, "must be valid CIDR"))
}
allErrs = append(allErrs, validation.IsValidCIDR(podCIDRsField.Index(idx), value)...)
}
// if more than PodCIDR then
@ -6954,9 +7122,7 @@ func validateEndpointSubsets(subsets []core.EndpointSubset, fldPath *field.Path)
func validateEndpointAddress(address *core.EndpointAddress, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
for _, msg := range validation.IsValidIP(address.IP) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("ip"), address.IP, msg))
}
allErrs = append(allErrs, validation.IsValidIP(fldPath.Child("ip"), address.IP)...)
if len(address.Hostname) > 0 {
allErrs = append(allErrs, ValidateDNS1123Label(address.Hostname, fldPath.Child("hostname"))...)
}
@ -7022,7 +7188,7 @@ func validateEndpointPort(port *core.EndpointPort, requireName bool, fldPath *fi
}
// ValidateSecurityContext ensures the security context contains valid settings
func ValidateSecurityContext(sc *core.SecurityContext, fldPath *field.Path) field.ErrorList {
func ValidateSecurityContext(sc *core.SecurityContext, fldPath *field.Path, hostUsers bool) field.ErrorList {
allErrs := field.ErrorList{}
// this should only be true for testing since SecurityContext is defaulted by the core
if sc == nil {
@ -7051,6 +7217,9 @@ func ValidateSecurityContext(sc *core.SecurityContext, fldPath *field.Path) fiel
if err := ValidateProcMountType(fldPath.Child("procMount"), *sc.ProcMount); err != nil {
allErrs = append(allErrs, err)
}
if hostUsers && *sc.ProcMount == core.UnmaskedProcMount {
allErrs = append(allErrs, field.Invalid(fldPath.Child("procMount"), sc.ProcMount, "`hostUsers` must be false to use `Unmasked`"))
}
}
allErrs = append(allErrs, validateSeccompProfileField(sc.SeccompProfile, fldPath.Child("seccompProfile"))...)
@ -7069,6 +7238,7 @@ func ValidateSecurityContext(sc *core.SecurityContext, fldPath *field.Path) fiel
}
allErrs = append(allErrs, validateWindowsSecurityContextOptions(sc.WindowsOptions, fldPath.Child("windowsOptions"))...)
allErrs = append(allErrs, ValidateAppArmorProfileField(sc.AppArmorProfile, fldPath.Child("appArmorProfile"))...)
return allErrs
}
@ -7302,9 +7472,7 @@ func ValidateLoadBalancerStatus(status *core.LoadBalancerStatus, fldPath *field.
for i, ingress := range status.Ingress {
idxPath := ingrPath.Index(i)
if len(ingress.IP) > 0 {
if isIP := (netutils.ParseIPSloppy(ingress.IP) != nil); !isIP {
allErrs = append(allErrs, field.Invalid(idxPath.Child("ip"), ingress.IP, "must be a valid IP address"))
}
allErrs = append(allErrs, validation.IsValidIP(idxPath.Child("ip"), ingress.IP)...)
}
if utilfeature.DefaultFeatureGate.Enabled(features.LoadBalancerIPMode) && ingress.IPMode == nil {
@ -7350,15 +7518,6 @@ func validateVolumeNodeAffinity(nodeAffinity *core.VolumeNodeAffinity, fldPath *
return true, allErrs
}
// ValidateCIDR validates whether a CIDR matches the conventions expected by net.ParseCIDR
func ValidateCIDR(cidr string) (*net.IPNet, error) {
_, net, err := netutils.ParseCIDRSloppy(cidr)
if err != nil {
return nil, err
}
return net, nil
}
func IsDecremented(update, old *int32) bool {
if update == nil && old != nil {
return true
@ -7658,11 +7817,9 @@ func ValidateServiceClusterIPsRelatedFields(service *core.Service) field.ErrorLi
}
// is it valid ip?
errorMessages := validation.IsValidIP(clusterIP)
errorMessages := validation.IsValidIP(clusterIPsField.Index(i), clusterIP)
hasInvalidIPs = (len(errorMessages) != 0) || hasInvalidIPs
for _, msg := range errorMessages {
allErrs = append(allErrs, field.Invalid(clusterIPsField.Index(i), clusterIP, msg))
}
allErrs = append(allErrs, errorMessages...)
}
// max two

View File

@ -74,6 +74,27 @@ func (in *Affinity) DeepCopy() *Affinity {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AppArmorProfile) DeepCopyInto(out *AppArmorProfile) {
*out = *in
if in.LocalhostProfile != nil {
in, out := &in.LocalhostProfile, &out.LocalhostProfile
*out = new(string)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AppArmorProfile.
func (in *AppArmorProfile) DeepCopy() *AppArmorProfile {
if in == nil {
return nil
}
out := new(AppArmorProfile)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AttachedVolume) DeepCopyInto(out *AttachedVolume) {
*out = *in
@ -1041,6 +1062,13 @@ func (in *ContainerStatus) DeepCopyInto(out *ContainerStatus) {
*out = new(ResourceRequirements)
(*in).DeepCopyInto(*out)
}
if in.VolumeMounts != nil {
in, out := &in.VolumeMounts, &out.VolumeMounts
*out = make([]VolumeMountStatus, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
@ -2728,24 +2756,43 @@ func (in *NodeProxyOptions) DeepCopyObject() runtime.Object {
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NodeResources) DeepCopyInto(out *NodeResources) {
func (in *NodeRuntimeHandler) DeepCopyInto(out *NodeRuntimeHandler) {
*out = *in
if in.Capacity != nil {
in, out := &in.Capacity, &out.Capacity
*out = make(ResourceList, len(*in))
for key, val := range *in {
(*out)[key] = val.DeepCopy()
}
if in.Features != nil {
in, out := &in.Features, &out.Features
*out = new(NodeRuntimeHandlerFeatures)
(*in).DeepCopyInto(*out)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeResources.
func (in *NodeResources) DeepCopy() *NodeResources {
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeRuntimeHandler.
func (in *NodeRuntimeHandler) DeepCopy() *NodeRuntimeHandler {
if in == nil {
return nil
}
out := new(NodeResources)
out := new(NodeRuntimeHandler)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NodeRuntimeHandlerFeatures) DeepCopyInto(out *NodeRuntimeHandlerFeatures) {
*out = *in
if in.RecursiveReadOnlyMounts != nil {
in, out := &in.RecursiveReadOnlyMounts, &out.RecursiveReadOnlyMounts
*out = new(bool)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeRuntimeHandlerFeatures.
func (in *NodeRuntimeHandlerFeatures) DeepCopy() *NodeRuntimeHandlerFeatures {
if in == nil {
return nil
}
out := new(NodeRuntimeHandlerFeatures)
in.DeepCopyInto(out)
return out
}
@ -2910,6 +2957,13 @@ func (in *NodeStatus) DeepCopyInto(out *NodeStatus) {
*out = new(NodeConfigStatus)
(*in).DeepCopyInto(*out)
}
if in.RuntimeHandlers != nil {
in, out := &in.RuntimeHandlers, &out.RuntimeHandlers
*out = make([]NodeRuntimeHandler, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
@ -4033,6 +4087,11 @@ func (in *PodSecurityContext) DeepCopyInto(out *PodSecurityContext) {
*out = new(SeccompProfile)
(*in).DeepCopyInto(*out)
}
if in.AppArmorProfile != nil {
in, out := &in.AppArmorProfile, &out.AppArmorProfile
*out = new(AppArmorProfile)
(*in).DeepCopyInto(*out)
}
return
}
@ -5401,6 +5460,11 @@ func (in *SecurityContext) DeepCopyInto(out *SecurityContext) {
*out = new(SeccompProfile)
(*in).DeepCopyInto(*out)
}
if in.AppArmorProfile != nil {
in, out := &in.AppArmorProfile, &out.AppArmorProfile
*out = new(AppArmorProfile)
(*in).DeepCopyInto(*out)
}
return
}
@ -5700,6 +5764,11 @@ func (in *ServiceSpec) DeepCopyInto(out *ServiceSpec) {
*out = new(ServiceInternalTrafficPolicy)
**out = **in
}
if in.TrafficDistribution != nil {
in, out := &in.TrafficDistribution, &out.TrafficDistribution
*out = new(string)
**out = **in
}
return
}
@ -6058,6 +6127,11 @@ func (in *VolumeDevice) DeepCopy() *VolumeDevice {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *VolumeMount) DeepCopyInto(out *VolumeMount) {
*out = *in
if in.RecursiveReadOnly != nil {
in, out := &in.RecursiveReadOnly, &out.RecursiveReadOnly
*out = new(RecursiveReadOnlyMode)
**out = **in
}
if in.MountPropagation != nil {
in, out := &in.MountPropagation, &out.MountPropagation
*out = new(MountPropagationMode)
@ -6076,6 +6150,27 @@ func (in *VolumeMount) DeepCopy() *VolumeMount {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *VolumeMountStatus) DeepCopyInto(out *VolumeMountStatus) {
*out = *in
if in.RecursiveReadOnly != nil {
in, out := &in.RecursiveReadOnly, &out.RecursiveReadOnly
*out = new(RecursiveReadOnlyMode)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeMountStatus.
func (in *VolumeMountStatus) DeepCopy() *VolumeMountStatus {
if in == nil {
return nil
}
out := new(VolumeMountStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *VolumeNodeAffinity) DeepCopyInto(out *VolumeNodeAffinity) {
*out = *in

View File

@ -52,7 +52,6 @@ import (
hashutil "k8s.io/kubernetes/pkg/util/hash"
taintutils "k8s.io/kubernetes/pkg/util/taints"
"k8s.io/utils/clock"
"k8s.io/utils/integer"
"k8s.io/klog/v2"
)
@ -940,7 +939,7 @@ func podReadyTime(pod *v1.Pod) *metav1.Time {
func maxContainerRestarts(pod *v1.Pod) int {
maxRestarts := 0
for _, c := range pod.Status.ContainerStatuses {
maxRestarts = integer.IntMax(maxRestarts, int(c.RestartCount))
maxRestarts = max(maxRestarts, int(c.RestartCount))
}
return maxRestarts
}
@ -952,7 +951,7 @@ func FilterActivePods(logger klog.Logger, pods []*v1.Pod) []*v1.Pod {
if IsPodActive(p) {
result = append(result, p)
} else {
logger.V(4).Info("Ignoring inactive pod", "pod", klog.KObj(p), "phase", p.Status.Phase, "deletionTime", p.DeletionTimestamp)
logger.V(4).Info("Ignoring inactive pod", "pod", klog.KObj(p), "phase", p.Status.Phase, "deletionTime", klog.SafePtr(p.DeletionTimestamp))
}
}
return result

View File

@ -479,12 +479,12 @@ func GetProportion(logger klog.Logger, rs *apps.ReplicaSet, d apps.Deployment, d
// Use the minimum between the replica set fraction and the maximum allowed replicas
// when scaling up. This way we ensure we will not scale up more than the allowed
// replicas we can add.
return integer.Int32Min(rsFraction, allowed)
return min(rsFraction, allowed)
}
// Use the maximum between the replica set fraction and the maximum allowed replicas
// when scaling down. This way we ensure we will not scale down more than the allowed
// replicas we can remove.
return integer.Int32Max(rsFraction, allowed)
return max(rsFraction, allowed)
}
// getReplicaSetFraction estimates the fraction of replicas a replica set can have in
@ -799,7 +799,7 @@ func NewRSNewReplicas(deployment *apps.Deployment, allRSs []*apps.ReplicaSet, ne
// Scale up.
scaleUpCount := maxTotalPods - currentPodCount
// Do not exceed the number of desired replicas.
scaleUpCount = int32(integer.IntMin(int(scaleUpCount), int(*(deployment.Spec.Replicas)-*(newRS.Spec.Replicas))))
scaleUpCount = min(scaleUpCount, *(deployment.Spec.Replicas)-*(newRS.Spec.Replicas))
return *(newRS.Spec.Replicas) + scaleUpCount, nil
case apps.RecreateDeploymentStrategyType:
return *(deployment.Spec.Replicas), nil

View File

@ -0,0 +1,69 @@
/*
Copyright 2024 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package features
import (
"fmt"
clientfeatures "k8s.io/client-go/features"
"k8s.io/component-base/featuregate"
)
// clientAdapter adapts a k8s.io/component-base/featuregate.MutableFeatureGate to client-go's
// feature Gate and Registry interfaces. The component-base types Feature, FeatureSpec, and
// prerelease, and the component-base prerelease constants, are duplicated by parallel types and
// constants in client-go. The parallel types exist to allow the feature gate mechanism to be used
// for client-go features without introducing a circular dependency between component-base and
// client-go.
type clientAdapter struct {
mfg featuregate.MutableFeatureGate
}
var _ clientfeatures.Gates = &clientAdapter{}
func (a *clientAdapter) Enabled(name clientfeatures.Feature) bool {
return a.mfg.Enabled(featuregate.Feature(name))
}
var _ clientfeatures.Registry = &clientAdapter{}
func (a *clientAdapter) Add(in map[clientfeatures.Feature]clientfeatures.FeatureSpec) error {
out := map[featuregate.Feature]featuregate.FeatureSpec{}
for name, spec := range in {
converted := featuregate.FeatureSpec{
Default: spec.Default,
LockToDefault: spec.LockToDefault,
}
switch spec.PreRelease {
case clientfeatures.Alpha:
converted.PreRelease = featuregate.Alpha
case clientfeatures.Beta:
converted.PreRelease = featuregate.Beta
case clientfeatures.GA:
converted.PreRelease = featuregate.GA
case clientfeatures.Deprecated:
converted.PreRelease = featuregate.Deprecated
default:
// The default case implies programmer error. The same set of prerelease
// constants must exist in both component-base and client-go, and each one
// must have a case here.
panic(fmt.Sprintf("unrecognized prerelease %q of feature %q", spec.PreRelease, name))
}
out[featuregate.Feature(name)] = converted
}
return a.mfg.Add(out)
}

View File

@ -21,6 +21,7 @@ import (
"k8s.io/apimachinery/pkg/util/runtime"
genericfeatures "k8s.io/apiserver/pkg/features"
utilfeature "k8s.io/apiserver/pkg/util/feature"
clientfeatures "k8s.io/client-go/features"
"k8s.io/component-base/featuregate"
)
@ -58,21 +59,18 @@ const (
// Enables usage of any object for volume data source in PVCs
AnyVolumeDataSource featuregate.Feature = "AnyVolumeDataSource"
// owner: @nabokihms
// alpha: v1.26
// beta: v1.27
// GA: v1.28
//
// Enables API to get self subject attributes after authentication.
APISelfSubjectReview featuregate.Feature = "APISelfSubjectReview"
// owner: @tallclair
// beta: v1.4
AppArmor featuregate.Feature = "AppArmor"
// owner: @tallclair
// beta: v1.30
AppArmorFields featuregate.Feature = "AppArmorFields"
// owner: @danwinship
// alpha: v1.27
// beta: v1.29
// GA: v1.30
//
// Enables dual-stack --node-ip in kubelet with external cloud providers
CloudDualStackNodeIPs featuregate.Feature = "CloudDualStackNodeIPs"
@ -137,14 +135,6 @@ const (
// Allow the usage of options to fine-tune the cpumanager policies.
CPUManagerPolicyOptions featuregate.Feature = "CPUManagerPolicyOptions"
// owner: @andyzhangx
// alpha: v1.15
// beta: v1.21
// GA: v1.26
//
// Enables the Azure File in-tree driver to Azure File Driver migration feature.
CSIMigrationAzureFile featuregate.Feature = "CSIMigrationAzureFile"
// owner: @mfordjody
// alpha: v1.26
//
@ -179,14 +169,6 @@ const (
// Enables kubelet to detect CSI volume condition and send the event of the abnormal volume to the corresponding pod that is using it.
CSIVolumeHealth featuregate.Feature = "CSIVolumeHealth"
// owner: @seans3
// kep: http://kep.k8s.io/4006
// alpha: v1.29
//
// Enables StreamTranslator proxy to handle WebSockets upgrade requests for the
// version of the RemoteCommand subprotocol that supports the "close" signal.
TranslateStreamCloseWebsocketRequests featuregate.Feature = "TranslateStreamCloseWebsocketRequests"
// owner: @nckturner
// kep: http://kep.k8s.io/2699
// alpha: v1.27
@ -196,6 +178,7 @@ const (
// owner: @adrianreber
// kep: https://kep.k8s.io/2008
// alpha: v1.25
// beta: v1.30
//
// Enables container Checkpoint support in the kubelet
ContainerCheckpoint featuregate.Feature = "ContainerCheckpoint"
@ -272,21 +255,11 @@ const (
// Lock to default and remove after v1.22 based on user feedback that should be reflected in KEP #1972 update
ExecProbeTimeout featuregate.Feature = "ExecProbeTimeout"
// owner: @gjkim42
// kep: https://kep.k8s.io/2595
// alpha: v1.22
// beta: v1.26
// GA: v1.28
//
// Enables apiserver and kubelet to allow up to 32 DNSSearchPaths and up to 2048 DNSSearchListChars.
ExpandedDNSConfig featuregate.Feature = "ExpandedDNSConfig"
// owner: @pweil-
// alpha: v1.5
// deprecated: v1.28
//
// This flag used to be needed for dockershim CRI and currently does nothing.
ExperimentalHostUserNamespaceDefaultingGate featuregate.Feature = "ExperimentalHostUserNamespaceDefaulting"
// owner: @jpbetz
// alpha: v1.30
// Resource create requests using generateName are retried automatically by the apiserver
// if the generated name conflicts with an existing resource name, up to a maximum number of 7 retries.
RetryGenerateName featuregate.Feature = "RetryGenerateName"
// owner: @bobbypage
// alpha: v1.20
@ -304,6 +277,7 @@ const (
// kep: https://kep.k8s.io/1610
// alpha: v1.20
// beta: v1.27
// GA: v1.30
//
// Add support for the HPA to scale based on metrics from individual containers
// in target pods
@ -372,15 +346,6 @@ const (
// Disables the vSphere in-tree driver.
InTreePluginvSphereUnregister featuregate.Feature = "InTreePluginvSphereUnregister"
// owner: @danwinship
// kep: https://kep.k8s.io/3178
// alpha: v1.25
// beta: v1.27
// stable: v1.28
//
// Causes kubelet to no longer create legacy IPTables rules
IPTablesOwnershipCleanup featuregate.Feature = "IPTablesOwnershipCleanup"
// owner: @mimowo
// kep: https://kep.k8s.io/3850
// alpha: v1.28
@ -389,6 +354,13 @@ const (
// Allows users to specify counting of failed pods per index.
JobBackoffLimitPerIndex featuregate.Feature = "JobBackoffLimitPerIndex"
// owner: @mimowo
// kep: https://kep.k8s.io/4368
// alpha: v1.30
//
// Allows to delegate reconciliation of a Job object to an external controller.
JobManagedBy featuregate.Feature = "JobManagedBy"
// owner: @mimowo
// kep: https://kep.k8s.io/3329
// alpha: v1.25
@ -406,6 +378,15 @@ const (
// Allow users to specify recreating pods of a job only when
// pods have fully terminated.
JobPodReplacementPolicy featuregate.Feature = "JobPodReplacementPolicy"
// owner: @tenzen-y
// kep: https://kep.k8s.io/3998
// alpha: v1.30
//
// Allow users to specify when a Job can be declared as succeeded
// based on the set of succeeded pods.
JobSuccessPolicy featuregate.Feature = "JobSuccessPolicy"
// owner: @alculquicondor
// alpha: v1.23
// beta: v1.24
@ -432,14 +413,6 @@ const (
// All the node components such as CRI need to be running in the same user namespace.
KubeletInUserNamespace featuregate.Feature = "KubeletInUserNamespace"
// owner: @dashpole, @ffromani (only for GA graduation)
// alpha: v1.13
// beta: v1.15
// GA: v1.28
//
// Enables the kubelet's pod resources grpc endpoint
KubeletPodResources featuregate.Feature = "KubeletPodResources"
// owner: @moshe010
// alpha: v1.27
//
@ -452,13 +425,6 @@ const (
// Enable POD resources API with Get method
KubeletPodResourcesGet featuregate.Feature = "KubeletPodResourcesGet"
// owner: @ffromani
// alpha: v1.21
// beta: v1.23
// GA: v1.28
// Enable POD resources API to return allocatable resources
KubeletPodResourcesGetAllocatable featuregate.Feature = "KubeletPodResourcesGetAllocatable"
// KubeletSeparateDiskGC enables Kubelet to garbage collection images/containers on different filesystems
// owner: @kannon92
// kep: https://kep.k8s.io/4191
@ -476,23 +442,17 @@ const (
// owner: @alexanderConstantinescu
// kep: http://kep.k8s.io/3836
// alpha: v1.28
// beta: v1.30
//
// Implement connection draining for terminating nodes for
// `externalTrafficPolicy: Cluster` services.
KubeProxyDrainingTerminatingNodes featuregate.Feature = "KubeProxyDrainingTerminatingNodes"
// owner: @zshihang
// kep: http://kep.k8s.io/2800
// alpha: v1.26
// beta: v1.27
//
// Enables tracking of secret-based service account tokens usage.
LegacyServiceAccountTokenTracking featuregate.Feature = "LegacyServiceAccountTokenTracking"
// owner: @yt2985
// kep: http://kep.k8s.io/2800
// kep: http://kep.k8s.io/2799
// alpha: v1.28
// beta: v1.29
// GA: v1.30
//
// Enables cleaning up of secret-based service account tokens.
LegacyServiceAccountTokenCleanUp featuregate.Feature = "LegacyServiceAccountTokenCleanUp"
@ -549,18 +509,11 @@ const (
// kep: https://kep.k8s.io/3022
// alpha: v1.24
// beta: v1.25
// GA: v1.30
//
// Enable MinDomains in Pod Topology Spread.
MinDomainsInPodTopologySpread featuregate.Feature = "MinDomainsInPodTopologySpread"
// owner: @danwinship
// kep: http://kep.k8s.io/3453
// alpha: v1.26
// beta: v1.27
//
// Enables new performance-improving code in kube-proxy iptables mode
MinimizeIPTablesRestore featuregate.Feature = "MinimizeIPTablesRestore"
// owner: @aojea
// kep: https://kep.k8s.io/1880
// alpha: v1.27
@ -572,6 +525,7 @@ const (
// kep: https://kep.k8s.io/3756
// alpha: v1.25 (as part of SELinuxMountReadWriteOncePod)
// beta: v1.27
// GA: v1.30
// Robust VolumeManager reconstruction after kubelet restart.
NewVolumeManagerReconstruction featuregate.Feature = "NewVolumeManagerReconstruction"
@ -585,6 +539,7 @@ const (
// owner: @aravindhp @LorbusChris
// kep: http://kep.k8s.io/2271
// alpha: v1.27
// beta: v1.30
//
// Enables querying logs of node services using the /logs endpoint
NodeLogQuery featuregate.Feature = "NodeLogQuery"
@ -598,11 +553,13 @@ const (
// Allow pods to failover to a different node in case of non graceful node shutdown
NodeOutOfServiceVolumeDetach featuregate.Feature = "NodeOutOfServiceVolumeDetach"
// owner: @iholder101
// owner: @iholder101 @kannon92
// kep: https://kep.k8s.io/2400
// alpha: v1.22
// beta1: v1.28. For more info, please look at the KEP: https://kep.k8s.io/2400.
//
// Permits kubelet to run with swap enabled
// beta1: v1.28 (default=false)
// beta2: v.1.30 (default=true)
// Permits kubelet to run with swap enabled.
NodeSwap featuregate.Feature = "NodeSwap"
// owner: @mortent, @atiratree, @ravig
@ -664,6 +621,7 @@ const (
// kep: http://kep.k8s.io/2681
// alpha: v1.28
// beta: v1.29
// GA: v1.30
//
// Adds pod.status.hostIPs and downward API
PodHostIPs featuregate.Feature = "PodHostIPs"
@ -671,6 +629,7 @@ const (
// owner: @AxeZhan
// kep: http://kep.k8s.io/3960
// alpha: v1.29
// beta: v1.30
//
// Enables SleepAction in container lifecycle hooks
PodLifecycleSleepAction featuregate.Feature = "PodLifecycleSleepAction"
@ -679,25 +638,24 @@ const (
// kep: https://kep.k8s.io/3521
// alpha: v1.26
// beta: v1.27
// stable: v1.30
//
// Enable users to specify when a Pod is ready for scheduling.
PodSchedulingReadiness featuregate.Feature = "PodSchedulingReadiness"
// owner: @seans3
// kep: http://kep.k8s.io/4006
// alpha: v1.30
//
// Enables PortForward to be proxied with a websocket client
PortForwardWebsockets featuregate.Feature = "PortForwardWebsockets"
// owner: @jessfraz
// alpha: v1.12
//
// Enables control over ProcMountType for containers.
ProcMountType featuregate.Feature = "ProcMountType"
// owner: @andrewsykim
// kep: https://kep.k8s.io/1669
// alpha: v1.22
// beta: v1.26
// GA: v1.28
//
// Enable kube-proxy to handle terminating ednpoints when externalTrafficPolicy=Local
ProxyTerminatingEndpoints featuregate.Feature = "ProxyTerminatingEndpoints"
// owner: @sjenning
// alpha: v1.11
//
@ -721,6 +679,13 @@ const (
// Allow users to recover from volume expansion failure
RecoverVolumeExpansionFailure featuregate.Feature = "RecoverVolumeExpansionFailure"
// owner: @HirazawaUi
// kep: https://kep.k8s.io/4369
// alpha: v1.30
//
// Allow almost all printable ASCII characters in environment variables
RelaxedEnvironmentVariableValidation featuregate.Feature = "RelaxedEnvironmentVariableValidation"
// owner: @mikedanese
// alpha: v1.7
// beta: v1.12
@ -754,14 +719,6 @@ const (
// which benefits to reduce the useless requeueing.
SchedulerQueueingHints featuregate.Feature = "SchedulerQueueingHints"
// owner: @mtardy
// alpha: v1.0
//
// Putting this admission plugin behind a feature gate is part of the
// deprecation process. For details about the removal see:
// https://github.com/kubernetes/kubernetes/issues/111516
SecurityContextDeny featuregate.Feature = "SecurityContextDeny"
// owner: @atosatto @yuanchen8911
// kep: http://kep.k8s.io/3902
// beta: v1.29
@ -772,6 +729,7 @@ const (
// owner: @munnerz
// kep: http://kep.k8s.io/4193
// alpha: v1.29
// beta: v1.30
//
// Controls whether JTIs (UUIDs) are embedded into generated service account tokens, and whether these JTIs are
// recorded into the audit log for future requests made by these tokens.
@ -787,6 +745,7 @@ const (
// owner: @munnerz
// kep: http://kep.k8s.io/4193
// alpha: v1.29
// beta: v1.30
//
// Controls whether the apiserver will validate Node claims in service account tokens.
ServiceAccountTokenNodeBindingValidation featuregate.Feature = "ServiceAccountTokenNodeBindingValidation"
@ -794,6 +753,7 @@ const (
// owner: @munnerz
// kep: http://kep.k8s.io/4193
// alpha: v1.29
// beta: v1.30
//
// Controls whether the apiserver embeds the node name and uid for the associated node when issuing
// service account tokens bound to Pod objects.
@ -808,9 +768,17 @@ const (
// Subdivide the NodePort range for dynamic and static port allocation.
ServiceNodePortStaticSubrange featuregate.Feature = "ServiceNodePortStaticSubrange"
// owner: @gauravkghildiyal @robscott
// kep: https://kep.k8s.io/4444
// alpha: v1.30
//
// Enables trafficDistribution field on Services.
ServiceTrafficDistribution featuregate.Feature = "ServiceTrafficDistribution"
// owner: @gjkim42 @SergeyKanzhelev @matthyx @tzneal
// kep: http://kep.k8s.io/753
// alpha: v1.28
// beta: v1.29
//
// Introduces sidecar containers, a new type of init container that starts
// before other containers but remains running for the full duration of the
@ -827,6 +795,7 @@ const (
// owner: @alexanderConstantinescu
// kep: http://kep.k8s.io/3458
// beta: v1.27
// GA: v1.30
//
// Enables less load balancer re-configurations by the service controller
// (KCCM) as an effect of changing node state.
@ -846,6 +815,13 @@ const (
// Enables a StatefulSet to start from an arbitrary non zero ordinal
StatefulSetStartOrdinal featuregate.Feature = "StatefulSetStartOrdinal"
// owner: @nilekhc
// kep: https://kep.k8s.io/4192
// alpha: v1.30
// Enables support for the StorageVersionMigrator controller.
StorageVersionMigrator featuregate.Feature = "StorageVersionMigrator"
// owner: @robscott
// kep: https://kep.k8s.io/2433
// alpha: v1.21
@ -882,6 +858,14 @@ const (
// Allow the usage of options to fine-tune the topology manager policies.
TopologyManagerPolicyOptions featuregate.Feature = "TopologyManagerPolicyOptions"
// owner: @seans3
// kep: http://kep.k8s.io/4006
// beta: v1.30
//
// Enables StreamTranslator proxy to handle WebSockets upgrade requests for the
// version of the RemoteCommand subprotocol that supports the "close" signal.
TranslateStreamCloseWebsocketRequests featuregate.Feature = "TranslateStreamCloseWebsocketRequests"
// owner: @richabanker
// alpha: v1.28
//
@ -891,6 +875,7 @@ const (
// owner: @rata, @giuseppe
// kep: https://kep.k8s.io/127
// alpha: v1.25
// beta: v1.30
//
// Enables user namespace support for stateless pods.
UserNamespacesSupport featuregate.Feature = "UserNamespacesSupport"
@ -951,15 +936,17 @@ const (
// Enables In-Place Pod Vertical Scaling
InPlacePodVerticalScaling featuregate.Feature = "InPlacePodVerticalScaling"
// owner: @Sh4d1,@RyanAoh
// owner: @Sh4d1,@RyanAoh,@rikatz
// kep: http://kep.k8s.io/1860
// alpha: v1.29
// beta: v1.30
// LoadBalancerIPMode enables the IPMode field in the LoadBalancerIngress status of a Service
LoadBalancerIPMode featuregate.Feature = "LoadBalancerIPMode"
// owner: @haircommander
// kep: http://kep.k8s.io/4210
// alpha: v1.29
// beta: v1.30
// ImageMaximumGCAge enables the Kubelet configuration field of the same name, allowing an admin
// to specify the age after which an image will be garbage collected.
ImageMaximumGCAge featuregate.Feature = "ImageMaximumGCAge"
@ -975,10 +962,39 @@ const (
// will not graduate or be enabled by default in future Kubernetes
// releases.
UserNamespacesPodSecurityStandards featuregate.Feature = "UserNamespacesPodSecurityStandards"
// owner: @ahutsunshine
// beta: v1.30
//
// Allows namespace indexer for namespace scope resources in apiserver cache to accelerate list operations.
StorageNamespaceIndex featuregate.Feature = "StorageNamespaceIndex"
// owner: @jsafrane
// kep: https://kep.k8s.io/1710
// alpha: v1.30
// Speed up container startup by mounting volumes with the correct SELinux label
// instead of changing each file on the volumes recursively.
SELinuxMount featuregate.Feature = "SELinuxMount"
// owner: @AkihiroSuda
// kep: https://kep.k8s.io/3857
// alpha: v1.30
//
// Allows recursive read-only mounts.
RecursiveReadOnlyMounts featuregate.Feature = "RecursiveReadOnlyMounts"
)
func init() {
runtime.Must(utilfeature.DefaultMutableFeatureGate.Add(defaultKubernetesFeatureGates))
// Register all client-go features with kube's feature gate instance and make all client-go
// feature checks use kube's instance. The effect is that for kube binaries, client-go
// features are wired to the existing --feature-gates flag just as all other features
// are. Further, client-go features automatically support the existing mechanisms for
// feature enablement metrics and test overrides.
ca := &clientAdapter{utilfeature.DefaultMutableFeatureGate}
runtime.Must(clientfeatures.AddFeaturesToExistingFeatureGates(ca))
clientfeatures.ReplaceFeatureGates(ca)
}
// defaultKubernetesFeatureGates consists of all known Kubernetes-specific feature keys.
@ -994,11 +1010,11 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
AnyVolumeDataSource: {Default: true, PreRelease: featuregate.Beta}, // on by default in 1.24
APISelfSubjectReview: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // GA in 1.28; remove in 1.30
AppArmor: {Default: true, PreRelease: featuregate.Beta},
CloudDualStackNodeIPs: {Default: true, PreRelease: featuregate.Beta},
AppArmorFields: {Default: true, PreRelease: featuregate.Beta},
CloudDualStackNodeIPs: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.32
ClusterTrustBundle: {Default: false, PreRelease: featuregate.Alpha},
@ -1014,8 +1030,6 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
CPUManagerPolicyOptions: {Default: true, PreRelease: featuregate.Beta},
CSIMigrationAzureFile: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.28
CSIMigrationPortworx: {Default: false, PreRelease: featuregate.Beta}, // Off by default (requires Portworx CSI driver)
CSIMigrationRBD: {Default: false, PreRelease: featuregate.Deprecated}, // deprecated in 1.28, remove in 1.31
@ -1026,13 +1040,11 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
SkipReadOnlyValidationGCE: {Default: true, PreRelease: featuregate.Deprecated}, // remove in 1.31
TranslateStreamCloseWebsocketRequests: {Default: false, PreRelease: featuregate.Alpha},
CloudControllerManagerWebhook: {Default: false, PreRelease: featuregate.Alpha},
ContainerCheckpoint: {Default: false, PreRelease: featuregate.Alpha},
ContainerCheckpoint: {Default: true, PreRelease: featuregate.Beta},
ConsistentHTTPGetHandlers: {Default: true, PreRelease: featuregate.GA},
ConsistentHTTPGetHandlers: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.31
CronJobsScheduledAnnotation: {Default: true, PreRelease: featuregate.Beta},
@ -1052,18 +1064,18 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
ExecProbeTimeout: {Default: true, PreRelease: featuregate.GA}, // lock to default and remove after v1.22 based on KEP #1972 update
ExpandedDNSConfig: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.30
ExperimentalHostUserNamespaceDefaultingGate: {Default: false, PreRelease: featuregate.Deprecated, LockToDefault: true}, // remove in 1.30
RetryGenerateName: {Default: false, PreRelease: featuregate.Alpha},
GracefulNodeShutdown: {Default: true, PreRelease: featuregate.Beta},
GracefulNodeShutdownBasedOnPodPriority: {Default: true, PreRelease: featuregate.Beta},
HPAContainerMetrics: {Default: true, PreRelease: featuregate.Beta},
HPAContainerMetrics: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.32
HonorPVReclaimPolicy: {Default: false, PreRelease: featuregate.Alpha},
ImageMaximumGCAge: {Default: true, PreRelease: featuregate.Beta},
InTreePluginAWSUnregister: {Default: false, PreRelease: featuregate.Alpha},
InTreePluginAzureDiskUnregister: {Default: false, PreRelease: featuregate.Alpha},
@ -1080,37 +1092,33 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
InTreePluginvSphereUnregister: {Default: false, PreRelease: featuregate.Alpha},
IPTablesOwnershipCleanup: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.30
JobBackoffLimitPerIndex: {Default: true, PreRelease: featuregate.Beta},
JobManagedBy: {Default: false, PreRelease: featuregate.Alpha},
JobPodFailurePolicy: {Default: true, PreRelease: featuregate.Beta},
JobPodReplacementPolicy: {Default: true, PreRelease: featuregate.Beta},
JobSuccessPolicy: {Default: false, PreRelease: featuregate.Alpha},
JobReadyPods: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.31
KubeletCgroupDriverFromCRI: {Default: false, PreRelease: featuregate.Alpha},
KubeletInUserNamespace: {Default: false, PreRelease: featuregate.Alpha},
KubeletPodResources: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // GA in 1.28, remove in 1.30
KubeletPodResourcesDynamicResources: {Default: false, PreRelease: featuregate.Alpha},
KubeletPodResourcesGet: {Default: false, PreRelease: featuregate.Alpha},
KubeletPodResourcesGetAllocatable: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // GA in 1.28, remove in 1.30
KubeletSeparateDiskGC: {Default: false, PreRelease: featuregate.Alpha},
KubeletTracing: {Default: true, PreRelease: featuregate.Beta},
KubeProxyDrainingTerminatingNodes: {Default: false, PreRelease: featuregate.Alpha},
KubeProxyDrainingTerminatingNodes: {Default: true, PreRelease: featuregate.Beta},
LegacyServiceAccountTokenTracking: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.30
LegacyServiceAccountTokenCleanUp: {Default: true, PreRelease: featuregate.Beta},
LegacyServiceAccountTokenCleanUp: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // GA in 1.30; remove in 1.32
LocalStorageCapacityIsolationFSQuotaMonitoring: {Default: false, PreRelease: featuregate.Alpha},
@ -1126,21 +1134,19 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
MemoryQoS: {Default: false, PreRelease: featuregate.Alpha},
MinDomainsInPodTopologySpread: {Default: true, PreRelease: featuregate.Beta},
MinimizeIPTablesRestore: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.30
MinDomainsInPodTopologySpread: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.32
MultiCIDRServiceAllocator: {Default: false, PreRelease: featuregate.Alpha},
NewVolumeManagerReconstruction: {Default: true, PreRelease: featuregate.Beta},
NewVolumeManagerReconstruction: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.32
NFTablesProxyMode: {Default: false, PreRelease: featuregate.Alpha},
NodeLogQuery: {Default: false, PreRelease: featuregate.Alpha},
NodeLogQuery: {Default: false, PreRelease: featuregate.Beta},
NodeOutOfServiceVolumeDetach: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.31
NodeSwap: {Default: false, PreRelease: featuregate.Beta},
NodeSwap: {Default: true, PreRelease: featuregate.Beta},
PDBUnhealthyPodEvictionPolicy: {Default: true, PreRelease: featuregate.Beta},
@ -1154,22 +1160,24 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
PodReadyToStartContainersCondition: {Default: true, PreRelease: featuregate.Beta},
PodHostIPs: {Default: true, PreRelease: featuregate.Beta},
PodHostIPs: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.32
PodLifecycleSleepAction: {Default: false, PreRelease: featuregate.Alpha},
PodLifecycleSleepAction: {Default: true, PreRelease: featuregate.Beta},
PodSchedulingReadiness: {Default: true, PreRelease: featuregate.Beta},
PodSchedulingReadiness: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // GA in 1.30; remove in 1.32
PortForwardWebsockets: {Default: false, PreRelease: featuregate.Alpha},
ProcMountType: {Default: false, PreRelease: featuregate.Alpha},
ProxyTerminatingEndpoints: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.30
QOSReserved: {Default: false, PreRelease: featuregate.Alpha},
ReadWriteOncePod: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.31
RecoverVolumeExpansionFailure: {Default: false, PreRelease: featuregate.Alpha},
RelaxedEnvironmentVariableValidation: {Default: false, PreRelease: featuregate.Alpha},
RotateKubeletServerCertificate: {Default: true, PreRelease: featuregate.Beta},
RuntimeClassInImageCriAPI: {Default: false, PreRelease: featuregate.Alpha},
@ -1178,30 +1186,32 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
SchedulerQueueingHints: {Default: false, PreRelease: featuregate.Beta},
SecurityContextDeny: {Default: false, PreRelease: featuregate.Alpha},
SeparateTaintEvictionController: {Default: true, PreRelease: featuregate.Beta},
ServiceAccountTokenJTI: {Default: false, PreRelease: featuregate.Alpha},
ServiceAccountTokenJTI: {Default: true, PreRelease: featuregate.Beta},
ServiceAccountTokenPodNodeInfo: {Default: false, PreRelease: featuregate.Alpha},
ServiceAccountTokenPodNodeInfo: {Default: true, PreRelease: featuregate.Beta},
ServiceAccountTokenNodeBinding: {Default: false, PreRelease: featuregate.Alpha},
ServiceAccountTokenNodeBindingValidation: {Default: false, PreRelease: featuregate.Alpha},
ServiceAccountTokenNodeBindingValidation: {Default: true, PreRelease: featuregate.Beta},
ServiceNodePortStaticSubrange: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // GA in 1.29; remove in 1.31
ServiceTrafficDistribution: {Default: false, PreRelease: featuregate.Alpha},
SidecarContainers: {Default: true, PreRelease: featuregate.Beta},
SizeMemoryBackedVolumes: {Default: true, PreRelease: featuregate.Beta},
StableLoadBalancerNodeSet: {Default: true, PreRelease: featuregate.Beta},
StableLoadBalancerNodeSet: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // GA in 1.30, remove in 1.31
StatefulSetAutoDeletePVC: {Default: true, PreRelease: featuregate.Beta},
StatefulSetStartOrdinal: {Default: true, PreRelease: featuregate.Beta},
StorageVersionMigrator: {Default: false, PreRelease: featuregate.Alpha},
TopologyAwareHints: {Default: true, PreRelease: featuregate.Beta},
TopologyManagerPolicyAlphaOptions: {Default: false, PreRelease: featuregate.Alpha},
@ -1210,13 +1220,15 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
TopologyManagerPolicyOptions: {Default: true, PreRelease: featuregate.Beta},
TranslateStreamCloseWebsocketRequests: {Default: true, PreRelease: featuregate.Beta},
UnknownVersionInteroperabilityProxy: {Default: false, PreRelease: featuregate.Alpha},
VolumeAttributesClass: {Default: false, PreRelease: featuregate.Alpha},
VolumeCapacityPriority: {Default: false, PreRelease: featuregate.Alpha},
UserNamespacesSupport: {Default: false, PreRelease: featuregate.Alpha},
UserNamespacesSupport: {Default: false, PreRelease: featuregate.Beta},
WinDSR: {Default: false, PreRelease: featuregate.Alpha},
@ -1232,18 +1244,18 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
PodIndexLabel: {Default: true, PreRelease: featuregate.Beta},
LoadBalancerIPMode: {Default: false, PreRelease: featuregate.Alpha},
ImageMaximumGCAge: {Default: false, PreRelease: featuregate.Alpha},
LoadBalancerIPMode: {Default: true, PreRelease: featuregate.Beta},
UserNamespacesPodSecurityStandards: {Default: false, PreRelease: featuregate.Alpha},
SELinuxMount: {Default: false, PreRelease: featuregate.Alpha},
// inherited features from generic apiserver, relisted here to get a conflict if it is changed
// unintentionally on either side:
genericfeatures.AdmissionWebhookMatchConditions: {Default: true, PreRelease: featuregate.Beta},
genericfeatures.AdmissionWebhookMatchConditions: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.33
genericfeatures.AggregatedDiscoveryEndpoint: {Default: true, PreRelease: featuregate.Beta},
genericfeatures.AggregatedDiscoveryEndpoint: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.33
genericfeatures.APIListChunking: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.32
@ -1251,36 +1263,68 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
genericfeatures.APIResponseCompression: {Default: true, PreRelease: featuregate.Beta},
genericfeatures.APIServerIdentity: {Default: true, PreRelease: featuregate.Beta},
genericfeatures.APIServerTracing: {Default: true, PreRelease: featuregate.Beta},
genericfeatures.APIServingWithRoutine: {Default: true, PreRelease: featuregate.Beta},
genericfeatures.ConsistentListFromCache: {Default: false, PreRelease: featuregate.Alpha},
genericfeatures.CustomResourceValidationExpressions: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.31
genericfeatures.EfficientWatchResumption: {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
genericfeatures.KMSv1: {Default: false, PreRelease: featuregate.Deprecated},
genericfeatures.KMSv2: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.31
genericfeatures.KMSv2KDF: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.31
genericfeatures.ValidatingAdmissionPolicy: {Default: false, PreRelease: featuregate.Beta},
genericfeatures.CustomResourceValidationExpressions: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.31
genericfeatures.MutatingAdmissionPolicy: {Default: false, PreRelease: featuregate.Alpha},
genericfeatures.OpenAPIEnums: {Default: true, PreRelease: featuregate.Beta},
genericfeatures.RemainingItemCount: {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
genericfeatures.SeparateCacheWatchRPC: {Default: true, PreRelease: featuregate.Beta},
genericfeatures.ServerSideApply: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.29
genericfeatures.ServerSideFieldValidation: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.29
genericfeatures.StructuredAuthorizationConfiguration: {Default: false, PreRelease: featuregate.Alpha},
genericfeatures.StorageVersionAPI: {Default: false, PreRelease: featuregate.Alpha},
genericfeatures.StorageVersionHash: {Default: true, PreRelease: featuregate.Beta},
genericfeatures.StructuredAuthenticationConfiguration: {Default: true, PreRelease: featuregate.Beta},
genericfeatures.StructuredAuthorizationConfiguration: {Default: true, PreRelease: featuregate.Beta},
genericfeatures.UnauthenticatedHTTP2DOSMitigation: {Default: true, PreRelease: featuregate.Beta},
genericfeatures.ZeroLimitedNominalConcurrencyShares: {Default: false, PreRelease: featuregate.Beta},
genericfeatures.ValidatingAdmissionPolicy: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.32
genericfeatures.WatchBookmark: {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
genericfeatures.WatchFromStorageWithoutResourceVersion: {Default: false, PreRelease: featuregate.Beta},
genericfeatures.WatchList: {Default: false, PreRelease: featuregate.Alpha},
genericfeatures.ZeroLimitedNominalConcurrencyShares: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.32
// inherited features from apiextensions-apiserver, relisted here to get a conflict if it is changed
// unintentionally on either side:
apiextensionsfeatures.CRDValidationRatcheting: {Default: false, PreRelease: featuregate.Alpha},
apiextensionsfeatures.CRDValidationRatcheting: {Default: true, PreRelease: featuregate.Beta},
apiextensionsfeatures.CustomResourceFieldSelectors: {Default: false, PreRelease: featuregate.Alpha},
// features that enable backwards compatibility but are scheduled to be removed
// ...
HPAScaleToZero: {Default: false, PreRelease: featuregate.Alpha},
StorageNamespaceIndex: {Default: true, PreRelease: featuregate.Beta},
RecursiveReadOnlyMounts: {Default: false, PreRelease: featuregate.Alpha},
}

27
vendor/k8s.io/kubernetes/pkg/util/filesystem/util.go generated vendored Normal file
View File

@ -0,0 +1,27 @@
/*
Copyright 2024 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package filesystem
import (
"path/filepath"
)
// IsPathClean will replace slashes to Separator (which is OS-specific).
// This will make sure that all slashes are the same before comparing.
func IsPathClean(path string) bool {
return filepath.ToSlash(filepath.Clean(path)) == filepath.ToSlash(path)
}

View File

@ -22,6 +22,7 @@ package filesystem
import (
"fmt"
"os"
"path/filepath"
)
// IsUnixDomainSocket returns whether a given file is a AF_UNIX socket file
@ -35,3 +36,8 @@ func IsUnixDomainSocket(filePath string) (bool, error) {
}
return true, nil
}
// IsAbs is same as filepath.IsAbs on Unix.
func IsAbs(path string) bool {
return filepath.IsAbs(path)
}

View File

@ -23,6 +23,8 @@ import (
"fmt"
"net"
"os"
"path/filepath"
"strings"
"time"
"k8s.io/apimachinery/pkg/util/wait"
@ -85,3 +87,13 @@ func IsUnixDomainSocket(filePath string) (bool, error) {
}
return true, nil
}
// IsAbs returns whether the given path is absolute or not.
// On Windows, filepath.IsAbs will not return True for paths prefixed with a slash, even
// though they can be used as absolute paths (https://docs.microsoft.com/en-us/dotnet/standard/io/file-path-formats).
//
// WARN: It isn't safe to use this for API values which will propagate across systems (e.g. REST API values
// that get validated on Unix, persisted, then consumed by Windows, etc).
func IsAbs(path string) bool {
return filepath.IsAbs(path) || strings.HasPrefix(path, `\`) || strings.HasPrefix(path, `/`)
}

View File

@ -17,6 +17,10 @@ limitations under the License.
package filesystem
import (
"context"
"fmt"
"time"
"github.com/fsnotify/fsnotify"
)
@ -87,3 +91,126 @@ func (w *fsnotifyWatcher) Run() {
}
}()
}
type watchAddRemover interface {
Add(path string) error
Remove(path string) error
}
type noopWatcher struct{}
func (noopWatcher) Add(path string) error { return nil }
func (noopWatcher) Remove(path string) error { return nil }
// WatchUntil watches the specified path for changes and blocks until ctx is canceled.
// eventHandler() must be non-nil, and pollInterval must be greater than 0.
// eventHandler() is invoked whenever a change event is observed or pollInterval elapses.
// errorHandler() is invoked (if non-nil) whenever an error occurs initializing or watching the specified path.
//
// If path is a directory, only the directory and immediate children are watched.
//
// If path does not exist or cannot be watched, an error is passed to errorHandler() and eventHandler() is called at pollInterval.
//
// Multiple observed events may collapse to a single invocation of eventHandler().
//
// eventHandler() is invoked immediately after successful initialization of the filesystem watch,
// in case the path changed concurrent with calling WatchUntil().
func WatchUntil(ctx context.Context, pollInterval time.Duration, path string, eventHandler func(), errorHandler func(err error)) {
if pollInterval <= 0 {
panic(fmt.Errorf("pollInterval must be > 0"))
}
if eventHandler == nil {
panic(fmt.Errorf("eventHandler must be non-nil"))
}
if errorHandler == nil {
errorHandler = func(err error) {}
}
// Initialize watcher, fall back to no-op
var (
eventsCh chan fsnotify.Event
errorCh chan error
watcher watchAddRemover
)
if w, err := fsnotify.NewWatcher(); err != nil {
errorHandler(fmt.Errorf("error creating file watcher, falling back to poll at interval %s: %w", pollInterval, err))
watcher = noopWatcher{}
} else {
watcher = w
eventsCh = w.Events
errorCh = w.Errors
defer func() {
_ = w.Close()
}()
}
// Initialize background poll
t := time.NewTicker(pollInterval)
defer t.Stop()
attemptPeriodicRewatch := false
// Start watching the path
if err := watcher.Add(path); err != nil {
errorHandler(err)
attemptPeriodicRewatch = true
} else {
// Invoke handle() at least once after successfully registering the listener,
// in case the file changed concurrent with calling WatchUntil.
eventHandler()
}
for {
select {
case <-ctx.Done():
return
case <-t.C:
// Prioritize exiting if context is canceled
if ctx.Err() != nil {
return
}
// Try to re-establish the watcher if we previously got a watch error
if attemptPeriodicRewatch {
_ = watcher.Remove(path)
if err := watcher.Add(path); err != nil {
errorHandler(err)
} else {
attemptPeriodicRewatch = false
}
}
// Handle
eventHandler()
case e := <-eventsCh:
// Prioritize exiting if context is canceled
if ctx.Err() != nil {
return
}
// Try to re-establish the watcher for events which dropped the existing watch
if e.Name == path && (e.Has(fsnotify.Remove) || e.Has(fsnotify.Rename)) {
_ = watcher.Remove(path)
if err := watcher.Add(path); err != nil {
errorHandler(err)
attemptPeriodicRewatch = true
}
}
// Handle
eventHandler()
case err := <-errorCh:
// Prioritize exiting if context is canceled
if ctx.Err() != nil {
return
}
// If the error occurs in response to calling watcher.Add, re-adding here could hot-loop.
// The periodic poll will attempt to re-establish the watch.
errorHandler(err)
attemptPeriodicRewatch = true
}
}
}

View File

@ -1064,7 +1064,7 @@ func NewPersistentVolumeRecyclerPodTemplate() *v1.Pod {
Containers: []v1.Container{
{
Name: "pv-recycler",
Image: "registry.k8s.io/build-image/debian-base:bookworm-v1.0.1",
Image: "registry.k8s.io/build-image/debian-base:bookworm-v1.0.2",
Command: []string{"/bin/sh"},
Args: []string{"-c", "test -e /scrub && find /scrub -mindepth 1 -delete && test -z \"$(ls -A /scrub)\" || exit 1"},
VolumeMounts: []v1.VolumeMount{

View File

@ -101,9 +101,9 @@ const (
// portion of the payload was deleted and is still present on disk.
//
// 4. The data in the current timestamped directory is compared to the projected
// data to determine if an update is required.
// data to determine if an update to data directory is required.
//
// 5. A new timestamped dir is created.
// 5. A new timestamped dir is created if an update is required.
//
// 6. The payload is written to the new timestamped directory.
//
@ -159,6 +159,7 @@ func (w *AtomicWriter) Write(payload map[string]FileProjection, setPerms func(su
oldTsPath := filepath.Join(w.targetDir, oldTsDir)
var pathsToRemove sets.String
shouldWrite := true
// if there was no old version, there's nothing to remove
if len(oldTsDir) != 0 {
// (3)
@ -173,57 +174,74 @@ func (w *AtomicWriter) Write(payload map[string]FileProjection, setPerms func(su
klog.Errorf("%s: error determining whether payload should be written to disk: %v", w.logContext, err)
return err
} else if !should && len(pathsToRemove) == 0 {
klog.V(4).Infof("%s: no update required for target directory %v", w.logContext, w.targetDir)
return nil
klog.V(4).Infof("%s: write not required for data directory %v", w.logContext, oldTsDir)
// data directory is already up to date, but we need to make sure that
// the user-visible symlinks are created.
// See https://github.com/kubernetes/kubernetes/issues/121472 for more details.
// Reset oldTsDir to empty string to avoid removing the data directory.
shouldWrite = false
oldTsDir = ""
} else {
klog.V(4).Infof("%s: write required for target directory %v", w.logContext, w.targetDir)
}
}
// (5)
tsDir, err := w.newTimestampDir()
if err != nil {
klog.V(4).Infof("%s: error creating new ts data directory: %v", w.logContext, err)
return err
}
tsDirName := filepath.Base(tsDir)
// (6)
if err = w.writePayloadToDir(cleanPayload, tsDir); err != nil {
klog.Errorf("%s: error writing payload to ts data directory %s: %v", w.logContext, tsDir, err)
return err
}
klog.V(4).Infof("%s: performed write of new data to ts data directory: %s", w.logContext, tsDir)
// (7)
if setPerms != nil {
if err := setPerms(tsDirName); err != nil {
klog.Errorf("%s: error applying ownership settings: %v", w.logContext, err)
if shouldWrite {
// (5)
tsDir, err := w.newTimestampDir()
if err != nil {
klog.V(4).Infof("%s: error creating new ts data directory: %v", w.logContext, err)
return err
}
}
tsDirName := filepath.Base(tsDir)
// (8)
newDataDirPath := filepath.Join(w.targetDir, newDataDirName)
if err = os.Symlink(tsDirName, newDataDirPath); err != nil {
os.RemoveAll(tsDir)
klog.Errorf("%s: error creating symbolic link for atomic update: %v", w.logContext, err)
return err
}
// (6)
if err = w.writePayloadToDir(cleanPayload, tsDir); err != nil {
klog.Errorf("%s: error writing payload to ts data directory %s: %v", w.logContext, tsDir, err)
return err
}
klog.V(4).Infof("%s: performed write of new data to ts data directory: %s", w.logContext, tsDir)
// (9)
if runtime.GOOS == "windows" {
os.Remove(dataDirPath)
err = os.Symlink(tsDirName, dataDirPath)
os.Remove(newDataDirPath)
} else {
err = os.Rename(newDataDirPath, dataDirPath)
}
if err != nil {
os.Remove(newDataDirPath)
os.RemoveAll(tsDir)
klog.Errorf("%s: error renaming symbolic link for data directory %s: %v", w.logContext, newDataDirPath, err)
return err
// (7)
if setPerms != nil {
if err := setPerms(tsDirName); err != nil {
klog.Errorf("%s: error applying ownership settings: %v", w.logContext, err)
return err
}
}
// (8)
newDataDirPath := filepath.Join(w.targetDir, newDataDirName)
if err = os.Symlink(tsDirName, newDataDirPath); err != nil {
if err := os.RemoveAll(tsDir); err != nil {
klog.Errorf("%s: error removing new ts directory %s: %v", w.logContext, tsDir, err)
}
klog.Errorf("%s: error creating symbolic link for atomic update: %v", w.logContext, err)
return err
}
// (9)
if runtime.GOOS == "windows" {
if err := os.Remove(dataDirPath); err != nil {
klog.Errorf("%s: error removing data dir directory %s: %v", w.logContext, dataDirPath, err)
}
err = os.Symlink(tsDirName, dataDirPath)
if err := os.Remove(newDataDirPath); err != nil {
klog.Errorf("%s: error removing new data dir directory %s: %v", w.logContext, newDataDirPath, err)
}
} else {
err = os.Rename(newDataDirPath, dataDirPath)
}
if err != nil {
if err := os.Remove(newDataDirPath); err != nil && err != os.ErrNotExist {
klog.Errorf("%s: error removing new data dir directory %s: %v", w.logContext, newDataDirPath, err)
}
if err := os.RemoveAll(tsDir); err != nil {
klog.Errorf("%s: error removing new ts directory %s: %v", w.logContext, tsDir, err)
}
klog.Errorf("%s: error renaming symbolic link for data directory %s: %v", w.logContext, newDataDirPath, err)
return err
}
}
// (10)

View File

@ -41,6 +41,10 @@ const (
FileTypeUnknown FileType = ""
)
var (
errUnknownFileType = fmt.Errorf("only recognise file, directory, socket, block device and character device")
)
// HostUtils defines the set of methods for interacting with paths on a host.
type HostUtils interface {
// DeviceOpened determines if the device (e.g. /dev/sdc) is in use elsewhere
@ -50,6 +54,7 @@ type HostUtils interface {
PathIsDevice(pathname string) (bool, error)
// GetDeviceNameFromMount finds the device name by checking the mount path
// to get the global mount path within its plugin directory.
// TODO: Remove this method once the rbd and vsphere plugins are removed from in-tree.
GetDeviceNameFromMount(mounter mount.Interface, mountPath, pluginMountDir string) (string, error)
// MakeRShared checks that given path is on a mount with 'rshared' mount
// propagation. If not, it bind-mounts the path as rshared.
@ -108,5 +113,5 @@ func getFileType(pathname string) (FileType, error) {
return FileTypeBlockDev, nil
}
return pathType, fmt.Errorf("only recognise file, directory, socket, block device and character device")
return pathType, errUnknownFileType
}

View File

@ -109,7 +109,7 @@ func (hu *HostUtil) GetDeviceNameFromMount(mounter mount.Interface, mountPath, p
return getDeviceNameFromMount(mounter, mountPath, pluginMountDir)
}
// getDeviceNameFromMountLinux find the device name from /proc/mounts in which
// getDeviceNameFromMount find the device name from /proc/self/mountinfo in which
// the mount path reference should match the given plugin mount directory. In case no mount path reference
// matches, returns the volume name taken from its given mountPath
func getDeviceNameFromMount(mounter mount.Interface, mountPath, pluginMountDir string) (string, error) {

View File

@ -23,7 +23,6 @@ import (
"fmt"
"io/fs"
"os"
"path"
"path/filepath"
"strings"
"syscall"
@ -72,7 +71,7 @@ func getDeviceNameFromMount(mounter mount.Interface, mountPath, pluginMountDir s
}
}
return path.Base(mountPath), nil
return filepath.Base(mountPath), nil
}
// DeviceOpened determines if the device is in use elsewhere
@ -106,7 +105,7 @@ func (hu *(HostUtil)) GetFileType(pathname string) (FileType, error) {
// os.Stat will return a 1920 error (windows.ERROR_CANT_ACCESS_FILE) if we use it on a Unix Socket
// on Windows. In this case, we need to use a different method to check if it's a Unix Socket.
if isSystemCannotAccessErr(err) {
if err == errUnknownFileType || isSystemCannotAccessErr(err) {
if isSocket, errSocket := filesystem.IsUnixDomainSocket(pathname); errSocket == nil && isSocket {
return FileTypeSocket, nil
}

View File

@ -177,6 +177,10 @@ func VolumeSupportsSELinuxMount(volumeSpec *volume.Spec) bool {
if len(volumeSpec.PersistentVolume.Spec.AccessModes) != 1 {
return false
}
if utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMount) {
return true
}
// Only SELinuxMountReadWriteOncePod feature enabled
if !v1helper.ContainsAccessMode(volumeSpec.PersistentVolume.Spec.AccessModes, v1.ReadWriteOncePod) {
return false
}