From 0094b88da98977f085d86dbc6aecb4ba9162a935 Mon Sep 17 00:00:00 2001 From: Jacob Barzee Date: Fri, 19 Mar 2021 02:26:11 -0600 Subject: [PATCH 01/15] A quick outline of the gRPC Server --- README.md | 6 + grpc/bitbox.pb.go | 724 +++++++++++++++++++++++++++++++++++++++++ grpc/bitbox.proto | 95 ++++++ grpc/bitbox_grpc.pb.go | 245 ++++++++++++++ grpc/generate.go | 4 + 5 files changed, 1074 insertions(+) create mode 100644 grpc/bitbox.pb.go create mode 100644 grpc/bitbox.proto create mode 100644 grpc/bitbox_grpc.pb.go create mode 100644 grpc/generate.go diff --git a/README.md b/README.md index d774eb5..2b4e3e2 100644 --- a/README.md +++ b/README.md @@ -7,3 +7,9 @@ # BitBox Rudementary implementation of containerization in linux. + + +## Development Tools +[gRPC & protoc](https://grpc.io/docs/languages/go/quickstart/) are used by `go generate` to update [bitbox/grpc](grpc/). + +[gRPCox](https://github.com/gusaul/grpcox) is a lightweight docker container for easy manual testing. \ No newline at end of file diff --git a/grpc/bitbox.pb.go b/grpc/bitbox.pb.go new file mode 100644 index 0000000..d0b73e8 --- /dev/null +++ b/grpc/bitbox.pb.go @@ -0,0 +1,724 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.25.0-devel +// protoc v3.15.6 +// source: bitbox.proto + +package grpc + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type StatusReply_Status int32 + +const ( + // Running indicates that the process is running. + StatusReply_Running StatusReply_Status = 0 + // Exited indicates that the process returned a non-zero exit code. + StatusReply_Exited StatusReply_Status = 1 + // Stopped indicates that the process returned no exit code. + StatusReply_Stopped StatusReply_Status = 2 +) + +// Enum value maps for StatusReply_Status. +var ( + StatusReply_Status_name = map[int32]string{ + 0: "Running", + 1: "Exited", + 2: "Stopped", + } + StatusReply_Status_value = map[string]int32{ + "Running": 0, + "Exited": 1, + "Stopped": 2, + } +) + +func (x StatusReply_Status) Enum() *StatusReply_Status { + p := new(StatusReply_Status) + *p = x + return p +} + +func (x StatusReply_Status) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (StatusReply_Status) Descriptor() protoreflect.EnumDescriptor { + return file_bitbox_proto_enumTypes[0].Descriptor() +} + +func (StatusReply_Status) Type() protoreflect.EnumType { + return &file_bitbox_proto_enumTypes[0] +} + +func (x StatusReply_Status) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use StatusReply_Status.Descriptor instead. +func (StatusReply_Status) EnumDescriptor() ([]byte, []int) { + return file_bitbox_proto_rawDescGZIP(), []int{5, 0} +} + +// StartRequest holds the command and nessecary parameters to run it. +type StartRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Command is an arbitrary linux command. + // Command should be a fullpath or found in a directory in PATH. + Command string `protobuf:"bytes,1,opt,name=Command,proto3" json:"Command,omitempty"` + // Parameters are handed to the command as ARGV. + // Glob patterns, pipelines, and redirections are not handled + // and will instead be passed as literal strings to the command. + Parameters []string `protobuf:"bytes,2,rep,name=Parameters,proto3" json:"Parameters,omitempty"` +} + +func (x *StartRequest) Reset() { + *x = StartRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_bitbox_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StartRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StartRequest) ProtoMessage() {} + +func (x *StartRequest) ProtoReflect() protoreflect.Message { + mi := &file_bitbox_proto_msgTypes[0] + 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 StartRequest.ProtoReflect.Descriptor instead. +func (*StartRequest) Descriptor() ([]byte, []int) { + return file_bitbox_proto_rawDescGZIP(), []int{0} +} + +func (x *StartRequest) GetCommand() string { + if x != nil { + return x.Command + } + return "" +} + +func (x *StartRequest) GetParameters() []string { + if x != nil { + return x.Parameters + } + return nil +} + +// StartReply holds the ID of the started process. +type StartReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // ID is the unique identifier of the process. + ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` +} + +func (x *StartReply) Reset() { + *x = StartReply{} + if protoimpl.UnsafeEnabled { + mi := &file_bitbox_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StartReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StartReply) ProtoMessage() {} + +func (x *StartReply) ProtoReflect() protoreflect.Message { + mi := &file_bitbox_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 StartReply.ProtoReflect.Descriptor instead. +func (*StartReply) Descriptor() ([]byte, []int) { + return file_bitbox_proto_rawDescGZIP(), []int{1} +} + +func (x *StartReply) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +// StopRequest holds the ID of the process that should be stopped. +type StopRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // ID is the unique identifier of the process. + ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` // TODO: Consider making the type of signal sent to the process configurable, not just kill. +} + +func (x *StopRequest) Reset() { + *x = StopRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_bitbox_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StopRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StopRequest) ProtoMessage() {} + +func (x *StopRequest) ProtoReflect() protoreflect.Message { + mi := &file_bitbox_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 StopRequest.ProtoReflect.Descriptor instead. +func (*StopRequest) Descriptor() ([]byte, []int) { + return file_bitbox_proto_rawDescGZIP(), []int{2} +} + +func (x *StopRequest) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +// StopReply is empty. +type StopReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *StopReply) Reset() { + *x = StopReply{} + if protoimpl.UnsafeEnabled { + mi := &file_bitbox_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StopReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StopReply) ProtoMessage() {} + +func (x *StopReply) ProtoReflect() protoreflect.Message { + mi := &file_bitbox_proto_msgTypes[3] + 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 StopReply.ProtoReflect.Descriptor instead. +func (*StopReply) Descriptor() ([]byte, []int) { + return file_bitbox_proto_rawDescGZIP(), []int{3} +} + +// StatusRequest holds the ID of the process to check the status of +type StatusRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // ID is the unique identifier of the process. + ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` +} + +func (x *StatusRequest) Reset() { + *x = StatusRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_bitbox_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StatusRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StatusRequest) ProtoMessage() {} + +func (x *StatusRequest) ProtoReflect() protoreflect.Message { + mi := &file_bitbox_proto_msgTypes[4] + 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 StatusRequest.ProtoReflect.Descriptor instead. +func (*StatusRequest) Descriptor() ([]byte, []int) { + return file_bitbox_proto_rawDescGZIP(), []int{4} +} + +func (x *StatusRequest) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +// StatusReply holds the status of the reply +type StatusReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *StatusReply) Reset() { + *x = StatusReply{} + if protoimpl.UnsafeEnabled { + mi := &file_bitbox_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StatusReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StatusReply) ProtoMessage() {} + +func (x *StatusReply) ProtoReflect() protoreflect.Message { + mi := &file_bitbox_proto_msgTypes[5] + 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 StatusReply.ProtoReflect.Descriptor instead. +func (*StatusReply) Descriptor() ([]byte, []int) { + return file_bitbox_proto_rawDescGZIP(), []int{5} +} + +// QueryRequest holds the ID of the process whose output is being queried. +type QueryRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // ID is the unique identifier of the process. + ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` +} + +func (x *QueryRequest) Reset() { + *x = QueryRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_bitbox_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QueryRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryRequest) ProtoMessage() {} + +func (x *QueryRequest) ProtoReflect() protoreflect.Message { + mi := &file_bitbox_proto_msgTypes[6] + 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 QueryRequest.ProtoReflect.Descriptor instead. +func (*QueryRequest) Descriptor() ([]byte, []int) { + return file_bitbox_proto_rawDescGZIP(), []int{6} +} + +func (x *QueryRequest) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +// QueryReply holds output of the process queried. +type QueryReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Output is one of the forms of output that a process may utilize. + // + // Types that are assignable to Output: + // *QueryReply_Stdout + // *QueryReply_Stderr + // *QueryReply_ExitCode + Output isQueryReply_Output `protobuf_oneof:"Output"` +} + +func (x *QueryReply) Reset() { + *x = QueryReply{} + if protoimpl.UnsafeEnabled { + mi := &file_bitbox_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QueryReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryReply) ProtoMessage() {} + +func (x *QueryReply) ProtoReflect() protoreflect.Message { + mi := &file_bitbox_proto_msgTypes[7] + 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 QueryReply.ProtoReflect.Descriptor instead. +func (*QueryReply) Descriptor() ([]byte, []int) { + return file_bitbox_proto_rawDescGZIP(), []int{7} +} + +func (m *QueryReply) GetOutput() isQueryReply_Output { + if m != nil { + return m.Output + } + return nil +} + +func (x *QueryReply) GetStdout() string { + if x, ok := x.GetOutput().(*QueryReply_Stdout); ok { + return x.Stdout + } + return "" +} + +func (x *QueryReply) GetStderr() string { + if x, ok := x.GetOutput().(*QueryReply_Stderr); ok { + return x.Stderr + } + return "" +} + +func (x *QueryReply) GetExitCode() uint32 { + if x, ok := x.GetOutput().(*QueryReply_ExitCode); ok { + return x.ExitCode + } + return 0 +} + +type isQueryReply_Output interface { + isQueryReply_Output() +} + +type QueryReply_Stdout struct { + // Stdout is any output from the process which was written to Stdout. + Stdout string `protobuf:"bytes,1,opt,name=Stdout,proto3,oneof"` +} + +type QueryReply_Stderr struct { + // Stderr is any output from the process which was written to Stderr. + Stderr string `protobuf:"bytes,2,opt,name=Stderr,proto3,oneof"` +} + +type QueryReply_ExitCode struct { + // ExitCode is the code the process exited with. + ExitCode uint32 `protobuf:"varint,3,opt,name=ExitCode,proto3,oneof"` +} + +func (*QueryReply_Stdout) isQueryReply_Output() {} + +func (*QueryReply_Stderr) isQueryReply_Output() {} + +func (*QueryReply_ExitCode) isQueryReply_Output() {} + +var File_bitbox_proto protoreflect.FileDescriptor + +var file_bitbox_proto_rawDesc = []byte{ + 0x0a, 0x0c, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, + 0x67, 0x72, 0x70, 0x63, 0x22, 0x48, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x1e, + 0x0a, 0x0a, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0a, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x22, 0x1c, + 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x0e, 0x0a, 0x02, + 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x22, 0x1d, 0x0a, 0x0b, + 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, + 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x22, 0x0b, 0x0a, 0x09, 0x53, + 0x74, 0x6f, 0x70, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1f, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x22, 0x3d, 0x0a, 0x0b, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x2e, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x10, 0x00, 0x12, + 0x0a, 0x0a, 0x06, 0x45, 0x78, 0x69, 0x74, 0x65, 0x64, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, + 0x74, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x10, 0x02, 0x22, 0x1e, 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x22, 0x68, 0x0a, 0x0a, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x06, 0x53, 0x74, 0x64, 0x6f, 0x75, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x53, 0x74, 0x64, 0x6f, 0x75, 0x74, + 0x12, 0x18, 0x0a, 0x06, 0x53, 0x74, 0x64, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x48, 0x00, 0x52, 0x06, 0x53, 0x74, 0x64, 0x65, 0x72, 0x72, 0x12, 0x1c, 0x0a, 0x08, 0x45, 0x78, + 0x69, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x08, + 0x45, 0x78, 0x69, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x4f, 0x75, 0x74, 0x70, + 0x75, 0x74, 0x32, 0xce, 0x01, 0x0a, 0x06, 0x42, 0x69, 0x74, 0x42, 0x6f, 0x78, 0x12, 0x2f, 0x0a, + 0x05, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, + 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x2c, + 0x0a, 0x04, 0x53, 0x74, 0x6f, 0x70, 0x12, 0x11, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, + 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x32, 0x0a, 0x06, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x13, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, + 0x12, 0x31, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, + 0x00, 0x30, 0x01, 0x42, 0x21, 0x5a, 0x1f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x6a, 0x6d, 0x62, 0x61, 0x72, 0x7a, 0x65, 0x65, 0x2f, 0x62, 0x69, 0x74, 0x62, 0x6f, + 0x78, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_bitbox_proto_rawDescOnce sync.Once + file_bitbox_proto_rawDescData = file_bitbox_proto_rawDesc +) + +func file_bitbox_proto_rawDescGZIP() []byte { + file_bitbox_proto_rawDescOnce.Do(func() { + file_bitbox_proto_rawDescData = protoimpl.X.CompressGZIP(file_bitbox_proto_rawDescData) + }) + return file_bitbox_proto_rawDescData +} + +var file_bitbox_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_bitbox_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_bitbox_proto_goTypes = []interface{}{ + (StatusReply_Status)(0), // 0: grpc.StatusReply.Status + (*StartRequest)(nil), // 1: grpc.StartRequest + (*StartReply)(nil), // 2: grpc.StartReply + (*StopRequest)(nil), // 3: grpc.StopRequest + (*StopReply)(nil), // 4: grpc.StopReply + (*StatusRequest)(nil), // 5: grpc.StatusRequest + (*StatusReply)(nil), // 6: grpc.StatusReply + (*QueryRequest)(nil), // 7: grpc.QueryRequest + (*QueryReply)(nil), // 8: grpc.QueryReply +} +var file_bitbox_proto_depIdxs = []int32{ + 1, // 0: grpc.BitBox.Start:input_type -> grpc.StartRequest + 3, // 1: grpc.BitBox.Stop:input_type -> grpc.StopRequest + 5, // 2: grpc.BitBox.Status:input_type -> grpc.StatusRequest + 7, // 3: grpc.BitBox.Query:input_type -> grpc.QueryRequest + 2, // 4: grpc.BitBox.Start:output_type -> grpc.StartReply + 4, // 5: grpc.BitBox.Stop:output_type -> grpc.StopReply + 6, // 6: grpc.BitBox.Status:output_type -> grpc.StatusReply + 8, // 7: grpc.BitBox.Query:output_type -> grpc.QueryReply + 4, // [4:8] is the sub-list for method output_type + 0, // [0:4] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_bitbox_proto_init() } +func file_bitbox_proto_init() { + if File_bitbox_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_bitbox_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StartRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_bitbox_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StartReply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_bitbox_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StopRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_bitbox_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StopReply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_bitbox_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StatusRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_bitbox_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StatusReply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_bitbox_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QueryRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_bitbox_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QueryReply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_bitbox_proto_msgTypes[7].OneofWrappers = []interface{}{ + (*QueryReply_Stdout)(nil), + (*QueryReply_Stderr)(nil), + (*QueryReply_ExitCode)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_bitbox_proto_rawDesc, + NumEnums: 1, + NumMessages: 8, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_bitbox_proto_goTypes, + DependencyIndexes: file_bitbox_proto_depIdxs, + EnumInfos: file_bitbox_proto_enumTypes, + MessageInfos: file_bitbox_proto_msgTypes, + }.Build() + File_bitbox_proto = out.File + file_bitbox_proto_rawDesc = nil + file_bitbox_proto_goTypes = nil + file_bitbox_proto_depIdxs = nil +} diff --git a/grpc/bitbox.proto b/grpc/bitbox.proto new file mode 100644 index 0000000..6707e57 --- /dev/null +++ b/grpc/bitbox.proto @@ -0,0 +1,95 @@ +syntax = "proto3"; + +package grpc; + +// The Go package name is "grpcb". +option go_package = "github.com/jmbarzee/bitbox/grpc"; + +service BitBox { + // Start initiates a process. + rpc Start (StartRequest) returns (StartReply) {} + + // Stop halts a process. + rpc Stop (StopRequest) returns (StopReply) {} + + // Status returns the status of a process. + rpc Status (StatusRequest) returns (StatusReply) {} + + // Query streams the output/result of a process. + rpc Query (QueryRequest) returns (stream QueryReply) {} +} + + +// StartRequest holds the command and nessecary parameters to run it. +message StartRequest { + // Command is an arbitrary linux command. + // Command should be a fullpath or found in a directory in PATH. + string Command = 1; + + // Parameters are handed to the command as ARGV. + // Glob patterns, pipelines, and redirections are not handled + // and will instead be passed as literal strings to the command. + repeated string Parameters = 2; +} + +// StartReply holds the ID of the started process. +message StartReply { + // ID is the unique identifier of the process. + string ID = 1; +} + + + +// StopRequest holds the ID of the process that should be stopped. +message StopRequest { + // ID is the unique identifier of the process. + string ID = 1; + // TODO: Consider making the type of signal sent to the process configurable, not just kill. +} + +// StopReply is empty. +message StopReply { + // TODO: consider including information about how the process was killed, Signal type, time, etc. +} + + + +// StatusRequest holds the ID of the process to check the status of +message StatusRequest { + // ID is the unique identifier of the process. + string ID = 1; +} + +// StatusReply holds the status of the reply +message StatusReply { + enum Status { + // Running indicates that the process is running. + Running = 0; + // Exited indicates that the process returned a non-zero exit code. + Exited = 1; + // Stopped indicates that the process returned no exit code. + Stopped = 2; + } +} + + + + +// QueryRequest holds the ID of the process whose output is being queried. +message QueryRequest { + // ID is the unique identifier of the process. + string ID = 1; +} + +// QueryReply holds output of the process queried. +message QueryReply { + // Output is one of the forms of output that a process may utilize. + oneof Output { + // Stdout is any output from the process which was written to Stdout. + string Stdout = 1; + // Stderr is any output from the process which was written to Stderr. + string Stderr = 2; + // ExitCode is the code the process exited with. + uint32 ExitCode = 3; + } +} \ No newline at end of file diff --git a/grpc/bitbox_grpc.pb.go b/grpc/bitbox_grpc.pb.go new file mode 100644 index 0000000..083259b --- /dev/null +++ b/grpc/bitbox_grpc.pb.go @@ -0,0 +1,245 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. + +package grpc + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// BitBoxClient is the client API for BitBox service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type BitBoxClient interface { + // Start initiates a process. + Start(ctx context.Context, in *StartRequest, opts ...grpc.CallOption) (*StartReply, error) + // Stop halts a process. + Stop(ctx context.Context, in *StopRequest, opts ...grpc.CallOption) (*StopReply, error) + // Status returns the status of a process. + Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusReply, error) + // Query streams the output/result of a process. + Query(ctx context.Context, in *QueryRequest, opts ...grpc.CallOption) (BitBox_QueryClient, error) +} + +type bitBoxClient struct { + cc grpc.ClientConnInterface +} + +func NewBitBoxClient(cc grpc.ClientConnInterface) BitBoxClient { + return &bitBoxClient{cc} +} + +func (c *bitBoxClient) Start(ctx context.Context, in *StartRequest, opts ...grpc.CallOption) (*StartReply, error) { + out := new(StartReply) + err := c.cc.Invoke(ctx, "/grpc.BitBox/Start", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *bitBoxClient) Stop(ctx context.Context, in *StopRequest, opts ...grpc.CallOption) (*StopReply, error) { + out := new(StopReply) + err := c.cc.Invoke(ctx, "/grpc.BitBox/Stop", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *bitBoxClient) Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusReply, error) { + out := new(StatusReply) + err := c.cc.Invoke(ctx, "/grpc.BitBox/Status", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *bitBoxClient) Query(ctx context.Context, in *QueryRequest, opts ...grpc.CallOption) (BitBox_QueryClient, error) { + stream, err := c.cc.NewStream(ctx, &BitBox_ServiceDesc.Streams[0], "/grpc.BitBox/Query", opts...) + if err != nil { + return nil, err + } + x := &bitBoxQueryClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type BitBox_QueryClient interface { + Recv() (*QueryReply, error) + grpc.ClientStream +} + +type bitBoxQueryClient struct { + grpc.ClientStream +} + +func (x *bitBoxQueryClient) Recv() (*QueryReply, error) { + m := new(QueryReply) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// BitBoxServer is the server API for BitBox service. +// All implementations must embed UnimplementedBitBoxServer +// for forward compatibility +type BitBoxServer interface { + // Start initiates a process. + Start(context.Context, *StartRequest) (*StartReply, error) + // Stop halts a process. + Stop(context.Context, *StopRequest) (*StopReply, error) + // Status returns the status of a process. + Status(context.Context, *StatusRequest) (*StatusReply, error) + // Query streams the output/result of a process. + Query(*QueryRequest, BitBox_QueryServer) error + mustEmbedUnimplementedBitBoxServer() +} + +// UnimplementedBitBoxServer must be embedded to have forward compatible implementations. +type UnimplementedBitBoxServer struct { +} + +func (UnimplementedBitBoxServer) Start(context.Context, *StartRequest) (*StartReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method Start not implemented") +} +func (UnimplementedBitBoxServer) Stop(context.Context, *StopRequest) (*StopReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method Stop not implemented") +} +func (UnimplementedBitBoxServer) Status(context.Context, *StatusRequest) (*StatusReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method Status not implemented") +} +func (UnimplementedBitBoxServer) Query(*QueryRequest, BitBox_QueryServer) error { + return status.Errorf(codes.Unimplemented, "method Query not implemented") +} +func (UnimplementedBitBoxServer) mustEmbedUnimplementedBitBoxServer() {} + +// UnsafeBitBoxServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to BitBoxServer will +// result in compilation errors. +type UnsafeBitBoxServer interface { + mustEmbedUnimplementedBitBoxServer() +} + +func RegisterBitBoxServer(s grpc.ServiceRegistrar, srv BitBoxServer) { + s.RegisterService(&BitBox_ServiceDesc, srv) +} + +func _BitBox_Start_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StartRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BitBoxServer).Start(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.BitBox/Start", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BitBoxServer).Start(ctx, req.(*StartRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _BitBox_Stop_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StopRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BitBoxServer).Stop(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.BitBox/Stop", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BitBoxServer).Stop(ctx, req.(*StopRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _BitBox_Status_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StatusRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BitBoxServer).Status(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.BitBox/Status", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BitBoxServer).Status(ctx, req.(*StatusRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _BitBox_Query_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(QueryRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(BitBoxServer).Query(m, &bitBoxQueryServer{stream}) +} + +type BitBox_QueryServer interface { + Send(*QueryReply) error + grpc.ServerStream +} + +type bitBoxQueryServer struct { + grpc.ServerStream +} + +func (x *bitBoxQueryServer) Send(m *QueryReply) error { + return x.ServerStream.SendMsg(m) +} + +// BitBox_ServiceDesc is the grpc.ServiceDesc for BitBox service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var BitBox_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "grpc.BitBox", + HandlerType: (*BitBoxServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Start", + Handler: _BitBox_Start_Handler, + }, + { + MethodName: "Stop", + Handler: _BitBox_Stop_Handler, + }, + { + MethodName: "Status", + Handler: _BitBox_Status_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "Query", + Handler: _BitBox_Query_Handler, + ServerStreams: true, + }, + }, + Metadata: "bitbox.proto", +} diff --git a/grpc/generate.go b/grpc/generate.go new file mode 100644 index 0000000..e9dea9d --- /dev/null +++ b/grpc/generate.go @@ -0,0 +1,4 @@ +package grpc + +// This file is exclusively used for hooking gRPC code generation into go +//go:generate protoc --proto_path=. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative bitbox.proto From 9dd2cbe7289fe67012a3c86e4e20304630313c36 Mon Sep 17 00:00:00 2001 From: Jacob Barzee Date: Fri, 19 Mar 2021 03:15:02 -0600 Subject: [PATCH 02/15] Add unimplemented bitbox.Server and server cmd --- .gitignore | 1 + README.md | 9 +++++ cmd/server/main.go | 45 ++++++++++++++++++++++ core.go | 6 +++ go.mod | 9 ++++- go.sum | 95 ++++++++++++++++++++++++++++++++++++++++++++++ server.go | 42 ++++++++++++++++++++ 7 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 cmd/server/main.go create mode 100644 server.go diff --git a/.gitignore b/.gitignore index 30c9b8d..70f413e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.dll *.so *.dylib +bin/* # Test binary, built with `go test -c` *.test diff --git a/README.md b/README.md index 2b4e3e2..69d3da9 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,15 @@ Rudementary implementation of containerization in linux. +## Server +For available endpoints view the [gRPC deffinition](grpc/bitbox.proto). +```bash +# Build the Server. +go build -o bin/bitbox cmd/server/main.go +# Run it. +./bin/bitbox +``` + ## Development Tools [gRPC & protoc](https://grpc.io/docs/languages/go/quickstart/) are used by `go generate` to update [bitbox/grpc](grpc/). diff --git a/cmd/server/main.go b/cmd/server/main.go new file mode 100644 index 0000000..0b14055 --- /dev/null +++ b/cmd/server/main.go @@ -0,0 +1,45 @@ +package main + +import ( + // temp import for build + "fmt" + "log" + "net" + "os" + + "github.com/jmbarzee/bitbox" + bbgrpc "github.com/jmbarzee/bitbox/grpc" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" +) + +var defaultPort = optionalEnvString("BIT_BOX_PORT", "8443") +var defaultAddress = optionalEnvString("BIT_BOX_ADDR", "") + +func main() { + + address := fmt.Sprintf("%s:%s", defaultAddress, defaultPort) + + lis, err := net.Listen("tcp", address) + if err != nil { + panic(fmt.Errorf("failed to listen on %s: %w", address, err)) + } + + bitBoxServer := bitbox.NewServer() + + server := grpc.NewServer() + + bbgrpc.RegisterBitBoxServer(server, bitBoxServer) + // Register reflection service on gRPC server. + reflection.Register(server) + + err = server.Serve(lis) +} + +func optionalEnvString(key, defaultValue string) string { + if value, ok := os.LookupEnv(key); ok { + return value + } + log.Printf("Missing optional environment variable %s, using default %s", key, defaultValue) + return defaultValue +} diff --git a/core.go b/core.go index 27bb056..f8e072c 100644 --- a/core.go +++ b/core.go @@ -15,6 +15,12 @@ type Core struct { processes map[uuid.UUID]proc.Proc } +func NewCore() *Core { + return &Core{ + processes: make(map[uuid.UUID]proc.Proc), + } +} + // Start initiates a process. func (c *Core) Start(cmd string, args ...string) (uuid.UUID, error) { diff --git a/go.mod b/go.mod index 17d9b09..add321e 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,11 @@ module github.com/jmbarzee/bitbox go 1.15 -require github.com/google/uuid v1.2.0 +require ( + github.com/google/uuid v1.2.0 + golang.org/x/net v0.0.0-20190620200207-3b0461eec859 // indirect + golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 // indirect + golang.org/x/text v0.3.2 // indirect + google.golang.org/grpc v1.36.0 + google.golang.org/protobuf v1.26.0 +) diff --git a/go.sum b/go.sum index a4d2b5e..3108572 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,97 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.36.0 h1:o1bcQ6imQMIOpdrO3SWf2z5RV72WbDwdXuK0MDlc8As= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/server.go b/server.go new file mode 100644 index 0000000..e3b00fa --- /dev/null +++ b/server.go @@ -0,0 +1,42 @@ +package bitbox + +import ( + "context" + + "github.com/jmbarzee/bitbox/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// ensure Server implements BitBoxServer +var _ grpc.BitBoxServer = (*Server)(nil) + +// Server starts, stops, and tracks arbitrary processes +type Server struct { + // UnimplementedBitBoxServer is embedded to enable forwards compatability + grpc.UnimplementedBitBoxServer +} + +func NewServer() *Server { + return &Server{} +} + +// Start initiates a process. +func (s *Server) Start(ctx context.Context, start *grpc.StartRequest) (*grpc.StartReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method Start not implemented") +} + +// Stop halts a process. +func (s *Server) Stop(context.Context, *grpc.StopRequest) (*grpc.StopReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method Stop not implemented") +} + +// Status returns the status of a process. +func (s *Server) Status(context.Context, *grpc.StatusRequest) (*grpc.StatusReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method Stop not implemented") +} + +// Query streams the output/result of a process. +func (s *Server) Query(*grpc.QueryRequest, grpc.BitBox_QueryServer) error { + return status.Errorf(codes.Unimplemented, "method Query not implemented") +} From b693ba28b29aa75b36d4e2adb1d32b3945205495 Mon Sep 17 00:00:00 2001 From: Jacob Barzee Date: Fri, 19 Mar 2021 03:15:46 -0600 Subject: [PATCH 03/15] Add bitbox cli cmd --- README.md | 9 ++ cmd/client/main.go | 75 +++++++++++++ cmd/client/query.go | 69 ++++++++++++ cmd/client/start.go | 53 ++++++++++ cmd/client/status.go | 50 +++++++++ cmd/client/stop.go | 50 +++++++++ go.mod | 1 + go.sum | 243 +++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 550 insertions(+) create mode 100644 cmd/client/main.go create mode 100644 cmd/client/query.go create mode 100644 cmd/client/start.go create mode 100644 cmd/client/status.go create mode 100644 cmd/client/stop.go diff --git a/README.md b/README.md index 69d3da9..71289a0 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,15 @@ go build -o bin/bitbox cmd/server/main.go ./bin/bitbox ``` + +## CLI Client +```bash +# Build the CLI +go build -o bin/bitboxcli cmd/client/*.go +# Run it. +./bin/bitboxcli start +``` + ## Development Tools [gRPC & protoc](https://grpc.io/docs/languages/go/quickstart/) are used by `go generate` to update [bitbox/grpc](grpc/). diff --git a/cmd/client/main.go b/cmd/client/main.go new file mode 100644 index 0000000..c64e50b --- /dev/null +++ b/cmd/client/main.go @@ -0,0 +1,75 @@ +package main + +import ( + "context" + "fmt" + "log" + "net" + "os" + + bbgrpc "github.com/jmbarzee/bitbox/grpc" + "github.com/spf13/cobra" + "google.golang.org/grpc" +) + +var defaultPort = optionalEnvString("BIT_BOX_PORT", "8443") + +var defaultAddress = optionalEnvString("BIT_BOX_ADDR", func() string { + ip, err := getOutboundIP() + if err != nil { + panic(err) + } + return ip.String() +}()) + +var root = &cobra.Command{ + Use: "bitboxc", + Short: "A CLI tool for remote BitBox operations", + Long: "Execute remote linux processes on a BitBox server", +} + +func main() { + root.AddCommand(cmdStart) + root.AddCommand(cmdStop) + root.AddCommand(cmdStatus) + root.AddCommand(cmdQuery) + if err := root.Execute(); err != nil { + panic(err) + } +} + +func optionalEnvString(key, defaultValue string) string { + if value, ok := os.LookupEnv(key); ok { + return value + } + log.Printf("Missing optional environment variable %s, using default %s", key, defaultValue) + return defaultValue +} + +func getOutboundIP() (net.IP, error) { + conn, err := net.Dial("udp", "8.8.8.8:80") + if err != nil { + return net.IP{}, err + } + defer conn.Close() + + localAddr := conn.LocalAddr().(*net.UDPAddr) + + return localAddr.IP, nil +} + +func getClient(ctx context.Context) bbgrpc.BitBoxClient { + address := fmt.Sprintf("%s:%s", defaultAddress, defaultPort) + + conn, err := grpc.DialContext( + context.TODO(), + address, + //TODO: replace with mTLS + grpc.WithInsecure(), + grpc.WithBlock()) + if err != nil { + panic(fmt.Errorf("Failed to dial connection during reconnect: %w", err)) + } + + return bbgrpc.NewBitBoxClient(conn) +} diff --git a/cmd/client/query.go b/cmd/client/query.go new file mode 100644 index 0000000..1f9c17b --- /dev/null +++ b/cmd/client/query.go @@ -0,0 +1,69 @@ +package main + +import ( + "context" + "errors" + "fmt" + "log" + + "github.com/spf13/cobra" + + bbgrpc "github.com/jmbarzee/bitbox/grpc" +) + +var cmdQuery = &cobra.Command{ + Use: "query", + Short: "query", + Long: "Query a process on the bitbox server", + Run: func(cmd *cobra.Command, args []string) { + if len(args) != 1 { + panic(errors.New("Require a single id as an argument")) + } + + job := jobQuery{ + id: args[0], + } + ctx := context.Background() + bbClient := getClient(ctx) + if err := job.execute(ctx, bbClient); err != nil { + panic(err) + } + }, +} + +type jobQuery struct { + id string +} + +// Execute querys a job on the remote BibBox +func (j jobQuery) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { + request := &bbgrpc.QueryRequest{ + ID: j.id, + } + + queryClient, err := c.Query(ctx, request) + if err != nil { + log.Fatal(fmt.Errorf("failed to stop process %s: %w", j.id, err)) + } + +Loop: + for { + reply, err := queryClient.Recv() + if err != nil { + log.Println(fmt.Errorf("failed to fetch reply: %w", err)) + log.Println(fmt.Errorf("failed to fetch reply: %w", err)) + break + } + switch output := reply.GetOutput().(type) { + case *bbgrpc.QueryReply_Stdout: + log.Println(output.Stdout) + case *bbgrpc.QueryReply_Stderr: + log.Printf("Error: %v", output.Stderr) + case *bbgrpc.QueryReply_ExitCode: + log.Printf("Process %v exited with code %v", j.id, output.ExitCode) + break Loop + } + } + + return nil +} diff --git a/cmd/client/start.go b/cmd/client/start.go new file mode 100644 index 0000000..6e043c6 --- /dev/null +++ b/cmd/client/start.go @@ -0,0 +1,53 @@ +package main + +import ( + "context" + "errors" + "fmt" + "log" + + "github.com/spf13/cobra" + + bbgrpc "github.com/jmbarzee/bitbox/grpc" +) + +var cmdStart = &cobra.Command{ + Use: "start", + Short: "start", + Long: "Start a process on the bitbox server", + Run: func(cmd *cobra.Command, args []string) { + if len(args) < 1 { + panic(errors.New("Require atleast a single command as an argument")) + } + + job := jobStart{ + command: args[0], + parameters: args[0:], + } + ctx := context.Background() + bbClient := getClient(ctx) + if err := job.execute(ctx, bbClient); err != nil { + panic(err) + } + }, +} + +type jobStart struct { + command string + parameters []string +} + +// Execute starts a job on the remote BibBox +func (j jobStart) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { + request := &bbgrpc.StartRequest{ + Command: j.command, + Parameters: j.parameters, + } + + reply, err := c.Start(ctx, request) + if err != nil { + log.Fatal(fmt.Errorf("failed to run %s: %w", j.command, err)) + } + log.Println("Successfully started process ", reply.GetID()) + return nil +} diff --git a/cmd/client/status.go b/cmd/client/status.go new file mode 100644 index 0000000..7b3b85d --- /dev/null +++ b/cmd/client/status.go @@ -0,0 +1,50 @@ +package main + +import ( + "context" + "errors" + "fmt" + "log" + + "github.com/spf13/cobra" + + bbgrpc "github.com/jmbarzee/bitbox/grpc" +) + +var cmdStatus = &cobra.Command{ + Use: "status", + Short: "status", + Long: "Stop a process on the bitbox server", + Run: func(cmd *cobra.Command, args []string) { + if len(args) != 1 { + panic(errors.New("Require a single id as an argument")) + } + + job := jobStatus{ + id: args[0], + } + ctx := context.Background() + bbClient := getClient(ctx) + if err := job.execute(ctx, bbClient); err != nil { + panic(err) + } + }, +} + +type jobStatus struct { + id string +} + +// Execute returns the status of a job on the remote BibBox +func (j jobStatus) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { + request := &bbgrpc.StopRequest{ + ID: j.id, + } + + _, err := c.Stop(ctx, request) + if err != nil { + log.Fatal(fmt.Errorf("failed to status process %s: %w", j.id, err)) + } + log.Println("Successfully statused process ", j.id) + return nil +} diff --git a/cmd/client/stop.go b/cmd/client/stop.go new file mode 100644 index 0000000..1047a63 --- /dev/null +++ b/cmd/client/stop.go @@ -0,0 +1,50 @@ +package main + +import ( + "context" + "errors" + "fmt" + "log" + + "github.com/spf13/cobra" + + bbgrpc "github.com/jmbarzee/bitbox/grpc" +) + +var cmdStop = &cobra.Command{ + Use: "stop", + Short: "stop", + Long: "Stop a process on the bitbox server", + Run: func(cmd *cobra.Command, args []string) { + if len(args) != 1 { + panic(errors.New("Require a single id as an argument")) + } + + job := jobStop{ + id: args[0], + } + ctx := context.Background() + bbClient := getClient(ctx) + if err := job.execute(ctx, bbClient); err != nil { + panic(err) + } + }, +} + +type jobStop struct { + id string +} + +// Execute stops a job on the remote BibBox +func (j jobStop) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { + request := &bbgrpc.StopRequest{ + ID: j.id, + } + + _, err := c.Stop(ctx, request) + if err != nil { + log.Fatal(fmt.Errorf("failed to stop process %s: %w", j.id, err)) + } + log.Println("Successfully stoped process ", j.id) + return nil +} diff --git a/go.mod b/go.mod index add321e..7626e65 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.15 require ( github.com/google/uuid v1.2.0 + github.com/spf13/cobra v1.1.3 golang.org/x/net v0.0.0-20190620200207-3b0461eec859 // indirect golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 // indirect golang.org/x/text v0.3.2 // indirect diff --git a/go.sum b/go.sum index 3108572..5d2e27d 100644 --- a/go.sum +++ b/go.sum @@ -1,16 +1,63 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -21,6 +68,8 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -28,52 +77,233 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= @@ -91,7 +321,20 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= From e378ecf4a897a20220ac65197d585e3abe43dcdb Mon Sep 17 00:00:00 2001 From: Jacob Barzee Date: Tue, 23 Mar 2021 14:37:26 -0600 Subject: [PATCH 04/15] change bitbox.Core constructor to handle *proc.Proc --- core.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core.go b/core.go index 998da58..964ff56 100644 --- a/core.go +++ b/core.go @@ -17,7 +17,7 @@ type Core struct { func NewCore() *Core { return &Core{ - processes: make(map[uuid.UUID]proc.Proc), + processes: make(map[uuid.UUID]*proc.Proc), } } From 4f03d6b4614e1bb3011656328c64b25006486c84 Mon Sep 17 00:00:00 2001 From: Jacob Barzee Date: Tue, 23 Mar 2021 15:26:02 -0600 Subject: [PATCH 05/15] Update proto to represent an ID with []byte --- cmd/client/query.go | 2 +- cmd/client/start.go | 2 +- cmd/client/status.go | 8 ++++---- cmd/client/stop.go | 4 ++-- grpc/bitbox.pb.go | 32 ++++++++++++++++---------------- grpc/bitbox.proto | 8 ++++---- 6 files changed, 28 insertions(+), 28 deletions(-) diff --git a/cmd/client/query.go b/cmd/client/query.go index 1f9c17b..e476278 100644 --- a/cmd/client/query.go +++ b/cmd/client/query.go @@ -38,7 +38,7 @@ type jobQuery struct { // Execute querys a job on the remote BibBox func (j jobQuery) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { request := &bbgrpc.QueryRequest{ - ID: j.id, + ID: []byte(j.id), } queryClient, err := c.Query(ctx, request) diff --git a/cmd/client/start.go b/cmd/client/start.go index 6e043c6..73f369a 100644 --- a/cmd/client/start.go +++ b/cmd/client/start.go @@ -48,6 +48,6 @@ func (j jobStart) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { if err != nil { log.Fatal(fmt.Errorf("failed to run %s: %w", j.command, err)) } - log.Println("Successfully started process ", reply.GetID()) + log.Println("Successfully started process: ", reply.GetID()) return nil } diff --git a/cmd/client/status.go b/cmd/client/status.go index 7b3b85d..0fd5ed5 100644 --- a/cmd/client/status.go +++ b/cmd/client/status.go @@ -37,13 +37,13 @@ type jobStatus struct { // Execute returns the status of a job on the remote BibBox func (j jobStatus) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { - request := &bbgrpc.StopRequest{ - ID: j.id, + request := &bbgrpc.StatusRequest{ + ID: []byte(j.id), } - _, err := c.Stop(ctx, request) + _, err := c.Status(ctx, request) if err != nil { - log.Fatal(fmt.Errorf("failed to status process %s: %w", j.id, err)) + log.Fatal(fmt.Errorf("failed to stop process %s: %w", j.id, err)) } log.Println("Successfully statused process ", j.id) return nil diff --git a/cmd/client/stop.go b/cmd/client/stop.go index 1047a63..1bbebf0 100644 --- a/cmd/client/stop.go +++ b/cmd/client/stop.go @@ -38,13 +38,13 @@ type jobStop struct { // Execute stops a job on the remote BibBox func (j jobStop) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { request := &bbgrpc.StopRequest{ - ID: j.id, + ID: []byte(j.id), } _, err := c.Stop(ctx, request) if err != nil { log.Fatal(fmt.Errorf("failed to stop process %s: %w", j.id, err)) } - log.Println("Successfully stoped process ", j.id) + log.Println("Successfully stopped process: ", j.id) return nil } diff --git a/grpc/bitbox.pb.go b/grpc/bitbox.pb.go index d0b73e8..065f46f 100644 --- a/grpc/bitbox.pb.go +++ b/grpc/bitbox.pb.go @@ -140,7 +140,7 @@ type StartReply struct { unknownFields protoimpl.UnknownFields // ID is the unique identifier of the process. - ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` + ID []byte `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` } func (x *StartReply) Reset() { @@ -175,11 +175,11 @@ func (*StartReply) Descriptor() ([]byte, []int) { return file_bitbox_proto_rawDescGZIP(), []int{1} } -func (x *StartReply) GetID() string { +func (x *StartReply) GetID() []byte { if x != nil { return x.ID } - return "" + return nil } // StopRequest holds the ID of the process that should be stopped. @@ -189,7 +189,7 @@ type StopRequest struct { unknownFields protoimpl.UnknownFields // ID is the unique identifier of the process. - ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` // TODO: Consider making the type of signal sent to the process configurable, not just kill. + ID []byte `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` // TODO: Consider making the type of signal sent to the process configurable, not just kill. } func (x *StopRequest) Reset() { @@ -224,11 +224,11 @@ func (*StopRequest) Descriptor() ([]byte, []int) { return file_bitbox_proto_rawDescGZIP(), []int{2} } -func (x *StopRequest) GetID() string { +func (x *StopRequest) GetID() []byte { if x != nil { return x.ID } - return "" + return nil } // StopReply is empty. @@ -277,7 +277,7 @@ type StatusRequest struct { unknownFields protoimpl.UnknownFields // ID is the unique identifier of the process. - ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` + ID []byte `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` } func (x *StatusRequest) Reset() { @@ -312,11 +312,11 @@ func (*StatusRequest) Descriptor() ([]byte, []int) { return file_bitbox_proto_rawDescGZIP(), []int{4} } -func (x *StatusRequest) GetID() string { +func (x *StatusRequest) GetID() []byte { if x != nil { return x.ID } - return "" + return nil } // StatusReply holds the status of the reply @@ -365,7 +365,7 @@ type QueryRequest struct { unknownFields protoimpl.UnknownFields // ID is the unique identifier of the process. - ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` + ID []byte `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` } func (x *QueryRequest) Reset() { @@ -400,11 +400,11 @@ func (*QueryRequest) Descriptor() ([]byte, []int) { return file_bitbox_proto_rawDescGZIP(), []int{6} } -func (x *QueryRequest) GetID() string { +func (x *QueryRequest) GetID() []byte { if x != nil { return x.ID } - return "" + return nil } // QueryReply holds output of the process queried. @@ -517,18 +517,18 @@ var file_bitbox_proto_rawDesc = []byte{ 0x0a, 0x0a, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x22, 0x1c, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x0e, 0x0a, 0x02, - 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x22, 0x1d, 0x0a, 0x0b, + 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x49, 0x44, 0x22, 0x1d, 0x0a, 0x0b, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, - 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x22, 0x0b, 0x0a, 0x09, 0x53, + 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x49, 0x44, 0x22, 0x0b, 0x0a, 0x09, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1f, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x22, 0x3d, 0x0a, 0x0b, 0x53, 0x74, 0x61, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x49, 0x44, 0x22, 0x3d, 0x0a, 0x0b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x2e, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x45, 0x78, 0x69, 0x74, 0x65, 0x64, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x74, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x10, 0x02, 0x22, 0x1e, 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x22, 0x68, 0x0a, 0x0a, 0x51, 0x75, 0x65, 0x72, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x49, 0x44, 0x22, 0x68, 0x0a, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x06, 0x53, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x53, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x12, 0x18, 0x0a, 0x06, 0x53, 0x74, 0x64, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, diff --git a/grpc/bitbox.proto b/grpc/bitbox.proto index 6707e57..86dad42 100644 --- a/grpc/bitbox.proto +++ b/grpc/bitbox.proto @@ -35,7 +35,7 @@ message StartRequest { // StartReply holds the ID of the started process. message StartReply { // ID is the unique identifier of the process. - string ID = 1; + bytes ID = 1; } @@ -43,7 +43,7 @@ message StartReply { // StopRequest holds the ID of the process that should be stopped. message StopRequest { // ID is the unique identifier of the process. - string ID = 1; + bytes ID = 1; // TODO: Consider making the type of signal sent to the process configurable, not just kill. } @@ -57,7 +57,7 @@ message StopReply { // StatusRequest holds the ID of the process to check the status of message StatusRequest { // ID is the unique identifier of the process. - string ID = 1; + bytes ID = 1; } // StatusReply holds the status of the reply @@ -78,7 +78,7 @@ message StatusReply { // QueryRequest holds the ID of the process whose output is being queried. message QueryRequest { // ID is the unique identifier of the process. - string ID = 1; + bytes ID = 1; } // QueryReply holds output of the process queried. From f23886540887774df3e7b800ef2fd4bf399a8843 Mon Sep 17 00:00:00 2001 From: Jacob Barzee Date: Tue, 23 Mar 2021 15:28:30 -0600 Subject: [PATCH 06/15] Change Start() parameters to arguments --- cmd/client/start.go | 12 +++---- grpc/bitbox.pb.go | 86 ++++++++++++++++++++++----------------------- grpc/bitbox.proto | 4 +-- 3 files changed, 51 insertions(+), 51 deletions(-) diff --git a/cmd/client/start.go b/cmd/client/start.go index 73f369a..0696200 100644 --- a/cmd/client/start.go +++ b/cmd/client/start.go @@ -21,8 +21,8 @@ var cmdStart = &cobra.Command{ } job := jobStart{ - command: args[0], - parameters: args[0:], + command: args[0], + arguments: args[0:], } ctx := context.Background() bbClient := getClient(ctx) @@ -33,15 +33,15 @@ var cmdStart = &cobra.Command{ } type jobStart struct { - command string - parameters []string + command string + arguments []string } // Execute starts a job on the remote BibBox func (j jobStart) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { request := &bbgrpc.StartRequest{ - Command: j.command, - Parameters: j.parameters, + Command: j.command, + Arguments: j.arguments, } reply, err := c.Start(ctx, request) diff --git a/grpc/bitbox.pb.go b/grpc/bitbox.pb.go index 065f46f..619ce67 100644 --- a/grpc/bitbox.pb.go +++ b/grpc/bitbox.pb.go @@ -81,10 +81,10 @@ type StartRequest struct { // Command is an arbitrary linux command. // Command should be a fullpath or found in a directory in PATH. Command string `protobuf:"bytes,1,opt,name=Command,proto3" json:"Command,omitempty"` - // Parameters are handed to the command as ARGV. + // Arguments are handed to the command as ARGV. // Glob patterns, pipelines, and redirections are not handled // and will instead be passed as literal strings to the command. - Parameters []string `protobuf:"bytes,2,rep,name=Parameters,proto3" json:"Parameters,omitempty"` + Arguments []string `protobuf:"bytes,2,rep,name=Arguments,proto3" json:"Arguments,omitempty"` } func (x *StartRequest) Reset() { @@ -126,9 +126,9 @@ func (x *StartRequest) GetCommand() string { return "" } -func (x *StartRequest) GetParameters() []string { +func (x *StartRequest) GetArguments() []string { if x != nil { - return x.Parameters + return x.Arguments } return nil } @@ -511,46 +511,46 @@ var File_bitbox_proto protoreflect.FileDescriptor var file_bitbox_proto_rawDesc = []byte{ 0x0a, 0x0c, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, - 0x67, 0x72, 0x70, 0x63, 0x22, 0x48, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, + 0x67, 0x72, 0x70, 0x63, 0x22, 0x46, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x1e, - 0x0a, 0x0a, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x0a, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x22, 0x1c, - 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x0e, 0x0a, 0x02, - 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x49, 0x44, 0x22, 0x1d, 0x0a, 0x0b, - 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, - 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x49, 0x44, 0x22, 0x0b, 0x0a, 0x09, 0x53, - 0x74, 0x6f, 0x70, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1f, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x49, 0x44, 0x22, 0x3d, 0x0a, 0x0b, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x2e, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x10, 0x00, 0x12, - 0x0a, 0x0a, 0x06, 0x45, 0x78, 0x69, 0x74, 0x65, 0x64, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, - 0x74, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x10, 0x02, 0x22, 0x1e, 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x49, 0x44, 0x22, 0x68, 0x0a, 0x0a, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x06, 0x53, 0x74, 0x64, 0x6f, 0x75, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x53, 0x74, 0x64, 0x6f, 0x75, 0x74, - 0x12, 0x18, 0x0a, 0x06, 0x53, 0x74, 0x64, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x48, 0x00, 0x52, 0x06, 0x53, 0x74, 0x64, 0x65, 0x72, 0x72, 0x12, 0x1c, 0x0a, 0x08, 0x45, 0x78, - 0x69, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x08, - 0x45, 0x78, 0x69, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x4f, 0x75, 0x74, 0x70, - 0x75, 0x74, 0x32, 0xce, 0x01, 0x0a, 0x06, 0x42, 0x69, 0x74, 0x42, 0x6f, 0x78, 0x12, 0x2f, 0x0a, - 0x05, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, - 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x67, 0x72, 0x70, - 0x63, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x2c, - 0x0a, 0x04, 0x53, 0x74, 0x6f, 0x70, 0x12, 0x11, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, - 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x67, 0x72, 0x70, 0x63, - 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x32, 0x0a, 0x06, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x13, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x67, 0x72, - 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, - 0x12, 0x31, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, - 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, - 0x67, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, - 0x00, 0x30, 0x01, 0x42, 0x21, 0x5a, 0x1f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x6a, 0x6d, 0x62, 0x61, 0x72, 0x7a, 0x65, 0x65, 0x2f, 0x62, 0x69, 0x74, 0x62, 0x6f, - 0x78, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x1c, + 0x0a, 0x09, 0x41, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x09, 0x41, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x1c, 0x0a, 0x0a, + 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x49, 0x44, 0x22, 0x1d, 0x0a, 0x0b, 0x53, 0x74, + 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x49, 0x44, 0x22, 0x0b, 0x0a, 0x09, 0x53, 0x74, 0x6f, + 0x70, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1f, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x02, 0x49, 0x44, 0x22, 0x3d, 0x0a, 0x0b, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x2e, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x10, 0x00, 0x12, 0x0a, 0x0a, + 0x06, 0x45, 0x78, 0x69, 0x74, 0x65, 0x64, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x74, 0x6f, + 0x70, 0x70, 0x65, 0x64, 0x10, 0x02, 0x22, 0x1e, 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x02, 0x49, 0x44, 0x22, 0x68, 0x0a, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x06, 0x53, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x53, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x12, 0x18, + 0x0a, 0x06, 0x53, 0x74, 0x64, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, + 0x52, 0x06, 0x53, 0x74, 0x64, 0x65, 0x72, 0x72, 0x12, 0x1c, 0x0a, 0x08, 0x45, 0x78, 0x69, 0x74, + 0x43, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x08, 0x45, 0x78, + 0x69, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x32, 0xce, 0x01, 0x0a, 0x06, 0x42, 0x69, 0x74, 0x42, 0x6f, 0x78, 0x12, 0x2f, 0x0a, 0x05, 0x53, + 0x74, 0x61, 0x72, 0x74, 0x12, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x72, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x2c, 0x0a, 0x04, + 0x53, 0x74, 0x6f, 0x70, 0x12, 0x11, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x6f, 0x70, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, + 0x74, 0x6f, 0x70, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x32, 0x0a, 0x06, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x12, 0x13, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x31, + 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x51, + 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x30, + 0x01, 0x42, 0x21, 0x5a, 0x1f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x6a, 0x6d, 0x62, 0x61, 0x72, 0x7a, 0x65, 0x65, 0x2f, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x2f, + 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/grpc/bitbox.proto b/grpc/bitbox.proto index 86dad42..1ffa249 100644 --- a/grpc/bitbox.proto +++ b/grpc/bitbox.proto @@ -26,10 +26,10 @@ message StartRequest { // Command should be a fullpath or found in a directory in PATH. string Command = 1; - // Parameters are handed to the command as ARGV. + // Arguments are handed to the command as ARGV. // Glob patterns, pipelines, and redirections are not handled // and will instead be passed as literal strings to the command. - repeated string Parameters = 2; + repeated string Arguments = 2; } // StartReply holds the ID of the started process. From 6ee8ab0270f0a8f98e45cb47dd773d58db4b80aa Mon Sep 17 00:00:00 2001 From: Jacob Barzee Date: Tue, 23 Mar 2021 15:29:55 -0600 Subject: [PATCH 07/15] Add Status field to proto StatusReply --- cmd/client/status.go | 5 +- grpc/bitbox.pb.go | 146 ++++++++++++++++++++++++------------------- grpc/bitbox.proto | 3 +- 3 files changed, 85 insertions(+), 69 deletions(-) diff --git a/cmd/client/status.go b/cmd/client/status.go index 0fd5ed5..ec35d81 100644 --- a/cmd/client/status.go +++ b/cmd/client/status.go @@ -41,10 +41,11 @@ func (j jobStatus) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { ID: []byte(j.id), } - _, err := c.Status(ctx, request) + reply, err := c.Status(ctx, request) if err != nil { log.Fatal(fmt.Errorf("failed to stop process %s: %w", j.id, err)) } - log.Println("Successfully statused process ", j.id) + log.Println("Successfully queried status of process: ", j.id, ", ", reply.Status.String()) + return nil } diff --git a/grpc/bitbox.pb.go b/grpc/bitbox.pb.go index 619ce67..05457a7 100644 --- a/grpc/bitbox.pb.go +++ b/grpc/bitbox.pb.go @@ -20,55 +20,55 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -type StatusReply_Status int32 +type StatusReply_StatusEnum int32 const ( // Running indicates that the process is running. - StatusReply_Running StatusReply_Status = 0 + StatusReply_Running StatusReply_StatusEnum = 0 // Exited indicates that the process returned a non-zero exit code. - StatusReply_Exited StatusReply_Status = 1 + StatusReply_Exited StatusReply_StatusEnum = 1 // Stopped indicates that the process returned no exit code. - StatusReply_Stopped StatusReply_Status = 2 + StatusReply_Stopped StatusReply_StatusEnum = 2 ) -// Enum value maps for StatusReply_Status. +// Enum value maps for StatusReply_StatusEnum. var ( - StatusReply_Status_name = map[int32]string{ + StatusReply_StatusEnum_name = map[int32]string{ 0: "Running", 1: "Exited", 2: "Stopped", } - StatusReply_Status_value = map[string]int32{ + StatusReply_StatusEnum_value = map[string]int32{ "Running": 0, "Exited": 1, "Stopped": 2, } ) -func (x StatusReply_Status) Enum() *StatusReply_Status { - p := new(StatusReply_Status) +func (x StatusReply_StatusEnum) Enum() *StatusReply_StatusEnum { + p := new(StatusReply_StatusEnum) *p = x return p } -func (x StatusReply_Status) String() string { +func (x StatusReply_StatusEnum) String() string { return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (StatusReply_Status) Descriptor() protoreflect.EnumDescriptor { +func (StatusReply_StatusEnum) Descriptor() protoreflect.EnumDescriptor { return file_bitbox_proto_enumTypes[0].Descriptor() } -func (StatusReply_Status) Type() protoreflect.EnumType { +func (StatusReply_StatusEnum) Type() protoreflect.EnumType { return &file_bitbox_proto_enumTypes[0] } -func (x StatusReply_Status) Number() protoreflect.EnumNumber { +func (x StatusReply_StatusEnum) Number() protoreflect.EnumNumber { return protoreflect.EnumNumber(x) } -// Deprecated: Use StatusReply_Status.Descriptor instead. -func (StatusReply_Status) EnumDescriptor() ([]byte, []int) { +// Deprecated: Use StatusReply_StatusEnum.Descriptor instead. +func (StatusReply_StatusEnum) EnumDescriptor() ([]byte, []int) { return file_bitbox_proto_rawDescGZIP(), []int{5, 0} } @@ -324,6 +324,8 @@ type StatusReply struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + + Status StatusReply_StatusEnum `protobuf:"varint,1,opt,name=Status,proto3,enum=grpc.StatusReply_StatusEnum" json:"Status,omitempty"` } func (x *StatusReply) Reset() { @@ -358,6 +360,13 @@ func (*StatusReply) Descriptor() ([]byte, []int) { return file_bitbox_proto_rawDescGZIP(), []int{5} } +func (x *StatusReply) GetStatus() StatusReply_StatusEnum { + if x != nil { + return x.Status + } + return StatusReply_Running +} + // QueryRequest holds the ID of the process whose output is being queried. type QueryRequest struct { state protoimpl.MessageState @@ -522,35 +531,39 @@ var file_bitbox_proto_rawDesc = []byte{ 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x49, 0x44, 0x22, 0x0b, 0x0a, 0x09, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1f, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x02, 0x49, 0x44, 0x22, 0x3d, 0x0a, 0x0b, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x2e, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x10, 0x00, 0x12, 0x0a, 0x0a, - 0x06, 0x45, 0x78, 0x69, 0x74, 0x65, 0x64, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x74, 0x6f, - 0x70, 0x70, 0x65, 0x64, 0x10, 0x02, 0x22, 0x1e, 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x02, 0x49, 0x44, 0x22, 0x68, 0x0a, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, - 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x06, 0x53, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x53, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x12, 0x18, - 0x0a, 0x06, 0x53, 0x74, 0x64, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, - 0x52, 0x06, 0x53, 0x74, 0x64, 0x65, 0x72, 0x72, 0x12, 0x1c, 0x0a, 0x08, 0x45, 0x78, 0x69, 0x74, - 0x43, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x08, 0x45, 0x78, - 0x69, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, - 0x32, 0xce, 0x01, 0x0a, 0x06, 0x42, 0x69, 0x74, 0x42, 0x6f, 0x78, 0x12, 0x2f, 0x0a, 0x05, 0x53, - 0x74, 0x61, 0x72, 0x74, 0x12, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x72, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, - 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x2c, 0x0a, 0x04, - 0x53, 0x74, 0x6f, 0x70, 0x12, 0x11, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x6f, 0x70, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, - 0x74, 0x6f, 0x70, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x32, 0x0a, 0x06, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x12, 0x13, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x67, 0x72, 0x70, 0x63, - 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x31, - 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x51, - 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x67, 0x72, - 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x30, - 0x01, 0x42, 0x21, 0x5a, 0x1f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x6a, 0x6d, 0x62, 0x61, 0x72, 0x7a, 0x65, 0x65, 0x2f, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x2f, - 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x01, 0x28, 0x0c, 0x52, 0x02, 0x49, 0x44, 0x22, 0x77, 0x0a, 0x0b, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x34, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x32, 0x0a, 0x0a, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x75, + 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x45, 0x78, 0x69, 0x74, 0x65, + 0x64, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x74, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x10, 0x02, + 0x22, 0x1e, 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x49, 0x44, + 0x22, 0x68, 0x0a, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18, + 0x0a, 0x06, 0x53, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, + 0x52, 0x06, 0x53, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x12, 0x18, 0x0a, 0x06, 0x53, 0x74, 0x64, 0x65, + 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x53, 0x74, 0x64, 0x65, + 0x72, 0x72, 0x12, 0x1c, 0x0a, 0x08, 0x45, 0x78, 0x69, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x08, 0x45, 0x78, 0x69, 0x74, 0x43, 0x6f, 0x64, 0x65, + 0x42, 0x08, 0x0a, 0x06, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x32, 0xce, 0x01, 0x0a, 0x06, 0x42, + 0x69, 0x74, 0x42, 0x6f, 0x78, 0x12, 0x2f, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x12, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x2c, 0x0a, 0x04, 0x53, 0x74, 0x6f, 0x70, 0x12, 0x11, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x0f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x70, + 0x6c, 0x79, 0x22, 0x00, 0x12, 0x32, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x13, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x12, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, + 0x72, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x30, 0x01, 0x42, 0x21, 0x5a, 0x1f, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6a, 0x6d, 0x62, 0x61, 0x72, 0x7a, + 0x65, 0x65, 0x2f, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -568,30 +581,31 @@ func file_bitbox_proto_rawDescGZIP() []byte { var file_bitbox_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_bitbox_proto_msgTypes = make([]protoimpl.MessageInfo, 8) var file_bitbox_proto_goTypes = []interface{}{ - (StatusReply_Status)(0), // 0: grpc.StatusReply.Status - (*StartRequest)(nil), // 1: grpc.StartRequest - (*StartReply)(nil), // 2: grpc.StartReply - (*StopRequest)(nil), // 3: grpc.StopRequest - (*StopReply)(nil), // 4: grpc.StopReply - (*StatusRequest)(nil), // 5: grpc.StatusRequest - (*StatusReply)(nil), // 6: grpc.StatusReply - (*QueryRequest)(nil), // 7: grpc.QueryRequest - (*QueryReply)(nil), // 8: grpc.QueryReply + (StatusReply_StatusEnum)(0), // 0: grpc.StatusReply.StatusEnum + (*StartRequest)(nil), // 1: grpc.StartRequest + (*StartReply)(nil), // 2: grpc.StartReply + (*StopRequest)(nil), // 3: grpc.StopRequest + (*StopReply)(nil), // 4: grpc.StopReply + (*StatusRequest)(nil), // 5: grpc.StatusRequest + (*StatusReply)(nil), // 6: grpc.StatusReply + (*QueryRequest)(nil), // 7: grpc.QueryRequest + (*QueryReply)(nil), // 8: grpc.QueryReply } var file_bitbox_proto_depIdxs = []int32{ - 1, // 0: grpc.BitBox.Start:input_type -> grpc.StartRequest - 3, // 1: grpc.BitBox.Stop:input_type -> grpc.StopRequest - 5, // 2: grpc.BitBox.Status:input_type -> grpc.StatusRequest - 7, // 3: grpc.BitBox.Query:input_type -> grpc.QueryRequest - 2, // 4: grpc.BitBox.Start:output_type -> grpc.StartReply - 4, // 5: grpc.BitBox.Stop:output_type -> grpc.StopReply - 6, // 6: grpc.BitBox.Status:output_type -> grpc.StatusReply - 8, // 7: grpc.BitBox.Query:output_type -> grpc.QueryReply - 4, // [4:8] is the sub-list for method output_type - 0, // [0:4] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name + 0, // 0: grpc.StatusReply.Status:type_name -> grpc.StatusReply.StatusEnum + 1, // 1: grpc.BitBox.Start:input_type -> grpc.StartRequest + 3, // 2: grpc.BitBox.Stop:input_type -> grpc.StopRequest + 5, // 3: grpc.BitBox.Status:input_type -> grpc.StatusRequest + 7, // 4: grpc.BitBox.Query:input_type -> grpc.QueryRequest + 2, // 5: grpc.BitBox.Start:output_type -> grpc.StartReply + 4, // 6: grpc.BitBox.Stop:output_type -> grpc.StopReply + 6, // 7: grpc.BitBox.Status:output_type -> grpc.StatusReply + 8, // 8: grpc.BitBox.Query:output_type -> grpc.QueryReply + 5, // [5:9] is the sub-list for method output_type + 1, // [1:5] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name } func init() { file_bitbox_proto_init() } diff --git a/grpc/bitbox.proto b/grpc/bitbox.proto index 1ffa249..c678389 100644 --- a/grpc/bitbox.proto +++ b/grpc/bitbox.proto @@ -62,7 +62,7 @@ message StatusRequest { // StatusReply holds the status of the reply message StatusReply { - enum Status { + enum StatusEnum { // Running indicates that the process is running. Running = 0; // Exited indicates that the process returned a non-zero exit code. @@ -70,6 +70,7 @@ message StatusReply { // Stopped indicates that the process returned no exit code. Stopped = 2; } + StatusEnum Status = 1; } From 9a56eaabfb4c89135326b8fcdfe89765d7f7d274 Mon Sep 17 00:00:00 2001 From: Jacob Barzee Date: Tue, 23 Mar 2021 15:30:17 -0600 Subject: [PATCH 08/15] Implement bitbox.Server() --- server.go | 68 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 8 deletions(-) diff --git a/server.go b/server.go index e3b00fa..f993bca 100644 --- a/server.go +++ b/server.go @@ -2,8 +2,11 @@ package bitbox import ( "context" + "fmt" + "github.com/google/uuid" "github.com/jmbarzee/bitbox/grpc" + "github.com/jmbarzee/bitbox/proc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -15,28 +18,77 @@ var _ grpc.BitBoxServer = (*Server)(nil) type Server struct { // UnimplementedBitBoxServer is embedded to enable forwards compatability grpc.UnimplementedBitBoxServer + c *Core } func NewServer() *Server { - return &Server{} + return &Server{ + c: NewCore(), + } } // Start initiates a process. -func (s *Server) Start(ctx context.Context, start *grpc.StartRequest) (*grpc.StartReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method Start not implemented") +func (s *Server) Start(ctx context.Context, request *grpc.StartRequest) (*grpc.StartReply, error) { + cmd := request.GetCommand() + args := request.GetArguments() + uuid, err := s.c.Start(cmd, args...) + if err != nil { + return nil, err + } + + uuidBytes := uuid[:] + + return &grpc.StartReply{ + ID: uuidBytes, + }, nil } // Stop halts a process. -func (s *Server) Stop(context.Context, *grpc.StopRequest) (*grpc.StopReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method Stop not implemented") +func (s *Server) Stop(ctx context.Context, request *grpc.StopRequest) (*grpc.StopReply, error) { + uuid, err := uuid.FromBytes(request.GetID()) + if err != nil { + return nil, err + } + return &grpc.StopReply{}, s.c.Stop(uuid) } // Status returns the status of a process. -func (s *Server) Status(context.Context, *grpc.StatusRequest) (*grpc.StatusReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method Stop not implemented") +func (s *Server) Status(ctx context.Context, request *grpc.StatusRequest) (*grpc.StatusReply, error) { + uuid, err := uuid.FromBytes(request.GetID()) + if err != nil { + return nil, err + } + + status, err := s.c.Status(uuid) + if err != nil { + return nil, err + } + + grpcStatus, err := convertToGRPCStatus(status) + if err != nil { + return nil, err + } + + return &grpc.StatusReply{ + Status: grpcStatus, + }, nil +} + +func convertToGRPCStatus(status proc.ProcStatus) (grpc.StatusReply_StatusEnum, error) { + // We could leverage implement this function on the proc.ProcStatus, + // That would force the proc package to know import grpc, which is worth avoiding. + switch status { + case proc.Running: + return grpc.StatusReply_Running, nil + case proc.Exited: + return grpc.StatusReply_Exited, nil + case proc.Stopped: + return grpc.StatusReply_Stopped, nil + } + return 0, fmt.Errorf("Unknown process status: %v", status) } // Query streams the output/result of a process. -func (s *Server) Query(*grpc.QueryRequest, grpc.BitBox_QueryServer) error { +func (s *Server) Query(request *grpc.QueryRequest, queryServer grpc.BitBox_QueryServer) error { return status.Errorf(codes.Unimplemented, "method Query not implemented") } From f61fcc17d37b40159338a94d5348c5afbe8ec7c5 Mon Sep 17 00:00:00 2001 From: Jacob Barzee Date: Tue, 23 Mar 2021 15:49:41 -0600 Subject: [PATCH 09/15] Add logging to bitbox.Server --- server.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/server.go b/server.go index f993bca..cea3532 100644 --- a/server.go +++ b/server.go @@ -3,6 +3,7 @@ package bitbox import ( "context" "fmt" + "log" "github.com/google/uuid" "github.com/jmbarzee/bitbox/grpc" @@ -31,6 +32,8 @@ func NewServer() *Server { func (s *Server) Start(ctx context.Context, request *grpc.StartRequest) (*grpc.StartReply, error) { cmd := request.GetCommand() args := request.GetArguments() + log.Println("[Start] ", cmd, args) + uuid, err := s.c.Start(cmd, args...) if err != nil { return nil, err @@ -49,6 +52,8 @@ func (s *Server) Stop(ctx context.Context, request *grpc.StopRequest) (*grpc.Sto if err != nil { return nil, err } + log.Println("[Stop] ", uuid.String()) + return &grpc.StopReply{}, s.c.Stop(uuid) } @@ -58,6 +63,7 @@ func (s *Server) Status(ctx context.Context, request *grpc.StatusRequest) (*grpc if err != nil { return nil, err } + log.Println("[Status] ", uuid.String()) status, err := s.c.Status(uuid) if err != nil { @@ -90,5 +96,11 @@ func convertToGRPCStatus(status proc.ProcStatus) (grpc.StatusReply_StatusEnum, e // Query streams the output/result of a process. func (s *Server) Query(request *grpc.QueryRequest, queryServer grpc.BitBox_QueryServer) error { + uuid, err := uuid.FromBytes(request.GetID()) + if err != nil { + return err + } + + log.Println("[Query] ", uuid.String()) return status.Errorf(codes.Unimplemented, "method Query not implemented") } From de99b405796b3a8c771e040bae0369357e22a776 Mon Sep 17 00:00:00 2001 From: Jacob Barzee Date: Tue, 23 Mar 2021 15:50:30 -0600 Subject: [PATCH 10/15] Fix argument passing in bitboxcli Start command --- cmd/client/start.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/client/start.go b/cmd/client/start.go index 0696200..bd5646b 100644 --- a/cmd/client/start.go +++ b/cmd/client/start.go @@ -22,7 +22,7 @@ var cmdStart = &cobra.Command{ job := jobStart{ command: args[0], - arguments: args[0:], + arguments: args[1:], } ctx := context.Background() bbClient := getClient(ctx) From 212cdcfeef9495cb10f43fec2b799452deb82a74 Mon Sep 17 00:00:00 2001 From: Jacob Barzee Date: Tue, 23 Mar 2021 15:51:05 -0600 Subject: [PATCH 11/15] Fix uuid parsing in bitboxcli --- cmd/client/query.go | 12 +++++++++--- cmd/client/start.go | 4 +++- cmd/client/status.go | 12 +++++++++--- cmd/client/stop.go | 12 +++++++++--- server.go | 4 +--- 5 files changed, 31 insertions(+), 13 deletions(-) diff --git a/cmd/client/query.go b/cmd/client/query.go index e476278..bb9d20c 100644 --- a/cmd/client/query.go +++ b/cmd/client/query.go @@ -6,6 +6,7 @@ import ( "fmt" "log" + "github.com/google/uuid" "github.com/spf13/cobra" bbgrpc "github.com/jmbarzee/bitbox/grpc" @@ -20,8 +21,13 @@ var cmdQuery = &cobra.Command{ panic(errors.New("Require a single id as an argument")) } + uuid, err := uuid.Parse(args[0]) + if err != nil { + panic(err) + } + job := jobQuery{ - id: args[0], + id: uuid, } ctx := context.Background() bbClient := getClient(ctx) @@ -32,13 +38,13 @@ var cmdQuery = &cobra.Command{ } type jobQuery struct { - id string + id uuid.UUID } // Execute querys a job on the remote BibBox func (j jobQuery) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { request := &bbgrpc.QueryRequest{ - ID: []byte(j.id), + ID: j.id[:], } queryClient, err := c.Query(ctx, request) diff --git a/cmd/client/start.go b/cmd/client/start.go index bd5646b..43277af 100644 --- a/cmd/client/start.go +++ b/cmd/client/start.go @@ -6,6 +6,7 @@ import ( "fmt" "log" + "github.com/google/uuid" "github.com/spf13/cobra" bbgrpc "github.com/jmbarzee/bitbox/grpc" @@ -48,6 +49,7 @@ func (j jobStart) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { if err != nil { log.Fatal(fmt.Errorf("failed to run %s: %w", j.command, err)) } - log.Println("Successfully started process: ", reply.GetID()) + uuid, err := uuid.FromBytes(reply.GetID()) + log.Println("Successfully started process: ", uuid.String()) return nil } diff --git a/cmd/client/status.go b/cmd/client/status.go index ec35d81..dae3e4d 100644 --- a/cmd/client/status.go +++ b/cmd/client/status.go @@ -6,6 +6,7 @@ import ( "fmt" "log" + "github.com/google/uuid" "github.com/spf13/cobra" bbgrpc "github.com/jmbarzee/bitbox/grpc" @@ -20,8 +21,13 @@ var cmdStatus = &cobra.Command{ panic(errors.New("Require a single id as an argument")) } + uuid, err := uuid.Parse(args[0]) + if err != nil { + panic(err) + } + job := jobStatus{ - id: args[0], + id: uuid, } ctx := context.Background() bbClient := getClient(ctx) @@ -32,13 +38,13 @@ var cmdStatus = &cobra.Command{ } type jobStatus struct { - id string + id uuid.UUID } // Execute returns the status of a job on the remote BibBox func (j jobStatus) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { request := &bbgrpc.StatusRequest{ - ID: []byte(j.id), + ID: j.id[:], } reply, err := c.Status(ctx, request) diff --git a/cmd/client/stop.go b/cmd/client/stop.go index 1bbebf0..c6a9d6a 100644 --- a/cmd/client/stop.go +++ b/cmd/client/stop.go @@ -6,6 +6,7 @@ import ( "fmt" "log" + "github.com/google/uuid" "github.com/spf13/cobra" bbgrpc "github.com/jmbarzee/bitbox/grpc" @@ -20,8 +21,13 @@ var cmdStop = &cobra.Command{ panic(errors.New("Require a single id as an argument")) } + uuid, err := uuid.Parse(args[0]) + if err != nil { + panic(err) + } + job := jobStop{ - id: args[0], + id: uuid, } ctx := context.Background() bbClient := getClient(ctx) @@ -32,13 +38,13 @@ var cmdStop = &cobra.Command{ } type jobStop struct { - id string + id uuid.UUID } // Execute stops a job on the remote BibBox func (j jobStop) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { request := &bbgrpc.StopRequest{ - ID: []byte(j.id), + ID: j.id[:], } _, err := c.Stop(ctx, request) diff --git a/server.go b/server.go index cea3532..e6f767d 100644 --- a/server.go +++ b/server.go @@ -39,10 +39,8 @@ func (s *Server) Start(ctx context.Context, request *grpc.StartRequest) (*grpc.S return nil, err } - uuidBytes := uuid[:] - return &grpc.StartReply{ - ID: uuidBytes, + ID: uuid[:], }, nil } From a649e72fe04c6e6cbc4cae2a35707a8a9933449d Mon Sep 17 00:00:00 2001 From: Jacob Barzee Date: Tue, 23 Mar 2021 16:34:15 -0600 Subject: [PATCH 12/15] Implement bitbox.Server.Query(), remove ProcOutput types in favor of string --- cmd/client/query.go | 18 +++----- core.go | 2 +- grpc/bitbox.pb.go | 108 ++++++++++---------------------------------- grpc/bitbox.proto | 11 +---- proc/proc.go | 54 ++++++---------------- server.go | 20 ++++++-- 6 files changed, 63 insertions(+), 150 deletions(-) diff --git a/cmd/client/query.go b/cmd/client/query.go index bb9d20c..5c24593 100644 --- a/cmd/client/query.go +++ b/cmd/client/query.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "io" "log" "github.com/google/uuid" @@ -52,23 +53,16 @@ func (j jobQuery) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { log.Fatal(fmt.Errorf("failed to stop process %s: %w", j.id, err)) } -Loop: for { reply, err := queryClient.Recv() - if err != nil { - log.Println(fmt.Errorf("failed to fetch reply: %w", err)) - log.Println(fmt.Errorf("failed to fetch reply: %w", err)) + if err == io.EOF { + log.Println("") break } - switch output := reply.GetOutput().(type) { - case *bbgrpc.QueryReply_Stdout: - log.Println(output.Stdout) - case *bbgrpc.QueryReply_Stderr: - log.Printf("Error: %v", output.Stderr) - case *bbgrpc.QueryReply_ExitCode: - log.Printf("Process %v exited with code %v", j.id, output.ExitCode) - break Loop + if err != nil { + log.Fatal(fmt.Errorf("failed to fetch reply: %w", err)) } + log.Print(reply.GetOutput()) } return nil diff --git a/core.go b/core.go index 964ff56..b4cad71 100644 --- a/core.go +++ b/core.go @@ -63,7 +63,7 @@ func (c *Core) Status(id uuid.UUID) (proc.ProcStatus, error) { } // Query streams the output/result of a process. -func (c *Core) Query(id uuid.UUID) (<-chan proc.ProcOutput, error) { +func (c *Core) Query(id uuid.UUID) (<-chan string, error) { var p *proc.Proc var err error diff --git a/grpc/bitbox.pb.go b/grpc/bitbox.pb.go index 05457a7..cb3af8a 100644 --- a/grpc/bitbox.pb.go +++ b/grpc/bitbox.pb.go @@ -422,13 +422,8 @@ type QueryReply struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Output is one of the forms of output that a process may utilize. - // - // Types that are assignable to Output: - // *QueryReply_Stdout - // *QueryReply_Stderr - // *QueryReply_ExitCode - Output isQueryReply_Output `protobuf_oneof:"Output"` + // Output is the output of the process (includes exit code) + Output string `protobuf:"bytes,1,opt,name=Output,proto3" json:"Output,omitempty"` } func (x *QueryReply) Reset() { @@ -463,59 +458,13 @@ func (*QueryReply) Descriptor() ([]byte, []int) { return file_bitbox_proto_rawDescGZIP(), []int{7} } -func (m *QueryReply) GetOutput() isQueryReply_Output { - if m != nil { - return m.Output - } - return nil -} - -func (x *QueryReply) GetStdout() string { - if x, ok := x.GetOutput().(*QueryReply_Stdout); ok { - return x.Stdout - } - return "" -} - -func (x *QueryReply) GetStderr() string { - if x, ok := x.GetOutput().(*QueryReply_Stderr); ok { - return x.Stderr +func (x *QueryReply) GetOutput() string { + if x != nil { + return x.Output } return "" } -func (x *QueryReply) GetExitCode() uint32 { - if x, ok := x.GetOutput().(*QueryReply_ExitCode); ok { - return x.ExitCode - } - return 0 -} - -type isQueryReply_Output interface { - isQueryReply_Output() -} - -type QueryReply_Stdout struct { - // Stdout is any output from the process which was written to Stdout. - Stdout string `protobuf:"bytes,1,opt,name=Stdout,proto3,oneof"` -} - -type QueryReply_Stderr struct { - // Stderr is any output from the process which was written to Stderr. - Stderr string `protobuf:"bytes,2,opt,name=Stderr,proto3,oneof"` -} - -type QueryReply_ExitCode struct { - // ExitCode is the code the process exited with. - ExitCode uint32 `protobuf:"varint,3,opt,name=ExitCode,proto3,oneof"` -} - -func (*QueryReply_Stdout) isQueryReply_Output() {} - -func (*QueryReply_Stderr) isQueryReply_Output() {} - -func (*QueryReply_ExitCode) isQueryReply_Output() {} - var File_bitbox_proto protoreflect.FileDescriptor var file_bitbox_proto_rawDesc = []byte{ @@ -541,29 +490,25 @@ var file_bitbox_proto_rawDesc = []byte{ 0x64, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x74, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x10, 0x02, 0x22, 0x1e, 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x49, 0x44, - 0x22, 0x68, 0x0a, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18, - 0x0a, 0x06, 0x53, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, - 0x52, 0x06, 0x53, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x12, 0x18, 0x0a, 0x06, 0x53, 0x74, 0x64, 0x65, - 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x53, 0x74, 0x64, 0x65, - 0x72, 0x72, 0x12, 0x1c, 0x0a, 0x08, 0x45, 0x78, 0x69, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x08, 0x45, 0x78, 0x69, 0x74, 0x43, 0x6f, 0x64, 0x65, - 0x42, 0x08, 0x0a, 0x06, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x32, 0xce, 0x01, 0x0a, 0x06, 0x42, - 0x69, 0x74, 0x42, 0x6f, 0x78, 0x12, 0x2f, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x12, - 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, - 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x2c, 0x0a, 0x04, 0x53, 0x74, 0x6f, 0x70, 0x12, 0x11, - 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x0f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x70, - 0x6c, 0x79, 0x22, 0x00, 0x12, 0x32, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x13, - 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x12, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, - 0x72, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x30, 0x01, 0x42, 0x21, 0x5a, 0x1f, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6a, 0x6d, 0x62, 0x61, 0x72, 0x7a, - 0x65, 0x65, 0x2f, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x22, 0x24, 0x0a, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x16, + 0x0a, 0x06, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x32, 0xce, 0x01, 0x0a, 0x06, 0x42, 0x69, 0x74, 0x42, 0x6f, + 0x78, 0x12, 0x2f, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x12, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x22, 0x00, 0x12, 0x2c, 0x0a, 0x04, 0x53, 0x74, 0x6f, 0x70, 0x12, 0x11, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, + 0x12, 0x32, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x13, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x11, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, + 0x6c, 0x79, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x12, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x10, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, + 0x70, 0x6c, 0x79, 0x22, 0x00, 0x30, 0x01, 0x42, 0x21, 0x5a, 0x1f, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6a, 0x6d, 0x62, 0x61, 0x72, 0x7a, 0x65, 0x65, 0x2f, 0x62, + 0x69, 0x74, 0x62, 0x6f, 0x78, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( @@ -711,11 +656,6 @@ func file_bitbox_proto_init() { } } } - file_bitbox_proto_msgTypes[7].OneofWrappers = []interface{}{ - (*QueryReply_Stdout)(nil), - (*QueryReply_Stderr)(nil), - (*QueryReply_ExitCode)(nil), - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ diff --git a/grpc/bitbox.proto b/grpc/bitbox.proto index c678389..78d792d 100644 --- a/grpc/bitbox.proto +++ b/grpc/bitbox.proto @@ -84,13 +84,6 @@ message QueryRequest { // QueryReply holds output of the process queried. message QueryReply { - // Output is one of the forms of output that a process may utilize. - oneof Output { - // Stdout is any output from the process which was written to Stdout. - string Stdout = 1; - // Stderr is any output from the process which was written to Stderr. - string Stderr = 2; - // ExitCode is the code the process exited with. - uint32 ExitCode = 3; - } + // Output is the output of the process (includes exit code) + string Output = 1; } \ No newline at end of file diff --git a/proc/proc.go b/proc/proc.go index d62d12f..8fdfaaf 100644 --- a/proc/proc.go +++ b/proc/proc.go @@ -9,6 +9,7 @@ package proc import ( "context" + "fmt" "io/ioutil" "os" "os/exec" @@ -109,7 +110,7 @@ func (ps ProcStatus) String() string { // a third routine finds that the process has exited. // The third routine cancels the context of the pollReads. // After the read routines finish the third routine sends the ExitCode and closes the channel. -func (p *Proc) Query() (<-chan ProcOutput, error) { +func (p *Proc) Query() (<-chan string, error) { flags := os.O_RDONLY | os.O_SYNC outputFile, err := os.OpenFile(p.outputFileName, flags, 0600) if err != nil { @@ -117,7 +118,7 @@ func (p *Proc) Query() (<-chan ProcOutput, error) { } ctx, cancel := context.WithCancel(context.Background()) - stream := make(chan ProcOutput) + stream := make(chan string) wg := &sync.WaitGroup{} wg.Add(1) @@ -138,9 +139,8 @@ func (p *Proc) Query() (<-chan ProcOutput, error) { cancel() wg.Wait() - stream <- &ProcOutput_ExitCode{ - ExitCode: uint32(p.cmd.ProcessState.ExitCode()), - } + exitCodeMsg := fmt.Sprintf("Exited with code %v", uint32(p.cmd.ProcessState.ExitCode())) + stream <- exitCodeMsg close(stream) }() @@ -150,7 +150,7 @@ func (p *Proc) Query() (<-chan ProcOutput, error) { func pollRead( ctx context.Context, file *os.File, - stream chan<- ProcOutput, + stream chan<- string, ) { buf := make([]byte, 1024) ticker := time.NewTicker(outputReadRefreshInterval) @@ -158,7 +158,6 @@ func pollRead( for { select { case <-ticker.C: - // ReadLoop for { n, err := file.Read(buf) if err != nil { @@ -168,7 +167,9 @@ func pollRead( if n == 0 { break // move to wait for ticker or context to end } - stream <- newProcOutput_Stdouterr(buf) + var copiedBytes []byte + copy(copiedBytes, buf) + stream <- string(copiedBytes) } case <-ctx.Done(): return @@ -178,7 +179,7 @@ func pollRead( func finishRead( file *os.File, - stream chan<- ProcOutput, + stream chan<- string, ) { buf := make([]byte, 1024) @@ -191,37 +192,8 @@ func finishRead( if n == 0 { break } - stream <- newProcOutput_Stdouterr(buf) - } -} - -// ProcOutput is any output from a process. -type ProcOutput interface { - isProcOutput() -} - -var _ ProcOutput = (*ProcOutput_Stdouterr)(nil) - -// ProcOutput_Stdouterr is any output from the process which was written to Stdout and Stderr. -type ProcOutput_Stdouterr struct { - // Stdout is a series of characters sent to Stdout by a process. - Output string -} - -func newProcOutput_Stdouterr(b []byte) ProcOutput { - return &ProcOutput_Stdouterr{ - Output: (string)(b), + var copiedBytes []byte + copy(copiedBytes, buf) + stream <- string(copiedBytes) } } - -func (*ProcOutput_Stdouterr) isProcOutput() {} - -var _ ProcOutput = (*ProcOutput_ExitCode)(nil) - -// ProcOutput_ExitCode is any output from the process which was written to Stderr. -type ProcOutput_ExitCode struct { - // ExitCode is the exit code of a process. - ExitCode uint32 -} - -func (*ProcOutput_ExitCode) isProcOutput() {} diff --git a/server.go b/server.go index e6f767d..b0e5615 100644 --- a/server.go +++ b/server.go @@ -8,8 +8,6 @@ import ( "github.com/google/uuid" "github.com/jmbarzee/bitbox/grpc" "github.com/jmbarzee/bitbox/proc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) // ensure Server implements BitBoxServer @@ -100,5 +98,21 @@ func (s *Server) Query(request *grpc.QueryRequest, queryServer grpc.BitBox_Query } log.Println("[Query] ", uuid.String()) - return status.Errorf(codes.Unimplemented, "method Query not implemented") + + // TODO: pass context from queryServer to Query + stream, err := s.c.Query(uuid) + if err != nil { + return err + } + + for output := range stream { + reply := &grpc.QueryReply{ + Output: output, + } + err := queryServer.Send(reply) + if err != nil { + return err // TODO: is this really how we should handle this? + } + } + return nil } From 456b86dcd7c89123aee4ebbf15b2b36fc6932a09 Mon Sep 17 00:00:00 2001 From: Jacob Barzee Date: Wed, 24 Mar 2021 12:37:13 -0600 Subject: [PATCH 13/15] Make Query() calls pass context --- core.go | 5 +++-- proc/proc.go | 43 ++++++++++++++++++++++++++++++------------- server.go | 2 +- 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/core.go b/core.go index b4cad71..589ed72 100644 --- a/core.go +++ b/core.go @@ -1,6 +1,7 @@ package bitbox import ( + "context" "fmt" "sync" @@ -63,7 +64,7 @@ func (c *Core) Status(id uuid.UUID) (proc.ProcStatus, error) { } // Query streams the output/result of a process. -func (c *Core) Query(id uuid.UUID) (<-chan string, error) { +func (c *Core) Query(ctx context.Context, id uuid.UUID) (<-chan string, error) { var p *proc.Proc var err error @@ -71,7 +72,7 @@ func (c *Core) Query(id uuid.UUID) (<-chan string, error) { return nil, c.newError("Query", err) } - return p.Query() + return p.Query(ctx) } func (c *Core) findProcess(id uuid.UUID) (*proc.Proc, error) { diff --git a/proc/proc.go b/proc/proc.go index 8fdfaaf..e03799d 100644 --- a/proc/proc.go +++ b/proc/proc.go @@ -106,25 +106,31 @@ func (ps ProcStatus) String() string { } // Query streams output from the process to the returned channel. -// The Stdout and Stderr files are opened for reads and polled until +// The output file is opened for reads and polled until // a third routine finds that the process has exited. // The third routine cancels the context of the pollReads. -// After the read routines finish the third routine sends the ExitCode and closes the channel. -func (p *Proc) Query() (<-chan string, error) { +// After the read routines finish the third routine sends +// the ExitCode and closes the channel. +// Note: this function's structure could probably be cleaned up. +func (p *Proc) Query(ctx context.Context) (<-chan string, error) { flags := os.O_RDONLY | os.O_SYNC outputFile, err := os.OpenFile(p.outputFileName, flags, 0600) if err != nil { return nil, err } - ctx, cancel := context.WithCancel(context.Background()) + pollContext, cancelPoll := context.WithCancel(ctx) stream := make(chan string) wg := &sync.WaitGroup{} wg.Add(1) go func() { - pollRead(ctx, outputFile, stream) - finishRead(outputFile, stream) + unstreamedBytes := pollRead(pollContext, outputFile, stream) + select { + case <-ctx.Done(): + case stream <- string(unstreamedBytes): + finishRead(ctx, outputFile, stream) + } outputFile.Close() wg.Done() }() @@ -137,7 +143,7 @@ func (p *Proc) Query() (<-chan string, error) { p.cmd.Wait() p.waitMutex.Unlock() - cancel() + cancelPoll() wg.Wait() exitCodeMsg := fmt.Sprintf("Exited with code %v", uint32(p.cmd.ProcessState.ExitCode())) stream <- exitCodeMsg @@ -151,33 +157,39 @@ func pollRead( ctx context.Context, file *os.File, stream chan<- string, -) { +) []byte { buf := make([]byte, 1024) ticker := time.NewTicker(outputReadRefreshInterval) for { select { + case <-ctx.Done(): + return nil case <-ticker.C: for { n, err := file.Read(buf) if err != nil { // TODO: should we log the error somehow? - return + return nil } if n == 0 { break // move to wait for ticker or context to end } var copiedBytes []byte copy(copiedBytes, buf) - stream <- string(copiedBytes) + select { + case stream <- string(copiedBytes): + //Do nothing + case <-ctx.Done(): + return copiedBytes + } } - case <-ctx.Done(): - return } } } func finishRead( + ctx context.Context, file *os.File, stream chan<- string, ) { @@ -194,6 +206,11 @@ func finishRead( } var copiedBytes []byte copy(copiedBytes, buf) - stream <- string(copiedBytes) + select { + case <-ctx.Done(): + return + case stream <- string(copiedBytes): + //Do nothing + } } } diff --git a/server.go b/server.go index b0e5615..c4ab50d 100644 --- a/server.go +++ b/server.go @@ -100,7 +100,7 @@ func (s *Server) Query(request *grpc.QueryRequest, queryServer grpc.BitBox_Query log.Println("[Query] ", uuid.String()) // TODO: pass context from queryServer to Query - stream, err := s.c.Query(uuid) + stream, err := s.c.Query(queryServer.Context(), uuid) if err != nil { return err } From 879e2c211b61354db3a92ac50e49b5ce03dc3326 Mon Sep 17 00:00:00 2001 From: Jacob Barzee Date: Wed, 24 Mar 2021 12:42:41 -0600 Subject: [PATCH 14/15] Improve error handling in client --- cmd/client/query.go | 16 +++++++--------- cmd/client/start.go | 15 ++++++++------- cmd/client/status.go | 14 ++++++-------- cmd/client/stop.go | 14 ++++++-------- 4 files changed, 27 insertions(+), 32 deletions(-) diff --git a/cmd/client/query.go b/cmd/client/query.go index 5c24593..4475463 100644 --- a/cmd/client/query.go +++ b/cmd/client/query.go @@ -17,14 +17,14 @@ var cmdQuery = &cobra.Command{ Use: "query", Short: "query", Long: "Query a process on the bitbox server", - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { if len(args) != 1 { - panic(errors.New("Require a single id as an argument")) + return errors.New("Require a single id as an argument") } uuid, err := uuid.Parse(args[0]) if err != nil { - panic(err) + return fmt.Errorf("failed to parse uuid: %s", args[0]) } job := jobQuery{ @@ -32,9 +32,7 @@ var cmdQuery = &cobra.Command{ } ctx := context.Background() bbClient := getClient(ctx) - if err := job.execute(ctx, bbClient); err != nil { - panic(err) - } + return job.execute(ctx, bbClient) }, } @@ -42,7 +40,7 @@ type jobQuery struct { id uuid.UUID } -// Execute querys a job on the remote BibBox +// Execute querys a job on the remote bitBox func (j jobQuery) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { request := &bbgrpc.QueryRequest{ ID: j.id[:], @@ -50,7 +48,7 @@ func (j jobQuery) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { queryClient, err := c.Query(ctx, request) if err != nil { - log.Fatal(fmt.Errorf("failed to stop process %s: %w", j.id, err)) + return fmt.Errorf("failed to stop process %s: %w", j.id, err) } for { @@ -60,7 +58,7 @@ func (j jobQuery) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { break } if err != nil { - log.Fatal(fmt.Errorf("failed to fetch reply: %w", err)) + return fmt.Errorf("failed to fetch reply: %w", err) } log.Print(reply.GetOutput()) } diff --git a/cmd/client/start.go b/cmd/client/start.go index 43277af..0ddf2c7 100644 --- a/cmd/client/start.go +++ b/cmd/client/start.go @@ -16,9 +16,9 @@ var cmdStart = &cobra.Command{ Use: "start", Short: "start", Long: "Start a process on the bitbox server", - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { if len(args) < 1 { - panic(errors.New("Require atleast a single command as an argument")) + return errors.New("Require atleast a single command as an argument") } job := jobStart{ @@ -27,9 +27,7 @@ var cmdStart = &cobra.Command{ } ctx := context.Background() bbClient := getClient(ctx) - if err := job.execute(ctx, bbClient); err != nil { - panic(err) - } + return job.execute(ctx, bbClient) }, } @@ -38,7 +36,7 @@ type jobStart struct { arguments []string } -// Execute starts a job on the remote BibBox +// Execute starts a job on the remote bitBox func (j jobStart) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { request := &bbgrpc.StartRequest{ Command: j.command, @@ -47,9 +45,12 @@ func (j jobStart) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { reply, err := c.Start(ctx, request) if err != nil { - log.Fatal(fmt.Errorf("failed to run %s: %w", j.command, err)) + return fmt.Errorf("failed to run %s: %w", j.command, err) } uuid, err := uuid.FromBytes(reply.GetID()) + if err != nil { + return fmt.Errorf("failed to parse uuid: %s", reply.GetID()) + } log.Println("Successfully started process: ", uuid.String()) return nil } diff --git a/cmd/client/status.go b/cmd/client/status.go index dae3e4d..0475539 100644 --- a/cmd/client/status.go +++ b/cmd/client/status.go @@ -16,14 +16,14 @@ var cmdStatus = &cobra.Command{ Use: "status", Short: "status", Long: "Stop a process on the bitbox server", - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { if len(args) != 1 { - panic(errors.New("Require a single id as an argument")) + return errors.New("Require a single id as an argument") } uuid, err := uuid.Parse(args[0]) if err != nil { - panic(err) + return fmt.Errorf("failed to parse uuid: %s", args[0]) } job := jobStatus{ @@ -31,9 +31,7 @@ var cmdStatus = &cobra.Command{ } ctx := context.Background() bbClient := getClient(ctx) - if err := job.execute(ctx, bbClient); err != nil { - panic(err) - } + return job.execute(ctx, bbClient) }, } @@ -41,7 +39,7 @@ type jobStatus struct { id uuid.UUID } -// Execute returns the status of a job on the remote BibBox +// Execute returns the status of a job on the remote bitBox func (j jobStatus) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { request := &bbgrpc.StatusRequest{ ID: j.id[:], @@ -49,7 +47,7 @@ func (j jobStatus) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { reply, err := c.Status(ctx, request) if err != nil { - log.Fatal(fmt.Errorf("failed to stop process %s: %w", j.id, err)) + return fmt.Errorf("failed to query process %s: %w", j.id, err) } log.Println("Successfully queried status of process: ", j.id, ", ", reply.Status.String()) diff --git a/cmd/client/stop.go b/cmd/client/stop.go index c6a9d6a..fe7fc64 100644 --- a/cmd/client/stop.go +++ b/cmd/client/stop.go @@ -16,14 +16,14 @@ var cmdStop = &cobra.Command{ Use: "stop", Short: "stop", Long: "Stop a process on the bitbox server", - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { if len(args) != 1 { - panic(errors.New("Require a single id as an argument")) + return errors.New("Require a single id as an argument") } uuid, err := uuid.Parse(args[0]) if err != nil { - panic(err) + return fmt.Errorf("failed to parse uuid: %s", args[0]) } job := jobStop{ @@ -31,9 +31,7 @@ var cmdStop = &cobra.Command{ } ctx := context.Background() bbClient := getClient(ctx) - if err := job.execute(ctx, bbClient); err != nil { - panic(err) - } + return job.execute(ctx, bbClient) }, } @@ -41,7 +39,7 @@ type jobStop struct { id uuid.UUID } -// Execute stops a job on the remote BibBox +// Execute stops a job on the remote bitBox func (j jobStop) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { request := &bbgrpc.StopRequest{ ID: j.id[:], @@ -49,7 +47,7 @@ func (j jobStop) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { _, err := c.Stop(ctx, request) if err != nil { - log.Fatal(fmt.Errorf("failed to stop process %s: %w", j.id, err)) + return fmt.Errorf("failed to stop process %s: %w", j.id, err) } log.Println("Successfully stopped process: ", j.id) return nil From 8aaad7a56e31ee726e1701ef58050c1cf7587c95 Mon Sep 17 00:00:00 2001 From: Jacob Barzee Date: Fri, 30 Apr 2021 13:27:16 -0600 Subject: [PATCH 15/15] Remaining fixes to Pull request --- cmd/client/main.go | 2 +- cmd/client/query.go | 11 ++++--- core.go | 2 +- grpc/bitbox.pb.go | 57 ++++++++++++++++++++++++++++++----- grpc/bitbox.proto | 9 ++++-- grpc/generate.go | 4 --- proc/proc.go | 73 +++++++++++++++++++++++++++++++-------------- server.go | 22 ++++++++++++-- 8 files changed, 136 insertions(+), 44 deletions(-) delete mode 100644 grpc/generate.go diff --git a/cmd/client/main.go b/cmd/client/main.go index c64e50b..4eadae7 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -23,7 +23,7 @@ var defaultAddress = optionalEnvString("BIT_BOX_ADDR", func() string { }()) var root = &cobra.Command{ - Use: "bitboxc", + Use: "bitboxcli", Short: "A CLI tool for remote BitBox operations", Long: "Execute remote linux processes on a BitBox server", } diff --git a/cmd/client/query.go b/cmd/client/query.go index 4475463..46c7de8 100644 --- a/cmd/client/query.go +++ b/cmd/client/query.go @@ -55,13 +55,16 @@ func (j jobQuery) execute(ctx context.Context, c bbgrpc.BitBoxClient) error { reply, err := queryClient.Recv() if err == io.EOF { log.Println("") - break } if err != nil { return fmt.Errorf("failed to fetch reply: %w", err) } - log.Print(reply.GetOutput()) + switch output := reply.GetOutput().(type) { + case *bbgrpc.QueryReply_Stdouterr: + log.Println(output.Stdouterr) + case *bbgrpc.QueryReply_ExitCode: + log.Printf("Process %v exited with code %v", j.id, output.ExitCode) + return nil + } } - - return nil } diff --git a/core.go b/core.go index 589ed72..9a161e8 100644 --- a/core.go +++ b/core.go @@ -64,7 +64,7 @@ func (c *Core) Status(id uuid.UUID) (proc.ProcStatus, error) { } // Query streams the output/result of a process. -func (c *Core) Query(ctx context.Context, id uuid.UUID) (<-chan string, error) { +func (c *Core) Query(ctx context.Context, id uuid.UUID) (<-chan proc.ProcOutput, error) { var p *proc.Proc var err error diff --git a/grpc/bitbox.pb.go b/grpc/bitbox.pb.go index cb3af8a..81fb176 100644 --- a/grpc/bitbox.pb.go +++ b/grpc/bitbox.pb.go @@ -422,8 +422,12 @@ type QueryReply struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Output is the output of the process (includes exit code) - Output string `protobuf:"bytes,1,opt,name=Output,proto3" json:"Output,omitempty"` + // Output is one of the forms of output that a process may utilize. + // + // Types that are assignable to Output: + // *QueryReply_Stdouterr + // *QueryReply_ExitCode + Output isQueryReply_Output `protobuf_oneof:"Output"` } func (x *QueryReply) Reset() { @@ -458,13 +462,45 @@ func (*QueryReply) Descriptor() ([]byte, []int) { return file_bitbox_proto_rawDescGZIP(), []int{7} } -func (x *QueryReply) GetOutput() string { - if x != nil { - return x.Output +func (m *QueryReply) GetOutput() isQueryReply_Output { + if m != nil { + return m.Output + } + return nil +} + +func (x *QueryReply) GetStdouterr() string { + if x, ok := x.GetOutput().(*QueryReply_Stdouterr); ok { + return x.Stdouterr } return "" } +func (x *QueryReply) GetExitCode() uint32 { + if x, ok := x.GetOutput().(*QueryReply_ExitCode); ok { + return x.ExitCode + } + return 0 +} + +type isQueryReply_Output interface { + isQueryReply_Output() +} + +type QueryReply_Stdouterr struct { + // Stdouterr is any output from the process which was written to Stdouterr. + Stdouterr string `protobuf:"bytes,1,opt,name=Stdouterr,proto3,oneof"` +} + +type QueryReply_ExitCode struct { + // ExitCode is the code the process exited with. + ExitCode uint32 `protobuf:"varint,3,opt,name=ExitCode,proto3,oneof"` // Leaving as 3 to allow for seperation of Stdout & Stderr at some point +} + +func (*QueryReply_Stdouterr) isQueryReply_Output() {} + +func (*QueryReply_ExitCode) isQueryReply_Output() {} + var File_bitbox_proto protoreflect.FileDescriptor var file_bitbox_proto_rawDesc = []byte{ @@ -490,8 +526,11 @@ var file_bitbox_proto_rawDesc = []byte{ 0x64, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x74, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x10, 0x02, 0x22, 0x1e, 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x49, 0x44, - 0x22, 0x24, 0x0a, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x16, - 0x0a, 0x06, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x22, 0x54, 0x0a, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1e, + 0x0a, 0x09, 0x53, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x00, 0x52, 0x09, 0x53, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x12, 0x1c, + 0x0a, 0x08, 0x45, 0x78, 0x69, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, + 0x48, 0x00, 0x52, 0x08, 0x45, 0x78, 0x69, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x32, 0xce, 0x01, 0x0a, 0x06, 0x42, 0x69, 0x74, 0x42, 0x6f, 0x78, 0x12, 0x2f, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, @@ -656,6 +695,10 @@ func file_bitbox_proto_init() { } } } + file_bitbox_proto_msgTypes[7].OneofWrappers = []interface{}{ + (*QueryReply_Stdouterr)(nil), + (*QueryReply_ExitCode)(nil), + } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ diff --git a/grpc/bitbox.proto b/grpc/bitbox.proto index 78d792d..8788a12 100644 --- a/grpc/bitbox.proto +++ b/grpc/bitbox.proto @@ -84,6 +84,11 @@ message QueryRequest { // QueryReply holds output of the process queried. message QueryReply { - // Output is the output of the process (includes exit code) - string Output = 1; + // Output is one of the forms of output that a process may utilize. + oneof Output { + // Stdouterr is any output from the process which was written to Stdouterr. + string Stdouterr = 1; + // ExitCode is the code the process exited with. + uint32 ExitCode = 3; // Leaving as 3 to allow for seperation of Stdout & Stderr at some point + } } \ No newline at end of file diff --git a/grpc/generate.go b/grpc/generate.go deleted file mode 100644 index e9dea9d..0000000 --- a/grpc/generate.go +++ /dev/null @@ -1,4 +0,0 @@ -package grpc - -// This file is exclusively used for hooking gRPC code generation into go -//go:generate protoc --proto_path=. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative bitbox.proto diff --git a/proc/proc.go b/proc/proc.go index e03799d..98886f7 100644 --- a/proc/proc.go +++ b/proc/proc.go @@ -1,15 +1,9 @@ -// proc offers control over arbitrary processes. -// proc depends heavily on os/exec. -// If/when proc needs to do resource control & isolation -// its probable that os/exec will need to be replaced with -// either the os package itself or syscall. package proc // Fingers crossed that its easier than rewriting os.ForkExec import ( "context" - "fmt" "io/ioutil" "os" "os/exec" @@ -21,6 +15,11 @@ const outputReadRefreshInterval = time.Millisecond * 10 // Proc is a BitBox process. // Stderr and Stdout are dumped to temp files on disk. +// Proc offers control over arbitrary processes. +// Proc depends heavily on os/exec. +// If/when proc needs to do resource control & isolation +// its probable that os/exec will need to be replaced with +// either the os package itself or syscall. type Proc struct { outputFileName string waitMutex sync.Mutex // See https://github.com/golang/go/issues/28461 @@ -112,7 +111,8 @@ func (ps ProcStatus) String() string { // After the read routines finish the third routine sends // the ExitCode and closes the channel. // Note: this function's structure could probably be cleaned up. -func (p *Proc) Query(ctx context.Context) (<-chan string, error) { +// After the read routines finish the third routine sends the ExitCode and closes the channel. +func (p *Proc) Query(ctx context.Context) (<-chan ProcOutput, error) { flags := os.O_RDONLY | os.O_SYNC outputFile, err := os.OpenFile(p.outputFileName, flags, 0600) if err != nil { @@ -120,15 +120,15 @@ func (p *Proc) Query(ctx context.Context) (<-chan string, error) { } pollContext, cancelPoll := context.WithCancel(ctx) - stream := make(chan string) + stream := make(chan ProcOutput) wg := &sync.WaitGroup{} wg.Add(1) go func() { - unstreamedBytes := pollRead(pollContext, outputFile, stream) + unstreamedOutput := pollRead(pollContext, outputFile, stream) select { case <-ctx.Done(): - case stream <- string(unstreamedBytes): + case stream <- unstreamedOutput: finishRead(ctx, outputFile, stream) } outputFile.Close() @@ -145,8 +145,9 @@ func (p *Proc) Query(ctx context.Context) (<-chan string, error) { cancelPoll() wg.Wait() - exitCodeMsg := fmt.Sprintf("Exited with code %v", uint32(p.cmd.ProcessState.ExitCode())) - stream <- exitCodeMsg + stream <- &ProcOutput_ExitCode{ + ExitCode: uint32(p.cmd.ProcessState.ExitCode()), + } close(stream) }() @@ -156,8 +157,8 @@ func (p *Proc) Query(ctx context.Context) (<-chan string, error) { func pollRead( ctx context.Context, file *os.File, - stream chan<- string, -) []byte { + stream chan<- ProcOutput, +) ProcOutput { buf := make([]byte, 1024) ticker := time.NewTicker(outputReadRefreshInterval) @@ -166,6 +167,7 @@ func pollRead( case <-ctx.Done(): return nil case <-ticker.C: + // ReadLoop for { n, err := file.Read(buf) if err != nil { @@ -175,13 +177,11 @@ func pollRead( if n == 0 { break // move to wait for ticker or context to end } - var copiedBytes []byte - copy(copiedBytes, buf) select { - case stream <- string(copiedBytes): + case stream <- newProcOutput_Stdouterr(buf): //Do nothing case <-ctx.Done(): - return copiedBytes + return newProcOutput_Stdouterr(buf) } } } @@ -191,7 +191,7 @@ func pollRead( func finishRead( ctx context.Context, file *os.File, - stream chan<- string, + stream chan<- ProcOutput, ) { buf := make([]byte, 1024) @@ -204,13 +204,42 @@ func finishRead( if n == 0 { break } - var copiedBytes []byte - copy(copiedBytes, buf) select { case <-ctx.Done(): return - case stream <- string(copiedBytes): + case stream <- newProcOutput_Stdouterr(buf): //Do nothing } } } + +// ProcOutput is any output from a process. +type ProcOutput interface { + isProcOutput() +} + +var _ ProcOutput = (*ProcOutput_Stdouterr)(nil) + +// ProcOutput_Stdouterr is any output from the process which was written to Stdout and Stderr. +type ProcOutput_Stdouterr struct { + // Stdout is a series of characters sent to Stdout by a process. + Output string +} + +func newProcOutput_Stdouterr(b []byte) ProcOutput { + return &ProcOutput_Stdouterr{ + Output: (string)(b), + } +} + +func (*ProcOutput_Stdouterr) isProcOutput() {} + +var _ ProcOutput = (*ProcOutput_ExitCode)(nil) + +// ProcOutput_ExitCode is any output from the process which was written to Stderr. +type ProcOutput_ExitCode struct { + // ExitCode is the exit code of a process. + ExitCode uint32 +} + +func (*ProcOutput_ExitCode) isProcOutput() {} diff --git a/server.go b/server.go index c4ab50d..4ef8305 100644 --- a/server.go +++ b/server.go @@ -1,5 +1,7 @@ package bitbox +//go:generate protoc --proto_path=. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative bitbox.proto + import ( "context" "fmt" @@ -98,7 +100,6 @@ func (s *Server) Query(request *grpc.QueryRequest, queryServer grpc.BitBox_Query } log.Println("[Query] ", uuid.String()) - // TODO: pass context from queryServer to Query stream, err := s.c.Query(queryServer.Context(), uuid) if err != nil { @@ -106,8 +107,23 @@ func (s *Server) Query(request *grpc.QueryRequest, queryServer grpc.BitBox_Query } for output := range stream { - reply := &grpc.QueryReply{ - Output: output, + // You should ask yourself: why do we initialize reply the same way twice? + // The answer: because QueryReply.Output is of type grpc.isQueryReply_Output + // which is not public. + var reply *grpc.QueryReply + switch output := output.(type) { + case *proc.ProcOutput_Stdouterr: + reply = &grpc.QueryReply{ + Output: &grpc.QueryReply_Stdouterr{ + Stdouterr: output.Output, + }, + } + case *proc.ProcOutput_ExitCode: + reply = &grpc.QueryReply{ + Output: &grpc.QueryReply_ExitCode{ + ExitCode: output.ExitCode, + }, + } } err := queryServer.Send(reply) if err != nil {