Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Bazel Build Event Stream support #811

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

aherrmann
Copy link
Contributor

@aherrmann aherrmann commented Nov 15, 2024

This PR adds support to connect Buck2 to a Bazel Build Event Stream server as found among some Bazel remote build execution platforms. It repurposes the existing RemoteEventSink used to connect to Scribe within Meta's internal Buck2 version and connects it to a Bazel Build Event Service over gRPC instead, and it adds a translation layer between Buck2 build events and Bazel build events.

This is a work in progress, only very few build events are translated so far. To test this code you can

  • build Buck2,
  • change into the examples/hello_world directory,
  • configure a BES service by setting the BES_URI environment-variable, and
  • start a build.
$ cargo build --bin=buck2
$ cd examples/hello_world
$ BES_URI=XYZ ../../target/debug/buck2 build :main

For example, with BuildBuddy, if you run bazel run server -- -app.log_level debug locally, set BES_URI=http://localhost:1985.

The Buck2 Trace-ID is used as the BES invocation ID and you can see a Buck2 build on the UI under e.g. http://localhost:8080/invocation/e3123cfa-c350-432b-9784-8b3fe48bed14.

  • BuckEvent: provide a Buck Event Publisher proto
  • Add buck2_event_publisher_proto to Cargo.toml
  • Add Bazel Build Event Protocol/Stream protobuf
  • Implement RemoteEventSink to publish to Bazel BES

sluongng and others added 4 commits November 1, 2024 10:51
Provide a BuckEvent Publisher service which emits BuckEvents to an
external server implementation.

Closes facebook#226
Repurposes the RemoteEventSink used to connect to Scribe within Meta internal Buck2 and connects
it to a Bazel Build Event Service over gRPC instead. Adds a translation layer between Buck2
build events and Bazel build events.
@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Nov 15, 2024
@nlopezgi
Copy link

Hi @aherrmann , thanks for putting this together, we are really looking forward to it. I tested it out and had a couple of questions:

  • I see the TLS bit is marked on a TODO as not enabled yet, are you planning on setting this up as part of this CL or a future one?
  • Is there any way that I can get some verbose logs from the service publishing BuildEvents? I did not find a way to see anything from this interaction.

Thanks again!

@aherrmann
Copy link
Contributor Author

I see the TLS bit is marked on a TODO as not enabled yet, are you planning on setting this up as part of this CL or a future one?

It's needed for the target use-case. So, I'm planning to add support for it.

Is there any way that I can get some verbose logs from the service publishing BuildEvents? I did not find a way to see anything from this interaction.

The BES client runs as a thread in the Buck2 daemon. Currently, there is just a bit of printf-debugging in the code. Buck2 has some logging facilities, see --verbose flag and BUCK_LOG env-var. However, this PR so far doesn't make explicit use of these.

@nlopezgi
Copy link

Thanks again for your help @aherrmann.
I've been continuing testing this code, I was able to hack together setting TLS certs so that my BES service would connect properly. I've made some progress and was able to see the sysout messages from your code producing the events and sending them to the BES service.
I am still, however, not able to have my BES service process the events successfully. One thing I noticed is that you are not sending any PublishLifecycleEvent calls, and you are setting the check_preceding_lifecycle_events_present on the PublishBuildToolEventStreamRequest. Do you have plans to add the PublishLifecycleEvent calls? Iiuc these are needed for the proper lifecycle of a build's interaction with a BES service. It also seems our implementation of the BES service needs them to happen to properly handle the PublishBuildToolEventStream calls.
Thanks!

@aherrmann
Copy link
Contributor Author

aherrmann commented Nov 21, 2024

Do you have plans to add the PublishLifecycleEvent calls?

I'm currently testing and developing against BuildBuddy. To my understanding so far, that implementation seems to largely ignore lifecycle events, at least I haven't spotted a need for them, yet. (I may be wrong, I'm not deeply familiar with the BuildBuddy implementation). So, for now, I'm not planning to add lifecycle events.

BuildBuddy uses pattern expand messages to collect the set of targets to report on.
Buck2 does not have a direct correspondance to the target completed message, for now we collect all
targets for which actions are completed and then emit a series of target completed events before we
close the stream.
Stdout and stderr are only included inline in Buck2 and not as CAS items, so we forward them as
inline data.
Failure details are used by BuildBuddy to display build errors in the UI, so we emit these.
@aherrmann
Copy link
Contributor Author

aherrmann commented Nov 22, 2024

Incremental update: I've added the necessary events to display targets, actions, command-lines, and command failure messages in the BuildBuddy UI for simple, local builds.

To reproduce

# BuildBuddy
$ bazel run server -- -app.log_level debug -app.enable_target_tracking true
# Buck2
$ cargo build --bin=buck2
$ cd examples/hello_world
$ BES_URI=http://localhost:1985 ../../target/debug/buck2 build :main

@nlopezgi
Copy link

Do you have plans to add the PublishLifecycleEvent calls?

I'm currently testing and developing against BuildBuddy. To my understanding so far, that implementation seems to largely ignore lifecycle events, at least I haven't spotted a need for them, yet. (I may be wrong, I'm not deeply familiar with the BuildBuddy implementation). So, for now, I'm not planning to add lifecycle events.

Thanks @aherrmann, I think your current process of develping against BuildBuddy makes sense as an initial approach to validate your POC.

I confirmed with some colleagues and our reading of the protocol is that there should be some lifecycle events in order to produce a legal event stream. Particularly The protocol mandates that BuildEnqueued must be sent before any other event, and this event seems to be something that is documented in the PublishLifecycle event docs as one that is needed.

I'm happy to talk more about this if you feel strongly that lifecycle events are really not needed and ask some of my colleagues with more experience on the protocol to chime in too.

Thanks again for your work on this feature!

@nlopezgi
Copy link

nlopezgi commented Dec 5, 2024

Circling back on the state of testing of this PoC with EngFlow UI. I have been able to test all the features on this PR successfully. The key things I had to hardcode to get it to work properly with EngFlow UI are the following:

  • TLS cert creation
  • Set project in requests to value "default"
  • Add lifecycle events called via rpc PublishLifecycleEvent for the following: BuildEnqueued, InvocationAttemptStarted, InvocationAttemptFinished, BuildFinished.
    Thanks again for putting this PoC together for testing @aherrmann . I will keep my eye out if you add more features to test them with EngFlow UI.

@facebook-github-bot
Copy link
Contributor

@facebook-github-bot has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@aherrmann
Copy link
Contributor Author

aherrmann commented Dec 18, 2024

I've added sufficient TLS and HTTP header support to connect to the BuildBuddy cloud service over https and using an access token.
The configuration is currently performed through env-vars:

  • BES_URI: The Build Event Stream service URI.
  • BES_RESULT: URL prefix for BES result.
  • BES_TLS: Set to 1 to enable TLS. (PEM TBD, see here for an implementation).
  • BES_HEADERS: Comma separated list of headers of the form KEY:VALUE, use this to set the access token.

fn buck_to_bazel_events<S: Stream<Item = BuckEvent>>(events: S) -> impl Stream<Item = v1::BuildEvent> {
let mut target_actions: HashMap<(String, String), Vec<(BuildEventId, bool)>> = HashMap::new();
stream! {
for await event in events {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should be able to use unpack_event to get an UnpackedBuckEvent that cuts down a bit on the boilerplate here (compare superconsole's matching on these events:

match unpack_event(event)? {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants