mirror of
https://github.com/garethgeorge/backrest.git
synced 2026-08-27 19:36:29 +00:00
feat: track long running generic commands in the oplog (#516)
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.32.0
|
||||
// protoc v5.27.2
|
||||
// protoc (unknown)
|
||||
// source: v1/config.proto
|
||||
|
||||
package v1
|
||||
|
||||
+233
-138
@@ -218,6 +218,7 @@ type Operation struct {
|
||||
// *Operation_OperationStats
|
||||
// *Operation_OperationRunHook
|
||||
// *Operation_OperationCheck
|
||||
// *Operation_OperationRunCommand
|
||||
Op isOperation_Op `protobuf_oneof:"op"`
|
||||
}
|
||||
|
||||
@@ -393,6 +394,13 @@ func (x *Operation) GetOperationCheck() *OperationCheck {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Operation) GetOperationRunCommand() *OperationRunCommand {
|
||||
if x, ok := x.GetOp().(*Operation_OperationRunCommand); ok {
|
||||
return x.OperationRunCommand
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type isOperation_Op interface {
|
||||
isOperation_Op()
|
||||
}
|
||||
@@ -429,6 +437,10 @@ type Operation_OperationCheck struct {
|
||||
OperationCheck *OperationCheck `protobuf:"bytes,107,opt,name=operation_check,json=operationCheck,proto3,oneof"`
|
||||
}
|
||||
|
||||
type Operation_OperationRunCommand struct {
|
||||
OperationRunCommand *OperationRunCommand `protobuf:"bytes,108,opt,name=operation_run_command,json=operationRunCommand,proto3,oneof"`
|
||||
}
|
||||
|
||||
func (*Operation_OperationBackup) isOperation_Op() {}
|
||||
|
||||
func (*Operation_OperationIndexSnapshot) isOperation_Op() {}
|
||||
@@ -445,6 +457,8 @@ func (*Operation_OperationRunHook) isOperation_Op() {}
|
||||
|
||||
func (*Operation_OperationCheck) isOperation_Op() {}
|
||||
|
||||
func (*Operation_OperationRunCommand) isOperation_Op() {}
|
||||
|
||||
// OperationEvent is used in the wireformat to stream operation changes to clients
|
||||
type OperationEvent struct {
|
||||
state protoimpl.MessageState
|
||||
@@ -838,6 +852,62 @@ func (x *OperationCheck) GetOutputLogref() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// OperationRunCommand tracks a long running command. Commands are grouped into a flow ID for each session.
|
||||
type OperationRunCommand struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Command string `protobuf:"bytes,1,opt,name=command,proto3" json:"command,omitempty"`
|
||||
OutputLogref string `protobuf:"bytes,2,opt,name=output_logref,json=outputLogref,proto3" json:"output_logref,omitempty"`
|
||||
}
|
||||
|
||||
func (x *OperationRunCommand) Reset() {
|
||||
*x = OperationRunCommand{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_v1_operations_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *OperationRunCommand) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*OperationRunCommand) ProtoMessage() {}
|
||||
|
||||
func (x *OperationRunCommand) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_v1_operations_proto_msgTypes[8]
|
||||
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 OperationRunCommand.ProtoReflect.Descriptor instead.
|
||||
func (*OperationRunCommand) Descriptor() ([]byte, []int) {
|
||||
return file_v1_operations_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
func (x *OperationRunCommand) GetCommand() string {
|
||||
if x != nil {
|
||||
return x.Command
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *OperationRunCommand) GetOutputLogref() string {
|
||||
if x != nil {
|
||||
return x.OutputLogref
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// OperationRestore tracks a restore operation.
|
||||
type OperationRestore struct {
|
||||
state protoimpl.MessageState
|
||||
@@ -852,7 +922,7 @@ type OperationRestore struct {
|
||||
func (x *OperationRestore) Reset() {
|
||||
*x = OperationRestore{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_v1_operations_proto_msgTypes[8]
|
||||
mi := &file_v1_operations_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -865,7 +935,7 @@ func (x *OperationRestore) String() string {
|
||||
func (*OperationRestore) ProtoMessage() {}
|
||||
|
||||
func (x *OperationRestore) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_v1_operations_proto_msgTypes[8]
|
||||
mi := &file_v1_operations_proto_msgTypes[9]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -878,7 +948,7 @@ func (x *OperationRestore) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use OperationRestore.ProtoReflect.Descriptor instead.
|
||||
func (*OperationRestore) Descriptor() ([]byte, []int) {
|
||||
return file_v1_operations_proto_rawDescGZIP(), []int{8}
|
||||
return file_v1_operations_proto_rawDescGZIP(), []int{9}
|
||||
}
|
||||
|
||||
func (x *OperationRestore) GetPath() string {
|
||||
@@ -914,7 +984,7 @@ type OperationStats struct {
|
||||
func (x *OperationStats) Reset() {
|
||||
*x = OperationStats{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_v1_operations_proto_msgTypes[9]
|
||||
mi := &file_v1_operations_proto_msgTypes[10]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -927,7 +997,7 @@ func (x *OperationStats) String() string {
|
||||
func (*OperationStats) ProtoMessage() {}
|
||||
|
||||
func (x *OperationStats) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_v1_operations_proto_msgTypes[9]
|
||||
mi := &file_v1_operations_proto_msgTypes[10]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -940,7 +1010,7 @@ func (x *OperationStats) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use OperationStats.ProtoReflect.Descriptor instead.
|
||||
func (*OperationStats) Descriptor() ([]byte, []int) {
|
||||
return file_v1_operations_proto_rawDescGZIP(), []int{9}
|
||||
return file_v1_operations_proto_rawDescGZIP(), []int{10}
|
||||
}
|
||||
|
||||
func (x *OperationStats) GetStats() *RepoStats {
|
||||
@@ -965,7 +1035,7 @@ type OperationRunHook struct {
|
||||
func (x *OperationRunHook) Reset() {
|
||||
*x = OperationRunHook{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_v1_operations_proto_msgTypes[10]
|
||||
mi := &file_v1_operations_proto_msgTypes[11]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -978,7 +1048,7 @@ func (x *OperationRunHook) String() string {
|
||||
func (*OperationRunHook) ProtoMessage() {}
|
||||
|
||||
func (x *OperationRunHook) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_v1_operations_proto_msgTypes[10]
|
||||
mi := &file_v1_operations_proto_msgTypes[11]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -991,7 +1061,7 @@ func (x *OperationRunHook) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use OperationRunHook.ProtoReflect.Descriptor instead.
|
||||
func (*OperationRunHook) Descriptor() ([]byte, []int) {
|
||||
return file_v1_operations_proto_rawDescGZIP(), []int{10}
|
||||
return file_v1_operations_proto_rawDescGZIP(), []int{11}
|
||||
}
|
||||
|
||||
func (x *OperationRunHook) GetParentOp() int64 {
|
||||
@@ -1033,7 +1103,7 @@ var file_v1_operations_proto_rawDesc = []byte{
|
||||
0x0a, 0x0d, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x12,
|
||||
0x2d, 0x0a, 0x0a, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20,
|
||||
0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x52, 0x0a, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x96,
|
||||
0x6f, 0x6e, 0x52, 0x0a, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xe5,
|
||||
0x07, 0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02,
|
||||
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x17, 0x0a, 0x07,
|
||||
0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x66,
|
||||
@@ -1091,98 +1161,108 @@ var file_v1_operations_proto_rawDesc = []byte{
|
||||
0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x6b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x48,
|
||||
0x00, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x65, 0x63,
|
||||
0x6b, 0x42, 0x04, 0x0a, 0x02, 0x6f, 0x70, 0x22, 0x93, 0x02, 0x0a, 0x0e, 0x4f, 0x70, 0x65, 0x72,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2d, 0x0a, 0x0a, 0x6b, 0x65,
|
||||
0x65, 0x70, 0x5f, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c,
|
||||
0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x48, 0x00, 0x52, 0x09,
|
||||
0x6b, 0x65, 0x65, 0x70, 0x41, 0x6c, 0x69, 0x76, 0x65, 0x12, 0x42, 0x0a, 0x12, 0x63, 0x72, 0x65,
|
||||
0x61, 0x74, 0x65, 0x64, 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x11, 0x63, 0x72, 0x65, 0x61,
|
||||
0x74, 0x65, 0x64, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x42, 0x0a,
|
||||
0x12, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x76, 0x31, 0x2e, 0x4f,
|
||||
0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x11,
|
||||
0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x73, 0x12, 0x41, 0x0a, 0x12, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x5f, 0x6f, 0x70, 0x65,
|
||||
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e,
|
||||
0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x4c, 0x69, 0x73, 0x74, 0x48,
|
||||
0x00, 0x52, 0x11, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x73, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x7c, 0x0a,
|
||||
0x0f, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70,
|
||||
0x12, 0x38, 0x0a, 0x0b, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18,
|
||||
0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75,
|
||||
0x70, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a,
|
||||
0x6c, 0x61, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2f, 0x0a, 0x06, 0x65, 0x72,
|
||||
0x72, 0x6f, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x45, 0x72,
|
||||
0x72, 0x6f, 0x72, 0x52, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x22, 0x60, 0x0a, 0x16, 0x4f,
|
||||
0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x6e, 0x61,
|
||||
0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x2e, 0x0a, 0x08, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f,
|
||||
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73,
|
||||
0x74, 0x69, 0x63, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x08, 0x73, 0x6e, 0x61,
|
||||
0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x67, 0x6f, 0x74, 0x18,
|
||||
0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x67, 0x6f, 0x74, 0x22, 0x6a, 0x0a,
|
||||
0x0f, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x6f, 0x72, 0x67, 0x65, 0x74,
|
||||
0x12, 0x2a, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x69, 0x63, 0x53, 0x6e, 0x61, 0x70,
|
||||
0x73, 0x68, 0x6f, 0x74, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x67, 0x65, 0x74, 0x12, 0x2b, 0x0a, 0x06,
|
||||
0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x52, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63,
|
||||
0x79, 0x52, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x51, 0x0a, 0x0e, 0x4f, 0x70, 0x65,
|
||||
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x75, 0x6e, 0x65, 0x12, 0x1a, 0x0a, 0x06, 0x6f,
|
||||
0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52,
|
||||
0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x6f, 0x75, 0x74, 0x70, 0x75,
|
||||
0x74, 0x5f, 0x6c, 0x6f, 0x67, 0x72, 0x65, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c,
|
||||
0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4c, 0x6f, 0x67, 0x72, 0x65, 0x66, 0x22, 0x51, 0x0a, 0x0e,
|
||||
0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x1a,
|
||||
0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02,
|
||||
0x18, 0x01, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x6f, 0x75,
|
||||
0x74, 0x70, 0x75, 0x74, 0x5f, 0x6c, 0x6f, 0x67, 0x72, 0x65, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x0c, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4c, 0x6f, 0x67, 0x72, 0x65, 0x66, 0x22,
|
||||
0x79, 0x0a, 0x10, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x74,
|
||||
0x6f, 0x72, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65,
|
||||
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12,
|
||||
0x39, 0x0a, 0x0b, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72,
|
||||
0x65, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a,
|
||||
0x6c, 0x61, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x35, 0x0a, 0x0e, 0x4f, 0x70,
|
||||
0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x23, 0x0a, 0x05,
|
||||
0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x52, 0x65, 0x70, 0x6f, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74,
|
||||
0x73, 0x22, 0x9a, 0x01, 0x0a, 0x10, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52,
|
||||
0x75, 0x6e, 0x48, 0x6f, 0x6f, 0x6b, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74,
|
||||
0x5f, 0x6f, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x70, 0x61, 0x72, 0x65, 0x6e,
|
||||
0x74, 0x4f, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x6f, 0x75, 0x74, 0x70, 0x75,
|
||||
0x74, 0x5f, 0x6c, 0x6f, 0x67, 0x72, 0x65, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c,
|
||||
0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4c, 0x6f, 0x67, 0x72, 0x65, 0x66, 0x12, 0x30, 0x0a, 0x09,
|
||||
0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32,
|
||||
0x12, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2a, 0x60,
|
||||
0x0a, 0x12, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74,
|
||||
0x54, 0x79, 0x70, 0x65, 0x12, 0x11, 0x0a, 0x0d, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x55, 0x4e,
|
||||
0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x45, 0x56, 0x45, 0x4e, 0x54,
|
||||
0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x45, 0x56,
|
||||
0x45, 0x4e, 0x54, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x11, 0x0a,
|
||||
0x0d, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x03,
|
||||
0x2a, 0xc2, 0x01, 0x0a, 0x0f, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74,
|
||||
0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55,
|
||||
0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x54, 0x41, 0x54,
|
||||
0x55, 0x53, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11,
|
||||
0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x49, 0x4e, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53,
|
||||
0x53, 0x10, 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x53, 0x55,
|
||||
0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x03, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x54, 0x41, 0x54, 0x55,
|
||||
0x53, 0x5f, 0x57, 0x41, 0x52, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x07, 0x12, 0x10, 0x0a, 0x0c, 0x53,
|
||||
0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x04, 0x12, 0x1b, 0x0a,
|
||||
0x17, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x53, 0x59, 0x53, 0x54, 0x45, 0x4d, 0x5f, 0x43,
|
||||
0x41, 0x4e, 0x43, 0x45, 0x4c, 0x4c, 0x45, 0x44, 0x10, 0x05, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x54,
|
||||
0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c,
|
||||
0x4c, 0x45, 0x44, 0x10, 0x06, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x72, 0x65, 0x74, 0x68, 0x67, 0x65, 0x6f, 0x72, 0x67, 0x65,
|
||||
0x2f, 0x62, 0x61, 0x63, 0x6b, 0x72, 0x65, 0x73, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f,
|
||||
0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x6b, 0x12, 0x4d, 0x0a, 0x15, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72,
|
||||
0x75, 0x6e, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x6c, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52,
|
||||
0x75, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x48, 0x00, 0x52, 0x13, 0x6f, 0x70, 0x65,
|
||||
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
||||
0x42, 0x04, 0x0a, 0x02, 0x6f, 0x70, 0x22, 0x93, 0x02, 0x0a, 0x0e, 0x4f, 0x70, 0x65, 0x72, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2d, 0x0a, 0x0a, 0x6b, 0x65, 0x65,
|
||||
0x70, 0x5f, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e,
|
||||
0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x48, 0x00, 0x52, 0x09, 0x6b,
|
||||
0x65, 0x65, 0x70, 0x41, 0x6c, 0x69, 0x76, 0x65, 0x12, 0x42, 0x0a, 0x12, 0x63, 0x72, 0x65, 0x61,
|
||||
0x74, 0x65, 0x64, 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x11, 0x63, 0x72, 0x65, 0x61, 0x74,
|
||||
0x65, 0x64, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x42, 0x0a, 0x12,
|
||||
0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70,
|
||||
0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x11, 0x75,
|
||||
0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
|
||||
0x12, 0x41, 0x0a, 0x12, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x5f, 0x6f, 0x70, 0x65, 0x72,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74,
|
||||
0x79, 0x70, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00,
|
||||
0x52, 0x11, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x73, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x7c, 0x0a, 0x0f,
|
||||
0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12,
|
||||
0x38, 0x0a, 0x0b, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70,
|
||||
0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6c,
|
||||
0x61, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2f, 0x0a, 0x06, 0x65, 0x72, 0x72,
|
||||
0x6f, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x42,
|
||||
0x61, 0x63, 0x6b, 0x75, 0x70, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x45, 0x72, 0x72,
|
||||
0x6f, 0x72, 0x52, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x22, 0x60, 0x0a, 0x16, 0x4f, 0x70,
|
||||
0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x6e, 0x61, 0x70,
|
||||
0x73, 0x68, 0x6f, 0x74, 0x12, 0x2e, 0x0a, 0x08, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x74,
|
||||
0x69, 0x63, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x08, 0x73, 0x6e, 0x61, 0x70,
|
||||
0x73, 0x68, 0x6f, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x67, 0x6f, 0x74, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x67, 0x6f, 0x74, 0x22, 0x6a, 0x0a, 0x0f,
|
||||
0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x6f, 0x72, 0x67, 0x65, 0x74, 0x12,
|
||||
0x2a, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||
0x12, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x69, 0x63, 0x53, 0x6e, 0x61, 0x70, 0x73,
|
||||
0x68, 0x6f, 0x74, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x67, 0x65, 0x74, 0x12, 0x2b, 0x0a, 0x06, 0x70,
|
||||
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x52, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79,
|
||||
0x52, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x51, 0x0a, 0x0e, 0x4f, 0x70, 0x65, 0x72,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x75, 0x6e, 0x65, 0x12, 0x1a, 0x0a, 0x06, 0x6f, 0x75,
|
||||
0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x06,
|
||||
0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74,
|
||||
0x5f, 0x6c, 0x6f, 0x67, 0x72, 0x65, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6f,
|
||||
0x75, 0x74, 0x70, 0x75, 0x74, 0x4c, 0x6f, 0x67, 0x72, 0x65, 0x66, 0x22, 0x51, 0x0a, 0x0e, 0x4f,
|
||||
0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x1a, 0x0a,
|
||||
0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18,
|
||||
0x01, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x6f, 0x75, 0x74,
|
||||
0x70, 0x75, 0x74, 0x5f, 0x6c, 0x6f, 0x67, 0x72, 0x65, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x0c, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4c, 0x6f, 0x67, 0x72, 0x65, 0x66, 0x22, 0x54,
|
||||
0x0a, 0x13, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6e, 0x43, 0x6f,
|
||||
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12,
|
||||
0x23, 0x0a, 0x0d, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x6c, 0x6f, 0x67, 0x72, 0x65, 0x66,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4c, 0x6f,
|
||||
0x67, 0x72, 0x65, 0x66, 0x22, 0x79, 0x0a, 0x10, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06,
|
||||
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61,
|
||||
0x72, 0x67, 0x65, 0x74, 0x12, 0x39, 0x0a, 0x0b, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x74, 0x61,
|
||||
0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x76, 0x31, 0x2e, 0x52,
|
||||
0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x45, 0x6e,
|
||||
0x74, 0x72, 0x79, 0x52, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22,
|
||||
0x35, 0x0a, 0x0e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74,
|
||||
0x73, 0x12, 0x23, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x0d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52,
|
||||
0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x22, 0x9a, 0x01, 0x0a, 0x10, 0x4f, 0x70, 0x65, 0x72, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6e, 0x48, 0x6f, 0x6f, 0x6b, 0x12, 0x1b, 0x0a, 0x09, 0x70,
|
||||
0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x6f, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08,
|
||||
0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x4f, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d,
|
||||
0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x6c, 0x6f, 0x67, 0x72, 0x65, 0x66, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x0c, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4c, 0x6f, 0x67, 0x72, 0x65,
|
||||
0x66, 0x12, 0x30, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x2e, 0x43,
|
||||
0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x2a, 0x60, 0x0a, 0x12, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x11, 0x0a, 0x0d, 0x45, 0x56, 0x45,
|
||||
0x4e, 0x54, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d,
|
||||
0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12,
|
||||
0x11, 0x0a, 0x0d, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x44,
|
||||
0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x44, 0x45, 0x4c, 0x45,
|
||||
0x54, 0x45, 0x44, 0x10, 0x03, 0x2a, 0xc2, 0x01, 0x0a, 0x0f, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x54, 0x41,
|
||||
0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x12, 0x0a,
|
||||
0x0e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10,
|
||||
0x01, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x49, 0x4e, 0x50, 0x52,
|
||||
0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x54, 0x41, 0x54,
|
||||
0x55, 0x53, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x03, 0x12, 0x12, 0x0a, 0x0e,
|
||||
0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x57, 0x41, 0x52, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x07,
|
||||
0x12, 0x10, 0x0a, 0x0c, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52,
|
||||
0x10, 0x04, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x53, 0x59, 0x53,
|
||||
0x54, 0x45, 0x4d, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x4c, 0x45, 0x44, 0x10, 0x05, 0x12,
|
||||
0x19, 0x0a, 0x15, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x43,
|
||||
0x41, 0x4e, 0x43, 0x45, 0x4c, 0x4c, 0x45, 0x44, 0x10, 0x06, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69,
|
||||
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x72, 0x65, 0x74, 0x68, 0x67,
|
||||
0x65, 0x6f, 0x72, 0x67, 0x65, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x72, 0x65, 0x73, 0x74, 0x2f, 0x67,
|
||||
0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -1198,7 +1278,7 @@ func file_v1_operations_proto_rawDescGZIP() []byte {
|
||||
}
|
||||
|
||||
var file_v1_operations_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
||||
var file_v1_operations_proto_msgTypes = make([]protoimpl.MessageInfo, 11)
|
||||
var file_v1_operations_proto_msgTypes = make([]protoimpl.MessageInfo, 12)
|
||||
var file_v1_operations_proto_goTypes = []interface{}{
|
||||
(OperationEventType)(0), // 0: v1.OperationEventType
|
||||
(OperationStatus)(0), // 1: v1.OperationStatus
|
||||
@@ -1210,18 +1290,19 @@ var file_v1_operations_proto_goTypes = []interface{}{
|
||||
(*OperationForget)(nil), // 7: v1.OperationForget
|
||||
(*OperationPrune)(nil), // 8: v1.OperationPrune
|
||||
(*OperationCheck)(nil), // 9: v1.OperationCheck
|
||||
(*OperationRestore)(nil), // 10: v1.OperationRestore
|
||||
(*OperationStats)(nil), // 11: v1.OperationStats
|
||||
(*OperationRunHook)(nil), // 12: v1.OperationRunHook
|
||||
(*types.Empty)(nil), // 13: types.Empty
|
||||
(*types.Int64List)(nil), // 14: types.Int64List
|
||||
(*BackupProgressEntry)(nil), // 15: v1.BackupProgressEntry
|
||||
(*BackupProgressError)(nil), // 16: v1.BackupProgressError
|
||||
(*ResticSnapshot)(nil), // 17: v1.ResticSnapshot
|
||||
(*RetentionPolicy)(nil), // 18: v1.RetentionPolicy
|
||||
(*RestoreProgressEntry)(nil), // 19: v1.RestoreProgressEntry
|
||||
(*RepoStats)(nil), // 20: v1.RepoStats
|
||||
(Hook_Condition)(0), // 21: v1.Hook.Condition
|
||||
(*OperationRunCommand)(nil), // 10: v1.OperationRunCommand
|
||||
(*OperationRestore)(nil), // 11: v1.OperationRestore
|
||||
(*OperationStats)(nil), // 12: v1.OperationStats
|
||||
(*OperationRunHook)(nil), // 13: v1.OperationRunHook
|
||||
(*types.Empty)(nil), // 14: types.Empty
|
||||
(*types.Int64List)(nil), // 15: types.Int64List
|
||||
(*BackupProgressEntry)(nil), // 16: v1.BackupProgressEntry
|
||||
(*BackupProgressError)(nil), // 17: v1.BackupProgressError
|
||||
(*ResticSnapshot)(nil), // 18: v1.ResticSnapshot
|
||||
(*RetentionPolicy)(nil), // 19: v1.RetentionPolicy
|
||||
(*RestoreProgressEntry)(nil), // 20: v1.RestoreProgressEntry
|
||||
(*RepoStats)(nil), // 21: v1.RepoStats
|
||||
(Hook_Condition)(0), // 22: v1.Hook.Condition
|
||||
}
|
||||
var file_v1_operations_proto_depIdxs = []int32{
|
||||
3, // 0: v1.OperationList.operations:type_name -> v1.Operation
|
||||
@@ -1230,27 +1311,28 @@ var file_v1_operations_proto_depIdxs = []int32{
|
||||
6, // 3: v1.Operation.operation_index_snapshot:type_name -> v1.OperationIndexSnapshot
|
||||
7, // 4: v1.Operation.operation_forget:type_name -> v1.OperationForget
|
||||
8, // 5: v1.Operation.operation_prune:type_name -> v1.OperationPrune
|
||||
10, // 6: v1.Operation.operation_restore:type_name -> v1.OperationRestore
|
||||
11, // 7: v1.Operation.operation_stats:type_name -> v1.OperationStats
|
||||
12, // 8: v1.Operation.operation_run_hook:type_name -> v1.OperationRunHook
|
||||
11, // 6: v1.Operation.operation_restore:type_name -> v1.OperationRestore
|
||||
12, // 7: v1.Operation.operation_stats:type_name -> v1.OperationStats
|
||||
13, // 8: v1.Operation.operation_run_hook:type_name -> v1.OperationRunHook
|
||||
9, // 9: v1.Operation.operation_check:type_name -> v1.OperationCheck
|
||||
13, // 10: v1.OperationEvent.keep_alive:type_name -> types.Empty
|
||||
2, // 11: v1.OperationEvent.created_operations:type_name -> v1.OperationList
|
||||
2, // 12: v1.OperationEvent.updated_operations:type_name -> v1.OperationList
|
||||
14, // 13: v1.OperationEvent.deleted_operations:type_name -> types.Int64List
|
||||
15, // 14: v1.OperationBackup.last_status:type_name -> v1.BackupProgressEntry
|
||||
16, // 15: v1.OperationBackup.errors:type_name -> v1.BackupProgressError
|
||||
17, // 16: v1.OperationIndexSnapshot.snapshot:type_name -> v1.ResticSnapshot
|
||||
17, // 17: v1.OperationForget.forget:type_name -> v1.ResticSnapshot
|
||||
18, // 18: v1.OperationForget.policy:type_name -> v1.RetentionPolicy
|
||||
19, // 19: v1.OperationRestore.last_status:type_name -> v1.RestoreProgressEntry
|
||||
20, // 20: v1.OperationStats.stats:type_name -> v1.RepoStats
|
||||
21, // 21: v1.OperationRunHook.condition:type_name -> v1.Hook.Condition
|
||||
22, // [22:22] is the sub-list for method output_type
|
||||
22, // [22:22] is the sub-list for method input_type
|
||||
22, // [22:22] is the sub-list for extension type_name
|
||||
22, // [22:22] is the sub-list for extension extendee
|
||||
0, // [0:22] is the sub-list for field type_name
|
||||
10, // 10: v1.Operation.operation_run_command:type_name -> v1.OperationRunCommand
|
||||
14, // 11: v1.OperationEvent.keep_alive:type_name -> types.Empty
|
||||
2, // 12: v1.OperationEvent.created_operations:type_name -> v1.OperationList
|
||||
2, // 13: v1.OperationEvent.updated_operations:type_name -> v1.OperationList
|
||||
15, // 14: v1.OperationEvent.deleted_operations:type_name -> types.Int64List
|
||||
16, // 15: v1.OperationBackup.last_status:type_name -> v1.BackupProgressEntry
|
||||
17, // 16: v1.OperationBackup.errors:type_name -> v1.BackupProgressError
|
||||
18, // 17: v1.OperationIndexSnapshot.snapshot:type_name -> v1.ResticSnapshot
|
||||
18, // 18: v1.OperationForget.forget:type_name -> v1.ResticSnapshot
|
||||
19, // 19: v1.OperationForget.policy:type_name -> v1.RetentionPolicy
|
||||
20, // 20: v1.OperationRestore.last_status:type_name -> v1.RestoreProgressEntry
|
||||
21, // 21: v1.OperationStats.stats:type_name -> v1.RepoStats
|
||||
22, // 22: v1.OperationRunHook.condition:type_name -> v1.Hook.Condition
|
||||
23, // [23:23] is the sub-list for method output_type
|
||||
23, // [23:23] is the sub-list for method input_type
|
||||
23, // [23:23] is the sub-list for extension type_name
|
||||
23, // [23:23] is the sub-list for extension extendee
|
||||
0, // [0:23] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_v1_operations_proto_init() }
|
||||
@@ -1358,7 +1440,7 @@ func file_v1_operations_proto_init() {
|
||||
}
|
||||
}
|
||||
file_v1_operations_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*OperationRestore); i {
|
||||
switch v := v.(*OperationRunCommand); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@@ -1370,7 +1452,7 @@ func file_v1_operations_proto_init() {
|
||||
}
|
||||
}
|
||||
file_v1_operations_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*OperationStats); i {
|
||||
switch v := v.(*OperationRestore); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@@ -1382,6 +1464,18 @@ func file_v1_operations_proto_init() {
|
||||
}
|
||||
}
|
||||
file_v1_operations_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*OperationStats); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_v1_operations_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*OperationRunHook); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
@@ -1403,6 +1497,7 @@ func file_v1_operations_proto_init() {
|
||||
(*Operation_OperationStats)(nil),
|
||||
(*Operation_OperationRunHook)(nil),
|
||||
(*Operation_OperationCheck)(nil),
|
||||
(*Operation_OperationRunCommand)(nil),
|
||||
}
|
||||
file_v1_operations_proto_msgTypes[2].OneofWrappers = []interface{}{
|
||||
(*OperationEvent_KeepAlive)(nil),
|
||||
@@ -1416,7 +1511,7 @@ func file_v1_operations_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_v1_operations_proto_rawDesc,
|
||||
NumEnums: 2,
|
||||
NumMessages: 11,
|
||||
NumMessages: 12,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
||||
+20
-20
@@ -961,7 +961,7 @@ var file_v1_service_proto_rawDesc = []byte{
|
||||
0x74, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x65, 0x70, 0x6f, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x70, 0x6f, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f,
|
||||
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d,
|
||||
0x6d, 0x61, 0x6e, 0x64, 0x32, 0xf9, 0x07, 0x0a, 0x08, 0x42, 0x61, 0x63, 0x6b, 0x72, 0x65, 0x73,
|
||||
0x6d, 0x61, 0x6e, 0x64, 0x32, 0xf7, 0x07, 0x0a, 0x08, 0x42, 0x61, 0x63, 0x6b, 0x72, 0x65, 0x73,
|
||||
0x74, 0x12, 0x31, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x16,
|
||||
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
|
||||
0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0a, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66,
|
||||
@@ -1009,26 +1009,26 @@ var file_v1_service_proto_rawDesc = []byte{
|
||||
0x79, 0x22, 0x00, 0x12, 0x34, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x12,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x11, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x73,
|
||||
0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x3a, 0x0a, 0x0a, 0x52, 0x75, 0x6e,
|
||||
0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x38, 0x0a, 0x0a, 0x52, 0x75, 0x6e,
|
||||
0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x15, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x75, 0x6e,
|
||||
0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11,
|
||||
0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75,
|
||||
0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x39, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x44, 0x6f, 0x77, 0x6e,
|
||||
0x6c, 0x6f, 0x61, 0x64, 0x55, 0x52, 0x4c, 0x12, 0x11, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e,
|
||||
0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x12, 0x2e, 0x74, 0x79, 0x70,
|
||||
0x65, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x00,
|
||||
0x12, 0x41, 0x0a, 0x0c, 0x43, 0x6c, 0x65, 0x61, 0x72, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79,
|
||||
0x12, 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x65, 0x61, 0x72, 0x48, 0x69, 0x73, 0x74, 0x6f,
|
||||
0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
|
||||
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74,
|
||||
0x79, 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x10, 0x50, 0x61, 0x74, 0x68, 0x41, 0x75, 0x74, 0x6f, 0x63,
|
||||
0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x12, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e,
|
||||
0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x11, 0x2e, 0x74, 0x79,
|
||||
0x70, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x00,
|
||||
0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67,
|
||||
0x61, 0x72, 0x65, 0x74, 0x68, 0x67, 0x65, 0x6f, 0x72, 0x67, 0x65, 0x2f, 0x62, 0x61, 0x63, 0x6b,
|
||||
0x72, 0x65, 0x73, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75,
|
||||
0x65, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f,
|
||||
0x61, 0x64, 0x55, 0x52, 0x4c, 0x12, 0x11, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x49, 0x6e,
|
||||
0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x12, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73,
|
||||
0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x00, 0x12, 0x41,
|
||||
0x0a, 0x0c, 0x43, 0x6c, 0x65, 0x61, 0x72, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x17,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x65, 0x61, 0x72, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22,
|
||||
0x00, 0x12, 0x3b, 0x0a, 0x10, 0x50, 0x61, 0x74, 0x68, 0x41, 0x75, 0x74, 0x6f, 0x63, 0x6f, 0x6d,
|
||||
0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x12, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x74,
|
||||
0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x11, 0x2e, 0x74, 0x79, 0x70, 0x65,
|
||||
0x73, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x00, 0x42, 0x2c,
|
||||
0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x72,
|
||||
0x65, 0x74, 0x68, 0x67, 0x65, 0x6f, 0x72, 0x67, 0x65, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x72, 0x65,
|
||||
0x73, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -1105,7 +1105,7 @@ var file_v1_service_proto_depIdxs = []int32{
|
||||
13, // 31: v1.Backrest.Restore:output_type -> google.protobuf.Empty
|
||||
13, // 32: v1.Backrest.Cancel:output_type -> google.protobuf.Empty
|
||||
21, // 33: v1.Backrest.GetLogs:output_type -> types.BytesValue
|
||||
21, // 34: v1.Backrest.RunCommand:output_type -> types.BytesValue
|
||||
17, // 34: v1.Backrest.RunCommand:output_type -> types.Int64Value
|
||||
16, // 35: v1.Backrest.GetDownloadURL:output_type -> types.StringValue
|
||||
13, // 36: v1.Backrest.ClearHistory:output_type -> google.protobuf.Empty
|
||||
22, // 37: v1.Backrest.PathAutocomplete:output_type -> types.StringList
|
||||
|
||||
@@ -64,7 +64,7 @@ type BackrestClient interface {
|
||||
// GetLogs returns the keyed large data for the given operation.
|
||||
GetLogs(ctx context.Context, in *LogDataRequest, opts ...grpc.CallOption) (Backrest_GetLogsClient, error)
|
||||
// RunCommand executes a generic restic command on the repository.
|
||||
RunCommand(ctx context.Context, in *RunCommandRequest, opts ...grpc.CallOption) (Backrest_RunCommandClient, error)
|
||||
RunCommand(ctx context.Context, in *RunCommandRequest, opts ...grpc.CallOption) (*types.Int64Value, error)
|
||||
// GetDownloadURL returns a signed download URL given a forget operation ID.
|
||||
GetDownloadURL(ctx context.Context, in *types.Int64Value, opts ...grpc.CallOption) (*types.StringValue, error)
|
||||
// Clears the history of operations
|
||||
@@ -244,36 +244,13 @@ func (x *backrestGetLogsClient) Recv() (*types.BytesValue, error) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *backrestClient) RunCommand(ctx context.Context, in *RunCommandRequest, opts ...grpc.CallOption) (Backrest_RunCommandClient, error) {
|
||||
stream, err := c.cc.NewStream(ctx, &Backrest_ServiceDesc.Streams[2], Backrest_RunCommand_FullMethodName, opts...)
|
||||
func (c *backrestClient) RunCommand(ctx context.Context, in *RunCommandRequest, opts ...grpc.CallOption) (*types.Int64Value, error) {
|
||||
out := new(types.Int64Value)
|
||||
err := c.cc.Invoke(ctx, Backrest_RunCommand_FullMethodName, in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &backrestRunCommandClient{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 Backrest_RunCommandClient interface {
|
||||
Recv() (*types.BytesValue, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
type backrestRunCommandClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *backrestRunCommandClient) Recv() (*types.BytesValue, error) {
|
||||
m := new(types.BytesValue)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *backrestClient) GetDownloadURL(ctx context.Context, in *types.Int64Value, opts ...grpc.CallOption) (*types.StringValue, error) {
|
||||
@@ -327,7 +304,7 @@ type BackrestServer interface {
|
||||
// GetLogs returns the keyed large data for the given operation.
|
||||
GetLogs(*LogDataRequest, Backrest_GetLogsServer) error
|
||||
// RunCommand executes a generic restic command on the repository.
|
||||
RunCommand(*RunCommandRequest, Backrest_RunCommandServer) error
|
||||
RunCommand(context.Context, *RunCommandRequest) (*types.Int64Value, error)
|
||||
// GetDownloadURL returns a signed download URL given a forget operation ID.
|
||||
GetDownloadURL(context.Context, *types.Int64Value) (*types.StringValue, error)
|
||||
// Clears the history of operations
|
||||
@@ -380,8 +357,8 @@ func (UnimplementedBackrestServer) Cancel(context.Context, *types.Int64Value) (*
|
||||
func (UnimplementedBackrestServer) GetLogs(*LogDataRequest, Backrest_GetLogsServer) error {
|
||||
return status.Errorf(codes.Unimplemented, "method GetLogs not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) RunCommand(*RunCommandRequest, Backrest_RunCommandServer) error {
|
||||
return status.Errorf(codes.Unimplemented, "method RunCommand not implemented")
|
||||
func (UnimplementedBackrestServer) RunCommand(context.Context, *RunCommandRequest) (*types.Int64Value, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RunCommand not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) GetDownloadURL(context.Context, *types.Int64Value) (*types.StringValue, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetDownloadURL not implemented")
|
||||
@@ -645,25 +622,22 @@ func (x *backrestGetLogsServer) Send(m *types.BytesValue) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func _Backrest_RunCommand_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
m := new(RunCommandRequest)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
func _Backrest_RunCommand_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(RunCommandRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return srv.(BackrestServer).RunCommand(m, &backrestRunCommandServer{stream})
|
||||
}
|
||||
|
||||
type Backrest_RunCommandServer interface {
|
||||
Send(*types.BytesValue) error
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type backrestRunCommandServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *backrestRunCommandServer) Send(m *types.BytesValue) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
if interceptor == nil {
|
||||
return srv.(BackrestServer).RunCommand(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Backrest_RunCommand_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BackrestServer).RunCommand(ctx, req.(*RunCommandRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Backrest_GetDownloadURL_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
@@ -771,6 +745,10 @@ var Backrest_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "Cancel",
|
||||
Handler: _Backrest_Cancel_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "RunCommand",
|
||||
Handler: _Backrest_RunCommand_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetDownloadURL",
|
||||
Handler: _Backrest_GetDownloadURL_Handler,
|
||||
@@ -795,11 +773,6 @@ var Backrest_ServiceDesc = grpc.ServiceDesc{
|
||||
Handler: _Backrest_GetLogs_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
{
|
||||
StreamName: "RunCommand",
|
||||
Handler: _Backrest_RunCommand_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "v1/service.proto",
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ type BackrestClient interface {
|
||||
// GetLogs returns the keyed large data for the given operation.
|
||||
GetLogs(context.Context, *connect.Request[v1.LogDataRequest]) (*connect.ServerStreamForClient[types.BytesValue], error)
|
||||
// RunCommand executes a generic restic command on the repository.
|
||||
RunCommand(context.Context, *connect.Request[v1.RunCommandRequest]) (*connect.ServerStreamForClient[types.BytesValue], error)
|
||||
RunCommand(context.Context, *connect.Request[v1.RunCommandRequest]) (*connect.Response[types.Int64Value], error)
|
||||
// GetDownloadURL returns a signed download URL given a forget operation ID.
|
||||
GetDownloadURL(context.Context, *connect.Request[types.Int64Value]) (*connect.Response[types.StringValue], error)
|
||||
// Clears the history of operations
|
||||
@@ -215,7 +215,7 @@ func NewBackrestClient(httpClient connect.HTTPClient, baseURL string, opts ...co
|
||||
connect.WithSchema(backrestGetLogsMethodDescriptor),
|
||||
connect.WithClientOptions(opts...),
|
||||
),
|
||||
runCommand: connect.NewClient[v1.RunCommandRequest, types.BytesValue](
|
||||
runCommand: connect.NewClient[v1.RunCommandRequest, types.Int64Value](
|
||||
httpClient,
|
||||
baseURL+BackrestRunCommandProcedure,
|
||||
connect.WithSchema(backrestRunCommandMethodDescriptor),
|
||||
@@ -257,7 +257,7 @@ type backrestClient struct {
|
||||
restore *connect.Client[v1.RestoreSnapshotRequest, emptypb.Empty]
|
||||
cancel *connect.Client[types.Int64Value, emptypb.Empty]
|
||||
getLogs *connect.Client[v1.LogDataRequest, types.BytesValue]
|
||||
runCommand *connect.Client[v1.RunCommandRequest, types.BytesValue]
|
||||
runCommand *connect.Client[v1.RunCommandRequest, types.Int64Value]
|
||||
getDownloadURL *connect.Client[types.Int64Value, types.StringValue]
|
||||
clearHistory *connect.Client[v1.ClearHistoryRequest, emptypb.Empty]
|
||||
pathAutocomplete *connect.Client[types.StringValue, types.StringList]
|
||||
@@ -329,8 +329,8 @@ func (c *backrestClient) GetLogs(ctx context.Context, req *connect.Request[v1.Lo
|
||||
}
|
||||
|
||||
// RunCommand calls v1.Backrest.RunCommand.
|
||||
func (c *backrestClient) RunCommand(ctx context.Context, req *connect.Request[v1.RunCommandRequest]) (*connect.ServerStreamForClient[types.BytesValue], error) {
|
||||
return c.runCommand.CallServerStream(ctx, req)
|
||||
func (c *backrestClient) RunCommand(ctx context.Context, req *connect.Request[v1.RunCommandRequest]) (*connect.Response[types.Int64Value], error) {
|
||||
return c.runCommand.CallUnary(ctx, req)
|
||||
}
|
||||
|
||||
// GetDownloadURL calls v1.Backrest.GetDownloadURL.
|
||||
@@ -370,7 +370,7 @@ type BackrestHandler interface {
|
||||
// GetLogs returns the keyed large data for the given operation.
|
||||
GetLogs(context.Context, *connect.Request[v1.LogDataRequest], *connect.ServerStream[types.BytesValue]) error
|
||||
// RunCommand executes a generic restic command on the repository.
|
||||
RunCommand(context.Context, *connect.Request[v1.RunCommandRequest], *connect.ServerStream[types.BytesValue]) error
|
||||
RunCommand(context.Context, *connect.Request[v1.RunCommandRequest]) (*connect.Response[types.Int64Value], error)
|
||||
// GetDownloadURL returns a signed download URL given a forget operation ID.
|
||||
GetDownloadURL(context.Context, *connect.Request[types.Int64Value]) (*connect.Response[types.StringValue], error)
|
||||
// Clears the history of operations
|
||||
@@ -463,7 +463,7 @@ func NewBackrestHandler(svc BackrestHandler, opts ...connect.HandlerOption) (str
|
||||
connect.WithSchema(backrestGetLogsMethodDescriptor),
|
||||
connect.WithHandlerOptions(opts...),
|
||||
)
|
||||
backrestRunCommandHandler := connect.NewServerStreamHandler(
|
||||
backrestRunCommandHandler := connect.NewUnaryHandler(
|
||||
BackrestRunCommandProcedure,
|
||||
svc.RunCommand,
|
||||
connect.WithSchema(backrestRunCommandMethodDescriptor),
|
||||
@@ -584,8 +584,8 @@ func (UnimplementedBackrestHandler) GetLogs(context.Context, *connect.Request[v1
|
||||
return connect.NewError(connect.CodeUnimplemented, errors.New("v1.Backrest.GetLogs is not implemented"))
|
||||
}
|
||||
|
||||
func (UnimplementedBackrestHandler) RunCommand(context.Context, *connect.Request[v1.RunCommandRequest], *connect.ServerStream[types.BytesValue]) error {
|
||||
return connect.NewError(connect.CodeUnimplemented, errors.New("v1.Backrest.RunCommand is not implemented"))
|
||||
func (UnimplementedBackrestHandler) RunCommand(context.Context, *connect.Request[v1.RunCommandRequest]) (*connect.Response[types.Int64Value], error) {
|
||||
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("v1.Backrest.RunCommand is not implemented"))
|
||||
}
|
||||
|
||||
func (UnimplementedBackrestHandler) GetDownloadURL(context.Context, *connect.Request[types.Int64Value]) (*connect.Response[types.StringValue], error) {
|
||||
|
||||
@@ -429,73 +429,28 @@ func (s *BackrestHandler) Restore(ctx context.Context, req *connect.Request[v1.R
|
||||
return connect.NewResponse(&emptypb.Empty{}), nil
|
||||
}
|
||||
|
||||
func (s *BackrestHandler) RunCommand(ctx context.Context, req *connect.Request[v1.RunCommandRequest], resp *connect.ServerStream[types.BytesValue]) error {
|
||||
repo, err := s.orchestrator.GetRepoOrchestrator(req.Msg.RepoId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get repo %q: %w", req.Msg.RepoId, err)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
|
||||
outputs := make(chan []byte, 100)
|
||||
errChan := make(chan error, 1)
|
||||
go func() {
|
||||
start := time.Now()
|
||||
zap.S().Infof("running command for webui: %v", req.Msg.Command)
|
||||
if err := repo.RunCommand(ctx, req.Msg.Command, func(output []byte) {
|
||||
outputs <- bytes.Clone(output)
|
||||
}); err != nil && ctx.Err() == nil {
|
||||
zap.S().Errorf("error running command for webui: %v", err)
|
||||
errChan <- err
|
||||
} else {
|
||||
zap.S().Infof("command completed for webui: %v", time.Since(start))
|
||||
}
|
||||
outputs <- []byte("took " + time.Since(start).String())
|
||||
cancel()
|
||||
}()
|
||||
|
||||
ticker := time.NewTicker(100 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
|
||||
bufSize := 32 * 1024
|
||||
buf := make([]byte, 0, bufSize)
|
||||
|
||||
flush := func() error {
|
||||
if len(buf) > 0 {
|
||||
if err := resp.Send(&types.BytesValue{Value: buf}); err != nil {
|
||||
return fmt.Errorf("failed to write output: %w", err)
|
||||
}
|
||||
buf = buf[:0]
|
||||
func (s *BackrestHandler) RunCommand(ctx context.Context, req *connect.Request[v1.RunCommandRequest]) (*connect.Response[types.Int64Value], error) {
|
||||
// group commands within the last 24 hours (or 256 operations) into the same flow ID
|
||||
var flowID int64
|
||||
if s.oplog.Query(oplog.Query{RepoID: req.Msg.RepoId, Limit: 256, Reversed: true}, func(op *v1.Operation) error {
|
||||
if op.GetOperationRunCommand() != nil && time.Since(time.UnixMilli(op.UnixTimeStartMs)) < 30*time.Minute {
|
||||
flowID = op.FlowId
|
||||
}
|
||||
return nil
|
||||
}) != nil {
|
||||
return nil, fmt.Errorf("failed to query operations")
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case err := <-errChan:
|
||||
if err := flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
case <-ctx.Done():
|
||||
return flush()
|
||||
case output := <-outputs:
|
||||
if len(output)+len(buf) > bufSize {
|
||||
flush()
|
||||
}
|
||||
if len(output) > bufSize {
|
||||
if err := resp.Send(&types.BytesValue{Value: output}); err != nil {
|
||||
return fmt.Errorf("failed to write output: %w", err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
buf = append(buf, output...)
|
||||
case <-ticker.C:
|
||||
if len(buf) > 0 {
|
||||
flush()
|
||||
}
|
||||
}
|
||||
task := tasks.NewOneoffRunCommandTask(req.Msg.RepoId, tasks.PlanForSystemTasks, flowID, time.Now(), req.Msg.Command)
|
||||
st, err := s.orchestrator.CreateUnscheduledTask(task, tasks.TaskPriorityInteractive, time.Now())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create task: %w", err)
|
||||
}
|
||||
if err := s.orchestrator.RunTask(context.Background(), st); err != nil {
|
||||
return nil, fmt.Errorf("failed to run command: %w", err)
|
||||
}
|
||||
|
||||
return connect.NewResponse(&types.Int64Value{Value: st.Op.GetId()}), nil
|
||||
}
|
||||
|
||||
func (s *BackrestHandler) Cancel(ctx context.Context, req *connect.Request[types.Int64Value]) (*connect.Response[emptypb.Empty], error) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
@@ -764,6 +765,67 @@ func TestRestore(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommand(t *testing.T) {
|
||||
sut := createSystemUnderTest(t, &config.MemoryStore{
|
||||
Config: &v1.Config{
|
||||
Modno: 1234,
|
||||
Instance: "test",
|
||||
Repos: []*v1.Repo{
|
||||
{
|
||||
Id: "local",
|
||||
Uri: t.TempDir(),
|
||||
Password: "test",
|
||||
Flags: []string{"--no-cache"},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
res, err := sut.handler.RunCommand(ctx, connect.NewRequest(&v1.RunCommandRequest{
|
||||
RepoId: "local",
|
||||
Command: "help",
|
||||
}))
|
||||
if err != nil {
|
||||
t.Fatalf("RunCommand() error = %v", err)
|
||||
}
|
||||
op, err := sut.oplog.Get(res.Msg.Value)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to find runcommand operation: %v", err)
|
||||
}
|
||||
|
||||
if op.Status != v1.OperationStatus_STATUS_SUCCESS {
|
||||
t.Fatalf("Expected runcommand operation to succeed")
|
||||
}
|
||||
|
||||
cmdOp := op.GetOperationRunCommand()
|
||||
if cmdOp == nil {
|
||||
t.Fatalf("Expected runcommand operation to be of type OperationRunCommand")
|
||||
}
|
||||
if cmdOp.Command != "help" {
|
||||
t.Fatalf("Expected runcommand operation to have correct command")
|
||||
}
|
||||
if cmdOp.OutputLogref == "" {
|
||||
t.Fatalf("Expected runcommand operation to have output logref")
|
||||
}
|
||||
|
||||
log, err := sut.logStore.Open(cmdOp.OutputLogref)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to open log: %v", err)
|
||||
}
|
||||
defer log.Close()
|
||||
|
||||
data, err := io.ReadAll(log)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read log: %v", err)
|
||||
}
|
||||
if !strings.Contains(string(data), "Usage") {
|
||||
t.Fatalf("Expected log output to contain help text")
|
||||
}
|
||||
}
|
||||
|
||||
type systemUnderTest struct {
|
||||
handler *BackrestHandler
|
||||
oplog *oplog.OpLog
|
||||
|
||||
@@ -427,7 +427,6 @@ func (w *writer) Close() error {
|
||||
}
|
||||
}
|
||||
w.ls.trackingMu.Unlock()
|
||||
|
||||
w.ls.maybeReleaseTempFile(w.fname)
|
||||
})
|
||||
|
||||
|
||||
@@ -38,8 +38,8 @@ type Orchestrator struct {
|
||||
taskQueue *queue.TimePriorityQueue[stContainer]
|
||||
logStore *logstore.LogStore
|
||||
|
||||
// cancelNotify is a list of channels that are notified when a task should be cancelled.
|
||||
cancelNotify []chan int64
|
||||
taskCancelMu sync.Mutex
|
||||
taskCancel map[int64]context.CancelFunc
|
||||
|
||||
// now for the purpose of testing; used by Run() to get the current time.
|
||||
now func() time.Time
|
||||
@@ -70,9 +70,10 @@ func NewOrchestrator(resticBin string, cfg *v1.Config, log *oplog.OpLog, logStor
|
||||
OpLog: log,
|
||||
config: cfg,
|
||||
// repoPool created with a memory store to ensure the config is updated in an atomic operation with the repo pool's config value.
|
||||
repoPool: newResticRepoPool(resticBin, cfg),
|
||||
taskQueue: queue.NewTimePriorityQueue[stContainer](),
|
||||
logStore: logStore,
|
||||
repoPool: newResticRepoPool(resticBin, cfg),
|
||||
taskQueue: queue.NewTimePriorityQueue[stContainer](),
|
||||
logStore: logStore,
|
||||
taskCancel: make(map[int64]context.CancelFunc),
|
||||
}
|
||||
|
||||
// verify the operation log and mark any incomplete operations as failed.
|
||||
@@ -166,10 +167,8 @@ func (o *Orchestrator) ScheduleDefaultTasks(config *v1.Config) error {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := o.cancelHelper(t.Op, v1.OperationStatus_STATUS_SYSTEM_CANCELLED); err != nil {
|
||||
zap.L().Error("failed to cancel queued task", zap.String("task", t.Task.Name()), zap.Error(err))
|
||||
} else {
|
||||
zap.L().Debug("queued task cancelled due to config change", zap.String("task", t.Task.Name()))
|
||||
if err := o.OpLog.Delete(t.Op.Id); err != nil {
|
||||
zap.S().Warnf("failed to cancel pending task %d: %v", t.Op.Id, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,14 +238,11 @@ func (o *Orchestrator) GetPlan(planID string) (*v1.Plan, error) {
|
||||
}
|
||||
|
||||
func (o *Orchestrator) CancelOperation(operationId int64, status v1.OperationStatus) error {
|
||||
o.mu.Lock()
|
||||
for _, c := range o.cancelNotify {
|
||||
select {
|
||||
case c <- operationId:
|
||||
default:
|
||||
}
|
||||
o.taskCancelMu.Lock()
|
||||
if cancel, ok := o.taskCancel[operationId]; ok {
|
||||
cancel()
|
||||
}
|
||||
o.mu.Unlock()
|
||||
o.taskCancelMu.Unlock()
|
||||
|
||||
allTasks := o.taskQueue.GetAll()
|
||||
idx := slices.IndexFunc(allTasks, func(t stContainer) bool {
|
||||
@@ -262,9 +258,15 @@ func (o *Orchestrator) CancelOperation(operationId int64, status v1.OperationSta
|
||||
}
|
||||
o.taskQueue.Remove(t)
|
||||
|
||||
if err := o.scheduleTaskHelper(t.Task, tasks.TaskPriorityDefault, t.RunAt); err != nil {
|
||||
if st, err := o.CreateUnscheduledTask(t.Task, tasks.TaskPriorityDefault, t.RunAt); err != nil {
|
||||
return fmt.Errorf("reschedule cancelled task: %w", err)
|
||||
} else if !st.Eq(tasks.NeverScheduledTask) {
|
||||
o.taskQueue.Enqueue(st.RunAt, tasks.TaskPriorityDefault, stContainer{
|
||||
ScheduledTask: st,
|
||||
configModno: o.config.Modno,
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -281,20 +283,6 @@ func (o *Orchestrator) cancelHelper(op *v1.Operation, status v1.OperationStatus)
|
||||
func (o *Orchestrator) Run(ctx context.Context) {
|
||||
zap.L().Info("starting orchestrator loop")
|
||||
|
||||
// subscribe to cancel notifications.
|
||||
o.mu.Lock()
|
||||
cancelNotifyChan := make(chan int64, 10) // buffered to queue up cancel notifications.
|
||||
o.cancelNotify = append(o.cancelNotify, cancelNotifyChan)
|
||||
o.mu.Unlock()
|
||||
|
||||
defer func() {
|
||||
o.mu.Lock()
|
||||
if idx := slices.Index(o.cancelNotify, cancelNotifyChan); idx != -1 {
|
||||
o.cancelNotify = slices.Delete(o.cancelNotify, idx, idx+1)
|
||||
}
|
||||
o.mu.Unlock()
|
||||
}()
|
||||
|
||||
for {
|
||||
if ctx.Err() != nil {
|
||||
zap.L().Info("shutting down orchestrator loop, context cancelled.")
|
||||
@@ -306,20 +294,6 @@ func (o *Orchestrator) Run(ctx context.Context) {
|
||||
continue
|
||||
}
|
||||
|
||||
taskCtx, cancelTaskCtx := context.WithCancel(ctx)
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-taskCtx.Done():
|
||||
return
|
||||
case opID := <-cancelNotifyChan:
|
||||
if t.Op != nil && opID == t.Op.GetId() {
|
||||
cancelTaskCtx()
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Clone the operation incase we need to reset changes and reschedule the task for a retry
|
||||
originalOp := proto.Clone(t.Op).(*v1.Operation)
|
||||
if t.Op != nil && t.retryCount != 0 {
|
||||
@@ -340,7 +314,7 @@ func (o *Orchestrator) Run(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
err := o.RunTask(taskCtx, t.ScheduledTask)
|
||||
err := o.RunTask(ctx, t.ScheduledTask)
|
||||
|
||||
o.mu.Lock()
|
||||
curCfgModno := o.config.Modno
|
||||
@@ -372,8 +346,6 @@ func (o *Orchestrator) Run(ctx context.Context) {
|
||||
zap.L().Error("reschedule task", zap.String("task", t.Task.Name()), zap.Error(e))
|
||||
}
|
||||
}
|
||||
cancelTaskCtx()
|
||||
|
||||
for _, cb := range t.callbacks {
|
||||
go cb(err)
|
||||
}
|
||||
@@ -381,11 +353,22 @@ func (o *Orchestrator) Run(ctx context.Context) {
|
||||
}
|
||||
|
||||
func (o *Orchestrator) RunTask(ctx context.Context, st tasks.ScheduledTask) error {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
zap.L().Info("running task", zap.String("task", st.Task.Name()), zap.String("runAt", st.RunAt.Format(time.RFC3339)))
|
||||
var logWriter io.WriteCloser
|
||||
op := st.Op
|
||||
if op != nil {
|
||||
var err error
|
||||
o.taskCancelMu.Lock()
|
||||
o.taskCancel[op.Id] = cancel
|
||||
o.taskCancelMu.Unlock()
|
||||
defer func() {
|
||||
o.taskCancelMu.Lock()
|
||||
delete(o.taskCancel, op.Id)
|
||||
o.taskCancelMu.Unlock()
|
||||
}()
|
||||
|
||||
randBytes := make([]byte, 8)
|
||||
if _, err := rand.Read(randBytes); err != nil {
|
||||
@@ -465,41 +448,49 @@ func (o *Orchestrator) RunTask(ctx context.Context, st tasks.ScheduledTask) erro
|
||||
// ScheduleTask schedules a task to run at the next available time.
|
||||
// note that o.mu must not be held when calling this function.
|
||||
func (o *Orchestrator) ScheduleTask(t tasks.Task, priority int, callbacks ...func(error)) error {
|
||||
return o.scheduleTaskHelper(t, priority, o.curTime(), callbacks...)
|
||||
}
|
||||
|
||||
func (o *Orchestrator) scheduleTaskHelper(t tasks.Task, priority int, curTime time.Time, callbacks ...func(error)) error {
|
||||
nextRun, err := t.Next(curTime, newTaskRunnerImpl(o, t, nil))
|
||||
nextRun, err := o.CreateUnscheduledTask(t, priority, o.curTime())
|
||||
if err != nil {
|
||||
return fmt.Errorf("finding run time for task %q: %w", t.Name(), err)
|
||||
return err
|
||||
}
|
||||
if nextRun.Eq(tasks.NeverScheduledTask) {
|
||||
return nil
|
||||
}
|
||||
nextRun.Task = t
|
||||
|
||||
stc := stContainer{
|
||||
ScheduledTask: nextRun,
|
||||
configModno: o.config.Modno,
|
||||
callbacks: callbacks,
|
||||
}
|
||||
|
||||
if stc.Op != nil {
|
||||
stc.Op.InstanceId = o.config.Instance
|
||||
stc.Op.PlanId = t.PlanID()
|
||||
stc.Op.RepoId = t.RepoID()
|
||||
stc.Op.Status = v1.OperationStatus_STATUS_PENDING
|
||||
stc.Op.UnixTimeStartMs = nextRun.RunAt.UnixMilli()
|
||||
|
||||
if err := o.OpLog.Add(nextRun.Op); err != nil {
|
||||
return fmt.Errorf("add operation to oplog: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
o.taskQueue.Enqueue(nextRun.RunAt, priority, stc)
|
||||
zap.L().Info("scheduled task", zap.String("task", t.Name()), zap.String("runAt", nextRun.RunAt.Format(time.RFC3339)))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Orchestrator) CreateUnscheduledTask(t tasks.Task, priority int, curTime time.Time) (tasks.ScheduledTask, error) {
|
||||
nextRun, err := t.Next(curTime, newTaskRunnerImpl(o, t, nil))
|
||||
if err != nil {
|
||||
return tasks.NeverScheduledTask, fmt.Errorf("finding run time for task %q: %w", t.Name(), err)
|
||||
}
|
||||
if nextRun.Eq(tasks.NeverScheduledTask) {
|
||||
return tasks.NeverScheduledTask, nil
|
||||
}
|
||||
nextRun.Task = t
|
||||
|
||||
if nextRun.Op != nil {
|
||||
nextRun.Op.InstanceId = o.config.Instance
|
||||
nextRun.Op.PlanId = t.PlanID()
|
||||
nextRun.Op.RepoId = t.RepoID()
|
||||
nextRun.Op.Status = v1.OperationStatus_STATUS_PENDING
|
||||
nextRun.Op.UnixTimeStartMs = nextRun.RunAt.UnixMilli()
|
||||
|
||||
if err := o.OpLog.Add(nextRun.Op); err != nil {
|
||||
return tasks.NeverScheduledTask, fmt.Errorf("add operation to oplog: %w", err)
|
||||
}
|
||||
}
|
||||
return nextRun, nil
|
||||
}
|
||||
|
||||
func (o *Orchestrator) Config() *v1.Config {
|
||||
o.mu.Lock()
|
||||
defer o.mu.Unlock()
|
||||
|
||||
@@ -389,7 +389,7 @@ func (r *RepoOrchestrator) AddTags(ctx context.Context, snapshotIDs []string, ta
|
||||
}
|
||||
|
||||
// RunCommand runs a command in the repo's environment. Output is buffered and sent to the onProgress callback in batches.
|
||||
func (r *RepoOrchestrator) RunCommand(ctx context.Context, command string, onProgress func([]byte)) error {
|
||||
func (r *RepoOrchestrator) RunCommand(ctx context.Context, command string, writer io.Writer) error {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
ctx, flush := forwardResticLogs(ctx)
|
||||
@@ -401,8 +401,7 @@ func (r *RepoOrchestrator) RunCommand(ctx context.Context, command string, onPro
|
||||
return fmt.Errorf("parse command: %w", err)
|
||||
}
|
||||
|
||||
ctx = restic.ContextWithLogger(ctx, &callbackWriter{callback: onProgress})
|
||||
|
||||
ctx = restic.ContextWithLogger(ctx, writer)
|
||||
return r.repo.GenericCommand(ctx, args)
|
||||
}
|
||||
|
||||
@@ -425,12 +424,3 @@ func chunkBy[T any](items []T, chunkSize int) (chunks [][]T) {
|
||||
}
|
||||
return append(chunks, items)
|
||||
}
|
||||
|
||||
type callbackWriter struct {
|
||||
callback func([]byte) // note: callback must not retain the byte slice
|
||||
}
|
||||
|
||||
func (w *callbackWriter) Write(p []byte) (n int, err error) {
|
||||
w.callback(p)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
@@ -104,10 +104,9 @@ func (t *taskRunnerImpl) ExecuteHooks(ctx context.Context, events []v1.Hook_Cond
|
||||
}
|
||||
|
||||
for _, task := range hookTasks {
|
||||
st, _ := task.Next(time.Now(), t)
|
||||
st.Task = task
|
||||
if err := t.OpLog().Add(st.Op); err != nil {
|
||||
return fmt.Errorf("%v: %w", task.Name(), err)
|
||||
st, err := t.orchestrator.CreateUnscheduledTask(task, tasks.TaskPriorityDefault, time.Now())
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating task for hook: %w", err)
|
||||
}
|
||||
if err := t.orchestrator.RunTask(ctx, st); hook.IsHaltingError(err) {
|
||||
var cancelErr *hook.HookErrorRequestCancel
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
v1 "github.com/garethgeorge/backrest/gen/go/v1"
|
||||
)
|
||||
|
||||
func NewOneoffRunCommandTask(repoID string, planID string, flowID int64, at time.Time, command string) Task {
|
||||
return &GenericOneoffTask{
|
||||
OneoffTask: OneoffTask{
|
||||
BaseTask: BaseTask{
|
||||
TaskType: "forget_snapshot",
|
||||
TaskName: fmt.Sprintf("run command in repo %q", repoID),
|
||||
TaskRepoID: repoID,
|
||||
TaskPlanID: planID,
|
||||
},
|
||||
FlowID: flowID,
|
||||
RunAt: at,
|
||||
ProtoOp: &v1.Operation{
|
||||
Op: &v1.Operation_OperationRunCommand{
|
||||
OperationRunCommand: &v1.OperationRunCommand{
|
||||
Command: command,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Do: func(ctx context.Context, st ScheduledTask, taskRunner TaskRunner) error {
|
||||
op := st.Op
|
||||
rc := op.GetOperationRunCommand()
|
||||
if rc == nil {
|
||||
panic("forget task with non-forget operation")
|
||||
}
|
||||
|
||||
return runCommandHelper(ctx, st, taskRunner, command)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func runCommandHelper(ctx context.Context, st ScheduledTask, taskRunner TaskRunner, command string) error {
|
||||
t := st.Task
|
||||
|
||||
repo, err := taskRunner.GetRepoOrchestrator(t.RepoID())
|
||||
if err != nil {
|
||||
return fmt.Errorf("get repo %q: %w", t.RepoID(), err)
|
||||
}
|
||||
|
||||
id, writer, err := taskRunner.LogrefWriter()
|
||||
if err != nil {
|
||||
return fmt.Errorf("get logref writer: %w", err)
|
||||
}
|
||||
st.Op.GetOperationRunCommand().OutputLogref = id
|
||||
if err := taskRunner.UpdateOperation(st.Op); err != nil {
|
||||
return fmt.Errorf("update operation: %w", err)
|
||||
}
|
||||
|
||||
if err := repo.RunCommand(ctx, command, writer); err != nil {
|
||||
return fmt.Errorf("command %q: %w", command, err)
|
||||
}
|
||||
|
||||
if err := writer.Close(); err != nil {
|
||||
return fmt.Errorf("close logref writer: %w", err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -41,6 +41,7 @@ message Operation {
|
||||
OperationStats operation_stats = 105;
|
||||
OperationRunHook operation_run_hook = 106;
|
||||
OperationCheck operation_check = 107;
|
||||
OperationRunCommand operation_run_command = 108;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +103,12 @@ message OperationCheck {
|
||||
string output_logref = 2; // logref of the check output.
|
||||
}
|
||||
|
||||
// OperationRunCommand tracks a long running command. Commands are grouped into a flow ID for each session.
|
||||
message OperationRunCommand {
|
||||
string command = 1;
|
||||
string output_logref = 2;
|
||||
}
|
||||
|
||||
// OperationRestore tracks a restore operation.
|
||||
message OperationRestore {
|
||||
string path = 1; // path in the snapshot to restore.
|
||||
|
||||
@@ -45,7 +45,7 @@ service Backrest {
|
||||
rpc GetLogs(LogDataRequest) returns (stream types.BytesValue) {}
|
||||
|
||||
// RunCommand executes a generic restic command on the repository.
|
||||
rpc RunCommand(RunCommandRequest) returns (stream types.BytesValue) {}
|
||||
rpc RunCommand(RunCommandRequest) returns (types.Int64Value) {}
|
||||
|
||||
// GetDownloadURL returns a signed download URL given a forget operation ID.
|
||||
rpc GetDownloadURL(types.Int64Value) returns (types.StringValue) {}
|
||||
|
||||
@@ -278,6 +278,12 @@ export class Operation extends Message<Operation> {
|
||||
*/
|
||||
value: OperationCheck;
|
||||
case: "operationCheck";
|
||||
} | {
|
||||
/**
|
||||
* @generated from field: v1.OperationRunCommand operation_run_command = 108;
|
||||
*/
|
||||
value: OperationRunCommand;
|
||||
case: "operationRunCommand";
|
||||
} | { case: undefined; value?: undefined } = { case: undefined };
|
||||
|
||||
constructor(data?: PartialMessage<Operation>) {
|
||||
@@ -307,6 +313,7 @@ export class Operation extends Message<Operation> {
|
||||
{ no: 105, name: "operation_stats", kind: "message", T: OperationStats, oneof: "op" },
|
||||
{ no: 106, name: "operation_run_hook", kind: "message", T: OperationRunHook, oneof: "op" },
|
||||
{ no: 107, name: "operation_check", kind: "message", T: OperationCheck, oneof: "op" },
|
||||
{ no: 108, name: "operation_run_command", kind: "message", T: OperationRunCommand, oneof: "op" },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): Operation {
|
||||
@@ -629,6 +636,51 @@ export class OperationCheck extends Message<OperationCheck> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* OperationRunCommand tracks a long running command. Commands are grouped into a flow ID for each session.
|
||||
*
|
||||
* @generated from message v1.OperationRunCommand
|
||||
*/
|
||||
export class OperationRunCommand extends Message<OperationRunCommand> {
|
||||
/**
|
||||
* @generated from field: string command = 1;
|
||||
*/
|
||||
command = "";
|
||||
|
||||
/**
|
||||
* @generated from field: string output_logref = 2;
|
||||
*/
|
||||
outputLogref = "";
|
||||
|
||||
constructor(data?: PartialMessage<OperationRunCommand>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "v1.OperationRunCommand";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "command", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 2, name: "output_logref", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): OperationRunCommand {
|
||||
return new OperationRunCommand().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): OperationRunCommand {
|
||||
return new OperationRunCommand().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): OperationRunCommand {
|
||||
return new OperationRunCommand().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: OperationRunCommand | PlainMessage<OperationRunCommand> | undefined, b: OperationRunCommand | PlainMessage<OperationRunCommand> | undefined): boolean {
|
||||
return proto3.util.equals(OperationRunCommand, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* OperationRestore tracks a restore operation.
|
||||
*
|
||||
|
||||
@@ -153,8 +153,8 @@ export const Backrest = {
|
||||
runCommand: {
|
||||
name: "RunCommand",
|
||||
I: RunCommandRequest,
|
||||
O: BytesValue,
|
||||
kind: MethodKind.ServerStreaming,
|
||||
O: Int64Value,
|
||||
kind: MethodKind.Unary,
|
||||
},
|
||||
/**
|
||||
* GetDownloadURL returns a signed download URL given a forget operation ID.
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { LogDataRequest } from "../../gen/ts/v1/service_pb";
|
||||
import { backrestService } from "../api";
|
||||
|
||||
import AutoSizer from "react-virtualized/dist/commonjs/AutoSizer";
|
||||
import List from "react-virtualized/dist/commonjs/List";
|
||||
import { set } from "lodash";
|
||||
import { Button } from "antd";
|
||||
|
||||
// TODO: refactor this to use the provider pattern
|
||||
export const LogView = ({ logref }: { logref: string }) => {
|
||||
const [lines, setLines] = useState<string[]>([""]);
|
||||
|
||||
console.log("LogView", logref);
|
||||
const [limit, setLimit] = useState(100);
|
||||
|
||||
useEffect(() => {
|
||||
if (!logref) {
|
||||
@@ -47,7 +43,10 @@ export const LogView = ({ logref }: { logref: string }) => {
|
||||
};
|
||||
}, [logref]);
|
||||
|
||||
console.log("LogView", lines);
|
||||
let displayLines = lines;
|
||||
if (lines.length > limit) {
|
||||
displayLines = lines.slice(0, limit);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -56,7 +55,7 @@ export const LogView = ({ logref }: { logref: string }) => {
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
{lines.map((line, i) => (
|
||||
{displayLines.map((line, i) => (
|
||||
<pre
|
||||
style={{ margin: "0px", whiteSpace: "pre", overflow: "visible" }}
|
||||
key={i}
|
||||
@@ -64,6 +63,18 @@ export const LogView = ({ logref }: { logref: string }) => {
|
||||
{line}
|
||||
</pre>
|
||||
))}
|
||||
{lines.length > limit ? (
|
||||
<>
|
||||
<Button
|
||||
color="default"
|
||||
type="link"
|
||||
onClick={() => setLimit(limit * 10)}
|
||||
>
|
||||
Show {Math.min(limit * 9, lines.length - limit)} more lines out of{" "}
|
||||
{lines.length} available...
|
||||
</Button>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import { DisplayType, colorForStatus } from "../state/flowdisplayaggregator";
|
||||
import {
|
||||
CodeOutlined,
|
||||
DeleteOutlined,
|
||||
DownloadOutlined,
|
||||
FileSearchOutlined,
|
||||
@@ -23,20 +24,10 @@ export const OperationIcon = ({
|
||||
let avatar: React.ReactNode;
|
||||
switch (type) {
|
||||
case DisplayType.BACKUP:
|
||||
avatar = (
|
||||
<SaveOutlined
|
||||
style={{ color: color }}
|
||||
spin={status === OperationStatus.STATUS_INPROGRESS}
|
||||
/>
|
||||
);
|
||||
avatar = <SaveOutlined style={{ color: color }} />;
|
||||
break;
|
||||
case DisplayType.FORGET:
|
||||
avatar = (
|
||||
<DeleteOutlined
|
||||
style={{ color: color }}
|
||||
spin={status === OperationStatus.STATUS_INPROGRESS}
|
||||
/>
|
||||
);
|
||||
avatar = <DeleteOutlined style={{ color: color }} />;
|
||||
break;
|
||||
case DisplayType.SNAPSHOT:
|
||||
avatar = <PaperClipOutlined style={{ color: color }} />;
|
||||
@@ -55,6 +46,9 @@ export const OperationIcon = ({
|
||||
case DisplayType.STATS:
|
||||
avatar = <InfoCircleOutlined style={{ color: color }} />;
|
||||
break;
|
||||
case DisplayType.RUNCOMMAND:
|
||||
avatar = <CodeOutlined style={{ color: color }} />;
|
||||
break;
|
||||
}
|
||||
|
||||
return avatar;
|
||||
|
||||
@@ -15,11 +15,13 @@ export const OperationList = ({
|
||||
useOperations,
|
||||
showPlan,
|
||||
displayHooksInline,
|
||||
filter,
|
||||
}: React.PropsWithoutRef<{
|
||||
req?: GetOperationsRequest;
|
||||
useOperations?: Operation[]; // exact set of operations to display; no filtering will be applied.
|
||||
showPlan?: boolean;
|
||||
displayHooksInline?: boolean;
|
||||
filter?: (op: Operation) => boolean;
|
||||
}>) => {
|
||||
const alertApi = useAlertApi();
|
||||
|
||||
@@ -27,7 +29,9 @@ export const OperationList = ({
|
||||
|
||||
if (req) {
|
||||
useEffect(() => {
|
||||
const logState = new OplogState((op) => !shouldHideStatus(op.status));
|
||||
const logState = new OplogState(
|
||||
(op) => !shouldHideStatus(op.status) && (!filter || filter(op))
|
||||
);
|
||||
|
||||
logState.subscribe((ids, flowIDs, event) => {
|
||||
setOperations(logState.getAll());
|
||||
|
||||
@@ -234,6 +234,18 @@ export const OperationRow = ({
|
||||
<pre>{check.output}</pre>
|
||||
),
|
||||
});
|
||||
} else if (operation.op.case === "operationRunCommand") {
|
||||
const run = operation.op.value;
|
||||
expandedBodyItems.push("run");
|
||||
bodyItems.push({
|
||||
key: "run",
|
||||
label: "Command Output",
|
||||
children: (
|
||||
<>
|
||||
<LogView logref={run.outputLogref} />
|
||||
</>
|
||||
),
|
||||
});
|
||||
} else if (operation.op.case === "operationRestore") {
|
||||
expandedBodyItems.push("restore");
|
||||
bodyItems.push({
|
||||
|
||||
@@ -487,7 +487,7 @@ const BackupView = ({ backup }: { backup?: FlowDisplayInfo }) => {
|
||||
backrestService.clearHistory(
|
||||
new ClearHistoryRequest({
|
||||
selector: new OpSelector({
|
||||
ids: backup.operations.map((op) => op.id),
|
||||
flowId: backup.flowID,
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
@@ -11,6 +11,7 @@ export enum DisplayType {
|
||||
RESTORE,
|
||||
STATS,
|
||||
RUNHOOK,
|
||||
RUNCOMMAND,
|
||||
}
|
||||
|
||||
export interface FlowDisplayInfo {
|
||||
@@ -156,6 +157,8 @@ export const getTypeForDisplay = (op: Operation) => {
|
||||
return DisplayType.STATS;
|
||||
case "operationRunHook":
|
||||
return DisplayType.RUNHOOK;
|
||||
case "operationRunCommand":
|
||||
return DisplayType.RUNCOMMAND;
|
||||
default:
|
||||
return DisplayType.UNKNOWN;
|
||||
}
|
||||
@@ -179,6 +182,8 @@ export const displayTypeToString = (type: DisplayType) => {
|
||||
return "Stats";
|
||||
case DisplayType.RUNHOOK:
|
||||
return "Run Hook";
|
||||
case DisplayType.RUNCOMMAND:
|
||||
return "Run Command";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
@@ -5,6 +5,11 @@ import { backrestService } from "../api";
|
||||
import { SpinButton } from "../components/SpinButton";
|
||||
import { ConnectError } from "@connectrpc/connect";
|
||||
import { useAlertApi } from "../components/Alerts";
|
||||
import {
|
||||
GetOperationsRequest,
|
||||
RunCommandRequest,
|
||||
} from "../../gen/ts/v1/service_pb";
|
||||
import { OperationList } from "../components/OperationList";
|
||||
|
||||
interface Invocation {
|
||||
command: string;
|
||||
@@ -17,64 +22,29 @@ export const RunCommandModal = ({ repoId }: { repoId: string }) => {
|
||||
const alertApi = useAlertApi()!;
|
||||
const [command, setCommand] = React.useState("");
|
||||
const [running, setRunning] = React.useState(false);
|
||||
const [invocations, setInvocations] = React.useState<Invocation[]>([]);
|
||||
const [abortController, setAbortController] = React.useState<
|
||||
AbortController | undefined
|
||||
>();
|
||||
|
||||
const handleCancel = () => {
|
||||
if (abortController) {
|
||||
alertApi.warning("In-progress restic command was aborted");
|
||||
abortController.abort();
|
||||
}
|
||||
showModal(null);
|
||||
};
|
||||
|
||||
const doExecute = async () => {
|
||||
if (running) return;
|
||||
if (!command) return;
|
||||
setRunning(true);
|
||||
|
||||
const newInvocation = { command, output: "", error: "" };
|
||||
setInvocations((invocations) => [newInvocation, ...invocations]);
|
||||
|
||||
let segments: string[] = [];
|
||||
const toRun = command.trim();
|
||||
setCommand("");
|
||||
|
||||
try {
|
||||
const abortController = new AbortController();
|
||||
setAbortController(abortController);
|
||||
|
||||
for await (const bytes of backrestService.runCommand(
|
||||
{
|
||||
const opID = await backrestService.runCommand(
|
||||
new RunCommandRequest({
|
||||
repoId,
|
||||
command,
|
||||
},
|
||||
{
|
||||
signal: abortController.signal,
|
||||
}
|
||||
)) {
|
||||
const output = new TextDecoder("utf-8").decode(bytes.value);
|
||||
segments.push(output);
|
||||
setInvocations((invocations) => {
|
||||
const copy = [...invocations];
|
||||
copy[0] = {
|
||||
...copy[0],
|
||||
output: segments.join(""),
|
||||
};
|
||||
return copy;
|
||||
});
|
||||
}
|
||||
command: toRun,
|
||||
})
|
||||
);
|
||||
} catch (e: any) {
|
||||
setInvocations((invocations) => {
|
||||
const copy = [...invocations];
|
||||
copy[0] = {
|
||||
...copy[0],
|
||||
error: (e as Error).message,
|
||||
};
|
||||
return copy;
|
||||
});
|
||||
alertApi.error("Command failed: " + e.message);
|
||||
} finally {
|
||||
setRunning(false);
|
||||
setAbortController(undefined);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -89,6 +59,7 @@ export const RunCommandModal = ({ repoId }: { repoId: string }) => {
|
||||
<Space.Compact style={{ width: "100%" }}>
|
||||
<Input
|
||||
placeholder="Run a restic comamnd e.g. 'help' to print help text"
|
||||
value={command}
|
||||
onChange={(e) => setCommand(e.target.value)}
|
||||
onKeyUp={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
@@ -100,14 +71,23 @@ export const RunCommandModal = ({ repoId }: { repoId: string }) => {
|
||||
Execute
|
||||
</SpinButton>
|
||||
</Space.Compact>
|
||||
{invocations.map((invocation, i) => (
|
||||
<div key={i}>
|
||||
{invocation.output ? <pre>{invocation.output}</pre> : null}
|
||||
{invocation.error ? (
|
||||
<pre style={{ color: "red" }}>{invocation.error}</pre>
|
||||
) : null}
|
||||
</div>
|
||||
))}
|
||||
{running && command ? (
|
||||
<em style={{ color: "gray" }}>
|
||||
Warning: another command is already running. Wait for it to finish
|
||||
before running another operation that requires the repo lock.
|
||||
</em>
|
||||
) : null}
|
||||
<OperationList
|
||||
req={
|
||||
new GetOperationsRequest({
|
||||
selector: {
|
||||
repoId: repoId,
|
||||
planId: "_system_", // run commands are not associated with a plan
|
||||
},
|
||||
})
|
||||
}
|
||||
filter={(op) => op.op.case === "operationRunCommand"}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user