github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/syz-cluster/pkg/service/build.go (about)

     1  // Copyright 2025 syzkaller project authors. All rights reserved.
     2  // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
     3  
     4  package service
     5  
     6  import (
     7  	"bytes"
     8  	"context"
     9  	"fmt"
    10  	"github.com/google/syzkaller/syz-cluster/pkg/api"
    11  	"github.com/google/syzkaller/syz-cluster/pkg/app"
    12  	"github.com/google/syzkaller/syz-cluster/pkg/blob"
    13  	"github.com/google/syzkaller/syz-cluster/pkg/db"
    14  	"github.com/google/uuid"
    15  )
    16  
    17  type BuildService struct {
    18  	buildRepo   *db.BuildRepository
    19  	blobStorage blob.Storage
    20  }
    21  
    22  func NewBuildService(env *app.AppEnvironment) *BuildService {
    23  	return &BuildService{
    24  		buildRepo:   db.NewBuildRepository(env.Spanner),
    25  		blobStorage: env.BlobStorage,
    26  	}
    27  }
    28  
    29  func (s *BuildService) Upload(ctx context.Context, req *api.UploadBuildReq) (*api.UploadBuildResp, error) {
    30  	build := &db.Build{
    31  		ID:         uuid.NewString(),
    32  		Arch:       req.Arch,
    33  		ConfigName: req.ConfigName,
    34  		TreeName:   req.TreeName,
    35  		TreeURL:    req.TreeURL,
    36  		CommitHash: req.CommitHash,
    37  		CommitDate: req.CommitDate,
    38  		Compiler:   req.Compiler,
    39  	}
    40  	if req.SeriesID != "" {
    41  		build.SetSeriesID(req.SeriesID)
    42  	}
    43  	if req.BuildSuccess {
    44  		build.Status = db.BuildSuccess
    45  	} else {
    46  		build.Status = db.BuildFailed
    47  	}
    48  	if len(req.Log) > 0 {
    49  		var err error
    50  		build.LogURI, err = s.blobStorage.Write(bytes.NewReader(req.Log), "Build", build.ID, "log")
    51  		if err != nil {
    52  			return nil, fmt.Errorf("failed to write log: %w", err)
    53  		}
    54  	}
    55  	if len(req.Config) > 0 {
    56  		var err error
    57  		build.ConfigURI, err = s.blobStorage.Write(bytes.NewReader(req.Config), "Build", build.ID, "config")
    58  		if err != nil {
    59  			return nil, fmt.Errorf("failed to write kernel config: %w", err)
    60  		}
    61  	}
    62  	err := s.buildRepo.Insert(ctx, build)
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  	return &api.UploadBuildResp{
    67  		ID: build.ID,
    68  	}, nil
    69  }
    70  
    71  func (s *BuildService) LastBuild(ctx context.Context, req *api.LastBuildReq) (*api.Build, error) {
    72  	build, err := s.buildRepo.LastBuiltTree(ctx, &db.LastBuildParams{
    73  		Arch:       req.Arch,
    74  		TreeName:   req.TreeName,
    75  		ConfigName: req.ConfigName,
    76  		Commit:     req.Commit,
    77  		Status:     req.Status,
    78  	})
    79  	if build == nil || err != nil {
    80  		return nil, err
    81  	}
    82  	resp := &api.Build{
    83  		Arch:         build.Arch,
    84  		TreeName:     build.TreeName,
    85  		TreeURL:      build.TreeURL,
    86  		ConfigName:   build.ConfigName,
    87  		CommitHash:   build.CommitHash,
    88  		CommitDate:   build.CommitDate,
    89  		BuildSuccess: build.Status == db.BuildSuccess,
    90  	}
    91  	if !build.SeriesID.IsNull() {
    92  		resp.SeriesID = build.SeriesID.String()
    93  	}
    94  	return resp, nil
    95  }
    96  
    97  func makeBuildInfo(url *api.URLGenerator, build *db.Build) api.BuildInfo {
    98  	return api.BuildInfo{
    99  		TreeName:   build.TreeName,
   100  		TreeURL:    build.TreeURL,
   101  		BaseCommit: build.CommitHash,
   102  		Arch:       build.Arch,
   103  		Compiler:   build.Compiler,
   104  		ConfigLink: url.BuildConfig(build.ID),
   105  	}
   106  }