github.com/zppinho/prow@v0.0.0-20240510014325-1738badeb017/cmd/webhook-server/mutation.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 "gomodules.xyz/jsonpatch/v2" 27 "k8s.io/api/admission/v1beta1" 28 apiv1 "k8s.io/apimachinery/pkg/apis/meta/v1" 29 "k8s.io/apimachinery/pkg/types" 30 "sigs.k8s.io/prow/pkg/apis/prowjobs/v1" 31 "sigs.k8s.io/prow/pkg/config" 32 ) 33 34 func (wa *webhookAgent) serveMutate(w http.ResponseWriter, r *http.Request) { 35 body, err := io.ReadAll(r.Body) 36 if err != nil { 37 logrus.WithError(err).Info("unable to read request") 38 http.Error(w, fmt.Sprintf("bad request %v", err), http.StatusBadRequest) 39 return 40 } 41 admissionReview := &v1beta1.AdmissionReview{} 42 err = json.Unmarshal(body, admissionReview) 43 if err != nil { 44 logrus.WithError(err).Info("unable to unmarshal admission review request") 45 http.Error(w, fmt.Sprintf("unable to unmarshal admission review request %v", err), http.StatusBadRequest) 46 return 47 } 48 admissionRequest := admissionReview.Request 49 var prowJob v1.ProwJob 50 err = json.Unmarshal(admissionRequest.Object.Raw, &prowJob) 51 if err != nil { 52 logrus.WithError(err).Info("unable to prowjob from request") 53 http.Error(w, fmt.Sprintf("unable to unmarshal prowjob %v", err), http.StatusBadRequest) 54 return 55 } 56 var mutatedProwJobPatch []byte 57 if admissionRequest.Operation == "CREATE" { 58 mutatedProwJobPatch, err = generateMutatingPatch(&prowJob, wa.plank) 59 if err != nil { 60 logrus.WithError(err).Info("unable to return mutated prowjob patch") 61 http.Error(w, fmt.Sprintf("unable to return mutated prowjob patch %v", err), http.StatusInternalServerError) 62 return 63 } 64 } 65 admissionReview.Response = createMutatingAdmissionResponse(admissionRequest.UID, mutatedProwJobPatch) 66 resp, err := json.Marshal(admissionReview) 67 if err != nil { 68 logrus.WithError(err).Info("unable to marshal response") 69 http.Error(w, fmt.Sprintf("unable to marshal mutated prowjob patch %v", err), http.StatusInternalServerError) 70 return 71 } 72 if _, err := w.Write(resp); err != nil { 73 logrus.WithError(err).Info("unable to write response") 74 http.Error(w, fmt.Sprintf("unable to write response: %v", err), http.StatusInternalServerError) 75 return 76 } 77 } 78 79 func createMutatingAdmissionResponse(uid types.UID, patch []byte) *v1beta1.AdmissionResponse { 80 return &v1beta1.AdmissionResponse{ 81 UID: uid, 82 Allowed: true, 83 Result: &apiv1.Status{ 84 Message: accepted, 85 }, 86 Patch: patch, 87 PatchType: func() *v1beta1.PatchType { 88 pt := v1beta1.PatchTypeJSONPatch 89 return &pt 90 }(), 91 } 92 } 93 94 func generateMutatingPatch(prowJob *v1.ProwJob, plank config.Plank) ([]byte, error) { 95 var defDecorationConfig *v1.DecorationConfig 96 var patchBytes []byte 97 if prowJob.Spec.Type == v1.PeriodicJob { 98 var repo string 99 if len(prowJob.Spec.ExtraRefs) > 0 { 100 repo = fmt.Sprintf("%s/%s", prowJob.Spec.ExtraRefs[0].Org, prowJob.Spec.ExtraRefs[0].Repo) 101 } 102 defDecorationConfig = plank.GuessDefaultDecorationConfigWithJobDC(repo, prowJob.Spec.Cluster, prowJob.Spec.DecorationConfig) 103 } else { 104 defDecorationConfig = plank.GuessDefaultDecorationConfig(prowJob.Spec.Refs.Repo, prowJob.Spec.Cluster) 105 } 106 prowJobCopy := prowJob.DeepCopy() 107 prowJobCopy.Spec.DecorationConfig = prowJobCopy.Spec.DecorationConfig.ApplyDefault(defDecorationConfig) 108 originalProwJobJSON, err := json.Marshal(prowJob) 109 if err != nil { 110 return nil, fmt.Errorf("unable to marshal prowjob %v", err) 111 } 112 mutatedProwJobJSON, err := json.Marshal(prowJobCopy) 113 if err != nil { 114 return nil, fmt.Errorf("unable to marshal prowjob %v", err) 115 } 116 patch, err := jsonpatch.CreatePatch(originalProwJobJSON, mutatedProwJobJSON) 117 if err != nil { 118 return nil, fmt.Errorf("unable to create json patch") 119 } 120 patchBytes, err = json.Marshal(patch) 121 if err != nil { 122 return nil, fmt.Errorf("unable to marshal patch") 123 } 124 125 return patchBytes, nil 126 }