github.com/zppinho/prow@v0.0.0-20240510014325-1738badeb017/cmd/webhook-server/validation.go (about) 1 /* 2 Copyright 2022 The Kubernetes 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 main 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "io" 23 "net/http" 24 25 "github.com/sirupsen/logrus" 26 27 "k8s.io/api/admission/v1beta1" 28 apiv1 "k8s.io/apimachinery/pkg/apis/meta/v1" 29 "k8s.io/apimachinery/pkg/types" 30 "k8s.io/apimachinery/pkg/util/sets" 31 "sigs.k8s.io/prow/pkg/apis/prowjobs/v1" 32 "sigs.k8s.io/prow/pkg/kube" 33 "sigs.k8s.io/prow/pkg/plank" 34 ) 35 36 var agentsNotSupportingCluster = sets.New[string]("jenkins") 37 38 const ( 39 denied = "DENIED" 40 accepted = "ACCEPTED" 41 ) 42 43 func (wa *webhookAgent) serveValidate(w http.ResponseWriter, r *http.Request) { 44 body, err := io.ReadAll(r.Body) 45 if err != nil { 46 logrus.WithError(err).Info("unable to read request") 47 http.Error(w, fmt.Sprintf("bad request %v", err), http.StatusBadRequest) 48 return 49 } 50 admissionReview := &v1beta1.AdmissionReview{} 51 err = json.Unmarshal(body, admissionReview) 52 if err != nil { 53 logrus.WithError(err).Info("unable to unmarshal admission review request") 54 http.Error(w, fmt.Sprintf("unable to unmarshal admission review request %v", err), http.StatusBadRequest) 55 return 56 } 57 admissionRequest := admissionReview.Request 58 var prowJob v1.ProwJob 59 err = json.Unmarshal(admissionRequest.Object.Raw, &prowJob) 60 if err != nil { 61 logrus.WithError(err).Info("unable to prowjob from request") 62 http.Error(w, fmt.Sprintf("unable to unmarshal prowjob %v", err), http.StatusBadRequest) 63 return 64 } 65 var admissionResponse *v1beta1.AdmissionResponse 66 if admissionRequest.Operation == "CREATE" { 67 if err := validateProwJobClusterOnCreate(prowJob, wa.statuses); err != nil { 68 admissionResponse = createValidatingAdmissionResponse(admissionRequest.UID, err) 69 } else { 70 admissionResponse = createValidatingAdmissionResponse(admissionRequest.UID, nil) 71 } 72 } 73 admissionReview.Response = admissionResponse 74 resp, err := json.Marshal(admissionReview) 75 if err != nil { 76 logrus.WithError(err).Info("unable to marshal response") 77 http.Error(w, fmt.Sprintf("unable to unmarshal prowjob %v", err), http.StatusInternalServerError) 78 return 79 } 80 if _, err := w.Write(resp); err != nil { 81 logrus.WithError(err).Info("unable to write response") 82 http.Error(w, fmt.Sprintf("unable to write response: %v", err), http.StatusInternalServerError) 83 return 84 } 85 } 86 87 func validateProwJobClusterOnCreate(prowJob v1.ProwJob, statuses map[string]plank.ClusterStatus) error { 88 if prowJob.Spec.Cluster != "" && prowJob.Spec.Cluster != kube.DefaultClusterAlias && agentsNotSupportingCluster.Has(string(prowJob.Spec.Agent)) { 89 return fmt.Errorf("%s: cannot set cluster field if agent is %s", prowJob.Name, prowJob.Spec.Agent) 90 } 91 if prowJob.Spec.Agent == v1.KubernetesAgent { 92 _, ok := statuses[prowJob.ClusterAlias()] 93 if !ok { 94 return fmt.Errorf("job configuration for %q specifies unknown 'cluster' value %q", prowJob.Name, prowJob.ClusterAlias()) 95 } 96 } 97 return nil 98 } 99 100 func createValidatingAdmissionResponse(uid types.UID, err error) *v1beta1.AdmissionResponse { 101 var ar *v1beta1.AdmissionResponse 102 var result *apiv1.Status 103 if err != nil { 104 result = &apiv1.Status{ 105 Message: denied, 106 Reason: apiv1.StatusReason(err.Error()), 107 } 108 } else { 109 result = &apiv1.Status{ 110 Message: accepted, 111 } 112 } 113 ar = &v1beta1.AdmissionResponse{ 114 UID: uid, 115 Allowed: err == nil, 116 Result: result, 117 } 118 return ar 119 }