dashboard/app: send machine information to dashboard

- Change syz-manager so that it will send machine info the first time a
  crash occurs.
- Add a field in entities.Crash to store machine info.
- Add a field in dashapi.BugReport to store machine info.
- Change the HTML template and struct uiCrash to display machine info.
- Add a test to make sure that the link to machine info appears on the
  webpage.

Update #466
This commit is contained in:
Cheng-Min Chiang 2020-09-02 17:23:49 -07:00 committed by Dmitry Vyukov
parent df4f5a9c4a
commit 9eff3337ee
9 changed files with 117 additions and 53 deletions

View File

@ -810,6 +810,9 @@ func saveCrash(c context.Context, ns string, req *dashapi.Crash, bugKey *db.Key,
if crash.ReproC, err = putText(c, ns, textReproC, req.ReproC, false); err != nil {
return err
}
if crash.MachineInfo, err = putText(c, ns, textMachineInfo, req.MachineInfo, false); err != nil {
return err
}
crashKey := db.NewIncompleteKey(c, "Crash", bugKey)
if _, err = db.Put(c, crashKey, crash); err != nil {
return fmt.Errorf("failed to put crash: %v", err)

View File

@ -131,6 +131,7 @@ type Crash struct {
ReproOpts []byte `datastore:",noindex"`
ReproSyz int64 // reference to ReproSyz text entity
ReproC int64 // reference to ReproC text entity
MachineInfo int64 // Reference to MachineInfo text entity.
// Custom crash priority for reporting (greater values are higher priority).
// For example, a crash in mainline kernel has higher priority than a crash in a side branch.
// For historical reasons this is called ReportLen.
@ -232,6 +233,7 @@ const (
textCrashReport = "CrashReport"
textReproSyz = "ReproSyz"
textReproC = "ReproC"
textMachineInfo = "MachineInfo"
textKernelConfig = "KernelConfig"
textPatch = "Patch"
textLog = "Log"

View File

@ -668,21 +668,22 @@ func createBugReportForJob(c context.Context, job *Job, jobKey *db.Key, config i
}
kernelRepo := kernelRepoInfo(build)
rep := &dashapi.BugReport{
Type: typ,
Config: reportingConfig,
JobID: extJobID(jobKey),
ExtID: job.ExtID,
CC: append(job.CC, kernelRepo.CC...),
Log: crashLog,
LogLink: externalLink(c, textCrashLog, job.CrashLog),
Report: report,
ReportLink: externalLink(c, textCrashReport, job.CrashReport),
ReproCLink: externalLink(c, textReproC, crash.ReproC),
ReproSyzLink: externalLink(c, textReproSyz, crash.ReproSyz),
CrashTitle: job.CrashTitle,
Error: jobError,
ErrorLink: externalLink(c, textError, job.Error),
PatchLink: externalLink(c, textPatch, job.Patch),
Type: typ,
Config: reportingConfig,
JobID: extJobID(jobKey),
ExtID: job.ExtID,
CC: append(job.CC, kernelRepo.CC...),
Log: crashLog,
LogLink: externalLink(c, textCrashLog, job.CrashLog),
Report: report,
ReportLink: externalLink(c, textCrashReport, job.CrashReport),
ReproCLink: externalLink(c, textReproC, crash.ReproC),
ReproSyzLink: externalLink(c, textReproSyz, crash.ReproSyz),
MachineInfoLink: externalLink(c, textMachineInfo, crash.MachineInfo),
CrashTitle: job.CrashTitle,
Error: jobError,
ErrorLink: externalLink(c, textError, job.Error),
PatchLink: externalLink(c, textPatch, job.Patch),
}
if job.Type == JobBisectCause || job.Type == JobBisectFix {
rep.Maintainers = append(crash.Maintainers, kernelRepo.Maintainers...)

View File

@ -165,13 +165,14 @@ type uiBug struct {
}
type uiCrash struct {
Manager string
Time time.Time
Maintainers string
LogLink string
ReportLink string
ReproSyzLink string
ReproCLink string
Manager string
Time time.Time
Maintainers string
LogLink string
ReportLink string
ReproSyzLink string
ReproCLink string
MachineInfoLink string
*uiBuild
}
@ -917,13 +918,14 @@ func loadFixBisectionsForBug(c context.Context, bug *Bug) ([]*uiCrash, error) {
func makeUICrash(crash *Crash, build *Build) *uiCrash {
ui := &uiCrash{
Manager: crash.Manager,
Time: crash.Time,
Maintainers: strings.Join(crash.Maintainers, ", "),
LogLink: textLink(textCrashLog, crash.Log),
ReportLink: textLink(textCrashReport, crash.Report),
ReproSyzLink: textLink(textReproSyz, crash.ReproSyz),
ReproCLink: textLink(textReproC, crash.ReproC),
Manager: crash.Manager,
Time: crash.Time,
Maintainers: strings.Join(crash.Maintainers, ", "),
LogLink: textLink(textCrashLog, crash.Log),
ReportLink: textLink(textCrashReport, crash.Report),
ReproSyzLink: textLink(textReproSyz, crash.ReproSyz),
ReproCLink: textLink(textReproC, crash.ReproC),
MachineInfoLink: textLink(textMachineInfo, crash.MachineInfo),
}
if build != nil {
ui.uiBuild = makeUIBuild(build)

View File

@ -391,6 +391,10 @@ func createBugReport(c context.Context, bug *Bug, crash *Crash, crashKey *db.Key
if err != nil {
return nil, err
}
machineInfo, _, err := getText(c, textMachineInfo, crash.MachineInfo)
if err != nil {
return nil, err
}
if len(reproSyz) != 0 {
buf := new(bytes.Buffer)
buf.WriteString(syzReproPrefix)
@ -411,24 +415,26 @@ func createBugReport(c context.Context, bug *Bug, crash *Crash, crashKey *db.Key
kernelRepo := kernelRepoInfo(build)
rep := &dashapi.BugReport{
Type: typ,
Config: reportingConfig,
ExtID: bugReporting.ExtID,
First: bugReporting.Reported.IsZero(),
Moderation: reporting.moderation,
Log: crashLog,
LogLink: externalLink(c, textCrashLog, crash.Log),
Report: report,
ReportLink: externalLink(c, textCrashReport, crash.Report),
CC: kernelRepo.CC,
Maintainers: append(crash.Maintainers, kernelRepo.Maintainers...),
ReproC: reproC,
ReproCLink: externalLink(c, textReproC, crash.ReproC),
ReproSyz: reproSyz,
ReproSyzLink: externalLink(c, textReproSyz, crash.ReproSyz),
CrashID: crashKey.IntID(),
NumCrashes: bug.NumCrashes,
HappenedOn: managersToRepos(c, bug.Namespace, bug.HappenedOn),
Type: typ,
Config: reportingConfig,
ExtID: bugReporting.ExtID,
First: bugReporting.Reported.IsZero(),
Moderation: reporting.moderation,
Log: crashLog,
LogLink: externalLink(c, textCrashLog, crash.Log),
Report: report,
ReportLink: externalLink(c, textCrashReport, crash.Report),
CC: kernelRepo.CC,
Maintainers: append(crash.Maintainers, kernelRepo.Maintainers...),
ReproC: reproC,
ReproCLink: externalLink(c, textReproC, crash.ReproC),
ReproSyz: reproSyz,
ReproSyzLink: externalLink(c, textReproSyz, crash.ReproSyz),
MachineInfo: machineInfo,
MachineInfoLink: externalLink(c, textMachineInfo, crash.MachineInfo),
CrashID: crashKey.IntID(),
NumCrashes: bug.NumCrashes,
HappenedOn: managersToRepos(c, bug.Namespace, bug.HappenedOn),
}
if bugReporting.CC != "" {
rep.CC = append(rep.CC, strings.Split(bugReporting.CC, "|")...)

View File

@ -5,6 +5,7 @@ package main
import (
"fmt"
"regexp"
"testing"
"time"
@ -460,3 +461,47 @@ func TestReportingFilter(t *testing.T) {
rep4 := c.client.pollBug()
c.expectEQ(string(rep4.Config), `{"Index":2}`)
}
func TestMachineInfo(t *testing.T) {
c := NewCtx(t)
defer c.Close()
build := testBuild(1)
c.client.UploadBuild(build)
machineInfo := []byte("info1")
// Create a crash with machine information and check the returned machine
// information field is equal.
crash := &dashapi.Crash{
BuildID: "build1",
Title: "title1",
Maintainers: []string{`"Foo Bar" <foo@bar.com>`, `bar@foo.com`},
Log: []byte("log1"),
Report: []byte("report1"),
MachineInfo: machineInfo,
}
c.client.ReportCrash(crash)
rep := c.client.pollBug()
c.expectEQ(machineInfo, rep.MachineInfo)
// Check that a link to machine information page is created on the dashboard,
// and the content is correct.
indexPage, err := c.AuthGET(AccessAdmin, "/test1")
c.expectOK(err)
bugLinkRegex := regexp.MustCompile(`<a href="(/bug\?id=[^"]+)">title1</a>`)
bugLinkSubmatch := bugLinkRegex.FindSubmatch(indexPage)
c.expectEQ(len(bugLinkSubmatch), 2)
bugURL := string(bugLinkSubmatch[1])
bugPage, err := c.AuthGET(AccessAdmin, bugURL)
c.expectOK(err)
infoLinkRegex := regexp.MustCompile(`<a href="(/text\?tag=MachineInfo[^"]+)">machine info</a>`)
infoLinkSubmatch := infoLinkRegex.FindSubmatch(bugPage)
c.expectEQ(len(infoLinkSubmatch), 2)
infoURL := string(infoLinkSubmatch[1])
receivedInfo, err := c.AuthGET(AccessAdmin, infoURL)
c.expectOK(err)
c.expectEQ(receivedInfo, machineInfo)
}

View File

@ -342,6 +342,7 @@ Use of this source code is governed by Apache 2 LICENSE that can be found in the
<td class="repro">{{if $b.ReportLink}}<a href="{{$b.ReportLink}}">report</a>{{end}}</td>
<td class="repro">{{if $b.ReproSyzLink}}<a href="{{$b.ReproSyzLink}}">syz</a>{{end}}</td>
<td class="repro">{{if $b.ReproCLink}}<a href="{{$b.ReproCLink}}">C</a>{{end}}</td>
<td class="repro">{{if $b.MachineInfoLink}}<a href="{{$b.MachineInfoLink}}">machine info</a>{{end}}</td>
{{if $.HasMaintainers}}
<td class="maintainers" title="{{$b.Maintainers}}">{{$b.Maintainers}}</td>
{{end}}

View File

@ -241,6 +241,7 @@ type Crash struct {
Recipients Recipients
Log []byte
Report []byte
MachineInfo []byte
// The following is optional and is filled only after repro.
ReproOpts []byte
ReproSyz []byte
@ -333,6 +334,8 @@ type BugReport struct {
ReproCLink string
ReproSyz []byte
ReproSyzLink string
MachineInfo []byte
MachineInfoLink string
CrashID int64 // returned back in BugUpdate
NumCrashes int64
HappenedOn []string // list of kernel repo aliases

View File

@ -695,12 +695,13 @@ func (mgr *Manager) saveCrash(crash *Crash) bool {
return true
}
dc := &dashapi.Crash{
BuildID: mgr.cfg.Tag,
Title: crash.Title,
Corrupted: crash.Corrupted,
Recipients: crash.Recipients.ToDash(),
Log: crash.Output,
Report: crash.Report.Report,
BuildID: mgr.cfg.Tag,
Title: crash.Title,
Corrupted: crash.Corrupted,
Recipients: crash.Recipients.ToDash(),
Log: crash.Output,
Report: crash.Report.Report,
MachineInfo: crash.machineInfo,
}
resp, err := mgr.dash.ReportCrash(dc)
if err != nil {