diff options
| -rw-r--r-- | syz-cluster/dashboard/templates/series.html | 6 | ||||
| -rw-r--r-- | syz-cluster/pkg/api/api.go | 8 | ||||
| -rw-r--r-- | syz-cluster/pkg/api/client.go | 9 | ||||
| -rw-r--r-- | syz-cluster/pkg/controller/api.go | 8 | ||||
| -rw-r--r-- | syz-cluster/pkg/service/session.go | 10 | ||||
| -rw-r--r-- | syz-cluster/pkg/workflow/template.yaml | 2 | ||||
| -rw-r--r-- | syz-cluster/workflow/triage-step/main.go | 38 |
7 files changed, 41 insertions, 40 deletions
diff --git a/syz-cluster/dashboard/templates/series.html b/syz-cluster/dashboard/templates/series.html index 35961d1ba..31eaebc8f 100644 --- a/syz-cluster/dashboard/templates/series.html +++ b/syz-cluster/dashboard/templates/series.html @@ -96,11 +96,11 @@ <th>Status</th> <td>{{.Status}}</td> </tr> - {{if not .SkipReason.IsNull}} + {{if or (not .SkipReason.IsNull) .TriageLogURI}} <tr> - <th>Skipped</th> + <th>Triaged</th> <td> - {{.SkipReason.StringVal}} + {{if not .SkipReason.IsNull}}Skipped: {{.SkipReason.StringVal}}{{else}}OK{{end}} {{if .TriageLogURI}} <a href="/sessions/{{.ID}}/triage_log">[Log]</a> {{end}} diff --git a/syz-cluster/pkg/api/api.go b/syz-cluster/pkg/api/api.go index 33d83684e..481554a50 100644 --- a/syz-cluster/pkg/api/api.go +++ b/syz-cluster/pkg/api/api.go @@ -5,18 +5,14 @@ package api import "time" +// The output passed to other workflow steps. type TriageResult struct { // If set, ignore the patch series completely. - Skip *SkipRequest `json:"skip"` + SkipReason string `json:"skip_reason"` // Fuzzing configuration to try (NULL if nothing). Fuzz *FuzzConfig `json:"fuzz"` } -type SkipRequest struct { - Reason string `json:"reason"` - TriageLog []byte `json:"log"` -} - // The data layout faclitates the simplicity of the workflow definition. type FuzzConfig struct { Base BuildRequest `json:"base"` diff --git a/syz-cluster/pkg/api/client.go b/syz-cluster/pkg/api/client.go index 787748e51..43da4b512 100644 --- a/syz-cluster/pkg/api/client.go +++ b/syz-cluster/pkg/api/client.go @@ -30,8 +30,13 @@ func (client Client) GetSeries(ctx context.Context, seriesID string) (*Series, e return getJSON[Series](ctx, client.baseURL+"/series/"+seriesID) } -func (client Client) SkipSession(ctx context.Context, sessionID string, req *SkipRequest) error { - _, err := postJSON[SkipRequest, any](ctx, client.baseURL+"/sessions/"+sessionID+"/skip", req) +type UploadTriageResultReq struct { + SkipReason string `json:"skip_reason"` + Log []byte `json:"log"` +} + +func (client Client) UploadTriageResult(ctx context.Context, sessionID string, req *UploadTriageResultReq) error { + _, err := postJSON[UploadTriageResultReq, any](ctx, client.baseURL+"/sessions/"+sessionID+"/triage_result", req) return err } diff --git a/syz-cluster/pkg/controller/api.go b/syz-cluster/pkg/controller/api.go index 6dbdc4889..a20860d6f 100644 --- a/syz-cluster/pkg/controller/api.go +++ b/syz-cluster/pkg/controller/api.go @@ -42,7 +42,7 @@ func (c APIServer) Mux() *http.ServeMux { mux.HandleFunc("/series/{series_id}", c.getSeries) mux.HandleFunc("/sessions/upload", c.uploadSession) mux.HandleFunc("/sessions/{session_id}/series", c.getSessionSeries) - mux.HandleFunc("/sessions/{session_id}/skip", c.skipSession) + mux.HandleFunc("/sessions/{session_id}/triage_result", c.triageResult) mux.HandleFunc("/tests/upload_artifacts", c.uploadTestArtifact) mux.HandleFunc("/tests/upload", c.uploadTest) mux.HandleFunc("/trees", c.getTrees) @@ -61,12 +61,12 @@ func (c APIServer) getSessionSeries(w http.ResponseWriter, r *http.Request) { api.ReplyJSON(w, resp) } -func (c APIServer) skipSession(w http.ResponseWriter, r *http.Request) { - req := api.ParseJSON[api.SkipRequest](w, r) +func (c APIServer) triageResult(w http.ResponseWriter, r *http.Request) { + req := api.ParseJSON[api.UploadTriageResultReq](w, r) if req == nil { return } - err := c.sessionService.SkipSession(r.Context(), r.PathValue("session_id"), req) + err := c.sessionService.TriageResult(r.Context(), r.PathValue("session_id"), req) if errors.Is(err, service.ErrSessionNotFound) { http.Error(w, fmt.Sprint(err), http.StatusNotFound) return diff --git a/syz-cluster/pkg/service/session.go b/syz-cluster/pkg/service/session.go index 446b431f4..62f959699 100644 --- a/syz-cluster/pkg/service/session.go +++ b/syz-cluster/pkg/service/session.go @@ -32,18 +32,20 @@ func NewSessionService(env *app.AppEnvironment) *SessionService { var ErrSessionNotFound = errors.New("session not found") -func (s *SessionService) SkipSession(ctx context.Context, sessionID string, skip *api.SkipRequest) error { +func (s *SessionService) TriageResult(ctx context.Context, sessionID string, req *api.UploadTriageResultReq) error { var triageLogURI string - if len(skip.TriageLog) > 0 { + if len(req.Log) > 0 { var err error - triageLogURI, err = s.blobStorage.Write(bytes.NewReader(skip.TriageLog), "Session", sessionID, "triage_log") + triageLogURI, err = s.blobStorage.Write(bytes.NewReader(req.Log), "Session", sessionID, "triage_log") if err != nil { return fmt.Errorf("failed to save the triage log: %w", err) } } err := s.sessionRepo.Update(ctx, sessionID, func(session *db.Session) error { session.TriageLogURI = triageLogURI - session.SetSkipReason(skip.Reason) + if req.SkipReason != "" { + session.SetSkipReason(req.SkipReason) + } return nil }) if errors.Is(err, db.ErrEntityNotFound) { diff --git a/syz-cluster/pkg/workflow/template.yaml b/syz-cluster/pkg/workflow/template.yaml index 53752787e..d9107799c 100644 --- a/syz-cluster/pkg/workflow/template.yaml +++ b/syz-cluster/pkg/workflow/template.yaml @@ -38,7 +38,7 @@ spec: template: triage-step - - name: abort-on-skip-outcome template: exit-workflow - when: "{{=jsonpath(steps['run-triage'].outputs.parameters.result, '$.skip') != nil}}" + when: "{{=jsonpath(steps['run-triage'].outputs.parameters.result, '$.skip_reason') != ''}}" - - name: run-process-fuzz template: process-fuzz arguments: diff --git a/syz-cluster/workflow/triage-step/main.go b/syz-cluster/workflow/triage-step/main.go index b412947a2..9fa7a50bd 100644 --- a/syz-cluster/workflow/triage-step/main.go +++ b/syz-cluster/workflow/triage-step/main.go @@ -8,13 +8,12 @@ import ( "context" "flag" "fmt" + "github.com/google/syzkaller/pkg/debugtracer" "github.com/google/syzkaller/pkg/osutil" "github.com/google/syzkaller/syz-cluster/pkg/api" "github.com/google/syzkaller/syz-cluster/pkg/app" "github.com/google/syzkaller/syz-cluster/pkg/triage" - "io" - "os" ) var ( @@ -35,15 +34,18 @@ func main() { app.Fatalf("failed to initialize the repository: %v", err) } ctx := context.Background() - verdict, err := getVerdict(ctx, client, repo) + output := new(bytes.Buffer) + tracer := &debugtracer.GenericTracer{WithTime: true, TraceWriter: output} + verdict, err := getVerdict(ctx, tracer, client, repo) if err != nil { app.Fatalf("failed to get the verdict: %v", err) } - if verdict.Skip != nil { - err := client.SkipSession(context.Background(), *flagSession, verdict.Skip) - if err != nil { - app.Fatalf("failed to upload the skip reason: %v", err) - } + err = client.UploadTriageResult(ctx, *flagSession, &api.UploadTriageResultReq{ + SkipReason: verdict.SkipReason, + Log: output.Bytes(), + }) + if err != nil { + app.Fatalf("failed to upload triage results: %v", err) } if *flagVerdict != "" { osutil.WriteJSON(*flagVerdict, verdict) @@ -54,7 +56,8 @@ func main() { // 2. What if controller does not reply? Let Argo just restart the step. } -func getVerdict(ctx context.Context, client *api.Client, ops triage.TreeOps) (*api.TriageResult, error) { +func getVerdict(ctx context.Context, tracer debugtracer.DebugTracer, client *api.Client, + ops triage.TreeOps) (*api.TriageResult, error) { series, err := client.GetSessionSeries(ctx, *flagSession) if err != nil { // TODO: the workflow step must be retried. @@ -67,11 +70,10 @@ func getVerdict(ctx context.Context, client *api.Client, ops triage.TreeOps) (*a tree := triage.SelectTree(series, trees.Trees) if tree == nil { return &api.TriageResult{ - Skip: &api.SkipRequest{ - Reason: "no suitable base kernel tree found", - }, + SkipReason: "no suitable base kernel tree found", }, nil } + tracer.Log("selected tree %q", tree.Name) arch := "amd64" lastBuild, err := client.LastBuild(ctx, &api.LastBuildReq{ Arch: arch, @@ -83,22 +85,18 @@ func getVerdict(ctx context.Context, client *api.Client, ops triage.TreeOps) (*a // TODO: the workflow step must be retried. return nil, fmt.Errorf("failed to query the last build: %w", err) } - var buf bytes.Buffer - selector := triage.NewCommitSelector(ops, &debugtracer.GenericTracer{ - TraceWriter: io.MultiWriter(os.Stderr, &buf), - }) + tracer.Log("last build: %q", lastBuild) + selector := triage.NewCommitSelector(ops, tracer) result, err := selector.Select(series, tree, lastBuild) if err != nil { // TODO: the workflow step must be retried. return nil, fmt.Errorf("failed to run the commit selector: %w", err) } else if result.Commit == "" { return &api.TriageResult{ - Skip: &api.SkipRequest{ - Reason: "failed to find the base commit: " + result.Reason, - TriageLog: buf.Bytes(), - }, + SkipReason: "failed to find the base commit: " + result.Reason, }, nil } + tracer.Log("selected base commit: %s", result.Commit) base := api.BuildRequest{ TreeName: tree.Name, TreeURL: tree.URL, |
