Graduate ReadWriteOncePod to GA
This commit is contained in:
		| @@ -1653,33 +1653,20 @@ var allowedTemplateObjectMetaFields = map[string]bool{ | ||||
|  | ||||
| // PersistentVolumeSpecValidationOptions contains the different settings for PeristentVolume validation | ||||
| type PersistentVolumeSpecValidationOptions struct { | ||||
| 	// Allow spec to contain the "ReadWiteOncePod" access mode | ||||
| 	AllowReadWriteOncePod bool | ||||
| } | ||||
|  | ||||
| // ValidatePersistentVolumeName checks that a name is appropriate for a | ||||
| // PersistentVolumeName object. | ||||
| var ValidatePersistentVolumeName = apimachineryvalidation.NameIsDNSSubdomain | ||||
|  | ||||
| var supportedAccessModes = sets.NewString(string(core.ReadWriteOnce), string(core.ReadOnlyMany), string(core.ReadWriteMany)) | ||||
| var supportedAccessModes = sets.NewString(string(core.ReadWriteOnce), string(core.ReadOnlyMany), string(core.ReadWriteMany), string(core.ReadWriteOncePod)) | ||||
|  | ||||
| var supportedReclaimPolicy = sets.NewString(string(core.PersistentVolumeReclaimDelete), string(core.PersistentVolumeReclaimRecycle), string(core.PersistentVolumeReclaimRetain)) | ||||
|  | ||||
| var supportedVolumeModes = sets.NewString(string(core.PersistentVolumeBlock), string(core.PersistentVolumeFilesystem)) | ||||
|  | ||||
| func ValidationOptionsForPersistentVolume(pv, oldPv *core.PersistentVolume) PersistentVolumeSpecValidationOptions { | ||||
| 	opts := PersistentVolumeSpecValidationOptions{ | ||||
| 		AllowReadWriteOncePod: utilfeature.DefaultFeatureGate.Enabled(features.ReadWriteOncePod), | ||||
| 	} | ||||
| 	if oldPv == nil { | ||||
| 		// If there's no old PV, use the options based solely on feature enablement | ||||
| 		return opts | ||||
| 	} | ||||
| 	if helper.ContainsAccessMode(oldPv.Spec.AccessModes, core.ReadWriteOncePod) { | ||||
| 		// If the old object allowed "ReadWriteOncePod", continue to allow it in the new object | ||||
| 		opts.AllowReadWriteOncePod = true | ||||
| 	} | ||||
| 	return opts | ||||
| 	return PersistentVolumeSpecValidationOptions{} | ||||
| } | ||||
|  | ||||
| func ValidatePersistentVolumeSpec(pvSpec *core.PersistentVolumeSpec, pvName string, validateInlinePersistentVolumeSpec bool, fldPath *field.Path, opts PersistentVolumeSpecValidationOptions) field.ErrorList { | ||||
| @@ -1701,15 +1688,10 @@ func ValidatePersistentVolumeSpec(pvSpec *core.PersistentVolumeSpec, pvName stri | ||||
| 		allErrs = append(allErrs, field.Required(fldPath.Child("accessModes"), "")) | ||||
| 	} | ||||
|  | ||||
| 	expandedSupportedAccessModes := sets.StringKeySet(supportedAccessModes) | ||||
| 	if opts.AllowReadWriteOncePod { | ||||
| 		expandedSupportedAccessModes.Insert(string(core.ReadWriteOncePod)) | ||||
| 	} | ||||
|  | ||||
| 	foundReadWriteOncePod, foundNonReadWriteOncePod := false, false | ||||
| 	for _, mode := range pvSpec.AccessModes { | ||||
| 		if !expandedSupportedAccessModes.Has(string(mode)) { | ||||
| 			allErrs = append(allErrs, field.NotSupported(fldPath.Child("accessModes"), mode, expandedSupportedAccessModes.List())) | ||||
| 		if !supportedAccessModes.Has(string(mode)) { | ||||
| 			allErrs = append(allErrs, field.NotSupported(fldPath.Child("accessModes"), mode, supportedAccessModes.List())) | ||||
| 		} | ||||
|  | ||||
| 		if mode == core.ReadWriteOncePod { | ||||
| @@ -2016,8 +1998,6 @@ func ValidatePersistentVolumeStatusUpdate(newPv, oldPv *core.PersistentVolume) f | ||||
| } | ||||
|  | ||||
| type PersistentVolumeClaimSpecValidationOptions struct { | ||||
| 	// Allow spec to contain the "ReadWiteOncePod" access mode | ||||
| 	AllowReadWriteOncePod bool | ||||
| 	// Allow users to recover from previously failing expansion operation | ||||
| 	EnableRecoverFromExpansionFailure bool | ||||
| 	// Allow to validate the label value of the label selector | ||||
| @@ -2028,7 +2008,6 @@ type PersistentVolumeClaimSpecValidationOptions struct { | ||||
|  | ||||
| func ValidationOptionsForPersistentVolumeClaim(pvc, oldPvc *core.PersistentVolumeClaim) PersistentVolumeClaimSpecValidationOptions { | ||||
| 	opts := PersistentVolumeClaimSpecValidationOptions{ | ||||
| 		AllowReadWriteOncePod:             utilfeature.DefaultFeatureGate.Enabled(features.ReadWriteOncePod), | ||||
| 		EnableRecoverFromExpansionFailure: utilfeature.DefaultFeatureGate.Enabled(features.RecoverVolumeExpansionFailure), | ||||
| 		AllowInvalidLabelValueInSelector:  false, | ||||
| 	} | ||||
| @@ -2048,11 +2027,6 @@ func ValidationOptionsForPersistentVolumeClaim(pvc, oldPvc *core.PersistentVolum | ||||
| 		opts.AllowInvalidLabelValueInSelector = true | ||||
| 	} | ||||
|  | ||||
| 	if helper.ContainsAccessMode(oldPvc.Spec.AccessModes, core.ReadWriteOncePod) { | ||||
| 		// If the old object allowed "ReadWriteOncePod", continue to allow it in the new object | ||||
| 		opts.AllowReadWriteOncePod = true | ||||
| 	} | ||||
|  | ||||
| 	if helper.ClaimContainsAllocatedResources(oldPvc) || | ||||
| 		helper.ClaimContainsAllocatedResourceStatus(oldPvc) { | ||||
| 		opts.EnableRecoverFromExpansionFailure = true | ||||
| @@ -2062,7 +2036,6 @@ func ValidationOptionsForPersistentVolumeClaim(pvc, oldPvc *core.PersistentVolum | ||||
|  | ||||
| func ValidationOptionsForPersistentVolumeClaimTemplate(claimTemplate, oldClaimTemplate *core.PersistentVolumeClaimTemplate) PersistentVolumeClaimSpecValidationOptions { | ||||
| 	opts := PersistentVolumeClaimSpecValidationOptions{ | ||||
| 		AllowReadWriteOncePod:            utilfeature.DefaultFeatureGate.Enabled(features.ReadWriteOncePod), | ||||
| 		AllowInvalidLabelValueInSelector: false, | ||||
| 	} | ||||
| 	if oldClaimTemplate == nil { | ||||
| @@ -2076,10 +2049,6 @@ func ValidationOptionsForPersistentVolumeClaimTemplate(claimTemplate, oldClaimTe | ||||
| 		// If the old object had an invalid label selector, continue to allow it in the new object | ||||
| 		opts.AllowInvalidLabelValueInSelector = true | ||||
| 	} | ||||
| 	if helper.ContainsAccessMode(oldClaimTemplate.Spec.AccessModes, core.ReadWriteOncePod) { | ||||
| 		// If the old object allowed "ReadWriteOncePod", continue to allow it in the new object | ||||
| 		opts.AllowReadWriteOncePod = true | ||||
| 	} | ||||
| 	return opts | ||||
| } | ||||
|  | ||||
| @@ -2172,15 +2141,10 @@ func ValidatePersistentVolumeClaimSpec(spec *core.PersistentVolumeClaimSpec, fld | ||||
| 		allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(spec.Selector, labelSelectorValidationOpts, fldPath.Child("selector"))...) | ||||
| 	} | ||||
|  | ||||
| 	expandedSupportedAccessModes := sets.StringKeySet(supportedAccessModes) | ||||
| 	if opts.AllowReadWriteOncePod { | ||||
| 		expandedSupportedAccessModes.Insert(string(core.ReadWriteOncePod)) | ||||
| 	} | ||||
|  | ||||
| 	foundReadWriteOncePod, foundNonReadWriteOncePod := false, false | ||||
| 	for _, mode := range spec.AccessModes { | ||||
| 		if !expandedSupportedAccessModes.Has(string(mode)) { | ||||
| 			allErrs = append(allErrs, field.NotSupported(fldPath.Child("accessModes"), mode, expandedSupportedAccessModes.List())) | ||||
| 		if !supportedAccessModes.Has(string(mode)) { | ||||
| 			allErrs = append(allErrs, field.NotSupported(fldPath.Child("accessModes"), mode, supportedAccessModes.List())) | ||||
| 		} | ||||
|  | ||||
| 		if mode == core.ReadWriteOncePod { | ||||
|   | ||||
| @@ -109,9 +109,8 @@ func TestValidatePersistentVolumes(t *testing.T) { | ||||
| 	validMode := core.PersistentVolumeFilesystem | ||||
| 	invalidMode := core.PersistentVolumeMode("fakeVolumeMode") | ||||
| 	scenarios := map[string]struct { | ||||
| 		isExpectedFailure      bool | ||||
| 		enableReadWriteOncePod bool | ||||
| 		volume                 *core.PersistentVolume | ||||
| 		isExpectedFailure bool | ||||
| 		volume            *core.PersistentVolume | ||||
| 	}{ | ||||
| 		"good-volume": { | ||||
| 			isExpectedFailure: false, | ||||
| @@ -253,9 +252,8 @@ func TestValidatePersistentVolumes(t *testing.T) { | ||||
| 				VolumeMode: &invalidMode, | ||||
| 			}), | ||||
| 		}, | ||||
| 		"with-read-write-once-pod-feature-gate-enabled": { | ||||
| 			isExpectedFailure:      false, | ||||
| 			enableReadWriteOncePod: true, | ||||
| 		"with-read-write-once-pod": { | ||||
| 			isExpectedFailure: false, | ||||
| 			volume: testVolume("foo", "", core.PersistentVolumeSpec{ | ||||
| 				Capacity: core.ResourceList{ | ||||
| 					core.ResourceName(core.ResourceStorage): resource.MustParse("10G"), | ||||
| @@ -269,25 +267,8 @@ func TestValidatePersistentVolumes(t *testing.T) { | ||||
| 				}, | ||||
| 			}), | ||||
| 		}, | ||||
| 		"with-read-write-once-pod-feature-gate-disabled": { | ||||
| 			isExpectedFailure:      true, | ||||
| 			enableReadWriteOncePod: false, | ||||
| 			volume: testVolume("foo", "", core.PersistentVolumeSpec{ | ||||
| 				Capacity: core.ResourceList{ | ||||
| 					core.ResourceName(core.ResourceStorage): resource.MustParse("10G"), | ||||
| 				}, | ||||
| 				AccessModes: []core.PersistentVolumeAccessMode{"ReadWriteOncePod"}, | ||||
| 				PersistentVolumeSource: core.PersistentVolumeSource{ | ||||
| 					HostPath: &core.HostPathVolumeSource{ | ||||
| 						Path: "/foo", | ||||
| 						Type: newHostPathType(string(core.HostPathDirectory)), | ||||
| 					}, | ||||
| 				}, | ||||
| 			}), | ||||
| 		}, | ||||
| 		"with-read-write-once-pod-and-others-feature-gate-enabled": { | ||||
| 			isExpectedFailure:      true, | ||||
| 			enableReadWriteOncePod: true, | ||||
| 		"with-read-write-once-pod-and-others": { | ||||
| 			isExpectedFailure: true, | ||||
| 			volume: testVolume("foo", "", core.PersistentVolumeSpec{ | ||||
| 				Capacity: core.ResourceList{ | ||||
| 					core.ResourceName(core.ResourceStorage): resource.MustParse("10G"), | ||||
| @@ -501,8 +482,6 @@ func TestValidatePersistentVolumes(t *testing.T) { | ||||
|  | ||||
| 	for name, scenario := range scenarios { | ||||
| 		t.Run(name, func(t *testing.T) { | ||||
| 			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, scenario.enableReadWriteOncePod)() | ||||
|  | ||||
| 			opts := ValidationOptionsForPersistentVolume(scenario.volume, nil) | ||||
| 			errs := ValidatePersistentVolume(scenario.volume, opts) | ||||
| 			if len(errs) == 0 && scenario.isExpectedFailure { | ||||
| @@ -903,51 +882,17 @@ func TestValidatePersistentVolumeSourceUpdate(t *testing.T) { | ||||
|  | ||||
| func TestValidationOptionsForPersistentVolume(t *testing.T) { | ||||
| 	tests := map[string]struct { | ||||
| 		oldPv                  *core.PersistentVolume | ||||
| 		enableReadWriteOncePod bool | ||||
| 		expectValidationOpts   PersistentVolumeSpecValidationOptions | ||||
| 		oldPv                *core.PersistentVolume | ||||
| 		expectValidationOpts PersistentVolumeSpecValidationOptions | ||||
| 	}{ | ||||
| 		"nil old pv": { | ||||
| 			oldPv:                  nil, | ||||
| 			enableReadWriteOncePod: true, | ||||
| 			expectValidationOpts: PersistentVolumeSpecValidationOptions{ | ||||
| 				AllowReadWriteOncePod: true, | ||||
| 			}, | ||||
| 		}, | ||||
| 		"rwop allowed because feature enabled": { | ||||
| 			oldPv:                  pvWithAccessModes([]core.PersistentVolumeAccessMode{core.ReadWriteOnce}), | ||||
| 			enableReadWriteOncePod: true, | ||||
| 			expectValidationOpts: PersistentVolumeSpecValidationOptions{ | ||||
| 				AllowReadWriteOncePod: true, | ||||
| 			}, | ||||
| 		}, | ||||
| 		"rwop not allowed because not used and feature disabled": { | ||||
| 			oldPv:                  pvWithAccessModes([]core.PersistentVolumeAccessMode{core.ReadWriteOnce}), | ||||
| 			enableReadWriteOncePod: false, | ||||
| 			expectValidationOpts: PersistentVolumeSpecValidationOptions{ | ||||
| 				AllowReadWriteOncePod: false, | ||||
| 			}, | ||||
| 		}, | ||||
| 		"rwop allowed because used and feature enabled": { | ||||
| 			oldPv:                  pvWithAccessModes([]core.PersistentVolumeAccessMode{core.ReadWriteOncePod}), | ||||
| 			enableReadWriteOncePod: true, | ||||
| 			expectValidationOpts: PersistentVolumeSpecValidationOptions{ | ||||
| 				AllowReadWriteOncePod: true, | ||||
| 			}, | ||||
| 		}, | ||||
| 		"rwop allowed because used and feature disabled": { | ||||
| 			oldPv:                  pvWithAccessModes([]core.PersistentVolumeAccessMode{core.ReadWriteOncePod}), | ||||
| 			enableReadWriteOncePod: false, | ||||
| 			expectValidationOpts: PersistentVolumeSpecValidationOptions{ | ||||
| 				AllowReadWriteOncePod: true, | ||||
| 			}, | ||||
| 			oldPv:                nil, | ||||
| 			expectValidationOpts: PersistentVolumeSpecValidationOptions{}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for name, tc := range tests { | ||||
| 		t.Run(name, func(t *testing.T) { | ||||
| 			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, tc.enableReadWriteOncePod)() | ||||
|  | ||||
| 			opts := ValidationOptionsForPersistentVolume(nil, tc.oldPv) | ||||
| 			if opts != tc.expectValidationOpts { | ||||
| 				t.Errorf("Expected opts: %+v, received: %+v", opts, tc.expectValidationOpts) | ||||
| @@ -973,29 +918,6 @@ func getCSIVolumeWithSecret(pv *core.PersistentVolume, secret *core.SecretRefere | ||||
|  | ||||
| 	return pvCopy | ||||
| } | ||||
| func pvWithAccessModes(accessModes []core.PersistentVolumeAccessMode) *core.PersistentVolume { | ||||
| 	return &core.PersistentVolume{ | ||||
| 		Spec: core.PersistentVolumeSpec{ | ||||
| 			AccessModes: accessModes, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func pvcWithAccessModes(accessModes []core.PersistentVolumeAccessMode) *core.PersistentVolumeClaim { | ||||
| 	return &core.PersistentVolumeClaim{ | ||||
| 		Spec: core.PersistentVolumeClaimSpec{ | ||||
| 			AccessModes: accessModes, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func pvcTemplateWithAccessModes(accessModes []core.PersistentVolumeAccessMode) *core.PersistentVolumeClaimTemplate { | ||||
| 	return &core.PersistentVolumeClaimTemplate{ | ||||
| 		Spec: core.PersistentVolumeClaimSpec{ | ||||
| 			AccessModes: accessModes, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func pvcWithDataSource(dataSource *core.TypedLocalObjectReference) *core.PersistentVolumeClaim { | ||||
| 	return &core.PersistentVolumeClaim{ | ||||
| @@ -1594,9 +1516,8 @@ func testValidatePVC(t *testing.T, ephemeral bool) { | ||||
| 	ten := int64(10) | ||||
|  | ||||
| 	scenarios := map[string]struct { | ||||
| 		isExpectedFailure      bool | ||||
| 		enableReadWriteOncePod bool | ||||
| 		claim                  *core.PersistentVolumeClaim | ||||
| 		isExpectedFailure bool | ||||
| 		claim             *core.PersistentVolumeClaim | ||||
| 	}{ | ||||
| 		"good-claim": { | ||||
| 			isExpectedFailure: false, | ||||
| @@ -1734,9 +1655,8 @@ func testValidatePVC(t *testing.T, ephemeral bool) { | ||||
| 				return claim | ||||
| 			}(), | ||||
| 		}, | ||||
| 		"with-read-write-once-pod-feature-gate-enabled": { | ||||
| 			isExpectedFailure:      false, | ||||
| 			enableReadWriteOncePod: true, | ||||
| 		"with-read-write-once-pod": { | ||||
| 			isExpectedFailure: false, | ||||
| 			claim: testVolumeClaim(goodName, goodNS, core.PersistentVolumeClaimSpec{ | ||||
| 				AccessModes: []core.PersistentVolumeAccessMode{"ReadWriteOncePod"}, | ||||
| 				Resources: core.VolumeResourceRequirements{ | ||||
| @@ -1746,21 +1666,8 @@ func testValidatePVC(t *testing.T, ephemeral bool) { | ||||
| 				}, | ||||
| 			}), | ||||
| 		}, | ||||
| 		"with-read-write-once-pod-feature-gate-disabled": { | ||||
| 			isExpectedFailure:      true, | ||||
| 			enableReadWriteOncePod: false, | ||||
| 			claim: testVolumeClaim(goodName, goodNS, core.PersistentVolumeClaimSpec{ | ||||
| 				AccessModes: []core.PersistentVolumeAccessMode{"ReadWriteOncePod"}, | ||||
| 				Resources: core.VolumeResourceRequirements{ | ||||
| 					Requests: core.ResourceList{ | ||||
| 						core.ResourceName(core.ResourceStorage): resource.MustParse("10G"), | ||||
| 					}, | ||||
| 				}, | ||||
| 			}), | ||||
| 		}, | ||||
| 		"with-read-write-once-pod-and-others-feature-gate-enabled": { | ||||
| 			isExpectedFailure:      true, | ||||
| 			enableReadWriteOncePod: true, | ||||
| 		"with-read-write-once-pod-and-others": { | ||||
| 			isExpectedFailure: true, | ||||
| 			claim: testVolumeClaim(goodName, goodNS, core.PersistentVolumeClaimSpec{ | ||||
| 				AccessModes: []core.PersistentVolumeAccessMode{"ReadWriteOncePod", "ReadWriteMany"}, | ||||
| 				Resources: core.VolumeResourceRequirements{ | ||||
| @@ -1991,8 +1898,6 @@ func testValidatePVC(t *testing.T, ephemeral bool) { | ||||
|  | ||||
| 	for name, scenario := range scenarios { | ||||
| 		t.Run(name, func(t *testing.T) { | ||||
| 			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, scenario.enableReadWriteOncePod)() | ||||
|  | ||||
| 			var errs field.ErrorList | ||||
| 			if ephemeral { | ||||
| 				volumes := []core.Volume{{ | ||||
| @@ -2754,47 +2659,12 @@ func TestValidationOptionsForPersistentVolumeClaim(t *testing.T) { | ||||
| 	invaildAPIGroup := "^invalid" | ||||
|  | ||||
| 	tests := map[string]struct { | ||||
| 		oldPvc                 *core.PersistentVolumeClaim | ||||
| 		enableReadWriteOncePod bool | ||||
| 		expectValidationOpts   PersistentVolumeClaimSpecValidationOptions | ||||
| 		oldPvc               *core.PersistentVolumeClaim | ||||
| 		expectValidationOpts PersistentVolumeClaimSpecValidationOptions | ||||
| 	}{ | ||||
| 		"nil pv": { | ||||
| 			oldPvc:                 nil, | ||||
| 			enableReadWriteOncePod: true, | ||||
| 			oldPvc: nil, | ||||
| 			expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{ | ||||
| 				AllowReadWriteOncePod:             true, | ||||
| 				EnableRecoverFromExpansionFailure: false, | ||||
| 			}, | ||||
| 		}, | ||||
| 		"rwop allowed because feature enabled": { | ||||
| 			oldPvc:                 pvcWithAccessModes([]core.PersistentVolumeAccessMode{core.ReadWriteOnce}), | ||||
| 			enableReadWriteOncePod: true, | ||||
| 			expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{ | ||||
| 				AllowReadWriteOncePod:             true, | ||||
| 				EnableRecoverFromExpansionFailure: false, | ||||
| 			}, | ||||
| 		}, | ||||
| 		"rwop not allowed because not used and feature disabled": { | ||||
| 			oldPvc:                 pvcWithAccessModes([]core.PersistentVolumeAccessMode{core.ReadWriteOnce}), | ||||
| 			enableReadWriteOncePod: false, | ||||
| 			expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{ | ||||
| 				AllowReadWriteOncePod:             false, | ||||
| 				EnableRecoverFromExpansionFailure: false, | ||||
| 			}, | ||||
| 		}, | ||||
| 		"rwop allowed because used and feature enabled": { | ||||
| 			oldPvc:                 pvcWithAccessModes([]core.PersistentVolumeAccessMode{core.ReadWriteOncePod}), | ||||
| 			enableReadWriteOncePod: true, | ||||
| 			expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{ | ||||
| 				AllowReadWriteOncePod:             true, | ||||
| 				EnableRecoverFromExpansionFailure: false, | ||||
| 			}, | ||||
| 		}, | ||||
| 		"rwop allowed because used and feature disabled": { | ||||
| 			oldPvc:                 pvcWithAccessModes([]core.PersistentVolumeAccessMode{core.ReadWriteOncePod}), | ||||
| 			enableReadWriteOncePod: false, | ||||
| 			expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{ | ||||
| 				AllowReadWriteOncePod:             true, | ||||
| 				EnableRecoverFromExpansionFailure: false, | ||||
| 			}, | ||||
| 		}, | ||||
| @@ -2814,8 +2684,6 @@ func TestValidationOptionsForPersistentVolumeClaim(t *testing.T) { | ||||
|  | ||||
| 	for name, tc := range tests { | ||||
| 		t.Run(name, func(t *testing.T) { | ||||
| 			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, tc.enableReadWriteOncePod)() | ||||
|  | ||||
| 			opts := ValidationOptionsForPersistentVolumeClaim(nil, tc.oldPvc) | ||||
| 			if opts != tc.expectValidationOpts { | ||||
| 				t.Errorf("Expected opts: %+v, received: %+v", tc.expectValidationOpts, opts) | ||||
| @@ -2826,51 +2694,17 @@ func TestValidationOptionsForPersistentVolumeClaim(t *testing.T) { | ||||
|  | ||||
| func TestValidationOptionsForPersistentVolumeClaimTemplate(t *testing.T) { | ||||
| 	tests := map[string]struct { | ||||
| 		oldPvcTemplate         *core.PersistentVolumeClaimTemplate | ||||
| 		enableReadWriteOncePod bool | ||||
| 		expectValidationOpts   PersistentVolumeClaimSpecValidationOptions | ||||
| 		oldPvcTemplate       *core.PersistentVolumeClaimTemplate | ||||
| 		expectValidationOpts PersistentVolumeClaimSpecValidationOptions | ||||
| 	}{ | ||||
| 		"nil pv": { | ||||
| 			oldPvcTemplate:         nil, | ||||
| 			enableReadWriteOncePod: true, | ||||
| 			expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{ | ||||
| 				AllowReadWriteOncePod: true, | ||||
| 			}, | ||||
| 		}, | ||||
| 		"rwop allowed because feature enabled": { | ||||
| 			oldPvcTemplate:         pvcTemplateWithAccessModes([]core.PersistentVolumeAccessMode{core.ReadWriteOnce}), | ||||
| 			enableReadWriteOncePod: true, | ||||
| 			expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{ | ||||
| 				AllowReadWriteOncePod: true, | ||||
| 			}, | ||||
| 		}, | ||||
| 		"rwop not allowed because not used and feature disabled": { | ||||
| 			oldPvcTemplate:         pvcTemplateWithAccessModes([]core.PersistentVolumeAccessMode{core.ReadWriteOnce}), | ||||
| 			enableReadWriteOncePod: false, | ||||
| 			expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{ | ||||
| 				AllowReadWriteOncePod: false, | ||||
| 			}, | ||||
| 		}, | ||||
| 		"rwop allowed because used and feature enabled": { | ||||
| 			oldPvcTemplate:         pvcTemplateWithAccessModes([]core.PersistentVolumeAccessMode{core.ReadWriteOncePod}), | ||||
| 			enableReadWriteOncePod: true, | ||||
| 			expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{ | ||||
| 				AllowReadWriteOncePod: true, | ||||
| 			}, | ||||
| 		}, | ||||
| 		"rwop allowed because used and feature disabled": { | ||||
| 			oldPvcTemplate:         pvcTemplateWithAccessModes([]core.PersistentVolumeAccessMode{core.ReadWriteOncePod}), | ||||
| 			enableReadWriteOncePod: false, | ||||
| 			expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{ | ||||
| 				AllowReadWriteOncePod: true, | ||||
| 			}, | ||||
| 			oldPvcTemplate:       nil, | ||||
| 			expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for name, tc := range tests { | ||||
| 		t.Run(name, func(t *testing.T) { | ||||
| 			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, tc.enableReadWriteOncePod)() | ||||
|  | ||||
| 			opts := ValidationOptionsForPersistentVolumeClaimTemplate(nil, tc.oldPvcTemplate) | ||||
| 			if opts != tc.expectValidationOpts { | ||||
| 				t.Errorf("Expected opts: %+v, received: %+v", opts, tc.expectValidationOpts) | ||||
|   | ||||
| @@ -670,6 +670,7 @@ const ( | ||||
| 	// kep: https://kep.k8s.io/2485 | ||||
| 	// alpha: v1.22 | ||||
| 	// beta: v1.27 | ||||
| 	// GA: v1.29 | ||||
| 	// | ||||
| 	// Enables usage of the ReadWriteOncePod PersistentVolume access mode. | ||||
| 	ReadWriteOncePod featuregate.Feature = "ReadWriteOncePod" | ||||
| @@ -1046,7 +1047,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS | ||||
|  | ||||
| 	QOSReserved: {Default: false, PreRelease: featuregate.Alpha}, | ||||
|  | ||||
| 	ReadWriteOncePod: {Default: true, PreRelease: featuregate.Beta}, | ||||
| 	ReadWriteOncePod: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.31 | ||||
|  | ||||
| 	RecoverVolumeExpansionFailure: {Default: false, PreRelease: featuregate.Alpha}, | ||||
|  | ||||
|   | ||||
| @@ -877,7 +877,6 @@ func Test_MarkDeviceAsMounted_Positive_NewVolume(t *testing.T) { | ||||
| // Verifies volume/pod combo exist using PodExistsInVolume() | ||||
| func Test_AddPodToVolume_Positive_SELinux(t *testing.T) { | ||||
| 	// Arrange | ||||
| 	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, true)() | ||||
| 	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)() | ||||
| 	volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t) | ||||
| 	asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr) | ||||
| @@ -956,7 +955,6 @@ func Test_AddPodToVolume_Positive_SELinux(t *testing.T) { | ||||
| // Verifies newly added volume exists in GetGloballyMountedVolumes() | ||||
| func Test_MarkDeviceAsMounted_Positive_SELinux(t *testing.T) { | ||||
| 	// Arrange | ||||
| 	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, true)() | ||||
| 	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)() | ||||
| 	volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t) | ||||
| 	asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr) | ||||
|   | ||||
| @@ -609,7 +609,6 @@ func Test_AddPodToVolume_WithEmptyDirSizeLimit(t *testing.T) { | ||||
| // Verifies newly added pod/volume exists via PodExistsInVolume() without SELinux context | ||||
| // VolumeExists() and GetVolumesToMount() and no errors. | ||||
| func Test_AddPodToVolume_Positive_SELinuxNoRWOP(t *testing.T) { | ||||
| 	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, true)() | ||||
| 	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)() | ||||
| 	// Arrange | ||||
| 	plugins := []volume.VolumePlugin{ | ||||
| @@ -690,7 +689,6 @@ func Test_AddPodToVolume_Positive_SELinuxNoRWOP(t *testing.T) { | ||||
| // Verifies newly added pod/volume exists via PodExistsInVolume() without SELinux context | ||||
| // VolumeExists() and GetVolumesToMount() and no errors. | ||||
| func Test_AddPodToVolume_Positive_NoSELinuxPlugin(t *testing.T) { | ||||
| 	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, true)() | ||||
| 	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)() | ||||
| 	// Arrange | ||||
| 	plugins := []volume.VolumePlugin{ | ||||
| @@ -772,7 +770,6 @@ func Test_AddPodToVolume_Positive_NoSELinuxPlugin(t *testing.T) { | ||||
| // Verifies newly added pod/volume exists via PodExistsInVolume() | ||||
| // VolumeExists() and GetVolumesToMount() and no errors. | ||||
| func Test_AddPodToVolume_Positive_ExistingPodSameSELinuxRWOP(t *testing.T) { | ||||
| 	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, true)() | ||||
| 	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)() | ||||
| 	// Arrange | ||||
| 	plugins := []volume.VolumePlugin{ | ||||
| @@ -873,7 +870,6 @@ func Test_AddPodToVolume_Positive_ExistingPodSameSELinuxRWOP(t *testing.T) { | ||||
| // Verifies newly added pod/volume exists via PodExistsInVolume() | ||||
| // VolumeExists() and GetVolumesToMount() and no errors. | ||||
| func Test_AddPodToVolume_Negative_ExistingPodDifferentSELinuxRWOP(t *testing.T) { | ||||
| 	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, true)() | ||||
| 	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)() | ||||
| 	// Arrange | ||||
| 	plugins := []volume.VolumePlugin{ | ||||
|   | ||||
| @@ -1189,7 +1189,6 @@ func TestCheckVolumeFSResize(t *testing.T) { | ||||
| } | ||||
|  | ||||
| func TestCheckVolumeSELinux(t *testing.T) { | ||||
| 	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, true)() | ||||
| 	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)() | ||||
| 	fullOpts := &v1.SELinuxOptions{ | ||||
| 		User:  "system_u", | ||||
|   | ||||
| @@ -21,7 +21,6 @@ package feature | ||||
| // the internal k8s features pkg. | ||||
| type Features struct { | ||||
| 	EnableDynamicResourceAllocation              bool | ||||
| 	EnableReadWriteOncePod                       bool | ||||
| 	EnableVolumeCapacityPriority                 bool | ||||
| 	EnableMinDomainsInPodTopologySpread          bool | ||||
| 	EnableNodeInclusionPolicyInPodTopologySpread bool | ||||
|   | ||||
| @@ -47,7 +47,6 @@ import ( | ||||
| func NewInTreeRegistry() runtime.Registry { | ||||
| 	fts := plfeature.Features{ | ||||
| 		EnableDynamicResourceAllocation:              feature.DefaultFeatureGate.Enabled(features.DynamicResourceAllocation), | ||||
| 		EnableReadWriteOncePod:                       feature.DefaultFeatureGate.Enabled(features.ReadWriteOncePod), | ||||
| 		EnableVolumeCapacityPriority:                 feature.DefaultFeatureGate.Enabled(features.VolumeCapacityPriority), | ||||
| 		EnableMinDomainsInPodTopologySpread:          feature.DefaultFeatureGate.Enabled(features.MinDomainsInPodTopologySpread), | ||||
| 		EnableNodeInclusionPolicyInPodTopologySpread: feature.DefaultFeatureGate.Enabled(features.NodeInclusionPolicyInPodTopologySpread), | ||||
|   | ||||
| @@ -33,9 +33,8 @@ import ( | ||||
|  | ||||
| // VolumeRestrictions is a plugin that checks volume restrictions. | ||||
| type VolumeRestrictions struct { | ||||
| 	pvcLister              corelisters.PersistentVolumeClaimLister | ||||
| 	sharedLister           framework.SharedLister | ||||
| 	enableReadWriteOncePod bool | ||||
| 	pvcLister    corelisters.PersistentVolumeClaimLister | ||||
| 	sharedLister framework.SharedLister | ||||
| } | ||||
|  | ||||
| var _ framework.PreFilterPlugin = &VolumeRestrictions{} | ||||
| @@ -169,13 +168,6 @@ func (pl *VolumeRestrictions) PreFilter(ctx context.Context, cycleState *framewo | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if !pl.enableReadWriteOncePod { | ||||
| 		if needsCheck { | ||||
| 			return nil, nil | ||||
| 		} | ||||
| 		return nil, framework.NewStatus(framework.Skip) | ||||
| 	} | ||||
|  | ||||
| 	pvcs, err := pl.readWriteOncePodPVCsForPod(ctx, pod) | ||||
| 	if err != nil { | ||||
| 		if apierrors.IsNotFound(err) { | ||||
| @@ -198,9 +190,6 @@ func (pl *VolumeRestrictions) PreFilter(ctx context.Context, cycleState *framewo | ||||
|  | ||||
| // AddPod from pre-computed data in cycleState. | ||||
| func (pl *VolumeRestrictions) AddPod(ctx context.Context, cycleState *framework.CycleState, podToSchedule *v1.Pod, podInfoToAdd *framework.PodInfo, nodeInfo *framework.NodeInfo) *framework.Status { | ||||
| 	if !pl.enableReadWriteOncePod { | ||||
| 		return nil | ||||
| 	} | ||||
| 	state, err := getPreFilterState(cycleState) | ||||
| 	if err != nil { | ||||
| 		return framework.AsStatus(err) | ||||
| @@ -211,9 +200,6 @@ func (pl *VolumeRestrictions) AddPod(ctx context.Context, cycleState *framework. | ||||
|  | ||||
| // RemovePod from pre-computed data in cycleState. | ||||
| func (pl *VolumeRestrictions) RemovePod(ctx context.Context, cycleState *framework.CycleState, podToSchedule *v1.Pod, podInfoToRemove *framework.PodInfo, nodeInfo *framework.NodeInfo) *framework.Status { | ||||
| 	if !pl.enableReadWriteOncePod { | ||||
| 		return nil | ||||
| 	} | ||||
| 	state, err := getPreFilterState(cycleState) | ||||
| 	if err != nil { | ||||
| 		return framework.AsStatus(err) | ||||
| @@ -321,9 +307,6 @@ func (pl *VolumeRestrictions) Filter(ctx context.Context, cycleState *framework. | ||||
| 	if !satisfyVolumeConflicts(pod, nodeInfo) { | ||||
| 		return framework.NewStatus(framework.Unschedulable, ErrReasonDiskConflict) | ||||
| 	} | ||||
| 	if !pl.enableReadWriteOncePod { | ||||
| 		return nil | ||||
| 	} | ||||
| 	state, err := getPreFilterState(cycleState) | ||||
| 	if err != nil { | ||||
| 		return framework.AsStatus(err) | ||||
| @@ -354,8 +337,7 @@ func New(_ context.Context, _ runtime.Object, handle framework.Handle, fts featu | ||||
| 	sharedLister := handle.SnapshotSharedLister() | ||||
|  | ||||
| 	return &VolumeRestrictions{ | ||||
| 		pvcLister:              pvcLister, | ||||
| 		sharedLister:           sharedLister, | ||||
| 		enableReadWriteOncePod: fts.EnableReadWriteOncePod, | ||||
| 		pvcLister:    pvcLister, | ||||
| 		sharedLister: sharedLister, | ||||
| 	}, nil | ||||
| } | ||||
|   | ||||
| @@ -24,9 +24,6 @@ import ( | ||||
| 	v1 "k8s.io/api/core/v1" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| 	"k8s.io/apimachinery/pkg/runtime" | ||||
| 	utilfeature "k8s.io/apiserver/pkg/util/feature" | ||||
| 	featuregatetesting "k8s.io/component-base/featuregate/testing" | ||||
| 	"k8s.io/kubernetes/pkg/features" | ||||
| 	"k8s.io/kubernetes/pkg/scheduler/apis/config" | ||||
| 	"k8s.io/kubernetes/pkg/scheduler/framework" | ||||
| 	"k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature" | ||||
| @@ -355,8 +352,6 @@ func TestISCSIDiskConflicts(t *testing.T) { | ||||
| } | ||||
|  | ||||
| func TestAccessModeConflicts(t *testing.T) { | ||||
| 	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, true)() | ||||
|  | ||||
| 	// Required for querying lister for PVCs in the same namespace. | ||||
| 	podWithOnePVC := st.MakePod().Name("pod-with-one-pvc").Namespace(metav1.NamespaceDefault).PVC("claim-with-rwop-1").Node("node-1").Obj() | ||||
| 	podWithTwoPVCs := st.MakePod().Name("pod-with-two-pvcs").Namespace(metav1.NamespaceDefault).PVC("claim-with-rwop-1").PVC("claim-with-rwop-2").Node("node-1").Obj() | ||||
| @@ -401,81 +396,64 @@ func TestAccessModeConflicts(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	tests := []struct { | ||||
| 		name                   string | ||||
| 		pod                    *v1.Pod | ||||
| 		nodeInfo               *framework.NodeInfo | ||||
| 		existingPods           []*v1.Pod | ||||
| 		existingNodes          []*v1.Node | ||||
| 		existingPVCs           []*v1.PersistentVolumeClaim | ||||
| 		enableReadWriteOncePod bool | ||||
| 		preFilterWantStatus    *framework.Status | ||||
| 		wantStatus             *framework.Status | ||||
| 		name                string | ||||
| 		pod                 *v1.Pod | ||||
| 		nodeInfo            *framework.NodeInfo | ||||
| 		existingPods        []*v1.Pod | ||||
| 		existingNodes       []*v1.Node | ||||
| 		existingPVCs        []*v1.PersistentVolumeClaim | ||||
| 		preFilterWantStatus *framework.Status | ||||
| 		wantStatus          *framework.Status | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name:                   "nothing", | ||||
| 			pod:                    &v1.Pod{}, | ||||
| 			nodeInfo:               framework.NewNodeInfo(), | ||||
| 			existingPods:           []*v1.Pod{}, | ||||
| 			existingNodes:          []*v1.Node{}, | ||||
| 			existingPVCs:           []*v1.PersistentVolumeClaim{}, | ||||
| 			enableReadWriteOncePod: true, | ||||
| 			preFilterWantStatus:    framework.NewStatus(framework.Skip), | ||||
| 			wantStatus:             nil, | ||||
| 			name:                "nothing", | ||||
| 			pod:                 &v1.Pod{}, | ||||
| 			nodeInfo:            framework.NewNodeInfo(), | ||||
| 			existingPods:        []*v1.Pod{}, | ||||
| 			existingNodes:       []*v1.Node{}, | ||||
| 			existingPVCs:        []*v1.PersistentVolumeClaim{}, | ||||
| 			preFilterWantStatus: framework.NewStatus(framework.Skip), | ||||
| 			wantStatus:          nil, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:                   "nothing, ReadWriteOncePod disabled", | ||||
| 			pod:                    &v1.Pod{}, | ||||
| 			nodeInfo:               framework.NewNodeInfo(), | ||||
| 			existingPods:           []*v1.Pod{}, | ||||
| 			existingNodes:          []*v1.Node{}, | ||||
| 			existingPVCs:           []*v1.PersistentVolumeClaim{}, | ||||
| 			enableReadWriteOncePod: false, | ||||
| 			preFilterWantStatus:    framework.NewStatus(framework.Skip), | ||||
| 			wantStatus:             nil, | ||||
| 			name:                "failed to get PVC", | ||||
| 			pod:                 podWithOnePVC, | ||||
| 			nodeInfo:            framework.NewNodeInfo(), | ||||
| 			existingPods:        []*v1.Pod{}, | ||||
| 			existingNodes:       []*v1.Node{}, | ||||
| 			existingPVCs:        []*v1.PersistentVolumeClaim{}, | ||||
| 			preFilterWantStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, "persistentvolumeclaim \"claim-with-rwop-1\" not found"), | ||||
| 			wantStatus:          nil, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:                   "failed to get PVC", | ||||
| 			pod:                    podWithOnePVC, | ||||
| 			nodeInfo:               framework.NewNodeInfo(), | ||||
| 			existingPods:           []*v1.Pod{}, | ||||
| 			existingNodes:          []*v1.Node{}, | ||||
| 			existingPVCs:           []*v1.PersistentVolumeClaim{}, | ||||
| 			enableReadWriteOncePod: true, | ||||
| 			preFilterWantStatus:    framework.NewStatus(framework.UnschedulableAndUnresolvable, "persistentvolumeclaim \"claim-with-rwop-1\" not found"), | ||||
| 			wantStatus:             nil, | ||||
| 			name:                "no access mode conflict", | ||||
| 			pod:                 podWithOnePVC, | ||||
| 			nodeInfo:            framework.NewNodeInfo(podWithReadWriteManyPVC), | ||||
| 			existingPods:        []*v1.Pod{podWithReadWriteManyPVC}, | ||||
| 			existingNodes:       []*v1.Node{node}, | ||||
| 			existingPVCs:        []*v1.PersistentVolumeClaim{readWriteOncePodPVC1, readWriteManyPVC}, | ||||
| 			preFilterWantStatus: framework.NewStatus(framework.Skip), | ||||
| 			wantStatus:          nil, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:                   "no access mode conflict", | ||||
| 			pod:                    podWithOnePVC, | ||||
| 			nodeInfo:               framework.NewNodeInfo(podWithReadWriteManyPVC), | ||||
| 			existingPods:           []*v1.Pod{podWithReadWriteManyPVC}, | ||||
| 			existingNodes:          []*v1.Node{node}, | ||||
| 			existingPVCs:           []*v1.PersistentVolumeClaim{readWriteOncePodPVC1, readWriteManyPVC}, | ||||
| 			enableReadWriteOncePod: true, | ||||
| 			preFilterWantStatus:    framework.NewStatus(framework.Skip), | ||||
| 			wantStatus:             nil, | ||||
| 			name:                "access mode conflict, unschedulable", | ||||
| 			pod:                 podWithOneConflict, | ||||
| 			nodeInfo:            framework.NewNodeInfo(podWithOnePVC, podWithReadWriteManyPVC), | ||||
| 			existingPods:        []*v1.Pod{podWithOnePVC, podWithReadWriteManyPVC}, | ||||
| 			existingNodes:       []*v1.Node{node}, | ||||
| 			existingPVCs:        []*v1.PersistentVolumeClaim{readWriteOncePodPVC1, readWriteManyPVC}, | ||||
| 			preFilterWantStatus: nil, | ||||
| 			wantStatus:          framework.NewStatus(framework.Unschedulable, ErrReasonReadWriteOncePodConflict), | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:                   "access mode conflict, unschedulable", | ||||
| 			pod:                    podWithOneConflict, | ||||
| 			nodeInfo:               framework.NewNodeInfo(podWithOnePVC, podWithReadWriteManyPVC), | ||||
| 			existingPods:           []*v1.Pod{podWithOnePVC, podWithReadWriteManyPVC}, | ||||
| 			existingNodes:          []*v1.Node{node}, | ||||
| 			existingPVCs:           []*v1.PersistentVolumeClaim{readWriteOncePodPVC1, readWriteManyPVC}, | ||||
| 			enableReadWriteOncePod: true, | ||||
| 			preFilterWantStatus:    nil, | ||||
| 			wantStatus:             framework.NewStatus(framework.Unschedulable, ErrReasonReadWriteOncePodConflict), | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:                   "two conflicts, unschedulable", | ||||
| 			pod:                    podWithTwoConflicts, | ||||
| 			nodeInfo:               framework.NewNodeInfo(podWithTwoPVCs, podWithReadWriteManyPVC), | ||||
| 			existingPods:           []*v1.Pod{podWithTwoPVCs, podWithReadWriteManyPVC}, | ||||
| 			existingNodes:          []*v1.Node{node}, | ||||
| 			existingPVCs:           []*v1.PersistentVolumeClaim{readWriteOncePodPVC1, readWriteOncePodPVC2, readWriteManyPVC}, | ||||
| 			enableReadWriteOncePod: true, | ||||
| 			preFilterWantStatus:    nil, | ||||
| 			wantStatus:             framework.NewStatus(framework.Unschedulable, ErrReasonReadWriteOncePodConflict), | ||||
| 			name:                "two conflicts, unschedulable", | ||||
| 			pod:                 podWithTwoConflicts, | ||||
| 			nodeInfo:            framework.NewNodeInfo(podWithTwoPVCs, podWithReadWriteManyPVC), | ||||
| 			existingPods:        []*v1.Pod{podWithTwoPVCs, podWithReadWriteManyPVC}, | ||||
| 			existingNodes:       []*v1.Node{node}, | ||||
| 			existingPVCs:        []*v1.PersistentVolumeClaim{readWriteOncePodPVC1, readWriteOncePodPVC2, readWriteManyPVC}, | ||||
| 			preFilterWantStatus: nil, | ||||
| 			wantStatus:          framework.NewStatus(framework.Unschedulable, ErrReasonReadWriteOncePodConflict), | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| @@ -483,7 +461,7 @@ func TestAccessModeConflicts(t *testing.T) { | ||||
| 		t.Run(test.name, func(t *testing.T) { | ||||
| 			ctx, cancel := context.WithCancel(context.Background()) | ||||
| 			defer cancel() | ||||
| 			p := newPluginWithListers(ctx, t, test.existingPods, test.existingNodes, test.existingPVCs, test.enableReadWriteOncePod) | ||||
| 			p := newPluginWithListers(ctx, t, test.existingPods, test.existingNodes, test.existingPVCs) | ||||
| 			cycleState := framework.NewCycleState() | ||||
| 			_, preFilterGotStatus := p.(framework.PreFilterPlugin).PreFilter(ctx, cycleState, test.pod) | ||||
| 			if diff := cmp.Diff(test.preFilterWantStatus, preFilterGotStatus); diff != "" { | ||||
| @@ -501,14 +479,12 @@ func TestAccessModeConflicts(t *testing.T) { | ||||
| } | ||||
|  | ||||
| func newPlugin(ctx context.Context, t *testing.T) framework.Plugin { | ||||
| 	return newPluginWithListers(ctx, t, nil, nil, nil, true) | ||||
| 	return newPluginWithListers(ctx, t, nil, nil, nil) | ||||
| } | ||||
|  | ||||
| func newPluginWithListers(ctx context.Context, t *testing.T, pods []*v1.Pod, nodes []*v1.Node, pvcs []*v1.PersistentVolumeClaim, enableReadWriteOncePod bool) framework.Plugin { | ||||
| func newPluginWithListers(ctx context.Context, t *testing.T, pods []*v1.Pod, nodes []*v1.Node, pvcs []*v1.PersistentVolumeClaim) framework.Plugin { | ||||
| 	pluginFactory := func(ctx context.Context, plArgs runtime.Object, fh framework.Handle) (framework.Plugin, error) { | ||||
| 		return New(ctx, plArgs, fh, feature.Features{ | ||||
| 			EnableReadWriteOncePod: enableReadWriteOncePod, | ||||
| 		}) | ||||
| 		return New(ctx, plArgs, fh, feature.Features{}) | ||||
| 	} | ||||
| 	snapshot := cache.NewSnapshot(pods, nodes) | ||||
|  | ||||
|   | ||||
| @@ -370,7 +370,6 @@ func TestPluginConstructVolumeSpec(t *testing.T) { | ||||
|  | ||||
| 	for _, tc := range testCases { | ||||
| 		t.Run(tc.name, func(t *testing.T) { | ||||
| 			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, tc.seLinuxMountEnabled)() | ||||
| 			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, tc.seLinuxMountEnabled)() | ||||
|  | ||||
| 			mounter, err := plug.NewMounter( | ||||
|   | ||||
| @@ -580,8 +580,7 @@ func (og *operationGenerator) GenerateMountVolumeFunc( | ||||
| 		} | ||||
|  | ||||
| 		// Enforce ReadWriteOncePod access mode if it is the only one present. This is also enforced during scheduling. | ||||
| 		if utilfeature.DefaultFeatureGate.Enabled(features.ReadWriteOncePod) && | ||||
| 			actualStateOfWorld.IsVolumeMountedElsewhere(volumeToMount.VolumeName, volumeToMount.PodName) && | ||||
| 		if actualStateOfWorld.IsVolumeMountedElsewhere(volumeToMount.VolumeName, volumeToMount.PodName) && | ||||
| 			// Because we do not know what access mode the pod intends to use if there are multiple. | ||||
| 			len(volumeToMount.VolumeSpec.PersistentVolume.Spec.AccessModes) == 1 && | ||||
| 			v1helper.ContainsAccessMode(volumeToMount.VolumeSpec.PersistentVolume.Spec.AccessModes, v1.ReadWriteOncePod) { | ||||
| @@ -1071,8 +1070,7 @@ func (og *operationGenerator) GenerateMapVolumeFunc( | ||||
| 		migrated := getMigratedStatusBySpec(volumeToMount.VolumeSpec) | ||||
|  | ||||
| 		// Enforce ReadWriteOncePod access mode. This is also enforced during scheduling. | ||||
| 		if utilfeature.DefaultFeatureGate.Enabled(features.ReadWriteOncePod) && | ||||
| 			actualStateOfWorld.IsVolumeMountedElsewhere(volumeToMount.VolumeName, volumeToMount.PodName) && | ||||
| 		if actualStateOfWorld.IsVolumeMountedElsewhere(volumeToMount.VolumeName, volumeToMount.PodName) && | ||||
| 			// Because we do not know what access mode the pod intends to use if there are multiple. | ||||
| 			len(volumeToMount.VolumeSpec.PersistentVolume.Spec.AccessModes) == 1 && | ||||
| 			v1helper.ContainsAccessMode(volumeToMount.VolumeSpec.PersistentVolume.Spec.AccessModes, v1.ReadWriteOncePod) { | ||||
|   | ||||
| @@ -168,10 +168,6 @@ func SupportsSELinuxContextMount(volumeSpec *volume.Spec, volumePluginMgr *volum | ||||
|  | ||||
| // VolumeSupportsSELinuxMount returns true if given volume access mode can support mount with SELinux mount options. | ||||
| func VolumeSupportsSELinuxMount(volumeSpec *volume.Spec) bool { | ||||
| 	// Right now, SELinux mount is supported only for ReadWriteOncePod volumes. | ||||
| 	if !utilfeature.DefaultFeatureGate.Enabled(features.ReadWriteOncePod) { | ||||
| 		return false | ||||
| 	} | ||||
| 	if !utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) { | ||||
| 		return false | ||||
| 	} | ||||
|   | ||||
| @@ -616,7 +616,6 @@ func TestMakeAbsolutePath(t *testing.T) { | ||||
| } | ||||
|  | ||||
| func TestGetPodVolumeNames(t *testing.T) { | ||||
| 	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, true)() | ||||
| 	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)() | ||||
| 	tests := []struct { | ||||
| 		name                    string | ||||
|   | ||||
| @@ -1554,11 +1554,10 @@ var ( | ||||
|  | ||||
| func TestUnschedulablePodBecomesSchedulable(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		name                   string | ||||
| 		init                   func(kubernetes.Interface, string) error | ||||
| 		pod                    *testutils.PausePodConfig | ||||
| 		update                 func(kubernetes.Interface, string) error | ||||
| 		enableReadWriteOncePod bool | ||||
| 		name   string | ||||
| 		init   func(kubernetes.Interface, string) error | ||||
| 		pod    *testutils.PausePodConfig | ||||
| 		update func(kubernetes.Interface, string) error | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "node gets added", | ||||
| @@ -1765,13 +1764,10 @@ func TestUnschedulablePodBecomesSchedulable(t *testing.T) { | ||||
| 			update: func(cs kubernetes.Interface, ns string) error { | ||||
| 				return deletePod(cs, "pod-to-be-deleted", ns) | ||||
| 			}, | ||||
| 			enableReadWriteOncePod: true, | ||||
| 		}, | ||||
| 	} | ||||
| 	for _, tt := range tests { | ||||
| 		t.Run(tt.name, func(t *testing.T) { | ||||
| 			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, tt.enableReadWriteOncePod)() | ||||
|  | ||||
| 			testCtx := initTest(t, "scheduler-informer") | ||||
|  | ||||
| 			if tt.init != nil { | ||||
|   | ||||
| @@ -1648,8 +1648,6 @@ func TestPreferNominatedNode(t *testing.T) { | ||||
| // TestReadWriteOncePodPreemption tests preemption scenarios for pods with | ||||
| // ReadWriteOncePod PVCs. | ||||
| func TestReadWriteOncePodPreemption(t *testing.T) { | ||||
| 	defer featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.ReadWriteOncePod, true)() | ||||
|  | ||||
| 	cfg := configtesting.V1ToInternalWithDefaults(t, configv1.KubeSchedulerConfiguration{ | ||||
| 		Profiles: []configv1.KubeSchedulerProfile{{ | ||||
| 			SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName), | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Chris Henzie
					Chris Henzie