From 5a90abbcda510187c06a53fb48df30bf1f4cfab6 Mon Sep 17 00:00:00 2001 From: vsoch Date: Fri, 5 Apr 2024 18:51:11 -0600 Subject: [PATCH] feat: state endpoint Problem: we want to be able to select a final cluster based on state Solution: while a cluster will likely send back state when accepting jobs, for the time being we are providing a one off endpoint for a cluster to send state data, and it requires the cluster to authenticate with the name and secret. For now the state date is key value pairs of compatibility metadata, and the values can be anything (interface) as we are expecting the selection algorithms that use them to know the type for a specific key. I will be added selection algorithms after this first stage that I intend to use in scheduler simulation - namely a post filter that serves as additional constraints that can be chosen (max jobs a cluster can accept and a cost value that can be minimized. Signed-off-by: vsoch --- Makefile | 10 +- api/v1/rainbow.proto | 27 + cmd/rainbow/rainbow.go | 17 + cmd/rainbow/update/state.go | 51 ++ docs/commands.md | 38 + docs/examples/scheduler/cluster-state.json | 4 + docs/examples/scheduler/rainbow-config.yaml | 2 +- pkg/api/v1/rainbow.pb.go | 691 ++++++++++++------- pkg/api/v1/rainbow_grpc.pb.go | 40 ++ pkg/client/client.go | 3 + pkg/client/endpoint.go | 51 ++ pkg/graph/backend/backend.go | 8 + pkg/graph/selection/selection.go | 5 +- pkg/server/endpoint.go | 35 +- pkg/types/backend.go | 4 + plugins/backends/memory/cluster.go | 11 + plugins/backends/memory/graph.go | 30 + plugins/backends/memory/memory.go | 21 + plugins/selection/random/random.go | 6 +- python/v1/README.md | 32 + python/v1/examples/flux/update-state.py | 50 ++ python/v1/rainbow/client.py | 24 + python/v1/rainbow/protos/rainbow_pb2.py | 64 +- python/v1/rainbow/protos/rainbow_pb2.pyi | 26 + python/v1/rainbow/protos/rainbow_pb2_grpc.py | 47 ++ python/v1/setup.py | 2 +- 26 files changed, 1030 insertions(+), 269 deletions(-) create mode 100644 cmd/rainbow/update/state.go create mode 100644 docs/examples/scheduler/cluster-state.json create mode 100644 python/v1/examples/flux/update-state.py diff --git a/Makefile b/Makefile index ecbc198..e8c1a6b 100644 --- a/Makefile +++ b/Makefile @@ -79,6 +79,10 @@ test: tidy ## Runs unit tests server: ## Runs uncompiled version of the server go run cmd/server/server.go --global-token rainbow +.PHONY: server-verbose +server-verbose: ## Runs uncompiled version of the server + go run cmd/server/server.go --loglevel 6 --global-token rainbow + .PHONY: stream stream: ## Runs the interface client go run cmd/stream/stream.go @@ -88,9 +92,13 @@ register: ## Run mock registration go run cmd/rainbow/rainbow.go register cluster --cluster-name keebler --nodes-json ./docs/examples/scheduler/cluster-nodes.json --config-path ./docs/examples/scheduler/rainbow-config.yaml --save .PHONY: subsystem -subsystem: ## Run mock registration +subsystem: ## Register subsystem go run cmd/rainbow/rainbow.go register subsystem --subsystem io --nodes-json ./docs/examples/scheduler/cluster-io-subsystem.json --config-path ./docs/examples/scheduler/rainbow-config.yaml +.PHONY: update-state +update-state: ## Update state + go run cmd/rainbow/rainbow.go update state --state-file ./docs/examples/scheduler/cluster-state.json --config-path ./docs/examples/scheduler/rainbow-config.yaml + .PHONY: tag tag: ## Creates release tag git tag -s -m "version bump to $(VERSION)" $(VERSION) diff --git a/api/v1/rainbow.proto b/api/v1/rainbow.proto index a8b7575..a02dc41 100644 --- a/api/v1/rainbow.proto +++ b/api/v1/rainbow.proto @@ -18,6 +18,10 @@ service RainbowScheduler { // Job Submission - request for submitting a job to a named cluster rpc SubmitJob(SubmitJobRequest) returns (SubmitJobResponse); + // Update State - allow a cluster to provide state metadata + // This is intended for use by a selection algorithm + rpc UpdateState(UpdateStateRequest) returns (UpdateStateResponse); + // Request Job - ask the rainbow scheduler for up to max jobs rpc ReceiveJobs(ReceiveJobsRequest) returns (ReceiveJobsResponse); @@ -37,6 +41,29 @@ message RegisterRequest { google.protobuf.Timestamp sent = 5; } +// UpdateStateRequests allows a cluster to set arbitrary metadata +// for its state. State metadata is used for selection algorithms +message UpdateStateRequest { + string cluster = 1; + string secret = 2; + + // We are generous that the payload can be a flat + // set of key value pairs, and will be parsed into + // types within the graph database + string payload = 3; +} + +message UpdateStateResponse { + enum ResultType { + UPDATE_STATE_UNSPECIFIED = 0; + UPDATE_STATE_PARTIAL = 1; + UPDATE_STATE_SUCCESS = 2; + UPDATE_STATE_ERROR = 3; + } + ResultType status = 1; +} + + // SubmitJobRequest takes a job name, cluster name // and requires the cluster token. Since we want to be generic, // we currently accept nodes, tasks, and the command diff --git a/cmd/rainbow/rainbow.go b/cmd/rainbow/rainbow.go index 0d07d2c..e1e0ce7 100644 --- a/cmd/rainbow/rainbow.go +++ b/cmd/rainbow/rainbow.go @@ -10,6 +10,7 @@ import ( "github.com/converged-computing/rainbow/cmd/rainbow/receive" "github.com/converged-computing/rainbow/cmd/rainbow/register" "github.com/converged-computing/rainbow/cmd/rainbow/submit" + "github.com/converged-computing/rainbow/cmd/rainbow/update" "github.com/converged-computing/rainbow/pkg/types" // Register database backends and selection algorithms @@ -41,6 +42,7 @@ func main() { submitCmd := parser.NewCommand("submit", "Submit a job to a rainbow scheduler") receiveCmd := parser.NewCommand("receive", "Receive and accept jobs") registerClusterCmd := registerCmd.NewCommand("cluster", "Register a new cluster") + updateCmd := parser.NewCommand("update", "Update a cluster") // Configuration configCmd := parser.NewCommand("config", "Interact with rainbow configs") @@ -69,6 +71,10 @@ func main() { // Register subsystem (requires config file for authentication) subsysCmd := registerCmd.NewCommand("subsystem", "Register a new subsystem") + // Update subcommands - currently just supported are state + stateCmd := updateCmd.NewCommand("state", "Update the state for a known cluster") + stateFile := stateCmd.String("", "state-file", &argparse.Options{Help: "JSON file with key, value attributes for the cluster"}) + // Submit (note that command for now needs to be in quotes to get the whole thing) token := submitCmd.String("", "token", &argparse.Options{Default: defaultSecret, Help: "Client token to submit jobs with."}) nodes := submitCmd.Int("n", "nodes", &argparse.Options{Default: 1, Help: "Number of nodes to request"}) @@ -91,6 +97,17 @@ func main() { log.Fatalf("Issue with config: %s\n", err) } + } else if stateCmd.Happened() { + err := update.UpdateState( + *host, + *clusterName, + *stateFile, + *cfg, + ) + if err != nil { + log.Fatalf("Issue with register subsystem: %s\n", err) + } + } else if registerCmd.Happened() { if subsysCmd.Happened() { diff --git a/cmd/rainbow/update/state.go b/cmd/rainbow/update/state.go new file mode 100644 index 0000000..db357db --- /dev/null +++ b/cmd/rainbow/update/state.go @@ -0,0 +1,51 @@ +package update + +import ( + "context" + "fmt" + "log" + + "github.com/converged-computing/rainbow/pkg/client" + "github.com/converged-computing/rainbow/pkg/config" +) + +// UpdateState updates state for a cluster +func UpdateState( + host, + clusterName, + stateFile, + cfgFile string, +) error { + + c, err := client.NewClient(host) + if err != nil { + return err + } + + // A config file is required here + if cfgFile == "" { + return fmt.Errorf("an existing configuration file is required to update an existing cluster") + } + if stateFile == "" { + return fmt.Errorf("a state file (json with key value pairs) is required to update state") + } + // Read in the config, if provided, command line takes preference + cfg, err := config.NewRainbowClientConfig(cfgFile, "", "", "", "", "") + if err != nil { + return err + } + + log.Printf("updating state for cluster: %s", cfg.Scheduler.Name) + + // Last argument is subsystem name, which we can derive from graph + response, err := c.UpdateState( + context.Background(), + cfg.Cluster.Name, + cfg.Cluster.Secret, + stateFile, + ) + // If we get here, success! Dump all the stuff. + log.Printf("%s", response) + return err + +} diff --git a/docs/commands.md b/docs/commands.md index 667589f..a39ac01 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -7,7 +7,11 @@ The following commands are currently supported. For Python, see the [README](htt You can run the server (with defaults) as follows: ```bash +# Regular logging make server + +# Verbose logging +make server-verbose ``` ```console go run cmd/server/server.go --global-token rainbow @@ -180,6 +184,40 @@ the following reasons: In Computer Science I think they are used interchangeably. For next steps we will be updating the memory graph database to be a little more meaty (adding proper metadata and likely a summary of resources at the top as a quick "does it satisfy" heuristic) and then working on the next interaction, the client submit command, which is going to hit the `Satisfies` endpoint. I will write up more about the database and submit design after that. +## Update State + +A cluster state is intended to be a superficial view of the cluster status. It's not considered a subsystem because (for the time being) we are only considering a flat listing of key value pairs that describe a cluster. The data is also intended to be small so it can be provided via this update endpoint more frequently. As an example, an update payload may look like the following: + +```json +{ + "cost-per-node": 12, + "nodes-free": 100 +} +``` + +While the above would not be suited for a real-world deployment (for example, there are many more costs than per node, and occupancy goes beyond nodes free) +but this will be appropriate for small tests and simulations. The metadata above will be provided, on a cluster level, for a final selection algorithm (to use or not). So after you've created your cluster, let's update the state. + +```bash +make update-state +``` +```console +Adding edge from socket -contains-> core +Adding edge from socket -contains-> core +2024/04/05 18:38:13 We have made an in memory graph (subsystem cluster) with 45 vertices! +Metrics for subsystem cluster{ + "cluster": 1, + "core": 36, + "node": 3, + "rack": 1, + "socket": 3 +} +2024/04/05 18:38:16 📝️ received state update: keebler +Updating state cost-per-node to 12 +Updating state max-jobs to 100 +``` +In debug logging mode (`make server-debug`) you will see the values updated, as shown above. They are also in blue, which you can't see! Note that this state metadata is provided to a selection algorithm, and we will be added more interesting ones soon for experiments! + ## Register Subsystem Adding a subsystem means adding another graph that has nodes with edges that connect (in some meaningful way) to the dominant subsystem. diff --git a/docs/examples/scheduler/cluster-state.json b/docs/examples/scheduler/cluster-state.json new file mode 100644 index 0000000..3c8932c --- /dev/null +++ b/docs/examples/scheduler/cluster-state.json @@ -0,0 +1,4 @@ +{ + "cost-per-node": 12, + "max-jobs": 100 +} \ No newline at end of file diff --git a/docs/examples/scheduler/rainbow-config.yaml b/docs/examples/scheduler/rainbow-config.yaml index 316602f..c0493ee 100644 --- a/docs/examples/scheduler/rainbow-config.yaml +++ b/docs/examples/scheduler/rainbow-config.yaml @@ -8,7 +8,7 @@ scheduler: name: match cluster: name: keebler - secret: 79643f8e-6408-4cd1-bd1a-76aa499d5864 + secret: 76948f58-8655-48c1-aaab-fccedf2bb383 graphdatabase: name: memory host: 127.0.0.1:50051 diff --git a/pkg/api/v1/rainbow.pb.go b/pkg/api/v1/rainbow.pb.go index daf7f9c..25be690 100644 --- a/pkg/api/v1/rainbow.pb.go +++ b/pkg/api/v1/rainbow.pb.go @@ -21,6 +21,58 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +type UpdateStateResponse_ResultType int32 + +const ( + UpdateStateResponse_UPDATE_STATE_UNSPECIFIED UpdateStateResponse_ResultType = 0 + UpdateStateResponse_UPDATE_STATE_PARTIAL UpdateStateResponse_ResultType = 1 + UpdateStateResponse_UPDATE_STATE_SUCCESS UpdateStateResponse_ResultType = 2 + UpdateStateResponse_UPDATE_STATE_ERROR UpdateStateResponse_ResultType = 3 +) + +// Enum value maps for UpdateStateResponse_ResultType. +var ( + UpdateStateResponse_ResultType_name = map[int32]string{ + 0: "UPDATE_STATE_UNSPECIFIED", + 1: "UPDATE_STATE_PARTIAL", + 2: "UPDATE_STATE_SUCCESS", + 3: "UPDATE_STATE_ERROR", + } + UpdateStateResponse_ResultType_value = map[string]int32{ + "UPDATE_STATE_UNSPECIFIED": 0, + "UPDATE_STATE_PARTIAL": 1, + "UPDATE_STATE_SUCCESS": 2, + "UPDATE_STATE_ERROR": 3, + } +) + +func (x UpdateStateResponse_ResultType) Enum() *UpdateStateResponse_ResultType { + p := new(UpdateStateResponse_ResultType) + *p = x + return p +} + +func (x UpdateStateResponse_ResultType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (UpdateStateResponse_ResultType) Descriptor() protoreflect.EnumDescriptor { + return file_rainbow_proto_enumTypes[0].Descriptor() +} + +func (UpdateStateResponse_ResultType) Type() protoreflect.EnumType { + return &file_rainbow_proto_enumTypes[0] +} + +func (x UpdateStateResponse_ResultType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use UpdateStateResponse_ResultType.Descriptor instead. +func (UpdateStateResponse_ResultType) EnumDescriptor() ([]byte, []int) { + return file_rainbow_proto_rawDescGZIP(), []int{2, 0} +} + // Registration statuses type RegisterResponse_ResultType int32 @@ -61,11 +113,11 @@ func (x RegisterResponse_ResultType) String() string { } func (RegisterResponse_ResultType) Descriptor() protoreflect.EnumDescriptor { - return file_rainbow_proto_enumTypes[0].Descriptor() + return file_rainbow_proto_enumTypes[1].Descriptor() } func (RegisterResponse_ResultType) Type() protoreflect.EnumType { - return &file_rainbow_proto_enumTypes[0] + return &file_rainbow_proto_enumTypes[1] } func (x RegisterResponse_ResultType) Number() protoreflect.EnumNumber { @@ -74,7 +126,7 @@ func (x RegisterResponse_ResultType) Number() protoreflect.EnumNumber { // Deprecated: Use RegisterResponse_ResultType.Descriptor instead. func (RegisterResponse_ResultType) EnumDescriptor() ([]byte, []int) { - return file_rainbow_proto_rawDescGZIP(), []int{4, 0} + return file_rainbow_proto_rawDescGZIP(), []int{6, 0} } // Enum to represent the result types of the operation. @@ -114,11 +166,11 @@ func (x SubmitJobResponse_ResultType) String() string { } func (SubmitJobResponse_ResultType) Descriptor() protoreflect.EnumDescriptor { - return file_rainbow_proto_enumTypes[1].Descriptor() + return file_rainbow_proto_enumTypes[2].Descriptor() } func (SubmitJobResponse_ResultType) Type() protoreflect.EnumType { - return &file_rainbow_proto_enumTypes[1] + return &file_rainbow_proto_enumTypes[2] } func (x SubmitJobResponse_ResultType) Number() protoreflect.EnumNumber { @@ -127,7 +179,7 @@ func (x SubmitJobResponse_ResultType) Number() protoreflect.EnumNumber { // Deprecated: Use SubmitJobResponse_ResultType.Descriptor instead. func (SubmitJobResponse_ResultType) EnumDescriptor() ([]byte, []int) { - return file_rainbow_proto_rawDescGZIP(), []int{5, 0} + return file_rainbow_proto_rawDescGZIP(), []int{7, 0} } // Enum to represent the result types of the operation. @@ -167,11 +219,11 @@ func (x ReceiveJobsResponse_ResultType) String() string { } func (ReceiveJobsResponse_ResultType) Descriptor() protoreflect.EnumDescriptor { - return file_rainbow_proto_enumTypes[2].Descriptor() + return file_rainbow_proto_enumTypes[3].Descriptor() } func (ReceiveJobsResponse_ResultType) Type() protoreflect.EnumType { - return &file_rainbow_proto_enumTypes[2] + return &file_rainbow_proto_enumTypes[3] } func (x ReceiveJobsResponse_ResultType) Number() protoreflect.EnumNumber { @@ -180,7 +232,7 @@ func (x ReceiveJobsResponse_ResultType) Number() protoreflect.EnumNumber { // Deprecated: Use ReceiveJobsResponse_ResultType.Descriptor instead. func (ReceiveJobsResponse_ResultType) EnumDescriptor() ([]byte, []int) { - return file_rainbow_proto_rawDescGZIP(), []int{6, 0} + return file_rainbow_proto_rawDescGZIP(), []int{8, 0} } type AcceptJobsResponse_ResultType int32 @@ -219,11 +271,11 @@ func (x AcceptJobsResponse_ResultType) String() string { } func (AcceptJobsResponse_ResultType) Descriptor() protoreflect.EnumDescriptor { - return file_rainbow_proto_enumTypes[3].Descriptor() + return file_rainbow_proto_enumTypes[4].Descriptor() } func (AcceptJobsResponse_ResultType) Type() protoreflect.EnumType { - return &file_rainbow_proto_enumTypes[3] + return &file_rainbow_proto_enumTypes[4] } func (x AcceptJobsResponse_ResultType) Number() protoreflect.EnumNumber { @@ -232,7 +284,7 @@ func (x AcceptJobsResponse_ResultType) Number() protoreflect.EnumNumber { // Deprecated: Use AcceptJobsResponse_ResultType.Descriptor instead. func (AcceptJobsResponse_ResultType) EnumDescriptor() ([]byte, []int) { - return file_rainbow_proto_rawDescGZIP(), []int{7, 0} + return file_rainbow_proto_rawDescGZIP(), []int{9, 0} } // RegisterRequest registers a cluster to the scheduler service @@ -317,6 +369,121 @@ func (x *RegisterRequest) GetSent() *timestamppb.Timestamp { return nil } +// UpdateStateRequests allows a cluster to set arbitrary metadata +// for its state. State metadata is used for selection algorithms +type UpdateStateRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Cluster string `protobuf:"bytes,1,opt,name=cluster,proto3" json:"cluster,omitempty"` + Secret string `protobuf:"bytes,2,opt,name=secret,proto3" json:"secret,omitempty"` + // We are generous that the payload can be a flat + // set of key value pairs, and will be parsed into + // types within the graph database + Payload string `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"` +} + +func (x *UpdateStateRequest) Reset() { + *x = UpdateStateRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_rainbow_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateStateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateStateRequest) ProtoMessage() {} + +func (x *UpdateStateRequest) ProtoReflect() protoreflect.Message { + mi := &file_rainbow_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateStateRequest.ProtoReflect.Descriptor instead. +func (*UpdateStateRequest) Descriptor() ([]byte, []int) { + return file_rainbow_proto_rawDescGZIP(), []int{1} +} + +func (x *UpdateStateRequest) GetCluster() string { + if x != nil { + return x.Cluster + } + return "" +} + +func (x *UpdateStateRequest) GetSecret() string { + if x != nil { + return x.Secret + } + return "" +} + +func (x *UpdateStateRequest) GetPayload() string { + if x != nil { + return x.Payload + } + return "" +} + +type UpdateStateResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Status UpdateStateResponse_ResultType `protobuf:"varint,1,opt,name=status,proto3,enum=convergedcomputing.org.grpc.v1.UpdateStateResponse_ResultType" json:"status,omitempty"` +} + +func (x *UpdateStateResponse) Reset() { + *x = UpdateStateResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_rainbow_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateStateResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateStateResponse) ProtoMessage() {} + +func (x *UpdateStateResponse) ProtoReflect() protoreflect.Message { + mi := &file_rainbow_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateStateResponse.ProtoReflect.Descriptor instead. +func (*UpdateStateResponse) Descriptor() ([]byte, []int) { + return file_rainbow_proto_rawDescGZIP(), []int{2} +} + +func (x *UpdateStateResponse) GetStatus() UpdateStateResponse_ResultType { + if x != nil { + return x.Status + } + return UpdateStateResponse_UPDATE_STATE_UNSPECIFIED +} + // SubmitJobRequest takes a job name, cluster name // and requires the cluster token. Since we want to be generic, // we currently accept nodes, tasks, and the command @@ -334,7 +501,7 @@ type SubmitJobRequest struct { func (x *SubmitJobRequest) Reset() { *x = SubmitJobRequest{} if protoimpl.UnsafeEnabled { - mi := &file_rainbow_proto_msgTypes[1] + mi := &file_rainbow_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -347,7 +514,7 @@ func (x *SubmitJobRequest) String() string { func (*SubmitJobRequest) ProtoMessage() {} func (x *SubmitJobRequest) ProtoReflect() protoreflect.Message { - mi := &file_rainbow_proto_msgTypes[1] + mi := &file_rainbow_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -360,7 +527,7 @@ func (x *SubmitJobRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitJobRequest.ProtoReflect.Descriptor instead. func (*SubmitJobRequest) Descriptor() ([]byte, []int) { - return file_rainbow_proto_rawDescGZIP(), []int{1} + return file_rainbow_proto_rawDescGZIP(), []int{3} } func (x *SubmitJobRequest) GetName() string { @@ -412,7 +579,7 @@ type ReceiveJobsRequest struct { func (x *ReceiveJobsRequest) Reset() { *x = ReceiveJobsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_rainbow_proto_msgTypes[2] + mi := &file_rainbow_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -425,7 +592,7 @@ func (x *ReceiveJobsRequest) String() string { func (*ReceiveJobsRequest) ProtoMessage() {} func (x *ReceiveJobsRequest) ProtoReflect() protoreflect.Message { - mi := &file_rainbow_proto_msgTypes[2] + mi := &file_rainbow_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -438,7 +605,7 @@ func (x *ReceiveJobsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReceiveJobsRequest.ProtoReflect.Descriptor instead. func (*ReceiveJobsRequest) Descriptor() ([]byte, []int) { - return file_rainbow_proto_rawDescGZIP(), []int{2} + return file_rainbow_proto_rawDescGZIP(), []int{4} } func (x *ReceiveJobsRequest) GetCluster() string { @@ -484,7 +651,7 @@ type AcceptJobsRequest struct { func (x *AcceptJobsRequest) Reset() { *x = AcceptJobsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_rainbow_proto_msgTypes[3] + mi := &file_rainbow_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -497,7 +664,7 @@ func (x *AcceptJobsRequest) String() string { func (*AcceptJobsRequest) ProtoMessage() {} func (x *AcceptJobsRequest) ProtoReflect() protoreflect.Message { - mi := &file_rainbow_proto_msgTypes[3] + mi := &file_rainbow_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -510,7 +677,7 @@ func (x *AcceptJobsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AcceptJobsRequest.ProtoReflect.Descriptor instead. func (*AcceptJobsRequest) Descriptor() ([]byte, []int) { - return file_rainbow_proto_rawDescGZIP(), []int{3} + return file_rainbow_proto_rawDescGZIP(), []int{5} } func (x *AcceptJobsRequest) GetCluster() string { @@ -559,7 +726,7 @@ type RegisterResponse struct { func (x *RegisterResponse) Reset() { *x = RegisterResponse{} if protoimpl.UnsafeEnabled { - mi := &file_rainbow_proto_msgTypes[4] + mi := &file_rainbow_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -572,7 +739,7 @@ func (x *RegisterResponse) String() string { func (*RegisterResponse) ProtoMessage() {} func (x *RegisterResponse) ProtoReflect() protoreflect.Message { - mi := &file_rainbow_proto_msgTypes[4] + mi := &file_rainbow_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -585,7 +752,7 @@ func (x *RegisterResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RegisterResponse.ProtoReflect.Descriptor instead. func (*RegisterResponse) Descriptor() ([]byte, []int) { - return file_rainbow_proto_rawDescGZIP(), []int{4} + return file_rainbow_proto_rawDescGZIP(), []int{6} } func (x *RegisterResponse) GetRequestId() string { @@ -631,7 +798,7 @@ type SubmitJobResponse struct { func (x *SubmitJobResponse) Reset() { *x = SubmitJobResponse{} if protoimpl.UnsafeEnabled { - mi := &file_rainbow_proto_msgTypes[5] + mi := &file_rainbow_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -644,7 +811,7 @@ func (x *SubmitJobResponse) String() string { func (*SubmitJobResponse) ProtoMessage() {} func (x *SubmitJobResponse) ProtoReflect() protoreflect.Message { - mi := &file_rainbow_proto_msgTypes[5] + mi := &file_rainbow_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -657,7 +824,7 @@ func (x *SubmitJobResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitJobResponse.ProtoReflect.Descriptor instead. func (*SubmitJobResponse) Descriptor() ([]byte, []int) { - return file_rainbow_proto_rawDescGZIP(), []int{5} + return file_rainbow_proto_rawDescGZIP(), []int{7} } func (x *SubmitJobResponse) GetRequestId() string { @@ -703,7 +870,7 @@ type ReceiveJobsResponse struct { func (x *ReceiveJobsResponse) Reset() { *x = ReceiveJobsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_rainbow_proto_msgTypes[6] + mi := &file_rainbow_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -716,7 +883,7 @@ func (x *ReceiveJobsResponse) String() string { func (*ReceiveJobsResponse) ProtoMessage() {} func (x *ReceiveJobsResponse) ProtoReflect() protoreflect.Message { - mi := &file_rainbow_proto_msgTypes[6] + mi := &file_rainbow_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -729,7 +896,7 @@ func (x *ReceiveJobsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReceiveJobsResponse.ProtoReflect.Descriptor instead. func (*ReceiveJobsResponse) Descriptor() ([]byte, []int) { - return file_rainbow_proto_rawDescGZIP(), []int{6} + return file_rainbow_proto_rawDescGZIP(), []int{8} } func (x *ReceiveJobsResponse) GetRequestId() string { @@ -765,7 +932,7 @@ type AcceptJobsResponse struct { func (x *AcceptJobsResponse) Reset() { *x = AcceptJobsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_rainbow_proto_msgTypes[7] + mi := &file_rainbow_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -778,7 +945,7 @@ func (x *AcceptJobsResponse) String() string { func (*AcceptJobsResponse) ProtoMessage() {} func (x *AcceptJobsResponse) ProtoReflect() protoreflect.Message { - mi := &file_rainbow_proto_msgTypes[7] + mi := &file_rainbow_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -791,7 +958,7 @@ func (x *AcceptJobsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AcceptJobsResponse.ProtoReflect.Descriptor instead. func (*AcceptJobsResponse) Descriptor() ([]byte, []int) { - return file_rainbow_proto_rawDescGZIP(), []int{7} + return file_rainbow_proto_rawDescGZIP(), []int{9} } func (x *AcceptJobsResponse) GetStatus() AcceptJobsResponse_ResultType { @@ -813,7 +980,7 @@ type SubmitJobRequest_Cluster struct { func (x *SubmitJobRequest_Cluster) Reset() { *x = SubmitJobRequest_Cluster{} if protoimpl.UnsafeEnabled { - mi := &file_rainbow_proto_msgTypes[8] + mi := &file_rainbow_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -826,7 +993,7 @@ func (x *SubmitJobRequest_Cluster) String() string { func (*SubmitJobRequest_Cluster) ProtoMessage() {} func (x *SubmitJobRequest_Cluster) ProtoReflect() protoreflect.Message { - mi := &file_rainbow_proto_msgTypes[8] + mi := &file_rainbow_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -839,7 +1006,7 @@ func (x *SubmitJobRequest_Cluster) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitJobRequest_Cluster.ProtoReflect.Descriptor instead. func (*SubmitJobRequest_Cluster) Descriptor() ([]byte, []int) { - return file_rainbow_proto_rawDescGZIP(), []int{1, 0} + return file_rainbow_proto_rawDescGZIP(), []int{3, 0} } func (x *SubmitJobRequest_Cluster) GetName() string { @@ -874,158 +1041,186 @@ var file_rainbow_proto_rawDesc = []byte{ 0x73, 0x74, 0x65, 0x6d, 0x12, 0x2e, 0x0a, 0x04, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, - 0x73, 0x65, 0x6e, 0x74, 0x22, 0xfb, 0x01, 0x0a, 0x10, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4a, - 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x54, 0x0a, - 0x08, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, - 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x08, 0x63, 0x6c, 0x75, 0x73, 0x74, - 0x65, 0x72, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6a, 0x6f, 0x62, 0x73, 0x70, 0x65, 0x63, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6a, 0x6f, 0x62, 0x73, 0x70, 0x65, 0x63, 0x12, 0x2e, 0x0a, - 0x04, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x73, 0x65, 0x6e, 0x74, 0x1a, 0x33, 0x0a, - 0x07, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, - 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, - 0x65, 0x6e, 0x22, 0x90, 0x01, 0x0a, 0x12, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4a, 0x6f, - 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6c, 0x75, - 0x73, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6c, 0x75, 0x73, - 0x74, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x6d, - 0x61, 0x78, 0x4a, 0x6f, 0x62, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x6d, 0x61, - 0x78, 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x2e, 0x0a, 0x04, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, - 0x04, 0x73, 0x65, 0x6e, 0x74, 0x22, 0x8d, 0x01, 0x0a, 0x11, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, - 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, - 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6c, - 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x16, 0x0a, - 0x06, 0x6a, 0x6f, 0x62, 0x69, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x05, 0x52, 0x06, 0x6a, - 0x6f, 0x62, 0x69, 0x64, 0x73, 0x12, 0x2e, 0x0a, 0x04, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, - 0x04, 0x73, 0x65, 0x6e, 0x74, 0x22, 0xb0, 0x02, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, - 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, - 0x16, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x53, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3b, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, - 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, - 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, - 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x54, 0x79, 0x70, 0x65, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x7a, 0x0a, 0x0a, - 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x45, - 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, - 0x45, 0x44, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, - 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, - 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x13, - 0x0a, 0x0f, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x44, 0x45, 0x4e, 0x49, 0x45, - 0x44, 0x10, 0x03, 0x12, 0x13, 0x0a, 0x0f, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, - 0x45, 0x58, 0x49, 0x53, 0x54, 0x53, 0x10, 0x04, 0x22, 0x97, 0x02, 0x0a, 0x11, 0x53, 0x75, 0x62, - 0x6d, 0x69, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, - 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, - 0x05, 0x6a, 0x6f, 0x62, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6a, 0x6f, - 0x62, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x54, 0x0a, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3c, 0x2e, - 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, - 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x53, - 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x22, 0x5d, 0x0a, 0x0a, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x55, 0x42, 0x4d, 0x49, 0x54, 0x5f, 0x55, 0x4e, 0x53, 0x50, - 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x55, 0x42, - 0x4d, 0x49, 0x54, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x01, 0x12, 0x10, 0x0a, - 0x0c, 0x53, 0x55, 0x42, 0x4d, 0x49, 0x54, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, - 0x11, 0x0a, 0x0d, 0x53, 0x55, 0x42, 0x4d, 0x49, 0x54, 0x5f, 0x44, 0x45, 0x4e, 0x49, 0x45, 0x44, - 0x10, 0x03, 0x22, 0x8d, 0x03, 0x0a, 0x13, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4a, 0x6f, - 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x51, 0x0a, 0x04, 0x6a, 0x6f, 0x62, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, - 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, - 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, - 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4a, 0x6f, 0x62, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x12, 0x56, 0x0a, 0x06, - 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3e, 0x2e, 0x63, - 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, 0x6e, - 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, - 0x63, 0x65, 0x69, 0x76, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x06, 0x73, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x1a, 0x37, 0x0a, 0x09, 0x4a, 0x6f, 0x62, 0x73, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, - 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x73, 0x0a, - 0x0a, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x52, - 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x4a, 0x4f, 0x42, 0x53, 0x5f, 0x4e, 0x4f, 0x52, 0x45, - 0x53, 0x55, 0x4c, 0x54, 0x53, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x45, 0x51, 0x55, 0x45, - 0x53, 0x54, 0x5f, 0x4a, 0x4f, 0x42, 0x53, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, - 0x01, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x4a, 0x4f, 0x42, - 0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x17, 0x0a, 0x13, 0x52, 0x45, 0x51, - 0x55, 0x45, 0x53, 0x54, 0x5f, 0x4a, 0x4f, 0x42, 0x53, 0x5f, 0x44, 0x45, 0x4e, 0x49, 0x45, 0x44, - 0x10, 0x03, 0x22, 0xdf, 0x01, 0x0a, 0x12, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x4a, 0x6f, 0x62, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x55, 0x0a, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3d, 0x2e, 0x63, 0x6f, 0x6e, 0x76, - 0x65, 0x72, 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6f, - 0x72, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x70, - 0x74, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x22, 0x72, 0x0a, 0x0a, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, - 0x0a, 0x17, 0x52, 0x45, 0x53, 0x55, 0x4c, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, - 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x52, - 0x45, 0x53, 0x55, 0x4c, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x41, 0x52, 0x54, 0x49, - 0x41, 0x4c, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x52, 0x45, 0x53, 0x55, 0x4c, 0x54, 0x5f, 0x54, - 0x59, 0x50, 0x45, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x02, 0x12, 0x15, 0x0a, - 0x11, 0x52, 0x45, 0x53, 0x55, 0x4c, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x52, 0x52, - 0x4f, 0x52, 0x10, 0x03, 0x32, 0xd8, 0x04, 0x0a, 0x10, 0x52, 0x61, 0x69, 0x6e, 0x62, 0x6f, 0x77, - 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x12, 0x6d, 0x0a, 0x08, 0x52, 0x65, 0x67, - 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x67, 0x65, - 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x67, - 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x67, - 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2e, - 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x76, 0x0a, 0x11, 0x52, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x65, 0x72, 0x53, 0x75, 0x62, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x2f, 0x2e, - 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, - 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x52, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, + 0x73, 0x65, 0x6e, 0x74, 0x22, 0x60, 0x0a, 0x12, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6c, + 0x75, 0x73, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6c, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x18, 0x0a, 0x07, + 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, + 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0xe5, 0x01, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, + 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3e, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, - 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x70, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4a, 0x6f, 0x62, 0x12, 0x30, 0x2e, - 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, - 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x53, - 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, - 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x76, 0x0a, 0x0b, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4a, 0x6f, 0x62, - 0x73, 0x12, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x76, 0x0a, 0x0a, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x1c, 0x0a, 0x18, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x53, + 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, + 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x53, 0x54, 0x41, + 0x54, 0x45, 0x5f, 0x50, 0x41, 0x52, 0x54, 0x49, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, + 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x53, 0x55, 0x43, + 0x43, 0x45, 0x53, 0x53, 0x10, 0x02, 0x12, 0x16, 0x0a, 0x12, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, + 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x22, 0xfb, + 0x01, 0x0a, 0x10, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x54, 0x0a, 0x08, 0x63, 0x6c, 0x75, 0x73, 0x74, + 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x76, + 0x65, 0x72, 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6f, + 0x72, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, + 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x43, 0x6c, 0x75, 0x73, + 0x74, 0x65, 0x72, 0x52, 0x08, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, 0x18, 0x0a, + 0x07, 0x6a, 0x6f, 0x62, 0x73, 0x70, 0x65, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x6a, 0x6f, 0x62, 0x73, 0x70, 0x65, 0x63, 0x12, 0x2e, 0x0a, 0x04, 0x73, 0x65, 0x6e, 0x74, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x52, 0x04, 0x73, 0x65, 0x6e, 0x74, 0x1a, 0x33, 0x0a, 0x07, 0x43, 0x6c, 0x75, 0x73, 0x74, + 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x90, 0x01, 0x0a, + 0x12, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x16, 0x0a, + 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, + 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x61, 0x78, 0x4a, 0x6f, 0x62, 0x73, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x6d, 0x61, 0x78, 0x4a, 0x6f, 0x62, 0x73, 0x12, + 0x2e, 0x0a, 0x04, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x73, 0x65, 0x6e, 0x74, 0x22, + 0x8d, 0x01, 0x0a, 0x11, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, + 0x16, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x69, 0x64, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x05, 0x52, 0x06, 0x6a, 0x6f, 0x62, 0x69, 0x64, 0x73, 0x12, + 0x2e, 0x0a, 0x04, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x73, 0x65, 0x6e, 0x74, 0x22, + 0xb0, 0x02, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x63, + 0x72, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, + 0x74, 0x12, 0x53, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x3b, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, + 0x70, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x7a, 0x0a, 0x0a, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, + 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x14, + 0x0a, 0x10, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, + 0x53, 0x53, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, + 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x52, 0x45, 0x47, 0x49, + 0x53, 0x54, 0x45, 0x52, 0x5f, 0x44, 0x45, 0x4e, 0x49, 0x45, 0x44, 0x10, 0x03, 0x12, 0x13, 0x0a, + 0x0f, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x45, 0x58, 0x49, 0x53, 0x54, 0x53, + 0x10, 0x04, 0x22, 0x97, 0x02, 0x0a, 0x11, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4a, 0x6f, 0x62, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6a, 0x6f, 0x62, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x69, 0x64, 0x12, 0x18, 0x0a, + 0x07, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x54, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3c, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, + 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4a, + 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x5d, 0x0a, + 0x0a, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x53, + 0x55, 0x42, 0x4d, 0x49, 0x54, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, + 0x44, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x55, 0x42, 0x4d, 0x49, 0x54, 0x5f, 0x53, 0x55, + 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x55, 0x42, 0x4d, 0x49, + 0x54, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x55, 0x42, + 0x4d, 0x49, 0x54, 0x5f, 0x44, 0x45, 0x4e, 0x49, 0x45, 0x44, 0x10, 0x03, 0x22, 0x8d, 0x03, 0x0a, + 0x13, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x49, 0x64, 0x12, 0x51, 0x0a, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x3d, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x67, 0x65, - 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x67, - 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4a, 0x6f, - 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x73, 0x0a, 0x0a, 0x41, 0x63, - 0x63, 0x65, 0x70, 0x74, 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4a, 0x6f, 0x62, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x12, 0x56, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3e, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x67, + 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4a, + 0x6f, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x1a, 0x37, + 0x0a, 0x09, 0x4a, 0x6f, 0x62, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x73, 0x0a, 0x0a, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, + 0x5f, 0x4a, 0x4f, 0x42, 0x53, 0x5f, 0x4e, 0x4f, 0x52, 0x45, 0x53, 0x55, 0x4c, 0x54, 0x53, 0x10, + 0x00, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x4a, 0x4f, 0x42, + 0x53, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x52, + 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x4a, 0x4f, 0x42, 0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, + 0x52, 0x10, 0x02, 0x12, 0x17, 0x0a, 0x13, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x4a, + 0x4f, 0x42, 0x53, 0x5f, 0x44, 0x45, 0x4e, 0x49, 0x45, 0x44, 0x10, 0x03, 0x22, 0xdf, 0x01, 0x0a, + 0x12, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x55, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x3d, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x67, 0x65, 0x64, 0x63, + 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x4a, 0x6f, 0x62, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x54, 0x79, + 0x70, 0x65, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x72, 0x0a, 0x0a, 0x52, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x45, 0x53, 0x55, + 0x4c, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, + 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x52, 0x45, 0x53, 0x55, 0x4c, 0x54, 0x5f, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x41, 0x52, 0x54, 0x49, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x17, + 0x0a, 0x13, 0x52, 0x45, 0x53, 0x55, 0x4c, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x55, + 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x52, 0x45, 0x53, 0x55, 0x4c, + 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x32, 0xd0, + 0x05, 0x0a, 0x10, 0x52, 0x61, 0x69, 0x6e, 0x62, 0x6f, 0x77, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, + 0x6c, 0x65, 0x72, 0x12, 0x6d, 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, + 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, + 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, + 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, + 0x75, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, + 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x76, 0x0a, 0x11, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x75, + 0x62, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, + 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6f, 0x72, - 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, - 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x63, 0x6f, + 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x70, 0x0a, 0x09, 0x53, 0x75, + 0x62, 0x6d, 0x69, 0x74, 0x4a, 0x6f, 0x62, 0x12, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, + 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4a, + 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x76, + 0x65, 0x72, 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6f, + 0x72, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, + 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x76, 0x0a, 0x0b, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, 0x6e, 0x67, - 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, - 0x65, 0x70, 0x74, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, - 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, - 0x6e, 0x76, 0x65, 0x72, 0x67, 0x65, 0x64, 0x2d, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, 0x6e, - 0x67, 0x2f, 0x72, 0x61, 0x69, 0x6e, 0x62, 0x6f, 0x77, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x61, 0x70, - 0x69, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, + 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, + 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x76, 0x0a, 0x0b, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4a, + 0x6f, 0x62, 0x73, 0x12, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x67, 0x65, 0x64, 0x63, + 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4a, 0x6f, 0x62, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, + 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, + 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x73, 0x0a, 0x0a, + 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x31, 0x2e, 0x63, 0x6f, 0x6e, + 0x76, 0x65, 0x72, 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x2e, + 0x6f, 0x72, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, + 0x70, 0x74, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, + 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x67, 0x65, 0x64, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x69, + 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x41, + 0x63, 0x63, 0x65, 0x70, 0x74, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x67, 0x65, 0x64, 0x2d, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, + 0x69, 0x6e, 0x67, 0x2f, 0x72, 0x61, 0x69, 0x6e, 0x62, 0x6f, 0x77, 0x2f, 0x70, 0x6b, 0x67, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1040,51 +1235,57 @@ func file_rainbow_proto_rawDescGZIP() []byte { return file_rainbow_proto_rawDescData } -var file_rainbow_proto_enumTypes = make([]protoimpl.EnumInfo, 4) -var file_rainbow_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_rainbow_proto_enumTypes = make([]protoimpl.EnumInfo, 5) +var file_rainbow_proto_msgTypes = make([]protoimpl.MessageInfo, 12) var file_rainbow_proto_goTypes = []interface{}{ - (RegisterResponse_ResultType)(0), // 0: convergedcomputing.org.grpc.v1.RegisterResponse.ResultType - (SubmitJobResponse_ResultType)(0), // 1: convergedcomputing.org.grpc.v1.SubmitJobResponse.ResultType - (ReceiveJobsResponse_ResultType)(0), // 2: convergedcomputing.org.grpc.v1.ReceiveJobsResponse.ResultType - (AcceptJobsResponse_ResultType)(0), // 3: convergedcomputing.org.grpc.v1.AcceptJobsResponse.ResultType - (*RegisterRequest)(nil), // 4: convergedcomputing.org.grpc.v1.RegisterRequest - (*SubmitJobRequest)(nil), // 5: convergedcomputing.org.grpc.v1.SubmitJobRequest - (*ReceiveJobsRequest)(nil), // 6: convergedcomputing.org.grpc.v1.ReceiveJobsRequest - (*AcceptJobsRequest)(nil), // 7: convergedcomputing.org.grpc.v1.AcceptJobsRequest - (*RegisterResponse)(nil), // 8: convergedcomputing.org.grpc.v1.RegisterResponse - (*SubmitJobResponse)(nil), // 9: convergedcomputing.org.grpc.v1.SubmitJobResponse - (*ReceiveJobsResponse)(nil), // 10: convergedcomputing.org.grpc.v1.ReceiveJobsResponse - (*AcceptJobsResponse)(nil), // 11: convergedcomputing.org.grpc.v1.AcceptJobsResponse - (*SubmitJobRequest_Cluster)(nil), // 12: convergedcomputing.org.grpc.v1.SubmitJobRequest.Cluster - nil, // 13: convergedcomputing.org.grpc.v1.ReceiveJobsResponse.JobsEntry - (*timestamppb.Timestamp)(nil), // 14: google.protobuf.Timestamp + (UpdateStateResponse_ResultType)(0), // 0: convergedcomputing.org.grpc.v1.UpdateStateResponse.ResultType + (RegisterResponse_ResultType)(0), // 1: convergedcomputing.org.grpc.v1.RegisterResponse.ResultType + (SubmitJobResponse_ResultType)(0), // 2: convergedcomputing.org.grpc.v1.SubmitJobResponse.ResultType + (ReceiveJobsResponse_ResultType)(0), // 3: convergedcomputing.org.grpc.v1.ReceiveJobsResponse.ResultType + (AcceptJobsResponse_ResultType)(0), // 4: convergedcomputing.org.grpc.v1.AcceptJobsResponse.ResultType + (*RegisterRequest)(nil), // 5: convergedcomputing.org.grpc.v1.RegisterRequest + (*UpdateStateRequest)(nil), // 6: convergedcomputing.org.grpc.v1.UpdateStateRequest + (*UpdateStateResponse)(nil), // 7: convergedcomputing.org.grpc.v1.UpdateStateResponse + (*SubmitJobRequest)(nil), // 8: convergedcomputing.org.grpc.v1.SubmitJobRequest + (*ReceiveJobsRequest)(nil), // 9: convergedcomputing.org.grpc.v1.ReceiveJobsRequest + (*AcceptJobsRequest)(nil), // 10: convergedcomputing.org.grpc.v1.AcceptJobsRequest + (*RegisterResponse)(nil), // 11: convergedcomputing.org.grpc.v1.RegisterResponse + (*SubmitJobResponse)(nil), // 12: convergedcomputing.org.grpc.v1.SubmitJobResponse + (*ReceiveJobsResponse)(nil), // 13: convergedcomputing.org.grpc.v1.ReceiveJobsResponse + (*AcceptJobsResponse)(nil), // 14: convergedcomputing.org.grpc.v1.AcceptJobsResponse + (*SubmitJobRequest_Cluster)(nil), // 15: convergedcomputing.org.grpc.v1.SubmitJobRequest.Cluster + nil, // 16: convergedcomputing.org.grpc.v1.ReceiveJobsResponse.JobsEntry + (*timestamppb.Timestamp)(nil), // 17: google.protobuf.Timestamp } var file_rainbow_proto_depIdxs = []int32{ - 14, // 0: convergedcomputing.org.grpc.v1.RegisterRequest.sent:type_name -> google.protobuf.Timestamp - 12, // 1: convergedcomputing.org.grpc.v1.SubmitJobRequest.clusters:type_name -> convergedcomputing.org.grpc.v1.SubmitJobRequest.Cluster - 14, // 2: convergedcomputing.org.grpc.v1.SubmitJobRequest.sent:type_name -> google.protobuf.Timestamp - 14, // 3: convergedcomputing.org.grpc.v1.ReceiveJobsRequest.sent:type_name -> google.protobuf.Timestamp - 14, // 4: convergedcomputing.org.grpc.v1.AcceptJobsRequest.sent:type_name -> google.protobuf.Timestamp - 0, // 5: convergedcomputing.org.grpc.v1.RegisterResponse.status:type_name -> convergedcomputing.org.grpc.v1.RegisterResponse.ResultType - 1, // 6: convergedcomputing.org.grpc.v1.SubmitJobResponse.status:type_name -> convergedcomputing.org.grpc.v1.SubmitJobResponse.ResultType - 13, // 7: convergedcomputing.org.grpc.v1.ReceiveJobsResponse.jobs:type_name -> convergedcomputing.org.grpc.v1.ReceiveJobsResponse.JobsEntry - 2, // 8: convergedcomputing.org.grpc.v1.ReceiveJobsResponse.status:type_name -> convergedcomputing.org.grpc.v1.ReceiveJobsResponse.ResultType - 3, // 9: convergedcomputing.org.grpc.v1.AcceptJobsResponse.status:type_name -> convergedcomputing.org.grpc.v1.AcceptJobsResponse.ResultType - 4, // 10: convergedcomputing.org.grpc.v1.RainbowScheduler.Register:input_type -> convergedcomputing.org.grpc.v1.RegisterRequest - 4, // 11: convergedcomputing.org.grpc.v1.RainbowScheduler.RegisterSubsystem:input_type -> convergedcomputing.org.grpc.v1.RegisterRequest - 5, // 12: convergedcomputing.org.grpc.v1.RainbowScheduler.SubmitJob:input_type -> convergedcomputing.org.grpc.v1.SubmitJobRequest - 6, // 13: convergedcomputing.org.grpc.v1.RainbowScheduler.ReceiveJobs:input_type -> convergedcomputing.org.grpc.v1.ReceiveJobsRequest - 7, // 14: convergedcomputing.org.grpc.v1.RainbowScheduler.AcceptJobs:input_type -> convergedcomputing.org.grpc.v1.AcceptJobsRequest - 8, // 15: convergedcomputing.org.grpc.v1.RainbowScheduler.Register:output_type -> convergedcomputing.org.grpc.v1.RegisterResponse - 8, // 16: convergedcomputing.org.grpc.v1.RainbowScheduler.RegisterSubsystem:output_type -> convergedcomputing.org.grpc.v1.RegisterResponse - 9, // 17: convergedcomputing.org.grpc.v1.RainbowScheduler.SubmitJob:output_type -> convergedcomputing.org.grpc.v1.SubmitJobResponse - 10, // 18: convergedcomputing.org.grpc.v1.RainbowScheduler.ReceiveJobs:output_type -> convergedcomputing.org.grpc.v1.ReceiveJobsResponse - 11, // 19: convergedcomputing.org.grpc.v1.RainbowScheduler.AcceptJobs:output_type -> convergedcomputing.org.grpc.v1.AcceptJobsResponse - 15, // [15:20] is the sub-list for method output_type - 10, // [10:15] is the sub-list for method input_type - 10, // [10:10] is the sub-list for extension type_name - 10, // [10:10] is the sub-list for extension extendee - 0, // [0:10] is the sub-list for field type_name + 17, // 0: convergedcomputing.org.grpc.v1.RegisterRequest.sent:type_name -> google.protobuf.Timestamp + 0, // 1: convergedcomputing.org.grpc.v1.UpdateStateResponse.status:type_name -> convergedcomputing.org.grpc.v1.UpdateStateResponse.ResultType + 15, // 2: convergedcomputing.org.grpc.v1.SubmitJobRequest.clusters:type_name -> convergedcomputing.org.grpc.v1.SubmitJobRequest.Cluster + 17, // 3: convergedcomputing.org.grpc.v1.SubmitJobRequest.sent:type_name -> google.protobuf.Timestamp + 17, // 4: convergedcomputing.org.grpc.v1.ReceiveJobsRequest.sent:type_name -> google.protobuf.Timestamp + 17, // 5: convergedcomputing.org.grpc.v1.AcceptJobsRequest.sent:type_name -> google.protobuf.Timestamp + 1, // 6: convergedcomputing.org.grpc.v1.RegisterResponse.status:type_name -> convergedcomputing.org.grpc.v1.RegisterResponse.ResultType + 2, // 7: convergedcomputing.org.grpc.v1.SubmitJobResponse.status:type_name -> convergedcomputing.org.grpc.v1.SubmitJobResponse.ResultType + 16, // 8: convergedcomputing.org.grpc.v1.ReceiveJobsResponse.jobs:type_name -> convergedcomputing.org.grpc.v1.ReceiveJobsResponse.JobsEntry + 3, // 9: convergedcomputing.org.grpc.v1.ReceiveJobsResponse.status:type_name -> convergedcomputing.org.grpc.v1.ReceiveJobsResponse.ResultType + 4, // 10: convergedcomputing.org.grpc.v1.AcceptJobsResponse.status:type_name -> convergedcomputing.org.grpc.v1.AcceptJobsResponse.ResultType + 5, // 11: convergedcomputing.org.grpc.v1.RainbowScheduler.Register:input_type -> convergedcomputing.org.grpc.v1.RegisterRequest + 5, // 12: convergedcomputing.org.grpc.v1.RainbowScheduler.RegisterSubsystem:input_type -> convergedcomputing.org.grpc.v1.RegisterRequest + 8, // 13: convergedcomputing.org.grpc.v1.RainbowScheduler.SubmitJob:input_type -> convergedcomputing.org.grpc.v1.SubmitJobRequest + 6, // 14: convergedcomputing.org.grpc.v1.RainbowScheduler.UpdateState:input_type -> convergedcomputing.org.grpc.v1.UpdateStateRequest + 9, // 15: convergedcomputing.org.grpc.v1.RainbowScheduler.ReceiveJobs:input_type -> convergedcomputing.org.grpc.v1.ReceiveJobsRequest + 10, // 16: convergedcomputing.org.grpc.v1.RainbowScheduler.AcceptJobs:input_type -> convergedcomputing.org.grpc.v1.AcceptJobsRequest + 11, // 17: convergedcomputing.org.grpc.v1.RainbowScheduler.Register:output_type -> convergedcomputing.org.grpc.v1.RegisterResponse + 11, // 18: convergedcomputing.org.grpc.v1.RainbowScheduler.RegisterSubsystem:output_type -> convergedcomputing.org.grpc.v1.RegisterResponse + 12, // 19: convergedcomputing.org.grpc.v1.RainbowScheduler.SubmitJob:output_type -> convergedcomputing.org.grpc.v1.SubmitJobResponse + 7, // 20: convergedcomputing.org.grpc.v1.RainbowScheduler.UpdateState:output_type -> convergedcomputing.org.grpc.v1.UpdateStateResponse + 13, // 21: convergedcomputing.org.grpc.v1.RainbowScheduler.ReceiveJobs:output_type -> convergedcomputing.org.grpc.v1.ReceiveJobsResponse + 14, // 22: convergedcomputing.org.grpc.v1.RainbowScheduler.AcceptJobs:output_type -> convergedcomputing.org.grpc.v1.AcceptJobsResponse + 17, // [17:23] is the sub-list for method output_type + 11, // [11:17] is the sub-list for method input_type + 11, // [11:11] is the sub-list for extension type_name + 11, // [11:11] is the sub-list for extension extendee + 0, // [0:11] is the sub-list for field type_name } func init() { file_rainbow_proto_init() } @@ -1106,7 +1307,7 @@ func file_rainbow_proto_init() { } } file_rainbow_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitJobRequest); i { + switch v := v.(*UpdateStateRequest); i { case 0: return &v.state case 1: @@ -1118,7 +1319,7 @@ func file_rainbow_proto_init() { } } file_rainbow_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReceiveJobsRequest); i { + switch v := v.(*UpdateStateResponse); i { case 0: return &v.state case 1: @@ -1130,7 +1331,7 @@ func file_rainbow_proto_init() { } } file_rainbow_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AcceptJobsRequest); i { + switch v := v.(*SubmitJobRequest); i { case 0: return &v.state case 1: @@ -1142,7 +1343,7 @@ func file_rainbow_proto_init() { } } file_rainbow_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RegisterResponse); i { + switch v := v.(*ReceiveJobsRequest); i { case 0: return &v.state case 1: @@ -1154,7 +1355,7 @@ func file_rainbow_proto_init() { } } file_rainbow_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitJobResponse); i { + switch v := v.(*AcceptJobsRequest); i { case 0: return &v.state case 1: @@ -1166,7 +1367,7 @@ func file_rainbow_proto_init() { } } file_rainbow_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReceiveJobsResponse); i { + switch v := v.(*RegisterResponse); i { case 0: return &v.state case 1: @@ -1178,7 +1379,7 @@ func file_rainbow_proto_init() { } } file_rainbow_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AcceptJobsResponse); i { + switch v := v.(*SubmitJobResponse); i { case 0: return &v.state case 1: @@ -1190,6 +1391,30 @@ func file_rainbow_proto_init() { } } file_rainbow_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReceiveJobsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rainbow_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AcceptJobsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rainbow_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SubmitJobRequest_Cluster); i { case 0: return &v.state @@ -1207,8 +1432,8 @@ func file_rainbow_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_rainbow_proto_rawDesc, - NumEnums: 4, - NumMessages: 10, + NumEnums: 5, + NumMessages: 12, NumExtensions: 0, NumServices: 1, }, diff --git a/pkg/api/v1/rainbow_grpc.pb.go b/pkg/api/v1/rainbow_grpc.pb.go index b671cc6..427208a 100644 --- a/pkg/api/v1/rainbow_grpc.pb.go +++ b/pkg/api/v1/rainbow_grpc.pb.go @@ -28,6 +28,9 @@ type RainbowSchedulerClient interface { RegisterSubsystem(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*RegisterResponse, error) // Job Submission - request for submitting a job to a named cluster SubmitJob(ctx context.Context, in *SubmitJobRequest, opts ...grpc.CallOption) (*SubmitJobResponse, error) + // Update State - allow a cluster to provide state metadata + // This is intended for use by a selection algorithm + UpdateState(ctx context.Context, in *UpdateStateRequest, opts ...grpc.CallOption) (*UpdateStateResponse, error) // Request Job - ask the rainbow scheduler for up to max jobs ReceiveJobs(ctx context.Context, in *ReceiveJobsRequest, opts ...grpc.CallOption) (*ReceiveJobsResponse, error) // Accept Jobs - accept some number of jobs @@ -69,6 +72,15 @@ func (c *rainbowSchedulerClient) SubmitJob(ctx context.Context, in *SubmitJobReq return out, nil } +func (c *rainbowSchedulerClient) UpdateState(ctx context.Context, in *UpdateStateRequest, opts ...grpc.CallOption) (*UpdateStateResponse, error) { + out := new(UpdateStateResponse) + err := c.cc.Invoke(ctx, "/convergedcomputing.org.grpc.v1.RainbowScheduler/UpdateState", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *rainbowSchedulerClient) ReceiveJobs(ctx context.Context, in *ReceiveJobsRequest, opts ...grpc.CallOption) (*ReceiveJobsResponse, error) { out := new(ReceiveJobsResponse) err := c.cc.Invoke(ctx, "/convergedcomputing.org.grpc.v1.RainbowScheduler/ReceiveJobs", in, out, opts...) @@ -97,6 +109,9 @@ type RainbowSchedulerServer interface { RegisterSubsystem(context.Context, *RegisterRequest) (*RegisterResponse, error) // Job Submission - request for submitting a job to a named cluster SubmitJob(context.Context, *SubmitJobRequest) (*SubmitJobResponse, error) + // Update State - allow a cluster to provide state metadata + // This is intended for use by a selection algorithm + UpdateState(context.Context, *UpdateStateRequest) (*UpdateStateResponse, error) // Request Job - ask the rainbow scheduler for up to max jobs ReceiveJobs(context.Context, *ReceiveJobsRequest) (*ReceiveJobsResponse, error) // Accept Jobs - accept some number of jobs @@ -117,6 +132,9 @@ func (UnimplementedRainbowSchedulerServer) RegisterSubsystem(context.Context, *R func (UnimplementedRainbowSchedulerServer) SubmitJob(context.Context, *SubmitJobRequest) (*SubmitJobResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method SubmitJob not implemented") } +func (UnimplementedRainbowSchedulerServer) UpdateState(context.Context, *UpdateStateRequest) (*UpdateStateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateState not implemented") +} func (UnimplementedRainbowSchedulerServer) ReceiveJobs(context.Context, *ReceiveJobsRequest) (*ReceiveJobsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ReceiveJobs not implemented") } @@ -190,6 +208,24 @@ func _RainbowScheduler_SubmitJob_Handler(srv interface{}, ctx context.Context, d return interceptor(ctx, in, info, handler) } +func _RainbowScheduler_UpdateState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateStateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RainbowSchedulerServer).UpdateState(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/convergedcomputing.org.grpc.v1.RainbowScheduler/UpdateState", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RainbowSchedulerServer).UpdateState(ctx, req.(*UpdateStateRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _RainbowScheduler_ReceiveJobs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ReceiveJobsRequest) if err := dec(in); err != nil { @@ -245,6 +281,10 @@ var RainbowScheduler_ServiceDesc = grpc.ServiceDesc{ MethodName: "SubmitJob", Handler: _RainbowScheduler_SubmitJob_Handler, }, + { + MethodName: "UpdateState", + Handler: _RainbowScheduler_UpdateState_Handler, + }, { MethodName: "ReceiveJobs", Handler: _RainbowScheduler_ReceiveJobs_Handler, diff --git a/pkg/client/client.go b/pkg/client/client.go index 98ea78b..71b4cc2 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -30,6 +30,9 @@ type Client interface { Register(ctx context.Context, clusterName, secret, clusterNodes, subsystem string) (*pb.RegisterResponse, error) RegisterSubsystem(ctx context.Context, clusterName, secret, subsystemNodes, subsystem string) (*pb.RegisterResponse, error) + // Update + UpdateState(ctx context.Context, clusterName, secret, stateFile string) (*pb.UpdateStateResponse, error) + // Job Client Interactions AcceptJobs(ctx context.Context, cluster, secret string, jobids []int32) (*pb.AcceptJobsResponse, error) SubmitJob(ctx context.Context, job *js.Jobspec, cfg *config.RainbowConfig) (*pb.SubmitJobResponse, error) diff --git a/pkg/client/endpoint.go b/pkg/client/endpoint.go index 1065a8e..a77c63c 100644 --- a/pkg/client/endpoint.go +++ b/pkg/client/endpoint.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "log" + "os" "time" js "github.com/compspec/jobspec-go/pkg/jobspec/experimental" @@ -220,6 +221,56 @@ func (c *RainbowClient) Register( return response, nil } +// UpdateState of an existing cluster +func (c *RainbowClient) UpdateState( + ctx context.Context, + cluster string, + secret string, + stateFile string, +) (*pb.UpdateStateResponse, error) { + + response := &pb.UpdateStateResponse{} + + // Unlike register, this is the cluster to add the subsytem for. + if cluster == "" { + return response, errors.New("cluster is required") + } + if secret == "" { + return response, errors.New("secret is required") + } + if !c.Connected() { + return response, errors.New("client is not connected") + } + if stateFile == "" { + return response, fmt.Errorf("a state file must be provided with --state-file") + } + _, err := utils.PathExists(stateFile) + if err != nil { + return response, errors.New(fmt.Sprintf("state file %s does not exist: %s", stateFile, err)) + } + + // Read stateFile into payload + states, err := os.ReadFile(stateFile) + if err != nil { + return response, err + } + + // Contact the server and print out its response. + ctx, cancel := context.WithTimeout(ctx, time.Second) + defer cancel() + + // Hit the register subsystem endpoint + response, err = c.service.UpdateState(ctx, &pb.UpdateStateRequest{ + Cluster: cluster, + Secret: secret, + Payload: string(states), + }) + if err != nil { + return response, errors.Wrap(err, "could not update endpoint") + } + return response, nil +} + // Register makes a request to register a new cluster func (c *RainbowClient) RegisterSubsystem( ctx context.Context, diff --git a/pkg/graph/backend/backend.go b/pkg/graph/backend/backend.go index 34124e3..39bcbf3 100644 --- a/pkg/graph/backend/backend.go +++ b/pkg/graph/backend/backend.go @@ -8,6 +8,7 @@ import ( "github.com/converged-computing/jsongraph-go/jsongraph/v2/graph" "github.com/converged-computing/rainbow/pkg/graph/algorithm" + "github.com/converged-computing/rainbow/pkg/types" "google.golang.org/grpc" ) @@ -41,6 +42,13 @@ type GraphBackend interface { // Add a subsystem to the graph AddSubsystem(name string, nodes *graph.JsonGraph, subsystem string) error + + // Update state of a cluster in the graph + UpdateState(name, payload string) error + + // GetStates for a final set of clusters, these states + // go to selection algorithms + GetStates([]string) (map[string]types.ClusterState, error) } // List returns known backends diff --git a/pkg/graph/selection/selection.go b/pkg/graph/selection/selection.go index 89a0fab..6e66006 100644 --- a/pkg/graph/selection/selection.go +++ b/pkg/graph/selection/selection.go @@ -3,6 +3,8 @@ package selection import ( "fmt" "log" + + "github.com/converged-computing/rainbow/pkg/types" ) // Lookup of Algorthms @@ -18,7 +20,8 @@ type SelectionAlgorithm interface { Init(map[string]string) error // Take a list of contenders and select based on algorithm - Select([]string) (string, error) + // The algorithm can optionally use cluster states from the graph + Select([]string, map[string]types.ClusterState) (string, error) } // List returns known backends diff --git a/pkg/server/endpoint.go b/pkg/server/endpoint.go index 5672414..20e1b27 100644 --- a/pkg/server/endpoint.go +++ b/pkg/server/endpoint.go @@ -47,6 +47,30 @@ func (s *Server) Register(_ context.Context, in *pb.RegisterRequest) (*pb.Regist return response, err } +// UpdateState sends state metadata to the graph for the selection step +// This could eventually be used in other parts of the graph search but +// right now makes sense to be used with algorithms +func (s *Server) UpdateState(_ context.Context, in *pb.UpdateStateRequest) (*pb.UpdateStateResponse, error) { + if in == nil { + return nil, errors.New("request is required") + } + if in.Cluster == "" || in.Secret == "" || in.Payload == "" { + return nil, errors.New("cluster, name, secret, and state file payload are required") + } + _, err := s.db.ValidateClusterSecret(in.Cluster, in.Secret) + if err != nil { + return nil, errors.New("request denied") + } + // A subsystem just needs to be added to the graph + log.Printf("📝️ received state update: %s", in.Cluster) + response := pb.UpdateStateResponse{Status: pb.UpdateStateResponse_UPDATE_STATE_SUCCESS} + err = s.graph.UpdateState(in.Cluster, in.Payload) + if err != nil { + response.Status = pb.UpdateStateResponse_UPDATE_STATE_ERROR + } + return &response, err +} + // Register a subsystem with the server func (s *Server) RegisterSubsystem(_ context.Context, in *pb.RegisterRequest) (*pb.RegisterResponse, error) { if in == nil { @@ -119,8 +143,15 @@ func (s *Server) SubmitJob(_ context.Context, in *pb.SubmitJobRequest) (*pb.Subm log.Printf("📝️ received job %s for %d contender clusters", in.Name, len(clusters)) - // Use the algorithm to select a final cluster - selected, err := s.selectionAlgorithm.Select(clusters) + // Get state for clusters. Note that we allow clusters that are missing + // state data - given that the algorithm needs it, they are not included + states, err := s.graph.GetStates(clusters) + if err != nil { + return nil, err + } + + // Use the algorithm to select a final cluster, providing states + selected, err := s.selectionAlgorithm.Select(clusters, states) if err != nil { return nil, err } diff --git a/pkg/types/backend.go b/pkg/types/backend.go index 9dc14aa..d4f80f9 100644 --- a/pkg/types/backend.go +++ b/pkg/types/backend.go @@ -14,6 +14,10 @@ type Resource struct { Metadata metadata.Metadata } +// A Cluster state is a key value interface. +// The algorithms are required to know what they are looking for +type ClusterState map[string]interface{} + // A vertex is defined by an identifier. We use an int // instead of a string because it's faster. Edges are other // vertices (and their identifiers) it's connected to. diff --git a/plugins/backends/memory/cluster.go b/plugins/backends/memory/cluster.go index d03ac09..9149c30 100644 --- a/plugins/backends/memory/cluster.go +++ b/plugins/backends/memory/cluster.go @@ -7,6 +7,7 @@ import ( jgf "github.com/converged-computing/jsongraph-go/jsongraph/v2/graph" rlog "github.com/converged-computing/rainbow/pkg/logger" + "github.com/converged-computing/rainbow/pkg/types" ) var ( @@ -19,6 +20,7 @@ var ( type ClusterGraph struct { subsystem map[string]*Subsystem lock sync.RWMutex + State map[string]interface{} // Courtesy holder for name Name string @@ -28,6 +30,14 @@ type ClusterGraph struct { dominantSubsystem string } +// GetState of the cluster +// We could expose this as a public variable, but I'm leaving +// like this in case we want to do additional processing +// (for example, maybe some attributes are private) +func (c *ClusterGraph) GetState() types.ClusterState { + return c.State +} + // Dominant subsystem gets the dominant subsystem func (c *ClusterGraph) DominantSubsystem() *Subsystem { return c.subsystem[c.dominantSubsystem] @@ -113,6 +123,7 @@ func NewClusterGraph(name string, domSubsystem string) *ClusterGraph { Name: name, subsystem: subsystems, dominantSubsystem: defaultDominantSubsystem, + State: types.ClusterState{}, } return g } diff --git a/plugins/backends/memory/graph.go b/plugins/backends/memory/graph.go index 199c710..34bc689 100644 --- a/plugins/backends/memory/graph.go +++ b/plugins/backends/memory/graph.go @@ -16,6 +16,7 @@ import ( "github.com/converged-computing/rainbow/pkg/graph" "github.com/converged-computing/rainbow/pkg/graph/algorithm" rlog "github.com/converged-computing/rainbow/pkg/logger" + "github.com/converged-computing/rainbow/pkg/types" "github.com/converged-computing/rainbow/pkg/utils" "github.com/converged-computing/rainbow/plugins/backends/memory/service" ) @@ -30,6 +31,35 @@ type Graph struct { dominantSubsystem string } +// GetStates for clusters in the graph +func (g *Graph) GetStates(names []string) (map[string]types.ClusterState, error) { + states := map[string]types.ClusterState{} + for _, name := range names { + + // Only error if the cluster isn't known + cluster, ok := g.Clusters[name] + if !ok { + return states, fmt.Errorf("cluster %s does not exist", name) + } + states[name] = cluster.GetState() + } + return states, nil +} + +// UpdateState updates the state of a known cluster in the graph +func (g *Graph) UpdateState(name string, state *types.ClusterState) error { + cluster, ok := g.Clusters[name] + if !ok { + return fmt.Errorf("cluster %s does not exist", name) + } + // We always update old values + for key, value := range *state { + rlog.Debugf("Updating state %s to %v\n", key, value) + cluster.State[key] = value + } + return nil +} + // NewGraph creates a structure that holds one or more graphs func NewGraph() *Graph { diff --git a/plugins/backends/memory/memory.go b/plugins/backends/memory/memory.go index 1017ba8..f4509f2 100644 --- a/plugins/backends/memory/memory.go +++ b/plugins/backends/memory/memory.go @@ -12,6 +12,7 @@ import ( "github.com/converged-computing/rainbow/pkg/graph/algorithm" "github.com/converged-computing/rainbow/pkg/graph/backend" + "github.com/converged-computing/rainbow/pkg/types" "github.com/converged-computing/rainbow/plugins/backends/memory/service" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" @@ -53,6 +54,26 @@ func (m MemoryGraph) AddCluster( } // Add subsystem adds a new subsystem to the graph! +func (m MemoryGraph) UpdateState( + name string, + payload string, +) error { + // Load state into interface + state := types.ClusterState{} + err := json.Unmarshal([]byte(payload), &state) + if err != nil { + return err + } + return graphClient.UpdateState(name, &state) +} + +// GetStates for a list of clusters +func (m MemoryGraph) GetStates(names []string) (map[string]types.ClusterState, error) { + return graphClient.GetStates(names) +} + +// UpdateState of a cluster in the graph. +// This is used for selection algorithms func (m MemoryGraph) AddSubsystem( name string, nodes *jgf.JsonGraph, diff --git a/plugins/selection/random/random.go b/plugins/selection/random/random.go index 0f36a58..3357caa 100644 --- a/plugins/selection/random/random.go +++ b/plugins/selection/random/random.go @@ -4,6 +4,7 @@ import ( "math/rand" "github.com/converged-computing/rainbow/pkg/graph/selection" + "github.com/converged-computing/rainbow/pkg/types" ) // Random selection of a cluster @@ -26,7 +27,10 @@ func (s RandomSelection) Description() string { // Select randomly chooses a cluster from the set // This should not receive an empty list, but we check anyway -func (s RandomSelection) Select(contenders []string) (string, error) { +func (s RandomSelection) Select( + contenders []string, + states map[string]types.ClusterState, +) (string, error) { if len(contenders) == 0 { return "", nil } diff --git a/python/v1/README.md b/python/v1/README.md index 8fcc897..84b2e57 100644 --- a/python/v1/README.md +++ b/python/v1/README.md @@ -100,6 +100,38 @@ In the server window you'll see the subsystem added: } ``` +### Update State + +While we likely will have clusters sending back state when they accept jobs, for now we have a separate endpoint to do a one-off request to update the state. You can test that here. + +```bash +python ./examples/flux/update-state.py keebler --config-path ./rainbow-config.yaml +``` +```console +status: UPDATE_STATE_SUCCESS +``` + +In the server terminal (depending on your level of logging) you'll see the state update. + +```console +2024/04/05 18:45:16 We have made an in memory graph (subsystem io) with 7 vertices, with 15 connections to the dominant! +Metrics for subsystem io{ + "io": 1, + "mtl1unit": 1, + "mtl2unit": 1, + "mtl3unit": 1, + "nvme": 1, + "shm": 1 +} +2024/04/05 18:47:18 📝️ received state update: keebler +Updating state cost-per-node to 12 +Updating state max-jobs to 100 +``` + +Note that the path to the state metadata file is provided as a default to make the demo simple. +This state metadata will be provided to the selection algorithm to use as needed to make choice for +a final cluster. + ### Submit Job (Simple) Now let's submit a job to our faux cluster. We need to provide the token we received above. Remember that this is a two stage process: diff --git a/python/v1/examples/flux/update-state.py b/python/v1/examples/flux/update-state.py new file mode 100644 index 0000000..ea28bb3 --- /dev/null +++ b/python/v1/examples/flux/update-state.py @@ -0,0 +1,50 @@ +import argparse +import os + +from rainbow.protos import rainbow_pb2 +from rainbow.client import RainbowClient +import rainbow.config as config + +# Config file from a few directories up +here = os.path.abspath(os.path.dirname(__file__)) +root = here + +# rainbow root directory +for iter in range(4): + root = os.path.dirname(root) + + +def get_parser(): + parser = argparse.ArgumentParser(description="🌈️ Rainbow scheduler update state") + parser.add_argument("--cluster", help="cluster name to register", default="keebler") + parser.add_argument("--host", help="host of rainbow cluster", default="localhost:50051") + parser.add_argument( + "--config-path", + help="Path to rainbow configuration file to write or use", + ) + parser.add_argument( + "--state-file", + help="Json file with key/value metadata pairs to update", + default=os.path.join(root, "docs", "examples", "scheduler", "cluster-state.json"), + ) + return parser + + +def main(): + parser = get_parser() + args, _ = parser.parse_known_args() + cli = RainbowClient(host=args.host) + + # Do we want to write or update a config file? + if not args.config_path or not os.path.exists(args.config_path): + cfg = config.new_rainbow_config(args.host, args.cluster, args.secret) + else: + cfg = config.RainbowConfig(args.config_path) + + # The secret we need is from the cluster config + secret = cfg._cfg["cluster"]["secret"] + response = cli.update_state(args.cluster, state_file=args.state_file, secret=secret) + print(response) + +if __name__ == "__main__": + main() diff --git a/python/v1/rainbow/client.py b/python/v1/rainbow/client.py index d2ffc22..0e2e9dc 100644 --- a/python/v1/rainbow/client.py +++ b/python/v1/rainbow/client.py @@ -104,6 +104,30 @@ def register(self, cluster, secret, cluster_nodes): response = stub.Register(registerRequest) return response + def update_state(self, cluster, state_file, secret): + """ + Update a cluster state + """ + if not cluster: + raise ValueError("A cluster name is required to register") + if not secret: + raise ValueError("A secret is required to register") + if not os.path.exists(state_file): + raise ValueError(f"State metadata file {state_file} does not exist.") + + payload = utils.read_file(state_file) + + # These are the variables for our cluster - name for now + request = rainbow_pb2.UpdateStateRequest( + cluster=cluster, + secret=secret, + payload=payload, + ) + with grpc.insecure_channel(self.host) as channel: + stub = rainbow_pb2_grpc.RainbowSchedulerStub(channel) + response = stub.UpdateState(request) + return response + def register_subsystem(self, cluster, subsystem, secret, nodes): """ Register subsystem nodes to rainbow diff --git a/python/v1/rainbow/protos/rainbow_pb2.py b/python/v1/rainbow/protos/rainbow_pb2.py index 3e66da7..0cda9fc 100644 --- a/python/v1/rainbow/protos/rainbow_pb2.py +++ b/python/v1/rainbow/protos/rainbow_pb2.py @@ -16,7 +16,7 @@ from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( - b'\n\rrainbow.proto\x12\x1e\x63onvergedcomputing.org.grpc.v1\x1a\x1fgoogle/protobuf/timestamp.proto"{\n\x0fRegisterRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06secret\x18\x02 \x01(\t\x12\r\n\x05nodes\x18\x03 \x01(\t\x12\x11\n\tsubsystem\x18\x04 \x01(\t\x12(\n\x04sent\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp"\xcf\x01\n\x10SubmitJobRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12J\n\x08\x63lusters\x18\x02 \x03(\x0b\x32\x38.convergedcomputing.org.grpc.v1.SubmitJobRequest.Cluster\x12\x0f\n\x07jobspec\x18\x03 \x01(\t\x12(\n\x04sent\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x1a&\n\x07\x43luster\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05token\x18\x02 \x01(\t"p\n\x12ReceiveJobsRequest\x12\x0f\n\x07\x63luster\x18\x01 \x01(\t\x12\x0e\n\x06secret\x18\x02 \x01(\t\x12\x0f\n\x07maxJobs\x18\x03 \x01(\x05\x12(\n\x04sent\x18\x07 \x01(\x0b\x32\x1a.google.protobuf.Timestamp"n\n\x11\x41\x63\x63\x65ptJobsRequest\x12\x0f\n\x07\x63luster\x18\x01 \x01(\t\x12\x0e\n\x06secret\x18\x02 \x01(\t\x12\x0e\n\x06jobids\x18\x03 \x03(\x05\x12(\n\x04sent\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp"\x8e\x02\n\x10RegisterResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12\r\n\x05token\x18\x02 \x01(\t\x12\x0e\n\x06secret\x18\x03 \x01(\t\x12K\n\x06status\x18\x04 \x01(\x0e\x32;.convergedcomputing.org.grpc.v1.RegisterResponse.ResultType"z\n\nResultType\x12\x18\n\x14REGISTER_UNSPECIFIED\x10\x00\x12\x14\n\x10REGISTER_SUCCESS\x10\x01\x12\x12\n\x0eREGISTER_ERROR\x10\x02\x12\x13\n\x0fREGISTER_DENIED\x10\x03\x12\x13\n\x0fREGISTER_EXISTS\x10\x04"\xf4\x01\n\x11SubmitJobResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12\r\n\x05jobid\x18\x02 \x01(\x05\x12\x0f\n\x07\x63luster\x18\x03 \x01(\t\x12L\n\x06status\x18\x04 \x01(\x0e\x32<.convergedcomputing.org.grpc.v1.SubmitJobResponse.ResultType"]\n\nResultType\x12\x16\n\x12SUBMIT_UNSPECIFIED\x10\x00\x12\x12\n\x0eSUBMIT_SUCCESS\x10\x01\x12\x10\n\x0cSUBMIT_ERROR\x10\x02\x12\x11\n\rSUBMIT_DENIED\x10\x03"\xe8\x02\n\x13ReceiveJobsResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12K\n\x04jobs\x18\x02 \x03(\x0b\x32=.convergedcomputing.org.grpc.v1.ReceiveJobsResponse.JobsEntry\x12N\n\x06status\x18\x03 \x01(\x0e\x32>.convergedcomputing.org.grpc.v1.ReceiveJobsResponse.ResultType\x1a+\n\tJobsEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01"s\n\nResultType\x12\x1a\n\x16REQUEST_JOBS_NORESULTS\x10\x00\x12\x18\n\x14REQUEST_JOBS_SUCCESS\x10\x01\x12\x16\n\x12REQUEST_JOBS_ERROR\x10\x02\x12\x17\n\x13REQUEST_JOBS_DENIED\x10\x03"\xd7\x01\n\x12\x41\x63\x63\x65ptJobsResponse\x12M\n\x06status\x18\x01 \x01(\x0e\x32=.convergedcomputing.org.grpc.v1.AcceptJobsResponse.ResultType"r\n\nResultType\x12\x1b\n\x17RESULT_TYPE_UNSPECIFIED\x10\x00\x12\x17\n\x13RESULT_TYPE_PARTIAL\x10\x01\x12\x17\n\x13RESULT_TYPE_SUCCESS\x10\x02\x12\x15\n\x11RESULT_TYPE_ERROR\x10\x03\x32\xd8\x04\n\x10RainbowScheduler\x12m\n\x08Register\x12/.convergedcomputing.org.grpc.v1.RegisterRequest\x1a\x30.convergedcomputing.org.grpc.v1.RegisterResponse\x12v\n\x11RegisterSubsystem\x12/.convergedcomputing.org.grpc.v1.RegisterRequest\x1a\x30.convergedcomputing.org.grpc.v1.RegisterResponse\x12p\n\tSubmitJob\x12\x30.convergedcomputing.org.grpc.v1.SubmitJobRequest\x1a\x31.convergedcomputing.org.grpc.v1.SubmitJobResponse\x12v\n\x0bReceiveJobs\x12\x32.convergedcomputing.org.grpc.v1.ReceiveJobsRequest\x1a\x33.convergedcomputing.org.grpc.v1.ReceiveJobsResponse\x12s\n\nAcceptJobs\x12\x31.convergedcomputing.org.grpc.v1.AcceptJobsRequest\x1a\x32.convergedcomputing.org.grpc.v1.AcceptJobsResponseB3Z1github.com/converged-computing/rainbow/pkg/api/v1b\x06proto3' + b'\n\rrainbow.proto\x12\x1e\x63onvergedcomputing.org.grpc.v1\x1a\x1fgoogle/protobuf/timestamp.proto"{\n\x0fRegisterRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06secret\x18\x02 \x01(\t\x12\r\n\x05nodes\x18\x03 \x01(\t\x12\x11\n\tsubsystem\x18\x04 \x01(\t\x12(\n\x04sent\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp"F\n\x12UpdateStateRequest\x12\x0f\n\x07\x63luster\x18\x01 \x01(\t\x12\x0e\n\x06secret\x18\x02 \x01(\t\x12\x0f\n\x07payload\x18\x03 \x01(\t"\xdd\x01\n\x13UpdateStateResponse\x12N\n\x06status\x18\x01 \x01(\x0e\x32>.convergedcomputing.org.grpc.v1.UpdateStateResponse.ResultType"v\n\nResultType\x12\x1c\n\x18UPDATE_STATE_UNSPECIFIED\x10\x00\x12\x18\n\x14UPDATE_STATE_PARTIAL\x10\x01\x12\x18\n\x14UPDATE_STATE_SUCCESS\x10\x02\x12\x16\n\x12UPDATE_STATE_ERROR\x10\x03"\xcf\x01\n\x10SubmitJobRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12J\n\x08\x63lusters\x18\x02 \x03(\x0b\x32\x38.convergedcomputing.org.grpc.v1.SubmitJobRequest.Cluster\x12\x0f\n\x07jobspec\x18\x03 \x01(\t\x12(\n\x04sent\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x1a&\n\x07\x43luster\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05token\x18\x02 \x01(\t"p\n\x12ReceiveJobsRequest\x12\x0f\n\x07\x63luster\x18\x01 \x01(\t\x12\x0e\n\x06secret\x18\x02 \x01(\t\x12\x0f\n\x07maxJobs\x18\x03 \x01(\x05\x12(\n\x04sent\x18\x07 \x01(\x0b\x32\x1a.google.protobuf.Timestamp"n\n\x11\x41\x63\x63\x65ptJobsRequest\x12\x0f\n\x07\x63luster\x18\x01 \x01(\t\x12\x0e\n\x06secret\x18\x02 \x01(\t\x12\x0e\n\x06jobids\x18\x03 \x03(\x05\x12(\n\x04sent\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp"\x8e\x02\n\x10RegisterResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12\r\n\x05token\x18\x02 \x01(\t\x12\x0e\n\x06secret\x18\x03 \x01(\t\x12K\n\x06status\x18\x04 \x01(\x0e\x32;.convergedcomputing.org.grpc.v1.RegisterResponse.ResultType"z\n\nResultType\x12\x18\n\x14REGISTER_UNSPECIFIED\x10\x00\x12\x14\n\x10REGISTER_SUCCESS\x10\x01\x12\x12\n\x0eREGISTER_ERROR\x10\x02\x12\x13\n\x0fREGISTER_DENIED\x10\x03\x12\x13\n\x0fREGISTER_EXISTS\x10\x04"\xf4\x01\n\x11SubmitJobResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12\r\n\x05jobid\x18\x02 \x01(\x05\x12\x0f\n\x07\x63luster\x18\x03 \x01(\t\x12L\n\x06status\x18\x04 \x01(\x0e\x32<.convergedcomputing.org.grpc.v1.SubmitJobResponse.ResultType"]\n\nResultType\x12\x16\n\x12SUBMIT_UNSPECIFIED\x10\x00\x12\x12\n\x0eSUBMIT_SUCCESS\x10\x01\x12\x10\n\x0cSUBMIT_ERROR\x10\x02\x12\x11\n\rSUBMIT_DENIED\x10\x03"\xe8\x02\n\x13ReceiveJobsResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12K\n\x04jobs\x18\x02 \x03(\x0b\x32=.convergedcomputing.org.grpc.v1.ReceiveJobsResponse.JobsEntry\x12N\n\x06status\x18\x03 \x01(\x0e\x32>.convergedcomputing.org.grpc.v1.ReceiveJobsResponse.ResultType\x1a+\n\tJobsEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01"s\n\nResultType\x12\x1a\n\x16REQUEST_JOBS_NORESULTS\x10\x00\x12\x18\n\x14REQUEST_JOBS_SUCCESS\x10\x01\x12\x16\n\x12REQUEST_JOBS_ERROR\x10\x02\x12\x17\n\x13REQUEST_JOBS_DENIED\x10\x03"\xd7\x01\n\x12\x41\x63\x63\x65ptJobsResponse\x12M\n\x06status\x18\x01 \x01(\x0e\x32=.convergedcomputing.org.grpc.v1.AcceptJobsResponse.ResultType"r\n\nResultType\x12\x1b\n\x17RESULT_TYPE_UNSPECIFIED\x10\x00\x12\x17\n\x13RESULT_TYPE_PARTIAL\x10\x01\x12\x17\n\x13RESULT_TYPE_SUCCESS\x10\x02\x12\x15\n\x11RESULT_TYPE_ERROR\x10\x03\x32\xd0\x05\n\x10RainbowScheduler\x12m\n\x08Register\x12/.convergedcomputing.org.grpc.v1.RegisterRequest\x1a\x30.convergedcomputing.org.grpc.v1.RegisterResponse\x12v\n\x11RegisterSubsystem\x12/.convergedcomputing.org.grpc.v1.RegisterRequest\x1a\x30.convergedcomputing.org.grpc.v1.RegisterResponse\x12p\n\tSubmitJob\x12\x30.convergedcomputing.org.grpc.v1.SubmitJobRequest\x1a\x31.convergedcomputing.org.grpc.v1.SubmitJobResponse\x12v\n\x0bUpdateState\x12\x32.convergedcomputing.org.grpc.v1.UpdateStateRequest\x1a\x33.convergedcomputing.org.grpc.v1.UpdateStateResponse\x12v\n\x0bReceiveJobs\x12\x32.convergedcomputing.org.grpc.v1.ReceiveJobsRequest\x1a\x33.convergedcomputing.org.grpc.v1.ReceiveJobsResponse\x12s\n\nAcceptJobs\x12\x31.convergedcomputing.org.grpc.v1.AcceptJobsRequest\x1a\x32.convergedcomputing.org.grpc.v1.AcceptJobsResponseB3Z1github.com/converged-computing/rainbow/pkg/api/v1b\x06proto3' ) _globals = globals() @@ -31,32 +31,38 @@ _globals["_RECEIVEJOBSRESPONSE_JOBSENTRY"]._serialized_options = b"8\001" _globals["_REGISTERREQUEST"]._serialized_start = 82 _globals["_REGISTERREQUEST"]._serialized_end = 205 - _globals["_SUBMITJOBREQUEST"]._serialized_start = 208 - _globals["_SUBMITJOBREQUEST"]._serialized_end = 415 - _globals["_SUBMITJOBREQUEST_CLUSTER"]._serialized_start = 377 - _globals["_SUBMITJOBREQUEST_CLUSTER"]._serialized_end = 415 - _globals["_RECEIVEJOBSREQUEST"]._serialized_start = 417 - _globals["_RECEIVEJOBSREQUEST"]._serialized_end = 529 - _globals["_ACCEPTJOBSREQUEST"]._serialized_start = 531 - _globals["_ACCEPTJOBSREQUEST"]._serialized_end = 641 - _globals["_REGISTERRESPONSE"]._serialized_start = 644 - _globals["_REGISTERRESPONSE"]._serialized_end = 914 - _globals["_REGISTERRESPONSE_RESULTTYPE"]._serialized_start = 792 - _globals["_REGISTERRESPONSE_RESULTTYPE"]._serialized_end = 914 - _globals["_SUBMITJOBRESPONSE"]._serialized_start = 917 - _globals["_SUBMITJOBRESPONSE"]._serialized_end = 1161 - _globals["_SUBMITJOBRESPONSE_RESULTTYPE"]._serialized_start = 1068 - _globals["_SUBMITJOBRESPONSE_RESULTTYPE"]._serialized_end = 1161 - _globals["_RECEIVEJOBSRESPONSE"]._serialized_start = 1164 - _globals["_RECEIVEJOBSRESPONSE"]._serialized_end = 1524 - _globals["_RECEIVEJOBSRESPONSE_JOBSENTRY"]._serialized_start = 1364 - _globals["_RECEIVEJOBSRESPONSE_JOBSENTRY"]._serialized_end = 1407 - _globals["_RECEIVEJOBSRESPONSE_RESULTTYPE"]._serialized_start = 1409 - _globals["_RECEIVEJOBSRESPONSE_RESULTTYPE"]._serialized_end = 1524 - _globals["_ACCEPTJOBSRESPONSE"]._serialized_start = 1527 - _globals["_ACCEPTJOBSRESPONSE"]._serialized_end = 1742 - _globals["_ACCEPTJOBSRESPONSE_RESULTTYPE"]._serialized_start = 1628 - _globals["_ACCEPTJOBSRESPONSE_RESULTTYPE"]._serialized_end = 1742 - _globals["_RAINBOWSCHEDULER"]._serialized_start = 1745 - _globals["_RAINBOWSCHEDULER"]._serialized_end = 2345 + _globals["_UPDATESTATEREQUEST"]._serialized_start = 207 + _globals["_UPDATESTATEREQUEST"]._serialized_end = 277 + _globals["_UPDATESTATERESPONSE"]._serialized_start = 280 + _globals["_UPDATESTATERESPONSE"]._serialized_end = 501 + _globals["_UPDATESTATERESPONSE_RESULTTYPE"]._serialized_start = 383 + _globals["_UPDATESTATERESPONSE_RESULTTYPE"]._serialized_end = 501 + _globals["_SUBMITJOBREQUEST"]._serialized_start = 504 + _globals["_SUBMITJOBREQUEST"]._serialized_end = 711 + _globals["_SUBMITJOBREQUEST_CLUSTER"]._serialized_start = 673 + _globals["_SUBMITJOBREQUEST_CLUSTER"]._serialized_end = 711 + _globals["_RECEIVEJOBSREQUEST"]._serialized_start = 713 + _globals["_RECEIVEJOBSREQUEST"]._serialized_end = 825 + _globals["_ACCEPTJOBSREQUEST"]._serialized_start = 827 + _globals["_ACCEPTJOBSREQUEST"]._serialized_end = 937 + _globals["_REGISTERRESPONSE"]._serialized_start = 940 + _globals["_REGISTERRESPONSE"]._serialized_end = 1210 + _globals["_REGISTERRESPONSE_RESULTTYPE"]._serialized_start = 1088 + _globals["_REGISTERRESPONSE_RESULTTYPE"]._serialized_end = 1210 + _globals["_SUBMITJOBRESPONSE"]._serialized_start = 1213 + _globals["_SUBMITJOBRESPONSE"]._serialized_end = 1457 + _globals["_SUBMITJOBRESPONSE_RESULTTYPE"]._serialized_start = 1364 + _globals["_SUBMITJOBRESPONSE_RESULTTYPE"]._serialized_end = 1457 + _globals["_RECEIVEJOBSRESPONSE"]._serialized_start = 1460 + _globals["_RECEIVEJOBSRESPONSE"]._serialized_end = 1820 + _globals["_RECEIVEJOBSRESPONSE_JOBSENTRY"]._serialized_start = 1660 + _globals["_RECEIVEJOBSRESPONSE_JOBSENTRY"]._serialized_end = 1703 + _globals["_RECEIVEJOBSRESPONSE_RESULTTYPE"]._serialized_start = 1705 + _globals["_RECEIVEJOBSRESPONSE_RESULTTYPE"]._serialized_end = 1820 + _globals["_ACCEPTJOBSRESPONSE"]._serialized_start = 1823 + _globals["_ACCEPTJOBSRESPONSE"]._serialized_end = 2038 + _globals["_ACCEPTJOBSRESPONSE_RESULTTYPE"]._serialized_start = 1924 + _globals["_ACCEPTJOBSRESPONSE_RESULTTYPE"]._serialized_end = 2038 + _globals["_RAINBOWSCHEDULER"]._serialized_start = 2041 + _globals["_RAINBOWSCHEDULER"]._serialized_end = 2761 # @@protoc_insertion_point(module_scope) diff --git a/python/v1/rainbow/protos/rainbow_pb2.pyi b/python/v1/rainbow/protos/rainbow_pb2.pyi index d038642..2ca4aff 100644 --- a/python/v1/rainbow/protos/rainbow_pb2.pyi +++ b/python/v1/rainbow/protos/rainbow_pb2.pyi @@ -21,6 +21,32 @@ class RegisterRequest(_message.Message): sent: _timestamp_pb2.Timestamp def __init__(self, name: _Optional[str] = ..., secret: _Optional[str] = ..., nodes: _Optional[str] = ..., subsystem: _Optional[str] = ..., sent: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ...) -> None: ... +class UpdateStateRequest(_message.Message): + __slots__ = ("cluster", "secret", "payload") + CLUSTER_FIELD_NUMBER: _ClassVar[int] + SECRET_FIELD_NUMBER: _ClassVar[int] + PAYLOAD_FIELD_NUMBER: _ClassVar[int] + cluster: str + secret: str + payload: str + def __init__(self, cluster: _Optional[str] = ..., secret: _Optional[str] = ..., payload: _Optional[str] = ...) -> None: ... + +class UpdateStateResponse(_message.Message): + __slots__ = ("status",) + class ResultType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): + __slots__ = () + UPDATE_STATE_UNSPECIFIED: _ClassVar[UpdateStateResponse.ResultType] + UPDATE_STATE_PARTIAL: _ClassVar[UpdateStateResponse.ResultType] + UPDATE_STATE_SUCCESS: _ClassVar[UpdateStateResponse.ResultType] + UPDATE_STATE_ERROR: _ClassVar[UpdateStateResponse.ResultType] + UPDATE_STATE_UNSPECIFIED: UpdateStateResponse.ResultType + UPDATE_STATE_PARTIAL: UpdateStateResponse.ResultType + UPDATE_STATE_SUCCESS: UpdateStateResponse.ResultType + UPDATE_STATE_ERROR: UpdateStateResponse.ResultType + STATUS_FIELD_NUMBER: _ClassVar[int] + status: UpdateStateResponse.ResultType + def __init__(self, status: _Optional[_Union[UpdateStateResponse.ResultType, str]] = ...) -> None: ... + class SubmitJobRequest(_message.Message): __slots__ = ("name", "clusters", "jobspec", "sent") class Cluster(_message.Message): diff --git a/python/v1/rainbow/protos/rainbow_pb2_grpc.py b/python/v1/rainbow/protos/rainbow_pb2_grpc.py index 581d9ea..2211f2e 100644 --- a/python/v1/rainbow/protos/rainbow_pb2_grpc.py +++ b/python/v1/rainbow/protos/rainbow_pb2_grpc.py @@ -29,6 +29,11 @@ def __init__(self, channel): request_serializer=rainbow__pb2.SubmitJobRequest.SerializeToString, response_deserializer=rainbow__pb2.SubmitJobResponse.FromString, ) + self.UpdateState = channel.unary_unary( + "/convergedcomputing.org.grpc.v1.RainbowScheduler/UpdateState", + request_serializer=rainbow__pb2.UpdateStateRequest.SerializeToString, + response_deserializer=rainbow__pb2.UpdateStateResponse.FromString, + ) self.ReceiveJobs = channel.unary_unary( "/convergedcomputing.org.grpc.v1.RainbowScheduler/ReceiveJobs", request_serializer=rainbow__pb2.ReceiveJobsRequest.SerializeToString, @@ -62,6 +67,14 @@ def SubmitJob(self, request, context): context.set_details("Method not implemented!") raise NotImplementedError("Method not implemented!") + def UpdateState(self, request, context): + """Update State - allow a cluster to provide state metadata + This is intended for use by a selection algorithm + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + def ReceiveJobs(self, request, context): """Request Job - ask the rainbow scheduler for up to max jobs""" context.set_code(grpc.StatusCode.UNIMPLEMENTED) @@ -92,6 +105,11 @@ def add_RainbowSchedulerServicer_to_server(servicer, server): request_deserializer=rainbow__pb2.SubmitJobRequest.FromString, response_serializer=rainbow__pb2.SubmitJobResponse.SerializeToString, ), + "UpdateState": grpc.unary_unary_rpc_method_handler( + servicer.UpdateState, + request_deserializer=rainbow__pb2.UpdateStateRequest.FromString, + response_serializer=rainbow__pb2.UpdateStateResponse.SerializeToString, + ), "ReceiveJobs": grpc.unary_unary_rpc_method_handler( servicer.ReceiveJobs, request_deserializer=rainbow__pb2.ReceiveJobsRequest.FromString, @@ -200,6 +218,35 @@ def SubmitJob( metadata, ) + @staticmethod + def UpdateState( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/convergedcomputing.org.grpc.v1.RainbowScheduler/UpdateState", + rainbow__pb2.UpdateStateRequest.SerializeToString, + rainbow__pb2.UpdateStateResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + ) + @staticmethod def ReceiveJobs( request, diff --git a/python/v1/setup.py b/python/v1/setup.py index 9e91888..22b1e37 100644 --- a/python/v1/setup.py +++ b/python/v1/setup.py @@ -18,7 +18,7 @@ if __name__ == "__main__": setup( name="rainbow-scheduler", - version="0.0.14", + version="0.0.15", author="Vanessasaurus", author_email="vsoch@users.noreply.github.com", maintainer="Vanessasaurus",