mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 10:51:29 +00:00
Promote PodOS field to GA
This commit is contained in:
parent
5108b0a3a0
commit
b79ebb8165
@ -418,8 +418,6 @@ func GetValidationOptionsFromPodSpecAndMeta(podSpec, oldPodSpec *api.PodSpec, po
|
||||
AllowWindowsHostProcessField: utilfeature.DefaultFeatureGate.Enabled(features.WindowsHostProcessContainers),
|
||||
// Allow pod spec with expanded DNS configuration
|
||||
AllowExpandedDNSConfig: utilfeature.DefaultFeatureGate.Enabled(features.ExpandedDNSConfig) || haveSameExpandedDNSConfig(podSpec, oldPodSpec),
|
||||
// Allow pod spec to use OS field
|
||||
AllowOSField: utilfeature.DefaultFeatureGate.Enabled(features.IdentifyPodOS),
|
||||
}
|
||||
|
||||
if oldPodSpec != nil {
|
||||
@ -435,9 +433,6 @@ func GetValidationOptionsFromPodSpecAndMeta(podSpec, oldPodSpec *api.PodSpec, po
|
||||
// if old spec has Windows Host Process fields set, we must allow it
|
||||
opts.AllowWindowsHostProcessField = opts.AllowWindowsHostProcessField || setsWindowsHostProcess(oldPodSpec)
|
||||
|
||||
// if old spec has OS field set, we must allow it
|
||||
opts.AllowOSField = opts.AllowOSField || oldPodSpec.OS != nil
|
||||
|
||||
// if old spec used non-integer multiple of huge page unit size, we must allow it
|
||||
opts.AllowIndivisibleHugePagesValues = usesIndivisibleHugePagesValues(oldPodSpec)
|
||||
|
||||
@ -556,10 +551,6 @@ func dropDisabledFields(
|
||||
|
||||
dropDisabledCSIVolumeSourceAlphaFields(podSpec, oldPodSpec)
|
||||
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.IdentifyPodOS) && !podOSInUse(oldPodSpec) {
|
||||
podSpec.OS = nil
|
||||
}
|
||||
|
||||
dropDisabledTopologySpreadConstraintsFields(podSpec, oldPodSpec)
|
||||
dropDisabledNodeInclusionPolicyFields(podSpec, oldPodSpec)
|
||||
}
|
||||
@ -591,17 +582,6 @@ func minDomainsInUse(podSpec *api.PodSpec) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// podOSInUse returns true if the pod spec is non-nil and has OS field set
|
||||
func podOSInUse(podSpec *api.PodSpec) bool {
|
||||
if podSpec == nil {
|
||||
return false
|
||||
}
|
||||
if podSpec.OS != nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// dropDisabledProcMountField removes disabled fields from PodSpec related
|
||||
// to ProcMount only if it is not already used by the old spec
|
||||
func dropDisabledProcMountField(podSpec, oldPodSpec *api.PodSpec) {
|
||||
|
@ -1687,88 +1687,6 @@ func TestDropDisabledTopologySpreadConstraintsFields(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDropOSField(t *testing.T) {
|
||||
podWithOSField := func() *api.Pod {
|
||||
osField := api.PodOS{Name: "linux"}
|
||||
return &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
OS: &osField,
|
||||
},
|
||||
}
|
||||
}
|
||||
podWithoutOSField := func() *api.Pod { return &api.Pod{} }
|
||||
podInfo := []struct {
|
||||
description string
|
||||
hasPodOSField bool
|
||||
pod func() *api.Pod
|
||||
}{
|
||||
{
|
||||
description: "has PodOS field",
|
||||
hasPodOSField: true,
|
||||
pod: podWithOSField,
|
||||
},
|
||||
{
|
||||
description: "does not have PodOS field",
|
||||
hasPodOSField: false,
|
||||
pod: podWithoutOSField,
|
||||
},
|
||||
{
|
||||
description: "is nil",
|
||||
hasPodOSField: false,
|
||||
pod: func() *api.Pod { return nil },
|
||||
},
|
||||
}
|
||||
|
||||
for _, enabled := range []bool{true, false} {
|
||||
for _, oldPodInfo := range podInfo {
|
||||
for _, newPodInfo := range podInfo {
|
||||
oldPodHasOsField, oldPod := oldPodInfo.hasPodOSField, oldPodInfo.pod()
|
||||
newPodHasOSField, newPod := newPodInfo.hasPodOSField, 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.IdentifyPodOS, 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 || oldPodHasOsField:
|
||||
// new pod should not be changed if the feature is enabled, or if the old pod had subpaths
|
||||
if !reflect.DeepEqual(newPod, newPodInfo.pod()) {
|
||||
t.Errorf("new pod changed: %v", cmp.Diff(newPod, newPodInfo.pod()))
|
||||
}
|
||||
case newPodHasOSField:
|
||||
// new pod should be changed
|
||||
if reflect.DeepEqual(newPod, newPodInfo.pod()) {
|
||||
t.Errorf("new pod was not changed")
|
||||
}
|
||||
// new pod should not have OSfield
|
||||
if !reflect.DeepEqual(newPod, podWithoutOSField()) {
|
||||
t.Errorf("new pod has OS field: %v", cmp.Diff(newPod, podWithoutOSField()))
|
||||
}
|
||||
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 TestDropNodeInclusionPolicyFields(t *testing.T) {
|
||||
ignore := api.NodeInclusionPolicyIgnore
|
||||
honor := api.NodeInclusionPolicyHonor
|
||||
|
@ -3396,8 +3396,6 @@ type PodValidationOptions struct {
|
||||
AllowWindowsHostProcessField bool
|
||||
// Allow more DNSSearchPaths and longer DNSSearchListChars
|
||||
AllowExpandedDNSConfig bool
|
||||
// Allow OSField to be set in the pod spec
|
||||
AllowOSField bool
|
||||
}
|
||||
|
||||
// validatePodMetadataAndSpec tests if required fields in the pod.metadata and pod.spec are set,
|
||||
@ -6345,9 +6343,6 @@ func validateOS(podSpec *core.PodSpec, fldPath *field.Path, opts PodValidationOp
|
||||
if os == nil {
|
||||
return allErrs
|
||||
}
|
||||
if !opts.AllowOSField {
|
||||
return append(allErrs, field.Forbidden(fldPath, "cannot be set when IdentifyPodOS feature is not enabled"))
|
||||
}
|
||||
if len(os.Name) == 0 {
|
||||
return append(allErrs, field.Required(fldPath.Child("name"), "cannot be empty"))
|
||||
}
|
||||
|
@ -6851,40 +6851,24 @@ func TestValidateWindowsPodSecurityContext(t *testing.T) {
|
||||
validWindowsSC := &core.PodSecurityContext{WindowsOptions: &core.WindowsSecurityContextOptions{RunAsUserName: utilpointer.String("dummy")}}
|
||||
invalidWindowsSC := &core.PodSecurityContext{SELinuxOptions: &core.SELinuxOptions{Role: "dummyRole"}}
|
||||
cases := map[string]struct {
|
||||
podSec *core.PodSpec
|
||||
expectErr bool
|
||||
errorType field.ErrorType
|
||||
errorDetail string
|
||||
featureEnabled bool
|
||||
podSec *core.PodSpec
|
||||
expectErr bool
|
||||
errorType field.ErrorType
|
||||
errorDetail string
|
||||
}{
|
||||
"valid SC, windows, no error": {
|
||||
podSec: &core.PodSpec{SecurityContext: validWindowsSC},
|
||||
expectErr: false,
|
||||
featureEnabled: true,
|
||||
podSec: &core.PodSpec{SecurityContext: validWindowsSC},
|
||||
expectErr: false,
|
||||
},
|
||||
"invalid SC, windows, error": {
|
||||
podSec: &core.PodSpec{SecurityContext: invalidWindowsSC},
|
||||
errorType: "FieldValueForbidden",
|
||||
errorDetail: "cannot be set for a windows pod",
|
||||
expectErr: true,
|
||||
featureEnabled: true,
|
||||
},
|
||||
"valid SC, windows, no error, no IdentifyPodOS featuregate": {
|
||||
podSec: &core.PodSpec{SecurityContext: validWindowsSC},
|
||||
expectErr: false,
|
||||
featureEnabled: false,
|
||||
},
|
||||
"invalid SC, windows, error, no IdentifyPodOS featuregate": {
|
||||
podSec: &core.PodSpec{SecurityContext: invalidWindowsSC},
|
||||
errorType: "FieldValueForbidden",
|
||||
errorDetail: "cannot be set for a windows pod",
|
||||
expectErr: true,
|
||||
featureEnabled: false,
|
||||
podSec: &core.PodSpec{SecurityContext: invalidWindowsSC},
|
||||
errorType: "FieldValueForbidden",
|
||||
errorDetail: "cannot be set for a windows pod",
|
||||
expectErr: true,
|
||||
},
|
||||
}
|
||||
for k, v := range cases {
|
||||
t.Run(k, func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.IdentifyPodOS, v.featureEnabled)()
|
||||
errs := validateWindows(v.podSec, field.NewPath("field"))
|
||||
if v.expectErr && len(errs) > 0 {
|
||||
if errs[0].Type != v.errorType || !strings.Contains(errs[0].Detail, v.errorDetail) {
|
||||
@ -6916,40 +6900,24 @@ func TestValidateLinuxPodSecurityContext(t *testing.T) {
|
||||
}
|
||||
|
||||
cases := map[string]struct {
|
||||
podSpec *core.PodSpec
|
||||
expectErr bool
|
||||
errorType field.ErrorType
|
||||
errorDetail string
|
||||
featureEnabled bool
|
||||
podSpec *core.PodSpec
|
||||
expectErr bool
|
||||
errorType field.ErrorType
|
||||
errorDetail string
|
||||
}{
|
||||
"valid SC, linux, no error": {
|
||||
podSpec: &core.PodSpec{SecurityContext: validLinuxSC},
|
||||
expectErr: false,
|
||||
featureEnabled: true,
|
||||
podSpec: &core.PodSpec{SecurityContext: validLinuxSC},
|
||||
expectErr: false,
|
||||
},
|
||||
"invalid SC, linux, error": {
|
||||
podSpec: &core.PodSpec{SecurityContext: invalidLinuxSC},
|
||||
errorType: "FieldValueForbidden",
|
||||
errorDetail: "windows options cannot be set for a linux pod",
|
||||
expectErr: true,
|
||||
featureEnabled: true,
|
||||
},
|
||||
"valid SC, linux, no error, no IdentifyPodOS featuregate": {
|
||||
podSpec: &core.PodSpec{SecurityContext: validLinuxSC},
|
||||
expectErr: false,
|
||||
featureEnabled: false,
|
||||
},
|
||||
"invalid SC, linux, error, no IdentifyPodOS featuregate": {
|
||||
podSpec: &core.PodSpec{SecurityContext: invalidLinuxSC},
|
||||
errorType: "FieldValueForbidden",
|
||||
errorDetail: "windows options cannot be set for a linux pod",
|
||||
expectErr: true,
|
||||
featureEnabled: false,
|
||||
podSpec: &core.PodSpec{SecurityContext: invalidLinuxSC},
|
||||
errorType: "FieldValueForbidden",
|
||||
errorDetail: "windows options cannot be set for a linux pod",
|
||||
expectErr: true,
|
||||
},
|
||||
}
|
||||
for k, v := range cases {
|
||||
t.Run(k, func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.IdentifyPodOS, v.featureEnabled)()
|
||||
errs := validateLinux(v.podSpec, field.NewPath("field"))
|
||||
if v.expectErr && len(errs) > 0 {
|
||||
if errs[0].Type != v.errorType || !strings.Contains(errs[0].Detail, v.errorDetail) {
|
||||
@ -9964,11 +9932,10 @@ func TestValidatePodUpdate(t *testing.T) {
|
||||
)
|
||||
|
||||
tests := []struct {
|
||||
new core.Pod
|
||||
old core.Pod
|
||||
err string
|
||||
test string
|
||||
enablePodOS bool
|
||||
new core.Pod
|
||||
old core.Pod
|
||||
err string
|
||||
test string
|
||||
}{
|
||||
{new: core.Pod{}, old: core.Pod{}, err: "", test: "nothing"},
|
||||
{
|
||||
@ -10792,9 +10759,8 @@ func TestValidatePodUpdate(t *testing.T) {
|
||||
SecurityContext: &core.PodSecurityContext{SELinuxOptions: &core.SELinuxOptions{Role: "dummy"}},
|
||||
},
|
||||
},
|
||||
err: "Forbidden: pod updates may not change fields other than `spec.containers[*].image`,",
|
||||
test: "pod OS changing from Linux to Windows, no IdentifyPodOS featuregate set, no validation done",
|
||||
enablePodOS: false,
|
||||
err: "Forbidden: pod updates may not change fields other than `spec.containers[*].image",
|
||||
test: "pod OS changing from Linux to Windows, IdentifyPodOS featuregate set",
|
||||
},
|
||||
{
|
||||
new: core.Pod{
|
||||
@ -10815,32 +10781,8 @@ func TestValidatePodUpdate(t *testing.T) {
|
||||
SecurityContext: &core.PodSecurityContext{SELinuxOptions: &core.SELinuxOptions{Role: "dummy"}},
|
||||
},
|
||||
},
|
||||
err: "Forbidden: pod updates may not change fields other than `spec.containers[*].image",
|
||||
test: "pod OS changing from Linux to Windows, IdentifyPodOS featuregate set",
|
||||
enablePodOS: true,
|
||||
},
|
||||
{
|
||||
new: core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
},
|
||||
Spec: core.PodSpec{
|
||||
OS: &core.PodOS{Name: core.Windows},
|
||||
SecurityContext: &core.PodSecurityContext{SELinuxOptions: &core.SELinuxOptions{Role: "dummy"}},
|
||||
},
|
||||
},
|
||||
old: core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
},
|
||||
Spec: core.PodSpec{
|
||||
OS: &core.PodOS{Name: core.Linux},
|
||||
SecurityContext: &core.PodSecurityContext{SELinuxOptions: &core.SELinuxOptions{Role: "dummy"}},
|
||||
},
|
||||
},
|
||||
err: "spec.securityContext.seLinuxOptions: Forbidden",
|
||||
test: "pod OS changing from Linux to Windows, IdentifyPodOS featuregate set, we'd get SELinux errors as well",
|
||||
enablePodOS: true,
|
||||
err: "spec.securityContext.seLinuxOptions: Forbidden",
|
||||
test: "pod OS changing from Linux to Windows, IdentifyPodOS featuregate set, we'd get SELinux errors as well",
|
||||
},
|
||||
{
|
||||
new: core.Pod{
|
||||
@ -10857,28 +10799,8 @@ func TestValidatePodUpdate(t *testing.T) {
|
||||
},
|
||||
Spec: core.PodSpec{},
|
||||
},
|
||||
err: "Forbidden: pod updates may not change fields other than `spec.containers[*].image",
|
||||
test: "invalid PodOS update, IdentifyPodOS featuregate set",
|
||||
enablePodOS: true,
|
||||
},
|
||||
{
|
||||
new: core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
},
|
||||
Spec: core.PodSpec{
|
||||
OS: &core.PodOS{Name: core.Windows},
|
||||
},
|
||||
},
|
||||
old: core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
},
|
||||
Spec: core.PodSpec{},
|
||||
},
|
||||
err: "Forbidden: pod updates may not change fields other than `spec.containers[*].image",
|
||||
test: "no pod spec OS to a valid value, no featuregate",
|
||||
enablePodOS: false,
|
||||
err: "Forbidden: pod updates may not change fields other than `spec.containers[*].image",
|
||||
test: "invalid PodOS update, IdentifyPodOS featuregate set",
|
||||
},
|
||||
{
|
||||
new: core.Pod{
|
||||
@ -10927,7 +10849,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
||||
test.old.Spec.RestartPolicy = "Always"
|
||||
}
|
||||
|
||||
errs := ValidatePodUpdate(&test.new, &test.old, PodValidationOptions{AllowOSField: test.enablePodOS})
|
||||
errs := ValidatePodUpdate(&test.new, &test.old, PodValidationOptions{})
|
||||
if test.err == "" {
|
||||
if len(errs) != 0 {
|
||||
t.Errorf("unexpected invalid: %s (%+v)\nA: %+v\nB: %+v", test.test, errs, test.new, test.old)
|
||||
@ -17504,61 +17426,34 @@ func TestValidateEndpointsUpdate(t *testing.T) {
|
||||
|
||||
func TestValidateWindowsSecurityContext(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
sc *core.PodSpec
|
||||
expectError bool
|
||||
errorMsg string
|
||||
errorType field.ErrorType
|
||||
featureEnabled bool
|
||||
name string
|
||||
sc *core.PodSpec
|
||||
expectError bool
|
||||
errorMsg string
|
||||
errorType field.ErrorType
|
||||
}{
|
||||
{
|
||||
name: "pod with SELinux Options",
|
||||
sc: &core.PodSpec{Containers: []core.Container{{SecurityContext: &core.SecurityContext{SELinuxOptions: &core.SELinuxOptions{Role: "dummy"}}}}},
|
||||
expectError: true,
|
||||
errorMsg: "cannot be set for a windows pod",
|
||||
errorType: "FieldValueForbidden",
|
||||
featureEnabled: true,
|
||||
name: "pod with SELinux Options",
|
||||
sc: &core.PodSpec{Containers: []core.Container{{SecurityContext: &core.SecurityContext{SELinuxOptions: &core.SELinuxOptions{Role: "dummy"}}}}},
|
||||
expectError: true,
|
||||
errorMsg: "cannot be set for a windows pod",
|
||||
errorType: "FieldValueForbidden",
|
||||
},
|
||||
{
|
||||
name: "pod with SeccompProfile",
|
||||
sc: &core.PodSpec{Containers: []core.Container{{SecurityContext: &core.SecurityContext{SeccompProfile: &core.SeccompProfile{LocalhostProfile: utilpointer.String("dummy")}}}}},
|
||||
expectError: true,
|
||||
errorMsg: "cannot be set for a windows pod",
|
||||
errorType: "FieldValueForbidden",
|
||||
featureEnabled: true,
|
||||
name: "pod with SeccompProfile",
|
||||
sc: &core.PodSpec{Containers: []core.Container{{SecurityContext: &core.SecurityContext{SeccompProfile: &core.SeccompProfile{LocalhostProfile: utilpointer.String("dummy")}}}}},
|
||||
expectError: true,
|
||||
errorMsg: "cannot be set for a windows pod",
|
||||
errorType: "FieldValueForbidden",
|
||||
},
|
||||
{
|
||||
name: "pod with WindowsOptions, no error",
|
||||
sc: &core.PodSpec{Containers: []core.Container{{SecurityContext: &core.SecurityContext{WindowsOptions: &core.WindowsSecurityContextOptions{RunAsUserName: utilpointer.String("dummy")}}}}},
|
||||
expectError: false,
|
||||
featureEnabled: true,
|
||||
},
|
||||
{
|
||||
name: "pod with SELinux Options, no IdentifyPodOS enabled",
|
||||
sc: &core.PodSpec{Containers: []core.Container{{SecurityContext: &core.SecurityContext{SELinuxOptions: &core.SELinuxOptions{Role: "dummy"}}}}},
|
||||
expectError: true,
|
||||
errorMsg: "cannot be set for a windows pod",
|
||||
errorType: "FieldValueForbidden",
|
||||
featureEnabled: false,
|
||||
},
|
||||
{
|
||||
name: "pod with SeccompProfile, no IdentifyPodOS enabled",
|
||||
sc: &core.PodSpec{Containers: []core.Container{{SecurityContext: &core.SecurityContext{SeccompProfile: &core.SeccompProfile{LocalhostProfile: utilpointer.String("dummy")}}}}},
|
||||
expectError: true,
|
||||
errorMsg: "cannot be set for a windows pod",
|
||||
errorType: "FieldValueForbidden",
|
||||
featureEnabled: false,
|
||||
},
|
||||
{
|
||||
name: "pod with WindowsOptions, no error, no IdentifyPodOS enabled",
|
||||
sc: &core.PodSpec{Containers: []core.Container{{SecurityContext: &core.SecurityContext{WindowsOptions: &core.WindowsSecurityContextOptions{RunAsUserName: utilpointer.String("dummy")}}}}},
|
||||
expectError: false,
|
||||
featureEnabled: false,
|
||||
name: "pod with WindowsOptions, no error",
|
||||
sc: &core.PodSpec{Containers: []core.Container{{SecurityContext: &core.SecurityContext{WindowsOptions: &core.WindowsSecurityContextOptions{RunAsUserName: utilpointer.String("dummy")}}}}},
|
||||
expectError: false,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.IdentifyPodOS, test.featureEnabled)()
|
||||
errs := validateWindows(test.sc, field.NewPath("field"))
|
||||
if test.expectError && len(errs) > 0 {
|
||||
if errs[0].Type != test.errorType {
|
||||
@ -17843,40 +17738,24 @@ func TestValidateLinuxSecurityContext(t *testing.T) {
|
||||
WindowsOptions: &core.WindowsSecurityContextOptions{RunAsUserName: utilpointer.String("myUser")},
|
||||
}
|
||||
cases := map[string]struct {
|
||||
sc *core.PodSpec
|
||||
expectErr bool
|
||||
errorType field.ErrorType
|
||||
errorDetail string
|
||||
featureEnabled bool
|
||||
sc *core.PodSpec
|
||||
expectErr bool
|
||||
errorType field.ErrorType
|
||||
errorDetail string
|
||||
}{
|
||||
"valid SC, linux, no error": {
|
||||
sc: &core.PodSpec{Containers: []core.Container{{SecurityContext: validLinuxSC}}},
|
||||
expectErr: false,
|
||||
featureEnabled: true,
|
||||
sc: &core.PodSpec{Containers: []core.Container{{SecurityContext: validLinuxSC}}},
|
||||
expectErr: false,
|
||||
},
|
||||
"invalid SC, linux, error": {
|
||||
sc: &core.PodSpec{Containers: []core.Container{{SecurityContext: invalidLinuxSC}}},
|
||||
errorType: "FieldValueForbidden",
|
||||
errorDetail: "windows options cannot be set for a linux pod",
|
||||
expectErr: true,
|
||||
featureEnabled: true,
|
||||
},
|
||||
"valid SC, linux, no error, no IdentifyPodOS featuregate": {
|
||||
sc: &core.PodSpec{Containers: []core.Container{{SecurityContext: validLinuxSC}}},
|
||||
expectErr: false,
|
||||
featureEnabled: false,
|
||||
},
|
||||
"invalid SC, linux, error, no IdentifyPodOS featuregate": {
|
||||
sc: &core.PodSpec{Containers: []core.Container{{SecurityContext: invalidLinuxSC}}},
|
||||
errorType: "FieldValueForbidden",
|
||||
errorDetail: "windows options cannot be set for a linux pod",
|
||||
expectErr: true,
|
||||
featureEnabled: false,
|
||||
sc: &core.PodSpec{Containers: []core.Container{{SecurityContext: invalidLinuxSC}}},
|
||||
errorType: "FieldValueForbidden",
|
||||
errorDetail: "windows options cannot be set for a linux pod",
|
||||
expectErr: true,
|
||||
},
|
||||
}
|
||||
for k, v := range cases {
|
||||
t.Run(k, func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.IdentifyPodOS, v.featureEnabled)()
|
||||
errs := validateLinux(v.sc, field.NewPath("field"))
|
||||
if v.expectErr && len(errs) > 0 {
|
||||
if errs[0].Type != v.errorType || !strings.Contains(errs[0].Detail, v.errorDetail) {
|
||||
@ -20377,83 +20256,44 @@ func TestValidateWindowsHostProcessPod(t *testing.T) {
|
||||
|
||||
func TestValidateOS(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
expectError bool
|
||||
featureEnabled bool
|
||||
podSpec *core.PodSpec
|
||||
name string
|
||||
expectError bool
|
||||
podSpec *core.PodSpec
|
||||
}{
|
||||
{
|
||||
name: "no OS field, featuregate",
|
||||
expectError: false,
|
||||
featureEnabled: true,
|
||||
podSpec: &core.PodSpec{OS: nil},
|
||||
name: "no OS field, featuregate",
|
||||
expectError: false,
|
||||
podSpec: &core.PodSpec{OS: nil},
|
||||
},
|
||||
{
|
||||
name: "empty OS field, featuregate",
|
||||
expectError: true,
|
||||
featureEnabled: true,
|
||||
podSpec: &core.PodSpec{OS: &core.PodOS{}},
|
||||
name: "empty OS field, featuregate",
|
||||
expectError: true,
|
||||
podSpec: &core.PodSpec{OS: &core.PodOS{}},
|
||||
},
|
||||
{
|
||||
name: "no OS field, no featuregate",
|
||||
expectError: false,
|
||||
featureEnabled: false,
|
||||
podSpec: &core.PodSpec{OS: nil},
|
||||
name: "OS field, featuregate, valid OS",
|
||||
expectError: false,
|
||||
podSpec: &core.PodSpec{OS: &core.PodOS{Name: core.Linux}},
|
||||
},
|
||||
{
|
||||
name: "empty OS field, no featuregate",
|
||||
expectError: true,
|
||||
featureEnabled: false,
|
||||
podSpec: &core.PodSpec{OS: &core.PodOS{}},
|
||||
name: "OS field, featuregate, valid OS",
|
||||
expectError: false,
|
||||
podSpec: &core.PodSpec{OS: &core.PodOS{Name: core.Windows}},
|
||||
},
|
||||
{
|
||||
name: "OS field, featuregate, valid OS",
|
||||
expectError: false,
|
||||
featureEnabled: true,
|
||||
podSpec: &core.PodSpec{OS: &core.PodOS{Name: core.Linux}},
|
||||
name: "OS field, featuregate, empty OS",
|
||||
expectError: true,
|
||||
podSpec: &core.PodSpec{OS: &core.PodOS{Name: ""}},
|
||||
},
|
||||
{
|
||||
name: "OS field, featuregate, valid OS",
|
||||
expectError: false,
|
||||
featureEnabled: true,
|
||||
podSpec: &core.PodSpec{OS: &core.PodOS{Name: core.Windows}},
|
||||
},
|
||||
{
|
||||
name: "OS field, featuregate, empty OS",
|
||||
expectError: true,
|
||||
featureEnabled: true,
|
||||
podSpec: &core.PodSpec{OS: &core.PodOS{Name: ""}},
|
||||
},
|
||||
{
|
||||
name: "OS field, no featuregate, empty OS",
|
||||
expectError: true,
|
||||
featureEnabled: false,
|
||||
podSpec: &core.PodSpec{OS: &core.PodOS{Name: ""}},
|
||||
},
|
||||
{
|
||||
name: "OS field, featuregate, invalid OS",
|
||||
expectError: true,
|
||||
featureEnabled: true,
|
||||
podSpec: &core.PodSpec{OS: &core.PodOS{Name: "dummyOS"}},
|
||||
},
|
||||
{
|
||||
name: "OS field, no featuregate, valid OS",
|
||||
expectError: true,
|
||||
featureEnabled: false,
|
||||
podSpec: &core.PodSpec{OS: &core.PodOS{Name: core.Linux}},
|
||||
},
|
||||
{
|
||||
name: "OS field, no featuregate, invalid OS",
|
||||
expectError: true,
|
||||
featureEnabled: false,
|
||||
podSpec: &core.PodSpec{OS: &core.PodOS{Name: "dummyOS"}},
|
||||
name: "OS field, featuregate, invalid OS",
|
||||
expectError: true,
|
||||
podSpec: &core.PodSpec{OS: &core.PodOS{Name: "dummyOS"}},
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.IdentifyPodOS, testCase.featureEnabled)()
|
||||
|
||||
errs := validateOS(testCase.podSpec, field.NewPath("spec"), PodValidationOptions{AllowOSField: testCase.featureEnabled})
|
||||
errs := validateOS(testCase.podSpec, field.NewPath("spec"), PodValidationOptions{})
|
||||
if testCase.expectError && len(errs) == 0 {
|
||||
t.Errorf("Unexpected success")
|
||||
}
|
||||
|
@ -374,6 +374,7 @@ const (
|
||||
// owner: @ravig
|
||||
// alpha: v1.23
|
||||
// beta: v1.24
|
||||
// GA: v1.25
|
||||
// IdentifyPodOS allows user to specify OS on which they'd like the Pod run. The user should still set the nodeSelector
|
||||
// with appropriate `kubernetes.io/os` label for scheduler to identify appropriate node for the pod to run.
|
||||
IdentifyPodOS featuregate.Feature = "IdentifyPodOS"
|
||||
@ -904,7 +905,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
|
||||
|
||||
HonorPVReclaimPolicy: {Default: false, PreRelease: featuregate.Alpha},
|
||||
|
||||
IdentifyPodOS: {Default: true, PreRelease: featuregate.Beta},
|
||||
IdentifyPodOS: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.27
|
||||
|
||||
InTreePluginAWSUnregister: {Default: false, PreRelease: featuregate.Alpha},
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user