github.com/oam-dev/kubevela@v1.9.11/pkg/webhook/core.oam.dev/v1beta1/application/validating_handler.go (about) 1 /* 2 Copyright 2021 The KubeVela Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package application 18 19 import ( 20 "context" 21 "fmt" 22 "net/http" 23 24 admissionv1 "k8s.io/api/admission/v1" 25 "k8s.io/apimachinery/pkg/util/validation/field" 26 "sigs.k8s.io/controller-runtime/pkg/client" 27 "sigs.k8s.io/controller-runtime/pkg/manager" 28 "sigs.k8s.io/controller-runtime/pkg/runtime/inject" 29 "sigs.k8s.io/controller-runtime/pkg/webhook" 30 "sigs.k8s.io/controller-runtime/pkg/webhook/admission" 31 32 "github.com/kubevela/workflow/pkg/cue/packages" 33 34 "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" 35 controller "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev" 36 "github.com/oam-dev/kubevela/pkg/oam/util" 37 ) 38 39 var _ admission.Handler = &ValidatingHandler{} 40 41 // ValidatingHandler handles application 42 type ValidatingHandler struct { 43 pd *packages.PackageDiscover 44 Client client.Client 45 // Decoder decodes objects 46 Decoder *admission.Decoder 47 } 48 49 var _ inject.Client = &ValidatingHandler{} 50 51 // InjectClient injects the client into the ApplicationValidateHandler 52 func (h *ValidatingHandler) InjectClient(c client.Client) error { 53 if h.Client != nil { 54 return nil 55 } 56 h.Client = c 57 return nil 58 } 59 60 var _ admission.DecoderInjector = &ValidatingHandler{} 61 62 // InjectDecoder injects the decoder into the ApplicationValidateHandler 63 func (h *ValidatingHandler) InjectDecoder(d *admission.Decoder) error { 64 if h.Decoder != nil { 65 return nil 66 } 67 h.Decoder = d 68 return nil 69 } 70 71 func simplifyError(err error) error { 72 switch e := err.(type) { // nolint 73 case *field.Error: 74 return fmt.Errorf("field \"%s\": %s error encountered, %s. ", e.Field, e.Type, e.Detail) 75 default: 76 return err 77 } 78 } 79 80 func mergeErrors(errs field.ErrorList) error { 81 s := "" 82 for _, err := range errs { 83 s += fmt.Sprintf("field \"%s\": %s error encountered, %s. ", err.Field, err.Type, err.Detail) 84 } 85 return fmt.Errorf(s) 86 } 87 88 // Handle validate Application Spec here 89 func (h *ValidatingHandler) Handle(ctx context.Context, req admission.Request) admission.Response { 90 app := &v1beta1.Application{} 91 if err := h.Decoder.Decode(req, app); err != nil { 92 return admission.Errored(http.StatusBadRequest, err) 93 } 94 ctx = util.SetNamespaceInCtx(ctx, app.Namespace) 95 switch req.Operation { 96 case admissionv1.Create: 97 if allErrs := h.ValidateCreate(ctx, app); len(allErrs) > 0 { 98 // http.StatusUnprocessableEntity will NOT report any error descriptions 99 // to the client, use generic http.StatusBadRequest instead. 100 return admission.Errored(http.StatusBadRequest, mergeErrors(allErrs)) 101 } 102 case admissionv1.Update: 103 oldApp := &v1beta1.Application{} 104 if err := h.Decoder.DecodeRaw(req.AdmissionRequest.OldObject, oldApp); err != nil { 105 return admission.Errored(http.StatusBadRequest, simplifyError(err)) 106 } 107 if app.ObjectMeta.DeletionTimestamp.IsZero() { 108 if allErrs := h.ValidateUpdate(ctx, app, oldApp); len(allErrs) > 0 { 109 return admission.Errored(http.StatusBadRequest, mergeErrors(allErrs)) 110 } 111 } 112 default: 113 // Do nothing for DELETE and CONNECT 114 } 115 return admission.ValidationResponse(true, "") 116 } 117 118 // RegisterValidatingHandler will register application validate handler to the webhook 119 func RegisterValidatingHandler(mgr manager.Manager, args controller.Args) { 120 server := mgr.GetWebhookServer() 121 server.Register("/validating-core-oam-dev-v1beta1-applications", &webhook.Admission{Handler: &ValidatingHandler{pd: args.PackageDiscover}}) 122 }