aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksandr Nogikh <nogikh@google.com>2023-10-09 16:30:20 +0200
committerAleksandr Nogikh <nogikh@google.com>2023-10-12 11:18:22 +0000
commitd753e779cd5f71b91eaca2e18c383c6598e77c9f (patch)
tree65aee07af8b18ce7d5736e8420a966bd7abf3c45
parent3cefb1441cc82b6846ee4b8e43c1661d417c88e9 (diff)
dashboard: access config through context
We used to have a single global `config` variable and access it throughout the whole dashboard application. However, this approach has been more and more complicated test writing -- sometimes we want the config to be only slightly different, so that it's not worth it adding new namespaces, sometimes we have to test how dashboard handles config changes over time. This has already led to a number of hacky contextWithXXX methods that mocked various parts of the global variable. The rest of the code had to sometimes still use `config` directly and sometimes invoke getXXX(c) methods. This is very inconsistent and prone to errors. With more and more situations where we need to patch the config appearing (see #4118), let's refactor the application to always access config via the getConfig(c) method. This allows us to uniformly patch the config and be sure that the non-patched copy is not accessible from anywhere else.
-rw-r--r--dashboard/app/access.go9
-rw-r--r--dashboard/app/access_test.go16
-rw-r--r--dashboard/app/admin.go10
-rw-r--r--dashboard/app/api.go26
-rw-r--r--dashboard/app/asset_storage.go2
-rw-r--r--dashboard/app/asset_storage_test.go4
-rw-r--r--dashboard/app/bisect_test.go8
-rw-r--r--dashboard/app/cache.go6
-rw-r--r--dashboard/app/config.go57
-rw-r--r--dashboard/app/email_test.go21
-rw-r--r--dashboard/app/entities.go26
-rw-r--r--dashboard/app/graphs.go8
-rw-r--r--dashboard/app/handler.go12
-rw-r--r--dashboard/app/jobs.go44
-rw-r--r--dashboard/app/jobs_test.go19
-rw-r--r--dashboard/app/kcidb.go4
-rw-r--r--dashboard/app/label.go2
-rw-r--r--dashboard/app/main.go60
-rw-r--r--dashboard/app/main_test.go2
-rw-r--r--dashboard/app/notifications_test.go4
-rw-r--r--dashboard/app/reporting.go45
-rw-r--r--dashboard/app/reporting_email.go96
-rw-r--r--dashboard/app/reporting_lists.go20
-rw-r--r--dashboard/app/reporting_test.go11
-rw-r--r--dashboard/app/subsystem.go29
-rw-r--r--dashboard/app/subsystem_test.go2
-rw-r--r--dashboard/app/tree.go8
-rw-r--r--dashboard/app/tree_test.go4
-rw-r--r--dashboard/app/util_test.go74
29 files changed, 336 insertions, 293 deletions
diff --git a/dashboard/app/access.go b/dashboard/app/access.go
index 97ed8af01..10a4ac3e9 100644
--- a/dashboard/app/access.go
+++ b/dashboard/app/access.go
@@ -63,7 +63,7 @@ func accessLevel(c context.Context, r *http.Request) AccessLevel {
if u == nil ||
// Devappserver does not pass AuthDomain.
u.AuthDomain != "gmail.com" && !isBrokenAuthDomainInTest ||
- !strings.HasSuffix(u.Email, config.AuthDomain) {
+ !strings.HasSuffix(u.Email, getConfig(c).AuthDomain) {
return AccessPublic
}
return AccessUser
@@ -127,7 +127,7 @@ func checkCrashTextAccess(c context.Context, r *http.Request, field string, id i
if err := db.Get(c, keys[0].Parent(), bug); err != nil {
return nil, nil, fmt.Errorf("failed to get bug: %w", err)
}
- bugLevel := bug.sanitizeAccess(accessLevel(c, r))
+ bugLevel := bug.sanitizeAccess(c, accessLevel(c, r))
return bug, crash, checkAccessLevel(c, r, bugLevel)
}
@@ -151,11 +151,12 @@ func checkJobTextAccess(c context.Context, r *http.Request, field string, id int
if err := db.Get(c, keys[0].Parent(), bug); err != nil {
return fmt.Errorf("failed to get bug: %w", err)
}
- bugLevel := bug.sanitizeAccess(accessLevel(c, r))
+ bugLevel := bug.sanitizeAccess(c, accessLevel(c, r))
return checkAccessLevel(c, r, bugLevel)
}
-func (bug *Bug) sanitizeAccess(currentLevel AccessLevel) AccessLevel {
+func (bug *Bug) sanitizeAccess(c context.Context, currentLevel AccessLevel) AccessLevel {
+ config := getConfig(c)
for ri := len(bug.Reporting) - 1; ri >= 0; ri-- {
bugReporting := &bug.Reporting[ri]
if ri == 0 || !bugReporting.Reported.IsZero() {
diff --git a/dashboard/app/access_test.go b/dashboard/app/access_test.go
index 7bd412acf..1247a8e36 100644
--- a/dashboard/app/access_test.go
+++ b/dashboard/app/access_test.go
@@ -12,11 +12,13 @@ import (
"testing"
"github.com/google/syzkaller/dashboard/dashapi"
+ "golang.org/x/net/context"
"google.golang.org/appengine/v2/user"
)
// TestAccessConfig checks that access level were properly assigned throughout the config.
func TestAccessConfig(t *testing.T) {
+ config := getConfig(context.Background())
tests := []struct {
what string
want AccessLevel
@@ -162,7 +164,7 @@ func TestAccess(t *testing.T) {
c.expectOK(err)
crash, _, err := findCrashForBug(c.ctx, bug)
c.expectOK(err)
- bugID := bug.keyHash()
+ bugID := bug.keyHash(c.ctx)
entities = append(entities, []entity{
{
level: level,
@@ -242,7 +244,7 @@ func TestAccess(t *testing.T) {
build, err := loadBuild(c.ctx, ns, buildID)
c.expectOK(err)
entities = append(entities, entity{
- level: config.Namespaces[ns].AccessLevel,
+ level: c.config().Namespaces[ns].AccessLevel,
ref: build.ID,
url: fmt.Sprintf("/text?tag=KernelConfig&id=%v", build.KernelConfig),
})
@@ -268,10 +270,10 @@ func TestAccess(t *testing.T) {
// duplicate/similar cross-references.
for _, ns := range []string{"access-admin", "access-user", "access-public"} {
clientName, clientKey := "", ""
- for k, v := range config.Namespaces[ns].Clients {
+ for k, v := range c.config().Namespaces[ns].Clients {
clientName, clientKey = k, v
}
- nsLevel := config.Namespaces[ns].AccessLevel
+ nsLevel := c.config().Namespaces[ns].AccessLevel
namespaceAccessPrefix := accessLevelPrefix(nsLevel)
client := c.makeClient(clientName, clientKey, true)
build := testBuild(1)
@@ -280,7 +282,7 @@ func TestAccess(t *testing.T) {
noteBuildAccessLevel(ns, build.ID)
for reportingIdx := 0; reportingIdx < 2; reportingIdx++ {
- accessLevel := config.Namespaces[ns].Reporting[reportingIdx].AccessLevel
+ accessLevel := c.config().Namespaces[ns].Reporting[reportingIdx].AccessLevel
accessPrefix := accessLevelPrefix(accessLevel)
crashInvalid := testCrashWithRepro(build, reportingIdx*10+0)
@@ -292,8 +294,8 @@ func TestAccess(t *testing.T) {
}
client.updateBug(repInvalid.ID, dashapi.BugStatusInvalid, "")
// Invalid bugs become visible up to the last reporting.
- finalLevel := config.Namespaces[ns].
- Reporting[len(config.Namespaces[ns].Reporting)-1].AccessLevel
+ finalLevel := c.config().Namespaces[ns].
+ Reporting[len(c.config().Namespaces[ns].Reporting)-1].AccessLevel
noteBugAccessLevel(repInvalid.ID, finalLevel, nsLevel)
crashFixed := testCrashWithRepro(build, reportingIdx*10+0)
diff --git a/dashboard/app/admin.go b/dashboard/app/admin.go
index 56c3d8bd5..767b4a627 100644
--- a/dashboard/app/admin.go
+++ b/dashboard/app/admin.go
@@ -213,7 +213,7 @@ func updateBugReporting(c context.Context, w http.ResponseWriter, r *http.Reques
return err
}
log.Warningf(c, "fetched %v bugs for namespce %v", len(bugs), ns)
- cfg := config.Namespaces[ns]
+ cfg := getConfig(c).Namespaces[ns]
var update []*db.Key
for i, bug := range bugs {
if len(bug.Reporting) >= len(cfg.Reporting) {
@@ -222,7 +222,7 @@ func updateBugReporting(c context.Context, w http.ResponseWriter, r *http.Reques
update = append(update, keys[i])
}
return updateBatch(c, update, func(_ *db.Key, bug *Bug) {
- err := bug.updateReportings(cfg, timeNow(c))
+ err := bug.updateReportings(c, cfg, timeNow(c))
if err != nil {
panic(err)
}
@@ -364,8 +364,8 @@ func updateHeadReproLevel(c context.Context, w http.ResponseWriter, r *http.Requ
}
}
if actual != bug.HeadReproLevel {
- fmt.Fprintf(w, "%v: HeadReproLevel mismatch, actual=%d db=%d\n", bugLink(bug.keyHash()), actual, bug.HeadReproLevel)
- newLevels[bug.keyHash()] = actual
+ fmt.Fprintf(w, "%v: HeadReproLevel mismatch, actual=%d db=%d\n", bugLink(bug.keyHash(c)), actual, bug.HeadReproLevel)
+ newLevels[bug.keyHash(c)] = actual
keys = append(keys, key)
}
return nil
@@ -373,7 +373,7 @@ func updateHeadReproLevel(c context.Context, w http.ResponseWriter, r *http.Requ
return err
}
return updateBatch(c, keys, func(_ *db.Key, bug *Bug) {
- newLevel, ok := newLevels[bug.keyHash()]
+ newLevel, ok := newLevels[bug.keyHash(c)]
if !ok {
panic("fetched unknown bug")
}
diff --git a/dashboard/app/api.go b/dashboard/app/api.go
index 7ce56c390..a9b220f2d 100644
--- a/dashboard/app/api.go
+++ b/dashboard/app/api.go
@@ -132,7 +132,7 @@ func handleAPI(c context.Context, r *http.Request) (reply interface{}, err error
return nil, err
}
// Somewhat confusingly the "key" parameter is the password.
- ns, err := checkClient(config, client, r.PostFormValue("key"), subj)
+ ns, err := checkClient(getConfig(c), client, r.PostFormValue("key"), subj)
if err != nil {
if client != "" {
log.Errorf(c, "%v", err)
@@ -220,7 +220,7 @@ loop:
}
func reportEmail(c context.Context, ns string) string {
- for _, reporting := range config.Namespaces[ns].Reporting {
+ for _, reporting := range getConfig(c).Namespaces[ns].Reporting {
if _, ok := reporting.Config.(*EmailConfig); ok {
return ownEmail(c)
}
@@ -232,7 +232,7 @@ func apiCommitPoll(c context.Context, ns string, r *http.Request, payload []byte
resp := &dashapi.CommitPollResp{
ReportEmail: reportEmail(c, ns),
}
- for _, repo := range getKernelRepos(c, ns) {
+ for _, repo := range getConfig(c).Namespaces[ns].Repos {
if repo.NoPoll {
continue
}
@@ -652,7 +652,7 @@ func managerList(c context.Context, ns string) ([]string, error) {
if err != nil {
return nil, fmt.Errorf("failed to query builds: %w", err)
}
- configManagers := config.Namespaces[ns].Managers
+ configManagers := getConfig(c).Namespaces[ns].Managers
var managers []string
for _, build := range builds {
if configManagers[build.Manager].Decommissioned {
@@ -681,9 +681,9 @@ func apiReportBuildError(c context.Context, ns string, r *http.Request, payload
if err := updateManager(c, ns, req.Build.Manager, func(mgr *Manager, stats *ManagerStats) error {
log.Infof(c, "failed build on %v: kernel=%v", req.Build.Manager, req.Build.KernelCommit)
if req.Build.KernelCommit != "" {
- mgr.FailedBuildBug = bug.keyHash()
+ mgr.FailedBuildBug = bug.keyHash(c)
} else {
- mgr.FailedSyzBuildBug = bug.keyHash()
+ mgr.FailedSyzBuildBug = bug.keyHash(c)
}
return nil
}); err != nil {
@@ -706,7 +706,7 @@ func apiReportCrash(c context.Context, ns string, r *http.Request, payload []byt
if err != nil {
return nil, err
}
- if !config.Namespaces[ns].TransformCrash(build, req) {
+ if !getConfig(c).Namespaces[ns].TransformCrash(build, req) {
return new(dashapi.ReportCrashResp), nil
}
bug, err := reportCrash(c, build, req)
@@ -856,7 +856,7 @@ func (crash *Crash) UpdateReportingPriority(c context.Context, build *Build, bug
prio += 1e8 // prefer reporting crash that matches bug title
}
managerPrio := 0
- if _, mgrConfig := activeManager(crash.Manager, bug.Namespace); mgrConfig != nil {
+ if _, mgrConfig := activeManager(c, crash.Manager, bug.Namespace); mgrConfig != nil {
managerPrio = mgrConfig.Priority
}
prio += int64((managerPrio - MinManagerPriority) * 1e5)
@@ -1221,7 +1221,7 @@ func loadBugReport(c context.Context, bug *Bug) (*dashapi.BugReport, error) {
}
// Create report for the last reporting so that it's stable and ExtID does not change over time.
bugReporting := &bug.Reporting[len(bug.Reporting)-1]
- reporting := config.Namespaces[bug.Namespace].ReportingByName(bugReporting.Name)
+ reporting := getConfig(c).Namespaces[bug.Namespace].ReportingByName(bugReporting.Name)
if reporting == nil {
return nil, fmt.Errorf("reporting %v is missing in config", bugReporting.Name)
}
@@ -1382,7 +1382,7 @@ func createBugForCrash(c context.Context, ns string, req *dashapi.Crash) (*Bug,
tx := func(c context.Context) error {
for seq := int64(0); ; seq++ {
bug = new(Bug)
- bugHash := bugKeyHash(ns, req.Title, seq)
+ bugHash := bugKeyHash(c, ns, req.Title, seq)
bugKey := db.NewKey(c, "Bug", bugHash, 0, nil)
if err := db.Get(c, bugKey, bug); err != nil {
if err != db.ErrNoSuchEntity {
@@ -1403,7 +1403,7 @@ func createBugForCrash(c context.Context, ns string, req *dashapi.Crash) (*Bug,
LastTime: now,
SubsystemsTime: now,
}
- err = bug.updateReportings(config.Namespaces[ns], now)
+ err = bug.updateReportings(c, getConfig(c).Namespaces[ns], now)
if err != nil {
return err
}
@@ -1465,7 +1465,7 @@ func needReproForBug(c context.Context, bug *Bug) bool {
bug.Title == suppressedReportTitle {
return false
}
- if !config.Namespaces[bug.Namespace].NeedRepro(bug) {
+ if !getConfig(c).Namespaces[bug.Namespace].NeedRepro(bug) {
return false
}
bestReproLevel := ReproLevelC
@@ -1604,7 +1604,7 @@ func checkClient(conf *GlobalConfig, name0, secretPassword, oauthSubject string)
func handleRefreshSubsystems(w http.ResponseWriter, r *http.Request) {
c := appengine.NewContext(r)
const updateBugsCount = 25
- for ns := range config.Namespaces {
+ for ns := range getConfig(c).Namespaces {
err := reassignBugSubsystems(c, ns, updateBugsCount)
if err != nil {
log.Errorf(c, "failed to update subsystems for %s: %v", ns, err)
diff --git a/dashboard/app/asset_storage.go b/dashboard/app/asset_storage.go
index 3ce096799..64d23f1fa 100644
--- a/dashboard/app/asset_storage.go
+++ b/dashboard/app/asset_storage.go
@@ -136,7 +136,7 @@ func neededCrashURLs(c context.Context) ([]string, error) {
func handleDeprecateAssets(w http.ResponseWriter, r *http.Request) {
c := appengine.NewContext(r)
- for ns := range config.Namespaces {
+ for ns := range getConfig(c).Namespaces {
err := deprecateNamespaceAssets(c, ns)
if err != nil {
log.Errorf(c, "deprecateNamespaceAssets failed for ns=%v: %v", ns, err)
diff --git a/dashboard/app/asset_storage_test.go b/dashboard/app/asset_storage_test.go
index c42b0d651..80d71105d 100644
--- a/dashboard/app/asset_storage_test.go
+++ b/dashboard/app/asset_storage_test.go
@@ -66,7 +66,7 @@ func TestBuildAssetLifetime(t *testing.T) {
crashLogLink := externalLink(c.ctx, textCrashLog, dbCrash.Log)
kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig)
c.expectEQ(sender, fromAddr(c.ctx))
- to := config.Namespaces["test2"].Reporting[0].Config.(*EmailConfig).Email
+ to := c.config().Namespaces["test2"].Reporting[0].Config.(*EmailConfig).Email
c.expectEQ(msg.To, []string{to})
c.expectEQ(msg.Subject, crash.Title)
c.expectEQ(len(msg.Attachments), 0)
@@ -358,7 +358,7 @@ func TestCrashAssetLifetime(t *testing.T) {
crashLogLink := externalLink(c.ctx, textCrashLog, dbCrash.Log)
kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig)
c.expectEQ(sender, fromAddr(c.ctx))
- to := config.Namespaces["test2"].Reporting[0].Config.(*EmailConfig).Email
+ to := c.config().Namespaces["test2"].Reporting[0].Config.(*EmailConfig).Email
c.expectEQ(msg.To, []string{to})
c.expectEQ(msg.Subject, crash.Title)
c.expectEQ(len(msg.Attachments), 0)
diff --git a/dashboard/app/bisect_test.go b/dashboard/app/bisect_test.go
index 504e7d396..5e10d5a7d 100644
--- a/dashboard/app/bisect_test.go
+++ b/dashboard/app/bisect_test.go
@@ -170,9 +170,9 @@ For information about bisection process see: https://goo.gl/tpsmEJ#bisection
`, extBugID, bisectLogLink, bisectCrashReportLink, bisectCrashLogLink, kernelConfigLink, reproSyzLink, reproCLink))
syzRepro := []byte(fmt.Sprintf("# https://testapp.appspot.com/bug?id=%v\n%s#%s\n%s",
- dbBug.keyHash(), syzReproPrefix, crash2.ReproOpts, crash2.ReproSyz))
+ dbBug.keyHash(c.ctx), syzReproPrefix, crash2.ReproOpts, crash2.ReproSyz))
cRepro := []byte(fmt.Sprintf("// https://testapp.appspot.com/bug?id=%v\n%s",
- dbBug.keyHash(), crash2.ReproC))
+ dbBug.keyHash(c.ctx), crash2.ReproC))
c.checkURLContents(bisectLogLink, []byte("bisect log 2"))
c.checkURLContents(bisectCrashReportLink, []byte("bisect crash report"))
c.checkURLContents(bisectCrashLogLink, []byte("bisect crash log"))
@@ -428,7 +428,7 @@ For information about bisection process see: https://goo.gl/tpsmEJ#bisection
`, extBugID, bisectLogLink, bisectCrashReportLink, bisectCrashLogLink, kernelConfigLink, reproSyzLink, reproCLink))
syzRepro := []byte(fmt.Sprintf("# https://testapp.appspot.com/bug?id=%v\n%s#%s\n%s",
- dbBug.keyHash(), syzReproPrefix, crash4.ReproOpts, crash4.ReproSyz))
+ dbBug.keyHash(c.ctx), syzReproPrefix, crash4.ReproOpts, crash4.ReproSyz))
c.checkURLContents(bisectLogLink, []byte("bisectfix log 4"))
c.checkURLContents(bisectCrashReportLink, []byte("bisectfix crash report 4"))
c.checkURLContents(bisectCrashLogLink, []byte("bisectfix crash log 4"))
@@ -1231,7 +1231,7 @@ func addBisectFixJob(c *Ctx, build *dashapi.Build) (*dashapi.JobPollResp, *dasha
c.expectTrue(strings.Contains(msg.Body, "syzbot suspects this issue was fixed by commit:"))
// Ensure we do not automatically close the bug.
- c.expectTrue(!config.Namespaces["test2"].FixBisectionAutoClose)
+ c.expectTrue(!c.config().Namespaces["test2"].FixBisectionAutoClose)
_, extBugID, err := email.RemoveAddrContext(msg.Sender)
c.expectOK(err)
dbBug, _, _ := c.loadBug(extBugID)
diff --git a/dashboard/app/cache.go b/dashboard/app/cache.go
index 236a7f1c3..b9ed0d54f 100644
--- a/dashboard/app/cache.go
+++ b/dashboard/app/cache.go
@@ -57,7 +57,7 @@ func cacheUpdate(w http.ResponseWriter, r *http.Request) {
log.Errorf(c, "failed load backports: %v", err)
return
}
- for ns := range config.Namespaces {
+ for ns := range getConfig(c).Namespaces {
bugs, _, err := loadNamespaceBugs(c, ns)
if err != nil {
log.Errorf(c, "failed load ns=%v bugs: %v", ns, err)
@@ -79,7 +79,7 @@ func buildAndStoreCached(c context.Context, bugs []*Bug, backports []*rawBackpor
Subsystems: make(map[string]CachedBugStats),
}
for _, bug := range bugs {
- if bug.Status == BugStatusOpen && accessLevel < bug.sanitizeAccess(accessLevel) {
+ if bug.Status == BugStatusOpen && accessLevel < bug.sanitizeAccess(c, accessLevel) {
continue
}
v.Total.Record(bug)
@@ -96,7 +96,7 @@ func buildAndStoreCached(c context.Context, bugs []*Bug, backports []*rawBackpor
for _, backport := range backports {
outgoing := stringInList(backport.FromNs, ns)
for _, bug := range backport.Bugs {
- if accessLevel < bug.sanitizeAccess(accessLevel) {
+ if accessLevel < bug.sanitizeAccess(c, accessLevel) {
continue
}
if bug.Namespace == ns || outgoing {
diff --git a/dashboard/app/config.go b/dashboard/app/config.go
index 9715c632a..235e4e853 100644
--- a/dashboard/app/config.go
+++ b/dashboard/app/config.go
@@ -336,25 +336,40 @@ func (cfg *Config) ReportingByName(name string) *Reporting {
return nil
}
-// config is installed either by tests or from mainConfig in main function
-// (a separate file should install mainConfig in an init function).
+// configDontUse holds the configuration object that is installed either by tests
+// or from mainConfig in main function (a separate file should install mainConfig
+// in an init function).
+// Please access it via the getConfig(context.Context) method.
var (
- config *GlobalConfig
- mainConfig *GlobalConfig
+ configDontUse *GlobalConfig
+ mainConfig *GlobalConfig
)
func installConfig(cfg *GlobalConfig) {
checkConfig(cfg)
- if config != nil {
+ if configDontUse != nil {
panic("another config is already installed")
}
- config = cfg
+ configDontUse = cfg
initEmailReporting()
initHTTPHandlers()
initAPIHandlers()
initKcidb()
}
+var contextConfigKey = "Updated config (to be used during tests). Use only in tests!"
+
+func contextWithConfig(c context.Context, cfg *GlobalConfig) context.Context {
+ return context.WithValue(c, &contextConfigKey, cfg)
+}
+
+func getConfig(c context.Context) *GlobalConfig {
+ if val, ok := c.Value(&contextConfigKey).(*GlobalConfig); ok {
+ return val
+ }
+ return configDontUse // The base config was not overwriten.
+}
+
func checkConfig(cfg *GlobalConfig) {
if cfg == nil {
panic("installing nil config")
@@ -690,34 +705,6 @@ func (cfg *Config) lastActiveReporting() int {
return last
}
-var kernelReposKey = "Custom list of kernel repositories"
-
-func contextWithRepos(c context.Context, list []KernelRepo) context.Context {
- return context.WithValue(c, &kernelReposKey, list)
-}
-
-func getKernelRepos(c context.Context, ns string) []KernelRepo {
- if val, ok := c.Value(&kernelReposKey).([]KernelRepo); ok {
- return val
- }
- return config.Namespaces[ns].Repos
-}
-
-var decommKey = "Custom decommissioned status"
-
-func contextWithDecommission(c context.Context, ns string, value bool) context.Context {
- mm, _ := c.Value(&decommKey).(map[string]bool)
- if mm == nil {
- mm = map[string]bool{}
- }
- mm[ns] = value
- return context.WithValue(c, &decommKey, mm)
-}
-
func isDecommissioned(c context.Context, ns string) bool {
- mm, _ := c.Value(&decommKey).(map[string]bool)
- if val, set := mm[ns]; set {
- return val
- }
- return config.Namespaces[ns].Decommissioned
+ return getConfig(c).Namespaces[ns].Decommissioned
}
diff --git a/dashboard/app/email_test.go b/dashboard/app/email_test.go
index 5c587199e..b79bdcb16 100644
--- a/dashboard/app/email_test.go
+++ b/dashboard/app/email_test.go
@@ -13,6 +13,7 @@ import (
"github.com/google/syzkaller/pkg/email"
"github.com/google/syzkaller/sys/targets"
"github.com/stretchr/testify/assert"
+ "golang.org/x/net/context"
)
// nolint: funlen
@@ -42,7 +43,7 @@ func TestEmailReport(t *testing.T) {
crashLogLink := externalLink(c.ctx, textCrashLog, dbCrash.Log)
kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig)
c.expectEQ(sender, fromAddr(c.ctx))
- to := config.Namespaces["test2"].Reporting[0].Config.(*EmailConfig).Email
+ to := c.config().Namespaces["test2"].Reporting[0].Config.(*EmailConfig).Email
c.expectEQ(msg.To, []string{to})
c.expectEQ(msg.Subject, crash.Title)
c.expectEQ(len(msg.Attachments), 0)
@@ -146,7 +147,7 @@ For more options, visit https://groups.google.com/d/optout.
crash.ReproOpts = []byte("repro opts")
crash.ReproSyz = []byte("getpid()")
syzRepro := []byte(fmt.Sprintf("# https://testapp.appspot.com/bug?id=%v\n%s#%s\n%s",
- dbBug0.keyHash(), syzReproPrefix, crash.ReproOpts, crash.ReproSyz))
+ dbBug0.keyHash(c.ctx), syzReproPrefix, crash.ReproOpts, crash.ReproSyz))
c.client2.ReportCrash(crash)
{
@@ -165,7 +166,7 @@ For more options, visit https://groups.google.com/d/optout.
"bugs@syzkaller.com", // This is from incomingEmail.
"default@sender.com", // This is from incomingEmail.
"foo@bar.com",
- config.Namespaces["test2"].Reporting[0].Config.(*EmailConfig).Email,
+ c.config().Namespaces["test2"].Reporting[0].Config.(*EmailConfig).Email,
}
c.expectEQ(msg.To, to)
c.expectEQ(msg.Subject, "Re: "+crash.Title)
@@ -295,7 +296,7 @@ Content-Type: text/plain
crash.Maintainers = []string{"\"qux\" <qux@qux.com>"}
c.client2.ReportCrash(crash)
cRepro := []byte(fmt.Sprintf("// https://testapp.appspot.com/bug?id=%v\n%s",
- dbBug0.keyHash(), crash.ReproC))
+ dbBug0.keyHash(c.ctx), crash.ReproC))
{
msg := c.pollEmailBug()
@@ -943,7 +944,7 @@ func TestSubjectTitleParser(t *testing.T) {
},
}
- p := subjectTitleParser{}
+ p := makeSubjectTitleParser(context.Background())
for _, test := range tests {
title, seq, err := p.parseTitle(test.inSubject)
if test.outTitle == "" {
@@ -990,7 +991,7 @@ func TestBugFromSubjectInference(t *testing.T) {
origSender := upstreamCrash(client, build, crashTitle)
upstreamCrash(client, build, "unrelated crash 2")
- mailingList := "<" + config.Namespaces["access-public-email"].Reporting[0].Config.(*EmailConfig).Email + ">"
+ mailingList := "<" + c.config().Namespaces["access-public-email"].Reporting[0].Config.(*EmailConfig).Email + ">"
// First try to ping some non-existing bug.
subject := "Re: unknown-bug"
@@ -1154,7 +1155,7 @@ func TestEmailSetInvalidSubsystems(t *testing.T) {
defer c.Close()
client := c.makeClient(clientPublicEmail, keyPublicEmail, true)
- mailingList := config.Namespaces["access-public-email"].Reporting[0].Config.(*EmailConfig).Email
+ mailingList := c.config().Namespaces["access-public-email"].Reporting[0].Config.(*EmailConfig).Email
build := testBuild(1)
client.UploadBuild(build)
@@ -1186,7 +1187,7 @@ func TestEmailSetSubsystems(t *testing.T) {
defer c.Close()
client := c.makeClient(clientPublicEmail, keyPublicEmail, true)
- mailingList := config.Namespaces["access-public-email"].Reporting[0].Config.(*EmailConfig).Email
+ mailingList := c.config().Namespaces["access-public-email"].Reporting[0].Config.(*EmailConfig).Email
build := testBuild(1)
client.UploadBuild(build)
@@ -1218,7 +1219,7 @@ func TestEmailBugLabels(t *testing.T) {
defer c.Close()
client := c.makeClient(clientPublicEmail, keyPublicEmail, true)
- mailingList := config.Namespaces["access-public-email"].Reporting[0].Config.(*EmailConfig).Email
+ mailingList := c.config().Namespaces["access-public-email"].Reporting[0].Config.(*EmailConfig).Email
build := testBuild(1)
client.UploadBuild(build)
@@ -1264,7 +1265,7 @@ func TestInvalidEmailBugLabels(t *testing.T) {
defer c.Close()
client := c.makeClient(clientPublicEmail, keyPublicEmail, true)
- mailingList := config.Namespaces["access-public-email"].Reporting[0].Config.(*EmailConfig).Email
+ mailingList := c.config().Namespaces["access-public-email"].Reporting[0].Config.(*EmailConfig).Email
build := testBuild(1)
client.UploadBuild(build)
diff --git a/dashboard/app/entities.go b/dashboard/app/entities.go
index f4cc68e79..8310cb281 100644
--- a/dashboard/app/entities.go
+++ b/dashboard/app/entities.go
@@ -775,7 +775,7 @@ func loadAllManagers(c context.Context, ns string) ([]*Manager, []*db.Key, error
var result []*Manager
var resultKeys []*db.Key
for i, mgr := range managers {
- if config.Namespaces[mgr.Namespace].Managers[mgr.Name].Decommissioned {
+ if getConfig(c).Namespaces[mgr.Namespace].Managers[mgr.Name].Decommissioned {
continue
}
result = append(result, mgr)
@@ -849,28 +849,28 @@ func canonicalBug(c context.Context, bug *Bug) (*Bug, error) {
bugKey := db.NewKey(c, "Bug", bug.DupOf, 0, nil)
if err := db.Get(c, bugKey, canon); err != nil {
return nil, fmt.Errorf("failed to get dup bug %q for %q: %w",
- bug.DupOf, bug.keyHash(), err)
+ bug.DupOf, bug.keyHash(c), err)
}
bug = canon
}
}
func (bug *Bug) key(c context.Context) *db.Key {
- return db.NewKey(c, "Bug", bug.keyHash(), 0, nil)
+ return db.NewKey(c, "Bug", bug.keyHash(c), 0, nil)
}
-func (bug *Bug) keyHash() string {
- return bugKeyHash(bug.Namespace, bug.Title, bug.Seq)
+func (bug *Bug) keyHash(c context.Context) string {
+ return bugKeyHash(c, bug.Namespace, bug.Title, bug.Seq)
}
-func bugKeyHash(ns, title string, seq int64) string {
- return hash.String([]byte(fmt.Sprintf("%v-%v-%v-%v", config.Namespaces[ns].Key, ns, title, seq)))
+func bugKeyHash(c context.Context, ns, title string, seq int64) string {
+ return hash.String([]byte(fmt.Sprintf("%v-%v-%v-%v", getConfig(c).Namespaces[ns].Key, ns, title, seq)))
}
func loadSimilarBugs(c context.Context, bug *Bug) ([]*Bug, error) {
- domain := config.Namespaces[bug.Namespace].SimilarityDomain
+ domain := getConfig(c).Namespaces[bug.Namespace].SimilarityDomain
dedup := make(map[string]bool)
- dedup[bug.keyHash()] = true
+ dedup[bug.keyHash(c)] = true
ret := []*Bug{}
for _, title := range bug.AltTitles {
@@ -882,11 +882,11 @@ func loadSimilarBugs(c context.Context, bug *Bug) ([]*Bug, error) {
return nil, err
}
for _, bug := range similar {
- if config.Namespaces[bug.Namespace].SimilarityDomain != domain ||
- dedup[bug.keyHash()] {
+ if getConfig(c).Namespaces[bug.Namespace].SimilarityDomain != domain ||
+ dedup[bug.keyHash(c)] {
continue
}
- dedup[bug.keyHash()] = true
+ dedup[bug.keyHash(c)] = true
ret = append(ret, bug)
}
}
@@ -1001,7 +1001,7 @@ func kernelRepoInfo(c context.Context, build *Build) KernelRepo {
func kernelRepoInfoRaw(c context.Context, ns, url, branch string) KernelRepo {
var info KernelRepo
- for _, repo := range getKernelRepos(c, ns) {
+ for _, repo := range getConfig(c).Namespaces[ns].Repos {
if repo.URL == url && repo.Branch == branch {
info = repo
break
diff --git a/dashboard/app/graphs.go b/dashboard/app/graphs.go
index 74d982eb0..89f549d92 100644
--- a/dashboard/app/graphs.go
+++ b/dashboard/app/graphs.go
@@ -166,7 +166,7 @@ func loadGraphBugs(c context.Context, ns string) ([]*Bug, error) {
}
n := 0
fixes := make(map[string]bool)
- lastReporting := config.Namespaces[ns].lastActiveReporting()
+ lastReporting := getConfig(c).Namespaces[ns].lastActiveReporting()
for _, bug := range bugs {
if bug.Reporting[lastReporting].Reported.IsZero() {
if bug.Status == BugStatusOpen {
@@ -293,7 +293,7 @@ func createBugLifetimes(c context.Context, bugs []*Bug, causeBisects map[string]
} else {
ui.NotFixed = 400 - float32(i%7)
}
- if job := causeBisects[bug.keyHash()]; job != nil {
+ if job := causeBisects[bug.keyHash(c)]; job != nil {
days := float32(job.Commits[0].Date.Sub(ui.Reported)) / float32(24*time.Hour)
if days < -365 {
ui.Introduced1y = -365 - float32(i%7)
@@ -523,7 +523,7 @@ func handleGraphCrashes(c context.Context, w http.ResponseWriter, r *http.Reques
accessLevel := accessLevel(c, r)
nbugs := 0
for _, bug := range bugs {
- if accessLevel < bug.sanitizeAccess(accessLevel) {
+ if accessLevel < bug.sanitizeAccess(c, accessLevel) {
continue
}
bugs[nbugs] = bug
@@ -564,7 +564,7 @@ func createCrashesTable(c context.Context, ns string, days int, bugs []*Bug) *ui
titleRegexp := regexp.QuoteMeta(bug.Title)
table.Rows = append(table.Rows, &uiCrashSummary{
Title: bug.Title,
- Link: bugLink(bug.keyHash()),
+ Link: bugLink(bug.keyHash(c)),
GraphLink: "?show-graph=1&Months=1&regexp=" + url.QueryEscape(titleRegexp),
Count: count,
})
diff --git a/dashboard/app/handler.go b/dashboard/app/handler.go
index 6c059c0f4..c8929290d 100644
--- a/dashboard/app/handler.go
+++ b/dashboard/app/handler.go
@@ -105,7 +105,7 @@ func (ce *ErrClient) HTTPStatus() int {
func handleAuth(fn contextHandler) contextHandler {
return func(c context.Context, w http.ResponseWriter, r *http.Request) error {
- if err := checkAccessLevel(c, r, config.AccessLevel); err != nil {
+ if err := checkAccessLevel(c, r, getConfig(c).AccessLevel); err != nil {
return err
}
return fn(c, w, r)
@@ -148,8 +148,8 @@ func commonHeaderRaw(c context.Context, r *http.Request) *uiHeader {
h := &uiHeader{
Admin: accessLevel(c, r) == AccessAdmin,
URLPath: r.URL.Path,
- AnalyticsTrackingID: config.AnalyticsTrackingID,
- ContactEmail: config.ContactEmail,
+ AnalyticsTrackingID: getConfig(c).AnalyticsTrackingID,
+ ContactEmail: getConfig(c).ContactEmail,
}
if user.Current(c) == nil {
h.LoginLink, _ = user.LoginURL(c, r.URL.String())
@@ -172,7 +172,7 @@ func commonHeader(c context.Context, r *http.Request, w http.ResponseWriter, ns
const adminPage = "admin"
isAdminPage := r.URL.Path == "/"+adminPage
found := false
- for ns1, cfg := range config.Namespaces {
+ for ns1, cfg := range getConfig(c).Namespaces {
if accessLevel < cfg.AccessLevel {
if ns1 == ns {
return nil, ErrAccess
@@ -195,8 +195,8 @@ func commonHeader(c context.Context, r *http.Request, w http.ResponseWriter, ns
})
cookie := decodeCookie(r)
if !found {
- ns = config.DefaultNamespace
- if cfg := config.Namespaces[cookie.Namespace]; cfg != nil && cfg.AccessLevel <= accessLevel {
+ ns = getConfig(c).DefaultNamespace
+ if cfg := getConfig(c).Namespaces[cookie.Namespace]; cfg != nil && cfg.AccessLevel <= accessLevel {
ns = cookie.Namespace
}
if accessLevel == AccessAdmin {
diff --git a/dashboard/app/jobs.go b/dashboard/app/jobs.go
index 187b5aae3..4a46f7387 100644
--- a/dashboard/app/jobs.go
+++ b/dashboard/app/jobs.go
@@ -44,7 +44,7 @@ type testReqArgs struct {
func handleTestRequest(c context.Context, args *testReqArgs) error {
log.Infof(c, "test request: bug=%s user=%q extID=%q patch=%v, repo=%q branch=%q",
args.bug.Title, args.user, args.extID, len(args.patch), args.repo, args.branch)
- for _, blocked := range config.EmailBlocklist {
+ for _, blocked := range getConfig(c).EmailBlocklist {
if args.user == blocked {
return &TestRequestDeniedError{
fmt.Sprintf("test request from blocked user: %v", args.user),
@@ -104,7 +104,7 @@ func addTestJob(c context.Context, args *testJobArgs) (*Job, *db.Key, error) {
if reason := checkTestJob(args); reason != "" {
return nil, nil, &BadTestRequestError{reason}
}
- manager, mgrConfig := activeManager(args.crash.Manager, args.bug.Namespace)
+ manager, mgrConfig := activeManager(c, args.crash.Manager, args.bug.Namespace)
if mgrConfig != nil && mgrConfig.RestrictedTestingRepo != "" &&
args.repo != mgrConfig.RestrictedTestingRepo {
return nil, nil, &BadTestRequestError{mgrConfig.RestrictedTestingReason}
@@ -413,7 +413,7 @@ func jobFromBugSample(c context.Context, managers map[string]dashapi.ManagerJobs
continue
}
managersList = append(managersList, name)
- managersList = append(managersList, decommissionedInto(name)...)
+ managersList = append(managersList, decommissionedInto(c, name)...)
}
managersList = unique(managersList)
@@ -444,7 +444,7 @@ func jobFromBugSample(c context.Context, managers map[string]dashapi.ManagerJobs
}
r := rand.New(rand.NewSource(timeNow(c).UnixNano()))
// Bugs often happen on multiple instances, so let's filter out duplicates.
- allBugs, allBugKeys = uniqueBugs(allBugs, allBugKeys)
+ allBugs, allBugKeys = uniqueBugs(c, allBugs, allBugKeys)
r.Shuffle(len(allBugs), func(i, j int) {
allBugs[i], allBugs[j] = allBugs[j], allBugs[i]
allBugKeys[i], allBugKeys[j] = allBugKeys[j], allBugKeys[i]
@@ -480,7 +480,7 @@ func createTreeBisectionJobs(c context.Context, bugs []*Bug, bugKeys []*db.Key,
}
any := false
for _, mgr := range bug.HappenedOn {
- newMgr, _ := activeManager(mgr, bug.Namespace)
+ newMgr, _ := activeManager(c, mgr, bug.Namespace)
any = any || managers[newMgr].BisectFix
}
if !any {
@@ -505,7 +505,7 @@ func createTreeTestJobs(c context.Context, bugs []*Bug, bugKeys []*db.Key,
takeBugs := 5
prio, next := []int{}, []int{}
for i, bug := range bugs {
- if !config.Namespaces[bug.Namespace].FindBugOriginTrees {
+ if !getConfig(c).Namespaces[bug.Namespace].FindBugOriginTrees {
continue
}
if timeNow(c).Before(bug.TreeTests.NextPoll) {
@@ -538,12 +538,12 @@ func createPatchRetestingJobs(c context.Context, bugs []*Bug, bugKeys []*db.Key,
managers map[string]dashapi.ManagerJobs) (*Job, *db.Key, error) {
takeBugs := 5
for i, bug := range bugs {
- if !config.Namespaces[bug.Namespace].RetestRepros {
+ if !getConfig(c).Namespaces[bug.Namespace].RetestRepros {
// Repro retesting is disabled for the namespace.
continue
}
- if config.Obsoleting.ReproRetestPeriod == 0 ||
- timeNow(c).Sub(bug.LastTime) < config.Obsoleting.ReproRetestStart {
+ if getConfig(c).Obsoleting.ReproRetestPeriod == 0 ||
+ timeNow(c).Sub(bug.LastTime) < getConfig(c).Obsoleting.ReproRetestStart {
// Don't retest reproducers if crashes are still happening.
continue
}
@@ -561,9 +561,9 @@ func createPatchRetestingJobs(c context.Context, bugs []*Bug, bugKeys []*db.Key,
return nil, nil, nil
}
-func decommissionedInto(jobMgr string) []string {
+func decommissionedInto(c context.Context, jobMgr string) []string {
var ret []string
- for _, nsConfig := range config.Namespaces {
+ for _, nsConfig := range getConfig(c).Namespaces {
for name, mgr := range nsConfig.Managers {
if mgr.DelegatedTo == jobMgr {
ret = append(ret, name)
@@ -591,7 +591,7 @@ func handleRetestForBug(c context.Context, bug *Bug, bugKey *db.Key,
if crash.ReproSyz == 0 && crash.ReproC == 0 {
continue
}
- if now.Sub(crash.LastReproRetest) < config.Obsoleting.ReproRetestPeriod {
+ if now.Sub(crash.LastReproRetest) < getConfig(c).Obsoleting.ReproRetestPeriod {
continue
}
if crash.ReproIsRevoked {
@@ -599,7 +599,7 @@ func handleRetestForBug(c context.Context, bug *Bug, bugKey *db.Key,
continue
}
// We could have decommissioned the original manager since then.
- manager, _ := activeManager(crash.Manager, bug.Namespace)
+ manager, _ := activeManager(c, crash.Manager, bug.Namespace)
if manager == "" || !managers[manager].TestPatches {
continue
}
@@ -747,7 +747,7 @@ func bisectCrashForBug(c context.Context, bug *Bug, bugKey *db.Key, managers map
continue
}
if jobType == JobBisectFix &&
- config.Namespaces[bug.Namespace].Managers[crash.Manager].FixBisectionDisabled {
+ getConfig(c).Namespaces[bug.Namespace].Managers[crash.Manager].FixBisectionDisabled {
continue
}
return crash, crashKeys[ci], nil
@@ -1171,7 +1171,7 @@ func updateBugBisection(c context.Context, job *Job, jobKey *db.Key, req *dashap
if job.Type == JobBisectCause && infraError {
bug.BisectCause = BisectNot
}
- _, bugReporting, _, _, _ := currentReporting(bug)
+ _, bugReporting, _, _, _ := currentReporting(c, bug)
// The bug is either already closed or not yet reported in the current reporting,
// either way we don't need to report it. If it wasn't reported, it will be reported
// with the bisection results.
@@ -1210,7 +1210,7 @@ func pollCompletedJobs(c context.Context, typ string) ([]*dashapi.BugReport, err
// In some cases (e.g. repro retesting), it's ok not to have a reporting.
continue
}
- reporting := config.Namespaces[job.Namespace].ReportingByName(job.Reporting)
+ reporting := getConfig(c).Namespaces[job.Namespace].ReportingByName(job.Reporting)
if reporting.Config.Type() != typ {
continue
}
@@ -1317,7 +1317,7 @@ func createBugReportForJob(c context.Context, job *Job, jobKey *db.Key, config i
}
rep.Maintainers = append(rep.Maintainers, emails...)
}
- if mgr := bug.managerConfig(); mgr != nil {
+ if mgr := bug.managerConfig(c); mgr != nil {
rep.CC = append(rep.CC, mgr.CC.Always...)
if job.Type == JobBisectCause || job.Type == JobBisectFix {
rep.Maintainers = append(rep.Maintainers, mgr.CC.Maintainers...)
@@ -1377,7 +1377,7 @@ func jobReported(c context.Context, jobID string) error {
// Auto-mark the bug as fixed by the result of fix bisection,
// if the setting is enabled for the namespace.
if job.Type == JobBisectFix &&
- config.Namespaces[job.Namespace].FixBisectionAutoClose &&
+ getConfig(c).Namespaces[job.Namespace].FixBisectionAutoClose &&
!job.IsCrossTree() &&
len(job.Commits) == 1 {
bug := new(Bug)
@@ -1486,8 +1486,8 @@ func loadPendingJob(c context.Context, managers map[string]dashapi.ManagerJobs)
// activeManager determines the manager currently responsible for all bugs found by
// the specified manager.
-func activeManager(manager, ns string) (string, *ConfigManager) {
- nsConfig := config.Namespaces[ns]
+func activeManager(c context.Context, manager, ns string) (string, *ConfigManager) {
+ nsConfig := getConfig(c).Namespaces[ns]
if mgr, ok := nsConfig.Managers[manager]; ok {
if mgr.Decommissioned {
newMgr := nsConfig.Managers[mgr.DelegatedTo]
@@ -1599,13 +1599,13 @@ func makeJobInfo(c context.Context, job *Job, jobKey *db.Key, bug *Bug, build *B
return info
}
-func uniqueBugs(inBugs []*Bug, inKeys []*db.Key) ([]*Bug, []*db.Key) {
+func uniqueBugs(c context.Context, inBugs []*Bug, inKeys []*db.Key) ([]*Bug, []*db.Key) {
var bugs []*Bug
var keys []*db.Key
dups := map[string]bool{}
for i, bug := range inBugs {
- hash := bug.keyHash()
+ hash := bug.keyHash(c)
if dups[hash] {
continue
}
diff --git a/dashboard/app/jobs_test.go b/dashboard/app/jobs_test.go
index 3327d46db..d2e81de75 100644
--- a/dashboard/app/jobs_test.go
+++ b/dashboard/app/jobs_test.go
@@ -41,7 +41,7 @@ func TestJob(t *testing.T) {
sender = c.pollEmailBug().Sender
_, extBugID, err := email.RemoveAddrContext(sender)
c.expectOK(err)
- mailingList := config.Namespaces["access-public-email"].Reporting[0].Config.(*EmailConfig).Email
+ mailingList := c.config().Namespaces["access-public-email"].Reporting[0].Config.(*EmailConfig).Email
c.incomingEmail(sender, "bla-bla-bla", EmailOptFrom("maintainer@kernel.org"),
EmailOptCC([]string{mailingList, "kernel@mailing.list"}))
@@ -293,7 +293,7 @@ func TestBootErrorPatch(t *testing.T) {
sender := c.pollEmailBug().Sender
c.incomingEmail(sender, "#syz upstream\n")
sender = c.pollEmailBug().Sender
- mailingList := config.Namespaces["test2"].Reporting[1].Config.(*EmailConfig).Email
+ mailingList := c.config().Namespaces["test2"].Reporting[1].Config.(*EmailConfig).Email
c.incomingEmail(sender, "#syz test: git://git.git/git.git kernel-branch\n"+sampleGitPatch,
EmailOptFrom("test@requester.com"), EmailOptCC([]string{mailingList}))
@@ -318,7 +318,7 @@ func TestTestErrorPatch(t *testing.T) {
sender := c.pollEmailBug().Sender
c.incomingEmail(sender, "#syz upstream\n")
sender = c.pollEmailBug().Sender
- mailingList := config.Namespaces["test2"].Reporting[1].Config.(*EmailConfig).Email
+ mailingList := c.config().Namespaces["test2"].Reporting[1].Config.(*EmailConfig).Email
c.incomingEmail(sender, "#syz test: git://git.git/git.git kernel-branch\n"+sampleGitPatch,
EmailOptFrom("test@requester.com"), EmailOptCC([]string{mailingList}))
@@ -431,7 +431,7 @@ func TestReproRetestJob(t *testing.T) {
c.expectEQ(bug.ReproLevel, ReproLevelC)
// Let's say that the C repro testing has failed.
- c.advanceTime(config.Obsoleting.ReproRetestStart + time.Hour)
+ c.advanceTime(c.config().Obsoleting.ReproRetestStart + time.Hour)
for i := 0; i < 2; i++ {
resp := client.pollSpecificJobs(build.Manager, dashapi.ManagerJobs{TestPatches: true})
c.expectEQ(resp.Type, dashapi.JobTestPatch)
@@ -461,7 +461,7 @@ func TestReproRetestJob(t *testing.T) {
bug, _, _ = c.loadBug(extBugID)
c.expectEQ(bug.HeadReproLevel, ReproLevelSyz)
// Let's also deprecate the syz repro.
- c.advanceTime(config.Obsoleting.ReproRetestPeriod + time.Hour)
+ c.advanceTime(c.config().Obsoleting.ReproRetestPeriod + time.Hour)
resp := client.pollSpecificJobs(build.Manager, dashapi.ManagerJobs{TestPatches: true})
c.expectEQ(resp.Type, dashapi.JobTestPatch)
@@ -510,10 +510,7 @@ func TestDelegatedManagerReproRetest(t *testing.T) {
c.expectOK(err)
// Deprecate the oldManager.
- mgrConfig := config.Namespaces["test-mgr-decommission"].Managers[oldManager]
- mgrConfig.Decommissioned = true
- mgrConfig.DelegatedTo = newManager
- config.Namespaces["test-mgr-decommission"].Managers[oldManager] = mgrConfig
+ c.decommissionManager("test-mgr-decommission", oldManager, newManager)
// Upload a build for the new manager.
c.advanceTime(time.Minute)
@@ -531,7 +528,7 @@ func TestDelegatedManagerReproRetest(t *testing.T) {
c.pollEmailBug()
// Let's say that the C repro testing has failed.
- c.advanceTime(config.Obsoleting.ReproRetestPeriod + time.Hour)
+ c.advanceTime(c.config().Obsoleting.ReproRetestPeriod + time.Hour)
resp := client.pollSpecificJobs(build.Manager, dashapi.ManagerJobs{TestPatches: true})
c.expectEQ(resp.Type, dashapi.JobTestPatch)
@@ -1252,7 +1249,7 @@ func TestEmailTestCommandNoArgs(t *testing.T) {
client.ReportCrash(crash)
sender := c.pollEmailBug().Sender
- mailingList := config.Namespaces["access-public-email"].Reporting[0].Config.(*EmailConfig).Email
+ mailingList := c.config().Namespaces["access-public-email"].Reporting[0].Config.(*EmailConfig).Email
c.incomingEmail(sender, "#syz test\n"+sampleGitPatch,
EmailOptFrom("test@requester.com"), EmailOptCC([]string{mailingList}))
diff --git a/dashboard/app/kcidb.go b/dashboard/app/kcidb.go
index b228e771c..19b704882 100644
--- a/dashboard/app/kcidb.go
+++ b/dashboard/app/kcidb.go
@@ -21,7 +21,7 @@ func initKcidb() {
func handleKcidbPoll(w http.ResponseWriter, r *http.Request) {
c := appengine.NewContext(r)
- for ns, cfg := range config.Namespaces {
+ for ns, cfg := range getConfig(c).Namespaces {
if cfg.Kcidb == nil {
continue
}
@@ -60,7 +60,7 @@ func handleKcidbNamespce(c context.Context, ns string, cfg *KcidbConfig) error {
func publishKcidbBug(c context.Context, client *kcidb.Client, bug *Bug, bugKey *db.Key) (bool, error) {
if bug.KcidbStatus != 0 ||
- bug.sanitizeAccess(AccessPublic) > AccessPublic ||
+ bug.sanitizeAccess(c, AccessPublic) > AccessPublic ||
bug.Reporting[len(bug.Reporting)-1].Reported.IsZero() ||
bug.Status != BugStatusOpen && timeSince(c, bug.LastTime) > 7*24*time.Hour {
return false, nil
diff --git a/dashboard/app/label.go b/dashboard/app/label.go
index 01d360755..f25ff4c5e 100644
--- a/dashboard/app/label.go
+++ b/dashboard/app/label.go
@@ -52,7 +52,7 @@ func makeLabelSet(c context.Context, ns string) *labelSet {
}
originLabels := []string{}
- for _, repo := range getKernelRepos(c, ns) {
+ for _, repo := range getConfig(c).Namespaces[ns].Repos {
if repo.LabelIntroduced != "" {
originLabels = append(originLabels, repo.LabelIntroduced)
}
diff --git a/dashboard/app/main.go b/dashboard/app/main.go
index 2a4baa69b..748c76f2c 100644
--- a/dashboard/app/main.go
+++ b/dashboard/app/main.go
@@ -54,7 +54,7 @@ func initHTTPHandlers() {
http.Handle("/x/bisect.txt", handlerWrapper(handleTextX(textLog)))
http.Handle("/x/error.txt", handlerWrapper(handleTextX(textError)))
http.Handle("/x/minfo.txt", handlerWrapper(handleTextX(textMachineInfo)))
- for ns := range config.Namespaces {
+ for ns := range getConfig(context.Background()).Namespaces {
http.Handle("/"+ns, handlerWrapper(handleMain))
http.Handle("/"+ns+"/fixed", handlerWrapper(handleFixed))
http.Handle("/"+ns+"/invalid", handlerWrapper(handleInvalid))
@@ -500,7 +500,7 @@ func handleMain(c context.Context, w http.ResponseWriter, r *http.Request) error
return err
}
for _, group := range groups {
- if config.Namespaces[hdr.Namespace].DisplayDiscussions {
+ if getConfig(c).Namespaces[hdr.Namespace].DisplayDiscussions {
group.DispDiscuss = true
} else {
group.DispLastAct = true
@@ -553,7 +553,7 @@ func handleSubsystemPage(c context.Context, w http.ResponseWriter, r *http.Reque
var subsystem *subsystem.Subsystem
if pos := strings.Index(r.URL.Path, "/s/"); pos != -1 {
name := r.URL.Path[pos+3:]
- if newName := config.Namespaces[hdr.Namespace].Subsystems.Redirect[name]; newName != "" {
+ if newName := getConfig(c).Namespaces[hdr.Namespace].Subsystems.Redirect[name]; newName != "" {
http.Redirect(w, r, r.URL.Path[:pos+3]+newName, http.StatusMovedPermanently)
return nil
}
@@ -575,7 +575,7 @@ func handleSubsystemPage(c context.Context, w http.ResponseWriter, r *http.Reque
return err
}
for _, group := range groups {
- group.DispDiscuss = config.Namespaces[hdr.Namespace].DisplayDiscussions
+ group.DispDiscuss = getConfig(c).Namespaces[hdr.Namespace].DisplayDiscussions
}
cached, err := CacheGet(c, r, hdr.Namespace)
if err != nil {
@@ -622,7 +622,7 @@ func handleBackports(c context.Context, w http.ResponseWriter, r *http.Request)
}
incoming := false
for _, bug := range backport.Bugs {
- if accessLevel < bug.sanitizeAccess(accessLevel) {
+ if accessLevel < bug.sanitizeAccess(c, accessLevel) {
continue
}
if !outgoing && bug.Namespace != hdr.Namespace {
@@ -680,7 +680,7 @@ func handleBackports(c context.Context, w http.ResponseWriter, r *http.Request)
Header: hdr,
Groups: groups,
DisplayNamespace: func(ns string) string {
- return config.Namespaces[ns].DisplayTitle
+ return getConfig(c).Namespaces[ns].DisplayTitle
},
})
}
@@ -743,7 +743,7 @@ func loadAllBackports(c context.Context) ([]*rawBackport, error) {
if backport == nil {
backport = &rawBackport{
From: from,
- FromNs: namespacesForRepo(from.URL, from.Branch),
+ FromNs: namespacesForRepo(c, from.URL, from.Branch),
To: to,
Commit: commit}
ret = append(ret, backport)
@@ -754,9 +754,9 @@ func loadAllBackports(c context.Context) ([]*rawBackport, error) {
return ret, nil
}
-func namespacesForRepo(url, branch string) []string {
+func namespacesForRepo(c context.Context, url, branch string) []string {
var ret []string
- for ns, cfg := range config.Namespaces {
+ for ns, cfg := range getConfig(c).Namespaces {
has := false
for _, repo := range cfg.Repos {
if repo.NoPoll {
@@ -943,7 +943,7 @@ func handleBug(c context.Context, w http.ResponseWriter, r *http.Request) error
return fmt.Errorf("%w: %w", ErrClientNotFound, err)
}
accessLevel := accessLevel(c, r)
- if err := checkAccessLevel(c, r, bug.sanitizeAccess(accessLevel)); err != nil {
+ if err := checkAccessLevel(c, r, bug.sanitizeAccess(c, accessLevel)); err != nil {
return err
}
if r.FormValue("debug_subsystems") != "" && accessLevel == AccessAdmin {
@@ -967,7 +967,7 @@ func handleBug(c context.Context, w http.ResponseWriter, r *http.Request) error
if err := db.Get(c, db.NewKey(c, "Bug", bug.DupOf, 0, nil), dup); err != nil {
return err
}
- if accessLevel >= dup.sanitizeAccess(accessLevel) {
+ if accessLevel >= dup.sanitizeAccess(c, accessLevel) {
sections = append(sections, &uiCollapsible{
Title: "Duplicate of",
Show: true,
@@ -1030,7 +1030,7 @@ func handleBug(c context.Context, w http.ResponseWriter, r *http.Request) error
if len(similar.Bugs) > 0 {
sections = append(sections, &uiCollapsible{
Title: fmt.Sprintf("Similar bugs (%d)", len(similar.Bugs)),
- Show: config.Namespaces[hdr.Namespace].AccessLevel != AccessPublic,
+ Show: getConfig(c).Namespaces[hdr.Namespace].AccessLevel != AccessPublic,
Type: sectionBugList,
Value: similar,
})
@@ -1415,7 +1415,7 @@ func handleTextImpl(c context.Context, w http.ResponseWriter, r *http.Request, t
}
return err
}
- if err := checkAccessLevel(c, r, config.Namespaces[ns].AccessLevel); err != nil {
+ if err := checkAccessLevel(c, r, getConfig(c).Namespaces[ns].AccessLevel); err != nil {
return err
}
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
@@ -1435,7 +1435,7 @@ func augmentRepro(c context.Context, w http.ResponseWriter, tag string, bug *Bug
if tag == textReproC {
prefix = "//"
}
- fmt.Fprintf(w, "%v %v/bug?id=%v\n", prefix, appURL(c), bug.keyHash())
+ fmt.Fprintf(w, "%v %v/bug?id=%v\n", prefix, appURL(c), bug.keyHash(c))
}
}
if tag == textReproSyz {
@@ -1519,7 +1519,7 @@ func fetchNamespaceBugs(c context.Context, accessLevel AccessLevel, ns string,
bugMap := make(map[string]*uiBug)
var dups []*Bug
for _, bug := range bugs {
- if accessLevel < bug.sanitizeAccess(accessLevel) {
+ if accessLevel < bug.sanitizeAccess(c, accessLevel) {
continue
}
if bug.Status == BugStatusDup {
@@ -1534,7 +1534,7 @@ func fetchNamespaceBugs(c context.Context, accessLevel AccessLevel, ns string,
// Don't show "fix pending" bugs on the main page.
continue
}
- bugMap[bug.keyHash()] = uiBug
+ bugMap[bug.keyHash(c)] = uiBug
id := uiBug.ReportingIndex
groups[id] = append(groups[id], uiBug)
}
@@ -1545,7 +1545,7 @@ func fetchNamespaceBugs(c context.Context, accessLevel AccessLevel, ns string,
}
mergeUIBug(c, bug, dup)
}
- cfg := config.Namespaces[ns]
+ cfg := getConfig(c).Namespaces[ns]
var uiGroups []*uiBugGroup
for index, bugs := range groups {
sort.Slice(bugs, func(i, j int) bool {
@@ -1658,7 +1658,7 @@ func fetchTerminalBugs(c context.Context, accessLevel AccessLevel,
Namespace: ns,
}
for _, bug := range bugs {
- if accessLevel < bug.sanitizeAccess(accessLevel) {
+ if accessLevel < bug.sanitizeAccess(c, accessLevel) {
continue
}
if !typ.Filter.MatchBug(bug) {
@@ -1686,7 +1686,7 @@ func applyBugFilter(query *db.Query, filter *userBugFilter) *db.Query {
func loadDupsForBug(c context.Context, r *http.Request, bug *Bug, state *ReportingState, managers []string) (
*uiBugGroup, error) {
- bugHash := bug.keyHash()
+ bugHash := bug.keyHash(c)
var dups []*Bug
_, err := db.NewQuery("Bug").
Filter("Status=", BugStatusDup).
@@ -1698,7 +1698,7 @@ func loadDupsForBug(c context.Context, r *http.Request, bug *Bug, state *Reporti
var results []*uiBug
accessLevel := accessLevel(c, r)
for _, dup := range dups {
- if accessLevel < dup.sanitizeAccess(accessLevel) {
+ if accessLevel < dup.sanitizeAccess(c, accessLevel) {
continue
}
results = append(results, createUIBug(c, dup, state, managers))
@@ -1722,7 +1722,7 @@ func loadSimilarBugsUI(c context.Context, r *http.Request, bug *Bug, state *Repo
}
var results []*uiBug
for _, similar := range similarBugs {
- if accessLevel < similar.sanitizeAccess(accessLevel) {
+ if accessLevel < similar.sanitizeAccess(c, accessLevel) {
continue
}
if managers[similar.Namespace] == nil {
@@ -1820,13 +1820,13 @@ func createUIBug(c context.Context, bug *Bug, state *ReportingState, managers []
ReproLevel: bug.ReproLevel,
ReportingIndex: reportingIdx,
Status: status,
- Link: bugExtLink(bug),
+ Link: bugExtLink(c, bug),
ExternalLink: link,
CreditEmail: creditEmail,
NumManagers: len(managers),
LastActivity: bug.LastActivity,
Discussions: bug.discussionSummary(),
- ID: bug.keyHash(),
+ ID: bug.keyHash(c),
}
for _, entry := range bug.Labels {
uiBug.Labels = append(uiBug.Labels, makeBugLabelUI(c, bug, entry))
@@ -1834,7 +1834,7 @@ func createUIBug(c context.Context, bug *Bug, state *ReportingState, managers []
updateBugBadness(c, uiBug)
if len(bug.Commits) != 0 {
for i, com := range bug.Commits {
- cfg := config.Namespaces[bug.Namespace]
+ cfg := getConfig(c).Namespaces[bug.Namespace]
info := bug.getCommitInfo(i)
uiBug.Commits = append(uiBug.Commits, &uiCommit{
Hash: info.Hash,
@@ -2087,8 +2087,8 @@ func loadManagers(c context.Context, accessLevel AccessLevel, ns string, filter
coverURL := ""
if asset, ok := coverAssets[mgr.Name]; ok {
coverURL = asset.DownloadURL
- } else if config.CoverPath != "" {
- coverURL = config.CoverPath + mgr.Name + ".html"
+ } else if getConfig(c).CoverPath != "" {
+ coverURL = getConfig(c).CoverPath + mgr.Name + ".html"
}
ui := &uiManager{
Now: timeNow(c),
@@ -2128,7 +2128,7 @@ func loadManagerList(c context.Context, accessLevel AccessLevel, ns string,
var filtered []*Manager
var filteredKeys []*db.Key
for i, mgr := range managers {
- cfg := config.Namespaces[mgr.Namespace]
+ cfg := getConfig(c).Namespaces[mgr.Namespace]
if accessLevel < cfg.AccessLevel {
continue
}
@@ -2388,10 +2388,10 @@ func (b *bugJobs) uiBestFixCandidate(c context.Context) (*uiJob, error) {
// bugExtLink should be preferred to bugLink since it provides a URL that's more consistent with
// links from email addresses.
-func bugExtLink(bug *Bug) string {
- _, bugReporting, _, _, _ := currentReporting(bug)
+func bugExtLink(c context.Context, bug *Bug) string {
+ _, bugReporting, _, _, _ := currentReporting(c, bug)
if bugReporting == nil || bugReporting.ID == "" {
- return bugLink(bug.keyHash())
+ return bugLink(bug.keyHash(c))
}
return "/bug?extid=" + bugReporting.ID
}
diff --git a/dashboard/app/main_test.go b/dashboard/app/main_test.go
index 410dd43d4..84cf888dc 100644
--- a/dashboard/app/main_test.go
+++ b/dashboard/app/main_test.go
@@ -256,7 +256,7 @@ func TestMultiLabelFilter(t *testing.T) {
defer c.Close()
client := c.makeClient(clientPublicEmail, keyPublicEmail, true)
- mailingList := config.Namespaces["access-public-email"].Reporting[0].Config.(*EmailConfig).Email
+ mailingList := c.config().Namespaces["access-public-email"].Reporting[0].Config.(*EmailConfig).Email
build1 := testBuild(1)
build1.Manager = "manager-name-123"
diff --git a/dashboard/app/notifications_test.go b/dashboard/app/notifications_test.go
index 0aceb9915..c9093c5e2 100644
--- a/dashboard/app/notifications_test.go
+++ b/dashboard/app/notifications_test.go
@@ -12,6 +12,7 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/syzkaller/dashboard/dashapi"
"github.com/google/syzkaller/pkg/email"
+ "golang.org/x/net/context"
)
func TestEmailNotifUpstreamEmbargo(t *testing.T) {
@@ -214,9 +215,10 @@ func TestBugObsoleting(t *testing.T) {
period: 80 * day,
},
}
+ c := context.Background()
for i, test := range tests {
test.bug.Namespace = "test1"
- got := test.bug.obsoletePeriod()
+ got := test.bug.obsoletePeriod(c)
if got != test.period {
t.Errorf("test #%v: got: %.2f, want %.2f",
i, float64(got/time.Hour)/24, float64(test.period/time.Hour)/24)
diff --git a/dashboard/app/reporting.go b/dashboard/app/reporting.go
index 27b1fed0b..7c9607249 100644
--- a/dashboard/app/reporting.go
+++ b/dashboard/app/reporting.go
@@ -96,7 +96,7 @@ func handleReportBug(c context.Context, typ string, state *ReportingState, bug *
func needReport(c context.Context, typ string, state *ReportingState, bug *Bug) (
reporting *Reporting, bugReporting *BugReporting, reportingIdx int,
status, link string, err error) {
- reporting, bugReporting, reportingIdx, status, err = currentReporting(bug)
+ reporting, bugReporting, reportingIdx, status, err = currentReporting(c, bug)
if err != nil || reporting == nil {
return
}
@@ -114,7 +114,7 @@ func needReport(c context.Context, typ string, state *ReportingState, bug *Bug)
return
}
ent := state.getEntry(timeNow(c), bug.Namespace, reporting.Name)
- cfg := config.Namespaces[bug.Namespace]
+ cfg := getConfig(c).Namespaces[bug.Namespace]
if timeSince(c, bug.FirstTime) < cfg.ReportingDelay {
status = fmt.Sprintf("%v: initial reporting delay", reporting.DisplayTitle)
reporting, bugReporting = nil, nil
@@ -187,7 +187,7 @@ func reportingPollNotifications(c context.Context, typ string) []*dashapi.BugNot
}
func handleReportNotif(c context.Context, typ string, bug *Bug) (*dashapi.BugNotification, error) {
- reporting, bugReporting, _, _, err := currentReporting(bug)
+ reporting, bugReporting, _, _, err := currentReporting(c, bug)
if err != nil || reporting == nil {
return nil, nil
}
@@ -239,7 +239,7 @@ var notificationGenerators = []func(context.Context, *Bug, *Reporting,
if len(bug.Commits) == 0 &&
bug.canBeObsoleted(c) &&
timeSince(c, bug.LastActivity) > notifyResendPeriod &&
- timeSince(c, bug.LastTime) > bug.obsoletePeriod() {
+ timeSince(c, bug.LastTime) > bug.obsoletePeriod(c) {
log.Infof(c, "%v: obsoleting: %v", bug.Namespace, bug.Title)
why := bugObsoletionReason(bug)
return createNotification(c, dashapi.BugNotifObsoleted, false, string(why), bug, reporting, bugReporting)
@@ -293,7 +293,7 @@ func createLabelNotification(c context.Context, label BugLabel, bug *Bug, report
var err error
notif.TreeJobs, err = treeTestJobs(c, bug)
if err != nil {
- log.Errorf(c, "failed to extract jobs for %s: %v", bug.keyHash(), err)
+ log.Errorf(c, "failed to extract jobs for %s: %v", bug.keyHash(c), err)
return nil, fmt.Errorf("failed to fetch jobs: %w", err)
}
}
@@ -331,7 +331,7 @@ func (bug *Bug) canBeObsoleted(c context.Context) bool {
return true
}
if obsoleteWhatWontBeFixBisected {
- cfg := config.Namespaces[bug.Namespace]
+ cfg := getConfig(c).Namespaces[bug.Namespace]
for _, mgr := range bug.HappenedOn {
if !cfg.Managers[mgr].FixBisectionDisabled {
return false
@@ -342,8 +342,9 @@ func (bug *Bug) canBeObsoleted(c context.Context) bool {
return false
}
-func (bug *Bug) obsoletePeriod() time.Duration {
+func (bug *Bug) obsoletePeriod(c context.Context) time.Duration {
period := never
+ config := getConfig(c)
if config.Obsoleting.MinPeriod == 0 {
return period
}
@@ -371,7 +372,7 @@ func (bug *Bug) obsoletePeriod() time.Duration {
bug.Reporting[len(bug.Reporting)-1].Reported.IsZero() {
min, max = config.Obsoleting.NonFinalMinPeriod, config.Obsoleting.NonFinalMaxPeriod
}
- if mgr := bug.managerConfig(); mgr != nil && mgr.ObsoletingMinPeriod != 0 {
+ if mgr := bug.managerConfig(c); mgr != nil && mgr.ObsoletingMinPeriod != 0 {
min, max = mgr.ObsoletingMinPeriod, mgr.ObsoletingMaxPeriod
}
if period < min {
@@ -383,11 +384,11 @@ func (bug *Bug) obsoletePeriod() time.Duration {
return period
}
-func (bug *Bug) managerConfig() *ConfigManager {
+func (bug *Bug) managerConfig(c context.Context) *ConfigManager {
if len(bug.HappenedOn) != 1 {
return nil
}
- mgr := config.Namespaces[bug.Namespace].Managers[bug.HappenedOn[0]]
+ mgr := getConfig(c).Namespaces[bug.Namespace].Managers[bug.HappenedOn[0]]
return &mgr
}
@@ -424,7 +425,7 @@ func createNotification(c context.Context, typ dashapi.BugNotif, public bool, te
if (public || reporting.moderation) && bugReporting.CC != "" {
notif.CC = append(notif.CC, strings.Split(bugReporting.CC, "|")...)
}
- if mgr := bug.managerConfig(); mgr != nil {
+ if mgr := bug.managerConfig(c); mgr != nil {
notif.CC = append(notif.CC, mgr.CC.Always...)
if public {
notif.Maintainers = append(notif.Maintainers, mgr.CC.Maintainers...)
@@ -433,7 +434,7 @@ func createNotification(c context.Context, typ dashapi.BugNotif, public bool, te
return notif, nil
}
-func currentReporting(bug *Bug) (*Reporting, *BugReporting, int, string, error) {
+func currentReporting(c context.Context, bug *Bug) (*Reporting, *BugReporting, int, string, error) {
if bug.NumCrashes == 0 {
// This is possible during the short window when we already created a bug,
// but did not attach the first crash to it yet. We need to avoid reporting this bug yet
@@ -446,7 +447,7 @@ func currentReporting(bug *Bug) (*Reporting, *BugReporting, int, string, error)
if !bugReporting.Closed.IsZero() {
continue
}
- reporting := config.Namespaces[bug.Namespace].ReportingByName(bugReporting.Name)
+ reporting := getConfig(c).Namespaces[bug.Namespace].ReportingByName(bugReporting.Name)
if reporting == nil {
return nil, nil, 0, "", fmt.Errorf("%v: missing in config", bugReporting.Name)
}
@@ -593,7 +594,7 @@ func crashBugReport(c context.Context, bug *Bug, crash *Crash, crashKey *db.Key,
if build.Type == BuildFailed {
rep.Maintainers = append(rep.Maintainers, kernelRepo.CC.BuildMaintainers...)
}
- if mgr := bug.managerConfig(); mgr != nil {
+ if mgr := bug.managerConfig(c); mgr != nil {
rep.CC = append(rep.CC, mgr.CC.Always...)
rep.Maintainers = append(rep.Maintainers, mgr.CC.Maintainers...)
if build.Type == BuildFailed {
@@ -923,7 +924,7 @@ func checkDupBug(c context.Context, cmd *dashapi.BugUpdate, bug *Bug, bugKey, du
if !dupReporting.Closed.IsZero() && dupCanon.Status == BugStatusOpen {
return nil, false, "Dup bug is already upstreamed.", nil
}
- if dupCanon.keyHash() == bugKey.StringID() {
+ if dupCanon.keyHash(c) == bugKey.StringID() {
return nil, false, "Setting this dup would lead to a bug cycle, cycles are not allowed.", nil
}
return dup, true, "", nil
@@ -945,7 +946,7 @@ func allowCrossReportingDup(c context.Context, bug, dup *Bug,
// provided that these two reportings have the same access level and type.
// The rest of the combinations can lead to surprising states and
// information hiding, so we don't allow them.
- cfg := config.Namespaces[bug.Namespace]
+ cfg := getConfig(c).Namespaces[bug.Namespace]
bugConfig := &cfg.Reporting[bugIdx]
dupConfig := &cfg.Reporting[dupIdx]
lastIdx := len(cfg.Reporting) - 1
@@ -1109,7 +1110,7 @@ func incomingCommandCmd(c context.Context, now time.Time, cmd *dashapi.BugUpdate
case dashapi.BugStatusDup:
bug.Status = BugStatusDup
bug.Closed = now
- bug.DupOf = dup.keyHash()
+ bug.DupOf = dup.keyHash(c)
case dashapi.BugStatusUpdate:
// Just update Link, Commits, etc below.
case dashapi.BugStatusUnCC:
@@ -1188,7 +1189,7 @@ func findDupByTitle(c context.Context, ns, title string) (*Bug, *db.Key, error)
if err != nil {
return nil, nil, err
}
- bugHash := bugKeyHash(ns, title, seq)
+ bugHash := bugKeyHash(c, ns, title, seq)
bugKey := db.NewKey(c, "Bug", bugHash, 0, nil)
bug := new(Bug)
if err := db.Get(c, bugKey, bug); err != nil {
@@ -1229,7 +1230,7 @@ func lastReportedReporting(bug *Bug) *BugReporting {
// The updateReporting method is supposed to be called both to fully initialize a new
// Bug object and also to adjust it to the updated namespace configuration.
-func (bug *Bug) updateReportings(cfg *Config, now time.Time) error {
+func (bug *Bug) updateReportings(c context.Context, cfg *Config, now time.Time) error {
oldReportings := map[string]BugReporting{}
oldPositions := map[string]int{}
for i, rep := range bug.Reporting {
@@ -1251,7 +1252,7 @@ func (bug *Bug) updateReportings(cfg *Config, now time.Time) error {
} else {
bug.Reporting = append(bug.Reporting, BugReporting{
Name: rep.Name,
- ID: bugReportingHash(bug.keyHash(), rep.Name),
+ ID: bugReportingHash(bug.keyHash(c), rep.Name),
})
}
}
@@ -1351,7 +1352,7 @@ func (state *ReportingState) getEntry(now time.Time, namespace, name string) *Re
func loadFullBugInfo(c context.Context, bug *Bug, bugKey *db.Key,
bugReporting *BugReporting) (*dashapi.FullBugInfo, error) {
- reporting := config.Namespaces[bug.Namespace].ReportingByName(bugReporting.Name)
+ reporting := getConfig(c).Namespaces[bug.Namespace].ReportingByName(bugReporting.Name)
if reporting == nil {
return nil, fmt.Errorf("failed to find the reporting object")
}
@@ -1383,7 +1384,7 @@ func loadFullBugInfo(c context.Context, bug *Bug, bugKey *db.Key,
return nil, err
}
for _, similarBug := range similar {
- _, bugReporting, _, _, _ := currentReporting(similarBug)
+ _, bugReporting, _, _, _ := currentReporting(c, similarBug)
if bugReporting == nil {
continue
}
diff --git a/dashboard/app/reporting_email.go b/dashboard/app/reporting_email.go
index 17c8efcec..324f70575 100644
--- a/dashboard/app/reporting_email.go
+++ b/dashboard/app/reporting_email.go
@@ -38,7 +38,7 @@ func initEmailReporting() {
http.HandleFunc("/_ah/bounce", handleEmailBounce)
mailingLists = make(map[string]bool)
- for _, cfg := range config.Namespaces {
+ for _, cfg := range getConfig(context.Background()).Namespaces {
for _, reporting := range cfg.Reporting {
if cfg, ok := reporting.Config.(*EmailConfig); ok {
mailingLists[email.CanonicalEmail(cfg.Email)] = true
@@ -272,7 +272,7 @@ func emailSendBugNotif(c context.Context, notif *dashapi.BugNotification) error
func buildBadCommitMessage(c context.Context, notif *dashapi.BugNotification) (string, error) {
var sb strings.Builder
days := int(notifyAboutBadCommitPeriod / time.Hour / 24)
- nsConfig := config.Namespaces[notif.Namespace]
+ nsConfig := getConfig(c).Namespaces[notif.Namespace]
fmt.Fprintf(&sb, `This bug is marked as fixed by commit:
%v
@@ -456,14 +456,14 @@ func handleIncomingMail(w http.ResponseWriter, r *http.Request) {
return
}
source := dashapi.NoDiscussion
- for _, item := range config.DiscussionEmails {
+ for _, item := range getConfig(c).DiscussionEmails {
if item.ReceiveAddress != myEmail {
continue
}
source = item.Source
break
}
- msg, err := email.Parse(r.Body, ownEmails(c), ownMailingLists(), []string{
+ msg, err := email.Parse(r.Body, ownEmails(c), ownMailingLists(c), []string{
appURL(c),
})
if err != nil {
@@ -632,7 +632,7 @@ func handleBugCommand(c context.Context, bugInfo *bugInfoResult, msg *email.Emai
return "no dup title"
}
var err error
- cmd.DupOf, err = subjectParser.parseFullTitle(command.Args)
+ cmd.DupOf, err = getSubjectParser(c).parseFullTitle(command.Args)
if err != nil {
return "failed to parse the dup title"
}
@@ -708,7 +708,7 @@ func handleTestCommand(c context.Context, info *bugInfoResult,
if len(args) == 2 {
repo, branch = args[0], args[1]
}
- if info.bug.sanitizeAccess(AccessPublic) != AccessPublic {
+ if info.bug.sanitizeAccess(c, AccessPublic) != AccessPublic {
log.Warningf(c, "%v: bug is not AccessPublic, patch testing request is denied", info.bug.Title)
return ""
}
@@ -954,12 +954,12 @@ func identifyEmail(c context.Context, msg *email.Email) (*bugInfoResult, *bugLis
log.Errorf(c, "no bug list with the %v ID found", bugID)
return nil, nil, nil
}
- reminderConfig := config.Namespaces[subsystem.Namespace].Subsystems.Reminder
+ reminderConfig := getConfig(c).Namespaces[subsystem.Namespace].Subsystems.Reminder
if reminderConfig == nil {
log.Errorf(c, "reminder configuration is empty")
return nil, nil, nil
}
- emailConfig, ok := bugListReportingConfig(subsystem.Namespace, stage).(*EmailConfig)
+ emailConfig, ok := bugListReportingConfig(c, subsystem.Namespace, stage).(*EmailConfig)
if !ok {
log.Errorf(c, "bug list's reporting config is not EmailConfig (id=%v)", bugID)
return nil, nil, nil
@@ -1047,7 +1047,7 @@ func loadBugInfo(c context.Context, msg *email.Email) *bugInfoResult {
}
return nil
}
- reporting := config.Namespaces[bug.Namespace].ReportingByName(bugReporting.Name)
+ reporting := getConfig(c).Namespaces[bug.Namespace].ReportingByName(bugReporting.Name)
if reporting == nil {
log.Errorf(c, "can't find reporting for this bug: namespace=%q reporting=%q",
bug.Namespace, bugReporting.Name)
@@ -1061,9 +1061,9 @@ func loadBugInfo(c context.Context, msg *email.Email) *bugInfoResult {
return &bugInfoResult{bug, bugKey, bugReporting, reporting}
}
-func ownMailingLists() []string {
+func ownMailingLists(c context.Context) []string {
configs := []ReportingType{}
- for _, ns := range config.Namespaces {
+ for _, ns := range getConfig(c).Namespaces {
for _, rep := range ns.Reporting {
configs = append(configs, rep.Config)
}
@@ -1090,12 +1090,25 @@ func ownMailingLists() []string {
}
var (
- subjectParser subjectTitleParser
- errAmbiguousTitle = errors.New("ambiguous bug title")
+ // Use getSubjectParser(c) instead.
+ defaultSubjectParser *subjectTitleParser
+ subjectParserInit sync.Once
+ errAmbiguousTitle = errors.New("ambiguous bug title")
)
+func getSubjectParser(c context.Context) *subjectTitleParser {
+ if getConfig(c) != getConfig(context.Background()) {
+ // For the non-default config, do not cache the parser.
+ return makeSubjectTitleParser(c)
+ }
+ subjectParserInit.Do(func() {
+ defaultSubjectParser = makeSubjectTitleParser(c)
+ })
+ return defaultSubjectParser
+}
+
func matchBugFromList(c context.Context, sender, subject string) (*bugInfoResult, error) {
- title, seq, err := subjectParser.parseTitle(subject)
+ title, seq, err := getSubjectParser(c).parseTitle(subject)
if err != nil {
return nil, err
}
@@ -1117,11 +1130,11 @@ func matchBugFromList(c context.Context, sender, subject string) (*bugInfoResult
log.Infof(c, "bug's seq is %v, wanted %d", bug.Seq, seq)
continue
}
- if bug.sanitizeAccess(AccessPublic) != AccessPublic {
+ if bug.sanitizeAccess(c, AccessPublic) != AccessPublic {
log.Infof(c, "access denied")
continue
}
- reporting, bugReporting, _, _, err := currentReporting(bug)
+ reporting, bugReporting, _, _, err := currentReporting(c, bug)
if err != nil || reporting == nil {
log.Infof(c, "could not query reporting: %s", err)
continue
@@ -1154,7 +1167,25 @@ func matchBugFromList(c context.Context, sender, subject string) (*bugInfoResult
type subjectTitleParser struct {
pattern *regexp.Regexp
- ready sync.Once
+}
+
+func makeSubjectTitleParser(c context.Context) *subjectTitleParser {
+ stripPrefixes := []string{`R[eE]:`}
+ for _, ns := range getConfig(c).Namespaces {
+ for _, rep := range ns.Reporting {
+ emailConfig, ok := rep.Config.(*EmailConfig)
+ if !ok {
+ continue
+ }
+ if ok && emailConfig.SubjectPrefix != "" {
+ stripPrefixes = append(stripPrefixes,
+ regexp.QuoteMeta(emailConfig.SubjectPrefix))
+ }
+ }
+ }
+ rePrefixes := `^(?:(?:` + strings.Join(stripPrefixes, "|") + `)\s*)*`
+ pattern := regexp.MustCompile(rePrefixes + `(?:\[[^\]]+\]\s*)*\s*(.*)$`)
+ return &subjectTitleParser{pattern}
}
func (p *subjectTitleParser) parseTitle(subject string) (string, int64, error) {
@@ -1166,7 +1197,6 @@ func (p *subjectTitleParser) parseTitle(subject string) (string, int64, error) {
}
func (p *subjectTitleParser) parseFullTitle(subject string) (string, error) {
- p.prepareRegexps()
subject = strings.TrimSpace(subject)
parts := p.pattern.FindStringSubmatch(subject)
if parts == nil || parts[len(parts)-1] == "" {
@@ -1175,26 +1205,6 @@ func (p *subjectTitleParser) parseFullTitle(subject string) (string, error) {
return parts[len(parts)-1], nil
}
-func (p *subjectTitleParser) prepareRegexps() {
- p.ready.Do(func() {
- stripPrefixes := []string{`R[eE]:`}
- for _, ns := range config.Namespaces {
- for _, rep := range ns.Reporting {
- emailConfig, ok := rep.Config.(*EmailConfig)
- if !ok {
- continue
- }
- if ok && emailConfig.SubjectPrefix != "" {
- stripPrefixes = append(stripPrefixes,
- regexp.QuoteMeta(emailConfig.SubjectPrefix))
- }
- }
- }
- rePrefixes := `^(?:(?:` + strings.Join(stripPrefixes, "|") + `)\s*)*`
- p.pattern = regexp.MustCompile(rePrefixes + `(?:\[[^\]]+\]\s*)*\s*(.*)$`)
- })
-}
-
func checkMailingListInCC(c context.Context, msg *email.Email, mailingList string) bool {
if msg.MailingList == mailingList {
return true
@@ -1266,8 +1276,8 @@ func replySubject(subject string) string {
}
func ownEmail(c context.Context) string {
- if config.OwnEmailAddress != "" {
- return config.OwnEmailAddress
+ if getConfig(c).OwnEmailAddress != "" {
+ return getConfig(c).OwnEmailAddress
}
return fmt.Sprintf("syzbot@%v.appspotmail.com", appengine.AppID(c))
}
@@ -1278,6 +1288,7 @@ func fromAddr(c context.Context) string {
func ownEmails(c context.Context) []string {
emails := []string{ownEmail(c)}
+ config := getConfig(c)
if config.ExtraOwnEmailAddresses != nil {
emails = append(emails, config.ExtraOwnEmailAddresses...)
} else if config.OwnEmailAddress == "" {
@@ -1310,8 +1321,9 @@ func externalLink(c context.Context, tag string, id int64) string {
}
func appURL(c context.Context) string {
- if config.AppURL != "" {
- return config.AppURL
+ appURL := getConfig(c).AppURL
+ if appURL != "" {
+ return appURL
}
return fmt.Sprintf("https://%v.appspot.com", appengine.AppID(c))
}
diff --git a/dashboard/app/reporting_lists.go b/dashboard/app/reporting_lists.go
index 7e3ff0540..2cd6e94a3 100644
--- a/dashboard/app/reporting_lists.go
+++ b/dashboard/app/reporting_lists.go
@@ -32,7 +32,7 @@ func reportingPollBugLists(c context.Context, typ string) []*dashapi.BugListRepo
return nil
}
ret := []*dashapi.BugListReport{}
- for ns, nsConfig := range config.Namespaces {
+ for ns, nsConfig := range getConfig(c).Namespaces {
rConfig := nsConfig.Subsystems.Reminder
if rConfig == nil {
continue
@@ -80,7 +80,7 @@ func handleSubsystemReports(w http.ResponseWriter, r *http.Request) {
log.Errorf(c, "failed to load subsystems: %v", err)
return
}
- for ns, nsConfig := range config.Namespaces {
+ for ns, nsConfig := range getConfig(c).Namespaces {
rConfig := nsConfig.Subsystems.Reminder
if rConfig == nil {
continue
@@ -173,7 +173,7 @@ func reportingBugListCommand(c context.Context, cmd *dashapi.BugListUpdate) (str
return fmt.Errorf("failed to query state: %w", err)
}
stateEnt := state.getEntry(timeNow(c), subsystem.Namespace,
- config.Namespaces[subsystem.Namespace].Subsystems.Reminder.SourceReporting)
+ getConfig(c).Namespaces[subsystem.Namespace].Subsystems.Reminder.SourceReporting)
stateEnt.Sent++
if err := saveReportingState(c, state); err != nil {
return fmt.Errorf("failed to save state: %w", err)
@@ -249,7 +249,7 @@ func querySubsystemReport(c context.Context, subsystem *Subsystem, reporting *Re
}
withRepro, noRepro := []*Bug{}, []*Bug{}
for _, bug := range rawOpenBugs {
- currReporting, _, _, _, _ := currentReporting(bug)
+ currReporting, _, _, _, _ := currentReporting(c, bug)
if reporting.Name != currReporting.Name {
// The big is not at the expected reporting stage.
continue
@@ -370,7 +370,7 @@ func queryMatchingBugs(c context.Context, ns, name string, accessLevel AccessLev
fixed = append(fixed, bug)
continue
}
- currReporting, _, _, _, err := currentReporting(bug)
+ currReporting, _, _, _, err := currentReporting(c, bug)
if err != nil {
continue
}
@@ -420,7 +420,7 @@ func reportingBugListReport(c context.Context, subsystemReport *SubsystemReport,
if !stage.Closed.IsZero() {
continue
}
- repConfig := bugListReportingConfig(ns, &stage)
+ repConfig := bugListReportingConfig(c, ns, &stage)
if repConfig == nil {
// It might happen if e.g. Moderation was set to nil.
// Just skip the stage then.
@@ -443,7 +443,7 @@ func reportingBugListReport(c context.Context, subsystemReport *SubsystemReport,
Moderation: stage.Moderation,
TotalStats: subsystemReport.TotalStats.toDashapi(),
PeriodStats: subsystemReport.PeriodStats.toDashapi(),
- PeriodDays: config.Namespaces[ns].Subsystems.Reminder.PeriodDays,
+ PeriodDays: getConfig(c).Namespaces[ns].Subsystems.Reminder.PeriodDays,
}
bugKeys, err := subsystemReport.getBugKeys()
if err != nil {
@@ -456,7 +456,7 @@ func reportingBugListReport(c context.Context, subsystemReport *SubsystemReport,
}
for _, bug := range bugs {
bugReporting := bugReportingByName(bug,
- config.Namespaces[ns].Subsystems.Reminder.SourceReporting)
+ getConfig(c).Namespaces[ns].Subsystems.Reminder.SourceReporting)
ret.Bugs = append(ret.Bugs, dashapi.BugListItem{
Title: bug.displayTitle(),
Link: fmt.Sprintf("%v/bug?extid=%v", appURL(c), bugReporting.ID),
@@ -469,8 +469,8 @@ func reportingBugListReport(c context.Context, subsystemReport *SubsystemReport,
return nil, nil
}
-func bugListReportingConfig(ns string, stage *SubsystemReportStage) ReportingType {
- cfg := config.Namespaces[ns].Subsystems.Reminder
+func bugListReportingConfig(c context.Context, ns string, stage *SubsystemReportStage) ReportingType {
+ cfg := getConfig(c).Namespaces[ns].Subsystems.Reminder
if stage.Moderation {
return cfg.ModerationConfig
}
diff --git a/dashboard/app/reporting_test.go b/dashboard/app/reporting_test.go
index 7ef314df4..0cb198d15 100644
--- a/dashboard/app/reporting_test.go
+++ b/dashboard/app/reporting_test.go
@@ -16,6 +16,7 @@ import (
"github.com/google/syzkaller/pkg/email"
"github.com/google/syzkaller/sys/targets"
"github.com/stretchr/testify/assert"
+ "golang.org/x/net/context"
)
func TestReportBug(t *testing.T) {
@@ -790,12 +791,12 @@ func TestUpdateBugReporting(t *testing.T) {
defer c.Close()
setIDs := func(bug *Bug, arr []BugReporting) {
for i := range arr {
- arr[i].ID = bugReportingHash(bug.keyHash(), arr[i].Name)
+ arr[i].ID = bugReportingHash(bug.keyHash(c.ctx), arr[i].Name)
}
}
now := timeNow(c.ctx)
// We test against the test2 namespace.
- cfg := config.Namespaces["test2"]
+ cfg := c.config().Namespaces["test2"]
tests := []struct {
Before []BugReporting
After []BugReporting
@@ -919,7 +920,7 @@ func TestUpdateBugReporting(t *testing.T) {
}
setIDs(bug, bug.Reporting)
setIDs(bug, test.After)
- hasError := bug.updateReportings(cfg, now) != nil
+ hasError := bug.updateReportings(c.ctx, cfg, now) != nil
if hasError != test.Error {
t.Errorf("Before: %#v, Expected error: %v, Got error: %v", test.Before, test.Error, hasError)
}
@@ -1109,6 +1110,8 @@ func TestReportDecommissionedBugs(t *testing.T) {
func TestObsoletePeriod(t *testing.T) {
base := time.Now()
+ c := context.Background()
+ config := getConfig(c)
tests := []struct {
name string
bug *Bug
@@ -1166,7 +1169,7 @@ func TestObsoletePeriod(t *testing.T) {
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
- ret := test.bug.obsoletePeriod()
+ ret := test.bug.obsoletePeriod(c)
assert.Equal(t, test.period, ret)
})
}
diff --git a/dashboard/app/subsystem.go b/dashboard/app/subsystem.go
index d056924c9..26b6b29ce 100644
--- a/dashboard/app/subsystem.go
+++ b/dashboard/app/subsystem.go
@@ -135,7 +135,7 @@ func logSubsystemChange(c context.Context, bug *Bug, new []*subsystem.Subsystem)
sort.Strings(newNames)
if !reflect.DeepEqual(oldNames, newNames) {
log.Infof(c, "bug %s: subsystems set from %v to %v",
- bug.keyHash(), oldNames, newNames)
+ bug.keyHash(c), oldNames, newNames)
}
}
@@ -190,35 +190,12 @@ func subsystemMaintainers(c context.Context, ns, subsystemName string) []string
return item.Emails()
}
-var subsystemsListKey = "custom list of kernel subsystems"
-
-type customSubsystemList struct {
- ns string
- list []*subsystem.Subsystem
- revision int
-}
-
-func contextWithSubsystems(c context.Context, custom *customSubsystemList) context.Context {
- return context.WithValue(c, &subsystemsListKey, custom)
-}
-
func getSubsystemService(c context.Context, ns string) *subsystem.Service {
- // This is needed to emulate changes to the subsystem list over time during testing.
- if val, ok := c.Value(&subsystemsListKey).(*customSubsystemList); ok && val.ns == ns {
- if len(val.list) == 0 {
- return nil
- } else {
- return subsystem.MustMakeService(val.list)
- }
- }
- return config.Namespaces[ns].Subsystems.Service
+ return getConfig(c).Namespaces[ns].Subsystems.Service
}
func getSubsystemRevision(c context.Context, ns string) int {
- if val, ok := c.Value(&subsystemsListKey).(*customSubsystemList); ok && val.ns == ns {
- return val.revision
- }
- return config.Namespaces[ns].Subsystems.Revision
+ return getConfig(c).Namespaces[ns].Subsystems.Revision
}
func subsystemListURL(c context.Context, ns string) string {
diff --git a/dashboard/app/subsystem_test.go b/dashboard/app/subsystem_test.go
index bc2bdb505..3462a471f 100644
--- a/dashboard/app/subsystem_test.go
+++ b/dashboard/app/subsystem_test.go
@@ -1005,7 +1005,7 @@ func TestRemindersPriority(t *testing.T) {
defer c.Close()
client := c.makeClient(clientSubsystemRemind, keySubsystemRemind, true)
- mailingList := config.Namespaces["subsystem-reminders"].Reporting[1].Config.(*EmailConfig).Email
+ mailingList := c.config().Namespaces["subsystem-reminders"].Reporting[1].Config.(*EmailConfig).Email
build := testBuild(1)
client.UploadBuild(build)
diff --git a/dashboard/app/tree.go b/dashboard/app/tree.go
index 07acde1fa..c1afc5b6c 100644
--- a/dashboard/app/tree.go
+++ b/dashboard/app/tree.go
@@ -585,7 +585,7 @@ func (ctx *bugTreeContext) loadCrashInfo() error {
if ctx.crash != nil {
var err error
ns := ctx.bug.Namespace
- repoGraph, err := makeRepoGraph(getKernelRepos(ctx.c, ns))
+ repoGraph, err := makeRepoGraph(getConfig(ctx.c).Namespaces[ns].Repos)
if err != nil {
return err
}
@@ -602,7 +602,7 @@ func (ctx *bugTreeContext) isCrashRelevant(crash *Crash) (bool, *Build, error) {
// Let's wait for the repro.
return false, nil, nil
}
- newManager, _ := activeManager(crash.Manager, ctx.bug.Namespace)
+ newManager, _ := activeManager(ctx.cGlobal, crash.Manager, ctx.bug.Namespace)
if newManager != crash.Manager {
// The manager was deprecated since the crash.
// Let's just ignore such bugs for now.
@@ -719,7 +719,7 @@ func treeTestJobs(c context.Context, bug *Bug) ([]*dashapi.JobInfo, error) {
// b) Whether the lookup was expensive (it can help optimize crossTreeBisection calls).
func crossTreeBisection(c context.Context, bug *Bug,
managers map[string]dashapi.ManagerJobs) (*Job, *db.Key, bool, error) {
- repoGraph, err := makeRepoGraph(getKernelRepos(c, bug.Namespace))
+ repoGraph, err := makeRepoGraph(getConfig(c).Namespaces[bug.Namespace].Repos)
if err != nil {
return nil, nil, false, err
}
@@ -754,7 +754,7 @@ func crossTreeBisection(c context.Context, bug *Bug,
if err != nil {
return err
}
- manager, _ := activeManager(crashJob.Manager, crashJob.Namespace)
+ manager, _ := activeManager(c, crashJob.Manager, crashJob.Namespace)
if !managers[manager].BisectFix {
return nil
}
diff --git a/dashboard/app/tree_test.go b/dashboard/app/tree_test.go
index f9109202f..5b8fc6134 100644
--- a/dashboard/app/tree_test.go
+++ b/dashboard/app/tree_test.go
@@ -967,12 +967,12 @@ func (ctx *treeTestCtx) now() time.Time {
}
func (ctx *treeTestCtx) updateRepos(repos []KernelRepo) {
- checkKernelRepos("tree-tests", config.Namespaces["tree-tests"], repos)
+ checkKernelRepos("tree-tests", ctx.ctx.config().Namespaces["tree-tests"], repos)
ctx.perAlias = map[string]KernelRepo{}
for _, repo := range repos {
ctx.perAlias[repo.Alias] = repo
}
- ctx.ctx.setKernelRepos(repos)
+ ctx.ctx.setKernelRepos("tree-tests", repos)
}
func (ctx *treeTestCtx) uploadBuild(repo, branch string) *dashapi.Build {
diff --git a/dashboard/app/util_test.go b/dashboard/app/util_test.go
index b0ac1c6fe..668c3b962 100644
--- a/dashboard/app/util_test.go
+++ b/dashboard/app/util_test.go
@@ -86,6 +86,10 @@ func NewCtx(t *testing.T) *Ctx {
return c
}
+func (c *Ctx) config() *GlobalConfig {
+ return getConfig(c.ctx)
+}
+
func (c *Ctx) expectOK(err error) {
if err != nil {
c.t.Helper()
@@ -211,17 +215,28 @@ func (c *Ctx) advanceTime(d time.Duration) {
func (c *Ctx) setSubsystems(ns string, list []*subsystem.Subsystem, rev int) {
c.transformContext = func(c context.Context) context.Context {
- return contextWithSubsystems(c, &customSubsystemList{
- ns: ns,
- list: list,
- revision: rev,
+ newConfig := replaceNamespaceConfig(c, ns, func(cfg *Config) *Config {
+ ret := *cfg
+ ret.Subsystems.Revision = rev
+ if list == nil {
+ ret.Subsystems.Service = nil
+ } else {
+ ret.Subsystems.Service = subsystem.MustMakeService(list)
+ }
+ return &ret
})
+ return contextWithConfig(c, newConfig)
}
}
-func (c *Ctx) setKernelRepos(list []KernelRepo) {
+func (c *Ctx) setKernelRepos(ns string, list []KernelRepo) {
c.transformContext = func(c context.Context) context.Context {
- return contextWithRepos(c, list)
+ newConfig := replaceNamespaceConfig(c, ns, func(cfg *Config) *Config {
+ ret := *cfg
+ ret.Repos = list
+ return &ret
+ })
+ return contextWithConfig(c, newConfig)
}
}
@@ -231,9 +246,25 @@ func (c *Ctx) setNoObsoletions() {
}
}
+func (c *Ctx) decommissionManager(ns, oldManager, newManager string) {
+ c.transformContext = func(c context.Context) context.Context {
+ newConfig := replaceManagerConfig(c, ns, oldManager, func(cfg ConfigManager) ConfigManager {
+ cfg.Decommissioned = true
+ cfg.DelegatedTo = newManager
+ return cfg
+ })
+ return contextWithConfig(c, newConfig)
+ }
+}
+
func (c *Ctx) decommission(ns string) {
c.transformContext = func(c context.Context) context.Context {
- return contextWithDecommission(c, ns, true)
+ newConfig := replaceNamespaceConfig(c, ns, func(cfg *Config) *Config {
+ ret := *cfg
+ ret.Decommissioned = true
+ return &ret
+ })
+ return contextWithConfig(c, newConfig)
}
}
@@ -669,3 +700,32 @@ func getRequestID(c context.Context) int {
}
return val
}
+
+// Create a shallow copy of GlobalConfig with a replaced namespace config.
+func replaceNamespaceConfig(c context.Context, ns string, f func(*Config) *Config) *GlobalConfig {
+ ret := *getConfig(c)
+ newNsMap := map[string]*Config{}
+ for name, nsCfg := range ret.Namespaces {
+ if name == ns {
+ nsCfg = f(nsCfg)
+ }
+ newNsMap[name] = nsCfg
+ }
+ ret.Namespaces = newNsMap
+ return &ret
+}
+
+func replaceManagerConfig(c context.Context, ns, mgr string, f func(ConfigManager) ConfigManager) *GlobalConfig {
+ return replaceNamespaceConfig(c, ns, func(cfg *Config) *Config {
+ ret := *cfg
+ newMgrMap := map[string]ConfigManager{}
+ for name, mgrCfg := range ret.Managers {
+ if name == mgr {
+ mgrCfg = f(mgrCfg)
+ }
+ newMgrMap[name] = mgrCfg
+ }
+ ret.Managers = newMgrMap
+ return &ret
+ })
+}