Merge pull request #508 from XiShanYongYe-Chang/webhook

Mutate policy's ResourceSelectors in webhook
This commit is contained in:
karmada-bot 2021-07-09 18:11:28 +08:00 committed by GitHub
commit 1f8c6a9bba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 89 additions and 8 deletions

View File

@ -32,7 +32,7 @@ func (c *ServiceImportController) Reconcile(ctx context.Context, req controllerr
svcImport := &mcsv1alpha1.ServiceImport{} svcImport := &mcsv1alpha1.ServiceImport{}
if err := c.Client.Get(context.TODO(), req.NamespacedName, svcImport); err != nil { if err := c.Client.Get(context.TODO(), req.NamespacedName, svcImport); err != nil {
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
return controllerruntime.Result{}, nil return c.deleteDerivedService(req.NamespacedName)
} }
return controllerruntime.Result{Requeue: true}, err return controllerruntime.Result{Requeue: true}, err
@ -50,14 +50,35 @@ func (c *ServiceImportController) SetupWithManager(mgr controllerruntime.Manager
return controllerruntime.NewControllerManagedBy(mgr).For(&mcsv1alpha1.ServiceImport{}).Complete(c) return controllerruntime.NewControllerManagedBy(mgr).For(&mcsv1alpha1.ServiceImport{}).Complete(c)
} }
func (c *ServiceImportController) deleteDerivedService(svcImport types.NamespacedName) (controllerruntime.Result, error) {
derivedSvc := &corev1.Service{}
derivedSvcNamespacedName := types.NamespacedName{
Namespace: svcImport.Namespace,
Name: names.GenerateDerivedServiceName(svcImport.Name),
}
err := c.Client.Get(context.TODO(), derivedSvcNamespacedName, derivedSvc)
if err != nil {
if errors.IsNotFound(err) {
return controllerruntime.Result{}, nil
}
return controllerruntime.Result{Requeue: true}, err
}
err = c.Client.Delete(context.TODO(), derivedSvc)
if err != nil {
klog.Errorf("Delete derived service(%s) failed, Error: %v", derivedSvcNamespacedName, err)
return controllerruntime.Result{Requeue: true}, err
}
return controllerruntime.Result{}, nil
}
func (c *ServiceImportController) deriveServiceFromServiceImport(svcImport *mcsv1alpha1.ServiceImport) (controllerruntime.Result, error) { func (c *ServiceImportController) deriveServiceFromServiceImport(svcImport *mcsv1alpha1.ServiceImport) (controllerruntime.Result, error) {
newDerivedService := &corev1.Service{ newDerivedService := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Namespace: svcImport.Namespace, Namespace: svcImport.Namespace,
Name: names.GenerateDerivedServiceName(svcImport.Name), Name: names.GenerateDerivedServiceName(svcImport.Name),
OwnerReferences: []metav1.OwnerReference{
*metav1.NewControllerRef(svcImport, svcImport.GroupVersionKind()),
},
}, },
Spec: corev1.ServiceSpec{ Spec: corev1.ServiceSpec{
Type: corev1.ServiceTypeClusterIP, Type: corev1.ServiceTypeClusterIP,
@ -77,7 +98,7 @@ func (c *ServiceImportController) deriveServiceFromServiceImport(svcImport *mcsv
return controllerruntime.Result{Requeue: true}, err return controllerruntime.Result{Requeue: true}, err
} }
return controllerruntime.Result{}, nil return c.updateServiceStatus(svcImport, newDerivedService)
} }
return controllerruntime.Result{Requeue: true}, err return controllerruntime.Result{Requeue: true}, err

View File

@ -92,10 +92,13 @@ const (
ReplicaSetKind = "ReplicaSet" ReplicaSetKind = "ReplicaSet"
// StatefulSetKind indicates the target resource is a statefulset // StatefulSetKind indicates the target resource is a statefulset
StatefulSetKind = "StatefulSet" StatefulSetKind = "StatefulSet"
// ServiceExportKind indicates the target resource is a serviceexport
ServiceExportKind = "ServiceExport"
// EndpointSliceKind indicates the target resource is a endpointslice // EndpointSliceKind indicates the target resource is a endpointslice
EndpointSliceKind = "EndpointSlice" EndpointSliceKind = "EndpointSlice"
// ServiceExportKind indicates the target resource is a serviceexport crd
ServiceExportKind = "ServiceExport"
// ServiceImportKind indicates the target resource is a serviceimport crd
ServiceImportKind = "ServiceImport"
) )
// Define resource filed // Define resource filed

View File

@ -3,10 +3,14 @@ package helper
import ( import (
"fmt" "fmt"
discoveryv1beta1 "k8s.io/api/discovery/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/klog/v2" "k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
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/names"
) )
// DenyReasonResourceSelectorsModify constructs a reason indicating that modify ResourceSelectors is not allowed. // DenyReasonResourceSelectorsModify constructs a reason indicating that modify ResourceSelectors is not allowed.
@ -73,3 +77,46 @@ func IsDependentClusterOverridesPresent(c client.Client, policy *policyv1alpha1.
return true, nil return true, nil
} }
// GetFollowedResourceSelectorsWhenMatchServiceImport get followed derived-service and endpointSlices resource selectors
// when policy's ResourceSelectors contains ResourceSelector, whose kind is ServiceImport.
func GetFollowedResourceSelectorsWhenMatchServiceImport(resourceSelectors []policyv1alpha1.ResourceSelector) []policyv1alpha1.ResourceSelector {
var addedResourceSelectors []policyv1alpha1.ResourceSelector
for _, resourceSelector := range resourceSelectors {
if resourceSelector.Kind != util.ServiceImportKind {
continue
}
if resourceSelector.Namespace == "" || resourceSelector.Name == "" {
continue
}
addedResourceSelectors = append(addedResourceSelectors, GenerateResourceSelectorForServiceImport(resourceSelector)...)
}
return addedResourceSelectors
}
// GenerateResourceSelectorForServiceImport generates resource selectors for ServiceImport.
func GenerateResourceSelectorForServiceImport(svcImport policyv1alpha1.ResourceSelector) []policyv1alpha1.ResourceSelector {
derivedServiceName := names.GenerateDerivedServiceName(svcImport.Name)
return []policyv1alpha1.ResourceSelector{
{
APIVersion: "v1",
Kind: util.ServiceKind,
Namespace: svcImport.Namespace,
Name: derivedServiceName,
},
{
APIVersion: "discovery.k8s.io/v1beta1",
Kind: util.EndpointSliceKind,
Namespace: svcImport.Namespace,
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
discoveryv1beta1.LabelServiceName: derivedServiceName,
},
},
},
}
}

View File

@ -38,6 +38,11 @@ func (a *MutatingAdmission) Handle(ctx context.Context, req admission.Request) a
return admission.Errored(http.StatusBadRequest, fmt.Errorf("ClusterPropagationPolicy's name should be no more than %d characters", validation.LabelValueMaxLength)) return admission.Errored(http.StatusBadRequest, fmt.Errorf("ClusterPropagationPolicy's name should be no more than %d characters", validation.LabelValueMaxLength))
} }
addedResourceSelectors := helper.GetFollowedResourceSelectorsWhenMatchServiceImport(policy.Spec.ResourceSelectors)
if addedResourceSelectors != nil {
policy.Spec.ResourceSelectors = append(policy.Spec.ResourceSelectors, addedResourceSelectors...)
}
marshaledBytes, err := json.Marshal(policy) marshaledBytes, err := json.Marshal(policy)
if err != nil { if err != nil {
return admission.Errored(http.StatusInternalServerError, err) return admission.Errored(http.StatusInternalServerError, err)

View File

@ -41,11 +41,16 @@ func (a *MutatingAdmission) Handle(ctx context.Context, req admission.Request) a
} }
if len(policy.Name) > validation.LabelValueMaxLength { if len(policy.Name) > validation.LabelValueMaxLength {
return admission.Errored(http.StatusBadRequest, fmt.Errorf("PropagationPolicy's name and should be no more than %d characters", validation.LabelValueMaxLength)) return admission.Errored(http.StatusBadRequest, fmt.Errorf("PropagationPolicy's name should be no more than %d characters", validation.LabelValueMaxLength))
} }
// Set default spread constraints if both 'SpreadByField' and 'SpreadByLabel' not set. // Set default spread constraints if both 'SpreadByField' and 'SpreadByLabel' not set.
helper.SetDefaultSpreadConstraints(policy.Spec.Placement.SpreadConstraints) helper.SetDefaultSpreadConstraints(policy.Spec.Placement.SpreadConstraints)
addedResourceSelectors := helper.GetFollowedResourceSelectorsWhenMatchServiceImport(policy.Spec.ResourceSelectors)
if addedResourceSelectors != nil {
policy.Spec.ResourceSelectors = append(policy.Spec.ResourceSelectors, addedResourceSelectors...)
}
marshaledBytes, err := json.Marshal(policy) marshaledBytes, err := json.Marshal(policy)
if err != nil { if err != nil {
return admission.Errored(http.StatusInternalServerError, err) return admission.Errored(http.StatusInternalServerError, err)