Skip to content

Commit

Permalink
fix(webhook): cleanup validatingconfig on openebs namespace deletion
Browse files Browse the repository at this point in the history
from k8s 1.20+ onwards Cluster-scoped dependents can only specify
cluster-scoped owners. In v1.20+, if a cluster-scoped dependent
specifies a namespaced kind as an owner, it is treated as having
an unresolveable owner reference, and is not able to be garbage
collected.

In v1.20+, if the garbage collector detects an invalid cross-namespace
ownerReference, or a cluster-scoped dependent with an ownerReference
referencing a namespaced kind, a warning Event with a reason of
OwnerRefInvalidNamespace and an involvedObject of the invalid dependent
is reported. You can check for that kind of Event by running
kubectl get events -A --field-selector=reason=OwnerRefInvalidNamespace.

Signed-off-by: prateekpandey14 <[email protected]>
  • Loading branch information
prateekpandey14 committed Feb 10, 2021
1 parent 291f6f4 commit d4e2f71
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 5 deletions.
2 changes: 2 additions & 0 deletions cmd/webhook/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import (
"k8s.io/client-go/tools/clientcmd"
"k8s.io/klog"

// ndmclientset "github.com/openebs/api/v2/pkg/client/openebs.io/ndm/v1alpha1/clientset/internalclientset"

clientset "github.com/openebs/api/v2/pkg/client/clientset/versioned"
//snapclientset "github.com/openebs/maya/pkg/client/generated/openebs.io/snapshot/v1alpha1/clientset/internalclientset"
)
Expand Down
30 changes: 26 additions & 4 deletions pkg/webhook/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (

"github.com/openebs/api/v2/pkg/apis/types"
"github.com/openebs/api/v2/pkg/util"
cutil "github.com/openebs/cstor-operators/pkg/util/maps"
"github.com/openebs/cstor-operators/pkg/version"
"github.com/pkg/errors"
"k8s.io/api/admissionregistration/v1beta1"
Expand Down Expand Up @@ -73,13 +74,17 @@ var (
Ignore = admissionregistration.Ignore
// Fail means that an error calling the webhook causes the admission to fail.
Fail = admissionregistration.Fail
// SideEffectClassNone means that calling the webhook will have no side effects.
SideEffectClassNone = v1beta1.SideEffectClassNone
// WebhookFailurePolicye represents failure policy env name to make it configurable
// via ENV
WebhookFailurePolicy = "ADMISSION_WEBHOOK_FAILURE_POLICY"
// transformation function lists to upgrade webhook resources
transformSecret = []transformSecretFunc{}
transformSvc = []transformSvcFunc{}
transformConfig = []transformConfigFunc{}
transformSecret = []transformSecretFunc{}
transformSvc = []transformSvcFunc{}
transformConfig = []transformConfigFunc{
addNSWithDeleteRule,
}
cvcRuleWithOperations = v1beta1.RuleWithOperations{
Operations: []v1beta1.OperationType{
v1beta1.Update,
Expand All @@ -90,6 +95,16 @@ var (
Resources: []string{"cstorvolumeconfigs"},
},
}
nsRuleWithOperations = v1beta1.RuleWithOperations{
Operations: []v1beta1.OperationType{
v1beta1.Delete,
},
Rule: v1beta1.Rule{
APIGroups: []string{"*"},
APIVersions: []string{"*"},
Resources: []string{"namespaces"},
},
}
)

// createWebhookService creates our webhook Service resource if it does not
Expand Down Expand Up @@ -202,6 +217,7 @@ func (c *client) createAdmissionValidatingConfig(
},
},
cvcRuleWithOperations,
nsRuleWithOperations,
},
ClientConfig: admissionregistration.WebhookClientConfig{
Service: &admissionregistration.ServiceReference{
Expand All @@ -211,7 +227,7 @@ func (c *client) createAdmissionValidatingConfig(
},
CABundle: signingCert,
},
// SideEffects: &sideEffectClass,
SideEffects: &SideEffectClassNone,
// AdmissionReviewVersions: []string{"v1"},
TimeoutSeconds: &five,
FailurePolicy: failurePolicy(),
Expand Down Expand Up @@ -423,6 +439,12 @@ func getOpenebsNamespace() (string, error) {
return ns, nil
}

func addNSWithDeleteRule(config *v1beta1.ValidatingWebhookConfiguration) {
if cutil.IsCurrentLessThanNewVersion(config.Labels[string(types.OpenEBSVersionLabelKey)], "2.5.0") {
config.Webhooks[0].Rules = append(config.Webhooks[0].Rules, nsRuleWithOperations)
}
}

// GetAdmissionName return the admission server name
func GetAdmissionName() (string, error) {
admissionName, found := os.LookupEnv(AdmissionNameEnvVar)
Expand Down
111 changes: 111 additions & 0 deletions pkg/webhook/namespace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
Copyright 2021 The OpenEBS 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 (
"fmt"

"k8s.io/api/admission/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/klog"
)

func (wh *webhook) validateNamespace(ar *v1beta1.AdmissionReview) *v1beta1.AdmissionResponse {
req := ar.Request
response := &v1beta1.AdmissionResponse{}
response.Allowed = true
openebsNamespace, err := getOpenebsNamespace()
if err != nil {
response.Allowed = false
response.Result = &metav1.Status{
Message: fmt.Sprintf("error getting OPENEBS_NAMESPACE env %s: %v", req.Name, err.Error()),
}
return response
}
// validates only if requested operation is DELETE
if openebsNamespace == req.Name && req.Operation == v1beta1.Delete {
return wh.validateNamespaceDeleteRequest(req)
}
klog.V(2).Info("Admission wehbook for Namespace module not " +
"configured for operations other than DELETE")
return response
}

func (wh *webhook) validateNamespaceDeleteRequest(req *v1beta1.AdmissionRequest) *v1beta1.AdmissionResponse {
response := &v1beta1.AdmissionResponse{}
response.Allowed = true
svcLabel := "openebs.io/controller-service=jiva-controller-svc"

msg := fmt.Sprintf("either BDCs or services with the label %s exists in the namespace %s.", svcLabel, req.Name)

// ignore the Delete request of Namespace if resource name is empty
if req.Name == "" {
return response
}

bdcList, err := wh.clientset.OpenebsV1alpha1().
BlockDeviceClaims(req.Name).
List(metav1.ListOptions{})
if err != nil {
response.Allowed = false
response.Result = &metav1.Status{
Message: fmt.Sprintf("error listing BDC in namespace %s: %v", req.Name, err.Error()),
}
return response
}

if len(bdcList.Items) != 0 {
response.Allowed = false
response.Result = &metav1.Status{
Message: msg,
}
return response
}

svcList, err := wh.kubeClient.CoreV1().Services(req.Name).
List(metav1.ListOptions{
LabelSelector: svcLabel,
})
if err != nil {
response.Allowed = false
response.Result = &metav1.Status{
Message: fmt.Sprintf("error listing svc in namespace %s: %v", req.Name, err.Error()),
}
return response
}

if len(svcList.Items) != 0 {
response.Allowed = false
response.Result = &metav1.Status{
Message: msg,
}
return response
}
// Delete the validatingWebhookConfiguration only if its a delete request to
// delete openebs namespace
err = wh.kubeClient.AdmissionregistrationV1().
ValidatingWebhookConfigurations().
Delete(validatorWebhook, &metav1.DeleteOptions{})
if err != nil {
response.Allowed = false
response.Result = &metav1.Status{
Message: err.Error(),
}
return response
}
return response
}
6 changes: 5 additions & 1 deletion pkg/webhook/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,13 +182,16 @@ func validationRequired(ignoredList []string, metadata *metav1.ObjectMeta) bool
return required
}

// validate validates the persistentvolumeclaim(PVC) create, delete request
// validate validates the different openebs resource related operations
func (wh *webhook) validate(ar *v1beta1.AdmissionReview) *v1beta1.AdmissionResponse {
req := ar.Request
response := &v1beta1.AdmissionResponse{}
response.Allowed = true
klog.Info("Admission webhook request received")
switch req.Kind.Kind {
case "Namespace":
klog.V(2).Infof("Admission webhook request for type %s", req.Kind.Kind)
return wh.validateNamespace(ar)
case "PersistentVolumeClaim":
klog.V(2).Infof("Admission webhook request for type %s", req.Kind.Kind)
return wh.validatePVC(ar)
Expand All @@ -198,6 +201,7 @@ func (wh *webhook) validate(ar *v1beta1.AdmissionReview) *v1beta1.AdmissionRespo
case "CStorVolumeConfig":
klog.V(2).Infof("Admission webhook request for type %s", req.Kind.Kind)
return wh.validateCVC(ar)

default:
klog.V(2).Infof("Admission webhook not configured for type %s", req.Kind.Kind)
return response
Expand Down

0 comments on commit d4e2f71

Please sign in to comment.