2019-07-17 14:30:04 +02:00
// Copyright 2019 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package build
import (
2020-07-16 18:18:37 +02:00
"fmt"
2020-07-07 14:48:26 +02:00
"os"
2019-07-17 14:30:04 +02:00
"path/filepath"
2022-01-13 08:13:10 +01:00
"runtime"
2022-04-27 20:52:56 +02:00
"strings"
2019-07-17 14:30:04 +02:00
2022-07-12 17:26:37 +02:00
"android/soong/remoteexec"
2019-07-17 14:30:04 +02:00
"android/soong/ui/metrics"
)
2020-07-07 14:48:26 +02:00
const (
rbeLeastNProcs = 2500
rbeLeastNFiles = 16000
// prebuilt RBE binaries
bootstrapCmd = "bootstrap"
// RBE metrics proto buffer file
rbeMetricsPBFilename = "rbe_metrics.pb"
2020-10-08 08:33:29 +02:00
defaultOutDir = "out"
2020-07-07 14:48:26 +02:00
)
func rbeCommand ( ctx Context , config Config , rbeCmd string ) string {
var cmdPath string
2020-08-12 07:26:23 +02:00
if rbeDir := config . rbeDir ( ) ; rbeDir != "" {
2020-07-07 14:48:26 +02:00
cmdPath = filepath . Join ( rbeDir , rbeCmd )
} else {
ctx . Fatalf ( "rbe command path not found" )
}
if _ , err := os . Stat ( cmdPath ) ; err != nil && os . IsNotExist ( err ) {
ctx . Fatalf ( "rbe command %q not found" , rbeCmd )
}
return cmdPath
}
2019-07-17 14:30:04 +02:00
2020-08-29 05:53:02 +02:00
func getRBEVars ( ctx Context , config Config ) map [ string ] string {
2020-08-12 07:26:23 +02:00
vars := map [ string ] string {
2023-10-10 20:36:59 +02:00
"RBE_log_dir" : config . rbeProxyLogsDir ( ) ,
"RBE_re_proxy" : config . rbeReproxy ( ) ,
"RBE_exec_root" : config . rbeExecRoot ( ) ,
"RBE_output_dir" : config . rbeProxyLogsDir ( ) ,
"RBE_proxy_log_dir" : config . rbeProxyLogsDir ( ) ,
"RBE_cache_dir" : config . rbeCacheDir ( ) ,
"RBE_download_tmp_dir" : config . rbeDownloadTmpDir ( ) ,
"RBE_platform" : "container-image=" + remoteexec . DefaultImage ,
2020-08-14 04:53:42 +02:00
}
if config . StartRBE ( ) {
2022-05-27 13:48:37 +02:00
name , err := config . rbeSockAddr ( absPath ( ctx , config . TempDir ( ) ) )
2020-08-29 05:53:02 +02:00
if err != nil {
ctx . Fatalf ( "Error retrieving socket address: %v" , err )
return nil
}
vars [ "RBE_server_address" ] = fmt . Sprintf ( "unix://%v" , name )
2020-08-12 07:26:23 +02:00
}
2022-01-13 08:13:10 +01:00
rf := 1.0
if config . Parallel ( ) < runtime . NumCPU ( ) {
rf = float64 ( config . Parallel ( ) ) / float64 ( runtime . NumCPU ( ) )
}
vars [ "RBE_local_resource_fraction" ] = fmt . Sprintf ( "%.2f" , rf )
2020-08-12 07:26:23 +02:00
k , v := config . rbeAuth ( )
vars [ k ] = v
return vars
2020-07-16 18:18:37 +02:00
}
2022-05-27 13:48:37 +02:00
func cleanupRBELogsDir ( ctx Context , config Config ) {
if ! config . shouldCleanupRBELogsDir ( ) {
return
}
rbeTmpDir := config . rbeProxyLogsDir ( )
if err := os . RemoveAll ( rbeTmpDir ) ; err != nil {
fmt . Fprintln ( ctx . Writer , "\033[33mUnable to remove RBE log directory: " , err , "\033[0m" )
}
}
2019-07-17 14:30:04 +02:00
func startRBE ( ctx Context , config Config ) {
2022-10-14 00:34:08 +02:00
if ! config . GoogleProdCredsExist ( ) && prodCredsAuthType ( config ) {
ctx . Fatalf ( "Unable to start RBE reproxy\nFAILED: Missing LOAS credentials." )
}
2019-07-17 14:30:04 +02:00
ctx . BeginTrace ( metrics . RunSetupTool , "rbe_bootstrap" )
defer ctx . EndTrace ( )
2023-02-16 21:53:32 +01:00
ctx . Status . Status ( "Starting rbe..." )
2019-07-17 14:30:04 +02:00
if u := ulimitOrFatal ( ctx , config , "-u" ) ; u < rbeLeastNProcs {
ctx . Fatalf ( "max user processes is insufficient: %d; want >= %d.\n" , u , rbeLeastNProcs )
}
if n := ulimitOrFatal ( ctx , config , "-n" ) ; n < rbeLeastNFiles {
ctx . Fatalf ( "max open files is insufficient: %d; want >= %d.\n" , n , rbeLeastNFiles )
}
2022-05-27 13:48:37 +02:00
if _ , err := os . Stat ( config . rbeProxyLogsDir ( ) ) ; os . IsNotExist ( err ) {
if err := os . MkdirAll ( config . rbeProxyLogsDir ( ) , 0744 ) ; err != nil {
ctx . Fatalf ( "Unable to create logs dir (%v) for RBE: %v" , config . rbeProxyLogsDir , err )
}
}
2019-07-17 14:30:04 +02:00
2020-07-07 14:48:26 +02:00
cmd := Command ( ctx , config , "startRBE bootstrap" , rbeCommand ( ctx , config , bootstrapCmd ) )
2019-07-17 14:30:04 +02:00
if output , err := cmd . CombinedOutput ( ) ; err != nil {
2021-01-26 20:30:53 +01:00
ctx . Fatalf ( "Unable to start RBE reproxy\nFAILED: RBE bootstrap failed with: %v\n%s\n" , err , output )
2019-07-17 14:30:04 +02:00
}
}
2020-07-07 14:48:26 +02:00
func stopRBE ( ctx Context , config Config ) {
cmd := Command ( ctx , config , "stopRBE bootstrap" , rbeCommand ( ctx , config , bootstrapCmd ) , "-shutdown" )
2021-03-22 03:35:26 +01:00
output , err := cmd . CombinedOutput ( )
if err != nil {
2020-07-07 14:48:26 +02:00
ctx . Fatalf ( "rbe bootstrap with shutdown failed with: %v\n%s\n" , err , output )
}
2021-03-22 03:35:26 +01:00
2021-04-21 05:58:19 +02:00
if ! config . Environment ( ) . IsEnvTrue ( "ANDROID_QUIET_BUILD" ) && len ( output ) > 0 {
2021-03-22 03:35:26 +01:00
fmt . Fprintln ( ctx . Writer , "" )
fmt . Fprintln ( ctx . Writer , fmt . Sprintf ( "%s" , output ) )
}
2020-07-07 14:48:26 +02:00
}
2022-04-27 20:52:56 +02:00
func prodCredsAuthType ( config Config ) bool {
authVar , val := config . rbeAuth ( )
if strings . Contains ( authVar , "use_google_prod_creds" ) && val != "" && val != "false" {
return true
}
return false
}
// Check whether proper auth exists for RBE builds run within a
// Google dev environment.
func CheckProdCreds ( ctx Context , config Config ) {
if ! config . IsGooglerEnvironment ( ) {
return
}
if ! config . StubbyExists ( ) && prodCredsAuthType ( config ) {
fmt . Fprintln ( ctx . Writer , "" )
2022-11-29 22:08:06 +01:00
fmt . Fprintln ( ctx . Writer , fmt . Sprintf ( "\033[33mWARNING: %q binary not found in $PATH, follow go/build-fast-without-stubby instead for authenticating with RBE.\033[0m" , "stubby" ) )
2022-04-27 20:52:56 +02:00
fmt . Fprintln ( ctx . Writer , "" )
return
}
if config . GoogleProdCredsExist ( ) {
return
}
fmt . Fprintln ( ctx . Writer , "" )
fmt . Fprintln ( ctx . Writer , "\033[33mWARNING: Missing LOAS credentials, please run `gcert`. This will result in failing builds in the future, see go/rbe-android-default-announcement.\033[0m" )
fmt . Fprintln ( ctx . Writer , "" )
}
2020-07-07 14:48:26 +02:00
// DumpRBEMetrics creates a metrics protobuf file containing RBE related metrics.
// The protobuf file is created if RBE is enabled and the proxy service has
// started. The proxy service is shutdown in order to dump the RBE metrics to the
// protobuf file.
func DumpRBEMetrics ( ctx Context , config Config , filename string ) {
ctx . BeginTrace ( metrics . RunShutdownTool , "dump_rbe_metrics" )
defer ctx . EndTrace ( )
// Remove the previous metrics file in case there is a failure or RBE has been
// disable for this run.
os . Remove ( filename )
// If RBE is not enabled then there are no metrics to generate.
// If RBE does not require to start, the RBE proxy maybe started
// manually for debugging purpose and can generate the metrics
// afterwards.
if ! config . StartRBE ( ) {
return
}
2022-05-27 13:48:37 +02:00
outputDir := config . rbeProxyLogsDir ( )
2020-07-07 14:48:26 +02:00
if outputDir == "" {
ctx . Fatal ( "RBE output dir variable not defined. Aborting metrics dumping." )
}
metricsFile := filepath . Join ( outputDir , rbeMetricsPBFilename )
// Stop the proxy first in order to generate the RBE metrics protobuf file.
stopRBE ( ctx , config )
2020-08-12 07:26:23 +02:00
if metricsFile == filename {
return
}
2020-07-07 14:48:26 +02:00
if _ , err := copyFile ( metricsFile , filename ) ; err != nil {
ctx . Fatalf ( "failed to copy %q to %q: %v\n" , metricsFile , filename , err )
}
}
2020-10-08 08:33:29 +02:00
// PrintOutDirWarning prints a warning to indicate to the user that
// setting output directory to a path other than "out" in an RBE enabled
// build can cause slow builds.
func PrintOutDirWarning ( ctx Context , config Config ) {
if config . UseRBE ( ) && config . OutDir ( ) != defaultOutDir {
fmt . Fprintln ( ctx . Writer , "" )
fmt . Fprintln ( ctx . Writer , "\033[33mWARNING:\033[0m" )
fmt . Fprintln ( ctx . Writer , fmt . Sprintf ( "Setting OUT_DIR to a path other than %v may result in slow RBE builds." , defaultOutDir ) )
fmt . Fprintln ( ctx . Writer , "See http://go/android_rbe_out_dir for a workaround." )
fmt . Fprintln ( ctx . Writer , "" )
}
}