Name: "arvados-controller",
}
h.cache = map[string]*cacheEnt{
- "/discovery/v1/apis/arvados/v1/rest": &cacheEnt{},
+ "/discovery/v1/apis/arvados/v1/rest": &cacheEnt{validateDD: true},
}
go h.trashSweepWorker()
// cacheEnt implements a basic stale-while-revalidate cache, suitable
// for the Arvados discovery document.
type cacheEnt struct {
+ validateDD bool
mtx sync.Mutex
header http.Header
body []byte
header[k] = v
}
}
- if mediatype, _, err := mime.ParseMediaType(header.Get("Content-Type")); err == nil && mediatype == "application/json" {
+ if ent.validateDD {
+ var dd arvados.DiscoveryDocument
+ if err := json.Unmarshal(body, &dd); err != nil {
+ return nil, nil, fmt.Errorf("error decoding JSON response: %w", err)
+ } else if dd.BasePath == "" {
+ return nil, nil, errors.New("error in discovery document: no value for basePath")
+ }
+ } else if mediatype, _, err := mime.ParseMediaType(header.Get("Content-Type")); err == nil && mediatype == "application/json" {
if !json.Valid(body) {
return nil, nil, errors.New("invalid JSON encoding in response")
}
return &wg
}
clearCache := func() {
- for path := range s.handler.cache {
- s.handler.cache[path] = &cacheEnt{}
+ for _, ent := range s.handler.cache {
+ ent.refreshLock.Lock()
+ ent.mtx.Lock()
+ ent.body, ent.header, ent.refreshAfter = nil, nil, time.Time{}
+ ent.mtx.Unlock()
+ ent.refreshLock.Unlock()
}
}
expireCache := func() {
}
c.Check(countRailsReqs(), check.Equals, reqsBefore+1)
- // Configure railsSpy to return an error when wantError==true.
- var wantError bool
+ // Configure railsSpy to return an error or bad content
+ // depending on flags.
+ var wantError, wantBadContent bool
s.railsSpy.Director = func(req *http.Request) {
if wantError {
req.Method = "MAKE-COFFEE"
+ } else if wantBadContent {
+ req.URL.Path = "/_health/ping"
+ req.Header.Set("Authorization", "Bearer "+arvadostest.ManagementToken)
}
}
wg.Wait()
c.Check(countRailsReqs(), check.Equals, reqsBefore+5)
+ // Response status is OK but body is not a discovery document
+ wantError = false
+ wantBadContent = true
+ reqsBefore = countRailsReqs()
+ c.Check(getDD(), check.Equals, http.StatusBadGateway)
+ c.Check(countRailsReqs(), check.Equals, reqsBefore+1)
+
// Error condition clears => caller gets OK, cache is warmed
// up
- wantError = false
+ wantBadContent = false
reqsBefore = countRailsReqs()
getDDConcurrently(5, http.StatusOK, check.Commentf("success after errors at startup")).Wait()
c.Check(countRailsReqs(), check.Equals, reqsBefore+1)