mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	validation and feature gate
This commit is contained in:
		@@ -2647,6 +2647,19 @@ const (
 | 
			
		||||
	MaxDNSSearchListChars = 256
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func validateReadinessGates(readinessGates []core.PodReadinessGate, fldPath *field.Path) field.ErrorList {
 | 
			
		||||
	allErrs := field.ErrorList{}
 | 
			
		||||
	if !utilfeature.DefaultFeatureGate.Enabled(features.PodReadinessGates) && len(readinessGates) > 0 {
 | 
			
		||||
		return append(allErrs, field.Forbidden(fldPath, "PodReadinessGates is disabled by feature gate"))
 | 
			
		||||
	}
 | 
			
		||||
	for i, value := range readinessGates {
 | 
			
		||||
		for _, msg := range validation.IsQualifiedName(string(value.ConditionType)) {
 | 
			
		||||
			allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("conditionType"), string(value.ConditionType), msg))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return allErrs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func validatePodDNSConfig(dnsConfig *core.PodDNSConfig, dnsPolicy *core.DNSPolicy, fldPath *field.Path) field.ErrorList {
 | 
			
		||||
	allErrs := field.ErrorList{}
 | 
			
		||||
 | 
			
		||||
@@ -2935,6 +2948,7 @@ func ValidatePodSpec(spec *core.PodSpec, fldPath *field.Path) field.ErrorList {
 | 
			
		||||
	allErrs = append(allErrs, validateImagePullSecrets(spec.ImagePullSecrets, fldPath.Child("imagePullSecrets"))...)
 | 
			
		||||
	allErrs = append(allErrs, validateAffinity(spec.Affinity, fldPath.Child("affinity"))...)
 | 
			
		||||
	allErrs = append(allErrs, validatePodDNSConfig(spec.DNSConfig, &spec.DNSPolicy, fldPath.Child("dnsConfig"))...)
 | 
			
		||||
	allErrs = append(allErrs, validateReadinessGates(spec.ReadinessGates, fldPath.Child("readinessGates"))...)
 | 
			
		||||
	if len(spec.ServiceAccountName) > 0 {
 | 
			
		||||
		for _, msg := range ValidateServiceAccountName(spec.ServiceAccountName, false) {
 | 
			
		||||
			allErrs = append(allErrs, field.Invalid(fldPath.Child("serviceAccountName"), spec.ServiceAccountName, msg))
 | 
			
		||||
@@ -3485,6 +3499,7 @@ func ValidatePodStatusUpdate(newPod, oldPod *core.Pod) field.ErrorList {
 | 
			
		||||
	fldPath := field.NewPath("metadata")
 | 
			
		||||
	allErrs := ValidateObjectMetaUpdate(&newPod.ObjectMeta, &oldPod.ObjectMeta, fldPath)
 | 
			
		||||
	allErrs = append(allErrs, ValidatePodSpecificAnnotationUpdates(newPod, oldPod, fldPath.Child("annotations"))...)
 | 
			
		||||
	allErrs = append(allErrs, validatePodConditions(newPod.Status.Conditions, fldPath.Child("conditions"))...)
 | 
			
		||||
 | 
			
		||||
	fldPath = field.NewPath("status")
 | 
			
		||||
	if newPod.Spec.NodeName != oldPod.Spec.NodeName {
 | 
			
		||||
@@ -3508,6 +3523,21 @@ func ValidatePodStatusUpdate(newPod, oldPod *core.Pod) field.ErrorList {
 | 
			
		||||
	return allErrs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// validatePodConditions tests if the custom pod conditions are valid.
 | 
			
		||||
func validatePodConditions(conditions []core.PodCondition, fldPath *field.Path) field.ErrorList {
 | 
			
		||||
	allErrs := field.ErrorList{}
 | 
			
		||||
	systemConditions := sets.NewString(string(core.PodScheduled), string(core.PodReady), string(core.PodInitialized))
 | 
			
		||||
	for i, condition := range conditions {
 | 
			
		||||
		if systemConditions.Has(string(condition.Type)) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		for _, msg := range validation.IsQualifiedName(string(condition.Type)) {
 | 
			
		||||
			allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("Type"), string(condition.Type), msg))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return allErrs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ValidatePodBinding tests if required fields in the pod binding are legal.
 | 
			
		||||
func ValidatePodBinding(binding *core.Binding) field.ErrorList {
 | 
			
		||||
	allErrs := field.ErrorList{}
 | 
			
		||||
 
 | 
			
		||||
@@ -5865,6 +5865,149 @@ func TestValidatePodDNSConfig(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestValidatePodReadinessGates(t *testing.T) {
 | 
			
		||||
	podReadinessGatesEnabled := utilfeature.DefaultFeatureGate.Enabled(features.PodReadinessGates)
 | 
			
		||||
	defer func() {
 | 
			
		||||
		// Restoring the old value.
 | 
			
		||||
		if err := utilfeature.DefaultFeatureGate.Set(fmt.Sprintf("%s=%v", features.PodReadinessGates, podReadinessGatesEnabled)); err != nil {
 | 
			
		||||
			t.Errorf("Failed to restore PodReadinessGates feature gate: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	if err := utilfeature.DefaultFeatureGate.Set(fmt.Sprintf("%s=true", features.PodReadinessGates)); err != nil {
 | 
			
		||||
		t.Errorf("Failed to enable PodReadinessGates feature gate: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	successCases := []struct {
 | 
			
		||||
		desc           string
 | 
			
		||||
		readinessGates []core.PodReadinessGate
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			"no gate",
 | 
			
		||||
			[]core.PodReadinessGate{},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"one readiness gate",
 | 
			
		||||
			[]core.PodReadinessGate{
 | 
			
		||||
				{
 | 
			
		||||
					ConditionType: core.PodConditionType("example.com/condition"),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"two readiness gates",
 | 
			
		||||
			[]core.PodReadinessGate{
 | 
			
		||||
				{
 | 
			
		||||
					ConditionType: core.PodConditionType("example.com/condition1"),
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					ConditionType: core.PodConditionType("example.com/condition2"),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tc := range successCases {
 | 
			
		||||
		if errs := validateReadinessGates(tc.readinessGates, field.NewPath("field")); len(errs) != 0 {
 | 
			
		||||
			t.Errorf("expect tc %q to success: %v", tc.desc, errs)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	errorCases := []struct {
 | 
			
		||||
		desc           string
 | 
			
		||||
		readinessGates []core.PodReadinessGate
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			"invalid condition type",
 | 
			
		||||
			[]core.PodReadinessGate{
 | 
			
		||||
				{
 | 
			
		||||
					ConditionType: core.PodConditionType("invalid/condition/type"),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tc := range errorCases {
 | 
			
		||||
		if errs := validateReadinessGates(tc.readinessGates, field.NewPath("field")); len(errs) == 0 {
 | 
			
		||||
			t.Errorf("expected tc %q to fail", tc.desc)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestValidatePodConditions(t *testing.T) {
 | 
			
		||||
	successCases := []struct {
 | 
			
		||||
		desc          string
 | 
			
		||||
		podConditions []core.PodCondition
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			"no condition",
 | 
			
		||||
			[]core.PodCondition{},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"one system condition",
 | 
			
		||||
			[]core.PodCondition{
 | 
			
		||||
				{
 | 
			
		||||
					Type:   core.PodReady,
 | 
			
		||||
					Status: core.ConditionTrue,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"one system condition and one custom condition",
 | 
			
		||||
			[]core.PodCondition{
 | 
			
		||||
				{
 | 
			
		||||
					Type:   core.PodReady,
 | 
			
		||||
					Status: core.ConditionTrue,
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					Type:   core.PodConditionType("example.com/condition"),
 | 
			
		||||
					Status: core.ConditionFalse,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"two custom condition",
 | 
			
		||||
			[]core.PodCondition{
 | 
			
		||||
				{
 | 
			
		||||
					Type:   core.PodConditionType("foobar"),
 | 
			
		||||
					Status: core.ConditionTrue,
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					Type:   core.PodConditionType("example.com/condition"),
 | 
			
		||||
					Status: core.ConditionFalse,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tc := range successCases {
 | 
			
		||||
		if errs := validatePodConditions(tc.podConditions, field.NewPath("field")); len(errs) != 0 {
 | 
			
		||||
			t.Errorf("expected tc %q to success, but got: %v", tc.desc, errs)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	errorCases := []struct {
 | 
			
		||||
		desc          string
 | 
			
		||||
		podConditions []core.PodCondition
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			"one system condition and a invalid custom condition",
 | 
			
		||||
			[]core.PodCondition{
 | 
			
		||||
				{
 | 
			
		||||
					Type:   core.PodReady,
 | 
			
		||||
					Status: core.ConditionStatus("True"),
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					Type:   core.PodConditionType("invalid/custom/condition"),
 | 
			
		||||
					Status: core.ConditionStatus("True"),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tc := range errorCases {
 | 
			
		||||
		if errs := validatePodConditions(tc.podConditions, field.NewPath("field")); len(errs) == 0 {
 | 
			
		||||
			t.Errorf("expected tc %q to fail", tc.desc)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestValidatePodSpec(t *testing.T) {
 | 
			
		||||
	activeDeadlineSeconds := int64(30)
 | 
			
		||||
	activeDeadlineSecondsMax := int64(math.MaxInt32)
 | 
			
		||||
 
 | 
			
		||||
@@ -292,6 +292,12 @@ const (
 | 
			
		||||
	// while making decisions.
 | 
			
		||||
	BalanceAttachedNodeVolumes utilfeature.Feature = "BalanceAttachedNodeVolumes"
 | 
			
		||||
 | 
			
		||||
	// owner @freehan
 | 
			
		||||
	// beta: v1.11
 | 
			
		||||
	//
 | 
			
		||||
	// Support Pod Ready++
 | 
			
		||||
	PodReadinessGates utilfeature.Feature = "PodReadinessGates"
 | 
			
		||||
 | 
			
		||||
	// owner: @lichuqiang
 | 
			
		||||
	// alpha: v1.11
 | 
			
		||||
	//
 | 
			
		||||
@@ -362,6 +368,7 @@ var defaultKubernetesFeatureGates = map[utilfeature.Feature]utilfeature.FeatureS
 | 
			
		||||
	VolumeSubpath:                               {Default: true, PreRelease: utilfeature.GA},
 | 
			
		||||
	BalanceAttachedNodeVolumes:                  {Default: false, PreRelease: utilfeature.Alpha},
 | 
			
		||||
	DynamicProvisioningScheduling:               {Default: false, PreRelease: utilfeature.Alpha},
 | 
			
		||||
	PodReadinessGates:                           {Default: false, PreRelease: utilfeature.Beta},
 | 
			
		||||
	VolumeSubpathEnvExpansion:                   {Default: false, PreRelease: utilfeature.Alpha},
 | 
			
		||||
	KubeletPluginsWatcher:                       {Default: false, PreRelease: utilfeature.Alpha},
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user