1// Copyright 2019 Google LLC. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14// 15 16syntax = "proto3"; 17 18package google.devtools.remoteworkers.v1test2; 19 20import "google/api/annotations.proto"; 21import "google/api/client.proto"; 22import "google/api/field_behavior.proto"; 23import "google/api/resource.proto"; 24import "google/devtools/remoteworkers/v1test2/worker.proto"; 25import "google/protobuf/any.proto"; 26import "google/protobuf/field_mask.proto"; 27import "google/protobuf/timestamp.proto"; 28import "google/rpc/status.proto"; 29 30option csharp_namespace = "Google.DevTools.RemoteWorkers.V1Test2"; 31option go_package = "google.golang.org/genproto/googleapis/devtools/remoteworkers/v1test2;remoteworkers"; 32option java_multiple_files = true; 33option java_outer_classname = "RemoteWorkersBots"; 34option java_package = "com.google.devtools.remoteworkers.v1test2"; 35option php_namespace = "Google\\Cloud\\Remoteworkers\\V1test2"; 36option objc_class_prefix = "RW"; 37 38// Design doc: https://goo.gl/oojM5H 39// 40// Loosely speaking, the Bots interface monitors a collection of workers (think 41// of them as "computers" for a moment). This collection is known as a "farm," 42// and its purpose is to perform work on behalf of a client. 43// 44// Each worker runs a small program known as a "bot" that allows it to be 45// controlled by the server. This interface contains only methods that are 46// called by the bots themselves; admin functionality is out of scope for this 47// interface. 48// 49// More precisely, we use the term "worker" to refer to the physical "thing" 50// running the bot. We use the term "worker," and not "machine" or "computer," 51// since a worker may consist of more than one machine - e.g., a computer with 52// multiple attached devices, or even a cluster of computers, with only one of 53// them running the bot. Conversely, a single machine may host several bots, in 54// which case each bot has a "worker" corresponding to the slice of the machine 55// being managed by that bot. 56// 57// The main resource in the Bots interface is not, surprisingly, a Bot - it is a 58// BotSession, which represents a period of time in which a bot is in continuous 59// contact with the server (see the BotSession message for more information). 60// The parent of a bot session can be thought of as an instance of a farm. That 61// is, one endpoint may be able to manage many farms for many users. For 62// example, for a farm managed through GCP, the parent resource will typically 63// take the form "projects/{project_id}". This is referred to below as "the farm 64// resource." 65service Bots { 66 option (google.api.default_host) = "remoteworkers.googleapis.com"; 67 68 // CreateBotSession is called when the bot first joins the farm, and 69 // establishes a session ID to ensure that multiple machines do not register 70 // using the same name accidentally. 71 rpc CreateBotSession(CreateBotSessionRequest) returns (BotSession) { 72 option (google.api.http) = { 73 post: "/v1test2/{parent=**}/botSessions" 74 body: "bot_session" 75 }; 76 option (google.api.method_signature) = "parent,bot_session"; 77 } 78 79 // UpdateBotSession must be called periodically by the bot (on a schedule 80 // determined by the server) to let the server know about its status, and to 81 // pick up new lease requests from the server. 82 rpc UpdateBotSession(UpdateBotSessionRequest) returns (BotSession) { 83 option (google.api.http) = { 84 patch: "/v1test2/{name=**/botSessions/*}" 85 body: "bot_session" 86 }; 87 option (google.api.method_signature) = "name,bot_session,update_mask"; 88 } 89} 90 91// A bot session represents the state of a bot while in continuous contact with 92// the server for a period of time. The session includes information about the 93// worker - that is, the *worker* (the physical or virtual hardware) is 94// considered to be a property of the bot (the software agent running on that 95// hardware), which is the reverse of real life, but more natural from the point 96// of the view of this API, which communicates solely with the bot and not 97// directly with the underlying worker. 98message BotSession { 99 option (google.api.resource) = { 100 type: "remoteworkers.googleapis.com/BotSession" 101 pattern: "{unknown_path}/botSessions/{bot_session}" 102 }; 103 104 // The bot session name, as selected by the server. Output only during a call 105 // to CreateBotSession. 106 string name = 1; 107 108 // A unique bot ID within the farm used to persistently identify this bot over 109 // time (i.e., over multiple sessions). This ID must be unique within a 110 // farm. Typically, the bot ID will be the same as the name of the primary 111 // device in the worker (e.g., what you'd get from typing `uname -n` on *nix), 112 // but this is not required since a single device may allow multiple bots to 113 // run on it, each with access to different resources. What is important is 114 // that this ID is meaningful to humans, who might need to hunt a physical 115 // machine down to fix it. 116 // 117 // When CreateBotSession is successfully called with a bot_id, all prior 118 // sessions with the same ID are invalidated. If a bot attempts to update an 119 // invalid session, the server must reject that request, and may also 120 // quarantine the other bot with the same bot IDs (ie, stop sending it new 121 // leases and alert an admin). 122 string bot_id = 2; 123 124 // The status of the bot. This must be populated in every call to 125 // UpdateBotSession. 126 BotStatus status = 3; 127 128 // A description of the worker hosting this bot. The Worker message is used 129 // here in the Status context (see Worker for more information). If multiple 130 // bots are running on the worker, this field should only describe the 131 // resources accessible from this bot. 132 // 133 // During the call to CreateBotSession, the server may make arbitrary changes 134 // to the worker's `server_properties` field (see that field for more 135 // information). Otherwise, this field is input-only. 136 Worker worker = 4; 137 138 // A list of all leases that are a part of this session. See the Lease message 139 // for details. 140 repeated Lease leases = 5; 141 142 // The time at which this bot session will expire, unless the bot calls 143 // UpdateBotSession again. Output only. 144 google.protobuf.Timestamp expire_time = 6; 145 146 // The version of the bot code currently running. The server may use this 147 // information to issue an admin action to tell the bot to update itself. 148 string version = 7; 149} 150 151// A Lease is a lease that the scheduler has assigned to this bot. If the bot 152// notices (by UpdateBotSession) that it has any leases in the PENDING state, it 153// should call UpdateBotSession to put the leases into the ACTIVE state and 154// start executing their assignments. 155// 156// All fields in this message are output-only, *except* the `state` and `status` 157// fields. Note that repeated fields can only be updated as a unit, so on every 158// update the bot must provide an update for *all* the leases the server expects 159// it to report on. 160// 161// The scheduler *should* ensure that all leases scheduled to a bot can actually 162// be accepted, but race conditions may occur. In such cases, the bot should 163// attempt to accept the leases in the order they are listed by the server, to 164// allow the server to control priorities. 165// 166// The server will remove COMPLETED leases from time to time, after which the 167// bot shouldn't report on them any more (the server will ignore superfluous 168// COMPLETED records). 169message Lease { 170 // A short string uniquely identifing the lease within this bot session. 171 string id = 7; 172 173 // The actual work to be performed, if any. May be omitted by the server if 174 // the lease is not in the `PENDING` state. The message must be meaningful to 175 // the bot. Output only (must only be set by the server). 176 google.protobuf.Any payload = 8; 177 178 // Any result the bot wishes to provide about the lease. Must not be changed 179 // after the first call with the lease in the `COMPLETED` or `CANCELLED` 180 // state. Input only (must only be set by the bot, will not be echoed by the 181 // server). 182 google.protobuf.Any result = 9; 183 184 // The state of the lease. See LeaseState for more information. 185 LeaseState state = 2; 186 187 // The final status of the lease (should be populated by the bot if the state 188 // is completed). This is the status of the lease, not of any task represented 189 // by the lease. For example, if the bot could not accept the lease because it 190 // asked for some resource the bot didn't have, this status will be 191 // FAILED_PRECONDITION. But if the assignment in the lease didn't execute 192 // correctly, this field will be `OK` while the failure of the assignment must 193 // communicated via the `result` field. 194 google.rpc.Status status = 3; 195 196 // The requirements that are being claimed by this lease. This field may be 197 // omitted by the server if the lease is not pending. 198 Worker requirements = 4; 199 200 // The time at which this lease expires. The server *may* extend this over 201 // time, but due to race conditions, the bot is not *required* to respect any 202 // expiry date except the first one. 203 google.protobuf.Timestamp expire_time = 5; 204 205 // DEPRECATED. The assignment should be provided to the bot via the `payload` 206 // field. Clients that wish to use a simple name (such as a queue of work 207 // provided elsewhere) should define a custom message type and encode it into 208 // `payload`. 209 string assignment = 1 [deprecated = true]; 210 211 // DEPRECATED. Use `payload` instead. 212 google.protobuf.Any inline_assignment = 6 [deprecated = true]; 213} 214 215// AdminTemp is a prelimiary set of administration tasks. It's called "Temp" 216// because we do not yet know the best way to represent admin tasks; it's 217// possible that this will be entirely replaced in later versions of this API. 218// If this message proves to be sufficient, it will be renamed in the alpha or 219// beta release of this API. 220// 221// This message (suitably marshalled into a protobuf.Any) can be used as the 222// inline_assignment field in a lease; the lease assignment field should simply 223// be `"admin"` in these cases. 224// 225// This message is heavily based on Swarming administration tasks from the LUCI 226// project (http://github.com/luci/luci-py/appengine/swarming). 227message AdminTemp { 228 // Possible administration actions. 229 enum Command { 230 // Illegal value. 231 UNSPECIFIED = 0; 232 233 // Download and run a new version of the bot. `arg` will be a resource 234 // accessible via `ByteStream.Read` to obtain the new bot code. 235 BOT_UPDATE = 1; 236 237 // Restart the bot without downloading a new version. `arg` will be a 238 // message to log. 239 BOT_RESTART = 2; 240 241 // Shut down the bot. `arg` will be a task resource name (similar to those 242 // in tasks.proto) that the bot can use to tell the server that it is 243 // terminating. 244 BOT_TERMINATE = 3; 245 246 // Restart the host computer. `arg` will be a message to log. 247 HOST_RESTART = 4; 248 } 249 250 // The admin action; see `Command` for legal values. 251 Command command = 1; 252 253 // The argument to the admin action; see `Command` for semantics. 254 string arg = 2; 255} 256 257// A coarse description of the status of the bot that the server uses to 258// determine whether to assign the bot new leases. 259enum BotStatus { 260 // Default value; do not use. 261 BOT_STATUS_UNSPECIFIED = 0; 262 263 // The bot is healthy, and will accept leases as normal. 264 OK = 1; 265 266 // The bot is unhealthy and will not accept new leases. For example, the bot 267 // may have detected that available disk space is too low. This situation may 268 // resolve itself, but will typically require human intervention. 269 UNHEALTHY = 2; 270 271 // The bot has been asked to reboot the host. The bot will not accept new 272 // leases; once all leases are complete, this session will no longer be 273 // updated but the bot will be expected to establish a new session after the 274 // reboot completes. 275 HOST_REBOOTING = 3; 276 277 // The bot has been asked to shut down. As with HOST_REBOOTING, once all 278 // leases are completed, the session will no longer be updated and the bot 279 // will not be expected to establish a new session. 280 // 281 // Bots are typically only asked to shut down if its host computer will be 282 // modified in some way, such as deleting a VM. 283 BOT_TERMINATING = 4; 284 285 // The bot is initializing and is not ready to accept leases. 286 INITIALIZING = 5; 287} 288 289// The state of the lease. All leases start in the PENDING state. A bot can 290// change PENDING to ACTIVE or (in the case of an error) COMPLETED, or from 291// ACTIVE to COMPLETED. The server can change PENDING or ACTIVE to CANCELLED if 292// it wants the bot to release its resources - for example, if the bot needs to 293// be quarantined (it's producing bad output) or a cell needs to be drained. 294enum LeaseState { 295 // Default value; do not use. 296 LEASE_STATE_UNSPECIFIED = 0; 297 298 // Pending: the server expects the bot to accept this lease. This may only be 299 // set by the server. 300 PENDING = 1; 301 302 // Active: the bot has accepted this lease. This may only be set by the bot. 303 ACTIVE = 2; 304 305 // Completed: the bot is no longer leased. This may only be set by the bot, 306 // and the status field must be populated iff the state is COMPLETED. 307 COMPLETED = 4; 308 309 // Cancelled: The bot should immediately release all resources associated with 310 // the lease. This may only be set by the server. 311 CANCELLED = 5; 312} 313 314// Request message for CreateBotSession. 315message CreateBotSessionRequest { 316 // Required. The farm resource. 317 string parent = 1 [(google.api.field_behavior) = REQUIRED]; 318 319 // Required. The bot session to create. Server-assigned fields like name must 320 // be unset. 321 BotSession bot_session = 2 [(google.api.field_behavior) = REQUIRED]; 322} 323 324// Request message for UpdateBotSession. 325message UpdateBotSessionRequest { 326 // Required. The bot session name. Must match bot_session.name. 327 string name = 1 [ 328 (google.api.field_behavior) = REQUIRED, 329 (google.api.resource_reference) = { 330 type: "remoteworkers.googleapis.com/BotSession" 331 } 332 ]; 333 334 // Required. The bot session resource to update. 335 BotSession bot_session = 2 [(google.api.field_behavior) = REQUIRED]; 336 337 // Required. The fields on the bot that should be updated. See the BotSession 338 // resource for which fields are updatable by which caller. 339 google.protobuf.FieldMask update_mask = 3 340 [(google.api.field_behavior) = REQUIRED]; 341} 342