add webhook for clusterpropagationpolicy and propagationpolicy (#201)
Signed-off-by: lihanbo <lihanbo2@huawei.com>
This commit is contained in:
parent
614d7b0b8d
commit
d48065f086
|
|
@ -19,6 +19,20 @@ webhooks:
|
|||
sideEffects: None
|
||||
admissionReviewVersions: ["v1beta1"]
|
||||
timeoutSeconds: 3
|
||||
- name: clusterpropagationpolicy.karmada.io
|
||||
rules:
|
||||
- operations: ["CREATE", "UPDATE"]
|
||||
apiGroups: ["policy.karmada.io"]
|
||||
apiVersions: ["*"]
|
||||
resources: ["clusterpropagationpolicies"]
|
||||
scope: "Cluster"
|
||||
clientConfig:
|
||||
url: https://karmada-webhook.karmada-system.svc:443/mutate-clusterpropagationpolicy
|
||||
caBundle: {{caBundle}}
|
||||
failurePolicy: Fail
|
||||
sideEffects: None
|
||||
admissionReviewVersions: ["v1beta1"]
|
||||
timeoutSeconds: 3
|
||||
- name: overridepolicy.karmada.io
|
||||
rules:
|
||||
- operations: ["CREATE", "UPDATE"]
|
||||
|
|
@ -69,3 +83,17 @@ webhooks:
|
|||
sideEffects: None
|
||||
admissionReviewVersions: ["v1beta1"]
|
||||
timeoutSeconds: 3
|
||||
- name: clusterpropagationpolicy.karmada.io
|
||||
rules:
|
||||
- operations: ["CREATE", "UPDATE"]
|
||||
apiGroups: ["policy.karmada.io"]
|
||||
apiVersions: ["*"]
|
||||
resources: ["clusterpropagationpolicies"]
|
||||
scope: "Cluster"
|
||||
clientConfig:
|
||||
url: https://karmada-webhook.karmada-system.svc:443/validate-clusterpropagationpolicy
|
||||
caBundle: {{caBundle}}
|
||||
failurePolicy: Fail
|
||||
sideEffects: None
|
||||
admissionReviewVersions: ["v1beta1"]
|
||||
timeoutSeconds: 3
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/karmada-io/karmada/cmd/webhook/app/options"
|
||||
"github.com/karmada-io/karmada/pkg/util/gclient"
|
||||
"github.com/karmada-io/karmada/pkg/webhook/cluster"
|
||||
"github.com/karmada-io/karmada/pkg/webhook/clusterpropagationpolicy"
|
||||
"github.com/karmada-io/karmada/pkg/webhook/overridepolicy"
|
||||
"github.com/karmada-io/karmada/pkg/webhook/propagationpolicy"
|
||||
)
|
||||
|
|
@ -69,6 +70,8 @@ func Run(opts *options.Options, stopChan <-chan struct{}) error {
|
|||
hookServer.Register("/validate-cluster", &webhook.Admission{Handler: &cluster.ValidatingAdmission{}})
|
||||
hookServer.Register("/mutate-propagationpolicy", &webhook.Admission{Handler: &propagationpolicy.MutatingAdmission{}})
|
||||
hookServer.Register("/validate-propagationpolicy", &webhook.Admission{Handler: &propagationpolicy.ValidatingAdmission{}})
|
||||
hookServer.Register("/mutate-clusterpropagationpolicy", &webhook.Admission{Handler: &clusterpropagationpolicy.MutatingAdmission{}})
|
||||
hookServer.Register("/validate-clusterpropagationpolicy", &webhook.Admission{Handler: &clusterpropagationpolicy.ValidatingAdmission{}})
|
||||
hookServer.Register("/mutate-overridepolicy", &webhook.Admission{Handler: &overridepolicy.MutatingAdmission{}})
|
||||
hookServer.WebhookMux.Handle("/readyz/", http.StripPrefix("/readyz/", &healthz.Handler{}))
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
package helper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
|
||||
)
|
||||
|
||||
// DenyReasonResourceSelectorsModify constructs a reason indicating that modify ResourceSelectors is not allowed.
|
||||
const DenyReasonResourceSelectorsModify = "modify ResourceSelectors is forbidden"
|
||||
|
||||
// SetDefaultSpreadConstraints set default spread constraints if both 'SpreadByField' and 'SpreadByLabel' not set.
|
||||
func SetDefaultSpreadConstraints(spreadConstraints []policyv1alpha1.SpreadConstraint) {
|
||||
for i := range spreadConstraints {
|
||||
if len(spreadConstraints[i].SpreadByLabel) == 0 && len(spreadConstraints[i].SpreadByField) == 0 {
|
||||
klog.Infof("Setting default SpreadByField with %s", policyv1alpha1.SpreadByFieldCluster)
|
||||
spreadConstraints[i].SpreadByField = policyv1alpha1.SpreadByFieldCluster
|
||||
}
|
||||
|
||||
if spreadConstraints[i].MinGroups == 0 {
|
||||
klog.Infof("Setting default MinGroups to 1")
|
||||
spreadConstraints[i].MinGroups = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ValidateSpreadConstraint tests if the constraints is valid.
|
||||
func ValidateSpreadConstraint(spreadConstraints []policyv1alpha1.SpreadConstraint) error {
|
||||
// SpreadByField and SpreadByLabel should not co-exist
|
||||
for _, constraint := range spreadConstraints {
|
||||
if len(constraint.SpreadByField) > 0 && len(constraint.SpreadByLabel) > 0 {
|
||||
return fmt.Errorf("invalid constraints: SpreadByLabel(%s) should not co-exist with spreadByField(%s)", constraint.SpreadByLabel, constraint.SpreadByField)
|
||||
}
|
||||
|
||||
// If MaxGroups provided, it should greater or equal than MinGroups.
|
||||
if constraint.MaxGroups > 0 && constraint.MaxGroups < constraint.MinGroups {
|
||||
return fmt.Errorf("maxGroups(%d) lower than minGroups(%d) is not allowed", constraint.MaxGroups, constraint.MinGroups)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package clusterpropagationpolicy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
||||
|
||||
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
|
||||
"github.com/karmada-io/karmada/pkg/util/helper"
|
||||
)
|
||||
|
||||
// MutatingAdmission mutates API request if necessary.
|
||||
type MutatingAdmission struct {
|
||||
decoder *admission.Decoder
|
||||
}
|
||||
|
||||
// Check if our MutatingAdmission implements necessary interface
|
||||
var _ admission.Handler = &MutatingAdmission{}
|
||||
var _ admission.DecoderInjector = &MutatingAdmission{}
|
||||
|
||||
// Handle yields a response to an AdmissionRequest.
|
||||
func (a *MutatingAdmission) Handle(ctx context.Context, req admission.Request) admission.Response {
|
||||
policy := &policyv1alpha1.ClusterPropagationPolicy{}
|
||||
|
||||
err := a.decoder.Decode(req, policy)
|
||||
if err != nil {
|
||||
return admission.Errored(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
// Set default spread constraints if both 'SpreadByField' and 'SpreadByLabel' not set.
|
||||
helper.SetDefaultSpreadConstraints(policy.Spec.Placement.SpreadConstraints)
|
||||
|
||||
marshaledBytes, err := json.Marshal(policy)
|
||||
if err != nil {
|
||||
return admission.Errored(http.StatusInternalServerError, err)
|
||||
}
|
||||
|
||||
return admission.PatchResponseFromRaw(req.Object.Raw, marshaledBytes)
|
||||
}
|
||||
|
||||
// InjectDecoder implements admission.DecoderInjector interface.
|
||||
// A decoder will be automatically injected.
|
||||
func (a *MutatingAdmission) InjectDecoder(d *admission.Decoder) error {
|
||||
a.decoder = d
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package clusterpropagationpolicy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"k8s.io/api/admission/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/api/equality"
|
||||
"k8s.io/klog/v2"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
||||
|
||||
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
|
||||
"github.com/karmada-io/karmada/pkg/util/helper"
|
||||
)
|
||||
|
||||
// ValidatingAdmission validates ClusterPropagationPolicy object when creating/updating/deleting.
|
||||
type ValidatingAdmission struct {
|
||||
decoder *admission.Decoder
|
||||
}
|
||||
|
||||
// Check if our ValidatingAdmission implements necessary interface
|
||||
var _ admission.Handler = &ValidatingAdmission{}
|
||||
var _ admission.DecoderInjector = &ValidatingAdmission{}
|
||||
|
||||
// Handle implements admission.Handler interface.
|
||||
// It yields a response to an AdmissionRequest.
|
||||
func (v *ValidatingAdmission) Handle(ctx context.Context, req admission.Request) admission.Response {
|
||||
policy := &policyv1alpha1.ClusterPropagationPolicy{}
|
||||
|
||||
err := v.decoder.Decode(req, policy)
|
||||
if err != nil {
|
||||
return admission.Errored(http.StatusBadRequest, err)
|
||||
}
|
||||
klog.V(2).Infof("Validating ClusterPropagationPolicy(%s) for request: %s", policy.Name, req.Operation)
|
||||
|
||||
if req.Operation == v1beta1.Update {
|
||||
oldPolicy := &policyv1alpha1.ClusterPropagationPolicy{}
|
||||
err := v.decoder.DecodeRaw(req.OldObject, oldPolicy)
|
||||
if err != nil {
|
||||
return admission.Errored(http.StatusBadRequest, err)
|
||||
}
|
||||
if !equality.Semantic.DeepEqual(policy.Spec.ResourceSelectors, oldPolicy.Spec.ResourceSelectors) {
|
||||
klog.Info(helper.DenyReasonResourceSelectorsModify)
|
||||
return admission.Denied(helper.DenyReasonResourceSelectorsModify)
|
||||
}
|
||||
}
|
||||
|
||||
if err := helper.ValidateSpreadConstraint(policy.Spec.Placement.SpreadConstraints); err != nil {
|
||||
klog.Info(err)
|
||||
return admission.Denied(err.Error())
|
||||
}
|
||||
|
||||
return admission.Allowed("")
|
||||
}
|
||||
|
||||
// InjectDecoder implements admission.DecoderInjector interface.
|
||||
// A decoder will be automatically injected.
|
||||
func (v *ValidatingAdmission) InjectDecoder(d *admission.Decoder) error {
|
||||
v.decoder = d
|
||||
return nil
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
||||
|
||||
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
|
||||
"github.com/karmada-io/karmada/pkg/util/helper"
|
||||
)
|
||||
|
||||
// MutatingAdmission mutates API request if necessary.
|
||||
|
|
@ -38,18 +39,7 @@ func (a *MutatingAdmission) Handle(ctx context.Context, req admission.Request) a
|
|||
}
|
||||
|
||||
// Set default spread constraints if both 'SpreadByField' and 'SpreadByLabel' not set.
|
||||
spreadConstraints := policy.Spec.Placement.SpreadConstraints
|
||||
for i := range spreadConstraints {
|
||||
if len(spreadConstraints[i].SpreadByLabel) == 0 && len(spreadConstraints[i].SpreadByField) == 0 {
|
||||
klog.Infof("Setting default SpreadByField with %s", policyv1alpha1.SpreadByFieldCluster)
|
||||
spreadConstraints[i].SpreadByField = policyv1alpha1.SpreadByFieldCluster
|
||||
}
|
||||
|
||||
if spreadConstraints[i].MinGroups == 0 {
|
||||
klog.Infof("Setting default MinGroups to 1")
|
||||
spreadConstraints[i].MinGroups = 1
|
||||
}
|
||||
}
|
||||
helper.SetDefaultSpreadConstraints(policy.Spec.Placement.SpreadConstraints)
|
||||
|
||||
marshaledBytes, err := json.Marshal(policy)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -2,13 +2,15 @@ package propagationpolicy
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"k8s.io/api/admission/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/api/equality"
|
||||
"k8s.io/klog/v2"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
||||
|
||||
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
|
||||
"github.com/karmada-io/karmada/pkg/util/helper"
|
||||
)
|
||||
|
||||
// ValidatingAdmission validates PropagationPolicy object when creating/updating/deleting.
|
||||
|
|
@ -31,20 +33,21 @@ func (v *ValidatingAdmission) Handle(ctx context.Context, req admission.Request)
|
|||
}
|
||||
klog.V(2).Infof("Validating PropagationPolicy(%s/%s) for request: %s", policy.Namespace, policy.Name, req.Operation)
|
||||
|
||||
// SpreadByField and SpreadByLabel should not co-exist
|
||||
for _, constraint := range policy.Spec.Placement.SpreadConstraints {
|
||||
if len(constraint.SpreadByField) > 0 && len(constraint.SpreadByLabel) > 0 {
|
||||
errMsg := fmt.Sprintf("invalid constraints: SpreadByLabel(%s) should not co-exist with spreadByField(%s)", constraint.SpreadByLabel, constraint.SpreadByField)
|
||||
klog.Info(errMsg)
|
||||
return admission.Denied(errMsg)
|
||||
if req.Operation == v1beta1.Update {
|
||||
oldPolicy := &policyv1alpha1.PropagationPolicy{}
|
||||
err := v.decoder.DecodeRaw(req.OldObject, oldPolicy)
|
||||
if err != nil {
|
||||
return admission.Errored(http.StatusBadRequest, err)
|
||||
}
|
||||
if !equality.Semantic.DeepEqual(policy.Spec.ResourceSelectors, oldPolicy.Spec.ResourceSelectors) {
|
||||
klog.Info(helper.DenyReasonResourceSelectorsModify)
|
||||
return admission.Denied(helper.DenyReasonResourceSelectorsModify)
|
||||
}
|
||||
}
|
||||
|
||||
// If MaxGroups provided, it should greater or equal than MinGroups.
|
||||
if constraint.MaxGroups > 0 && constraint.MaxGroups < constraint.MinGroups {
|
||||
errMsg := fmt.Sprintf("maxGroups(%d) lower than minGroups(%d) is not allowed", constraint.MaxGroups, constraint.MinGroups)
|
||||
klog.Info(errMsg)
|
||||
return admission.Denied(errMsg)
|
||||
}
|
||||
if err := helper.ValidateSpreadConstraint(policy.Spec.Placement.SpreadConstraints); err != nil {
|
||||
klog.Info(err)
|
||||
return admission.Denied(err.Error())
|
||||
}
|
||||
|
||||
return admission.Allowed("")
|
||||
|
|
|
|||
Loading…
Reference in New Issue