Merge pull request #3407 from Poor12/webhook-change

Add validation for failover
This commit is contained in:
karmada-bot 2023-04-20 17:32:07 +08:00 committed by GitHub
commit 7b1ddc9ee1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 116 additions and 7 deletions

View File

@ -15044,7 +15044,7 @@
"format": "int32" "format": "int32"
}, },
"decisionConditions": { "decisionConditions": {
"description": "DecisionConditions indicates the decision conditions of performing the failover process. Only when all conditions are met can the failover process be performed. Currently, DecisionConditions includes several conditions: - TolerationSeconds (optional) - HealthyState (mandatory)", "description": "DecisionConditions indicates the decision conditions of performing the failover process. Only when all conditions are met can the failover process be performed. Currently, DecisionConditions includes several conditions: - TolerationSeconds (optional)",
"default": {}, "default": {},
"$ref": "#/definitions/com.github.karmada-io.karmada.pkg.apis.policy.v1alpha1.DecisionConditions" "$ref": "#/definitions/com.github.karmada-io.karmada.pkg.apis.policy.v1alpha1.DecisionConditions"
}, },

View File

@ -87,7 +87,7 @@ spec:
of performing the failover process. Only when all conditions of performing the failover process. Only when all conditions
are met can the failover process be performed. Currently, are met can the failover process be performed. Currently,
DecisionConditions includes several conditions: - TolerationSeconds DecisionConditions includes several conditions: - TolerationSeconds
(optional) - HealthyState (mandatory)' (optional)'
properties: properties:
tolerationSeconds: tolerationSeconds:
default: 300 default: 300

View File

@ -83,7 +83,7 @@ spec:
of performing the failover process. Only when all conditions of performing the failover process. Only when all conditions
are met can the failover process be performed. Currently, are met can the failover process be performed. Currently,
DecisionConditions includes several conditions: - TolerationSeconds DecisionConditions includes several conditions: - TolerationSeconds
(optional) - HealthyState (mandatory)' (optional)'
properties: properties:
tolerationSeconds: tolerationSeconds:
default: 300 default: 300

View File

@ -291,7 +291,7 @@ spec:
of performing the failover process. Only when all conditions of performing the failover process. Only when all conditions
are met can the failover process be performed. Currently, are met can the failover process be performed. Currently,
DecisionConditions includes several conditions: - TolerationSeconds DecisionConditions includes several conditions: - TolerationSeconds
(optional) - HealthyState (mandatory)' (optional)'
properties: properties:
tolerationSeconds: tolerationSeconds:
default: 300 default: 300

View File

@ -291,7 +291,7 @@ spec:
of performing the failover process. Only when all conditions of performing the failover process. Only when all conditions
are met can the failover process be performed. Currently, are met can the failover process be performed. Currently,
DecisionConditions includes several conditions: - TolerationSeconds DecisionConditions includes several conditions: - TolerationSeconds
(optional) - HealthyState (mandatory)' (optional)'
properties: properties:
tolerationSeconds: tolerationSeconds:
default: 300 default: 300

View File

@ -210,7 +210,6 @@ type ApplicationFailoverBehavior struct {
// Only when all conditions are met can the failover process be performed. // Only when all conditions are met can the failover process be performed.
// Currently, DecisionConditions includes several conditions: // Currently, DecisionConditions includes several conditions:
// - TolerationSeconds (optional) // - TolerationSeconds (optional)
// - HealthyState (mandatory)
// +required // +required
DecisionConditions DecisionConditions `json:"decisionConditions"` DecisionConditions DecisionConditions `json:"decisionConditions"`

View File

@ -2164,7 +2164,7 @@ func schema_pkg_apis_policy_v1alpha1_ApplicationFailoverBehavior(ref common.Refe
}, },
"decisionConditions": { "decisionConditions": {
SchemaProps: spec.SchemaProps{ SchemaProps: spec.SchemaProps{
Description: "DecisionConditions indicates the decision conditions of performing the failover process. Only when all conditions are met can the failover process be performed. Currently, DecisionConditions includes several conditions: - TolerationSeconds (optional) - HealthyState (mandatory)", Description: "DecisionConditions indicates the decision conditions of performing the failover process. Only when all conditions are met can the failover process be performed. Currently, DecisionConditions includes several conditions: - TolerationSeconds (optional)",
Default: map[string]interface{}{}, Default: map[string]interface{}{},
Ref: ref("github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1.DecisionConditions"), Ref: ref("github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1.DecisionConditions"),
}, },

View File

@ -21,6 +21,7 @@ const LabelValueMaxLength int = 63
func ValidatePropagationSpec(spec policyv1alpha1.PropagationSpec) field.ErrorList { func ValidatePropagationSpec(spec policyv1alpha1.PropagationSpec) field.ErrorList {
var allErrs field.ErrorList var allErrs field.ErrorList
allErrs = append(allErrs, ValidatePlacement(spec.Placement, field.NewPath("spec").Child("placement"))...) allErrs = append(allErrs, ValidatePlacement(spec.Placement, field.NewPath("spec").Child("placement"))...)
allErrs = append(allErrs, ValidateFailover(spec.Failover, field.NewPath("spec").Child("failover"))...)
return allErrs return allErrs
} }
@ -142,6 +143,42 @@ func ValidateSpreadConstraint(spreadConstraints []policyv1alpha1.SpreadConstrain
return allErrs return allErrs
} }
// ValidateFailover validates that the failoverBehavior is correctly defined.
func ValidateFailover(failoverBehavior *policyv1alpha1.FailoverBehavior, fldPath *field.Path) field.ErrorList {
var allErrs field.ErrorList
if failoverBehavior == nil {
return nil
}
allErrs = append(allErrs, ValidateApplicationFailover(failoverBehavior.Application, fldPath.Child("application"))...)
return allErrs
}
// ValidateApplicationFailover validates that the application failover is correctly defined.
func ValidateApplicationFailover(applicationFailoverBehavior *policyv1alpha1.ApplicationFailoverBehavior, fldPath *field.Path) field.ErrorList {
var allErrs field.ErrorList
if applicationFailoverBehavior == nil {
return nil
}
preConditions := applicationFailoverBehavior.PreConditions
if preConditions != nil && preConditions.DelaySeconds != nil && *preConditions.DelaySeconds < 0 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("preConditions").Child("delaySeconds"), *preConditions.DelaySeconds, "must be greater than or equal to 0"))
}
if *applicationFailoverBehavior.DecisionConditions.TolerationSeconds < 0 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("decisionConditions").Child("tolerationSeconds"), *applicationFailoverBehavior.DecisionConditions.TolerationSeconds, "must be greater than or equal to 0"))
}
if *applicationFailoverBehavior.BlockPredecessorSeconds < 0 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("blockPredecessorSeconds"), *applicationFailoverBehavior.BlockPredecessorSeconds, "must be greater than or equal to 0"))
}
return allErrs
}
// ValidateOverrideSpec validates that the overrider specification is correctly defined. // ValidateOverrideSpec validates that the overrider specification is correctly defined.
func ValidateOverrideSpec(overrideSpec *policyv1alpha1.OverrideSpec) field.ErrorList { func ValidateOverrideSpec(overrideSpec *policyv1alpha1.OverrideSpec) field.ErrorList {
var allErrs field.ErrorList var allErrs field.ErrorList

View File

@ -5,6 +5,8 @@ import (
"testing" "testing"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/utils/pointer"
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1" policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
"github.com/karmada-io/karmada/pkg/util" "github.com/karmada-io/karmada/pkg/util"
@ -554,3 +556,74 @@ func TestValidatePropagationSpec(t *testing.T) {
}) })
} }
} }
func TestValidateApplicationFailover(t *testing.T) {
tests := []struct {
name string
applicationFailoverBehavior *policyv1alpha1.ApplicationFailoverBehavior
expectedErr string
}{
{
name: "application failover is nil",
applicationFailoverBehavior: nil,
expectedErr: "",
},
{
name: "the delaySeconds is less than zero",
applicationFailoverBehavior: &policyv1alpha1.ApplicationFailoverBehavior{
BlockPredecessorSeconds: pointer.Int32(100),
DecisionConditions: policyv1alpha1.DecisionConditions{
TolerationSeconds: pointer.Int32(100),
},
PreConditions: &policyv1alpha1.PreConditions{
DelaySeconds: pointer.Int32(-100),
},
},
expectedErr: "spec.failover.application.preConditions.delaySeconds: Invalid value: -100: must be greater than or equal to 0",
},
{
name: "the tolerationSeconds is less than zero",
applicationFailoverBehavior: &policyv1alpha1.ApplicationFailoverBehavior{
BlockPredecessorSeconds: pointer.Int32(100),
DecisionConditions: policyv1alpha1.DecisionConditions{
TolerationSeconds: pointer.Int32(-100),
},
},
expectedErr: "spec.failover.application.decisionConditions.tolerationSeconds: Invalid value: -100: must be greater than or equal to 0",
},
{
name: "the blockPredecessorSeconds is less than zero",
applicationFailoverBehavior: &policyv1alpha1.ApplicationFailoverBehavior{
BlockPredecessorSeconds: pointer.Int32(-100),
DecisionConditions: policyv1alpha1.DecisionConditions{
TolerationSeconds: pointer.Int32(100),
},
},
expectedErr: "spec.failover.application.blockPredecessorSeconds: Invalid value: -100: must be greater than or equal to 0",
},
{
name: "application behavior is correctly defined",
applicationFailoverBehavior: &policyv1alpha1.ApplicationFailoverBehavior{
BlockPredecessorSeconds: pointer.Int32(100),
DecisionConditions: policyv1alpha1.DecisionConditions{
TolerationSeconds: pointer.Int32(100),
},
PreConditions: &policyv1alpha1.PreConditions{
DelaySeconds: pointer.Int32(100),
},
},
expectedErr: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
errs := ValidateApplicationFailover(tt.applicationFailoverBehavior, field.NewPath("spec").Child("failover").Child("application"))
err := errs.ToAggregate()
if err != nil && err.Error() != tt.expectedErr {
t.Errorf("expected error:\n %s, but got:\n %s", tt.expectedErr, err.Error())
} else if err == nil && tt.expectedErr != "" {
t.Errorf("expected error:\n %s, but got no error\n", tt.expectedErr)
}
})
}
}