github.com/abayer/test-infra@v0.0.5/mungegithub/mungers/e2e/resolved.go (about) 1 /* 2 Copyright 2016 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 e2e 18 19 import ( 20 "encoding/json" 21 "net/http" 22 "strconv" 23 "sync" 24 25 cache "k8s.io/test-infra/mungegithub/mungers/flakesync" 26 27 "github.com/golang/glog" 28 ) 29 30 type resolutionKey struct { 31 job cache.Job 32 number cache.Number 33 } 34 35 // ResolutionTracker provides a place for build cops to say "I've resolved this 36 // problem" so the merge queue can continue merging. 37 type ResolutionTracker struct { 38 resolved map[resolutionKey]bool 39 lock sync.RWMutex 40 } 41 42 // NewResolutionTracker constructs an empty resolution tracker. It's the 43 // caller's responsibility to hook up Get/SetHTTP. 44 func NewResolutionTracker() *ResolutionTracker { 45 return &ResolutionTracker{ 46 resolved: map[resolutionKey]bool{}, 47 } 48 } 49 50 // Resolved returns true if the given build has been manually marked as resolved. 51 func (r *ResolutionTracker) Resolved(j cache.Job, n cache.Number) bool { 52 r.lock.RLock() 53 defer r.lock.RUnlock() 54 return r.resolved[resolutionKey{j, n}] 55 } 56 57 func getReqKey(req *http.Request) (key resolutionKey, err error) { 58 key.job = cache.Job(req.URL.Query().Get("job")) 59 var n int 60 n, err = strconv.Atoi(req.URL.Query().Get("number")) 61 key.number = cache.Number(n) 62 return key, err 63 } 64 65 func (r *ResolutionTracker) serve(data interface{}, status int, res http.ResponseWriter) { 66 res.Header().Set("Content-type", "application/json") 67 res.WriteHeader(status) 68 if err := json.NewEncoder(res).Encode(data); err != nil { 69 glog.Errorf("Couldn't write %#v: %v", data, err) 70 } 71 } 72 73 // ListHTTP returns a list of overrides that have been entered. 74 func (r *ResolutionTracker) ListHTTP(res http.ResponseWriter, req *http.Request) { 75 r.lock.RLock() 76 defer r.lock.RUnlock() 77 type Entry struct { 78 Job cache.Job 79 Number cache.Number 80 Resolved bool 81 } 82 var list []Entry 83 for key, resolved := range r.resolved { 84 if !resolved { 85 continue 86 } 87 list = append(list, Entry{ 88 Job: key.job, 89 Number: key.number, 90 Resolved: true, 91 }) 92 } 93 r.serve(struct{ ManualResolutions []Entry }{list}, http.StatusOK, res) 94 } 95 96 // GetHTTP accepts "job" and "number" query parameters and returns a json blob 97 // indicating whether the specified build has been marked as resolved. 98 func (r *ResolutionTracker) GetHTTP(res http.ResponseWriter, req *http.Request) { 99 key, err := getReqKey(req) 100 if err != nil { 101 r.serve(struct{ Error string }{err.Error()}, http.StatusNotAcceptable, res) 102 return 103 } 104 r.lock.RLock() 105 defer r.lock.RUnlock() 106 r.serveKeyLocked(key, res) 107 } 108 109 // SetHTTP accepts "job", "number", and "resolved" query parameters. "resolved" 110 // counts as "true" if not explicitly set to "false". Returns a json blob 111 // indicating whether the specified build has been marked as resolved. 112 func (r *ResolutionTracker) SetHTTP(res http.ResponseWriter, req *http.Request) { 113 key, err := getReqKey(req) 114 if err != nil { 115 r.serve(struct{ Error string }{err.Error()}, http.StatusNotAcceptable, res) 116 return 117 } 118 r.lock.Lock() 119 defer r.lock.Unlock() 120 r.resolved[key] = req.URL.Query().Get("resolved") != "false" 121 glog.Infof("Marking manually resolved: %v %v: %v", key.job, key.number, r.resolved[key]) 122 r.serveKeyLocked(key, res) 123 } 124 125 func (r *ResolutionTracker) serveKeyLocked(key resolutionKey, res http.ResponseWriter) { 126 r.serve(struct { 127 Job string 128 Number int 129 Resolved bool 130 }{ 131 string(key.job), 132 int(key.number), 133 r.resolved[key], 134 }, http.StatusOK, res) 135 }