sigs.k8s.io/prow@v0.0.0-20240503223140-c5e374dc7eb1/pkg/moonraker/moonraker.go (about) 1 /* 2 Copyright 2023 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 moonraker 18 19 import ( 20 "context" 21 "encoding/json" 22 "fmt" 23 "io" 24 "net/http" 25 "reflect" 26 27 "github.com/sirupsen/logrus" 28 29 prowapi "sigs.k8s.io/prow/pkg/apis/prowjobs/v1" 30 "sigs.k8s.io/prow/pkg/config" 31 ) 32 33 const ( 34 PathGetInrepoconfig = "inrepoconfig" 35 PathPing = "ping" 36 ) 37 38 type Moonraker struct { 39 ConfigAgent *config.Agent 40 InRepoConfigCache *config.InRepoConfigCache 41 } 42 43 type configSectionsToWatch struct { 44 config.InRepoConfig // Map of allowlisted inrepoconfig URLs to clone from 45 } 46 47 // payload is the message payload we use for Moonraker. For 48 // forward-compatibility, we don't use a prowapi.Refs directly. 49 type payload struct { 50 Refs prowapi.Refs `json:"refs"` 51 } 52 53 type ProwYAMLGetter interface { 54 GetProwYAML(payload *payload) (*config.ProwYAML, error) 55 } 56 57 // ServePing responds with "pong". It's meant to be used by clients to check if 58 // the service is up. 59 func (mr *Moonraker) ServePing(w http.ResponseWriter, r *http.Request) { 60 fmt.Fprintf(w, "pong") 61 } 62 63 // serveGetInrepoconfig returns a ProwYAML object marshaled into JSON. 64 func (mr *Moonraker) ServeGetInrepoconfig(w http.ResponseWriter, r *http.Request) { 65 body, err := io.ReadAll(r.Body) 66 if err != nil { 67 logrus.WithError(err).Info("unable to read request") 68 http.Error(w, fmt.Sprintf("bad request %v", err), http.StatusBadRequest) 69 return 70 } 71 72 payload := &payload{} 73 err = json.Unmarshal(body, payload) 74 if err != nil { 75 logrus.WithError(err).Info("unable to unmarshal getInrepoconfig request") 76 http.Error(w, fmt.Sprintf("unable to unmarshal getInrepoconfig request: %v", err), http.StatusBadRequest) 77 return 78 } 79 80 baseSHAGetter := func() (string, error) { 81 return payload.Refs.BaseSHA, nil 82 } 83 var headSHAGetters []func() (string, error) 84 for _, pull := range payload.Refs.Pulls { 85 pull := pull 86 headSHAGetters = append(headSHAGetters, func() (string, error) { 87 return pull.SHA, nil 88 }) 89 } 90 identifier := payload.Refs.Org + "/" + payload.Refs.Repo 91 92 prowYAML, err := mr.InRepoConfigCache.GetProwYAMLWithoutDefaults(identifier, payload.Refs.BaseRef, baseSHAGetter, headSHAGetters...) 93 if err != nil { 94 logrus.WithError(err).Error("unable to retrieve inrepoconfig ProwYAML") 95 http.Error(w, fmt.Sprintf("unable to retrieve inrepoconfig ProwYAML: %v", err), http.StatusBadRequest) 96 return 97 } 98 99 w.Header().Set("Content-Type", "application/json") 100 if err := json.NewEncoder(w).Encode(prowYAML); err != nil { 101 logrus.WithError(err).Error("unable to encode inrepoconfig ProwYAML into JSON") 102 http.Error(w, fmt.Sprintf("unable to encode inrepoconfig ProwYAML into JSON: %v", err), http.StatusBadRequest) 103 return 104 } 105 } 106 107 func (mr *Moonraker) RunConfigWatcher(ctx context.Context) error { 108 configEvent := make(chan config.Delta, 2) 109 mr.ConfigAgent.Subscribe(configEvent) 110 111 var err error 112 defer func() { 113 if err != nil { 114 logrus.WithError(ctx.Err()).Error("ConfigWatcher shutting down.") 115 } 116 logrus.Debug("Pull server shutting down.") 117 }() 118 currentConfig := configSectionsToWatch{ 119 mr.ConfigAgent.Config().InRepoConfig, 120 } 121 122 for { 123 select { 124 // Parent context. Shutdown 125 case <-ctx.Done(): 126 return nil 127 // Checking for update config 128 case event := <-configEvent: 129 newConfig := configSectionsToWatch{ 130 event.After.InRepoConfig, 131 } 132 logrus.Info("Received new config") 133 if !reflect.DeepEqual(currentConfig, newConfig) { 134 logrus.Info("New config found, resetting Config in ConfigAgent") 135 mr.ConfigAgent.SetWithoutBroadcast(&event.After) 136 currentConfig = newConfig 137 } 138 } 139 } 140 }