Skip to content

Commit

Permalink
add: Support the deletion protection of service and ingress (#1269)
Browse files Browse the repository at this point in the history
Signed-off-by: kevin1689 <kevinyang1689@163.com>
  • Loading branch information
kevin1689-cloud authored Mar 7, 2024
1 parent 6bb78c4 commit 04254fb
Show file tree
Hide file tree
Showing 11 changed files with 495 additions and 2 deletions.
41 changes: 41 additions & 0 deletions config/webhook/manifests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,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 @@ -659,6 +680,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
4 changes: 2 additions & 2 deletions pkg/features/kruise_features.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ const (
CloneSetPartitionRollback featuregate.Feature = "CloneSetPartitionRollback"

// ResourcesDeletionProtection enables protection for resources deletion, currently supports
// Namespace, CustomResourcesDefinition, Deployment, StatefulSet, ReplicaSet, CloneSet, Advanced StatefulSet, UnitedDeployment.
// Namespace, Service, Ingress, CustomResourcesDefinition, Deployment, StatefulSet, ReplicaSet, CloneSet, Advanced StatefulSet, UnitedDeployment.
// It is only supported for Kubernetes version >= 1.16
// Note that if it is enabled during Kruise installation or upgrade, Kruise will require more authorities:
// 1. Webhook for deletion operation of namespace, crd, deployment, statefulset, replicaset and workloads in Kruise.
// 1. Webhook for deletion operation of namespace, service, ingress, crd, deployment, statefulset, replicaset and workloads in Kruise.
ResourcesDeletionProtection featuregate.Feature = "ResourcesDeletionProtection"

// PodUnavailableBudgetDeleteGate enables PUB capability to protect pod from deletion and eviction
Expand Down
29 changes: 29 additions & 0 deletions pkg/webhook/add_ingress.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
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/features"
utilfeature "github.com/openkruise/kruise/pkg/util/feature"
"github.com/openkruise/kruise/pkg/webhook/ingress/validating"
)

func init() {
addHandlersWithGate(validating.HandlerMap, func() (enabled bool) {
return utilfeature.DefaultFeatureGate.Enabled(features.ResourcesDeletionProtection)
})
}
29 changes: 29 additions & 0 deletions pkg/webhook/add_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
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/features"
utilfeature "github.com/openkruise/kruise/pkg/util/feature"
"github.com/openkruise/kruise/pkg/webhook/service/validating"
)

func init() {
addHandlersWithGate(validating.HandlerMap, func() (enabled bool) {
return utilfeature.DefaultFeatureGate.Enabled(features.ResourcesDeletionProtection)
})
}
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 @@ -49,6 +49,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 04254fb

Please sign in to comment.