mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-30 23:15:14 +00:00
Validation
This commit is contained in:
parent
70540c9f43
commit
0380f2c41c
@ -270,6 +270,12 @@ func SetContainerImage(image string) TweakContainer {
|
||||
}
|
||||
}
|
||||
|
||||
func SetContainerLifecycle(lifecycle api.Lifecycle) TweakContainer {
|
||||
return func(cnr *api.Container) {
|
||||
cnr.Lifecycle = &lifecycle
|
||||
}
|
||||
}
|
||||
|
||||
func MakeResourceRequirements(requests, limits map[string]string) api.ResourceRequirements {
|
||||
rr := api.ResourceRequirements{Requests: api.ResourceList{}, Limits: api.ResourceList{}}
|
||||
for k, v := range requests {
|
||||
|
@ -678,6 +678,51 @@ func dropDisabledFields(
|
||||
dropPodLifecycleSleepAction(podSpec, oldPodSpec)
|
||||
dropImageVolumes(podSpec, oldPodSpec)
|
||||
dropSELinuxChangePolicy(podSpec, oldPodSpec)
|
||||
dropContainerStopSignals(podSpec, oldPodSpec)
|
||||
}
|
||||
|
||||
func dropContainerStopSignals(podSpec, oldPodSpec *api.PodSpec) {
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.ContainerStopSignals) || containerStopSignalsInUse(oldPodSpec) {
|
||||
return
|
||||
}
|
||||
|
||||
wipeLifecycle := func(ctr *api.Container) {
|
||||
if ctr.Lifecycle == nil {
|
||||
return
|
||||
}
|
||||
if ctr.Lifecycle.StopSignal != nil {
|
||||
ctr.Lifecycle.StopSignal = nil
|
||||
if *ctr.Lifecycle == (api.Lifecycle{}) {
|
||||
ctr.Lifecycle = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VisitContainers(podSpec, AllContainers, func(c *api.Container, containerType ContainerType) bool {
|
||||
if c.Lifecycle == nil {
|
||||
return true
|
||||
}
|
||||
wipeLifecycle(c)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func containerStopSignalsInUse(podSpec *api.PodSpec) bool {
|
||||
if podSpec == nil {
|
||||
return false
|
||||
}
|
||||
var inUse bool
|
||||
VisitContainers(podSpec, AllContainers, func(c *api.Container, containerType ContainerType) bool {
|
||||
if c.Lifecycle == nil {
|
||||
return true
|
||||
}
|
||||
if c.Lifecycle.StopSignal != nil {
|
||||
inUse = true
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
return inUse
|
||||
}
|
||||
|
||||
func dropDisabledPodLevelResources(podSpec, oldPodSpec *api.PodSpec) {
|
||||
@ -713,7 +758,7 @@ func dropPodLifecycleSleepAction(podSpec, oldPodSpec *api.PodSpec) {
|
||||
continue
|
||||
}
|
||||
adjustLifecycle(podSpec.Containers[i].Lifecycle)
|
||||
if podSpec.Containers[i].Lifecycle.PreStop == nil && podSpec.Containers[i].Lifecycle.PostStart == nil {
|
||||
if podSpec.Containers[i].Lifecycle.PreStop == nil && podSpec.Containers[i].Lifecycle.PostStart == nil && podSpec.Containers[i].Lifecycle.StopSignal == nil {
|
||||
podSpec.Containers[i].Lifecycle = nil
|
||||
}
|
||||
}
|
||||
@ -723,7 +768,7 @@ func dropPodLifecycleSleepAction(podSpec, oldPodSpec *api.PodSpec) {
|
||||
continue
|
||||
}
|
||||
adjustLifecycle(podSpec.InitContainers[i].Lifecycle)
|
||||
if podSpec.InitContainers[i].Lifecycle.PreStop == nil && podSpec.InitContainers[i].Lifecycle.PostStart == nil {
|
||||
if podSpec.InitContainers[i].Lifecycle.PreStop == nil && podSpec.InitContainers[i].Lifecycle.PostStart == nil && podSpec.InitContainers[i].Lifecycle.StopSignal == nil {
|
||||
podSpec.InitContainers[i].Lifecycle = nil
|
||||
}
|
||||
}
|
||||
@ -733,7 +778,7 @@ func dropPodLifecycleSleepAction(podSpec, oldPodSpec *api.PodSpec) {
|
||||
continue
|
||||
}
|
||||
adjustLifecycle(podSpec.EphemeralContainers[i].Lifecycle)
|
||||
if podSpec.EphemeralContainers[i].Lifecycle.PreStop == nil && podSpec.EphemeralContainers[i].Lifecycle.PostStart == nil {
|
||||
if podSpec.EphemeralContainers[i].Lifecycle.PreStop == nil && podSpec.EphemeralContainers[i].Lifecycle.PostStart == nil && podSpec.EphemeralContainers[i].Lifecycle.StopSignal == nil {
|
||||
podSpec.EphemeralContainers[i].Lifecycle = nil
|
||||
}
|
||||
}
|
||||
|
@ -3436,6 +3436,148 @@ func TestDropPodLifecycleSleepAction(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDropContainerStopSignals(t *testing.T) {
|
||||
makeContainer := func(lifecycle *api.Lifecycle) api.Container {
|
||||
container := api.Container{Name: "foo"}
|
||||
if lifecycle != nil {
|
||||
container.Lifecycle = lifecycle
|
||||
}
|
||||
return container
|
||||
}
|
||||
|
||||
makeEphemeralContainer := func(lifecycle *api.Lifecycle) api.EphemeralContainer {
|
||||
container := api.EphemeralContainer{
|
||||
EphemeralContainerCommon: api.EphemeralContainerCommon{Name: "foo"},
|
||||
}
|
||||
if lifecycle != nil {
|
||||
container.Lifecycle = lifecycle
|
||||
}
|
||||
return container
|
||||
}
|
||||
|
||||
makePod := func(os api.OSName, containers []api.Container, initContainers []api.Container, ephemeralContainers []api.EphemeralContainer) *api.PodSpec {
|
||||
return &api.PodSpec{
|
||||
OS: &api.PodOS{Name: os},
|
||||
Containers: containers,
|
||||
InitContainers: initContainers,
|
||||
EphemeralContainers: ephemeralContainers,
|
||||
}
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
featuregateEnabled bool
|
||||
oldLifecycle *api.Lifecycle
|
||||
newLifecycle *api.Lifecycle
|
||||
expectedLifecycle *api.Lifecycle
|
||||
}{
|
||||
// feature gate is turned on and stopsignal is not in use - Lifecycle stays nil
|
||||
{
|
||||
featuregateEnabled: true,
|
||||
oldLifecycle: nil,
|
||||
newLifecycle: nil,
|
||||
expectedLifecycle: nil,
|
||||
},
|
||||
// feature gate is turned off and StopSignal is in use - StopSignal is not dropped
|
||||
{
|
||||
featuregateEnabled: false,
|
||||
oldLifecycle: &api.Lifecycle{StopSignal: ptr.To(api.SIGTERM)},
|
||||
newLifecycle: &api.Lifecycle{StopSignal: ptr.To(api.SIGTERM)},
|
||||
expectedLifecycle: &api.Lifecycle{StopSignal: ptr.To(api.SIGTERM)},
|
||||
},
|
||||
// feature gate is turned off and StopSignal is not in use - Entire lifecycle is dropped
|
||||
{
|
||||
featuregateEnabled: false,
|
||||
oldLifecycle: &api.Lifecycle{StopSignal: nil},
|
||||
newLifecycle: &api.Lifecycle{StopSignal: ptr.To(api.SIGTERM)},
|
||||
expectedLifecycle: nil,
|
||||
},
|
||||
// feature gate is turned on and StopSignal is in use - StopSignal is not dropped
|
||||
{
|
||||
featuregateEnabled: true,
|
||||
oldLifecycle: &api.Lifecycle{StopSignal: nil},
|
||||
newLifecycle: &api.Lifecycle{StopSignal: ptr.To(api.SIGTERM)},
|
||||
expectedLifecycle: &api.Lifecycle{StopSignal: ptr.To(api.SIGTERM)},
|
||||
},
|
||||
// feature gate is turned off and PreStop is in use - StopSignal alone is dropped
|
||||
{
|
||||
featuregateEnabled: false,
|
||||
oldLifecycle: &api.Lifecycle{StopSignal: nil, PreStop: &api.LifecycleHandler{
|
||||
Exec: &api.ExecAction{Command: []string{"foo"}},
|
||||
}},
|
||||
newLifecycle: &api.Lifecycle{StopSignal: ptr.To(api.SIGTERM), PreStop: &api.LifecycleHandler{
|
||||
Exec: &api.ExecAction{Command: []string{"foo"}},
|
||||
}},
|
||||
expectedLifecycle: &api.Lifecycle{StopSignal: nil, PreStop: &api.LifecycleHandler{
|
||||
Exec: &api.ExecAction{Command: []string{"foo"}},
|
||||
}},
|
||||
},
|
||||
// feature gate is turned on and PreStop is in use - StopSignal is not dropped
|
||||
{
|
||||
featuregateEnabled: true,
|
||||
oldLifecycle: &api.Lifecycle{StopSignal: nil, PreStop: &api.LifecycleHandler{
|
||||
Exec: &api.ExecAction{Command: []string{"foo"}},
|
||||
}},
|
||||
newLifecycle: &api.Lifecycle{StopSignal: ptr.To(api.SIGTERM), PreStop: &api.LifecycleHandler{
|
||||
Exec: &api.ExecAction{Command: []string{"foo"}},
|
||||
}},
|
||||
expectedLifecycle: &api.Lifecycle{StopSignal: ptr.To(api.SIGTERM), PreStop: &api.LifecycleHandler{
|
||||
Exec: &api.ExecAction{Command: []string{"foo"}},
|
||||
}},
|
||||
},
|
||||
// feature gate is turned off and PreStop and StopSignal are in use - nothing is dropped
|
||||
{
|
||||
featuregateEnabled: true,
|
||||
oldLifecycle: &api.Lifecycle{StopSignal: ptr.To(api.SIGTERM), PreStop: &api.LifecycleHandler{
|
||||
Exec: &api.ExecAction{Command: []string{"foo"}},
|
||||
}},
|
||||
newLifecycle: &api.Lifecycle{StopSignal: ptr.To(api.SIGTERM), PreStop: &api.LifecycleHandler{
|
||||
Exec: &api.ExecAction{Command: []string{"foo"}},
|
||||
}},
|
||||
expectedLifecycle: &api.Lifecycle{StopSignal: ptr.To(api.SIGTERM), PreStop: &api.LifecycleHandler{
|
||||
Exec: &api.ExecAction{Command: []string{"foo"}},
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("test_%d", i), func(t *testing.T) {
|
||||
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ContainerStopSignals, tc.featuregateEnabled)
|
||||
// Containers
|
||||
{
|
||||
oldPod := makePod(api.Linux, []api.Container{makeContainer(tc.oldLifecycle.DeepCopy())}, nil, nil)
|
||||
newPod := makePod(api.Linux, []api.Container{makeContainer(tc.newLifecycle.DeepCopy())}, nil, nil)
|
||||
expectedPod := makePod(api.Linux, []api.Container{makeContainer(tc.expectedLifecycle.DeepCopy())}, nil, nil)
|
||||
dropDisabledFields(newPod, nil, oldPod, nil)
|
||||
|
||||
if diff := cmp.Diff(expectedPod, newPod); diff != "" {
|
||||
t.Fatalf("Unexpected modification to new pod; diff (-got +want)\n%s", diff)
|
||||
}
|
||||
}
|
||||
// InitContainers
|
||||
{
|
||||
oldPod := makePod(api.Linux, nil, []api.Container{makeContainer(tc.oldLifecycle.DeepCopy())}, nil)
|
||||
newPod := makePod(api.Linux, nil, []api.Container{makeContainer(tc.newLifecycle.DeepCopy())}, nil)
|
||||
expectPod := makePod(api.Linux, nil, []api.Container{makeContainer(tc.expectedLifecycle.DeepCopy())}, nil)
|
||||
dropDisabledFields(newPod, nil, oldPod, nil)
|
||||
if diff := cmp.Diff(expectPod, newPod); diff != "" {
|
||||
t.Fatalf("Unexpected modification to new pod; diff (-got +want)\n%s", diff)
|
||||
}
|
||||
}
|
||||
// EphemeralContainers
|
||||
{
|
||||
oldPod := makePod(api.Linux, nil, nil, []api.EphemeralContainer{makeEphemeralContainer(tc.oldLifecycle.DeepCopy())})
|
||||
newPod := makePod(api.Linux, nil, nil, []api.EphemeralContainer{makeEphemeralContainer(tc.newLifecycle.DeepCopy())})
|
||||
expectPod := makePod(api.Linux, nil, nil, []api.EphemeralContainer{makeEphemeralContainer(tc.expectedLifecycle.DeepCopy())})
|
||||
dropDisabledFields(newPod, nil, oldPod, nil)
|
||||
if diff := cmp.Diff(expectPod, newPod); diff != "" {
|
||||
t.Fatalf("Unexpected modification to new pod; diff (-got +want)\n%s", diff)
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDropSupplementalGroupsPolicy(t *testing.T) {
|
||||
supplementalGroupsPolicyMerge := api.SupplementalGroupsPolicyMerge
|
||||
podWithSupplementalGroupsPolicy := func() *api.Pod {
|
||||
|
@ -3343,7 +3343,48 @@ func validateHandler(handler commonHandler, gracePeriod *int64, fldPath *field.P
|
||||
return allErrors
|
||||
}
|
||||
|
||||
func validateLifecycle(lifecycle *core.Lifecycle, gracePeriod *int64, fldPath *field.Path, opts PodValidationOptions) field.ErrorList {
|
||||
var supportedStopSignalsLinux = sets.New(
|
||||
core.SIGABRT, core.SIGALRM, core.SIGBUS, core.SIGCHLD,
|
||||
core.SIGCLD, core.SIGCONT, core.SIGFPE, core.SIGHUP,
|
||||
core.SIGILL, core.SIGINT, core.SIGIO, core.SIGIOT,
|
||||
core.SIGKILL, core.SIGPIPE, core.SIGPOLL, core.SIGPROF,
|
||||
core.SIGPWR, core.SIGQUIT, core.SIGSEGV, core.SIGSTKFLT,
|
||||
core.SIGSTOP, core.SIGSYS, core.SIGTERM, core.SIGTRAP,
|
||||
core.SIGTSTP, core.SIGTTIN, core.SIGTTOU, core.SIGURG,
|
||||
core.SIGUSR1, core.SIGUSR2, core.SIGVTALRM, core.SIGWINCH,
|
||||
core.SIGXCPU, core.SIGXFSZ, core.SIGRTMIN, core.SIGRTMINPLUS1,
|
||||
core.SIGRTMINPLUS2, core.SIGRTMINPLUS3, core.SIGRTMINPLUS4,
|
||||
core.SIGRTMINPLUS5, core.SIGRTMINPLUS6, core.SIGRTMINPLUS7,
|
||||
core.SIGRTMINPLUS8, core.SIGRTMINPLUS9, core.SIGRTMINPLUS10,
|
||||
core.SIGRTMINPLUS11, core.SIGRTMINPLUS12, core.SIGRTMINPLUS13,
|
||||
core.SIGRTMINPLUS14, core.SIGRTMINPLUS15, core.SIGRTMAXMINUS14,
|
||||
core.SIGRTMAXMINUS13, core.SIGRTMAXMINUS12, core.SIGRTMAXMINUS11,
|
||||
core.SIGRTMAXMINUS10, core.SIGRTMAXMINUS9, core.SIGRTMAXMINUS8,
|
||||
core.SIGRTMAXMINUS7, core.SIGRTMAXMINUS6, core.SIGRTMAXMINUS5,
|
||||
core.SIGRTMAXMINUS4, core.SIGRTMAXMINUS3, core.SIGRTMAXMINUS2,
|
||||
core.SIGRTMAXMINUS1, core.SIGRTMAX)
|
||||
|
||||
var supportedStopSignalsWindows = sets.New(core.SIGKILL, core.SIGTERM)
|
||||
|
||||
func validateStopSignal(stopSignal *core.Signal, fldPath *field.Path, os *core.PodOS) field.ErrorList {
|
||||
allErrors := field.ErrorList{}
|
||||
|
||||
if os == nil {
|
||||
allErrors = append(allErrors, field.Forbidden(fldPath, "may not be set for containers with empty `spec.os.name`"))
|
||||
} else if os.Name == core.Windows {
|
||||
if !supportedStopSignalsWindows.Has(*stopSignal) {
|
||||
allErrors = append(allErrors, field.NotSupported(fldPath, stopSignal, sets.List(supportedStopSignalsWindows)))
|
||||
}
|
||||
} else if os.Name == core.Linux {
|
||||
if !supportedStopSignalsLinux.Has(*stopSignal) {
|
||||
allErrors = append(allErrors, field.NotSupported(fldPath, stopSignal, sets.List(supportedStopSignalsLinux)))
|
||||
}
|
||||
}
|
||||
|
||||
return allErrors
|
||||
}
|
||||
|
||||
func validateLifecycle(lifecycle *core.Lifecycle, gracePeriod *int64, fldPath *field.Path, opts PodValidationOptions, os *core.PodOS) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if lifecycle.PostStart != nil {
|
||||
allErrs = append(allErrs, validateHandler(handlerFromLifecycle(lifecycle.PostStart), gracePeriod, fldPath.Child("postStart"), opts)...)
|
||||
@ -3351,6 +3392,9 @@ func validateLifecycle(lifecycle *core.Lifecycle, gracePeriod *int64, fldPath *f
|
||||
if lifecycle.PreStop != nil {
|
||||
allErrs = append(allErrs, validateHandler(handlerFromLifecycle(lifecycle.PreStop), gracePeriod, fldPath.Child("preStop"), opts)...)
|
||||
}
|
||||
if lifecycle.StopSignal != nil {
|
||||
allErrs = append(allErrs, validateStopSignal(lifecycle.StopSignal, fldPath.Child("stopSignal"), os)...)
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
@ -3494,7 +3538,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, hostUsers bool) field.ErrorList {
|
||||
func validateInitContainers(containers []core.Container, os *core.PodOS, 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]{}
|
||||
@ -3528,7 +3572,7 @@ func validateInitContainers(containers []core.Container, regularContainers []cor
|
||||
switch {
|
||||
case restartAlways:
|
||||
if ctr.Lifecycle != nil {
|
||||
allErrs = append(allErrs, validateLifecycle(ctr.Lifecycle, gracePeriod, idxPath.Child("lifecycle"), opts)...)
|
||||
allErrs = append(allErrs, validateLifecycle(ctr.Lifecycle, gracePeriod, idxPath.Child("lifecycle"), opts, os)...)
|
||||
}
|
||||
allErrs = append(allErrs, validateLivenessProbe(ctr.LivenessProbe, gracePeriod, idxPath.Child("livenessProbe"), opts)...)
|
||||
allErrs = append(allErrs, validateReadinessProbe(ctr.ReadinessProbe, gracePeriod, idxPath.Child("readinessProbe"), opts)...)
|
||||
@ -3632,7 +3676,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, hostUsers bool) field.ErrorList {
|
||||
func validateContainers(containers []core.Container, os *core.PodOS, 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 {
|
||||
@ -3660,7 +3704,7 @@ func validateContainers(containers []core.Container, volumes map[string]core.Vol
|
||||
// Regular init container and ephemeral container validation will return
|
||||
// field.Forbidden() for these paths.
|
||||
if ctr.Lifecycle != nil {
|
||||
allErrs = append(allErrs, validateLifecycle(ctr.Lifecycle, gracePeriod, path.Child("lifecycle"), opts)...)
|
||||
allErrs = append(allErrs, validateLifecycle(ctr.Lifecycle, gracePeriod, path.Child("lifecycle"), opts, os)...)
|
||||
}
|
||||
allErrs = append(allErrs, validateLivenessProbe(ctr.LivenessProbe, gracePeriod, path.Child("livenessProbe"), opts)...)
|
||||
allErrs = append(allErrs, validateReadinessProbe(ctr.ReadinessProbe, gracePeriod, path.Child("readinessProbe"), opts)...)
|
||||
@ -4207,8 +4251,8 @@ func ValidatePodSpec(spec *core.PodSpec, podMeta *metav1.ObjectMeta, fldPath *fi
|
||||
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, hostUsers)...)
|
||||
allErrs = append(allErrs, validateInitContainers(spec.InitContainers, spec.Containers, vols, podClaimNames, gracePeriod, fldPath.Child("initContainers"), opts, &spec.RestartPolicy, hostUsers)...)
|
||||
allErrs = append(allErrs, validateContainers(spec.Containers, spec.OS, vols, podClaimNames, gracePeriod, fldPath.Child("containers"), opts, &spec.RestartPolicy, hostUsers)...)
|
||||
allErrs = append(allErrs, validateInitContainers(spec.InitContainers, spec.OS, 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)...)
|
||||
|
||||
if opts.PodLevelResourcesEnabled {
|
||||
|
@ -8372,6 +8372,7 @@ func TestValidateLinuxPodSecurityContext(t *testing.T) {
|
||||
|
||||
func TestValidateContainers(t *testing.T) {
|
||||
volumeDevices := make(map[string]core.VolumeSource)
|
||||
podOS := &core.PodOS{Name: core.OSName(v1.Linux)}
|
||||
capabilities.ResetForTest()
|
||||
capabilities.Initialize(capabilities.Capabilities{
|
||||
AllowPrivileged: true,
|
||||
@ -8568,11 +8569,19 @@ func TestValidateContainers(t *testing.T) {
|
||||
{ResourceName: "memory", RestartPolicy: "NotRequired"},
|
||||
{ResourceName: "cpu", RestartPolicy: "RestartContainer"},
|
||||
},
|
||||
}, {
|
||||
Name: "container-with-stopsignal-lifecycle",
|
||||
Image: "image",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
TerminationMessagePolicy: "File",
|
||||
Lifecycle: &core.Lifecycle{
|
||||
StopSignal: ptr.To(core.SIGTERM),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var PodRestartPolicy core.RestartPolicy = "Always"
|
||||
if errs := validateContainers(successCase, volumeDevices, nil, defaultGracePeriod, field.NewPath("field"), PodValidationOptions{}, &PodRestartPolicy, noUserNamespace); len(errs) != 0 {
|
||||
if errs := validateContainers(successCase, podOS, volumeDevices, nil, defaultGracePeriod, field.NewPath("field"), PodValidationOptions{}, &PodRestartPolicy, noUserNamespace); len(errs) != 0 {
|
||||
t.Errorf("expected success: %v", errs)
|
||||
}
|
||||
|
||||
@ -9187,7 +9196,7 @@ func TestValidateContainers(t *testing.T) {
|
||||
|
||||
for _, tc := range errorCases {
|
||||
t.Run(tc.title+"__@L"+tc.line, func(t *testing.T) {
|
||||
errs := validateContainers(tc.containers, volumeDevices, nil, defaultGracePeriod, field.NewPath("containers"), PodValidationOptions{}, &PodRestartPolicy, noUserNamespace)
|
||||
errs := validateContainers(tc.containers, podOS, volumeDevices, nil, defaultGracePeriod, field.NewPath("containers"), PodValidationOptions{}, &PodRestartPolicy, noUserNamespace)
|
||||
if len(errs) == 0 {
|
||||
t.Fatal("expected error but received none")
|
||||
}
|
||||
@ -9202,6 +9211,7 @@ func TestValidateContainers(t *testing.T) {
|
||||
|
||||
func TestValidateInitContainers(t *testing.T) {
|
||||
volumeDevices := make(map[string]core.VolumeSource)
|
||||
podOS := &core.PodOS{Name: core.OSName(v1.Linux)}
|
||||
capabilities.ResetForTest()
|
||||
capabilities.Initialize(capabilities.Capabilities{
|
||||
AllowPrivileged: true,
|
||||
@ -9285,7 +9295,7 @@ func TestValidateInitContainers(t *testing.T) {
|
||||
},
|
||||
}
|
||||
var PodRestartPolicy core.RestartPolicy = "Never"
|
||||
if errs := validateInitContainers(successCase, containers, volumeDevices, nil, defaultGracePeriod, field.NewPath("field"), PodValidationOptions{AllowSidecarResizePolicy: true}, &PodRestartPolicy, noUserNamespace); len(errs) != 0 {
|
||||
if errs := validateInitContainers(successCase, podOS, containers, volumeDevices, nil, defaultGracePeriod, field.NewPath("field"), PodValidationOptions{AllowSidecarResizePolicy: true}, &PodRestartPolicy, noUserNamespace); len(errs) != 0 {
|
||||
t.Errorf("expected success: %v", errs)
|
||||
}
|
||||
|
||||
@ -9679,7 +9689,7 @@ func TestValidateInitContainers(t *testing.T) {
|
||||
|
||||
for _, tc := range errorCases {
|
||||
t.Run(tc.title+"__@L"+tc.line, func(t *testing.T) {
|
||||
errs := validateInitContainers(tc.initContainers, containers, volumeDevices, nil, defaultGracePeriod, field.NewPath("initContainers"), PodValidationOptions{}, &PodRestartPolicy, noUserNamespace)
|
||||
errs := validateInitContainers(tc.initContainers, podOS, containers, volumeDevices, nil, defaultGracePeriod, field.NewPath("initContainers"), PodValidationOptions{}, &PodRestartPolicy, noUserNamespace)
|
||||
if len(errs) == 0 {
|
||||
t.Fatal("expected error but received none")
|
||||
}
|
||||
@ -11051,6 +11061,22 @@ func TestValidatePod(t *testing.T) {
|
||||
},
|
||||
}),
|
||||
),
|
||||
"Pod with valid StopSignal and valid OS": *podtest.MakePod("test-pod",
|
||||
podtest.SetOS(core.Linux),
|
||||
podtest.SetContainers(podtest.MakeContainer(
|
||||
"test-container",
|
||||
podtest.SetContainerImage("image"),
|
||||
podtest.SetContainerLifecycle(core.Lifecycle{StopSignal: ptr.To(core.SIGTERM)}),
|
||||
)),
|
||||
),
|
||||
"Pod with valid StopSignal and valid OS (Windows)": *podtest.MakePod("test-pod",
|
||||
podtest.SetOS(core.Windows),
|
||||
podtest.SetContainers(podtest.MakeContainer(
|
||||
"test-container",
|
||||
podtest.SetContainerImage("image"),
|
||||
podtest.SetContainerLifecycle(core.Lifecycle{StopSignal: ptr.To(core.SIGTERM)}),
|
||||
)),
|
||||
),
|
||||
}
|
||||
|
||||
for k, v := range successCases {
|
||||
@ -12390,6 +12416,27 @@ func TestValidatePod(t *testing.T) {
|
||||
}),
|
||||
),
|
||||
},
|
||||
"Pod with a StopSignal without `spec.os.name`": {
|
||||
expectedError: "spec.containers[0].lifecycle.stopSignal: Forbidden: may not be set for containers with empty `spec.os.name`",
|
||||
spec: *podtest.MakePod("test-pod",
|
||||
podtest.SetContainers(podtest.MakeContainer(
|
||||
"test-container",
|
||||
podtest.SetContainerImage("image"),
|
||||
podtest.SetContainerLifecycle(core.Lifecycle{StopSignal: ptr.To(core.SIGTERM)}),
|
||||
)),
|
||||
),
|
||||
},
|
||||
"Pod with a StopSignal not supported by OS": {
|
||||
expectedError: "spec.containers[0].lifecycle.stopSignal: Unsupported value: \"SIGHUP\": supported values: \"SIGKILL\", \"SIGTERM\"",
|
||||
spec: *podtest.MakePod("test-pod",
|
||||
podtest.SetOS(core.Windows),
|
||||
podtest.SetContainers(podtest.MakeContainer(
|
||||
"test-container",
|
||||
podtest.SetContainerImage("image"),
|
||||
podtest.SetContainerLifecycle(core.Lifecycle{StopSignal: ptr.To(core.SIGHUP)}),
|
||||
)),
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
for k, v := range errorCases {
|
||||
@ -26968,3 +27015,58 @@ func TestValidateNodeSwapStatus(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateStopSignal(t *testing.T) {
|
||||
fldPath := field.NewPath("root")
|
||||
sigkill := core.SIGKILL
|
||||
sigterm := core.SIGTERM
|
||||
sighup := core.SIGHUP
|
||||
linux := core.PodOS{Name: core.Linux}
|
||||
windows := core.PodOS{Name: core.Windows}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
stopsignal *core.Signal
|
||||
os *core.PodOS
|
||||
expectErr field.ErrorList
|
||||
}{
|
||||
{
|
||||
name: "Empty spec.os.name",
|
||||
stopsignal: &sigterm,
|
||||
os: nil,
|
||||
expectErr: field.ErrorList{field.Forbidden(fldPath, "may not be set for containers with empty `spec.os.name`")},
|
||||
},
|
||||
{
|
||||
name: "Invalid signal passed to windows pod",
|
||||
stopsignal: &sighup,
|
||||
os: &windows,
|
||||
expectErr: field.ErrorList{field.NotSupported(fldPath, &sighup, sets.List(supportedStopSignalsWindows))},
|
||||
},
|
||||
{
|
||||
name: "Valid signal passed to windows pod",
|
||||
stopsignal: &sigkill,
|
||||
os: &windows,
|
||||
},
|
||||
{
|
||||
name: "Valid signal passed to linux pod",
|
||||
stopsignal: &sighup,
|
||||
os: &linux,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
errs := validateStopSignal(tc.stopsignal, fldPath, tc.os)
|
||||
|
||||
if len(tc.expectErr) > 0 && len(errs) == 0 {
|
||||
t.Errorf("Unexpected success")
|
||||
} else if len(tc.expectErr) == 0 && len(errs) != 0 {
|
||||
t.Errorf("Unexpected error(s): %v", errs)
|
||||
} else if len(tc.expectErr) > 0 {
|
||||
if tc.expectErr[0].Error() != errs[0].Error() {
|
||||
t.Errorf("Unexpected error(s): %v", errs)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user