Skip to content

Commit

Permalink
Remove support for displaying build event streams
Browse files Browse the repository at this point in the history
The bb-event-service was deprecated some time ago. There is therefore no
longer any need to keep this code in bb-browser. Folks in the community
are invited to develop their own solutions for displaying this data. It
doesn't need to be part of the Buildbarn umbrella.

Fixes: buildbarn#21
  • Loading branch information
EdSchouten committed Apr 2, 2020
1 parent ef0e6e7 commit 59d39de
Show file tree
Hide file tree
Showing 12 changed files with 0 additions and 2,079 deletions.
10 changes: 0 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,6 @@ use of Buildbarn Browser:
Buildbarn Browser is capable of displaying these action results in
additition to cached ones stored in the AC.

- **Storing Build Event Streams.**

Bazel has the ability to log build execution progress and output
through [the Build Event Protocol](https://docs.bazel.build/versions/master/build-event-protocol.html).
Logs can either be written to disk or be transmitted to a gRPC
service. [The Buildbarn Event Service](https://github.com/buildbarn/bb-event-service)
is a gRPC service that writes these logs directly into the CAS. Upon
completion, an AC entry is created to permit lookups of streams by
Bazel invocation ID.

We invite other implementations of the Remote Execution API to implement
such features as well. At the time of writing, the developers of
[BuildGrid](https://gitlab.com/BuildGrid) are also working on adding
Expand Down
7 changes: 0 additions & 7 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,6 @@ http_archive(
],
)

http_archive(
name = "com_github_bazelbuild_bazel",
patches = ["//:patches/com_github_bazelbuild_bazel/build_event_stream.diff"],
sha256 = "3371cd9050989173a3b27364668328653a65653a50a85c320adc53953b4d5f46",
urls = ["https://github.com/bazelbuild/bazel/releases/download/2.1.0/bazel-2.1.0-dist.zip"],
)

http_archive(
name = "com_github_twbs_bootstrap",
build_file_content = """exports_files(["css/bootstrap.min.css", "js/bootstrap.min.js"])""",
Expand Down
3 changes: 0 additions & 3 deletions cmd/bb_browser/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ go_library(
visibility = ["//visibility:private"],
deps = [
"//cmd/bb_browser/assets:go_default_library",
"//pkg/buildevents:go_default_library",
"//pkg/proto/configuration/bb_browser:go_default_library",
"@com_github_bazelbuild_bazel//src/main/java/com/google/devtools/build/lib/buildeventstream/proto:go_default_library",
"@com_github_bazelbuild_remote_apis//build/bazel/remote/execution/v2:go_default_library",
"@com_github_buildbarn_bb_remote_execution//pkg/proto/resourceusage:go_default_library",
"@com_github_buildbarn_bb_storage//pkg/blobstore:go_default_library",
Expand All @@ -31,7 +29,6 @@ go_library(
"@com_github_gorilla_mux//:go_default_library",
"@com_github_grpc_ecosystem_go_grpc_middleware//util/metautils:go_default_library",
"@com_github_kballard_go_shellquote//:go_default_library",
"@com_github_matttproud_golang_protobuf_extensions//pbutil:go_default_library",
"@io_bazel_rules_go//proto/wkt:any_go_proto",
"@io_bazel_rules_go//proto/wkt:duration_go_proto",
"@io_bazel_rules_go//proto/wkt:timestamp_go_proto",
Expand Down
136 changes: 0 additions & 136 deletions cmd/bb_browser/browser_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,25 @@ import (
"archive/tar"
"compress/gzip"
"context"
"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
"html/template"
"io"
"log"
"net/http"
"net/url"
"path"
"strconv"
"strings"
"unicode/utf8"

buildeventstream "github.com/bazelbuild/bazel/src/main/java/com/google/devtools/build/lib/buildeventstream/proto"
remoteexecution "github.com/bazelbuild/remote-apis/build/bazel/remote/execution/v2"
"github.com/buildbarn/bb-browser/pkg/buildevents"
"github.com/buildbarn/bb-storage/pkg/blobstore"
"github.com/buildbarn/bb-storage/pkg/cas"
"github.com/buildbarn/bb-storage/pkg/digest"
"github.com/buildkite/terminal"
"github.com/golang/protobuf/proto"
"github.com/gorilla/mux"
"github.com/grpc-ecosystem/go-grpc-middleware/util/metautils"
"github.com/matttproud/golang_protobuf_extensions/pbutil"

"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
Expand Down Expand Up @@ -78,7 +72,6 @@ func NewBrowserService(contentAddressableStorage cas.ContentAddressableStorage,
}
router.HandleFunc("/", s.handleWelcome)
router.HandleFunc("/action/{instance}/{hash}/{sizeBytes}/", s.handleAction)
router.HandleFunc("/build_events/{instance}/{invocationID}", s.handleBuildEvents)
router.HandleFunc("/command/{instance}/{hash}/{sizeBytes}/", s.handleCommand)
router.HandleFunc("/directory/{instance}/{hash}/{sizeBytes}/", s.handleDirectory)
router.HandleFunc("/file/{instance}/{hash}/{sizeBytes}/{name}", s.handleFile)
Expand Down Expand Up @@ -125,97 +118,6 @@ func (s *BrowserService) handleAction(w http.ResponseWriter, req *http.Request)
})
}

func (s *BrowserService) readBuildEventStream(ctx context.Context, parser *buildevents.StreamParser, digest digest.Digest) error {
r := s.contentAddressableStorageBlobAccess.Get(ctx, digest).ToReader()
defer r.Close()

for {
var event buildeventstream.BuildEvent
if _, err := pbutil.ReadDelimited(r, &event); err == io.EOF {
return nil
} else if err != nil {
return err
}
if err := parser.AddBuildEvent(&event); err != nil {
return err
}
}
}

func (s *BrowserService) handleBuildEvents(w http.ResponseWriter, req *http.Request) {
// Convert the invocation ID in the URL to a digest by hashing
// it, so that a fictive Action Cache entry can be accessed.
vars := mux.Vars(req)
hash := sha256.Sum256([]byte(vars["invocationID"]))
digest, err := digest.NewDigest(vars["instance"], hex.EncodeToString(hash[:]), 0)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

// Look up the invocation ID in the Action Cache. The output
// files of this entry correspond to one or more blobs in the
// CAS that, when concatenated, represents a Build Event Stream.
ctx := extractContextFromRequest(req)
actionResult, err := s.actionCache.Get(ctx, digest).ToActionResult(s.maximumMessageSizeBytes)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
parser := buildevents.NewStreamParser()
for _, file := range actionResult.OutputFiles {
fileDigest, err := digest.NewDerivedDigest(file.Digest)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if err := s.readBuildEventStream(ctx, parser, fileDigest); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
}
started, eventsExpected, err := parser.Finalize()
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

// Convert stdout and stderr stored in ActionCompletedNodes to a
// format usable by the templates.
logsForActionsCompleted := map[*buildevents.ActionCompletedNode][]*logInfo{}
if started != nil {
for progress := started.Progress; progress != nil; progress = progress.Progress {
for _, actionCompleted := range progress.ActionsCompleted {
if stdout, err := s.getLogInfoFromActionCompleted(ctx, "Standard output", actionCompleted.Payload.Stdout); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
} else if stdout != nil {
logsForActionsCompleted[actionCompleted] = append(logsForActionsCompleted[actionCompleted], stdout)
}

if stderr, err := s.getLogInfoFromActionCompleted(ctx, "Standard error", actionCompleted.Payload.Stderr); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
} else if stderr != nil {
logsForActionsCompleted[actionCompleted] = append(logsForActionsCompleted[actionCompleted], stderr)
}
}
}
}

if err := s.templates.ExecuteTemplate(w, "page_build_events.html", struct {
Started *buildevents.StartedNode
EventsExpected int
LogsForActionsCompleted map[*buildevents.ActionCompletedNode][]*logInfo
}{
Started: started,
EventsExpected: eventsExpected,
LogsForActionsCompleted: logsForActionsCompleted,
}); err != nil {
log.Print(err)
}
}

func (s *BrowserService) handleUncachedActionResult(w http.ResponseWriter, req *http.Request) {
digest, err := getDigestFromRequest(req)
if err != nil {
Expand Down Expand Up @@ -260,44 +162,6 @@ func (s *BrowserService) getLogInfoFromActionResult(ctx context.Context, name st
return nil, nil
}

func (s *BrowserService) getLogInfoFromActionCompleted(ctx context.Context, name string, file *buildeventstream.File) (*logInfo, error) {
if file == nil {
return nil, nil
}
switch data := file.File.(type) {
case *buildeventstream.File_Uri:
// A pathname or URL is provided. Load the log from the
// Content Addressable Storage if it's in the form of a
// bytestream:// URL.
u, err := url.Parse(data.Uri)
if err != nil || u.Scheme != "bytestream" {
return &logInfo{
Name: name,
NotFound: true,
}, nil
}
digest, err := digest.NewDigestFromBytestreamPath(u.Path)
if err != nil {
return &logInfo{
Name: name,
NotFound: true,
}, nil
}
return s.getLogInfoForDigest(ctx, name, digest)
case *buildeventstream.File_Contents:
// Log body is small enough to be provided inline.
return &logInfo{
Name: name,
HTML: template.HTML(data.Contents),
}, nil
default:
return &logInfo{
Name: name,
NotFound: true,
}, nil
}
}

func (s *BrowserService) getLogInfoForDigest(ctx context.Context, name string, digest digest.Digest) (*logInfo, error) {
maximumLogSizeBytes := 100000
if size := digest.GetSizeBytes(); size == 0 {
Expand Down
25 changes: 0 additions & 25 deletions cmd/bb_browser/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,14 @@ import (
"html/template"
"log"
"net/http"
"net/url"
"os"
"path"
"time"

buildeventstream "github.com/bazelbuild/bazel/src/main/java/com/google/devtools/build/lib/buildeventstream/proto"
"github.com/buildbarn/bb-browser/pkg/proto/configuration/bb_browser"
"github.com/buildbarn/bb-remote-execution/pkg/proto/resourceusage"
blobstore_configuration "github.com/buildbarn/bb-storage/pkg/blobstore/configuration"
"github.com/buildbarn/bb-storage/pkg/cas"
"github.com/buildbarn/bb-storage/pkg/digest"
"github.com/buildbarn/bb-storage/pkg/global"
"github.com/buildbarn/bb-storage/pkg/util"
"github.com/dustin/go-humanize"
Expand Down Expand Up @@ -64,23 +61,6 @@ func main() {
templates, err := template.New("templates").Funcs(template.FuncMap{
"asset_path": GetAssetPath,
"basename": path.Base,
"build_event_file_to_digest": func(in *buildeventstream.File) *digest.Digest {
// Converts URLs of this format to digest objects:
// bytestream://host/instance/blobs/hash/size
fileURI, ok := in.File.(*buildeventstream.File_Uri)
if !ok {
return nil
}
u, err := url.Parse(fileURI.Uri)
if err != nil || u.Scheme != "bytestream" {
return nil
}
digest, err := digest.NewDigestFromBytestreamPath(u.Path)
if err != nil {
return nil
}
return &digest
},
"duration_proto": func(pb *duration.Duration) *time.Duration {
// Converts a Protobuf duration to Go's native type.
d, err := ptypes.Duration(pb)
Expand Down Expand Up @@ -121,11 +101,6 @@ func main() {
// Converts a timestamp to RFC3339 format.
return t.Format(rfc3339Milli)
},
"timestamp_millis_rfc3339": func(in int64) string {
// Converts a time in milliseconds since the
// Epoch to RFC3339 format.
return time.Unix(in/1000, in%1000*1000000).Format(rfc3339Milli)
},
"timestamp_proto_delta": func(pbPrevious *timestamp.Timestamp, pbNow *timestamp.Timestamp) *timestampDelta {
tNow, err := ptypes.Timestamp(pbNow)
if err != nil {
Expand Down
Loading

0 comments on commit 59d39de

Please sign in to comment.