mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	Sidecar: API changes
- Add SidecarContaienrs feature gate - Add ContainerRestartPolicy type - Add RestartPolicy field to the Container - Drop RestartPolicy field if the feature is disabled - Add validation for the SidecarContainers - Allow restartable init containaers to have a startup probe
This commit is contained in:
		
				
					committed by
					
						
						Sergey Kanzhelev
					
				
			
			
				
	
			
			
			
						parent
						
							c17601fa18
						
					
				
				
					commit
					5d26bcd468
				
			@@ -510,6 +510,14 @@ func dropDisabledFields(
 | 
				
			|||||||
			podSpec.EphemeralContainers[i].ResizePolicy = nil
 | 
								podSpec.EphemeralContainers[i].ResizePolicy = nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !utilfeature.DefaultFeatureGate.Enabled(features.SidecarContainers) && !restartableInitContainersInUse(oldPodSpec) {
 | 
				
			||||||
 | 
							// Drop the RestartPolicy field of init containers.
 | 
				
			||||||
 | 
							for i := range podSpec.InitContainers {
 | 
				
			||||||
 | 
								podSpec.InitContainers[i].RestartPolicy = nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// For other types of containers, validateContainers will handle them.
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// dropDisabledPodStatusFields removes disabled fields from the pod status
 | 
					// dropDisabledPodStatusFields removes disabled fields from the pod status
 | 
				
			||||||
@@ -778,6 +786,23 @@ func schedulingGatesInUse(podSpec *api.PodSpec) bool {
 | 
				
			|||||||
	return len(podSpec.SchedulingGates) != 0
 | 
						return len(podSpec.SchedulingGates) != 0
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// restartableInitContainersInUse returns true if the pod spec is non-nil and
 | 
				
			||||||
 | 
					// it has any init container with ContainerRestartPolicyAlways.
 | 
				
			||||||
 | 
					func restartableInitContainersInUse(podSpec *api.PodSpec) bool {
 | 
				
			||||||
 | 
						if podSpec == nil {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var inUse bool
 | 
				
			||||||
 | 
						VisitContainers(podSpec, InitContainers, func(c *api.Container, containerType ContainerType) bool {
 | 
				
			||||||
 | 
							if c.RestartPolicy != nil && *c.RestartPolicy == api.ContainerRestartPolicyAlways {
 | 
				
			||||||
 | 
								inUse = true
 | 
				
			||||||
 | 
								return false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						return inUse
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func hasInvalidLabelValueInAffinitySelector(spec *api.PodSpec) bool {
 | 
					func hasInvalidLabelValueInAffinitySelector(spec *api.PodSpec) bool {
 | 
				
			||||||
	if spec.Affinity != nil {
 | 
						if spec.Affinity != nil {
 | 
				
			||||||
		if spec.Affinity.PodAffinity != nil {
 | 
							if spec.Affinity.PodAffinity != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2052,6 +2052,109 @@ func TestDropInPlacePodVerticalScaling(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestDropSidecarContainers(t *testing.T) {
 | 
				
			||||||
 | 
						containerRestartPolicyAlways := api.ContainerRestartPolicyAlways
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						podWithSidecarContainers := func() *api.Pod {
 | 
				
			||||||
 | 
							return &api.Pod{
 | 
				
			||||||
 | 
								Spec: api.PodSpec{
 | 
				
			||||||
 | 
									InitContainers: []api.Container{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Name:          "c1",
 | 
				
			||||||
 | 
											Image:         "image",
 | 
				
			||||||
 | 
											RestartPolicy: &containerRestartPolicyAlways,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						podWithoutSidecarContainers := func() *api.Pod {
 | 
				
			||||||
 | 
							return &api.Pod{
 | 
				
			||||||
 | 
								Spec: api.PodSpec{
 | 
				
			||||||
 | 
									InitContainers: []api.Container{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Name:  "c1",
 | 
				
			||||||
 | 
											Image: "image",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						podInfo := []struct {
 | 
				
			||||||
 | 
							description         string
 | 
				
			||||||
 | 
							hasSidecarContainer bool
 | 
				
			||||||
 | 
							pod                 func() *api.Pod
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								description:         "has a sidecar container",
 | 
				
			||||||
 | 
								hasSidecarContainer: true,
 | 
				
			||||||
 | 
								pod:                 podWithSidecarContainers,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								description:         "does not have a sidecar container",
 | 
				
			||||||
 | 
								hasSidecarContainer: false,
 | 
				
			||||||
 | 
								pod:                 podWithoutSidecarContainers,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								description:         "is nil",
 | 
				
			||||||
 | 
								hasSidecarContainer: false,
 | 
				
			||||||
 | 
								pod:                 func() *api.Pod { return nil },
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, enabled := range []bool{true, false} {
 | 
				
			||||||
 | 
							for _, oldPodInfo := range podInfo {
 | 
				
			||||||
 | 
								for _, newPodInfo := range podInfo {
 | 
				
			||||||
 | 
									oldPodHasSidecarContainer, oldPod := oldPodInfo.hasSidecarContainer, oldPodInfo.pod()
 | 
				
			||||||
 | 
									newPodHasSidecarContainer, newPod := newPodInfo.hasSidecarContainer, newPodInfo.pod()
 | 
				
			||||||
 | 
									if newPod == nil {
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									t.Run(fmt.Sprintf("feature enabled=%v, old pod %v, new pod %v", enabled, oldPodInfo.description, newPodInfo.description), func(t *testing.T) {
 | 
				
			||||||
 | 
										defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SidecarContainers, enabled)()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										var oldPodSpec *api.PodSpec
 | 
				
			||||||
 | 
										if oldPod != nil {
 | 
				
			||||||
 | 
											oldPodSpec = &oldPod.Spec
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										dropDisabledFields(&newPod.Spec, nil, oldPodSpec, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// old pod should never be changed
 | 
				
			||||||
 | 
										if !reflect.DeepEqual(oldPod, oldPodInfo.pod()) {
 | 
				
			||||||
 | 
											t.Errorf("old pod changed: %v", cmp.Diff(oldPod, oldPodInfo.pod()))
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										switch {
 | 
				
			||||||
 | 
										case enabled || oldPodHasSidecarContainer:
 | 
				
			||||||
 | 
											// new pod shouldn't change if feature enabled or if old pod has
 | 
				
			||||||
 | 
											// any sidecar container
 | 
				
			||||||
 | 
											if !reflect.DeepEqual(newPod, newPodInfo.pod()) {
 | 
				
			||||||
 | 
												t.Errorf("new pod changed: %v", cmp.Diff(newPod, newPodInfo.pod()))
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										case newPodHasSidecarContainer:
 | 
				
			||||||
 | 
											// new pod should be changed
 | 
				
			||||||
 | 
											if reflect.DeepEqual(newPod, newPodInfo.pod()) {
 | 
				
			||||||
 | 
												t.Errorf("new pod was not changed")
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											// new pod should not have any sidecar container
 | 
				
			||||||
 | 
											if !reflect.DeepEqual(newPod, podWithoutSidecarContainers()) {
 | 
				
			||||||
 | 
												t.Errorf("new pod has a sidecar container: %v", cmp.Diff(newPod, podWithoutSidecarContainers()))
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										default:
 | 
				
			||||||
 | 
											// new pod should not need to be changed
 | 
				
			||||||
 | 
											if !reflect.DeepEqual(newPod, newPodInfo.pod()) {
 | 
				
			||||||
 | 
												t.Errorf("new pod changed: %v", cmp.Diff(newPod, newPodInfo.pod()))
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestMarkPodProposedForResize(t *testing.T) {
 | 
					func TestMarkPodProposedForResize(t *testing.T) {
 | 
				
			||||||
	testCases := []struct {
 | 
						testCases := []struct {
 | 
				
			||||||
		desc        string
 | 
							desc        string
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2279,6 +2279,24 @@ type Container struct {
 | 
				
			|||||||
	// +featureGate=InPlacePodVerticalScaling
 | 
						// +featureGate=InPlacePodVerticalScaling
 | 
				
			||||||
	// +optional
 | 
						// +optional
 | 
				
			||||||
	ResizePolicy []ContainerResizePolicy
 | 
						ResizePolicy []ContainerResizePolicy
 | 
				
			||||||
 | 
						// RestartPolicy defines the restart behavior of individual containers in a pod.
 | 
				
			||||||
 | 
						// This field may only be set for init containers, and the only allowed value is "Always".
 | 
				
			||||||
 | 
						// For non-init containers or when this field is not specified,
 | 
				
			||||||
 | 
						// the restart behavior is defined by the Pod's restart policy and the container type.
 | 
				
			||||||
 | 
						// Setting the RestartPolicy as "Always" for the init container will have the following effect:
 | 
				
			||||||
 | 
						// this init container will be continually restarted on
 | 
				
			||||||
 | 
						// exit until all regular containers have terminated. Once all regular
 | 
				
			||||||
 | 
						// containers have completed, all init containers with restartPolicy "Always"
 | 
				
			||||||
 | 
						// will be shut down. This lifecycle differs from normal init containers and
 | 
				
			||||||
 | 
						// is often referred to as a "sidecar" container. Although this init
 | 
				
			||||||
 | 
						// container still starts in the init container sequence, it does not wait
 | 
				
			||||||
 | 
						// for the container to complete before proceeding to the next init
 | 
				
			||||||
 | 
						// container. Instead, the next init container starts immediately after this
 | 
				
			||||||
 | 
						// init container is started, or after any startupProbe has successfully
 | 
				
			||||||
 | 
						// completed.
 | 
				
			||||||
 | 
						// +featureGate=SidecarContainers
 | 
				
			||||||
 | 
						// +optional
 | 
				
			||||||
 | 
						RestartPolicy *ContainerRestartPolicy
 | 
				
			||||||
	// +optional
 | 
						// +optional
 | 
				
			||||||
	VolumeMounts []VolumeMount
 | 
						VolumeMounts []VolumeMount
 | 
				
			||||||
	// volumeDevices is the list of block devices to be used by the container.
 | 
						// volumeDevices is the list of block devices to be used by the container.
 | 
				
			||||||
@@ -2597,6 +2615,14 @@ const (
 | 
				
			|||||||
	RestartPolicyNever     RestartPolicy = "Never"
 | 
						RestartPolicyNever     RestartPolicy = "Never"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ContainerRestartPolicy is the restart policy for a single container.
 | 
				
			||||||
 | 
					// This may only be set for init containers and only allowed value is "Always".
 | 
				
			||||||
 | 
					type ContainerRestartPolicy string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						ContainerRestartPolicyAlways ContainerRestartPolicy = "Always"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 | 
					// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// PodList is a list of Pods.
 | 
					// PodList is a list of Pods.
 | 
				
			||||||
@@ -3505,6 +3531,13 @@ type EphemeralContainerCommon struct {
 | 
				
			|||||||
	// +featureGate=InPlacePodVerticalScaling
 | 
						// +featureGate=InPlacePodVerticalScaling
 | 
				
			||||||
	// +optional
 | 
						// +optional
 | 
				
			||||||
	ResizePolicy []ContainerResizePolicy
 | 
						ResizePolicy []ContainerResizePolicy
 | 
				
			||||||
 | 
						// Restart policy for the container to manage the restart behavior of each
 | 
				
			||||||
 | 
						// container within a pod.
 | 
				
			||||||
 | 
						// This may only be set for init containers. You cannot set this field on
 | 
				
			||||||
 | 
						// ephemeral containers.
 | 
				
			||||||
 | 
						// +featureGate=SidecarContainers
 | 
				
			||||||
 | 
						// +optional
 | 
				
			||||||
 | 
						RestartPolicy *ContainerRestartPolicy
 | 
				
			||||||
	// Pod volumes to mount into the container's filesystem. Subpath mounts are not allowed for ephemeral containers.
 | 
						// Pod volumes to mount into the container's filesystem. Subpath mounts are not allowed for ephemeral containers.
 | 
				
			||||||
	// +optional
 | 
						// +optional
 | 
				
			||||||
	VolumeMounts []VolumeMount
 | 
						VolumeMounts []VolumeMount
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2835,6 +2835,23 @@ func validateProbe(probe *core.Probe, fldPath *field.Path) field.ErrorList {
 | 
				
			|||||||
	return allErrs
 | 
						return allErrs
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func validateInitContainerRestartPolicy(restartPolicy *core.ContainerRestartPolicy, fldPath *field.Path) field.ErrorList {
 | 
				
			||||||
 | 
						var allErrors field.ErrorList
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if restartPolicy == nil {
 | 
				
			||||||
 | 
							return allErrors
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						switch *restartPolicy {
 | 
				
			||||||
 | 
						case core.ContainerRestartPolicyAlways:
 | 
				
			||||||
 | 
							break
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							validValues := []string{string(core.ContainerRestartPolicyAlways)}
 | 
				
			||||||
 | 
							allErrors = append(allErrors, field.NotSupported(fldPath, *restartPolicy, validValues))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return allErrors
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type commonHandler struct {
 | 
					type commonHandler struct {
 | 
				
			||||||
	Exec      *core.ExecAction
 | 
						Exec      *core.ExecAction
 | 
				
			||||||
	HTTPGet   *core.HTTPGetAction
 | 
						HTTPGet   *core.HTTPGetAction
 | 
				
			||||||
@@ -3165,6 +3182,13 @@ func validateInitContainers(containers []core.Container, regularContainers []cor
 | 
				
			|||||||
		// Apply the validation common to all container types
 | 
							// Apply the validation common to all container types
 | 
				
			||||||
		allErrs = append(allErrs, validateContainerCommon(&ctr, volumes, podClaimNames, idxPath, opts)...)
 | 
							allErrs = append(allErrs, validateContainerCommon(&ctr, volumes, podClaimNames, idxPath, opts)...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							restartAlways := false
 | 
				
			||||||
 | 
							// Apply the validation specific to init containers
 | 
				
			||||||
 | 
							if ctr.RestartPolicy != nil {
 | 
				
			||||||
 | 
								allErrs = append(allErrs, validateInitContainerRestartPolicy(ctr.RestartPolicy, idxPath.Child("restartPolicy"))...)
 | 
				
			||||||
 | 
								restartAlways = *ctr.RestartPolicy == core.ContainerRestartPolicyAlways
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Names must be unique within regular and init containers. Collisions with ephemeral containers
 | 
							// Names must be unique within regular and init containers. Collisions with ephemeral containers
 | 
				
			||||||
		// will be detected by validateEphemeralContainers().
 | 
							// will be detected by validateEphemeralContainers().
 | 
				
			||||||
		if allNames.Has(ctr.Name) {
 | 
							if allNames.Has(ctr.Name) {
 | 
				
			||||||
@@ -3176,19 +3200,41 @@ func validateInitContainers(containers []core.Container, regularContainers []cor
 | 
				
			|||||||
		// Check for port conflicts in init containers individually since init containers run one-by-one.
 | 
							// Check for port conflicts in init containers individually since init containers run one-by-one.
 | 
				
			||||||
		allErrs = append(allErrs, checkHostPortConflicts([]core.Container{ctr}, fldPath)...)
 | 
							allErrs = append(allErrs, checkHostPortConflicts([]core.Container{ctr}, fldPath)...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// These fields are disallowed for init containers.
 | 
							switch {
 | 
				
			||||||
		if ctr.Lifecycle != nil {
 | 
							case restartAlways:
 | 
				
			||||||
			allErrs = append(allErrs, field.Forbidden(idxPath.Child("lifecycle"), "may not be set for init containers"))
 | 
								// TODO: Allow restartable init containers to have a lifecycle hook.
 | 
				
			||||||
		}
 | 
								if ctr.Lifecycle != nil {
 | 
				
			||||||
		if ctr.LivenessProbe != nil {
 | 
									allErrs = append(allErrs, field.Forbidden(idxPath.Child("lifecycle"), "may not be set for init containers"))
 | 
				
			||||||
			allErrs = append(allErrs, field.Forbidden(idxPath.Child("livenessProbe"), "may not be set for init containers"))
 | 
								}
 | 
				
			||||||
		}
 | 
								// TODO: Allow restartable init containers to have a liveness probe.
 | 
				
			||||||
		if ctr.ReadinessProbe != nil {
 | 
								if ctr.LivenessProbe != nil {
 | 
				
			||||||
			allErrs = append(allErrs, field.Forbidden(idxPath.Child("readinessProbe"), "may not be set for init containers"))
 | 
									allErrs = append(allErrs, field.Forbidden(idxPath.Child("livenessProbe"), "may not be set for init containers"))
 | 
				
			||||||
		}
 | 
								}
 | 
				
			||||||
		if ctr.StartupProbe != nil {
 | 
								// TODO: Allow restartable init containers to have a readiness probe.
 | 
				
			||||||
			allErrs = append(allErrs, field.Forbidden(idxPath.Child("startupProbe"), "may not be set for init containers"))
 | 
								if ctr.ReadinessProbe != nil {
 | 
				
			||||||
 | 
									allErrs = append(allErrs, field.Forbidden(idxPath.Child("readinessProbe"), "may not be set for init containers"))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								allErrs = append(allErrs, validateProbe(ctr.StartupProbe, idxPath.Child("startupProbe"))...)
 | 
				
			||||||
 | 
								if ctr.StartupProbe != nil && ctr.StartupProbe.SuccessThreshold != 1 {
 | 
				
			||||||
 | 
									allErrs = append(allErrs, field.Invalid(idxPath.Child("startupProbe", "successThreshold"), ctr.StartupProbe.SuccessThreshold, "must be 1"))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								// These fields are disallowed for init containers.
 | 
				
			||||||
 | 
								if ctr.Lifecycle != nil {
 | 
				
			||||||
 | 
									allErrs = append(allErrs, field.Forbidden(idxPath.Child("lifecycle"), "may not be set for init containers"))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if ctr.LivenessProbe != nil {
 | 
				
			||||||
 | 
									allErrs = append(allErrs, field.Forbidden(idxPath.Child("livenessProbe"), "may not be set for init containers"))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if ctr.ReadinessProbe != nil {
 | 
				
			||||||
 | 
									allErrs = append(allErrs, field.Forbidden(idxPath.Child("readinessProbe"), "may not be set for init containers"))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if ctr.StartupProbe != nil {
 | 
				
			||||||
 | 
									allErrs = append(allErrs, field.Forbidden(idxPath.Child("startupProbe"), "may not be set for init containers"))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if len(ctr.ResizePolicy) > 0 {
 | 
							if len(ctr.ResizePolicy) > 0 {
 | 
				
			||||||
			allErrs = append(allErrs, field.Invalid(idxPath.Child("resizePolicy"), ctr.ResizePolicy, "must not be set for init containers"))
 | 
								allErrs = append(allErrs, field.Invalid(idxPath.Child("resizePolicy"), ctr.ResizePolicy, "must not be set for init containers"))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -3311,6 +3357,11 @@ func validateContainers(containers []core.Container, volumes map[string]core.Vol
 | 
				
			|||||||
		if ctr.StartupProbe != nil && ctr.StartupProbe.SuccessThreshold != 1 {
 | 
							if ctr.StartupProbe != nil && ctr.StartupProbe.SuccessThreshold != 1 {
 | 
				
			||||||
			allErrs = append(allErrs, field.Invalid(path.Child("startupProbe", "successThreshold"), ctr.StartupProbe.SuccessThreshold, "must be 1"))
 | 
								allErrs = append(allErrs, field.Invalid(path.Child("startupProbe", "successThreshold"), ctr.StartupProbe.SuccessThreshold, "must be 1"))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// These fields are disallowed for regular containers
 | 
				
			||||||
 | 
							if ctr.RestartPolicy != nil {
 | 
				
			||||||
 | 
								allErrs = append(allErrs, field.Forbidden(path.Child("restartPolicy"), "may not be set for non-init containers"))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Port conflicts are checked across all containers
 | 
						// Port conflicts are checked across all containers
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,6 +54,14 @@ const (
 | 
				
			|||||||
	envVarNameErrMsg        = "a valid environment variable name must consist of"
 | 
						envVarNameErrMsg        = "a valid environment variable name must consist of"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						containerRestartPolicyAlways    = core.ContainerRestartPolicyAlways
 | 
				
			||||||
 | 
						containerRestartPolicyOnFailure = core.ContainerRestartPolicy("OnFailure")
 | 
				
			||||||
 | 
						containerRestartPolicyNever     = core.ContainerRestartPolicy("Never")
 | 
				
			||||||
 | 
						containerRestartPolicyInvalid   = core.ContainerRestartPolicy("invalid")
 | 
				
			||||||
 | 
						containerRestartPolicyEmpty     = core.ContainerRestartPolicy("")
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type topologyPair struct {
 | 
					type topologyPair struct {
 | 
				
			||||||
	key   string
 | 
						key   string
 | 
				
			||||||
	value string
 | 
						value string
 | 
				
			||||||
@@ -7129,6 +7137,71 @@ func TestValidateEphemeralContainers(t *testing.T) {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
		}},
 | 
							}},
 | 
				
			||||||
		field.ErrorList{{Type: field.ErrorTypeForbidden, Field: "ephemeralContainers[0].resizePolicy"}},
 | 
							field.ErrorList{{Type: field.ErrorTypeForbidden, Field: "ephemeralContainers[0].resizePolicy"}},
 | 
				
			||||||
 | 
						}, {
 | 
				
			||||||
 | 
							"Forbidden RestartPolicy: Always",
 | 
				
			||||||
 | 
							line(),
 | 
				
			||||||
 | 
							[]core.EphemeralContainer{{
 | 
				
			||||||
 | 
								EphemeralContainerCommon: core.EphemeralContainerCommon{
 | 
				
			||||||
 | 
									Name:                     "foo",
 | 
				
			||||||
 | 
									Image:                    "image",
 | 
				
			||||||
 | 
									ImagePullPolicy:          "IfNotPresent",
 | 
				
			||||||
 | 
									TerminationMessagePolicy: "File",
 | 
				
			||||||
 | 
									RestartPolicy:            &containerRestartPolicyAlways,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							}},
 | 
				
			||||||
 | 
							field.ErrorList{{Type: field.ErrorTypeForbidden, Field: "ephemeralContainers[0].restartPolicy"}},
 | 
				
			||||||
 | 
						}, {
 | 
				
			||||||
 | 
							"Forbidden RestartPolicy: OnFailure",
 | 
				
			||||||
 | 
							line(),
 | 
				
			||||||
 | 
							[]core.EphemeralContainer{{
 | 
				
			||||||
 | 
								EphemeralContainerCommon: core.EphemeralContainerCommon{
 | 
				
			||||||
 | 
									Name:                     "foo",
 | 
				
			||||||
 | 
									Image:                    "image",
 | 
				
			||||||
 | 
									ImagePullPolicy:          "IfNotPresent",
 | 
				
			||||||
 | 
									TerminationMessagePolicy: "File",
 | 
				
			||||||
 | 
									RestartPolicy:            &containerRestartPolicyOnFailure,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							}},
 | 
				
			||||||
 | 
							field.ErrorList{{Type: field.ErrorTypeForbidden, Field: "ephemeralContainers[0].restartPolicy"}},
 | 
				
			||||||
 | 
						}, {
 | 
				
			||||||
 | 
							"Forbidden RestartPolicy: Never",
 | 
				
			||||||
 | 
							line(),
 | 
				
			||||||
 | 
							[]core.EphemeralContainer{{
 | 
				
			||||||
 | 
								EphemeralContainerCommon: core.EphemeralContainerCommon{
 | 
				
			||||||
 | 
									Name:                     "foo",
 | 
				
			||||||
 | 
									Image:                    "image",
 | 
				
			||||||
 | 
									ImagePullPolicy:          "IfNotPresent",
 | 
				
			||||||
 | 
									TerminationMessagePolicy: "File",
 | 
				
			||||||
 | 
									RestartPolicy:            &containerRestartPolicyNever,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							}},
 | 
				
			||||||
 | 
							field.ErrorList{{Type: field.ErrorTypeForbidden, Field: "ephemeralContainers[0].restartPolicy"}},
 | 
				
			||||||
 | 
						}, {
 | 
				
			||||||
 | 
							"Forbidden RestartPolicy: invalid",
 | 
				
			||||||
 | 
							line(),
 | 
				
			||||||
 | 
							[]core.EphemeralContainer{{
 | 
				
			||||||
 | 
								EphemeralContainerCommon: core.EphemeralContainerCommon{
 | 
				
			||||||
 | 
									Name:                     "foo",
 | 
				
			||||||
 | 
									Image:                    "image",
 | 
				
			||||||
 | 
									ImagePullPolicy:          "IfNotPresent",
 | 
				
			||||||
 | 
									TerminationMessagePolicy: "File",
 | 
				
			||||||
 | 
									RestartPolicy:            &containerRestartPolicyInvalid,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							}},
 | 
				
			||||||
 | 
							field.ErrorList{{Type: field.ErrorTypeForbidden, Field: "ephemeralContainers[0].restartPolicy"}},
 | 
				
			||||||
 | 
						}, {
 | 
				
			||||||
 | 
							"Forbidden RestartPolicy: empty",
 | 
				
			||||||
 | 
							line(),
 | 
				
			||||||
 | 
							[]core.EphemeralContainer{{
 | 
				
			||||||
 | 
								EphemeralContainerCommon: core.EphemeralContainerCommon{
 | 
				
			||||||
 | 
									Name:                     "foo",
 | 
				
			||||||
 | 
									Image:                    "image",
 | 
				
			||||||
 | 
									ImagePullPolicy:          "IfNotPresent",
 | 
				
			||||||
 | 
									TerminationMessagePolicy: "File",
 | 
				
			||||||
 | 
									RestartPolicy:            &containerRestartPolicyEmpty,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							}},
 | 
				
			||||||
 | 
							field.ErrorList{{Type: field.ErrorTypeForbidden, Field: "ephemeralContainers[0].restartPolicy"}},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -7986,6 +8059,61 @@ func TestValidateContainers(t *testing.T) {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
		}},
 | 
							}},
 | 
				
			||||||
		field.ErrorList{{Type: field.ErrorTypeNotSupported, Field: "containers[0].resizePolicy"}},
 | 
							field.ErrorList{{Type: field.ErrorTypeNotSupported, Field: "containers[0].resizePolicy"}},
 | 
				
			||||||
 | 
						}, {
 | 
				
			||||||
 | 
							"Forbidden RestartPolicy: Always",
 | 
				
			||||||
 | 
							line(),
 | 
				
			||||||
 | 
							[]core.Container{{
 | 
				
			||||||
 | 
								Name:                     "foo",
 | 
				
			||||||
 | 
								Image:                    "image",
 | 
				
			||||||
 | 
								ImagePullPolicy:          "IfNotPresent",
 | 
				
			||||||
 | 
								TerminationMessagePolicy: "File",
 | 
				
			||||||
 | 
								RestartPolicy:            &containerRestartPolicyAlways,
 | 
				
			||||||
 | 
							}},
 | 
				
			||||||
 | 
							field.ErrorList{{Type: field.ErrorTypeForbidden, Field: "containers[0].restartPolicy"}},
 | 
				
			||||||
 | 
						}, {
 | 
				
			||||||
 | 
							"Forbidden RestartPolicy: OnFailure",
 | 
				
			||||||
 | 
							line(),
 | 
				
			||||||
 | 
							[]core.Container{{
 | 
				
			||||||
 | 
								Name:                     "foo",
 | 
				
			||||||
 | 
								Image:                    "image",
 | 
				
			||||||
 | 
								ImagePullPolicy:          "IfNotPresent",
 | 
				
			||||||
 | 
								TerminationMessagePolicy: "File",
 | 
				
			||||||
 | 
								RestartPolicy:            &containerRestartPolicyOnFailure,
 | 
				
			||||||
 | 
							}},
 | 
				
			||||||
 | 
							field.ErrorList{{Type: field.ErrorTypeForbidden, Field: "containers[0].restartPolicy"}},
 | 
				
			||||||
 | 
						}, {
 | 
				
			||||||
 | 
							"Forbidden RestartPolicy: Never",
 | 
				
			||||||
 | 
							line(),
 | 
				
			||||||
 | 
							[]core.Container{{
 | 
				
			||||||
 | 
								Name:                     "foo",
 | 
				
			||||||
 | 
								Image:                    "image",
 | 
				
			||||||
 | 
								ImagePullPolicy:          "IfNotPresent",
 | 
				
			||||||
 | 
								TerminationMessagePolicy: "File",
 | 
				
			||||||
 | 
								RestartPolicy:            &containerRestartPolicyNever,
 | 
				
			||||||
 | 
							}},
 | 
				
			||||||
 | 
							field.ErrorList{{Type: field.ErrorTypeForbidden, Field: "containers[0].restartPolicy"}},
 | 
				
			||||||
 | 
						}, {
 | 
				
			||||||
 | 
							"Forbidden RestartPolicy: invalid",
 | 
				
			||||||
 | 
							line(),
 | 
				
			||||||
 | 
							[]core.Container{{
 | 
				
			||||||
 | 
								Name:                     "foo",
 | 
				
			||||||
 | 
								Image:                    "image",
 | 
				
			||||||
 | 
								ImagePullPolicy:          "IfNotPresent",
 | 
				
			||||||
 | 
								TerminationMessagePolicy: "File",
 | 
				
			||||||
 | 
								RestartPolicy:            &containerRestartPolicyInvalid,
 | 
				
			||||||
 | 
							}},
 | 
				
			||||||
 | 
							field.ErrorList{{Type: field.ErrorTypeForbidden, Field: "containers[0].restartPolicy"}},
 | 
				
			||||||
 | 
						}, {
 | 
				
			||||||
 | 
							"Forbidden RestartPolicy: empty",
 | 
				
			||||||
 | 
							line(),
 | 
				
			||||||
 | 
							[]core.Container{{
 | 
				
			||||||
 | 
								Name:                     "foo",
 | 
				
			||||||
 | 
								Image:                    "image",
 | 
				
			||||||
 | 
								ImagePullPolicy:          "IfNotPresent",
 | 
				
			||||||
 | 
								TerminationMessagePolicy: "File",
 | 
				
			||||||
 | 
								RestartPolicy:            &containerRestartPolicyEmpty,
 | 
				
			||||||
 | 
							}},
 | 
				
			||||||
 | 
							field.ErrorList{{Type: field.ErrorTypeForbidden, Field: "containers[0].restartPolicy"}},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for _, tc := range errorCases {
 | 
						for _, tc := range errorCases {
 | 
				
			||||||
@@ -8035,6 +8163,18 @@ func TestValidateInitContainers(t *testing.T) {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		ImagePullPolicy:          "IfNotPresent",
 | 
							ImagePullPolicy:          "IfNotPresent",
 | 
				
			||||||
		TerminationMessagePolicy: "File",
 | 
							TerminationMessagePolicy: "File",
 | 
				
			||||||
 | 
						}, {
 | 
				
			||||||
 | 
							Name:                     "container-3-restart-always-with-startup-probe",
 | 
				
			||||||
 | 
							Image:                    "image",
 | 
				
			||||||
 | 
							ImagePullPolicy:          "IfNotPresent",
 | 
				
			||||||
 | 
							TerminationMessagePolicy: "File",
 | 
				
			||||||
 | 
							RestartPolicy:            &containerRestartPolicyAlways,
 | 
				
			||||||
 | 
							StartupProbe: &core.Probe{
 | 
				
			||||||
 | 
								ProbeHandler: core.ProbeHandler{
 | 
				
			||||||
 | 
									TCPSocket: &core.TCPSocketAction{Port: intstr.FromInt(80)},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								SuccessThreshold: 1,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if errs := validateInitContainers(successCase, containers, volumeDevices, nil, field.NewPath("field"), PodValidationOptions{}); len(errs) != 0 {
 | 
						if errs := validateInitContainers(successCase, containers, volumeDevices, nil, field.NewPath("field"), PodValidationOptions{}); len(errs) != 0 {
 | 
				
			||||||
@@ -8191,6 +8331,67 @@ func TestValidateInitContainers(t *testing.T) {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
		}},
 | 
							}},
 | 
				
			||||||
		field.ErrorList{{Type: field.ErrorTypeForbidden, Field: "initContainers[0].startupProbe", BadValue: ""}},
 | 
							field.ErrorList{{Type: field.ErrorTypeForbidden, Field: "initContainers[0].startupProbe", BadValue: ""}},
 | 
				
			||||||
 | 
						}, {
 | 
				
			||||||
 | 
							"Not supported RestartPolicy: OnFailure",
 | 
				
			||||||
 | 
							line(),
 | 
				
			||||||
 | 
							[]core.Container{{
 | 
				
			||||||
 | 
								Name:                     "init",
 | 
				
			||||||
 | 
								Image:                    "image",
 | 
				
			||||||
 | 
								ImagePullPolicy:          "IfNotPresent",
 | 
				
			||||||
 | 
								TerminationMessagePolicy: "File",
 | 
				
			||||||
 | 
								RestartPolicy:            &containerRestartPolicyOnFailure,
 | 
				
			||||||
 | 
							}},
 | 
				
			||||||
 | 
							field.ErrorList{{Type: field.ErrorTypeNotSupported, Field: "initContainers[0].restartPolicy", BadValue: containerRestartPolicyOnFailure}},
 | 
				
			||||||
 | 
						}, {
 | 
				
			||||||
 | 
							"Not supported RestartPolicy: Never",
 | 
				
			||||||
 | 
							line(),
 | 
				
			||||||
 | 
							[]core.Container{{
 | 
				
			||||||
 | 
								Name:                     "init",
 | 
				
			||||||
 | 
								Image:                    "image",
 | 
				
			||||||
 | 
								ImagePullPolicy:          "IfNotPresent",
 | 
				
			||||||
 | 
								TerminationMessagePolicy: "File",
 | 
				
			||||||
 | 
								RestartPolicy:            &containerRestartPolicyNever,
 | 
				
			||||||
 | 
							}},
 | 
				
			||||||
 | 
							field.ErrorList{{Type: field.ErrorTypeNotSupported, Field: "initContainers[0].restartPolicy", BadValue: containerRestartPolicyNever}},
 | 
				
			||||||
 | 
						}, {
 | 
				
			||||||
 | 
							"Not supported RestartPolicy: invalid",
 | 
				
			||||||
 | 
							line(),
 | 
				
			||||||
 | 
							[]core.Container{{
 | 
				
			||||||
 | 
								Name:                     "init",
 | 
				
			||||||
 | 
								Image:                    "image",
 | 
				
			||||||
 | 
								ImagePullPolicy:          "IfNotPresent",
 | 
				
			||||||
 | 
								TerminationMessagePolicy: "File",
 | 
				
			||||||
 | 
								RestartPolicy:            &containerRestartPolicyInvalid,
 | 
				
			||||||
 | 
							}},
 | 
				
			||||||
 | 
							field.ErrorList{{Type: field.ErrorTypeNotSupported, Field: "initContainers[0].restartPolicy", BadValue: containerRestartPolicyInvalid}},
 | 
				
			||||||
 | 
						}, {
 | 
				
			||||||
 | 
							"Not supported RestartPolicy: empty",
 | 
				
			||||||
 | 
							line(),
 | 
				
			||||||
 | 
							[]core.Container{{
 | 
				
			||||||
 | 
								Name:                     "init",
 | 
				
			||||||
 | 
								Image:                    "image",
 | 
				
			||||||
 | 
								ImagePullPolicy:          "IfNotPresent",
 | 
				
			||||||
 | 
								TerminationMessagePolicy: "File",
 | 
				
			||||||
 | 
								RestartPolicy:            &containerRestartPolicyEmpty,
 | 
				
			||||||
 | 
							}},
 | 
				
			||||||
 | 
							field.ErrorList{{Type: field.ErrorTypeNotSupported, Field: "initContainers[0].restartPolicy", BadValue: containerRestartPolicyEmpty}},
 | 
				
			||||||
 | 
						}, {
 | 
				
			||||||
 | 
							"invalid startup probe in restartable container, successThreshold != 1",
 | 
				
			||||||
 | 
							line(),
 | 
				
			||||||
 | 
							[]core.Container{{
 | 
				
			||||||
 | 
								Name:                     "restartable-init",
 | 
				
			||||||
 | 
								Image:                    "image",
 | 
				
			||||||
 | 
								ImagePullPolicy:          "IfNotPresent",
 | 
				
			||||||
 | 
								TerminationMessagePolicy: "File",
 | 
				
			||||||
 | 
								RestartPolicy:            &containerRestartPolicyAlways,
 | 
				
			||||||
 | 
								StartupProbe: &core.Probe{
 | 
				
			||||||
 | 
									ProbeHandler: core.ProbeHandler{
 | 
				
			||||||
 | 
										TCPSocket: &core.TCPSocketAction{Port: intstr.FromInt(80)},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									SuccessThreshold: 2,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							}},
 | 
				
			||||||
 | 
							field.ErrorList{{Type: field.ErrorTypeInvalid, Field: "initContainers[0].startupProbe.successThreshold", BadValue: int32(2)}},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for _, tc := range errorCases {
 | 
						for _, tc := range errorCases {
 | 
				
			||||||
@@ -19323,6 +19524,7 @@ func TestValidateOSFields(t *testing.T) {
 | 
				
			|||||||
		"Containers[*].Resources",
 | 
							"Containers[*].Resources",
 | 
				
			||||||
		"Containers[*].ResizePolicy[*].RestartPolicy",
 | 
							"Containers[*].ResizePolicy[*].RestartPolicy",
 | 
				
			||||||
		"Containers[*].ResizePolicy[*].ResourceName",
 | 
							"Containers[*].ResizePolicy[*].ResourceName",
 | 
				
			||||||
 | 
							"Containers[*].RestartPolicy",
 | 
				
			||||||
		"Containers[*].SecurityContext.RunAsNonRoot",
 | 
							"Containers[*].SecurityContext.RunAsNonRoot",
 | 
				
			||||||
		"Containers[*].Stdin",
 | 
							"Containers[*].Stdin",
 | 
				
			||||||
		"Containers[*].StdinOnce",
 | 
							"Containers[*].StdinOnce",
 | 
				
			||||||
@@ -19349,6 +19551,7 @@ func TestValidateOSFields(t *testing.T) {
 | 
				
			|||||||
		"EphemeralContainers[*].EphemeralContainerCommon.Resources",
 | 
							"EphemeralContainers[*].EphemeralContainerCommon.Resources",
 | 
				
			||||||
		"EphemeralContainers[*].EphemeralContainerCommon.ResizePolicy[*].RestartPolicy",
 | 
							"EphemeralContainers[*].EphemeralContainerCommon.ResizePolicy[*].RestartPolicy",
 | 
				
			||||||
		"EphemeralContainers[*].EphemeralContainerCommon.ResizePolicy[*].ResourceName",
 | 
							"EphemeralContainers[*].EphemeralContainerCommon.ResizePolicy[*].ResourceName",
 | 
				
			||||||
 | 
							"EphemeralContainers[*].EphemeralContainerCommon.RestartPolicy",
 | 
				
			||||||
		"EphemeralContainers[*].EphemeralContainerCommon.Stdin",
 | 
							"EphemeralContainers[*].EphemeralContainerCommon.Stdin",
 | 
				
			||||||
		"EphemeralContainers[*].EphemeralContainerCommon.StdinOnce",
 | 
							"EphemeralContainers[*].EphemeralContainerCommon.StdinOnce",
 | 
				
			||||||
		"EphemeralContainers[*].EphemeralContainerCommon.TTY",
 | 
							"EphemeralContainers[*].EphemeralContainerCommon.TTY",
 | 
				
			||||||
@@ -19377,6 +19580,7 @@ func TestValidateOSFields(t *testing.T) {
 | 
				
			|||||||
		"InitContainers[*].Resources",
 | 
							"InitContainers[*].Resources",
 | 
				
			||||||
		"InitContainers[*].ResizePolicy[*].RestartPolicy",
 | 
							"InitContainers[*].ResizePolicy[*].RestartPolicy",
 | 
				
			||||||
		"InitContainers[*].ResizePolicy[*].ResourceName",
 | 
							"InitContainers[*].ResizePolicy[*].ResourceName",
 | 
				
			||||||
 | 
							"InitContainers[*].RestartPolicy",
 | 
				
			||||||
		"InitContainers[*].Stdin",
 | 
							"InitContainers[*].Stdin",
 | 
				
			||||||
		"InitContainers[*].StdinOnce",
 | 
							"InitContainers[*].StdinOnce",
 | 
				
			||||||
		"InitContainers[*].TTY",
 | 
							"InitContainers[*].TTY",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -714,6 +714,15 @@ const (
 | 
				
			|||||||
	// Subdivide the NodePort range for dynamic and static port allocation.
 | 
						// Subdivide the NodePort range for dynamic and static port allocation.
 | 
				
			||||||
	ServiceNodePortStaticSubrange featuregate.Feature = "ServiceNodePortStaticSubrange"
 | 
						ServiceNodePortStaticSubrange featuregate.Feature = "ServiceNodePortStaticSubrange"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// owner: @gjkim42 @SergeyKanzhelev @matthyx @tzneal
 | 
				
			||||||
 | 
						// kep: http://kep.k8s.io/753
 | 
				
			||||||
 | 
						// alpha: v1.28
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Introduces sidecar containers, a new type of init container that starts
 | 
				
			||||||
 | 
						// before other containers but remains running for the full duration of the
 | 
				
			||||||
 | 
						// pod's lifecycle and will not block pod termination.
 | 
				
			||||||
 | 
						SidecarContainers featuregate.Feature = "SidecarContainers"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// owner: @derekwaynecarr
 | 
						// owner: @derekwaynecarr
 | 
				
			||||||
	// alpha: v1.20
 | 
						// alpha: v1.20
 | 
				
			||||||
	// beta: v1.22
 | 
						// beta: v1.22
 | 
				
			||||||
@@ -1037,6 +1046,8 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	ServiceNodePortStaticSubrange: {Default: true, PreRelease: featuregate.Beta},
 | 
						ServiceNodePortStaticSubrange: {Default: true, PreRelease: featuregate.Beta},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SidecarContainers: {Default: false, PreRelease: featuregate.Alpha},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SizeMemoryBackedVolumes: {Default: true, PreRelease: featuregate.Beta},
 | 
						SizeMemoryBackedVolumes: {Default: true, PreRelease: featuregate.Beta},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	StableLoadBalancerNodeSet: {Default: true, PreRelease: featuregate.Beta},
 | 
						StableLoadBalancerNodeSet: {Default: true, PreRelease: featuregate.Beta},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2446,6 +2446,24 @@ type Container struct {
 | 
				
			|||||||
	// +optional
 | 
						// +optional
 | 
				
			||||||
	// +listType=atomic
 | 
						// +listType=atomic
 | 
				
			||||||
	ResizePolicy []ContainerResizePolicy `json:"resizePolicy,omitempty" protobuf:"bytes,23,rep,name=resizePolicy"`
 | 
						ResizePolicy []ContainerResizePolicy `json:"resizePolicy,omitempty" protobuf:"bytes,23,rep,name=resizePolicy"`
 | 
				
			||||||
 | 
						// RestartPolicy defines the restart behavior of individual containers in a pod.
 | 
				
			||||||
 | 
						// This field may only be set for init containers, and the only allowed value is "Always".
 | 
				
			||||||
 | 
						// For non-init containers or when this field is not specified,
 | 
				
			||||||
 | 
						// the restart behavior is defined by the Pod's restart policy and the container type.
 | 
				
			||||||
 | 
						// Setting the RestartPolicy as "Always" for the init container will have the following effect:
 | 
				
			||||||
 | 
						// this init container will be continually restarted on
 | 
				
			||||||
 | 
						// exit until all regular containers have terminated. Once all regular
 | 
				
			||||||
 | 
						// containers have completed, all init containers with restartPolicy "Always"
 | 
				
			||||||
 | 
						// will be shut down. This lifecycle differs from normal init containers and
 | 
				
			||||||
 | 
						// is often referred to as a "sidecar" container. Although this init
 | 
				
			||||||
 | 
						// container still starts in the init container sequence, it does not wait
 | 
				
			||||||
 | 
						// for the container to complete before proceeding to the next init
 | 
				
			||||||
 | 
						// container. Instead, the next init container starts immediately after this
 | 
				
			||||||
 | 
						// init container is started, or after any startupProbe has successfully
 | 
				
			||||||
 | 
						// completed.
 | 
				
			||||||
 | 
						// +featureGate=SidecarContainers
 | 
				
			||||||
 | 
						// +optional
 | 
				
			||||||
 | 
						RestartPolicy *ContainerRestartPolicy `json:"restartPolicy,omitempty" protobuf:"bytes,24,opt,name=restartPolicy,casttype=ContainerRestartPolicy"`
 | 
				
			||||||
	// Pod volumes to mount into the container's filesystem.
 | 
						// Pod volumes to mount into the container's filesystem.
 | 
				
			||||||
	// Cannot be updated.
 | 
						// Cannot be updated.
 | 
				
			||||||
	// +optional
 | 
						// +optional
 | 
				
			||||||
@@ -2842,6 +2860,14 @@ const (
 | 
				
			|||||||
	RestartPolicyNever     RestartPolicy = "Never"
 | 
						RestartPolicyNever     RestartPolicy = "Never"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ContainerRestartPolicy is the restart policy for a single container.
 | 
				
			||||||
 | 
					// This may only be set for init containers and only allowed value is "Always".
 | 
				
			||||||
 | 
					type ContainerRestartPolicy string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						ContainerRestartPolicyAlways ContainerRestartPolicy = "Always"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// DNSPolicy defines how a pod's DNS will be configured.
 | 
					// DNSPolicy defines how a pod's DNS will be configured.
 | 
				
			||||||
// +enum
 | 
					// +enum
 | 
				
			||||||
type DNSPolicy string
 | 
					type DNSPolicy string
 | 
				
			||||||
@@ -3976,6 +4002,13 @@ type EphemeralContainerCommon struct {
 | 
				
			|||||||
	// +optional
 | 
						// +optional
 | 
				
			||||||
	// +listType=atomic
 | 
						// +listType=atomic
 | 
				
			||||||
	ResizePolicy []ContainerResizePolicy `json:"resizePolicy,omitempty" protobuf:"bytes,23,rep,name=resizePolicy"`
 | 
						ResizePolicy []ContainerResizePolicy `json:"resizePolicy,omitempty" protobuf:"bytes,23,rep,name=resizePolicy"`
 | 
				
			||||||
 | 
						// Restart policy for the container to manage the restart behavior of each
 | 
				
			||||||
 | 
						// container within a pod.
 | 
				
			||||||
 | 
						// This may only be set for init containers. You cannot set this field on
 | 
				
			||||||
 | 
						// ephemeral containers.
 | 
				
			||||||
 | 
						// +featureGate=SidecarContainers
 | 
				
			||||||
 | 
						// +optional
 | 
				
			||||||
 | 
						RestartPolicy *ContainerRestartPolicy `json:"restartPolicy,omitempty" protobuf:"bytes,24,opt,name=restartPolicy,casttype=ContainerRestartPolicy"`
 | 
				
			||||||
	// Pod volumes to mount into the container's filesystem. Subpath mounts are not allowed for ephemeral containers.
 | 
						// Pod volumes to mount into the container's filesystem. Subpath mounts are not allowed for ephemeral containers.
 | 
				
			||||||
	// Cannot be updated.
 | 
						// Cannot be updated.
 | 
				
			||||||
	// +optional
 | 
						// +optional
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user