github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/cloud/pkg/admissioncontroller/admit_devicemodel.go (about) 1 package admissioncontroller 2 3 import ( 4 "encoding/json" 5 "io/ioutil" 6 "net/http" 7 "strings" 8 9 admissionv1beta1 "k8s.io/api/admission/v1beta1" 10 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 11 "k8s.io/klog" 12 13 devicesv1alpha1 "github.com/kubeedge/kubeedge/cloud/pkg/apis/devices/v1alpha1" 14 ) 15 16 // admitFunc is the type we use for all of our validators and mutators 17 type admitFunc func(admissionv1beta1.AdmissionReview) *admissionv1beta1.AdmissionResponse 18 19 func serve(w http.ResponseWriter, r *http.Request, admit admitFunc) { 20 var body []byte 21 if r.Body != nil { 22 if data, err := ioutil.ReadAll(r.Body); err == nil { 23 body = data 24 } 25 } 26 27 // verify the content type is accurate 28 contentType := r.Header.Get("Content-Type") 29 if contentType != "application/json" { 30 klog.Fatalf("contentType=%s, expect application/json", contentType) 31 return 32 } 33 34 // The AdmissionReview that was sent to the webhook 35 requestedAdmissionReview := admissionv1beta1.AdmissionReview{} 36 37 // The AdmissionReview that will be returned 38 responseAdmissionReview := admissionv1beta1.AdmissionReview{} 39 40 deserializer := codecs.UniversalDeserializer() 41 if _, _, err := deserializer.Decode(body, nil, &requestedAdmissionReview); err != nil { 42 klog.Fatalf("decode failed with error: %v", err) 43 responseAdmissionReview.Response = toAdmissionResponse(err) 44 } else { 45 responseAdmissionReview.Response = admit(requestedAdmissionReview) 46 } 47 48 // Return the same UID 49 responseAdmissionReview.Response.UID = requestedAdmissionReview.Request.UID 50 klog.Infof("sending response: %v", responseAdmissionReview.Response) 51 52 respBytes, err := json.Marshal(responseAdmissionReview) 53 if err != nil { 54 klog.Fatalf("cannot marshal to a valid reponse %v", err) 55 } 56 if _, err := w.Write(respBytes); err != nil { 57 klog.Fatalf("cannot write reponse %v", err) 58 } 59 } 60 61 func admitDeviceModel(review admissionv1beta1.AdmissionReview) *admissionv1beta1.AdmissionResponse { 62 reviewResponse := admissionv1beta1.AdmissionResponse{} 63 reviewResponse.Allowed = true 64 var msg string 65 66 switch review.Request.Operation { 67 case admissionv1beta1.Create, admissionv1beta1.Update: 68 raw := review.Request.Object.Raw 69 devicemodel := devicesv1alpha1.DeviceModel{} 70 deserializer := codecs.UniversalDeserializer() 71 if _, _, err := deserializer.Decode(raw, nil, &devicemodel); err != nil { 72 klog.Errorf("validation failed with error: %v", err) 73 return toAdmissionResponse(err) 74 } 75 msg = validateDeviceModel(&devicemodel, &reviewResponse) 76 case admissionv1beta1.Delete, admissionv1beta1.Connect: 77 //no rule defined for above operations, greenlight for all of above. 78 reviewResponse.Allowed = true 79 klog.Info("admission validation passed!") 80 default: 81 klog.Infof("Unsupported webhook operation %v", review.Request.Operation) 82 reviewResponse.Allowed = false 83 msg = msg + "Unsupported webhook operation!" 84 } 85 if !reviewResponse.Allowed { 86 reviewResponse.Result = &metav1.Status{Message: strings.TrimSpace(msg)} 87 } 88 return &reviewResponse 89 } 90 91 func validateDeviceModel(devicemodel *devicesv1alpha1.DeviceModel, response *admissionv1beta1.AdmissionResponse) string { 92 //device properties must be either Int or String while additional properties is not banned. 93 var msg string 94 for _, property := range devicemodel.Spec.Properties { 95 if property.Type.String == nil && property.Type.Int == nil { 96 msg = "Either Int or String must be set" 97 response.Allowed = false 98 } else if property.Type.String != nil && property.Type.Int != nil { 99 msg = "Only one of [Int, String] could be set for properties" 100 response.Allowed = false 101 } 102 } 103 return msg 104 } 105 106 // toAdmissionResponse is a helper function to create an AdmissionResponse 107 func toAdmissionResponse(err error) *admissionv1beta1.AdmissionResponse { 108 return &admissionv1beta1.AdmissionResponse{ 109 Result: &metav1.Status{ 110 Message: err.Error(), 111 }, 112 } 113 } 114 115 func serveDeviceModel(w http.ResponseWriter, r *http.Request) { 116 serve(w, r, admitDeviceModel) 117 }