aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2019-11-27 16:40:04 +0100
committerDmitry Vyukov <dvyukov@google.com>2019-11-27 16:40:04 +0100
commit0d63f89cabcbc3e57201973370a309b646cc43c9 (patch)
tree3eb549e19dc354cf37fa9c735ea2f7cf3b901a5b
parent4cea005389a2c907bf947f6f2b79ef2bc9e42ce1 (diff)
syz-ci: allow enabling bisect cause and fix jobs separately
Some backport-only kernels may only be interested in fix bisections. Allow enabling these separately.
-rw-r--r--dashboard/app/api.go4
-rw-r--r--dashboard/app/bisect_test.go1
-rw-r--r--dashboard/app/jobs.go56
-rw-r--r--dashboard/app/util_test.go14
-rw-r--r--dashboard/dashapi/dashapi.go9
-rw-r--r--syz-ci/jobs.go40
-rw-r--r--syz-ci/syz-ci.go43
7 files changed, 91 insertions, 76 deletions
diff --git a/dashboard/app/api.go b/dashboard/app/api.go
index f8a59a3e9..09313b6a6 100644
--- a/dashboard/app/api.go
+++ b/dashboard/app/api.go
@@ -357,10 +357,10 @@ func apiJobPoll(c context.Context, r *http.Request, payload []byte) (interface{}
if err := json.Unmarshal(payload, req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %v", err)
}
- if len(req.PatchTestManagers) == 0 && len(req.BisectManagers) == 0 {
+ if len(req.Managers) == 0 {
return nil, fmt.Errorf("no managers")
}
- return pollPendingJobs(c, req.PatchTestManagers, req.BisectManagers)
+ return pollPendingJobs(c, req.Managers)
}
func apiJobDone(c context.Context, r *http.Request, payload []byte) (interface{}, error) {
diff --git a/dashboard/app/bisect_test.go b/dashboard/app/bisect_test.go
index 88aedc7fb..b385aa655 100644
--- a/dashboard/app/bisect_test.go
+++ b/dashboard/app/bisect_test.go
@@ -771,6 +771,7 @@ func TestBisectCauseExternal(t *testing.T) {
rep := c.client.pollBug()
pollResp := c.client.pollJobs(build.Manager)
+ c.expectNE(pollResp.ID, "")
jobID := pollResp.ID
done := &dashapi.JobDoneReq{
ID: jobID,
diff --git a/dashboard/app/jobs.go b/dashboard/app/jobs.go
index 7c7c011c0..4a31d8ff1 100644
--- a/dashboard/app/jobs.go
+++ b/dashboard/app/jobs.go
@@ -186,17 +186,10 @@ func checkTestJob(c context.Context, bug *Bug, bugReporting *BugReporting, crash
}
// pollPendingJobs returns the next job to execute for the provided list of managers.
-func pollPendingJobs(c context.Context, testMgrs, bisectMgrs []string) (*dashapi.JobPollResp, error) {
- testManagers := make(map[string]bool)
- for _, mgr := range testMgrs {
- testManagers[mgr] = true
- }
- bisectManagers := make(map[string]bool)
- for _, mgr := range bisectMgrs {
- bisectManagers[mgr] = true
- }
+func pollPendingJobs(c context.Context, managers map[string]dashapi.ManagerJobs) (
+ *dashapi.JobPollResp, error) {
retry:
- job, jobKey, err := getNextJob(c, testManagers, bisectManagers)
+ job, jobKey, err := getNextJob(c, managers)
if job == nil || err != nil {
return nil, err
}
@@ -210,35 +203,45 @@ retry:
return resp, nil
}
-func getNextJob(c context.Context, testManagers, bisectManagers map[string]bool) (*Job, *db.Key, error) {
- job, jobKey, err := loadPendingJob(c, testManagers, bisectManagers)
+func getNextJob(c context.Context, managers map[string]dashapi.ManagerJobs) (*Job, *db.Key, error) {
+ job, jobKey, err := loadPendingJob(c, managers)
if job != nil || err != nil {
return job, jobKey, err
}
- if len(bisectManagers) == 0 {
- return nil, nil, nil
- }
// We need both C and syz repros, but the crazy datastore query restrictions
// do not allow to use ReproLevel>ReproLevelNone in the query. So we do 2 separate queries.
// C repros tend to be of higher reliability so maybe it's not bad.
- job, jobKey, err = createBisectJob(c, bisectManagers, ReproLevelC)
+ job, jobKey, err = createBisectJob(c, managers, ReproLevelC)
if job != nil || err != nil {
return job, jobKey, err
}
- return createBisectJob(c, bisectManagers, ReproLevelSyz)
+ return createBisectJob(c, managers, ReproLevelSyz)
}
-func createBisectJob(c context.Context, managers map[string]bool, reproLevel dashapi.ReproLevel) (
- *Job, *db.Key, error) {
- job, jobKey, err := findBugsForBisection(c, managers, reproLevel, JobBisectCause)
+func createBisectJob(c context.Context, managers map[string]dashapi.ManagerJobs,
+ reproLevel dashapi.ReproLevel) (*Job, *db.Key, error) {
+ causeManagers := make(map[string]bool)
+ fixManagers := make(map[string]bool)
+ for mgr, jobs := range managers {
+ if jobs.BisectCause {
+ causeManagers[mgr] = true
+ }
+ if jobs.BisectFix {
+ fixManagers[mgr] = true
+ }
+ }
+ job, jobKey, err := findBugsForBisection(c, causeManagers, reproLevel, JobBisectCause)
if job != nil || err != nil {
return job, jobKey, err
}
- return findBugsForBisection(c, managers, reproLevel, JobBisectFix)
+ return findBugsForBisection(c, fixManagers, reproLevel, JobBisectFix)
}
-func findBugsForBisection(c context.Context, managers map[string]bool, reproLevel dashapi.ReproLevel, jobType JobType) (
- *Job, *db.Key, error) {
+func findBugsForBisection(c context.Context, managers map[string]bool,
+ reproLevel dashapi.ReproLevel, jobType JobType) (*Job, *db.Key, error) {
+ if len(managers) == 0 {
+ return nil, nil, nil
+ }
// Note: we could also include len(Commits)==0 but datastore does not work this way.
// So we would need an additional HasCommits field or something.
// Note: For JobBisectCause, order the bugs from newest to oldest. For JobBisectFix,
@@ -762,7 +765,7 @@ func jobReported(c context.Context, jobID string) error {
return db.RunInTransaction(c, tx, nil)
}
-func loadPendingJob(c context.Context, testManagers, bisectManagers map[string]bool) (*Job, *db.Key, error) {
+func loadPendingJob(c context.Context, managers map[string]dashapi.ManagerJobs) (*Job, *db.Key, error) {
var jobs []*Job
keys, err := db.NewQuery("Job").
Filter("Finished=", time.Time{}).
@@ -775,11 +778,12 @@ func loadPendingJob(c context.Context, testManagers, bisectManagers map[string]b
for i, job := range jobs {
switch job.Type {
case JobTestPatch:
- if !testManagers[job.Manager] {
+ if !managers[job.Manager].TestPatches {
continue
}
case JobBisectCause, JobBisectFix:
- if !bisectManagers[job.Manager] {
+ if job.Type == JobBisectCause && !managers[job.Manager].BisectCause ||
+ job.Type == JobBisectFix && !managers[job.Manager].BisectFix {
continue
}
// Don't retry bisection jobs too often.
diff --git a/dashboard/app/util_test.go b/dashboard/app/util_test.go
index 1d98b0e6d..c80ab6a95 100644
--- a/dashboard/app/util_test.go
+++ b/dashboard/app/util_test.go
@@ -392,10 +392,16 @@ func (client *apiClient) updateBug(extID string, status dashapi.BugStatus, dup s
}
func (client *apiClient) pollJobs(manager string) *dashapi.JobPollResp {
- resp, err := client.JobPoll(&dashapi.JobPollReq{
- PatchTestManagers: []string{manager},
- BisectManagers: []string{manager},
- })
+ req := &dashapi.JobPollReq{
+ Managers: map[string]dashapi.ManagerJobs{
+ manager: {
+ TestPatches: true,
+ BisectCause: true,
+ BisectFix: true,
+ },
+ },
+ }
+ resp, err := client.JobPoll(req)
client.expectOK(err)
return resp
}
diff --git a/dashboard/dashapi/dashapi.go b/dashboard/dashapi/dashapi.go
index 833dd099f..8b93f0ae2 100644
--- a/dashboard/dashapi/dashapi.go
+++ b/dashboard/dashapi/dashapi.go
@@ -122,8 +122,13 @@ func (dash *Dashboard) BuilderPoll(manager string) (*BuilderPollResp, error) {
// ID must match JobPollResp.ID.
type JobPollReq struct {
- PatchTestManagers []string
- BisectManagers []string
+ Managers map[string]ManagerJobs
+}
+
+type ManagerJobs struct {
+ TestPatches bool
+ BisectCause bool
+ BisectFix bool
}
type JobPollResp struct {
diff --git a/syz-ci/jobs.go b/syz-ci/jobs.go
index faa53cc25..a90d100f9 100644
--- a/syz-ci/jobs.go
+++ b/syz-ci/jobs.go
@@ -42,23 +42,17 @@ type JobProcessor struct {
}
func newJobProcessor(cfg *Config, managers []*Manager, stop, shutdownPending chan struct{}) *JobProcessor {
- jp := &JobProcessor{
+ return &JobProcessor{
cfg: cfg,
name: fmt.Sprintf("%v-job", cfg.Name),
managers: managers,
knownCommits: make(map[string]bool),
stop: stop,
shutdownPending: shutdownPending,
+ dash: dashapi.New(cfg.DashboardClient, cfg.DashboardAddr, cfg.DashboardKey),
syzkallerRepo: cfg.SyzkallerRepo,
syzkallerBranch: cfg.SyzkallerBranch,
}
- if cfg.EnableJobs {
- if cfg.DashboardAddr == "" || cfg.DashboardClient == "" {
- panic("enabled_jobs is set but no dashboard info")
- }
- jp.dash = dashapi.New(cfg.DashboardClient, cfg.DashboardAddr, cfg.DashboardKey)
- }
- return jp
}
func (jp *JobProcessor) loop() {
@@ -81,9 +75,7 @@ loop:
// Otherwise we claim a job, but can't start it for a while.
continue loop
}
- if jp.cfg.EnableJobs {
- jp.pollJobs()
- }
+ jp.pollJobs()
if time.Since(lastCommitPoll) > commitPollPeriod {
jp.pollCommits()
lastCommitPoll = time.Now()
@@ -97,7 +89,7 @@ loop:
func (jp *JobProcessor) pollCommits() {
for _, mgr := range jp.managers {
- if !mgr.mgrcfg.PollCommits {
+ if !mgr.mgrcfg.Jobs.PollCommits {
continue
}
if err := jp.pollManagerCommits(mgr); err != nil {
@@ -206,17 +198,25 @@ func (jp *JobProcessor) getCommitInfo(mgr *Manager, URL, branch string, commits
}
func (jp *JobProcessor) pollJobs() {
- var patchTestManagers, bisectManagers []string
+ poll := &dashapi.JobPollReq{
+ Managers: make(map[string]dashapi.ManagerJobs),
+ }
for _, mgr := range jp.managers {
- patchTestManagers = append(patchTestManagers, mgr.name)
- if mgr.mgrcfg.Bisect {
- bisectManagers = append(bisectManagers, mgr.name)
+ if !mgr.mgrcfg.Jobs.TestPatches &&
+ !mgr.mgrcfg.Jobs.BisectCause &&
+ !mgr.mgrcfg.Jobs.BisectFix {
+ continue
+ }
+ poll.Managers[mgr.name] = dashapi.ManagerJobs{
+ TestPatches: mgr.mgrcfg.Jobs.TestPatches,
+ BisectCause: mgr.mgrcfg.Jobs.BisectCause,
+ BisectFix: mgr.mgrcfg.Jobs.BisectFix,
}
}
- req, err := jp.dash.JobPoll(&dashapi.JobPollReq{
- PatchTestManagers: patchTestManagers,
- BisectManagers: bisectManagers,
- })
+ if len(poll.Managers) == 0 {
+ return
+ }
+ req, err := jp.dash.JobPoll(poll)
if err != nil {
jp.Errorf("failed to poll jobs: %v", err)
return
diff --git a/syz-ci/syz-ci.go b/syz-ci/syz-ci.go
index 428856696..b81de31f0 100644
--- a/syz-ci/syz-ci.go
+++ b/syz-ci/syz-ci.go
@@ -91,11 +91,9 @@ type Config struct {
// Dir with additional syscall descriptions (.txt and .const files).
SyzkallerDescriptions string `json:"syzkaller_descriptions"`
// GCS path to upload coverage reports from managers (optional).
- CoverUploadPath string `json:"cover_upload_path"`
- // Enable patch testing jobs.
- //EnableJobs bool `json:"enable_jobs"`
- BisectBinDir string `json:"bisect_bin_dir"`
- Managers []*ManagerConfig `json:"managers"`
+ CoverUploadPath string `json:"cover_upload_path"`
+ BisectBinDir string `json:"bisect_bin_dir"`
+ Managers []*ManagerConfig `json:"managers"`
}
type ManagerConfig struct {
@@ -112,21 +110,20 @@ type ManagerConfig struct {
// File with kernel cmdline values (optional).
KernelCmdline string `json:"kernel_cmdline"`
// File with sysctl values (e.g. output of sysctl -a, optional).
- KernelSysctl string `json:"kernel_sysctl"`
- //PollCommits bool `json:"poll_commits"`
- //Bisect bool `json:"bisect"`
-
- // Comma-separated list of job types to do for this manager:
- // - test-patch: test proposed fix patches
- // - bisect-cause: do cause bisection
- // - bisect-fix: do fix bisection
- // - poll-commits: poll info about fix commits
- Jobs string `json:"bisect"`
+ KernelSysctl string `json:"kernel_sysctl"`
+ Jobs ManagerJobs `json:"jobs"`
ManagerConfig json.RawMessage `json:"manager_config"`
managercfg *mgrconfig.Config
}
+type ManagerJobs struct {
+ TestPatches bool `json:"test_patches"` // enable patch testing jobs
+ PollCommits bool `json:"poll_commits"` // poll info about fix commits
+ BisectCause bool `json:"bisect_cause"` // do cause bisection
+ BisectFix bool `json:"bisect_fix"` // do fix bisection
+}
+
func main() {
flag.Parse()
log.EnableLogCaching(1000, 1<<20)
@@ -251,12 +248,6 @@ func loadConfig(filename string) (*Config, error) {
if len(cfg.Managers) == 0 {
return nil, fmt.Errorf("no managers specified")
}
- if cfg.EnableJobs && (cfg.DashboardAddr == "" || cfg.DashboardClient == "") {
- return nil, fmt.Errorf("enabled_jobs is set but no dashboard info")
- }
- if cfg.EnableJobs && cfg.BisectBinDir == "" {
- return nil, fmt.Errorf("enabled_jobs is set but no bisect_bin_dir")
- }
// Manager name must not contain dots because it is used as GCE image name prefix.
managerNameRe := regexp.MustCompile("^[a-zA-Z0-9-_]{4,64}$")
for i, mgr := range cfg.Managers {
@@ -270,9 +261,17 @@ func loadConfig(filename string) (*Config, error) {
if err != nil {
return nil, fmt.Errorf("manager %v: %v", mgr.Name, err)
}
- if mgr.PollCommits && (cfg.DashboardAddr == "" || mgr.DashboardClient == "") {
+ if (mgr.Jobs.TestPatches || mgr.Jobs.PollCommits ||
+ mgr.Jobs.BisectCause || mgr.Jobs.BisectFix) &&
+ (cfg.DashboardAddr == "" || cfg.DashboardClient == "") {
+ return nil, fmt.Errorf("manager %v: has jobs but no dashboard info", mgr.Name)
+ }
+ if mgr.Jobs.PollCommits && (cfg.DashboardAddr == "" || mgr.DashboardClient == "") {
return nil, fmt.Errorf("manager %v: commit_poll is set but no dashboard info", mgr.Name)
}
+ if (mgr.Jobs.BisectCause || mgr.Jobs.BisectFix) && cfg.BisectBinDir == "" {
+ return nil, fmt.Errorf("manager %v: enabled bisection but no bisect_bin_dir", mgr.Name)
+ }
mgr.managercfg = managercfg
managercfg.Name = cfg.Name + "-" + mgr.Name
managercfg.Syzkaller = filepath.FromSlash("syzkaller/current")