[Notes] [Git][BuildGrid/buildgrid][mablanch/157-action-browser-url] 4 commits: cmd_bot and cmd_execute: allow specifying list of Platform attributes



Title: GitLab

Martin Blanchard pushed to branch mablanch/157-action-browser-url at BuildGrid / buildgrid

Commits:

17 changed files:

Changes:

  • buildgrid/_app/commands/cmd_bot.py
    ... ... @@ -59,11 +59,14 @@ from ..cli import pass_context, setup_logging
    59 59
                   help="Time period for bot updates to the server in seconds.")
    
    60 60
     @click.option('--parent', type=click.STRING, default=None, show_default=True,
    
    61 61
                   help="Targeted farm resource.")
    
    62
    +@click.option('-w', '--worker-property', nargs=2, type=(click.STRING, click.STRING), multiple=True,
    
    63
    +              help="List of key-value pairs of worker properties.")
    
    62 64
     @click.option('-v', '--verbose', count=True,
    
    63 65
                   help='Increase log verbosity level.')
    
    64 66
     @pass_context
    
    65
    -def cli(context, parent, update_period, remote, auth_token, client_key, client_cert, server_cert,
    
    66
    -        remote_cas, cas_client_key, cas_client_cert, cas_server_cert, verbose):
    
    67
    +def cli(context, parent, update_period, remote, auth_token, client_key,
    
    68
    +        client_cert, server_cert, remote_cas, cas_client_key, cas_client_cert,
    
    69
    +        cas_server_cert, worker_property, verbose):
    
    67 70
         setup_logging(verbosity=verbose)
    
    68 71
         # Setup the remote execution server channel:
    
    69 72
         try:
    
    ... ... @@ -90,8 +93,14 @@ def cli(context, parent, update_period, remote, auth_token, client_key, client_c
    90 93
     
    
    91 94
         bot_interface = interface.BotInterface(context.channel)
    
    92 95
     
    
    96
    +    worker_properties_dict = {}
    
    97
    +    for property_name, property_value in worker_property:
    
    98
    +        if property_name not in worker_properties_dict:
    
    99
    +            worker_properties_dict[property_name] = set()
    
    100
    +        worker_properties_dict[property_name].add(property_value)
    
    101
    +
    
    93 102
         worker = Worker()
    
    94
    -    worker.add_device(Device())
    
    103
    +    worker.add_device(Device(properties=worker_properties_dict))
    
    95 104
         hardware_interface = HardwareInterface(worker)
    
    96 105
     
    
    97 106
         context.bot_interface = bot_interface
    

  • buildgrid/_app/commands/cmd_cas.py
    ... ... @@ -65,15 +65,27 @@ def cli(context, remote, instance_name, auth_token, client_key, client_cert, ser
    65 65
     @cli.command('upload-dummy', short_help="Upload a dummy action. Should be used with `execute dummy-request`")
    
    66 66
     @pass_context
    
    67 67
     def upload_dummy(context):
    
    68
    -    action = remote_execution_pb2.Action(do_not_cache=True)
    
    68
    +    command = remote_execution_pb2.Command()
    
    69
    +    with upload(context.channel, instance=context.instance_name) as uploader:
    
    70
    +        command_digest = uploader.put_message(command)
    
    71
    +
    
    72
    +    if command_digest.ByteSize():
    
    73
    +        click.echo('Success: Pushed Command, digest=["{}/{}]"'
    
    74
    +                   .format(command_digest.hash, command_digest.size_bytes))
    
    75
    +    else:
    
    76
    +        click.echo("Error: Failed pushing empty Command.", err=True)
    
    77
    +
    
    78
    +    action = remote_execution_pb2.Action(command_digest=command_digest,
    
    79
    +                                         do_not_cache=True)
    
    80
    +
    
    69 81
         with upload(context.channel, instance=context.instance_name) as uploader:
    
    70 82
             action_digest = uploader.put_message(action)
    
    71 83
     
    
    72 84
         if action_digest.ByteSize():
    
    73
    -        click.echo('Success: Pushed digest=["{}/{}]"'
    
    85
    +        click.echo('Success: Pushed Action, digest=["{}/{}]"'
    
    74 86
                        .format(action_digest.hash, action_digest.size_bytes))
    
    75 87
         else:
    
    76
    -        click.echo("Error: Failed pushing empty message.", err=True)
    
    88
    +        click.echo("Error: Failed pushing empty Action.", err=True)
    
    77 89
     
    
    78 90
     
    
    79 91
     @cli.command('upload-file', short_help="Upload files to the CAS server.")
    

  • buildgrid/_app/commands/cmd_execute.py
    ... ... @@ -72,7 +72,11 @@ def cli(context, remote, instance_name, auth_token, client_key, client_cert, ser
    72 72
     def request_dummy(context, number, wait_for_completion):
    
    73 73
     
    
    74 74
         click.echo("Sending execution request...")
    
    75
    -    action = remote_execution_pb2.Action(do_not_cache=True)
    
    75
    +    command = remote_execution_pb2.Command()
    
    76
    +    command_digest = create_digest(command.SerializeToString())
    
    77
    +
    
    78
    +    action = remote_execution_pb2.Action(command_digest=command_digest,
    
    79
    +                                         do_not_cache=True)
    
    76 80
         action_digest = create_digest(action.SerializeToString())
    
    77 81
     
    
    78 82
         stub = remote_execution_pb2_grpc.ExecutionStub(context.channel)
    
    ... ... @@ -107,23 +111,31 @@ def request_dummy(context, number, wait_for_completion):
    107 111
                   help="Tuple of expected output file and is-executeable flag.")
    
    108 112
     @click.option('--output-directory', default='testing', show_default=True,
    
    109 113
                   help="Output directory for the output files.")
    
    114
    +@click.option('-p', '--platform-property', nargs=2, type=(click.STRING, click.STRING), multiple=True,
    
    115
    +              help="List of key-value pairs of required platform properties.")
    
    110 116
     @click.argument('input-root', nargs=1, type=click.Path(), required=True)
    
    111 117
     @click.argument('commands', nargs=-1, type=click.STRING, required=True)
    
    112 118
     @pass_context
    
    113
    -def run_command(context, input_root, commands, output_file, output_directory):
    
    119
    +def run_command(context, input_root, commands, output_file, output_directory,
    
    120
    +                platform_property):
    
    114 121
         stub = remote_execution_pb2_grpc.ExecutionStub(context.channel)
    
    115 122
     
    
    116
    -    output_executeables = []
    
    123
    +    output_executables = []
    
    117 124
         with upload(context.channel, instance=context.instance_name) as uploader:
    
    118 125
             command = remote_execution_pb2.Command()
    
    119 126
     
    
    120 127
             for arg in commands:
    
    121 128
                 command.arguments.extend([arg])
    
    122 129
     
    
    123
    -        for file, is_executeable in output_file:
    
    130
    +        for file, is_executable in output_file:
    
    124 131
                 command.output_files.extend([file])
    
    125
    -            if is_executeable:
    
    126
    -                output_executeables.append(file)
    
    132
    +            if is_executable:
    
    133
    +                output_executables.append(file)
    
    134
    +
    
    135
    +        for attribute_name, attribute_value in platform_property:
    
    136
    +            new_property = command.platform.properties.add()
    
    137
    +            new_property.name = attribute_name
    
    138
    +            new_property.value = attribute_value
    
    127 139
     
    
    128 140
             command_digest = uploader.put_message(command, queue=True)
    
    129 141
     
    
    ... ... @@ -165,6 +177,6 @@ def run_command(context, input_root, commands, output_file, output_directory):
    165 177
                 downloader.download_file(output_file_response.digest, path)
    
    166 178
     
    
    167 179
         for output_file_response in execute_response.result.output_files:
    
    168
    -        if output_file_response.path in output_executeables:
    
    180
    +        if output_file_response.path in output_executables:
    
    169 181
                 st = os.stat(path)
    
    170 182
                 os.chmod(path, st.st_mode | stat.S_IXUSR)

  • buildgrid/_app/settings/parser.py
    ... ... @@ -235,8 +235,8 @@ class Execution(YamlFactory):
    235 235
     
    
    236 236
         yaml_tag = u'!execution'
    
    237 237
     
    
    238
    -    def __new__(cls, storage, action_cache=None):
    
    239
    -        return ExecutionController(action_cache, storage)
    
    238
    +    def __new__(cls, storage, action_cache=None, action_browser_url=None):
    
    239
    +        return ExecutionController(storage, action_cache, action_browser_url)
    
    240 240
     
    
    241 241
     
    
    242 242
     class Action(YamlFactory):
    

  • buildgrid/_app/settings/reference.yml
    ... ... @@ -75,7 +75,7 @@ instances:
    75 75
             # Whether or not writing to the cache is allowed.
    
    76 76
             allow-updates: true
    
    77 77
             ##
    
    78
    -        # Whether failed actions (non-zero exit code) are stored
    
    78
    +        # Whether failed actions (non-zero exit code) are stored.
    
    79 79
             cache-failed-actions: true
    
    80 80
     
    
    81 81
           - !execution
    
    ... ... @@ -85,6 +85,9 @@ instances:
    85 85
             ##
    
    86 86
             # Alias to an action-cache service.
    
    87 87
             action-cache: *main-action
    
    88
    +        ##
    
    89
    +        # Base URL for external build action (web) browser service.
    
    90
    +        action-browser-url: http://localhost:8080
    
    88 91
     
    
    89 92
           - !cas
    
    90 93
             ##
    

  • buildgrid/_protos/build/bazel/remote/execution/v2/remote_execution.proto
    ... ... @@ -81,6 +81,7 @@ service Execution {
    81 81
       // action will be reported in the `status` field of the `ExecuteResponse`. The
    
    82 82
       // server MUST NOT set the `error` field of the `Operation` proto.
    
    83 83
       // The possible errors include:
    
    84
    +  //
    
    84 85
       // * `INVALID_ARGUMENT`: One or more arguments are invalid.
    
    85 86
       // * `FAILED_PRECONDITION`: One or more errors occurred in setting up the
    
    86 87
       //   action requested, such as a missing input or command or no worker being
    
    ... ... @@ -140,6 +141,7 @@ service ActionCache {
    140 141
       // Retrieve a cached execution result.
    
    141 142
       //
    
    142 143
       // Errors:
    
    144
    +  //
    
    143 145
       // * `NOT_FOUND`: The requested `ActionResult` is not in the cache.
    
    144 146
       rpc GetActionResult(GetActionResultRequest) returns (ActionResult) {
    
    145 147
         option (google.api.http) = { get: "/v2/{instance_name=**}/actionResults/{action_digest.hash}/{action_digest.size_bytes}" };
    
    ... ... @@ -147,11 +149,6 @@ service ActionCache {
    147 149
     
    
    148 150
       // Upload a new execution result.
    
    149 151
       //
    
    150
    -  // This method is intended for servers which implement the distributed cache
    
    151
    -  // independently of the
    
    152
    -  // [Execution][build.bazel.remote.execution.v2.Execution] API. As a
    
    153
    -  // result, it is OPTIONAL for servers to implement.
    
    154
    -  //
    
    155 152
       // In order to allow the server to perform access control based on the type of
    
    156 153
       // action, and to assist with client debugging, the client MUST first upload
    
    157 154
       // the [Action][build.bazel.remote.execution.v2.Execution] that produced the
    
    ... ... @@ -160,7 +157,10 @@ service ActionCache {
    160 157
       // `ContentAddressableStorage`.
    
    161 158
       //
    
    162 159
       // Errors:
    
    163
    -  // * `UNIMPLEMENTED`: This method is not supported by the server.
    
    160
    +  //
    
    161
    +  // * `INVALID_ARGUMENT`: One or more arguments are invalid.
    
    162
    +  // * `FAILED_PRECONDITION`: One or more errors occurred in updating the
    
    163
    +  //   action result, such as a missing command or action.
    
    164 164
       // * `RESOURCE_EXHAUSTED`: There is insufficient storage space to add the
    
    165 165
       //   entry to the cache.
    
    166 166
       rpc UpdateActionResult(UpdateActionResultRequest) returns (ActionResult) {
    
    ... ... @@ -207,6 +207,9 @@ service ActionCache {
    207 207
     // by the server. For servers which do not support multiple instances, then the
    
    208 208
     // `instance_name` is the empty path and the leading slash is omitted, so that
    
    209 209
     // the `resource_name` becomes `uploads/{uuid}/blobs/{hash}/{size}`.
    
    210
    +// To simplify parsing, a path segment cannot equal any of the following
    
    211
    +// keywords: `blobs`, `uploads`, `actions`, `actionResults`, `operations` and
    
    212
    +// `capabilities`.
    
    210 213
     //
    
    211 214
     // When attempting an upload, if another client has already completed the upload
    
    212 215
     // (which may occur in the middle of a single upload if another client uploads
    
    ... ... @@ -258,10 +261,12 @@ service ContentAddressableStorage {
    258 261
       // independently.
    
    259 262
       //
    
    260 263
       // Errors:
    
    264
    +  //
    
    261 265
       // * `INVALID_ARGUMENT`: The client attempted to upload more than the
    
    262 266
       //   server supported limit.
    
    263 267
       //
    
    264 268
       // Individual requests may return the following errors, additionally:
    
    269
    +  //
    
    265 270
       // * `RESOURCE_EXHAUSTED`: There is insufficient disk quota to store the blob.
    
    266 271
       // * `INVALID_ARGUMENT`: The
    
    267 272
       // [Digest][build.bazel.remote.execution.v2.Digest] does not match the
    
    ... ... @@ -284,6 +289,7 @@ service ContentAddressableStorage {
    284 289
       // independently.
    
    285 290
       //
    
    286 291
       // Errors:
    
    292
    +  //
    
    287 293
       // * `INVALID_ARGUMENT`: The client attempted to read more than the
    
    288 294
       //   server supported limit.
    
    289 295
       //
    
    ... ... @@ -390,7 +396,8 @@ message Action {
    390 396
       // immediately, rather than whenever the cache entry gets evicted.
    
    391 397
       google.protobuf.Duration timeout = 6;
    
    392 398
     
    
    393
    -  // If true, then the `Action`'s result cannot be cached.
    
    399
    +  // If true, then the `Action`'s result cannot be cached, and in-flight
    
    400
    +  // requests for the same `Action` may not be merged.
    
    394 401
       bool do_not_cache = 7;
    
    395 402
     }
    
    396 403
     
    
    ... ... @@ -421,7 +428,8 @@ message Command {
    421 428
       // provide its own default environment variables; these defaults can be
    
    422 429
       // overridden using this field. Additional variables can also be specified.
    
    423 430
       //
    
    424
    -  // In order to ensure that equivalent `Command`s always hash to the same
    
    431
    +  // In order to ensure that equivalent
    
    432
    +  // [Command][build.bazel.remote.execution.v2.Command]s always hash to the same
    
    425 433
       // value, the environment variables MUST be lexicographically sorted by name.
    
    426 434
       // Sorting of strings is done by code point, equivalently, by the UTF-8 bytes.
    
    427 435
       repeated EnvironmentVariable environment_variables = 2;
    
    ... ... @@ -444,6 +452,9 @@ message Command {
    444 452
       //
    
    445 453
       // An output file cannot be duplicated, be a parent of another output file, or
    
    446 454
       // have the same path as any of the listed output directories.
    
    455
    +  //
    
    456
    +  // Directories leading up to the output files are created by the worker prior
    
    457
    +  // to execution, even if they are not explicitly part of the input root.
    
    447 458
       repeated string output_files = 3;
    
    448 459
     
    
    449 460
       // A list of the output directories that the client expects to retrieve from
    
    ... ... @@ -468,6 +479,10 @@ message Command {
    468 479
       //
    
    469 480
       // An output directory cannot be duplicated or have the same path as any of
    
    470 481
       // the listed output files.
    
    482
    +  //
    
    483
    +  // Directories leading up to the output directories (but not the output
    
    484
    +  // directories themselves) are created by the worker prior to execution, even
    
    485
    +  // if they are not explicitly part of the input root.
    
    471 486
       repeated string output_directories = 4;
    
    472 487
     
    
    473 488
       // The platform requirements for the execution environment. The server MAY
    
    ... ... @@ -531,12 +546,18 @@ message Platform {
    531 546
     // In order to ensure that two equivalent directory trees hash to the same
    
    532 547
     // value, the following restrictions MUST be obeyed when constructing a
    
    533 548
     // a `Directory`:
    
    534
    -//   - Every child in the directory must have a path of exactly one segment.
    
    535
    -//     Multiple levels of directory hierarchy may not be collapsed.
    
    536
    -//   - Each child in the directory must have a unique path segment (file name).
    
    537
    -//   - The files, directories and symlinks in the directory must each be sorted
    
    538
    -//     in lexicographical order by path. The path strings must be sorted by code
    
    539
    -//     point, equivalently, by UTF-8 bytes.
    
    549
    +//
    
    550
    +// * Every child in the directory must have a path of exactly one segment.
    
    551
    +//   Multiple levels of directory hierarchy may not be collapsed.
    
    552
    +// * Each child in the directory must have a unique path segment (file name).
    
    553
    +//   Note that while the API itself is case-sensitive, the environment where
    
    554
    +//   the Action is executed may or may not be case-sensitive. That is, it is
    
    555
    +//   legal to call the API with a Directory that has both "Foo" and "foo" as
    
    556
    +//   children, but the Action may be rejected by the remote system upon
    
    557
    +//   execution.
    
    558
    +// * The files, directories and symlinks in the directory must each be sorted
    
    559
    +//   in lexicographical order by path. The path strings must be sorted by code
    
    560
    +//   point, equivalently, by UTF-8 bytes.
    
    540 561
     //
    
    541 562
     // A `Directory` that obeys the restrictions is said to be in canonical form.
    
    542 563
     //
    
    ... ... @@ -656,11 +677,12 @@ message SymlinkNode {
    656 677
     // When a `Digest` is used to refer to a proto message, it always refers to the
    
    657 678
     // message in binary encoded form. To ensure consistent hashing, clients and
    
    658 679
     // servers MUST ensure that they serialize messages according to the following
    
    659
    -// rules, even if there are alternate valid encodings for the same message.
    
    660
    -// - Fields are serialized in tag order.
    
    661
    -// - There are no unknown fields.
    
    662
    -// - There are no duplicate fields.
    
    663
    -// - Fields are serialized according to the default semantics for their type.
    
    680
    +// rules, even if there are alternate valid encodings for the same message:
    
    681
    +//
    
    682
    +// * Fields are serialized in tag order.
    
    683
    +// * There are no unknown fields.
    
    684
    +// * There are no duplicate fields.
    
    685
    +// * Fields are serialized according to the default semantics for their type.
    
    664 686
     //
    
    665 687
     // Most protocol buffer implementations will always follow these rules when
    
    666 688
     // serializing, but care should be taken to avoid shortcuts. For instance,
    
    ... ... @@ -727,7 +749,7 @@ message ActionResult {
    727 749
       // The output files of the action that are symbolic links to other files. Those
    
    728 750
       // may be links to other output files, or input files, or even absolute paths
    
    729 751
       // outside of the working directory, if the server supports
    
    730
    -  // [SymlinkAbsolutePathStrategy.ALLOWED][build.bazel.remote.execution.v2.SymlinkAbsolutePathStrategy].
    
    752
    +  // [SymlinkAbsolutePathStrategy.ALLOWED][build.bazel.remote.execution.v2.CacheCapabilities.SymlinkAbsolutePathStrategy].
    
    731 753
       // For each output file requested in the `output_files` field of the Action,
    
    732 754
       // if the corresponding file existed after
    
    733 755
       // the action completed, a single entry will be present either in this field,
    
    ... ... @@ -804,7 +826,7 @@ message ActionResult {
    804 826
       // directories. Those may be links to other output directories, or input
    
    805 827
       // directories, or even absolute paths outside of the working directory,
    
    806 828
       // if the server supports
    
    807
    -  // [SymlinkAbsolutePathStrategy.ALLOWED][build.bazel.remote.execution.v2.SymlinkAbsolutePathStrategy].
    
    829
    +  // [SymlinkAbsolutePathStrategy.ALLOWED][build.bazel.remote.execution.v2.CacheCapabilities.SymlinkAbsolutePathStrategy].
    
    808 830
       // For each output directory requested in the `output_directories` field of
    
    809 831
       // the Action, if the directory file existed after
    
    810 832
       // the action completed, a single entry will be present either in this field,
    
    ... ... @@ -961,9 +983,19 @@ message ExecuteRequest {
    961 983
       // omitted.
    
    962 984
       string instance_name = 1;
    
    963 985
     
    
    964
    -  // If true, the action will be executed anew even if its result was already
    
    965
    -  // present in the cache. If false, the result may be served from the
    
    966
    -  // [ActionCache][build.bazel.remote.execution.v2.ActionCache].
    
    986
    +  // If true, the action will be executed even if its result is already
    
    987
    +  // present in the [ActionCache][build.bazel.remote.execution.v2.ActionCache].
    
    988
    +  // The execution is still allowed to be merged with other in-flight executions
    
    989
    +  // of the same action, however - semantically, the service MUST only guarantee
    
    990
    +  // that the results of an execution with this field set were not visible
    
    991
    +  // before the corresponding execution request was sent.
    
    992
    +  // Note that actions from execution requests setting this field set are still
    
    993
    +  // eligible to be entered into the action cache upon completion, and services
    
    994
    +  // SHOULD overwrite any existing entries that may exist. This allows
    
    995
    +  // skip_cache_lookup requests to be used as a mechanism for replacing action
    
    996
    +  // cache entries that reference outputs no longer available or that are
    
    997
    +  // poisoned in any way.
    
    998
    +  // If false, the result may be served from the action cache.
    
    967 999
       bool skip_cache_lookup = 3;
    
    968 1000
     
    
    969 1001
       reserved 2, 4, 5; // Used for removed fields in an earlier version of the API.
    
    ... ... @@ -1027,6 +1059,10 @@ message ExecuteResponse {
    1027 1059
       // phase. The keys SHOULD be human readable so that a client can display them
    
    1028 1060
       // to a user.
    
    1029 1061
       map<string, LogFile> server_logs = 4;
    
    1062
    +
    
    1063
    +  // Freeform informational message with details on the execution of the action
    
    1064
    +  // that may be displayed to the user upon failure or when requested explicitly.
    
    1065
    +  string message = 5;
    
    1030 1066
     }
    
    1031 1067
     
    
    1032 1068
     // Metadata about an ongoing
    
    ... ... @@ -1072,7 +1108,7 @@ message ExecuteOperationMetadata {
    1072 1108
     // A request message for
    
    1073 1109
     // [WaitExecution][build.bazel.remote.execution.v2.Execution.WaitExecution].
    
    1074 1110
     message WaitExecutionRequest {
    
    1075
    -  // The name of the [Operation][google.longrunning.operations.v1.Operation]
    
    1111
    +  // The name of the [Operation][google.longrunning.Operation]
    
    1076 1112
       // returned by [Execute][build.bazel.remote.execution.v2.Execution.Execute].
    
    1077 1113
       string name = 1;
    
    1078 1114
     }
    
    ... ... @@ -1193,7 +1229,7 @@ message BatchReadBlobsRequest {
    1193 1229
     // A response message for
    
    1194 1230
     // [ContentAddressableStorage.BatchReadBlobs][build.bazel.remote.execution.v2.ContentAddressableStorage.BatchReadBlobs].
    
    1195 1231
     message BatchReadBlobsResponse {
    
    1196
    -  // A response corresponding to a single blob that the client tried to upload.
    
    1232
    +  // A response corresponding to a single blob that the client tried to download.
    
    1197 1233
       message Response {
    
    1198 1234
         // The digest to which this response corresponds.
    
    1199 1235
         Digest digest = 1;
    
    ... ... @@ -1251,7 +1287,7 @@ message GetTreeResponse {
    1251 1287
     }
    
    1252 1288
     
    
    1253 1289
     // A request message for
    
    1254
    -// [Capabilities.GetCapabilities][google.devtools.remoteexecution.v2.Capabilities.GetCapabilities].
    
    1290
    +// [Capabilities.GetCapabilities][build.bazel.remote.execution.v2.Capabilities.GetCapabilities].
    
    1255 1291
     message GetCapabilitiesRequest {
    
    1256 1292
       // The instance of the execution system to operate against. A server may
    
    1257 1293
       // support multiple instances of the execution system (with their own workers,
    
    ... ... @@ -1262,7 +1298,7 @@ message GetCapabilitiesRequest {
    1262 1298
     }
    
    1263 1299
     
    
    1264 1300
     // A response message for
    
    1265
    -// [Capabilities.GetCapabilities][google.devtools.remoteexecution.v2.Capabilities.GetCapabilities].
    
    1301
    +// [Capabilities.GetCapabilities][build.bazel.remote.execution.v2.Capabilities.GetCapabilities].
    
    1266 1302
     message ServerCapabilities {
    
    1267 1303
       // Capabilities of the remote cache system.
    
    1268 1304
       CacheCapabilities cache_capabilities = 1;
    
    ... ... @@ -1283,9 +1319,16 @@ message ServerCapabilities {
    1283 1319
     // The digest function used for converting values into keys for CAS and Action
    
    1284 1320
     // Cache.
    
    1285 1321
     enum DigestFunction {
    
    1322
    +  // It is an error for the server to return this value.
    
    1286 1323
       UNKNOWN = 0;
    
    1324
    +
    
    1325
    +  // The Sha-256 digest function.
    
    1287 1326
       SHA256 = 1;
    
    1327
    +
    
    1328
    +  // The Sha-1 digest function.
    
    1288 1329
       SHA1 = 2;
    
    1330
    +
    
    1331
    +  // The MD5 digest function.
    
    1289 1332
       MD5 = 3;
    
    1290 1333
     }
    
    1291 1334
     
    
    ... ... @@ -1312,9 +1355,10 @@ message CacheCapabilities {
    1312 1355
       enum SymlinkAbsolutePathStrategy {
    
    1313 1356
         UNKNOWN = 0;
    
    1314 1357
     
    
    1315
    -    // Server will return an INVALID_ARGUMENT on input symlinks with absolute targets.
    
    1358
    +    // Server will return an `INVALID_ARGUMENT` on input symlinks with absolute
    
    1359
    +    // targets.
    
    1316 1360
         // If an action tries to create an output symlink with an absolute target, a
    
    1317
    -    // FAILED_PRECONDITION will be returned.
    
    1361
    +    // `FAILED_PRECONDITION` will be returned.
    
    1318 1362
         DISALLOWED = 1;
    
    1319 1363
     
    
    1320 1364
         // Server will allow symlink targets to escape the input root tree, possibly
    
    ... ... @@ -1367,8 +1411,9 @@ message ToolDetails {
    1367 1411
     // external context of the request. The server may use this for logging or other
    
    1368 1412
     // purposes. To use it, the client attaches the header to the call using the
    
    1369 1413
     // canonical proto serialization:
    
    1370
    -// name: build.bazel.remote.execution.v2.requestmetadata-bin
    
    1371
    -// contents: the base64 encoded binary RequestMetadata message.
    
    1414
    +//
    
    1415
    +// * name: `build.bazel.remote.execution.v2.requestmetadata-bin`
    
    1416
    +// * contents: the base64 encoded binary `RequestMetadata` message.
    
    1372 1417
     message RequestMetadata {
    
    1373 1418
       // The details for the tool invoking the requests.
    
    1374 1419
       ToolDetails tool_details = 1;
    

  • buildgrid/_protos/build/bazel/remote/execution/v2/remote_execution_pb2.py
    ... ... @@ -26,7 +26,7 @@ DESCRIPTOR = _descriptor.FileDescriptor(
    26 26
       package='build.bazel.remote.execution.v2',
    
    27 27
       syntax='proto3',
    
    28 28
       serialized_options=_b('\n\037build.bazel.remote.execution.v2B\024RemoteExecutionProtoP\001Z\017remoteexecution\242\002\003REX\252\002\037Build.Bazel.Remote.Execution.V2'),
    
    29
    -  serialized_pb=_b('\n6build/bazel/remote/execution/v2/remote_execution.proto\x12\x1f\x62uild.bazel.remote.execution.v2\x1a\x1f\x62uild/bazel/semver/semver.proto\x1a\x1cgoogle/api/annotations.proto\x1a#google/longrunning/operations.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x17google/rpc/status.proto\"\xd5\x01\n\x06\x41\x63tion\x12?\n\x0e\x63ommand_digest\x18\x01 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12\x42\n\x11input_root_digest\x18\x02 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12*\n\x07timeout\x18\x06 \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x14\n\x0c\x64o_not_cache\x18\x07 \x01(\x08J\x04\x08\x03\x10\x06\"\xb7\x02\n\x07\x43ommand\x12\x11\n\targuments\x18\x01 \x03(\t\x12[\n\x15\x65nvironment_variables\x18\x02 \x03(\x0b\x32<.build.bazel.remote.execution.v2.Command.EnvironmentVariable\x12\x14\n\x0coutput_files\x18\x03 \x03(\t\x12\x1a\n\x12output_directories\x18\x04 \x03(\t\x12;\n\x08platform\x18\x05 \x01(\x0b\x32).build.bazel.remote.execution.v2.Platform\x12\x19\n\x11working_directory\x18\x06 \x01(\t\x1a\x32\n\x13\x45nvironmentVariable\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"{\n\x08Platform\x12\x46\n\nproperties\x18\x01 \x03(\x0b\x32\x32.build.bazel.remote.execution.v2.Platform.Property\x1a\'\n\x08Property\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"\xca\x01\n\tDirectory\x12\x38\n\x05\x66iles\x18\x01 \x03(\x0b\x32).build.bazel.remote.execution.v2.FileNode\x12\x43\n\x0b\x64irectories\x18\x02 \x03(\x0b\x32..build.bazel.remote.execution.v2.DirectoryNode\x12>\n\x08symlinks\x18\x03 \x03(\x0b\x32,.build.bazel.remote.execution.v2.SymlinkNode\"n\n\x08\x46ileNode\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x37\n\x06\x64igest\x18\x02 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12\x15\n\ris_executable\x18\x04 \x01(\x08J\x04\x08\x03\x10\x04\"V\n\rDirectoryNode\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x37\n\x06\x64igest\x18\x02 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\"+\n\x0bSymlinkNode\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06target\x18\x02 \x01(\t\"*\n\x06\x44igest\x12\x0c\n\x04hash\x18\x01 \x01(\t\x12\x12\n\nsize_bytes\x18\x02 \x01(\x03\"\xec\x04\n\x16\x45xecutedActionMetadata\x12\x0e\n\x06worker\x18\x01 \x01(\t\x12\x34\n\x10queued_timestamp\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12:\n\x16worker_start_timestamp\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12>\n\x1aworker_completed_timestamp\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12?\n\x1binput_fetch_start_timestamp\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x43\n\x1finput_fetch_completed_timestamp\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12=\n\x19\x65xecution_start_timestamp\x18\x07 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x41\n\x1d\x65xecution_completed_timestamp\x18\x08 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x41\n\x1doutput_upload_start_timestamp\x18\t \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x45\n!output_upload_completed_timestamp\x18\n \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\xd6\x04\n\x0c\x41\x63tionResult\x12\x41\n\x0coutput_files\x18\x02 \x03(\x0b\x32+.build.bazel.remote.execution.v2.OutputFile\x12L\n\x14output_file_symlinks\x18\n \x03(\x0b\x32..build.bazel.remote.execution.v2.OutputSymlink\x12L\n\x12output_directories\x18\x03 \x03(\x0b\x32\x30.build.bazel.remote.execution.v2.OutputDirectory\x12Q\n\x19output_directory_symlinks\x18\x0b \x03(\x0b\x32..build.bazel.remote.execution.v2.OutputSymlink\x12\x11\n\texit_code\x18\x04 \x01(\x05\x12\x12\n\nstdout_raw\x18\x05 \x01(\x0c\x12>\n\rstdout_digest\x18\x06 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12\x12\n\nstderr_raw\x18\x07 \x01(\x0c\x12>\n\rstderr_digest\x18\x08 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12S\n\x12\x65xecution_metadata\x18\t \x01(\x0b\x32\x37.build.bazel.remote.execution.v2.ExecutedActionMetadataJ\x04\x08\x01\x10\x02\"p\n\nOutputFile\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x37\n\x06\x64igest\x18\x02 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12\x15\n\ris_executable\x18\x04 \x01(\x08J\x04\x08\x03\x10\x04\"~\n\x04Tree\x12\x38\n\x04root\x18\x01 \x01(\x0b\x32*.build.bazel.remote.execution.v2.Directory\x12<\n\x08\x63hildren\x18\x02 \x03(\x0b\x32*.build.bazel.remote.execution.v2.Directory\"c\n\x0fOutputDirectory\x12\x0c\n\x04path\x18\x01 \x01(\t\x12<\n\x0btree_digest\x18\x03 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.DigestJ\x04\x08\x02\x10\x03\"-\n\rOutputSymlink\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x0e\n\x06target\x18\x02 \x01(\t\"#\n\x0f\x45xecutionPolicy\x12\x10\n\x08priority\x18\x01 \x01(\x05\"&\n\x12ResultsCachePolicy\x12\x10\n\x08priority\x18\x01 \x01(\x05\"\xb3\x02\n\x0e\x45xecuteRequest\x12\x15\n\rinstance_name\x18\x01 \x01(\t\x12\x19\n\x11skip_cache_lookup\x18\x03 \x01(\x08\x12>\n\raction_digest\x18\x06 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12J\n\x10\x65xecution_policy\x18\x07 \x01(\x0b\x32\x30.build.bazel.remote.execution.v2.ExecutionPolicy\x12Q\n\x14results_cache_policy\x18\x08 \x01(\x0b\x32\x33.build.bazel.remote.execution.v2.ResultsCachePolicyJ\x04\x08\x02\x10\x03J\x04\x08\x04\x10\x05J\x04\x08\x05\x10\x06\"Z\n\x07LogFile\x12\x37\n\x06\x64igest\x18\x01 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12\x16\n\x0ehuman_readable\x18\x02 \x01(\x08\"\xbf\x02\n\x0f\x45xecuteResponse\x12=\n\x06result\x18\x01 \x01(\x0b\x32-.build.bazel.remote.execution.v2.ActionResult\x12\x15\n\rcached_result\x18\x02 \x01(\x08\x12\"\n\x06status\x18\x03 \x01(\x0b\x32\x12.google.rpc.Status\x12U\n\x0bserver_logs\x18\x04 \x03(\x0b\x32@.build.bazel.remote.execution.v2.ExecuteResponse.ServerLogsEntry\x1a[\n\x0fServerLogsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x37\n\x05value\x18\x02 \x01(\x0b\x32(.build.bazel.remote.execution.v2.LogFile:\x02\x38\x01\"\xb3\x02\n\x18\x45xecuteOperationMetadata\x12N\n\x05stage\x18\x01 \x01(\x0e\x32?.build.bazel.remote.execution.v2.ExecuteOperationMetadata.Stage\x12>\n\raction_digest\x18\x02 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12\x1a\n\x12stdout_stream_name\x18\x03 \x01(\t\x12\x1a\n\x12stderr_stream_name\x18\x04 \x01(\t\"O\n\x05Stage\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x0f\n\x0b\x43\x41\x43HE_CHECK\x10\x01\x12\n\n\x06QUEUED\x10\x02\x12\r\n\tEXECUTING\x10\x03\x12\r\n\tCOMPLETED\x10\x04\"$\n\x14WaitExecutionRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"o\n\x16GetActionResultRequest\x12\x15\n\rinstance_name\x18\x01 \x01(\t\x12>\n\raction_digest\x18\x02 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\"\x8b\x02\n\x19UpdateActionResultRequest\x12\x15\n\rinstance_name\x18\x01 \x01(\t\x12>\n\raction_digest\x18\x02 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12\x44\n\raction_result\x18\x03 \x01(\x0b\x32-.build.bazel.remote.execution.v2.ActionResult\x12Q\n\x14results_cache_policy\x18\x04 \x01(\x0b\x32\x33.build.bazel.remote.execution.v2.ResultsCachePolicy\"o\n\x17\x46indMissingBlobsRequest\x12\x15\n\rinstance_name\x18\x01 \x01(\t\x12=\n\x0c\x62lob_digests\x18\x02 \x03(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\"a\n\x18\x46indMissingBlobsResponse\x12\x45\n\x14missing_blob_digests\x18\x02 \x03(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\"\xd6\x01\n\x17\x42\x61tchUpdateBlobsRequest\x12\x15\n\rinstance_name\x18\x01 \x01(\t\x12R\n\x08requests\x18\x02 \x03(\x0b\x32@.build.bazel.remote.execution.v2.BatchUpdateBlobsRequest.Request\x1aP\n\x07Request\x12\x37\n\x06\x64igest\x18\x01 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"\xda\x01\n\x18\x42\x61tchUpdateBlobsResponse\x12U\n\tresponses\x18\x01 \x03(\x0b\x32\x42.build.bazel.remote.execution.v2.BatchUpdateBlobsResponse.Response\x1ag\n\x08Response\x12\x37\n\x06\x64igest\x18\x01 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12\"\n\x06status\x18\x02 \x01(\x0b\x32\x12.google.rpc.Status\"h\n\x15\x42\x61tchReadBlobsRequest\x12\x15\n\rinstance_name\x18\x01 \x01(\t\x12\x38\n\x07\x64igests\x18\x02 \x03(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\"\xe4\x01\n\x16\x42\x61tchReadBlobsResponse\x12S\n\tresponses\x18\x01 \x03(\x0b\x32@.build.bazel.remote.execution.v2.BatchReadBlobsResponse.Response\x1au\n\x08Response\x12\x37\n\x06\x64igest\x18\x01 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\"\n\x06status\x18\x03 \x01(\x0b\x32\x12.google.rpc.Status\"\x8c\x01\n\x0eGetTreeRequest\x12\x15\n\rinstance_name\x18\x01 \x01(\t\x12<\n\x0broot_digest\x18\x02 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12\x11\n\tpage_size\x18\x03 \x01(\x05\x12\x12\n\npage_token\x18\x04 \x01(\t\"k\n\x0fGetTreeResponse\x12?\n\x0b\x64irectories\x18\x01 \x03(\x0b\x32*.build.bazel.remote.execution.v2.Directory\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\"/\n\x16GetCapabilitiesRequest\x12\x15\n\rinstance_name\x18\x01 \x01(\t\"\xe3\x02\n\x12ServerCapabilities\x12N\n\x12\x63\x61\x63he_capabilities\x18\x01 \x01(\x0b\x32\x32.build.bazel.remote.execution.v2.CacheCapabilities\x12V\n\x16\x65xecution_capabilities\x18\x02 \x01(\x0b\x32\x36.build.bazel.remote.execution.v2.ExecutionCapabilities\x12:\n\x16\x64\x65precated_api_version\x18\x03 \x01(\x0b\x32\x1a.build.bazel.semver.SemVer\x12\x33\n\x0flow_api_version\x18\x04 \x01(\x0b\x32\x1a.build.bazel.semver.SemVer\x12\x34\n\x10high_api_version\x18\x05 \x01(\x0b\x32\x1a.build.bazel.semver.SemVer\"7\n\x1d\x41\x63tionCacheUpdateCapabilities\x12\x16\n\x0eupdate_enabled\x18\x01 \x01(\x08\"\xac\x01\n\x14PriorityCapabilities\x12W\n\npriorities\x18\x01 \x03(\x0b\x32\x43.build.bazel.remote.execution.v2.PriorityCapabilities.PriorityRange\x1a;\n\rPriorityRange\x12\x14\n\x0cmin_priority\x18\x01 \x01(\x05\x12\x14\n\x0cmax_priority\x18\x02 \x01(\x05\"\x88\x04\n\x11\x43\x61\x63heCapabilities\x12H\n\x0f\x64igest_function\x18\x01 \x03(\x0e\x32/.build.bazel.remote.execution.v2.DigestFunction\x12h\n action_cache_update_capabilities\x18\x02 \x01(\x0b\x32>.build.bazel.remote.execution.v2.ActionCacheUpdateCapabilities\x12Z\n\x1b\x63\x61\x63he_priority_capabilities\x18\x03 \x01(\x0b\x32\x35.build.bazel.remote.execution.v2.PriorityCapabilities\x12\"\n\x1amax_batch_total_size_bytes\x18\x04 \x01(\x03\x12v\n\x1esymlink_absolute_path_strategy\x18\x05 \x01(\x0e\x32N.build.bazel.remote.execution.v2.CacheCapabilities.SymlinkAbsolutePathStrategy\"G\n\x1bSymlinkAbsolutePathStrategy\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x0e\n\nDISALLOWED\x10\x01\x12\x0b\n\x07\x41LLOWED\x10\x02\"\xd7\x01\n\x15\x45xecutionCapabilities\x12H\n\x0f\x64igest_function\x18\x01 \x01(\x0e\x32/.build.bazel.remote.execution.v2.DigestFunction\x12\x14\n\x0c\x65xec_enabled\x18\x02 \x01(\x08\x12^\n\x1f\x65xecution_priority_capabilities\x18\x03 \x01(\x0b\x32\x35.build.bazel.remote.execution.v2.PriorityCapabilities\"6\n\x0bToolDetails\x12\x11\n\ttool_name\x18\x01 \x01(\t\x12\x14\n\x0ctool_version\x18\x02 \x01(\t\"\xa7\x01\n\x0fRequestMetadata\x12\x42\n\x0ctool_details\x18\x01 \x01(\x0b\x32,.build.bazel.remote.execution.v2.ToolDetails\x12\x11\n\taction_id\x18\x02 \x01(\t\x12\x1a\n\x12tool_invocation_id\x18\x03 \x01(\t\x12!\n\x19\x63orrelated_invocations_id\x18\x04 \x01(\t*<\n\x0e\x44igestFunction\x12\x0b\n\x07UNKNOWN\x10\x00\x12\n\n\x06SHA256\x10\x01\x12\x08\n\x04SHA1\x10\x02\x12\x07\n\x03MD5\x10\x03\x32\xb9\x02\n\tExecution\x12\x8e\x01\n\x07\x45xecute\x12/.build.bazel.remote.execution.v2.ExecuteRequest\x1a\x1d.google.longrunning.Operation\"1\x82\xd3\xe4\x93\x02+\"&/v2/{instance_name=**}/actions:execute:\x01*0\x01\x12\x9a\x01\n\rWaitExecution\x12\x35.build.bazel.remote.execution.v2.WaitExecutionRequest\x1a\x1d.google.longrunning.Operation\"1\x82\xd3\xe4\x93\x02+\"&/v2/{name=operations/**}:waitExecution:\x01*0\x01\x32\xd6\x03\n\x0b\x41\x63tionCache\x12\xd7\x01\n\x0fGetActionResult\x12\x37.build.bazel.remote.execution.v2.GetActionResultRequest\x1a-.build.bazel.remote.execution.v2.ActionResult\"\\\x82\xd3\xe4\x93\x02V\x12T/v2/{instance_name=**}/actionResults/{action_digest.hash}/{action_digest.size_bytes}\x12\xec\x01\n\x12UpdateActionResult\x12:.build.bazel.remote.execution.v2.UpdateActionResultRequest\x1a-.build.bazel.remote.execution.v2.ActionResult\"k\x82\xd3\xe4\x93\x02\x65\x1aT/v2/{instance_name=**}/actionResults/{action_digest.hash}/{action_digest.size_bytes}:\raction_result2\x9b\x06\n\x19\x43ontentAddressableStorage\x12\xbc\x01\n\x10\x46indMissingBlobs\x12\x38.build.bazel.remote.execution.v2.FindMissingBlobsRequest\x1a\x39.build.bazel.remote.execution.v2.FindMissingBlobsResponse\"3\x82\xd3\xe4\x93\x02-\"(/v2/{instance_name=**}/blobs:findMissing:\x01*\x12\xbc\x01\n\x10\x42\x61tchUpdateBlobs\x12\x38.build.bazel.remote.execution.v2.BatchUpdateBlobsRequest\x1a\x39.build.bazel.remote.execution.v2.BatchUpdateBlobsResponse\"3\x82\xd3\xe4\x93\x02-\"(/v2/{instance_name=**}/blobs:batchUpdate:\x01*\x12\xb4\x01\n\x0e\x42\x61tchReadBlobs\x12\x36.build.bazel.remote.execution.v2.BatchReadBlobsRequest\x1a\x37.build.bazel.remote.execution.v2.BatchReadBlobsResponse\"1\x82\xd3\xe4\x93\x02+\"&/v2/{instance_name=**}/blobs:batchRead:\x01*\x12\xc8\x01\n\x07GetTree\x12/.build.bazel.remote.execution.v2.GetTreeRequest\x1a\x30.build.bazel.remote.execution.v2.GetTreeResponse\"X\x82\xd3\xe4\x93\x02R\x12P/v2/{instance_name=**}/blobs/{root_digest.hash}/{root_digest.size_bytes}:getTree0\x01\x32\xbd\x01\n\x0c\x43\x61pabilities\x12\xac\x01\n\x0fGetCapabilities\x12\x37.build.bazel.remote.execution.v2.GetCapabilitiesRequest\x1a\x33.build.bazel.remote.execution.v2.ServerCapabilities\"+\x82\xd3\xe4\x93\x02%\x12#/v2/{instance_name=**}/capabilitiesBr\n\x1f\x62uild.bazel.remote.execution.v2B\x14RemoteExecutionProtoP\x01Z\x0fremoteexecution\xa2\x02\x03REX\xaa\x02\x1f\x42uild.Bazel.Remote.Execution.V2b\x06proto3')
    
    29
    +  serialized_pb=_b('\n6build/bazel/remote/execution/v2/remote_execution.proto\x12\x1f\x62uild.bazel.remote.execution.v2\x1a\x1f\x62uild/bazel/semver/semver.proto\x1a\x1cgoogle/api/annotations.proto\x1a#google/longrunning/operations.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x17google/rpc/status.proto\"\xd5\x01\n\x06\x41\x63tion\x12?\n\x0e\x63ommand_digest\x18\x01 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12\x42\n\x11input_root_digest\x18\x02 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12*\n\x07timeout\x18\x06 \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x14\n\x0c\x64o_not_cache\x18\x07 \x01(\x08J\x04\x08\x03\x10\x06\"\xb7\x02\n\x07\x43ommand\x12\x11\n\targuments\x18\x01 \x03(\t\x12[\n\x15\x65nvironment_variables\x18\x02 \x03(\x0b\x32<.build.bazel.remote.execution.v2.Command.EnvironmentVariable\x12\x14\n\x0coutput_files\x18\x03 \x03(\t\x12\x1a\n\x12output_directories\x18\x04 \x03(\t\x12;\n\x08platform\x18\x05 \x01(\x0b\x32).build.bazel.remote.execution.v2.Platform\x12\x19\n\x11working_directory\x18\x06 \x01(\t\x1a\x32\n\x13\x45nvironmentVariable\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"{\n\x08Platform\x12\x46\n\nproperties\x18\x01 \x03(\x0b\x32\x32.build.bazel.remote.execution.v2.Platform.Property\x1a\'\n\x08Property\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"\xca\x01\n\tDirectory\x12\x38\n\x05\x66iles\x18\x01 \x03(\x0b\x32).build.bazel.remote.execution.v2.FileNode\x12\x43\n\x0b\x64irectories\x18\x02 \x03(\x0b\x32..build.bazel.remote.execution.v2.DirectoryNode\x12>\n\x08symlinks\x18\x03 \x03(\x0b\x32,.build.bazel.remote.execution.v2.SymlinkNode\"n\n\x08\x46ileNode\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x37\n\x06\x64igest\x18\x02 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12\x15\n\ris_executable\x18\x04 \x01(\x08J\x04\x08\x03\x10\x04\"V\n\rDirectoryNode\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x37\n\x06\x64igest\x18\x02 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\"+\n\x0bSymlinkNode\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06target\x18\x02 \x01(\t\"*\n\x06\x44igest\x12\x0c\n\x04hash\x18\x01 \x01(\t\x12\x12\n\nsize_bytes\x18\x02 \x01(\x03\"\xec\x04\n\x16\x45xecutedActionMetadata\x12\x0e\n\x06worker\x18\x01 \x01(\t\x12\x34\n\x10queued_timestamp\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12:\n\x16worker_start_timestamp\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12>\n\x1aworker_completed_timestamp\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12?\n\x1binput_fetch_start_timestamp\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x43\n\x1finput_fetch_completed_timestamp\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12=\n\x19\x65xecution_start_timestamp\x18\x07 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x41\n\x1d\x65xecution_completed_timestamp\x18\x08 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x41\n\x1doutput_upload_start_timestamp\x18\t \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x45\n!output_upload_completed_timestamp\x18\n \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\xd6\x04\n\x0c\x41\x63tionResult\x12\x41\n\x0coutput_files\x18\x02 \x03(\x0b\x32+.build.bazel.remote.execution.v2.OutputFile\x12L\n\x14output_file_symlinks\x18\n \x03(\x0b\x32..build.bazel.remote.execution.v2.OutputSymlink\x12L\n\x12output_directories\x18\x03 \x03(\x0b\x32\x30.build.bazel.remote.execution.v2.OutputDirectory\x12Q\n\x19output_directory_symlinks\x18\x0b \x03(\x0b\x32..build.bazel.remote.execution.v2.OutputSymlink\x12\x11\n\texit_code\x18\x04 \x01(\x05\x12\x12\n\nstdout_raw\x18\x05 \x01(\x0c\x12>\n\rstdout_digest\x18\x06 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12\x12\n\nstderr_raw\x18\x07 \x01(\x0c\x12>\n\rstderr_digest\x18\x08 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12S\n\x12\x65xecution_metadata\x18\t \x01(\x0b\x32\x37.build.bazel.remote.execution.v2.ExecutedActionMetadataJ\x04\x08\x01\x10\x02\"p\n\nOutputFile\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x37\n\x06\x64igest\x18\x02 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12\x15\n\ris_executable\x18\x04 \x01(\x08J\x04\x08\x03\x10\x04\"~\n\x04Tree\x12\x38\n\x04root\x18\x01 \x01(\x0b\x32*.build.bazel.remote.execution.v2.Directory\x12<\n\x08\x63hildren\x18\x02 \x03(\x0b\x32*.build.bazel.remote.execution.v2.Directory\"c\n\x0fOutputDirectory\x12\x0c\n\x04path\x18\x01 \x01(\t\x12<\n\x0btree_digest\x18\x03 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.DigestJ\x04\x08\x02\x10\x03\"-\n\rOutputSymlink\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x0e\n\x06target\x18\x02 \x01(\t\"#\n\x0f\x45xecutionPolicy\x12\x10\n\x08priority\x18\x01 \x01(\x05\"&\n\x12ResultsCachePolicy\x12\x10\n\x08priority\x18\x01 \x01(\x05\"\xb3\x02\n\x0e\x45xecuteRequest\x12\x15\n\rinstance_name\x18\x01 \x01(\t\x12\x19\n\x11skip_cache_lookup\x18\x03 \x01(\x08\x12>\n\raction_digest\x18\x06 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12J\n\x10\x65xecution_policy\x18\x07 \x01(\x0b\x32\x30.build.bazel.remote.execution.v2.ExecutionPolicy\x12Q\n\x14results_cache_policy\x18\x08 \x01(\x0b\x32\x33.build.bazel.remote.execution.v2.ResultsCachePolicyJ\x04\x08\x02\x10\x03J\x04\x08\x04\x10\x05J\x04\x08\x05\x10\x06\"Z\n\x07LogFile\x12\x37\n\x06\x64igest\x18\x01 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12\x16\n\x0ehuman_readable\x18\x02 \x01(\x08\"\xd0\x02\n\x0f\x45xecuteResponse\x12=\n\x06result\x18\x01 \x01(\x0b\x32-.build.bazel.remote.execution.v2.ActionResult\x12\x15\n\rcached_result\x18\x02 \x01(\x08\x12\"\n\x06status\x18\x03 \x01(\x0b\x32\x12.google.rpc.Status\x12U\n\x0bserver_logs\x18\x04 \x03(\x0b\x32@.build.bazel.remote.execution.v2.ExecuteResponse.ServerLogsEntry\x12\x0f\n\x07message\x18\x05 \x01(\t\x1a[\n\x0fServerLogsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x37\n\x05value\x18\x02 \x01(\x0b\x32(.build.bazel.remote.execution.v2.LogFile:\x02\x38\x01\"\xb3\x02\n\x18\x45xecuteOperationMetadata\x12N\n\x05stage\x18\x01 \x01(\x0e\x32?.build.bazel.remote.execution.v2.ExecuteOperationMetadata.Stage\x12>\n\raction_digest\x18\x02 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12\x1a\n\x12stdout_stream_name\x18\x03 \x01(\t\x12\x1a\n\x12stderr_stream_name\x18\x04 \x01(\t\"O\n\x05Stage\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x0f\n\x0b\x43\x41\x43HE_CHECK\x10\x01\x12\n\n\x06QUEUED\x10\x02\x12\r\n\tEXECUTING\x10\x03\x12\r\n\tCOMPLETED\x10\x04\"$\n\x14WaitExecutionRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"o\n\x16GetActionResultRequest\x12\x15\n\rinstance_name\x18\x01 \x01(\t\x12>\n\raction_digest\x18\x02 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\"\x8b\x02\n\x19UpdateActionResultRequest\x12\x15\n\rinstance_name\x18\x01 \x01(\t\x12>\n\raction_digest\x18\x02 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12\x44\n\raction_result\x18\x03 \x01(\x0b\x32-.build.bazel.remote.execution.v2.ActionResult\x12Q\n\x14results_cache_policy\x18\x04 \x01(\x0b\x32\x33.build.bazel.remote.execution.v2.ResultsCachePolicy\"o\n\x17\x46indMissingBlobsRequest\x12\x15\n\rinstance_name\x18\x01 \x01(\t\x12=\n\x0c\x62lob_digests\x18\x02 \x03(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\"a\n\x18\x46indMissingBlobsResponse\x12\x45\n\x14missing_blob_digests\x18\x02 \x03(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\"\xd6\x01\n\x17\x42\x61tchUpdateBlobsRequest\x12\x15\n\rinstance_name\x18\x01 \x01(\t\x12R\n\x08requests\x18\x02 \x03(\x0b\x32@.build.bazel.remote.execution.v2.BatchUpdateBlobsRequest.Request\x1aP\n\x07Request\x12\x37\n\x06\x64igest\x18\x01 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"\xda\x01\n\x18\x42\x61tchUpdateBlobsResponse\x12U\n\tresponses\x18\x01 \x03(\x0b\x32\x42.build.bazel.remote.execution.v2.BatchUpdateBlobsResponse.Response\x1ag\n\x08Response\x12\x37\n\x06\x64igest\x18\x01 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12\"\n\x06status\x18\x02 \x01(\x0b\x32\x12.google.rpc.Status\"h\n\x15\x42\x61tchReadBlobsRequest\x12\x15\n\rinstance_name\x18\x01 \x01(\t\x12\x38\n\x07\x64igests\x18\x02 \x03(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\"\xe4\x01\n\x16\x42\x61tchReadBlobsResponse\x12S\n\tresponses\x18\x01 \x03(\x0b\x32@.build.bazel.remote.execution.v2.BatchReadBlobsResponse.Response\x1au\n\x08Response\x12\x37\n\x06\x64igest\x18\x01 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\"\n\x06status\x18\x03 \x01(\x0b\x32\x12.google.rpc.Status\"\x8c\x01\n\x0eGetTreeRequest\x12\x15\n\rinstance_name\x18\x01 \x01(\t\x12<\n\x0broot_digest\x18\x02 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12\x11\n\tpage_size\x18\x03 \x01(\x05\x12\x12\n\npage_token\x18\x04 \x01(\t\"k\n\x0fGetTreeResponse\x12?\n\x0b\x64irectories\x18\x01 \x03(\x0b\x32*.build.bazel.remote.execution.v2.Directory\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\"/\n\x16GetCapabilitiesRequest\x12\x15\n\rinstance_name\x18\x01 \x01(\t\"\xe3\x02\n\x12ServerCapabilities\x12N\n\x12\x63\x61\x63he_capabilities\x18\x01 \x01(\x0b\x32\x32.build.bazel.remote.execution.v2.CacheCapabilities\x12V\n\x16\x65xecution_capabilities\x18\x02 \x01(\x0b\x32\x36.build.bazel.remote.execution.v2.ExecutionCapabilities\x12:\n\x16\x64\x65precated_api_version\x18\x03 \x01(\x0b\x32\x1a.build.bazel.semver.SemVer\x12\x33\n\x0flow_api_version\x18\x04 \x01(\x0b\x32\x1a.build.bazel.semver.SemVer\x12\x34\n\x10high_api_version\x18\x05 \x01(\x0b\x32\x1a.build.bazel.semver.SemVer\"7\n\x1d\x41\x63tionCacheUpdateCapabilities\x12\x16\n\x0eupdate_enabled\x18\x01 \x01(\x08\"\xac\x01\n\x14PriorityCapabilities\x12W\n\npriorities\x18\x01 \x03(\x0b\x32\x43.build.bazel.remote.execution.v2.PriorityCapabilities.PriorityRange\x1a;\n\rPriorityRange\x12\x14\n\x0cmin_priority\x18\x01 \x01(\x05\x12\x14\n\x0cmax_priority\x18\x02 \x01(\x05\"\x88\x04\n\x11\x43\x61\x63heCapabilities\x12H\n\x0f\x64igest_function\x18\x01 \x03(\x0e\x32/.build.bazel.remote.execution.v2.DigestFunction\x12h\n action_cache_update_capabilities\x18\x02 \x01(\x0b\x32>.build.bazel.remote.execution.v2.ActionCacheUpdateCapabilities\x12Z\n\x1b\x63\x61\x63he_priority_capabilities\x18\x03 \x01(\x0b\x32\x35.build.bazel.remote.execution.v2.PriorityCapabilities\x12\"\n\x1amax_batch_total_size_bytes\x18\x04 \x01(\x03\x12v\n\x1esymlink_absolute_path_strategy\x18\x05 \x01(\x0e\x32N.build.bazel.remote.execution.v2.CacheCapabilities.SymlinkAbsolutePathStrategy\"G\n\x1bSymlinkAbsolutePathStrategy\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x0e\n\nDISALLOWED\x10\x01\x12\x0b\n\x07\x41LLOWED\x10\x02\"\xd7\x01\n\x15\x45xecutionCapabilities\x12H\n\x0f\x64igest_function\x18\x01 \x01(\x0e\x32/.build.bazel.remote.execution.v2.DigestFunction\x12\x14\n\x0c\x65xec_enabled\x18\x02 \x01(\x08\x12^\n\x1f\x65xecution_priority_capabilities\x18\x03 \x01(\x0b\x32\x35.build.bazel.remote.execution.v2.PriorityCapabilities\"6\n\x0bToolDetails\x12\x11\n\ttool_name\x18\x01 \x01(\t\x12\x14\n\x0ctool_version\x18\x02 \x01(\t\"\xa7\x01\n\x0fRequestMetadata\x12\x42\n\x0ctool_details\x18\x01 \x01(\x0b\x32,.build.bazel.remote.execution.v2.ToolDetails\x12\x11\n\taction_id\x18\x02 \x01(\t\x12\x1a\n\x12tool_invocation_id\x18\x03 \x01(\t\x12!\n\x19\x63orrelated_invocations_id\x18\x04 \x01(\t*<\n\x0e\x44igestFunction\x12\x0b\n\x07UNKNOWN\x10\x00\x12\n\n\x06SHA256\x10\x01\x12\x08\n\x04SHA1\x10\x02\x12\x07\n\x03MD5\x10\x03\x32\xb9\x02\n\tExecution\x12\x8e\x01\n\x07\x45xecute\x12/.build.bazel.remote.execution.v2.ExecuteRequest\x1a\x1d.google.longrunning.Operation\"1\x82\xd3\xe4\x93\x02+\"&/v2/{instance_name=**}/actions:execute:\x01*0\x01\x12\x9a\x01\n\rWaitExecution\x12\x35.build.bazel.remote.execution.v2.WaitExecutionRequest\x1a\x1d.google.longrunning.Operation\"1\x82\xd3\xe4\x93\x02+\"&/v2/{name=operations/**}:waitExecution:\x01*0\x01\x32\xd6\x03\n\x0b\x41\x63tionCache\x12\xd7\x01\n\x0fGetActionResult\x12\x37.build.bazel.remote.execution.v2.GetActionResultRequest\x1a-.build.bazel.remote.execution.v2.ActionResult\"\\\x82\xd3\xe4\x93\x02V\x12T/v2/{instance_name=**}/actionResults/{action_digest.hash}/{action_digest.size_bytes}\x12\xec\x01\n\x12UpdateActionResult\x12:.build.bazel.remote.execution.v2.UpdateActionResultRequest\x1a-.build.bazel.remote.execution.v2.ActionResult\"k\x82\xd3\xe4\x93\x02\x65\x1aT/v2/{instance_name=**}/actionResults/{action_digest.hash}/{action_digest.size_bytes}:\raction_result2\x9b\x06\n\x19\x43ontentAddressableStorage\x12\xbc\x01\n\x10\x46indMissingBlobs\x12\x38.build.bazel.remote.execution.v2.FindMissingBlobsRequest\x1a\x39.build.bazel.remote.execution.v2.FindMissingBlobsResponse\"3\x82\xd3\xe4\x93\x02-\"(/v2/{instance_name=**}/blobs:findMissing:\x01*\x12\xbc\x01\n\x10\x42\x61tchUpdateBlobs\x12\x38.build.bazel.remote.execution.v2.BatchUpdateBlobsRequest\x1a\x39.build.bazel.remote.execution.v2.BatchUpdateBlobsResponse\"3\x82\xd3\xe4\x93\x02-\"(/v2/{instance_name=**}/blobs:batchUpdate:\x01*\x12\xb4\x01\n\x0e\x42\x61tchReadBlobs\x12\x36.build.bazel.remote.execution.v2.BatchReadBlobsRequest\x1a\x37.build.bazel.remote.execution.v2.BatchReadBlobsResponse\"1\x82\xd3\xe4\x93\x02+\"&/v2/{instance_name=**}/blobs:batchRead:\x01*\x12\xc8\x01\n\x07GetTree\x12/.build.bazel.remote.execution.v2.GetTreeRequest\x1a\x30.build.bazel.remote.execution.v2.GetTreeResponse\"X\x82\xd3\xe4\x93\x02R\x12P/v2/{instance_name=**}/blobs/{root_digest.hash}/{root_digest.size_bytes}:getTree0\x01\x32\xbd\x01\n\x0c\x43\x61pabilities\x12\xac\x01\n\x0fGetCapabilities\x12\x37.build.bazel.remote.execution.v2.GetCapabilitiesRequest\x1a\x33.build.bazel.remote.execution.v2.ServerCapabilities\"+\x82\xd3\xe4\x93\x02%\x12#/v2/{instance_name=**}/capabilitiesBr\n\x1f\x62uild.bazel.remote.execution.v2B\x14RemoteExecutionProtoP\x01Z\x0fremoteexecution\xa2\x02\x03REX\xaa\x02\x1f\x42uild.Bazel.Remote.Execution.V2b\x06proto3')
    
    30 30
       ,
    
    31 31
       dependencies=[build_dot_bazel_dot_semver_dot_semver__pb2.DESCRIPTOR,google_dot_api_dot_annotations__pb2.DESCRIPTOR,google_dot_longrunning_dot_operations__pb2.DESCRIPTOR,google_dot_protobuf_dot_duration__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,google_dot_rpc_dot_status__pb2.DESCRIPTOR,])
    
    32 32
     
    
    ... ... @@ -55,8 +55,8 @@ _DIGESTFUNCTION = _descriptor.EnumDescriptor(
    55 55
       ],
    
    56 56
       containing_type=None,
    
    57 57
       serialized_options=None,
    
    58
    -  serialized_start=7421,
    
    59
    -  serialized_end=7481,
    
    58
    +  serialized_start=7438,
    
    59
    +  serialized_end=7498,
    
    60 60
     )
    
    61 61
     _sym_db.RegisterEnumDescriptor(_DIGESTFUNCTION)
    
    62 62
     
    
    ... ... @@ -96,8 +96,8 @@ _EXECUTEOPERATIONMETADATA_STAGE = _descriptor.EnumDescriptor(
    96 96
       ],
    
    97 97
       containing_type=None,
    
    98 98
       serialized_options=None,
    
    99
    -  serialized_start=4074,
    
    100
    -  serialized_end=4153,
    
    99
    +  serialized_start=4091,
    
    100
    +  serialized_end=4170,
    
    101 101
     )
    
    102 102
     _sym_db.RegisterEnumDescriptor(_EXECUTEOPERATIONMETADATA_STAGE)
    
    103 103
     
    
    ... ... @@ -122,8 +122,8 @@ _CACHECAPABILITIES_SYMLINKABSOLUTEPATHSTRATEGY = _descriptor.EnumDescriptor(
    122 122
       ],
    
    123 123
       containing_type=None,
    
    124 124
       serialized_options=None,
    
    125
    -  serialized_start=6904,
    
    126
    -  serialized_end=6975,
    
    125
    +  serialized_start=6921,
    
    126
    +  serialized_end=6992,
    
    127 127
     )
    
    128 128
     _sym_db.RegisterEnumDescriptor(_CACHECAPABILITIES_SYMLINKABSOLUTEPATHSTRATEGY)
    
    129 129
     
    
    ... ... @@ -1094,8 +1094,8 @@ _EXECUTERESPONSE_SERVERLOGSENTRY = _descriptor.Descriptor(
    1094 1094
       extension_ranges=[],
    
    1095 1095
       oneofs=[
    
    1096 1096
       ],
    
    1097
    -  serialized_start=3752,
    
    1098
    -  serialized_end=3843,
    
    1097
    +  serialized_start=3769,
    
    1098
    +  serialized_end=3860,
    
    1099 1099
     )
    
    1100 1100
     
    
    1101 1101
     _EXECUTERESPONSE = _descriptor.Descriptor(
    
    ... ... @@ -1133,6 +1133,13 @@ _EXECUTERESPONSE = _descriptor.Descriptor(
    1133 1133
           message_type=None, enum_type=None, containing_type=None,
    
    1134 1134
           is_extension=False, extension_scope=None,
    
    1135 1135
           serialized_options=None, file=DESCRIPTOR),
    
    1136
    +    _descriptor.FieldDescriptor(
    
    1137
    +      name='message', full_name='build.bazel.remote.execution.v2.ExecuteResponse.message', index=4,
    
    1138
    +      number=5, type=9, cpp_type=9, label=1,
    
    1139
    +      has_default_value=False, default_value=_b("").decode('utf-8'),
    
    1140
    +      message_type=None, enum_type=None, containing_type=None,
    
    1141
    +      is_extension=False, extension_scope=None,
    
    1142
    +      serialized_options=None, file=DESCRIPTOR),
    
    1136 1143
       ],
    
    1137 1144
       extensions=[
    
    1138 1145
       ],
    
    ... ... @@ -1146,7 +1153,7 @@ _EXECUTERESPONSE = _descriptor.Descriptor(
    1146 1153
       oneofs=[
    
    1147 1154
       ],
    
    1148 1155
       serialized_start=3524,
    
    1149
    -  serialized_end=3843,
    
    1156
    +  serialized_end=3860,
    
    1150 1157
     )
    
    1151 1158
     
    
    1152 1159
     
    
    ... ... @@ -1198,8 +1205,8 @@ _EXECUTEOPERATIONMETADATA = _descriptor.Descriptor(
    1198 1205
       extension_ranges=[],
    
    1199 1206
       oneofs=[
    
    1200 1207
       ],
    
    1201
    -  serialized_start=3846,
    
    1202
    -  serialized_end=4153,
    
    1208
    +  serialized_start=3863,
    
    1209
    +  serialized_end=4170,
    
    1203 1210
     )
    
    1204 1211
     
    
    1205 1212
     
    
    ... ... @@ -1229,8 +1236,8 @@ _WAITEXECUTIONREQUEST = _descriptor.Descriptor(
    1229 1236
       extension_ranges=[],
    
    1230 1237
       oneofs=[
    
    1231 1238
       ],
    
    1232
    -  serialized_start=4155,
    
    1233
    -  serialized_end=4191,
    
    1239
    +  serialized_start=4172,
    
    1240
    +  serialized_end=4208,
    
    1234 1241
     )
    
    1235 1242
     
    
    1236 1243
     
    
    ... ... @@ -1267,8 +1274,8 @@ _GETACTIONRESULTREQUEST = _descriptor.Descriptor(
    1267 1274
       extension_ranges=[],
    
    1268 1275
       oneofs=[
    
    1269 1276
       ],
    
    1270
    -  serialized_start=4193,
    
    1271
    -  serialized_end=4304,
    
    1277
    +  serialized_start=4210,
    
    1278
    +  serialized_end=4321,
    
    1272 1279
     )
    
    1273 1280
     
    
    1274 1281
     
    
    ... ... @@ -1319,8 +1326,8 @@ _UPDATEACTIONRESULTREQUEST = _descriptor.Descriptor(
    1319 1326
       extension_ranges=[],
    
    1320 1327
       oneofs=[
    
    1321 1328
       ],
    
    1322
    -  serialized_start=4307,
    
    1323
    -  serialized_end=4574,
    
    1329
    +  serialized_start=4324,
    
    1330
    +  serialized_end=4591,
    
    1324 1331
     )
    
    1325 1332
     
    
    1326 1333
     
    
    ... ... @@ -1357,8 +1364,8 @@ _FINDMISSINGBLOBSREQUEST = _descriptor.Descriptor(
    1357 1364
       extension_ranges=[],
    
    1358 1365
       oneofs=[
    
    1359 1366
       ],
    
    1360
    -  serialized_start=4576,
    
    1361
    -  serialized_end=4687,
    
    1367
    +  serialized_start=4593,
    
    1368
    +  serialized_end=4704,
    
    1362 1369
     )
    
    1363 1370
     
    
    1364 1371
     
    
    ... ... @@ -1388,8 +1395,8 @@ _FINDMISSINGBLOBSRESPONSE = _descriptor.Descriptor(
    1388 1395
       extension_ranges=[],
    
    1389 1396
       oneofs=[
    
    1390 1397
       ],
    
    1391
    -  serialized_start=4689,
    
    1392
    -  serialized_end=4786,
    
    1398
    +  serialized_start=4706,
    
    1399
    +  serialized_end=4803,
    
    1393 1400
     )
    
    1394 1401
     
    
    1395 1402
     
    
    ... ... @@ -1426,8 +1433,8 @@ _BATCHUPDATEBLOBSREQUEST_REQUEST = _descriptor.Descriptor(
    1426 1433
       extension_ranges=[],
    
    1427 1434
       oneofs=[
    
    1428 1435
       ],
    
    1429
    -  serialized_start=4923,
    
    1430
    -  serialized_end=5003,
    
    1436
    +  serialized_start=4940,
    
    1437
    +  serialized_end=5020,
    
    1431 1438
     )
    
    1432 1439
     
    
    1433 1440
     _BATCHUPDATEBLOBSREQUEST = _descriptor.Descriptor(
    
    ... ... @@ -1463,8 +1470,8 @@ _BATCHUPDATEBLOBSREQUEST = _descriptor.Descriptor(
    1463 1470
       extension_ranges=[],
    
    1464 1471
       oneofs=[
    
    1465 1472
       ],
    
    1466
    -  serialized_start=4789,
    
    1467
    -  serialized_end=5003,
    
    1473
    +  serialized_start=4806,
    
    1474
    +  serialized_end=5020,
    
    1468 1475
     )
    
    1469 1476
     
    
    1470 1477
     
    
    ... ... @@ -1501,8 +1508,8 @@ _BATCHUPDATEBLOBSRESPONSE_RESPONSE = _descriptor.Descriptor(
    1501 1508
       extension_ranges=[],
    
    1502 1509
       oneofs=[
    
    1503 1510
       ],
    
    1504
    -  serialized_start=5121,
    
    1505
    -  serialized_end=5224,
    
    1511
    +  serialized_start=5138,
    
    1512
    +  serialized_end=5241,
    
    1506 1513
     )
    
    1507 1514
     
    
    1508 1515
     _BATCHUPDATEBLOBSRESPONSE = _descriptor.Descriptor(
    
    ... ... @@ -1531,8 +1538,8 @@ _BATCHUPDATEBLOBSRESPONSE = _descriptor.Descriptor(
    1531 1538
       extension_ranges=[],
    
    1532 1539
       oneofs=[
    
    1533 1540
       ],
    
    1534
    -  serialized_start=5006,
    
    1535
    -  serialized_end=5224,
    
    1541
    +  serialized_start=5023,
    
    1542
    +  serialized_end=5241,
    
    1536 1543
     )
    
    1537 1544
     
    
    1538 1545
     
    
    ... ... @@ -1569,8 +1576,8 @@ _BATCHREADBLOBSREQUEST = _descriptor.Descriptor(
    1569 1576
       extension_ranges=[],
    
    1570 1577
       oneofs=[
    
    1571 1578
       ],
    
    1572
    -  serialized_start=5226,
    
    1573
    -  serialized_end=5330,
    
    1579
    +  serialized_start=5243,
    
    1580
    +  serialized_end=5347,
    
    1574 1581
     )
    
    1575 1582
     
    
    1576 1583
     
    
    ... ... @@ -1614,8 +1621,8 @@ _BATCHREADBLOBSRESPONSE_RESPONSE = _descriptor.Descriptor(
    1614 1621
       extension_ranges=[],
    
    1615 1622
       oneofs=[
    
    1616 1623
       ],
    
    1617
    -  serialized_start=5444,
    
    1618
    -  serialized_end=5561,
    
    1624
    +  serialized_start=5461,
    
    1625
    +  serialized_end=5578,
    
    1619 1626
     )
    
    1620 1627
     
    
    1621 1628
     _BATCHREADBLOBSRESPONSE = _descriptor.Descriptor(
    
    ... ... @@ -1644,8 +1651,8 @@ _BATCHREADBLOBSRESPONSE = _descriptor.Descriptor(
    1644 1651
       extension_ranges=[],
    
    1645 1652
       oneofs=[
    
    1646 1653
       ],
    
    1647
    -  serialized_start=5333,
    
    1648
    -  serialized_end=5561,
    
    1654
    +  serialized_start=5350,
    
    1655
    +  serialized_end=5578,
    
    1649 1656
     )
    
    1650 1657
     
    
    1651 1658
     
    
    ... ... @@ -1696,8 +1703,8 @@ _GETTREEREQUEST = _descriptor.Descriptor(
    1696 1703
       extension_ranges=[],
    
    1697 1704
       oneofs=[
    
    1698 1705
       ],
    
    1699
    -  serialized_start=5564,
    
    1700
    -  serialized_end=5704,
    
    1706
    +  serialized_start=5581,
    
    1707
    +  serialized_end=5721,
    
    1701 1708
     )
    
    1702 1709
     
    
    1703 1710
     
    
    ... ... @@ -1734,8 +1741,8 @@ _GETTREERESPONSE = _descriptor.Descriptor(
    1734 1741
       extension_ranges=[],
    
    1735 1742
       oneofs=[
    
    1736 1743
       ],
    
    1737
    -  serialized_start=5706,
    
    1738
    -  serialized_end=5813,
    
    1744
    +  serialized_start=5723,
    
    1745
    +  serialized_end=5830,
    
    1739 1746
     )
    
    1740 1747
     
    
    1741 1748
     
    
    ... ... @@ -1765,8 +1772,8 @@ _GETCAPABILITIESREQUEST = _descriptor.Descriptor(
    1765 1772
       extension_ranges=[],
    
    1766 1773
       oneofs=[
    
    1767 1774
       ],
    
    1768
    -  serialized_start=5815,
    
    1769
    -  serialized_end=5862,
    
    1775
    +  serialized_start=5832,
    
    1776
    +  serialized_end=5879,
    
    1770 1777
     )
    
    1771 1778
     
    
    1772 1779
     
    
    ... ... @@ -1824,8 +1831,8 @@ _SERVERCAPABILITIES = _descriptor.Descriptor(
    1824 1831
       extension_ranges=[],
    
    1825 1832
       oneofs=[
    
    1826 1833
       ],
    
    1827
    -  serialized_start=5865,
    
    1828
    -  serialized_end=6220,
    
    1834
    +  serialized_start=5882,
    
    1835
    +  serialized_end=6237,
    
    1829 1836
     )
    
    1830 1837
     
    
    1831 1838
     
    
    ... ... @@ -1855,8 +1862,8 @@ _ACTIONCACHEUPDATECAPABILITIES = _descriptor.Descriptor(
    1855 1862
       extension_ranges=[],
    
    1856 1863
       oneofs=[
    
    1857 1864
       ],
    
    1858
    -  serialized_start=6222,
    
    1859
    -  serialized_end=6277,
    
    1865
    +  serialized_start=6239,
    
    1866
    +  serialized_end=6294,
    
    1860 1867
     )
    
    1861 1868
     
    
    1862 1869
     
    
    ... ... @@ -1893,8 +1900,8 @@ _PRIORITYCAPABILITIES_PRIORITYRANGE = _descriptor.Descriptor(
    1893 1900
       extension_ranges=[],
    
    1894 1901
       oneofs=[
    
    1895 1902
       ],
    
    1896
    -  serialized_start=6393,
    
    1897
    -  serialized_end=6452,
    
    1903
    +  serialized_start=6410,
    
    1904
    +  serialized_end=6469,
    
    1898 1905
     )
    
    1899 1906
     
    
    1900 1907
     _PRIORITYCAPABILITIES = _descriptor.Descriptor(
    
    ... ... @@ -1923,8 +1930,8 @@ _PRIORITYCAPABILITIES = _descriptor.Descriptor(
    1923 1930
       extension_ranges=[],
    
    1924 1931
       oneofs=[
    
    1925 1932
       ],
    
    1926
    -  serialized_start=6280,
    
    1927
    -  serialized_end=6452,
    
    1933
    +  serialized_start=6297,
    
    1934
    +  serialized_end=6469,
    
    1928 1935
     )
    
    1929 1936
     
    
    1930 1937
     
    
    ... ... @@ -1983,8 +1990,8 @@ _CACHECAPABILITIES = _descriptor.Descriptor(
    1983 1990
       extension_ranges=[],
    
    1984 1991
       oneofs=[
    
    1985 1992
       ],
    
    1986
    -  serialized_start=6455,
    
    1987
    -  serialized_end=6975,
    
    1993
    +  serialized_start=6472,
    
    1994
    +  serialized_end=6992,
    
    1988 1995
     )
    
    1989 1996
     
    
    1990 1997
     
    
    ... ... @@ -2028,8 +2035,8 @@ _EXECUTIONCAPABILITIES = _descriptor.Descriptor(
    2028 2035
       extension_ranges=[],
    
    2029 2036
       oneofs=[
    
    2030 2037
       ],
    
    2031
    -  serialized_start=6978,
    
    2032
    -  serialized_end=7193,
    
    2038
    +  serialized_start=6995,
    
    2039
    +  serialized_end=7210,
    
    2033 2040
     )
    
    2034 2041
     
    
    2035 2042
     
    
    ... ... @@ -2066,8 +2073,8 @@ _TOOLDETAILS = _descriptor.Descriptor(
    2066 2073
       extension_ranges=[],
    
    2067 2074
       oneofs=[
    
    2068 2075
       ],
    
    2069
    -  serialized_start=7195,
    
    2070
    -  serialized_end=7249,
    
    2076
    +  serialized_start=7212,
    
    2077
    +  serialized_end=7266,
    
    2071 2078
     )
    
    2072 2079
     
    
    2073 2080
     
    
    ... ... @@ -2118,8 +2125,8 @@ _REQUESTMETADATA = _descriptor.Descriptor(
    2118 2125
       extension_ranges=[],
    
    2119 2126
       oneofs=[
    
    2120 2127
       ],
    
    2121
    -  serialized_start=7252,
    
    2122
    -  serialized_end=7419,
    
    2128
    +  serialized_start=7269,
    
    2129
    +  serialized_end=7436,
    
    2123 2130
     )
    
    2124 2131
     
    
    2125 2132
     _ACTION.fields_by_name['command_digest'].message_type = _DIGEST
    
    ... ... @@ -2583,8 +2590,8 @@ _EXECUTION = _descriptor.ServiceDescriptor(
    2583 2590
       file=DESCRIPTOR,
    
    2584 2591
       index=0,
    
    2585 2592
       serialized_options=None,
    
    2586
    -  serialized_start=7484,
    
    2587
    -  serialized_end=7797,
    
    2593
    +  serialized_start=7501,
    
    2594
    +  serialized_end=7814,
    
    2588 2595
       methods=[
    
    2589 2596
       _descriptor.MethodDescriptor(
    
    2590 2597
         name='Execute',
    
    ... ... @@ -2616,8 +2623,8 @@ _ACTIONCACHE = _descriptor.ServiceDescriptor(
    2616 2623
       file=DESCRIPTOR,
    
    2617 2624
       index=1,
    
    2618 2625
       serialized_options=None,
    
    2619
    -  serialized_start=7800,
    
    2620
    -  serialized_end=8270,
    
    2626
    +  serialized_start=7817,
    
    2627
    +  serialized_end=8287,
    
    2621 2628
       methods=[
    
    2622 2629
       _descriptor.MethodDescriptor(
    
    2623 2630
         name='GetActionResult',
    
    ... ... @@ -2649,8 +2656,8 @@ _CONTENTADDRESSABLESTORAGE = _descriptor.ServiceDescriptor(
    2649 2656
       file=DESCRIPTOR,
    
    2650 2657
       index=2,
    
    2651 2658
       serialized_options=None,
    
    2652
    -  serialized_start=8273,
    
    2653
    -  serialized_end=9068,
    
    2659
    +  serialized_start=8290,
    
    2660
    +  serialized_end=9085,
    
    2654 2661
       methods=[
    
    2655 2662
       _descriptor.MethodDescriptor(
    
    2656 2663
         name='FindMissingBlobs',
    
    ... ... @@ -2700,8 +2707,8 @@ _CAPABILITIES = _descriptor.ServiceDescriptor(
    2700 2707
       file=DESCRIPTOR,
    
    2701 2708
       index=3,
    
    2702 2709
       serialized_options=None,
    
    2703
    -  serialized_start=9071,
    
    2704
    -  serialized_end=9260,
    
    2710
    +  serialized_start=9088,
    
    2711
    +  serialized_end=9277,
    
    2705 2712
       methods=[
    
    2706 2713
       _descriptor.MethodDescriptor(
    
    2707 2714
         name='GetCapabilities',
    

  • buildgrid/_protos/build/bazel/remote/execution/v2/remote_execution_pb2_grpc.py
    ... ... @@ -87,6 +87,7 @@ class ExecutionServicer(object):
    87 87
         action will be reported in the `status` field of the `ExecuteResponse`. The
    
    88 88
         server MUST NOT set the `error` field of the `Operation` proto.
    
    89 89
         The possible errors include:
    
    90
    +
    
    90 91
         * `INVALID_ARGUMENT`: One or more arguments are invalid.
    
    91 92
         * `FAILED_PRECONDITION`: One or more errors occurred in setting up the
    
    92 93
         action requested, such as a missing input or command or no worker being
    
    ... ... @@ -210,6 +211,7 @@ class ActionCacheServicer(object):
    210 211
         """Retrieve a cached execution result.
    
    211 212
     
    
    212 213
         Errors:
    
    214
    +
    
    213 215
         * `NOT_FOUND`: The requested `ActionResult` is not in the cache.
    
    214 216
         """
    
    215 217
         context.set_code(grpc.StatusCode.UNIMPLEMENTED)
    
    ... ... @@ -219,11 +221,6 @@ class ActionCacheServicer(object):
    219 221
       def UpdateActionResult(self, request, context):
    
    220 222
         """Upload a new execution result.
    
    221 223
     
    
    222
    -    This method is intended for servers which implement the distributed cache
    
    223
    -    independently of the
    
    224
    -    [Execution][build.bazel.remote.execution.v2.Execution] API. As a
    
    225
    -    result, it is OPTIONAL for servers to implement.
    
    226
    -
    
    227 224
         In order to allow the server to perform access control based on the type of
    
    228 225
         action, and to assist with client debugging, the client MUST first upload
    
    229 226
         the [Action][build.bazel.remote.execution.v2.Execution] that produced the
    
    ... ... @@ -232,7 +229,10 @@ class ActionCacheServicer(object):
    232 229
         `ContentAddressableStorage`.
    
    233 230
     
    
    234 231
         Errors:
    
    235
    -    * `UNIMPLEMENTED`: This method is not supported by the server.
    
    232
    +
    
    233
    +    * `INVALID_ARGUMENT`: One or more arguments are invalid.
    
    234
    +    * `FAILED_PRECONDITION`: One or more errors occurred in updating the
    
    235
    +    action result, such as a missing command or action.
    
    236 236
         * `RESOURCE_EXHAUSTED`: There is insufficient storage space to add the
    
    237 237
         entry to the cache.
    
    238 238
         """
    
    ... ... @@ -299,6 +299,9 @@ class ContentAddressableStorageStub(object):
    299 299
       by the server. For servers which do not support multiple instances, then the
    
    300 300
       `instance_name` is the empty path and the leading slash is omitted, so that
    
    301 301
       the `resource_name` becomes `uploads/{uuid}/blobs/{hash}/{size}`.
    
    302
    +  To simplify parsing, a path segment cannot equal any of the following
    
    303
    +  keywords: `blobs`, `uploads`, `actions`, `actionResults`, `operations` and
    
    304
    +  `capabilities`.
    
    302 305
     
    
    303 306
       When attempting an upload, if another client has already completed the upload
    
    304 307
       (which may occur in the middle of a single upload if another client uploads
    
    ... ... @@ -395,6 +398,9 @@ class ContentAddressableStorageServicer(object):
    395 398
       by the server. For servers which do not support multiple instances, then the
    
    396 399
       `instance_name` is the empty path and the leading slash is omitted, so that
    
    397 400
       the `resource_name` becomes `uploads/{uuid}/blobs/{hash}/{size}`.
    
    401
    +  To simplify parsing, a path segment cannot equal any of the following
    
    402
    +  keywords: `blobs`, `uploads`, `actions`, `actionResults`, `operations` and
    
    403
    +  `capabilities`.
    
    398 404
     
    
    399 405
       When attempting an upload, if another client has already completed the upload
    
    400 406
       (which may occur in the middle of a single upload if another client uploads
    
    ... ... @@ -450,10 +456,12 @@ class ContentAddressableStorageServicer(object):
    450 456
         independently.
    
    451 457
     
    
    452 458
         Errors:
    
    459
    +
    
    453 460
         * `INVALID_ARGUMENT`: The client attempted to upload more than the
    
    454 461
         server supported limit.
    
    455 462
     
    
    456 463
         Individual requests may return the following errors, additionally:
    
    464
    +
    
    457 465
         * `RESOURCE_EXHAUSTED`: There is insufficient disk quota to store the blob.
    
    458 466
         * `INVALID_ARGUMENT`: The
    
    459 467
         [Digest][build.bazel.remote.execution.v2.Digest] does not match the
    
    ... ... @@ -478,6 +486,7 @@ class ContentAddressableStorageServicer(object):
    478 486
         independently.
    
    479 487
     
    
    480 488
         Errors:
    
    489
    +
    
    481 490
         * `INVALID_ARGUMENT`: The client attempted to read more than the
    
    482 491
         server supported limit.
    
    483 492
     
    

  • buildgrid/_protos/build/bazel/semver/semver.proto
    ... ... @@ -23,9 +23,19 @@ option java_outer_classname = "SemverProto";
    23 23
     option java_package = "build.bazel.semver";
    
    24 24
     option objc_class_prefix = "SMV";
    
    25 25
     
    
    26
    +// The full version of a given tool.
    
    26 27
     message SemVer {
    
    28
    +  // The major version, e.g 10 for 10.2.3.
    
    27 29
       int32 major = 1;
    
    30
    +
    
    31
    +  // The minor version, e.g. 2 for 10.2.3.
    
    28 32
       int32 minor = 2;
    
    33
    +
    
    34
    +  // The patch version, e.g 3 for 10.2.3.
    
    29 35
       int32 patch = 3;
    
    36
    +
    
    37
    +  // The pre-release version. Either this field or major/minor/patch fields
    
    38
    +  // must be filled. They are mutually exclusive. Pre-release versions are
    
    39
    +  // assumed to be earlier than any released versions.
    
    30 40
       string prerelease = 4;
    
    31 41
     }

  • buildgrid/server/bots/instance.py
    ... ... @@ -50,7 +50,6 @@ class BotsInterface:
    50 50
             register with the service, the old one should be closed along
    
    51 51
             with all its jobs.
    
    52 52
             """
    
    53
    -
    
    54 53
             bot_id = bot_session.bot_id
    
    55 54
     
    
    56 55
             if bot_id == "":
    
    ... ... @@ -100,10 +99,25 @@ class BotsInterface:
    100 99
             return bot_session
    
    101 100
     
    
    102 101
         def _request_leases(self, bot_session):
    
    103
    -        # TODO: Send worker capabilities to the scheduler!
    
    104 102
             # Only send one lease at a time currently.
    
    105 103
             if not bot_session.leases:
    
    106
    -            leases = self._scheduler.request_job_leases({})
    
    104
    +            worker_capabilities = {}
    
    105
    +
    
    106
    +            # TODO? Fail if there are no devices in the worker?
    
    107
    +            if bot_session.worker.devices:
    
    108
    +                # According to the spec:
    
    109
    +                #   "The first device in the worker is the "primary device" -
    
    110
    +                #   that is, the device running a bot and which is
    
    111
    +                #   responsible for actually executing commands."
    
    112
    +                primary_device = bot_session.worker.devices[0]
    
    113
    +
    
    114
    +                for device_property in primary_device.properties:
    
    115
    +                    if device_property.key not in worker_capabilities:
    
    116
    +                        worker_capabilities[device_property.key] = set()
    
    117
    +                    worker_capabilities[device_property.key].add(device_property.value)
    
    118
    +
    
    119
    +            leases = self._scheduler.request_job_leases(worker_capabilities)
    
    120
    +
    
    107 121
                 if leases:
    
    108 122
                     for lease in leases:
    
    109 123
                         self._assigned_leases[bot_session.name].add(lease.id)
    

  • buildgrid/server/controller.py
    ... ... @@ -36,7 +36,7 @@ from .operations.instance import OperationsInstance
    36 36
     
    
    37 37
     class ExecutionController:
    
    38 38
     
    
    39
    -    def __init__(self, action_cache=None, storage=None):
    
    39
    +    def __init__(self, storage=None, action_cache=None, action_browser_url=None):
    
    40 40
             self.__logger = logging.getLogger(__name__)
    
    41 41
     
    
    42 42
             scheduler = Scheduler(action_cache)
    

  • buildgrid/server/execution/instance.py
    ... ... @@ -22,7 +22,7 @@ An instance of the Remote Execution Service.
    22 22
     import logging
    
    23 23
     
    
    24 24
     from buildgrid._exceptions import FailedPreconditionError, InvalidArgumentError, NotFoundError
    
    25
    -from buildgrid._protos.build.bazel.remote.execution.v2.remote_execution_pb2 import Action
    
    25
    +from buildgrid._protos.build.bazel.remote.execution.v2.remote_execution_pb2 import Action, Command
    
    26 26
     from buildgrid.utils import get_hash_type
    
    27 27
     
    
    28 28
     
    
    ... ... @@ -50,11 +50,22 @@ class ExecutionInstance:
    50 50
             this action.
    
    51 51
             """
    
    52 52
             action = self._storage.get_message(action_digest, Action)
    
    53
    -
    
    54 53
             if not action:
    
    55 54
                 raise FailedPreconditionError("Could not get action from storage.")
    
    56 55
     
    
    56
    +        command = self._storage.get_message(action.command_digest, Command)
    
    57
    +
    
    58
    +        if not command:
    
    59
    +            raise FailedPreconditionError("Could not get command from storage.")
    
    60
    +
    
    61
    +        platform_requirements = {}
    
    62
    +        for platform_property in command.platform.properties:
    
    63
    +            if platform_property.name not in platform_requirements:
    
    64
    +                platform_requirements[platform_property.name] = set()
    
    65
    +            platform_requirements[platform_property.name].add(platform_property.value)
    
    66
    +
    
    57 67
             return self._scheduler.queue_job_action(action, action_digest,
    
    68
    +                                                platform_requirements=platform_requirements,
    
    58 69
                                                     skip_cache_lookup=skip_cache_lookup)
    
    59 70
     
    
    60 71
         def register_job_peer(self, job_name, peer, message_queue):
    

  • buildgrid/server/job.py
    ... ... @@ -29,7 +29,7 @@ from buildgrid._protos.google.rpc import code_pb2
    29 29
     
    
    30 30
     class Job:
    
    31 31
     
    
    32
    -    def __init__(self, action, action_digest, priority=0):
    
    32
    +    def __init__(self, action, action_digest, platform_requirements=None, priority=0):
    
    33 33
             self.__logger = logging.getLogger(__name__)
    
    34 34
     
    
    35 35
             self._name = str(uuid.uuid4())
    
    ... ... @@ -59,6 +59,9 @@ class Job:
    59 59
             self._do_not_cache = self._action.do_not_cache
    
    60 60
             self._n_tries = 0
    
    61 61
     
    
    62
    +        self._platform_requirements = platform_requirements \
    
    63
    +            if platform_requirements else dict()
    
    64
    +
    
    62 65
             self._done = False
    
    63 66
     
    
    64 67
         def __lt__(self, other):
    
    ... ... @@ -113,6 +116,10 @@ class Job:
    113 116
     
    
    114 117
         # --- Public API: REAPI ---
    
    115 118
     
    
    119
    +    @property
    
    120
    +    def platform_requirements(self):
    
    121
    +        return self._platform_requirements
    
    122
    +
    
    116 123
         @property
    
    117 124
         def do_not_cache(self):
    
    118 125
             return self._do_not_cache
    

  • buildgrid/server/scheduler.py
    ... ... @@ -145,7 +145,8 @@ class Scheduler:
    145 145
             if not job.n_peers and job.done and not job.lease:
    
    146 146
                 self._delete_job(job.name)
    
    147 147
     
    
    148
    -    def queue_job_action(self, action, action_digest, priority=0, skip_cache_lookup=False):
    
    148
    +    def queue_job_action(self, action, action_digest, platform_requirements=None,
    
    149
    +                         priority=0, skip_cache_lookup=False):
    
    149 150
             """Inserts a newly created job into the execution queue.
    
    150 151
     
    
    151 152
             Warning:
    
    ... ... @@ -155,6 +156,9 @@ class Scheduler:
    155 156
             Args:
    
    156 157
                 action (Action): the given action to queue for execution.
    
    157 158
                 action_digest (Digest): the digest of the given action.
    
    159
    +            platform_requirements (dict(set)): platform attributes that a worker
    
    160
    +                must satisfy in order to be assigned the job. (Each key can
    
    161
    +                have multiple values.)
    
    158 162
                 priority (int): the execution job's priority.
    
    159 163
                 skip_cache_lookup (bool): whether or not to look for pre-computed
    
    160 164
                     result for the given action.
    
    ... ... @@ -178,7 +182,9 @@ class Scheduler:
    178 182
     
    
    179 183
                     return job.name
    
    180 184
     
    
    181
    -        job = Job(action, action_digest, priority=priority)
    
    185
    +        job = Job(action, action_digest,
    
    186
    +                  platform_requirements=platform_requirements,
    
    187
    +                  priority=priority)
    
    182 188
     
    
    183 189
             self.__logger.debug("Job created for action [%s]: [%s]",
    
    184 190
                                 action_digest.hash[:8], job.name)
    
    ... ... @@ -271,28 +277,29 @@ class Scheduler:
    271 277
             """Generates a list of the highest priority leases to be run.
    
    272 278
     
    
    273 279
             Args:
    
    274
    -            worker_capabilities (dict): a set of key-value pairs decribing the
    
    280
    +            worker_capabilities (dict): a set of key-value pairs describing the
    
    275 281
                     worker properties, configuration and state at the time of the
    
    276 282
                     request.
    
    277
    -
    
    278
    -        Warning: Worker capabilities handling is not implemented at the moment!
    
    279 283
             """
    
    280 284
             if not self.__queue:
    
    281 285
                 return []
    
    282 286
     
    
    283
    -        # TODO: Try to match worker_capabilities with jobs properties.
    
    284
    -        job = self.__queue.pop()
    
    287
    +        # Looking for the first job that could be assigned to the worker...
    
    288
    +        for job_index, job in enumerate(self.__queue):
    
    289
    +            if self._worker_is_capable(worker_capabilities, job):
    
    290
    +                self.__logger.info("Job scheduled to run: [%s]", job.name)
    
    285 291
     
    
    286
    -        self.__logger.info("Job scheduled to run: [%s]", job.name)
    
    292
    +                lease = job.lease
    
    287 293
     
    
    288
    -        lease = job.lease
    
    294
    +                if not lease:
    
    295
    +                    # For now, one lease at a time:
    
    296
    +                    lease = job.create_lease()
    
    289 297
     
    
    290
    -        if not lease:
    
    291
    -            # For now, one lease at a time:
    
    292
    -            lease = job.create_lease()
    
    298
    +                if lease:
    
    299
    +                    del self.__queue[job_index]
    
    300
    +                    return [lease]
    
    293 301
     
    
    294
    -        if lease:
    
    295
    -            return [lease]
    
    302
    +                return None
    
    296 303
     
    
    297 304
             return None
    
    298 305
     
    
    ... ... @@ -622,3 +629,28 @@ class Scheduler:
    622 629
     
    
    623 630
                         for message_queue in self.__build_metadata_queues:
    
    624 631
                             message_queue.put(message)
    
    632
    +
    
    633
    +    def _worker_is_capable(self, worker_capabilities, job):
    
    634
    +        """Returns whether the worker is suitable to run the job."""
    
    635
    +        # TODO: Replace this with the logic defined in the Platform msg. standard.
    
    636
    +
    
    637
    +        job_requirements = job.platform_requirements
    
    638
    +        # For now we'll only check OS and ISA properties.
    
    639
    +
    
    640
    +        if not job_requirements:
    
    641
    +            return True
    
    642
    +
    
    643
    +        # OS:
    
    644
    +        worker_oses = worker_capabilities.get('os', set())
    
    645
    +        job_oses = job_requirements.get('os', set())
    
    646
    +        if job_oses and not (job_oses & worker_oses):
    
    647
    +            return False
    
    648
    +
    
    649
    +        # ISAs:
    
    650
    +        worker_isas = worker_capabilities.get('isa', [])
    
    651
    +        job_isas = job_requirements.get('isa', None)
    
    652
    +
    
    653
    +        if job_isas and not (job_isas & worker_isas):
    
    654
    +            return False
    
    655
    +
    
    656
    +        return True

  • tests/integration/bots_service.py
    ... ... @@ -153,11 +153,27 @@ def test_post_bot_event_temp(context, instance):
    153 153
         context.set_code.assert_called_once_with(grpc.StatusCode.UNIMPLEMENTED)
    
    154 154
     
    
    155 155
     
    
    156
    -def _inject_work(scheduler, action=None, action_digest=None):
    
    156
    +def test_unmet_platform_requirements(bot_session, context, instance):
    
    157
    +    request = bots_pb2.CreateBotSessionRequest(parent='',
    
    158
    +                                               bot_session=bot_session)
    
    159
    +
    
    160
    +    action_digest = remote_execution_pb2.Digest(hash='gaff')
    
    161
    +    _inject_work(instance._instances[""]._scheduler,
    
    162
    +                 action_digest=action_digest,
    
    163
    +                 platform_requirements={'os': set('wonderful-os')})
    
    164
    +
    
    165
    +    response = instance.CreateBotSession(request, context)
    
    166
    +
    
    167
    +    assert len(response.leases) == 0
    
    168
    +
    
    169
    +
    
    170
    +def _inject_work(scheduler, action=None, action_digest=None,
    
    171
    +                 platform_requirements=None):
    
    157 172
         if not action:
    
    158 173
             action = remote_execution_pb2.Action()
    
    159 174
     
    
    160 175
         if not action_digest:
    
    161 176
             action_digest = remote_execution_pb2.Digest()
    
    162 177
     
    
    163
    -    scheduler.queue_job_action(action, action_digest, skip_cache_lookup=True)
    178
    +    scheduler.queue_job_action(action, action_digest, platform_requirements,
    
    179
    +                               skip_cache_lookup=True)

  • tests/integration/execution_service.py
    ... ... @@ -37,7 +37,12 @@ from buildgrid.server.execution.service import ExecutionService
    37 37
     
    
    38 38
     
    
    39 39
     server = mock.create_autospec(grpc.server)
    
    40
    -action = remote_execution_pb2.Action(do_not_cache=True)
    
    40
    +
    
    41
    +command = remote_execution_pb2.Command()
    
    42
    +command_digest = create_digest(command.SerializeToString())
    
    43
    +
    
    44
    +action = remote_execution_pb2.Action(command_digest=command_digest,
    
    45
    +                                     do_not_cache=True)
    
    41 46
     action_digest = create_digest(action.SerializeToString())
    
    42 47
     
    
    43 48
     
    
    ... ... @@ -50,15 +55,21 @@ def context():
    50 55
     @pytest.fixture(params=["action-cache", "no-action-cache"])
    
    51 56
     def controller(request):
    
    52 57
         storage = lru_memory_cache.LRUMemoryCache(1024 * 1024)
    
    58
    +
    
    59
    +    write_session = storage.begin_write(command_digest)
    
    60
    +    write_session.write(command.SerializeToString())
    
    61
    +    storage.commit_write(command_digest, write_session)
    
    62
    +
    
    53 63
         write_session = storage.begin_write(action_digest)
    
    64
    +    write_session.write(action.SerializeToString())
    
    54 65
         storage.commit_write(action_digest, write_session)
    
    55 66
     
    
    56 67
         if request.param == "action-cache":
    
    57 68
             cache = ActionCache(storage, 50)
    
    58
    -        yield ExecutionController(cache, storage)
    
    69
    +        yield ExecutionController(storage=storage, action_cache=cache)
    
    59 70
     
    
    60 71
         else:
    
    61
    -        yield ExecutionController(None, storage)
    
    72
    +        yield ExecutionController(storage=storage)
    
    62 73
     
    
    63 74
     
    
    64 75
     # Instance to test
    

  • tests/integration/operations_service.py
    ... ... @@ -36,7 +36,12 @@ from buildgrid.utils import create_digest
    36 36
     
    
    37 37
     server = mock.create_autospec(grpc.server)
    
    38 38
     instance_name = "blade"
    
    39
    -action = remote_execution_pb2.Action(do_not_cache=True)
    
    39
    +
    
    40
    +command = remote_execution_pb2.Command()
    
    41
    +command_digest = create_digest(command.SerializeToString())
    
    42
    +
    
    43
    +action = remote_execution_pb2.Action(command_digest=command_digest,
    
    44
    +                                     do_not_cache=True)
    
    40 45
     action_digest = create_digest(action.SerializeToString())
    
    41 46
     
    
    42 47
     
    
    ... ... @@ -57,10 +62,16 @@ def execute_request():
    57 62
     @pytest.fixture
    
    58 63
     def controller():
    
    59 64
         storage = lru_memory_cache.LRUMemoryCache(1024 * 1024)
    
    65
    +
    
    66
    +    write_session = storage.begin_write(command_digest)
    
    67
    +    write_session.write(command.SerializeToString())
    
    68
    +    storage.commit_write(command_digest, write_session)
    
    69
    +
    
    60 70
         write_session = storage.begin_write(action_digest)
    
    71
    +    write_session.write(action.SerializeToString())
    
    61 72
         storage.commit_write(action_digest, write_session)
    
    62 73
     
    
    63
    -    yield ExecutionController(None, storage)
    
    74
    +    yield ExecutionController(storage=storage)
    
    64 75
     
    
    65 76
     
    
    66 77
     # Instance to test
    



  • [Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]