-
Notifications
You must be signed in to change notification settings - Fork 40
feat: deny the member leave when member still has serviceExport #1092
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,12 +5,15 @@ import ( | |
| "fmt" | ||
| "net/http" | ||
|
|
||
| admissionv1 "k8s.io/api/admission/v1" | ||
| "k8s.io/apimachinery/pkg/types" | ||
| "k8s.io/klog/v2" | ||
| "sigs.k8s.io/controller-runtime/pkg/client" | ||
| "sigs.k8s.io/controller-runtime/pkg/manager" | ||
| "sigs.k8s.io/controller-runtime/pkg/webhook" | ||
| "sigs.k8s.io/controller-runtime/pkg/webhook/admission" | ||
|
|
||
| fleetnetworkingv1alpha1 "go.goms.io/fleet-networking/api/v1alpha1" | ||
| clusterv1beta1 "go.goms.io/fleet/apis/cluster/v1beta1" | ||
| "go.goms.io/fleet/pkg/utils" | ||
| "go.goms.io/fleet/pkg/utils/validator" | ||
|
|
@@ -22,26 +25,47 @@ var ( | |
| ) | ||
|
|
||
| type memberClusterValidator struct { | ||
| client client.Client | ||
| decoder webhook.AdmissionDecoder | ||
| } | ||
|
|
||
| // Add registers the webhook for K8s bulit-in object types. | ||
| func Add(mgr manager.Manager) error { | ||
| hookServer := mgr.GetWebhookServer() | ||
| hookServer.Register(ValidationPath, &webhook.Admission{Handler: &memberClusterValidator{admission.NewDecoder(mgr.GetScheme())}}) | ||
| hookServer.Register(ValidationPath, &webhook.Admission{Handler: &memberClusterValidator{client: mgr.GetClient(), decoder: admission.NewDecoder(mgr.GetScheme())}}) | ||
| return nil | ||
| } | ||
|
|
||
| // Handle memberClusterValidator checks to see if member cluster has valid fields. | ||
| func (v *memberClusterValidator) Handle(_ context.Context, req admission.Request) admission.Response { | ||
| func (v *memberClusterValidator) Handle(ctx context.Context, req admission.Request) admission.Response { | ||
| mcObjectName := types.NamespacedName{Name: req.Name, Namespace: req.Namespace} | ||
| klog.V(2).InfoS("Validating webhook handling member cluster", "operation", req.Operation, "memberCluster", mcObjectName) | ||
|
|
||
| if req.Operation == admissionv1.Delete { // Will reject the requests whenever the serviceExport is not deleted | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have some random thoughts, these are not blocker per se, just something that occurred to me when reading the code:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We already have a webhook that guards against deletion attempts on Azure Fleet Manager from users (or any source other than RP, AKS support, etc.). So technically speaking the added logic is added to prevent RP (in most cases) from triggering the deletion. How would these components interact I guess? The concern is mostly that users won't see the error message that reminds them to delete service exports.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For upstream they have full control so we generally assume that protection is not 100% a must.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the RP side, we should surface this error to the user. Will test that. |
||
| klog.V(2).InfoS("Validating webhook member cluster DELETE", "memberCluster", mcObjectName) | ||
| namespaceName := fmt.Sprintf(utils.NamespaceNameFormat, mcObjectName.Name) | ||
| internalServiceExportList := &fleetnetworkingv1alpha1.InternalServiceExportList{} | ||
| if err := v.client.List(ctx, internalServiceExportList, client.InNamespace(namespaceName)); err != nil { | ||
| klog.ErrorS(err, "Failed to list internalServiceExportList when validating") | ||
| return admission.Errored(http.StatusInternalServerError, fmt.Errorf("failed to list internalServiceExportList, please retry the request: %w", err)) | ||
| } | ||
| for _, internalServiceExport := range internalServiceExportList.Items { | ||
| if internalServiceExport.DeletionTimestamp.IsZero() { | ||
| klog.Warning("ServiceExport exists in the member cluster, request is denied", "operation", req.Operation, "memberCluster", mcObjectName) | ||
| return admission.Denied(fmt.Sprintf("Please delete serviceExport %s in the member cluster before leaving, request is denied", internalServiceExport.Spec.ServiceReference.NamespacedName)) | ||
| } | ||
| } | ||
| return admission.Allowed("Member cluster is ready to leave") | ||
| } | ||
|
|
||
| var mc clusterv1beta1.MemberCluster | ||
| klog.V(2).InfoS("Validating webhook handling member cluster", "operation", req.Operation, "namespacedName", types.NamespacedName{Name: req.Name}) | ||
| if err := v.decoder.Decode(req, &mc); err != nil { | ||
| klog.ErrorS(err, "Failed to decode member cluster object for validating fields", "userName", req.UserInfo.Username, "groups", req.UserInfo.Groups) | ||
| return admission.Errored(http.StatusBadRequest, err) | ||
| } | ||
|
|
||
| if err := validator.ValidateMemberCluster(mc); err != nil { | ||
| klog.V(2).ErrorS(err, "Member cluster has invalid fields, request is denied", "operation", req.Operation, "namespacedName", types.NamespacedName{Name: mc.Name}) | ||
| klog.V(2).ErrorS(err, "Member cluster has invalid fields, request is denied", "operation", req.Operation, "memberCluster", mcObjectName) | ||
| return admission.Denied(err.Error()) | ||
| } | ||
| return admission.Allowed("Member cluster has valid fields") | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another naming nit: the added logic might no longer belong in a validator? It's more of a guard 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is, the logic seems to be more aligned with those in
fleetresourcehandlerpkg?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fleetresourcehandler pkg is aim to validate the CR permissions so far. feel this package is better?