Skip to content

Commit

Permalink
add: Support the deletion protection of service and ingress
Browse files Browse the repository at this point in the history
Signed-off-by: kevin1689 <kevinyang1689@163.com>
  • Loading branch information
kevin1689-cloud committed Jul 10, 2023
1 parent 7f5046d commit ab3a2f7
Show file tree
Hide file tree
Showing 10 changed files with 485 additions and 0 deletions.
41 changes: 41 additions & 0 deletions config/webhook/manifests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,27 @@ webhooks:
resources:
- imagepulljobs
sideEffects: None
- admissionReviewVersions:
- v1
- v1beta1
clientConfig:
service:
name: webhook-service
namespace: system
path: /validate-ingress
failurePolicy: Fail
name: vingress.kb.io
rules:
- apiGroups:
- networking.k8s.io
apiVersions:
- v1
- v1beta1
operations:
- DELETE
resources:
- ingresses
sideEffects: None
- admissionReviewVersions:
- v1
- v1beta1
Expand Down Expand Up @@ -619,6 +640,26 @@ webhooks:
resources:
- podunavailablebudgets
sideEffects: None
- admissionReviewVersions:
- v1
- v1beta1
clientConfig:
service:
name: webhook-service
namespace: system
path: /validate-service
failurePolicy: Fail
name: vservice.kb.io
rules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- DELETE
resources:
- services
sideEffects: None
- admissionReviewVersions:
- v1
- v1beta1
Expand Down
10 changes: 10 additions & 0 deletions config/webhook/patch_manifests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ webhooks:
matchExpressions:
- key: policy.kruise.io/delete-protection
operator: Exists
- name: vservice.kb.io
objectSelector:
matchExpressions:
- key: policy.kruise.io/delete-protection
operator: Exists
- name: vingress.kb.io
objectSelector:
matchExpressions:
- key: policy.kruise.io/delete-protection
operator: Exists
- name: vpod.kb.io
namespaceSelector:
matchExpressions:
Expand Down
25 changes: 25 additions & 0 deletions pkg/webhook/add_ingress.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
Copyright 2023 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package webhook

import (
"github.com/openkruise/kruise/pkg/webhook/ingress/validating"
)

func init() {
addHandlers(validating.HandlerMap)
}
25 changes: 25 additions & 0 deletions pkg/webhook/add_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
Copyright 2023 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package webhook

import (
"github.com/openkruise/kruise/pkg/webhook/service/validating"
)

func init() {
addHandlers(validating.HandlerMap)
}
87 changes: 87 additions & 0 deletions pkg/webhook/ingress/validating/ingress_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
Copyright 2023 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package validating

import (
"context"
"net/http"

"github.com/openkruise/kruise/pkg/webhook/util/deletionprotection"
admissionv1 "k8s.io/api/admission/v1"
networkingv1 "k8s.io/api/networking/v1"
networkingv1beta1 "k8s.io/api/networking/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

type IngressHandler struct {
Client client.Client

// Decoder decodes objects
Decoder *admission.Decoder
}

var _ admission.Handler = &IngressHandler{}

// Handle handles admission requests.
func (h *IngressHandler) Handle(ctx context.Context, req admission.Request) admission.Response {
if req.AdmissionRequest.Operation != admissionv1.Delete || req.AdmissionRequest.SubResource != "" {
return admission.ValidationResponse(true, "")
}
if len(req.OldObject.Raw) == 0 {
klog.Warningf("Skip to validate ingress %s deletion for no old object, maybe because of Kubernetes version < 1.16", req.Name)
return admission.ValidationResponse(true, "")
}

var metaObj metav1.Object
switch req.Kind.Version {
case "v1beta1":
obj := &networkingv1beta1.Ingress{}
if err := h.Decoder.DecodeRaw(req.AdmissionRequest.OldObject, obj); err != nil {
return admission.Errored(http.StatusBadRequest, err)
}
metaObj = obj
case "v1":
obj := &networkingv1.Ingress{}
if err := h.Decoder.DecodeRaw(req.AdmissionRequest.OldObject, obj); err != nil {
return admission.Errored(http.StatusBadRequest, err)
}
metaObj = obj
}

if err := deletionprotection.ValidateIngressDeletion(metaObj); err != nil {
return admission.Errored(http.StatusForbidden, err)
}
return admission.ValidationResponse(true, "")
}

var _ inject.Client = &IngressHandler{}

func (h *IngressHandler) InjectClient(c client.Client) error {
h.Client = c
return nil
}

var _ admission.DecoderInjector = &IngressHandler{}

func (h *IngressHandler) InjectDecoder(d *admission.Decoder) error {
h.Decoder = d
return nil
}
28 changes: 28 additions & 0 deletions pkg/webhook/ingress/validating/webhooks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
Copyright 2023 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package validating

import "sigs.k8s.io/controller-runtime/pkg/webhook/admission"

// +kubebuilder:webhook:path=/validate-ingress,mutating=false,failurePolicy=fail,sideEffects=None,admissionReviewVersions=v1;v1beta1,groups=networking.k8s.io,resources=ingresses,verbs=delete,versions=v1;v1beta1,name=vingress.kb.io

var (
// HandlerMap contains admission webhook handlers
HandlerMap = map[string]admission.Handler{
"validate-ingress": &IngressHandler{},
}
)
74 changes: 74 additions & 0 deletions pkg/webhook/service/validating/service_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
Copyright 2023 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package validating

import (
"context"
"net/http"

"github.com/openkruise/kruise/pkg/webhook/util/deletionprotection"
admissionv1 "k8s.io/api/admission/v1"
v1 "k8s.io/api/core/v1"
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

type ServiceHandler struct {
Client client.Client

// Decoder decodes objects
Decoder *admission.Decoder
}

var _ admission.Handler = &ServiceHandler{}

// Handle handles admission requests.
func (h *ServiceHandler) Handle(ctx context.Context, req admission.Request) admission.Response {
if req.AdmissionRequest.Operation != admissionv1.Delete || req.AdmissionRequest.SubResource != "" {
return admission.ValidationResponse(true, "")
}
if len(req.OldObject.Raw) == 0 {
klog.Warningf("Skip to validate service %s deletion for no old object, maybe because of Kubernetes version < 1.16", req.Name)
return admission.ValidationResponse(true, "")
}

obj := &v1.Service{}
if err := h.Decoder.DecodeRaw(req.AdmissionRequest.OldObject, obj); err != nil {
return admission.Errored(http.StatusBadRequest, err)
}

if err := deletionprotection.ValidateServiceDeletion(obj); err != nil {
return admission.Errored(http.StatusForbidden, err)
}
return admission.ValidationResponse(true, "")
}

var _ inject.Client = &ServiceHandler{}

func (h *ServiceHandler) InjectClient(c client.Client) error {
h.Client = c
return nil
}

var _ admission.DecoderInjector = &ServiceHandler{}

func (h *ServiceHandler) InjectDecoder(d *admission.Decoder) error {
h.Decoder = d
return nil
}
28 changes: 28 additions & 0 deletions pkg/webhook/service/validating/webhooks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
Copyright 2023 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package validating

import "sigs.k8s.io/controller-runtime/pkg/webhook/admission"

// +kubebuilder:webhook:path=/validate-service,mutating=false,failurePolicy=fail,sideEffects=None,admissionReviewVersions=v1;v1beta1,groups="",resources=services,verbs=delete,versions=v1,name=vservice.kb.io

var (
// HandlerMap contains admission webhook handlers
HandlerMap = map[string]admission.Handler{
"validate-service": &ServiceHandler{},
}
)
24 changes: 24 additions & 0 deletions pkg/webhook/util/deletionprotection/deletion_protection.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,30 @@ func ValidateWorkloadDeletion(obj metav1.Object, replicas *int32) error {
return nil
}

func ValidateServiceDeletion(service *v1.Service) error {
if !utilfeature.DefaultFeatureGate.Enabled(features.ResourcesDeletionProtection) || service.DeletionTimestamp != nil {
return nil
}
switch val := service.Labels[policyv1alpha1.DeletionProtectionKey]; val {
case policyv1alpha1.DeletionProtectionTypeAlways:
return fmt.Errorf("forbidden by ResourcesProtectionDeletion for %s=%s", policyv1alpha1.DeletionProtectionKey, val)
default:
}
return nil
}

func ValidateIngressDeletion(obj metav1.Object) error {
if !utilfeature.DefaultFeatureGate.Enabled(features.ResourcesDeletionProtection) || obj.GetDeletionTimestamp() != nil {
return nil
}
switch val := obj.GetLabels()[policyv1alpha1.DeletionProtectionKey]; val {
case policyv1alpha1.DeletionProtectionTypeAlways:
return fmt.Errorf("forbidden by ResourcesProtectionDeletion for %s=%s", policyv1alpha1.DeletionProtectionKey, val)
default:
}
return nil
}

func ValidateNamespaceDeletion(c client.Client, namespace *v1.Namespace) error {
if !utilfeature.DefaultFeatureGate.Enabled(features.ResourcesDeletionProtection) || namespace.DeletionTimestamp != nil {
return nil
Expand Down
Loading

0 comments on commit ab3a2f7

Please sign in to comment.