feat: allow hook exit codes to control backup execution (e.g fail, skip, etc)

This commit is contained in:
garethgeorge
2024-04-12 00:05:27 -07:00
parent 63b6dc7b38
commit e3965db42a
23 changed files with 723 additions and 286 deletions
+58 -7
View File
@@ -208,6 +208,44 @@ func (x *Int64Value) GetValue() int64 {
return 0
}
type Empty struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *Empty) Reset() {
*x = Empty{}
if protoimpl.UnsafeEnabled {
mi := &file_types_value_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Empty) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Empty) ProtoMessage() {}
func (x *Empty) ProtoReflect() protoreflect.Message {
mi := &file_types_value_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 Empty.ProtoReflect.Descriptor instead.
func (*Empty) Descriptor() ([]byte, []int) {
return file_types_value_proto_rawDescGZIP(), []int{4}
}
var File_types_value_proto protoreflect.FileDescriptor
var file_types_value_proto_rawDesc = []byte{
@@ -221,11 +259,11 @@ var file_types_value_proto_rawDesc = []byte{
0x74, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
0x09, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x22, 0x0a, 0x0a, 0x49, 0x6e, 0x74,
0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x2f, 0x5a,
0x2d, 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, 0x74, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x07, 0x0a,
0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x2f, 0x5a, 0x2d, 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, 0x74, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -240,12 +278,13 @@ func file_types_value_proto_rawDescGZIP() []byte {
return file_types_value_proto_rawDescData
}
var file_types_value_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_types_value_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_types_value_proto_goTypes = []interface{}{
(*StringValue)(nil), // 0: types.StringValue
(*BytesValue)(nil), // 1: types.BytesValue
(*StringList)(nil), // 2: types.StringList
(*Int64Value)(nil), // 3: types.Int64Value
(*Empty)(nil), // 4: types.Empty
}
var file_types_value_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
@@ -309,6 +348,18 @@ func file_types_value_proto_init() {
return nil
}
}
file_types_value_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Empty); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
@@ -316,7 +367,7 @@ func file_types_value_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_types_value_proto_rawDesc,
NumEnums: 0,
NumMessages: 4,
NumMessages: 5,
NumExtensions: 0,
NumServices: 0,
},
+353 -210
View File
@@ -9,6 +9,7 @@ package v1
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
_ "google.golang.org/protobuf/types/known/emptypb"
reflect "reflect"
sync "sync"
)
@@ -75,6 +76,104 @@ func (Hook_Condition) EnumDescriptor() ([]byte, []int) {
return file_v1_config_proto_rawDescGZIP(), []int{5, 0}
}
type Hook_OnError int32
const (
Hook_ON_ERROR_IGNORE Hook_OnError = 0
Hook_ON_ERROR_CANCEL Hook_OnError = 1 // cancels the operation and skips subsequent hooks
Hook_ON_ERROR_FATAL Hook_OnError = 2 // fails the operation and subsequent hooks
)
// Enum value maps for Hook_OnError.
var (
Hook_OnError_name = map[int32]string{
0: "ON_ERROR_IGNORE",
1: "ON_ERROR_CANCEL",
2: "ON_ERROR_FATAL",
}
Hook_OnError_value = map[string]int32{
"ON_ERROR_IGNORE": 0,
"ON_ERROR_CANCEL": 1,
"ON_ERROR_FATAL": 2,
}
)
func (x Hook_OnError) Enum() *Hook_OnError {
p := new(Hook_OnError)
*p = x
return p
}
func (x Hook_OnError) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (Hook_OnError) Descriptor() protoreflect.EnumDescriptor {
return file_v1_config_proto_enumTypes[1].Descriptor()
}
func (Hook_OnError) Type() protoreflect.EnumType {
return &file_v1_config_proto_enumTypes[1]
}
func (x Hook_OnError) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use Hook_OnError.Descriptor instead.
func (Hook_OnError) EnumDescriptor() ([]byte, []int) {
return file_v1_config_proto_rawDescGZIP(), []int{5, 1}
}
type Hook_Webhook_Method int32
const (
Hook_Webhook_UNKNOWN Hook_Webhook_Method = 0
Hook_Webhook_GET Hook_Webhook_Method = 1
Hook_Webhook_POST Hook_Webhook_Method = 2
)
// Enum value maps for Hook_Webhook_Method.
var (
Hook_Webhook_Method_name = map[int32]string{
0: "UNKNOWN",
1: "GET",
2: "POST",
}
Hook_Webhook_Method_value = map[string]int32{
"UNKNOWN": 0,
"GET": 1,
"POST": 2,
}
)
func (x Hook_Webhook_Method) Enum() *Hook_Webhook_Method {
p := new(Hook_Webhook_Method)
*p = x
return p
}
func (x Hook_Webhook_Method) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (Hook_Webhook_Method) Descriptor() protoreflect.EnumDescriptor {
return file_v1_config_proto_enumTypes[2].Descriptor()
}
func (Hook_Webhook_Method) Type() protoreflect.EnumType {
return &file_v1_config_proto_enumTypes[2]
}
func (x Hook_Webhook_Method) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use Hook_Webhook_Method.Descriptor instead.
func (Hook_Webhook_Method) EnumDescriptor() ([]byte, []int) {
return file_v1_config_proto_rawDescGZIP(), []int{5, 1, 0}
}
// Config is the top level config object for restic UI.
type Config struct {
state protoimpl.MessageState
@@ -631,6 +730,7 @@ type Hook struct {
unknownFields protoimpl.UnknownFields
Conditions []Hook_Condition `protobuf:"varint,1,rep,packed,name=conditions,proto3,enum=v1.Hook_Condition" json:"conditions,omitempty"`
OnError Hook_OnError `protobuf:"varint,2,opt,name=on_error,json=onError,proto3,enum=v1.Hook_OnError" json:"on_error,omitempty"`
// Types that are assignable to Action:
//
// *Hook_ActionCommand
@@ -681,6 +781,13 @@ func (x *Hook) GetConditions() []Hook_Condition {
return nil
}
func (x *Hook) GetOnError() Hook_OnError {
if x != nil {
return x.OnError
}
return Hook_ON_ERROR_IGNORE
}
func (m *Hook) GetAction() isHook_Action {
if m != nil {
return m.Action
@@ -1031,7 +1138,9 @@ type Hook_Webhook struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
WebhookUrl string `protobuf:"bytes,1,opt,name=webhook_url,json=webhookUrl,proto3" json:"webhook_url,omitempty"`
WebhookUrl string `protobuf:"bytes,1,opt,name=webhook_url,json=webhookUrl,proto3" json:"webhook_url,omitempty"`
Method Hook_Webhook_Method `protobuf:"varint,2,opt,name=method,proto3,enum=v1.Hook_Webhook_Method" json:"method,omitempty"`
Template string `protobuf:"bytes,100,opt,name=template,proto3" json:"template,omitempty"`
}
func (x *Hook_Webhook) Reset() {
@@ -1073,6 +1182,20 @@ func (x *Hook_Webhook) GetWebhookUrl() string {
return ""
}
func (x *Hook_Webhook) GetMethod() Hook_Webhook_Method {
if x != nil {
return x.Method
}
return Hook_Webhook_UNKNOWN
}
func (x *Hook_Webhook) GetTemplate() string {
if x != nil {
return x.Template
}
return ""
}
type Hook_Discord struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -1313,177 +1436,193 @@ var File_v1_config_proto protoreflect.FileDescriptor
var file_v1_config_proto_rawDesc = []byte{
0x0a, 0x0f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x12, 0x02, 0x76, 0x31, 0x22, 0xaa, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x6e, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52,
0x05, 0x6d, 0x6f, 0x64, 0x6e, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
0x68, 0x6f, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x05, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x18, 0x03, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x52, 0x05, 0x72,
0x65, 0x70, 0x6f, 0x73, 0x12, 0x1e, 0x0a, 0x05, 0x70, 0x6c, 0x61, 0x6e, 0x73, 0x18, 0x04, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x52, 0x05, 0x70,
0x6c, 0x61, 0x6e, 0x73, 0x12, 0x1c, 0x0a, 0x04, 0x61, 0x75, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x52, 0x04, 0x61, 0x75,
0x74, 0x68, 0x22, 0xe1, 0x01, 0x0a, 0x04, 0x52, 0x65, 0x70, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69,
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75,
0x72, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12, 0x1a, 0x0a,
0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x76,
0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x65, 0x6e, 0x76, 0x12, 0x14, 0x0a, 0x05, 0x66,
0x6c, 0x61, 0x67, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67,
0x73, 0x12, 0x32, 0x0a, 0x0c, 0x70, 0x72, 0x75, 0x6e, 0x65, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63,
0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x75,
0x6e, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x0b, 0x70, 0x72, 0x75, 0x6e, 0x65, 0x50,
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x1e, 0x0a, 0x05, 0x68, 0x6f, 0x6f, 0x6b, 0x73, 0x18, 0x07,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x52, 0x05,
0x68, 0x6f, 0x6f, 0x6b, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x75, 0x6e,
0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x61, 0x75, 0x74, 0x6f,
0x55, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0xa1, 0x02, 0x0a, 0x04, 0x50, 0x6c, 0x61, 0x6e, 0x12,
0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12,
0x12, 0x0a, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72,
0x65, 0x70, 0x6f, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18,
0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12,
0x14, 0x0a, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05,
0x70, 0x61, 0x74, 0x68, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65,
0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65,
0x73, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x18, 0x09,
0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x69, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x12,
0x12, 0x0a, 0x04, 0x63, 0x72, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63,
0x72, 0x6f, 0x6e, 0x12, 0x31, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e,
0x18, 0x07, 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, 0x09, 0x72, 0x65, 0x74,
0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x05, 0x68, 0x6f, 0x6f, 0x6b, 0x73, 0x18,
0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x52,
0x05, 0x68, 0x6f, 0x6f, 0x6b, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70,
0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x62, 0x61,
0x63, 0x6b, 0x75, 0x70, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x22, 0xa0, 0x05, 0x0a, 0x0f, 0x52,
0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x2c,
0x0a, 0x10, 0x6d, 0x61, 0x78, 0x5f, 0x75, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x6c, 0x69, 0x6d,
0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0e, 0x6d, 0x61,
0x78, 0x55, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x22, 0x0a, 0x0b,
0x6b, 0x65, 0x65, 0x70, 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28,
0x05, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x6b, 0x65, 0x65, 0x70, 0x4c, 0x61, 0x73, 0x74, 0x4e,
0x12, 0x23, 0x0a, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x68, 0x6f, 0x75, 0x72, 0x6c, 0x79, 0x18,
0x03, 0x20, 0x01, 0x28, 0x05, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x6b, 0x65, 0x65, 0x70, 0x48,
0x6f, 0x75, 0x72, 0x6c, 0x79, 0x12, 0x21, 0x0a, 0x0a, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x64, 0x61,
0x69, 0x6c, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x6b,
0x65, 0x65, 0x70, 0x44, 0x61, 0x69, 0x6c, 0x79, 0x12, 0x23, 0x0a, 0x0b, 0x6b, 0x65, 0x65, 0x70,
0x5f, 0x77, 0x65, 0x65, 0x6b, 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x42, 0x02, 0x18,
0x01, 0x52, 0x0a, 0x6b, 0x65, 0x65, 0x70, 0x57, 0x65, 0x65, 0x6b, 0x6c, 0x79, 0x12, 0x25, 0x0a,
0x0c, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x6c, 0x79, 0x18, 0x06, 0x20,
0x01, 0x28, 0x05, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x4d, 0x6f, 0x6e,
0x74, 0x68, 0x6c, 0x79, 0x12, 0x23, 0x0a, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x79, 0x65, 0x61,
0x72, 0x6c, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x6b,
0x65, 0x65, 0x70, 0x59, 0x65, 0x61, 0x72, 0x6c, 0x79, 0x12, 0x34, 0x0a, 0x14, 0x6b, 0x65, 0x65,
0x70, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x12, 0x6b, 0x65, 0x65,
0x70, 0x57, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12,
0x2d, 0x0a, 0x12, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x6c,
0x61, 0x73, 0x74, 0x5f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x0f, 0x70,
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4b, 0x65, 0x65, 0x70, 0x4c, 0x61, 0x73, 0x74, 0x4e, 0x12, 0x5a,
0x0a, 0x14, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x62, 0x75,
0x63, 0x6b, 0x65, 0x74, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76,
0x31, 0x2e, 0x52, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63,
0x79, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x65, 0x64, 0x43, 0x6f,
0x75, 0x6e, 0x74, 0x73, 0x48, 0x00, 0x52, 0x12, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, 0x69,
0x6d, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x65, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x6f,
0x6c, 0x69, 0x63, 0x79, 0x5f, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x61, 0x6c, 0x6c, 0x18, 0x0c, 0x20,
0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x0d, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4b, 0x65, 0x65,
0x70, 0x41, 0x6c, 0x6c, 0x1a, 0x8c, 0x01, 0x0a, 0x12, 0x54, 0x69, 0x6d, 0x65, 0x42, 0x75, 0x63,
0x6b, 0x65, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x68,
0x6f, 0x75, 0x72, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x68, 0x6f, 0x75,
0x72, 0x6c, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x18, 0x02, 0x20, 0x01,
0x28, 0x05, 0x52, 0x05, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x77, 0x65, 0x65,
0x6b, 0x6c, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x77, 0x65, 0x65, 0x6b, 0x6c,
0x79, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x6c, 0x79, 0x18, 0x04, 0x20, 0x01,
0x28, 0x05, 0x52, 0x07, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x6c, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x79,
0x65, 0x61, 0x72, 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x79, 0x65, 0x61,
0x72, 0x6c, 0x79, 0x42, 0x08, 0x0a, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x93, 0x01,
0x0a, 0x0b, 0x50, 0x72, 0x75, 0x6e, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x2c, 0x0a,
0x12, 0x6d, 0x61, 0x78, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x64,
0x61, 0x79, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x6d, 0x61, 0x78, 0x46, 0x72,
0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x44, 0x61, 0x79, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x6d,
0x61, 0x78, 0x5f, 0x75, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e,
0x74, 0x18, 0x64, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x6d, 0x61, 0x78, 0x55, 0x6e, 0x75, 0x73,
0x65, 0x64, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x61, 0x78,
0x5f, 0x75, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x65, 0x20,
0x01, 0x28, 0x05, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x55, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x42, 0x79,
0x74, 0x65, 0x73, 0x22, 0xde, 0x07, 0x0a, 0x04, 0x48, 0x6f, 0x6f, 0x6b, 0x12, 0x32, 0x0a, 0x0a,
0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0e,
0x32, 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69,
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73,
0x12, 0x39, 0x0a, 0x0e, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
0x6e, 0x64, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f,
0x6f, 0x6b, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x39, 0x0a, 0x0e, 0x61,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x18, 0x65, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x2e, 0x57, 0x65,
0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x57,
0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x12, 0x39, 0x0a, 0x0e, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x66, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10,
0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x72, 0x64,
0x48, 0x00, 0x52, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x72,
0x64, 0x12, 0x36, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x67, 0x6f, 0x74, 0x69,
0x66, 0x79, 0x18, 0x67, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f,
0x6f, 0x6b, 0x2e, 0x47, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x48, 0x00, 0x52, 0x0c, 0x61, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x47, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x12, 0x33, 0x0a, 0x0c, 0x61, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x18, 0x68, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x0e, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x2e, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x48,
0x00, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x12, 0x3c,
0x0a, 0x0f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x68, 0x6f, 0x75, 0x74, 0x72, 0x72,
0x72, 0x18, 0x69, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f,
0x6b, 0x2e, 0x53, 0x68, 0x6f, 0x75, 0x74, 0x72, 0x72, 0x72, 0x48, 0x00, 0x52, 0x0e, 0x61, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x53, 0x68, 0x6f, 0x75, 0x74, 0x72, 0x72, 0x72, 0x1a, 0x23, 0x0a, 0x07,
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, 0x1a, 0x2a, 0x0a, 0x07, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x12, 0x1f, 0x0a, 0x0b,
0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0a, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x55, 0x72, 0x6c, 0x1a, 0x46, 0x0a,
0x07, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x77, 0x65, 0x62, 0x68,
0x6f, 0x6f, 0x6b, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77,
0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x55, 0x72, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6d,
0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6d,
0x70, 0x6c, 0x61, 0x74, 0x65, 0x1a, 0x7c, 0x0a, 0x06, 0x47, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x12,
0x19, 0x0a, 0x08, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x07, 0x62, 0x61, 0x73, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f,
0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e,
0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, 0x64, 0x20, 0x01,
0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x12, 0x25, 0x0a, 0x0e,
0x74, 0x69, 0x74, 0x6c, 0x65, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, 0x65,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c,
0x61, 0x74, 0x65, 0x1a, 0x44, 0x0a, 0x05, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x12, 0x1f, 0x0a, 0x0b,
0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0a, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x55, 0x72, 0x6c, 0x12, 0x1a, 0x0a,
0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x1a, 0x49, 0x0a, 0x08, 0x53, 0x68, 0x6f,
0x75, 0x74, 0x72, 0x72, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x68, 0x6f, 0x75, 0x74, 0x72, 0x72,
0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x68, 0x6f,
0x75, 0x74, 0x72, 0x72, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6d, 0x70,
0x6c, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6d, 0x70,
0x6c, 0x61, 0x74, 0x65, 0x22, 0x93, 0x01, 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69,
0x6f, 0x6e, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x4f, 0x4e, 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x5f,
0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x43, 0x4f, 0x4e,
0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x41, 0x4e, 0x59, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52,
0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x43, 0x4f, 0x4e, 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x5f,
0x53, 0x4e, 0x41, 0x50, 0x53, 0x48, 0x4f, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x10, 0x02,
0x12, 0x1a, 0x0a, 0x16, 0x43, 0x4f, 0x4e, 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x4e,
0x41, 0x50, 0x53, 0x48, 0x4f, 0x54, 0x5f, 0x45, 0x4e, 0x44, 0x10, 0x03, 0x12, 0x1c, 0x0a, 0x18,
0x43, 0x4f, 0x4e, 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x4e, 0x41, 0x50, 0x53, 0x48,
0x4f, 0x54, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x04, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x22, 0x42, 0x0a, 0x04, 0x41, 0x75, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08,
0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08,
0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x1e, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72,
0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65,
0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0x51, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72,
0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
0x6e, 0x61, 0x6d, 0x65, 0x12, 0x29, 0x0a, 0x0f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64,
0x5f, 0x62, 0x63, 0x72, 0x79, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52,
0x0e, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x42, 0x63, 0x72, 0x79, 0x70, 0x74, 0x42,
0x0a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 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,
0x6f, 0x12, 0x02, 0x76, 0x31, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x22, 0xaa, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x14, 0x0a,
0x05, 0x6d, 0x6f, 0x64, 0x6e, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6d, 0x6f,
0x64, 0x6e, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06,
0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a,
0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73,
0x74, 0x12, 0x1e, 0x0a, 0x05, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x52, 0x05, 0x72, 0x65, 0x70, 0x6f,
0x73, 0x12, 0x1e, 0x0a, 0x05, 0x70, 0x6c, 0x61, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b,
0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x52, 0x05, 0x70, 0x6c, 0x61, 0x6e,
0x73, 0x12, 0x1c, 0x0a, 0x04, 0x61, 0x75, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x08, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x52, 0x04, 0x61, 0x75, 0x74, 0x68, 0x22,
0xe1, 0x01, 0x0a, 0x04, 0x52, 0x65, 0x70, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61,
0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61,
0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x04, 0x20,
0x03, 0x28, 0x09, 0x52, 0x03, 0x65, 0x6e, 0x76, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67,
0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x32,
0x0a, 0x0c, 0x70, 0x72, 0x75, 0x6e, 0x65, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x06,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x75, 0x6e, 0x65, 0x50,
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x0b, 0x70, 0x72, 0x75, 0x6e, 0x65, 0x50, 0x6f, 0x6c, 0x69,
0x63, 0x79, 0x12, 0x1e, 0x0a, 0x05, 0x68, 0x6f, 0x6f, 0x6b, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x52, 0x05, 0x68, 0x6f, 0x6f,
0x6b, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x75, 0x6e, 0x6c, 0x6f, 0x63,
0x6b, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x61, 0x75, 0x74, 0x6f, 0x55, 0x6e, 0x6c,
0x6f, 0x63, 0x6b, 0x22, 0xa1, 0x02, 0x0a, 0x04, 0x50, 0x6c, 0x61, 0x6e, 0x12, 0x0e, 0x0a, 0x02,
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04,
0x72, 0x65, 0x70, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x65, 0x70, 0x6f,
0x12, 0x1a, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01,
0x28, 0x08, 0x52, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05,
0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x70, 0x61, 0x74,
0x68, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x18, 0x05,
0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x12, 0x1c,
0x0a, 0x09, 0x69, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28,
0x09, 0x52, 0x09, 0x69, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04,
0x63, 0x72, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x72, 0x6f, 0x6e,
0x12, 0x31, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 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, 0x09, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74,
0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x05, 0x68, 0x6f, 0x6f, 0x6b, 0x73, 0x18, 0x08, 0x20, 0x03,
0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x52, 0x05, 0x68, 0x6f,
0x6f, 0x6b, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x66, 0x6c,
0x61, 0x67, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x62, 0x61, 0x63, 0x6b, 0x75,
0x70, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x22, 0xa0, 0x05, 0x0a, 0x0f, 0x52, 0x65, 0x74, 0x65,
0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x2c, 0x0a, 0x10, 0x6d,
0x61, 0x78, 0x5f, 0x75, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x55, 0x6e,
0x75, 0x73, 0x65, 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x22, 0x0a, 0x0b, 0x6b, 0x65, 0x65,
0x70, 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x42, 0x02,
0x18, 0x01, 0x52, 0x09, 0x6b, 0x65, 0x65, 0x70, 0x4c, 0x61, 0x73, 0x74, 0x4e, 0x12, 0x23, 0x0a,
0x0b, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x68, 0x6f, 0x75, 0x72, 0x6c, 0x79, 0x18, 0x03, 0x20, 0x01,
0x28, 0x05, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x6b, 0x65, 0x65, 0x70, 0x48, 0x6f, 0x75, 0x72,
0x6c, 0x79, 0x12, 0x21, 0x0a, 0x0a, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x64, 0x61, 0x69, 0x6c, 0x79,
0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x6b, 0x65, 0x65, 0x70,
0x44, 0x61, 0x69, 0x6c, 0x79, 0x12, 0x23, 0x0a, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x77, 0x65,
0x65, 0x6b, 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a,
0x6b, 0x65, 0x65, 0x70, 0x57, 0x65, 0x65, 0x6b, 0x6c, 0x79, 0x12, 0x25, 0x0a, 0x0c, 0x6b, 0x65,
0x65, 0x70, 0x5f, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x6c, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05,
0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x4d, 0x6f, 0x6e, 0x74, 0x68, 0x6c,
0x79, 0x12, 0x23, 0x0a, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x79, 0x65, 0x61, 0x72, 0x6c, 0x79,
0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x6b, 0x65, 0x65, 0x70,
0x59, 0x65, 0x61, 0x72, 0x6c, 0x79, 0x12, 0x34, 0x0a, 0x14, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x77,
0x69, 0x74, 0x68, 0x69, 0x6e, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08,
0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x12, 0x6b, 0x65, 0x65, 0x70, 0x57, 0x69,
0x74, 0x68, 0x69, 0x6e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x0a, 0x12,
0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x6c, 0x61, 0x73, 0x74,
0x5f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x0f, 0x70, 0x6f, 0x6c, 0x69,
0x63, 0x79, 0x4b, 0x65, 0x65, 0x70, 0x4c, 0x61, 0x73, 0x74, 0x4e, 0x12, 0x5a, 0x0a, 0x14, 0x70,
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x62, 0x75, 0x63, 0x6b, 0x65,
0x74, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x31, 0x2e, 0x52,
0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x54,
0x69, 0x6d, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74,
0x73, 0x48, 0x00, 0x52, 0x12, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x42,
0x75, 0x63, 0x6b, 0x65, 0x74, 0x65, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x6f, 0x6c, 0x69, 0x63,
0x79, 0x5f, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x61, 0x6c, 0x6c, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08,
0x48, 0x00, 0x52, 0x0d, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4b, 0x65, 0x65, 0x70, 0x41, 0x6c,
0x6c, 0x1a, 0x8c, 0x01, 0x0a, 0x12, 0x54, 0x69, 0x6d, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74,
0x65, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x6f, 0x75, 0x72,
0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x68, 0x6f, 0x75, 0x72, 0x6c, 0x79,
0x12, 0x14, 0x0a, 0x05, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52,
0x05, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x77, 0x65, 0x65, 0x6b, 0x6c, 0x79,
0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x77, 0x65, 0x65, 0x6b, 0x6c, 0x79, 0x12, 0x18,
0x0a, 0x07, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x6c, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52,
0x07, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x6c, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x79, 0x65, 0x61, 0x72,
0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x79, 0x65, 0x61, 0x72, 0x6c, 0x79,
0x42, 0x08, 0x0a, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x93, 0x01, 0x0a, 0x0b, 0x50,
0x72, 0x75, 0x6e, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x2c, 0x0a, 0x12, 0x6d, 0x61,
0x78, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x64, 0x61, 0x79, 0x73,
0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x6d, 0x61, 0x78, 0x46, 0x72, 0x65, 0x71, 0x75,
0x65, 0x6e, 0x63, 0x79, 0x44, 0x61, 0x79, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x6d, 0x61, 0x78, 0x5f,
0x75, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x64,
0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x6d, 0x61, 0x78, 0x55, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x50,
0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x61, 0x78, 0x5f, 0x75, 0x6e,
0x75, 0x73, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x65, 0x20, 0x01, 0x28, 0x05,
0x52, 0x0e, 0x6d, 0x61, 0x78, 0x55, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73,
0x22, 0xcc, 0x09, 0x0a, 0x04, 0x48, 0x6f, 0x6f, 0x6b, 0x12, 0x32, 0x0a, 0x0a, 0x63, 0x6f, 0x6e,
0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x12, 0x2e,
0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f,
0x6e, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2b, 0x0a,
0x08, 0x6f, 0x6e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32,
0x10, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x2e, 0x4f, 0x6e, 0x45, 0x72, 0x72, 0x6f,
0x72, 0x52, 0x07, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x39, 0x0a, 0x0e, 0x61, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x64, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x2e, 0x43, 0x6f, 0x6d,
0x6d, 0x61, 0x6e, 0x64, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f,
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x39, 0x0a, 0x0e, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x18, 0x65, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e,
0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x2e, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x48,
0x00, 0x52, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b,
0x12, 0x39, 0x0a, 0x0e, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f,
0x72, 0x64, 0x18, 0x66, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f,
0x6f, 0x6b, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x72, 0x64, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x36, 0x0a, 0x0d, 0x61,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x67, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x18, 0x67, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x2e, 0x47, 0x6f, 0x74,
0x69, 0x66, 0x79, 0x48, 0x00, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x47, 0x6f, 0x74,
0x69, 0x66, 0x79, 0x12, 0x33, 0x0a, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x6c,
0x61, 0x63, 0x6b, 0x18, 0x68, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x76, 0x31, 0x2e, 0x48,
0x6f, 0x6f, 0x6b, 0x2e, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x48, 0x00, 0x52, 0x0b, 0x61, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x12, 0x3c, 0x0a, 0x0f, 0x61, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x5f, 0x73, 0x68, 0x6f, 0x75, 0x74, 0x72, 0x72, 0x72, 0x18, 0x69, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x11, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x2e, 0x53, 0x68, 0x6f, 0x75,
0x74, 0x72, 0x72, 0x72, 0x48, 0x00, 0x52, 0x0e, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x68,
0x6f, 0x75, 0x74, 0x72, 0x72, 0x72, 0x1a, 0x23, 0x0a, 0x07, 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, 0x1a, 0xa1, 0x01, 0x0a, 0x07,
0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x12, 0x1f, 0x0a, 0x0b, 0x77, 0x65, 0x62, 0x68, 0x6f,
0x6f, 0x6b, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x65,
0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x55, 0x72, 0x6c, 0x12, 0x2f, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68,
0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f,
0x6f, 0x6b, 0x2e, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f,
0x64, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6d,
0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, 0x64, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6d,
0x70, 0x6c, 0x61, 0x74, 0x65, 0x22, 0x28, 0x0a, 0x06, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12,
0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03,
0x47, 0x45, 0x54, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x50, 0x4f, 0x53, 0x54, 0x10, 0x02, 0x1a,
0x46, 0x0a, 0x07, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x77, 0x65,
0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0a, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x55, 0x72, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x74,
0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74,
0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x1a, 0x7c, 0x0a, 0x06, 0x47, 0x6f, 0x74, 0x69, 0x66,
0x79, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x07, 0x62, 0x61, 0x73, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x14, 0x0a, 0x05,
0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b,
0x65, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, 0x64,
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x12, 0x25,
0x0a, 0x0e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65,
0x18, 0x65, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x54, 0x65, 0x6d,
0x70, 0x6c, 0x61, 0x74, 0x65, 0x1a, 0x44, 0x0a, 0x05, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x12, 0x1f,
0x0a, 0x0b, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x55, 0x72, 0x6c, 0x12,
0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x1a, 0x49, 0x0a, 0x08, 0x53,
0x68, 0x6f, 0x75, 0x74, 0x72, 0x72, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x68, 0x6f, 0x75, 0x74,
0x72, 0x72, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73,
0x68, 0x6f, 0x75, 0x74, 0x72, 0x72, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65,
0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65,
0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x22, 0x93, 0x01, 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x64, 0x69,
0x74, 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x4f, 0x4e, 0x44, 0x49, 0x54, 0x49, 0x4f,
0x4e, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x43,
0x4f, 0x4e, 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x41, 0x4e, 0x59, 0x5f, 0x45, 0x52, 0x52,
0x4f, 0x52, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x43, 0x4f, 0x4e, 0x44, 0x49, 0x54, 0x49, 0x4f,
0x4e, 0x5f, 0x53, 0x4e, 0x41, 0x50, 0x53, 0x48, 0x4f, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54,
0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x4f, 0x4e, 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x5f,
0x53, 0x4e, 0x41, 0x50, 0x53, 0x48, 0x4f, 0x54, 0x5f, 0x45, 0x4e, 0x44, 0x10, 0x03, 0x12, 0x1c,
0x0a, 0x18, 0x43, 0x4f, 0x4e, 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x4e, 0x41, 0x50,
0x53, 0x48, 0x4f, 0x54, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x04, 0x22, 0x47, 0x0a, 0x07,
0x4f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x13, 0x0a, 0x0f, 0x4f, 0x4e, 0x5f, 0x45, 0x52,
0x52, 0x4f, 0x52, 0x5f, 0x49, 0x47, 0x4e, 0x4f, 0x52, 0x45, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f,
0x4f, 0x4e, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10,
0x01, 0x12, 0x12, 0x0a, 0x0e, 0x4f, 0x4e, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x46, 0x41,
0x54, 0x41, 0x4c, 0x10, 0x02, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22,
0x42, 0x0a, 0x04, 0x41, 0x75, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62,
0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62,
0x6c, 0x65, 0x64, 0x12, 0x1e, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03,
0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05, 0x75, 0x73,
0x65, 0x72, 0x73, 0x22, 0x51, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e,
0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12,
0x29, 0x0a, 0x0f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x62, 0x63, 0x72, 0x79,
0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0e, 0x70, 0x61, 0x73, 0x73,
0x77, 0x6f, 0x72, 0x64, 0x42, 0x63, 0x72, 0x79, 0x70, 0x74, 0x42, 0x0a, 0x0a, 0x08, 0x70, 0x61,
0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 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 (
@@ -1498,48 +1637,52 @@ func file_v1_config_proto_rawDescGZIP() []byte {
return file_v1_config_proto_rawDescData
}
var file_v1_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_v1_config_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
var file_v1_config_proto_msgTypes = make([]protoimpl.MessageInfo, 15)
var file_v1_config_proto_goTypes = []interface{}{
(Hook_Condition)(0), // 0: v1.Hook.Condition
(*Config)(nil), // 1: v1.Config
(*Repo)(nil), // 2: v1.Repo
(*Plan)(nil), // 3: v1.Plan
(*RetentionPolicy)(nil), // 4: v1.RetentionPolicy
(*PrunePolicy)(nil), // 5: v1.PrunePolicy
(*Hook)(nil), // 6: v1.Hook
(*Auth)(nil), // 7: v1.Auth
(*User)(nil), // 8: v1.User
(*RetentionPolicy_TimeBucketedCounts)(nil), // 9: v1.RetentionPolicy.TimeBucketedCounts
(*Hook_Command)(nil), // 10: v1.Hook.Command
(*Hook_Webhook)(nil), // 11: v1.Hook.Webhook
(*Hook_Discord)(nil), // 12: v1.Hook.Discord
(*Hook_Gotify)(nil), // 13: v1.Hook.Gotify
(*Hook_Slack)(nil), // 14: v1.Hook.Slack
(*Hook_Shoutrrr)(nil), // 15: v1.Hook.Shoutrrr
(Hook_Condition)(0), // 0: v1.Hook.Condition
(Hook_OnError)(0), // 1: v1.Hook.OnError
(Hook_Webhook_Method)(0), // 2: v1.Hook.Webhook.Method
(*Config)(nil), // 3: v1.Config
(*Repo)(nil), // 4: v1.Repo
(*Plan)(nil), // 5: v1.Plan
(*RetentionPolicy)(nil), // 6: v1.RetentionPolicy
(*PrunePolicy)(nil), // 7: v1.PrunePolicy
(*Hook)(nil), // 8: v1.Hook
(*Auth)(nil), // 9: v1.Auth
(*User)(nil), // 10: v1.User
(*RetentionPolicy_TimeBucketedCounts)(nil), // 11: v1.RetentionPolicy.TimeBucketedCounts
(*Hook_Command)(nil), // 12: v1.Hook.Command
(*Hook_Webhook)(nil), // 13: v1.Hook.Webhook
(*Hook_Discord)(nil), // 14: v1.Hook.Discord
(*Hook_Gotify)(nil), // 15: v1.Hook.Gotify
(*Hook_Slack)(nil), // 16: v1.Hook.Slack
(*Hook_Shoutrrr)(nil), // 17: v1.Hook.Shoutrrr
}
var file_v1_config_proto_depIdxs = []int32{
2, // 0: v1.Config.repos:type_name -> v1.Repo
3, // 1: v1.Config.plans:type_name -> v1.Plan
7, // 2: v1.Config.auth:type_name -> v1.Auth
5, // 3: v1.Repo.prune_policy:type_name -> v1.PrunePolicy
6, // 4: v1.Repo.hooks:type_name -> v1.Hook
4, // 5: v1.Plan.retention:type_name -> v1.RetentionPolicy
6, // 6: v1.Plan.hooks:type_name -> v1.Hook
9, // 7: v1.RetentionPolicy.policy_time_bucketed:type_name -> v1.RetentionPolicy.TimeBucketedCounts
4, // 0: v1.Config.repos:type_name -> v1.Repo
5, // 1: v1.Config.plans:type_name -> v1.Plan
9, // 2: v1.Config.auth:type_name -> v1.Auth
7, // 3: v1.Repo.prune_policy:type_name -> v1.PrunePolicy
8, // 4: v1.Repo.hooks:type_name -> v1.Hook
6, // 5: v1.Plan.retention:type_name -> v1.RetentionPolicy
8, // 6: v1.Plan.hooks:type_name -> v1.Hook
11, // 7: v1.RetentionPolicy.policy_time_bucketed:type_name -> v1.RetentionPolicy.TimeBucketedCounts
0, // 8: v1.Hook.conditions:type_name -> v1.Hook.Condition
10, // 9: v1.Hook.action_command:type_name -> v1.Hook.Command
11, // 10: v1.Hook.action_webhook:type_name -> v1.Hook.Webhook
12, // 11: v1.Hook.action_discord:type_name -> v1.Hook.Discord
13, // 12: v1.Hook.action_gotify:type_name -> v1.Hook.Gotify
14, // 13: v1.Hook.action_slack:type_name -> v1.Hook.Slack
15, // 14: v1.Hook.action_shoutrrr:type_name -> v1.Hook.Shoutrrr
8, // 15: v1.Auth.users:type_name -> v1.User
16, // [16:16] is the sub-list for method output_type
16, // [16:16] is the sub-list for method input_type
16, // [16:16] is the sub-list for extension type_name
16, // [16:16] is the sub-list for extension extendee
0, // [0:16] is the sub-list for field type_name
1, // 9: v1.Hook.on_error:type_name -> v1.Hook.OnError
12, // 10: v1.Hook.action_command:type_name -> v1.Hook.Command
13, // 11: v1.Hook.action_webhook:type_name -> v1.Hook.Webhook
14, // 12: v1.Hook.action_discord:type_name -> v1.Hook.Discord
15, // 13: v1.Hook.action_gotify:type_name -> v1.Hook.Gotify
16, // 14: v1.Hook.action_slack:type_name -> v1.Hook.Slack
17, // 15: v1.Hook.action_shoutrrr:type_name -> v1.Hook.Shoutrrr
10, // 16: v1.Auth.users:type_name -> v1.User
2, // 17: v1.Hook.Webhook.method:type_name -> v1.Hook.Webhook.Method
18, // [18:18] is the sub-list for method output_type
18, // [18:18] is the sub-list for method input_type
18, // [18:18] is the sub-list for extension type_name
18, // [18:18] is the sub-list for extension extendee
0, // [0:18] is the sub-list for field type_name
}
func init() { file_v1_config_proto_init() }
@@ -1750,7 +1893,7 @@ func file_v1_config_proto_init() {
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_v1_config_proto_rawDesc,
NumEnums: 1,
NumEnums: 3,
NumMessages: 15,
NumExtensions: 0,
NumServices: 0,
+29
View File
@@ -0,0 +1,29 @@
package hook
import "fmt"
// HookErrorCancel requests that the calling operation cancel itself. It must be handled explicitly caller. Subsequent hooks will be skipped.
type HookErrorRequestCancel struct {
Err error
}
func (e HookErrorRequestCancel) Error() string {
return fmt.Sprintf("cancel: %v", e.Err.Error())
}
func (e HookErrorRequestCancel) Unwrap() error {
return e.Err
}
// HookErrorFatal stops evaluation of subsequent hooks and will propagate to the hook flow's caller
type HookErrorFatal struct {
Err error
}
func (e HookErrorFatal) Error() string {
return fmt.Sprintf("fatal: %v", e.Err.Error())
}
func (e HookErrorFatal) Unwrap() error {
return e.Err
}
+59 -18
View File
@@ -2,6 +2,7 @@ package hook
import (
"bytes"
"errors"
"fmt"
"io"
"slices"
@@ -34,15 +35,13 @@ func NewHookExecutor(oplog *oplog.OpLog, bigOutputStore *rotatinglog.RotatingLog
// ExecuteHooks schedules tasks for the hooks subscribed to the given event. The vars map is used to substitute variables
// Hooks are pulled both from the provided plan and from the repo config.
func (e *HookExecutor) ExecuteHooks(repo *v1.Repo, plan *v1.Plan, snapshotId string, events []v1.Hook_Condition, vars HookVars) {
func (e *HookExecutor) ExecuteHooks(repo *v1.Repo, plan *v1.Plan, events []v1.Hook_Condition, vars HookVars) error {
operationBase := v1.Operation{
Status: v1.OperationStatus_STATUS_INPROGRESS,
PlanId: plan.GetId(),
RepoId: repo.GetId(),
SnapshotId: snapshotId,
Status: v1.OperationStatus_STATUS_INPROGRESS,
PlanId: plan.GetId(),
RepoId: repo.GetId(),
}
vars.SnapshotId = snapshotId
vars.Repo = repo
vars.Plan = plan
vars.CurTime = time.Now()
@@ -56,6 +55,7 @@ func (e *HookExecutor) ExecuteHooks(repo *v1.Repo, plan *v1.Plan, snapshotId str
name := fmt.Sprintf("repo/%v/hook/%v", repo.Id, idx)
operation := proto.Clone(&operationBase).(*v1.Operation)
operation.DisplayMessage = "running " + name
operation.UnixTimeStartMs = curTimeMs()
operation.Op = &v1.Operation_OperationRunHook{
OperationRunHook: &v1.OperationRunHook{
@@ -63,7 +63,12 @@ func (e *HookExecutor) ExecuteHooks(repo *v1.Repo, plan *v1.Plan, snapshotId str
},
}
zap.L().Info("running hook", zap.String("plan", plan.Id), zap.Int64("opId", operation.Id), zap.String("hook", name))
e.executeHook(operation, h, event, vars)
if err := e.executeHook(operation, h, event, vars); err != nil {
zap.S().Errorf("error on repo hook %v on condition %v: %v", idx, event.String(), err)
if isHaltingError(err) {
return fmt.Errorf("repo hook %v on condition %v: %w", idx, event.String(), err)
}
}
}
for idx, hook := range plan.GetHooks() {
@@ -75,15 +80,23 @@ func (e *HookExecutor) ExecuteHooks(repo *v1.Repo, plan *v1.Plan, snapshotId str
name := fmt.Sprintf("plan/%v/hook/%v", plan.Id, idx)
operation := proto.Clone(&operationBase).(*v1.Operation)
operation.DisplayMessage = "running " + name
operation.UnixTimeStartMs = curTimeMs()
operation.Op = &v1.Operation_OperationRunHook{
OperationRunHook: &v1.OperationRunHook{
Name: name,
},
}
zap.L().Info("running hook", zap.String("plan", plan.Id), zap.Int64("opId", operation.Id), zap.String("hook", name))
e.executeHook(operation, h, event, vars)
if err := e.executeHook(operation, h, event, vars); err != nil {
zap.S().Errorf("error on plan hook %v on condition %v: %v", idx, event.String(), err)
if isHaltingError(err) {
return fmt.Errorf("plan hook %v on condition %v: %w", idx, event.String(), err)
}
}
}
return nil
}
func firstMatchingCondition(hook *Hook, events []v1.Hook_Condition) v1.Hook_Condition {
@@ -95,35 +108,43 @@ func firstMatchingCondition(hook *Hook, events []v1.Hook_Condition) v1.Hook_Cond
return v1.Hook_CONDITION_UNKNOWN
}
func (e *HookExecutor) executeHook(op *v1.Operation, hook *Hook, event v1.Hook_Condition, vars HookVars) {
func (e *HookExecutor) executeHook(op *v1.Operation, hook *Hook, event v1.Hook_Condition, vars HookVars) error {
if err := e.oplog.Add(op); err != nil {
zap.S().Errorf("execute hook: add operation: %v", err)
return
return errors.New("couldn't create operation")
}
output := &bytes.Buffer{}
fmt.Fprintf(output, "triggering condition: %v\n", event.String())
var retErr error
if err := hook.Do(event, vars, io.MultiWriter(output)); err != nil {
output.Write([]byte(fmt.Sprintf("Error: %v", err)))
op.DisplayMessage = err.Error()
op.Status = v1.OperationStatus_STATUS_ERROR
zap.S().Errorf("execute hook: %v", err)
err = applyHookErrorPolicy(hook.OnError, err)
var cancelErr *HookErrorRequestCancel
if errors.As(err, &cancelErr) {
// if it was a cancel then it successfully indicated it's intent to the caller
// no error should be displayed in the UI.
op.Status = v1.OperationStatus_STATUS_SUCCESS
} else {
op.Status = v1.OperationStatus_STATUS_ERROR
}
retErr = err
} else {
op.Status = v1.OperationStatus_STATUS_SUCCESS
}
outputRef, err := e.logStore.Write(output.Bytes())
if err != nil {
zap.S().Errorf("execute hook: write log: %v", err)
return
retErr = errors.Join(retErr, fmt.Errorf("write logstore: %w", err))
}
op.Op.(*v1.Operation_OperationRunHook).OperationRunHook.OutputLogref = outputRef
op.Logref = outputRef
op.UnixTimeEndMs = curTimeMs()
if err := e.oplog.Update(op); err != nil {
zap.S().Errorf("execute hook: update operation: %v", err)
return
retErr = errors.Join(retErr, fmt.Errorf("update oplog: %w", err))
}
return retErr
}
func curTimeMs() int64 {
@@ -175,3 +196,23 @@ func (h *Hook) renderTemplateOrDefault(template string, defaultTmpl string, vars
}
return h.renderTemplate(template, vars)
}
func applyHookErrorPolicy(onError v1.Hook_OnError, err error) error {
if err == nil || errors.As(err, &HookErrorFatal{}) || errors.As(err, &HookErrorRequestCancel{}) {
return err
}
if onError == v1.Hook_ON_ERROR_CANCEL {
return &HookErrorRequestCancel{Err: err}
} else if onError == v1.Hook_ON_ERROR_FATAL {
return &HookErrorFatal{Err: err}
}
return err
}
// isHaltingError returns true if the error is a fatal error or a request to cancel the operation
func isHaltingError(err error) bool {
var fatalErr *HookErrorFatal
var cancelErr *HookErrorRequestCancel
return errors.As(err, &fatalErr) || errors.As(err, &cancelErr)
}
+28
View File
@@ -2,6 +2,7 @@ package hook
import (
"bytes"
"errors"
"os/exec"
"runtime"
"testing"
@@ -56,3 +57,30 @@ exit $counter`,
t.Fatalf("expected exit code 3, got %v", err.(*exec.ExitError).ExitCode())
}
}
func TestCommandHookErrorHandling(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("skipping test on windows")
}
hook := Hook(v1.Hook{
Conditions: []v1.Hook_Condition{
v1.Hook_CONDITION_SNAPSHOT_START,
},
Action: &v1.Hook_ActionCommand{
ActionCommand: &v1.Hook_Command{
Command: "exit 1",
},
},
OnError: v1.Hook_ON_ERROR_CANCEL,
})
err := applyHookErrorPolicy(hook.OnError, hook.Do(v1.Hook_CONDITION_SNAPSHOT_START, HookVars{}, &bytes.Buffer{}))
if err == nil {
t.Fatal("expected error")
}
var cancelErr *HookErrorRequestCancel
if !errors.As(err, &cancelErr) {
t.Fatalf("expected HookErrorRequestCancel, got %v", err)
}
}
+32 -7
View File
@@ -108,11 +108,30 @@ func backupHelper(ctx context.Context, t Task, orchestrator *Orchestrator, plan
return fmt.Errorf("couldn't get repo %q: %w", plan.Repo, err)
}
orchestrator.hookExecutor.ExecuteHooks(repo.Config(), plan, "", []v1.Hook_Condition{
// Run start hooks e.g. preflight checks and backup start notifications.
if err := orchestrator.hookExecutor.ExecuteHooks(repo.Config(), plan, []v1.Hook_Condition{
v1.Hook_CONDITION_SNAPSHOT_START,
}, hook.HookVars{
Task: t.Name(),
})
}); err != nil {
var cancelErr *hook.HookErrorRequestCancel
if errors.As(err, &cancelErr) {
op.Status = v1.OperationStatus_STATUS_USER_CANCELLED // user visible cancelled status
op.DisplayMessage = err.Error()
return nil
}
// If the snapshot start hook fails we trigger error notification hooks.
retErr := fmt.Errorf("hook failed: %w", err)
_ = orchestrator.hookExecutor.ExecuteHooks(repo.Config(), plan, []v1.Hook_Condition{
v1.Hook_CONDITION_ANY_ERROR,
}, hook.HookVars{
Task: t.Name(),
Error: retErr.Error(),
})
return retErr
}
var sendWg sync.WaitGroup
lastSent := time.Now() // debounce progress updates, these can endup being very frequent.
@@ -160,24 +179,30 @@ func backupHelper(ctx context.Context, t Task, orchestrator *Orchestrator, plan
}()
})
sendWg.Wait()
if summary == nil {
summary = &restic.BackupProgressEntry{}
}
vars := hook.HookVars{
Task: t.Name(),
SnapshotStats: summary,
SnapshotId: summary.SnapshotId,
}
if err != nil {
vars.Error = err.Error()
orchestrator.hookExecutor.ExecuteHooks(repo.Config(), plan, "", []v1.Hook_Condition{
v1.Hook_CONDITION_SNAPSHOT_ERROR, v1.Hook_CONDITION_ANY_ERROR,
}, vars)
if !errors.Is(err, restic.ErrPartialBackup) {
_ = orchestrator.hookExecutor.ExecuteHooks(repo.Config(), plan, []v1.Hook_Condition{
v1.Hook_CONDITION_SNAPSHOT_ERROR, v1.Hook_CONDITION_ANY_ERROR,
}, vars)
return fmt.Errorf("repo.Backup for repo %q: %w", plan.Repo, err)
}
op.Status = v1.OperationStatus_STATUS_WARNING
op.DisplayMessage = "Partial backup, some files may not have been read completely."
}
orchestrator.hookExecutor.ExecuteHooks(repo.Config(), plan, summary.SnapshotId, []v1.Hook_Condition{
orchestrator.hookExecutor.ExecuteHooks(repo.Config(), plan, []v1.Hook_Condition{
v1.Hook_CONDITION_SNAPSHOT_END,
}, vars)
+4 -3
View File
@@ -109,11 +109,12 @@ func (t *ForgetTask) Run(ctx context.Context) error {
return err
}); err != nil {
repo, _ := t.orch.GetRepo(t.plan.Repo)
t.orch.hookExecutor.ExecuteHooks(repo.Config(), t.plan, t.linkSnapshot, []v1.Hook_Condition{
_ = t.orch.hookExecutor.ExecuteHooks(repo.Config(), t.plan, []v1.Hook_Condition{
v1.Hook_CONDITION_ANY_ERROR,
}, hook.HookVars{
Task: t.Name(),
Error: err.Error(),
Task: t.Name(),
Error: err.Error(),
SnapshotId: t.linkSnapshot,
})
}
return nil
+1 -1
View File
@@ -46,7 +46,7 @@ func (t *IndexSnapshotsTask) Next(now time.Time) *time.Time {
func (t *IndexSnapshotsTask) Run(ctx context.Context) error {
if err := indexSnapshotsHelper(ctx, t.orchestrator, t.repoId); err != nil {
repo, _ := t.orchestrator.GetRepo(t.repoId)
t.orchestrator.hookExecutor.ExecuteHooks(repo.Config(), nil, "", []v1.Hook_Condition{
t.orchestrator.hookExecutor.ExecuteHooks(repo.Config(), nil, []v1.Hook_Condition{
v1.Hook_CONDITION_ANY_ERROR,
}, hook.HookVars{
Task: t.Name(),
+1 -1
View File
@@ -168,7 +168,7 @@ func (t *PruneTask) Run(ctx context.Context) error {
return nil
}); err != nil {
repo, _ := t.orch.GetRepo(t.plan.Repo)
t.orch.hookExecutor.ExecuteHooks(repo.Config(), t.plan, "", []v1.Hook_Condition{
_ = t.orch.hookExecutor.ExecuteHooks(repo.Config(), t.plan, []v1.Hook_Condition{
v1.Hook_CONDITION_ANY_ERROR,
}, hook.HookVars{
Task: t.Name(),
+4 -3
View File
@@ -112,11 +112,12 @@ func (t *RestoreTask) Run(ctx context.Context) error {
}); err != nil {
if t.restoreOpts.RepoId != "" {
repo, _ := t.orch.GetRepo(t.restoreOpts.RepoId)
t.orch.hookExecutor.ExecuteHooks(repo.Config(), nil, t.restoreOpts.SnapshotId, []v1.Hook_Condition{
_ = t.orch.hookExecutor.ExecuteHooks(repo.Config(), nil, []v1.Hook_Condition{
v1.Hook_CONDITION_ANY_ERROR,
}, hook.HookVars{
Task: t.Name(),
Error: err.Error(),
Task: t.Name(),
Error: err.Error(),
SnapshotId: t.restoreOpts.SnapshotId,
})
}
return err
+1 -1
View File
@@ -76,7 +76,7 @@ func (t *StatsTask) Run(ctx context.Context) error {
}); err != nil {
repo, _ := t.orch.GetRepo(t.repoId)
plan, _ := t.orch.GetPlan(t.planId)
t.orch.hookExecutor.ExecuteHooks(repo.Config(), plan, "", []v1.Hook_Condition{
_ = t.orch.hookExecutor.ExecuteHooks(repo.Config(), plan, []v1.Hook_Condition{
v1.Hook_CONDITION_ANY_ERROR,
}, hook.HookVars{
Task: t.Name(),
+2
View File
@@ -19,3 +19,5 @@ message StringList {
message Int64Value {
int64 value = 1;
}
message Empty {}
+16
View File
@@ -4,6 +4,8 @@ package v1;
option go_package = "github.com/garethgeorge/backrest/gen/go/v1";
import "google/protobuf/empty.proto";
// Config is the top level config object for restic UI.
message Config {
// modification number, used for read-modify-write consistency in the UI. Incremented on every write.
@@ -83,7 +85,14 @@ message Hook {
CONDITION_SNAPSHOT_ERROR = 4; // snapshot failed.
}
enum OnError {
ON_ERROR_IGNORE = 0;
ON_ERROR_CANCEL = 1; // cancels the operation and skips subsequent hooks
ON_ERROR_FATAL = 2; // fails the operation and subsequent hooks
}
repeated Condition conditions = 1 [json_name="conditions"];
OnError on_error = 2 [json_name="onError"];
oneof action {
Command action_command = 100 [json_name="actionCommand"];
@@ -100,6 +109,13 @@ message Hook {
message Webhook {
string webhook_url = 1 [json_name="webhookUrl"];
enum Method {
UNKNOWN = 0;
GET = 1;
POST = 2;
}
Method method = 2 [json_name="method"];
string template = 100 [json_name="template"];
}
message Discord {
-3
View File
@@ -1,3 +0,0 @@
syntax = "proto3";
package v1;
+31
View File
@@ -154,3 +154,34 @@ export class Int64Value extends Message<Int64Value> {
}
}
/**
* @generated from message types.Empty
*/
export class Empty extends Message<Empty> {
constructor(data?: PartialMessage<Empty>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime: typeof proto3 = proto3;
static readonly typeName = "types.Empty";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): Empty {
return new Empty().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): Empty {
return new Empty().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): Empty {
return new Empty().fromJsonString(jsonString, options);
}
static equals(a: Empty | PlainMessage<Empty> | undefined, b: Empty | PlainMessage<Empty> | undefined): boolean {
return proto3.util.equals(Empty, a, b);
}
}
+74
View File
@@ -535,6 +535,11 @@ export class Hook extends Message<Hook> {
*/
conditions: Hook_Condition[] = [];
/**
* @generated from field: v1.Hook.OnError on_error = 2;
*/
onError = Hook_OnError.IGNORE;
/**
* @generated from oneof v1.Hook.action
*/
@@ -585,6 +590,7 @@ export class Hook extends Message<Hook> {
static readonly typeName = "v1.Hook";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "conditions", kind: "enum", T: proto3.getEnumType(Hook_Condition), repeated: true },
{ no: 2, name: "on_error", kind: "enum", T: proto3.getEnumType(Hook_OnError) },
{ no: 100, name: "action_command", kind: "message", T: Hook_Command, oneof: "action" },
{ no: 101, name: "action_webhook", kind: "message", T: Hook_Webhook, oneof: "action" },
{ no: 102, name: "action_discord", kind: "message", T: Hook_Discord, oneof: "action" },
@@ -656,6 +662,36 @@ proto3.util.setEnumType(Hook_Condition, "v1.Hook.Condition", [
{ no: 4, name: "CONDITION_SNAPSHOT_ERROR" },
]);
/**
* @generated from enum v1.Hook.OnError
*/
export enum Hook_OnError {
/**
* @generated from enum value: ON_ERROR_IGNORE = 0;
*/
IGNORE = 0,
/**
* cancels the operation and skips subsequent hooks
*
* @generated from enum value: ON_ERROR_CANCEL = 1;
*/
CANCEL = 1,
/**
* fails the operation and subsequent hooks
*
* @generated from enum value: ON_ERROR_FATAL = 2;
*/
FATAL = 2,
}
// Retrieve enum metadata with: proto3.getEnumType(Hook_OnError)
proto3.util.setEnumType(Hook_OnError, "v1.Hook.OnError", [
{ no: 0, name: "ON_ERROR_IGNORE" },
{ no: 1, name: "ON_ERROR_CANCEL" },
{ no: 2, name: "ON_ERROR_FATAL" },
]);
/**
* @generated from message v1.Hook.Command
*/
@@ -702,6 +738,16 @@ export class Hook_Webhook extends Message<Hook_Webhook> {
*/
webhookUrl = "";
/**
* @generated from field: v1.Hook.Webhook.Method method = 2;
*/
method = Hook_Webhook_Method.UNKNOWN;
/**
* @generated from field: string template = 100;
*/
template = "";
constructor(data?: PartialMessage<Hook_Webhook>) {
super();
proto3.util.initPartial(data, this);
@@ -711,6 +757,8 @@ export class Hook_Webhook extends Message<Hook_Webhook> {
static readonly typeName = "v1.Hook.Webhook";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "webhook_url", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 2, name: "method", kind: "enum", T: proto3.getEnumType(Hook_Webhook_Method) },
{ no: 100, name: "template", kind: "scalar", T: 9 /* ScalarType.STRING */ },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): Hook_Webhook {
@@ -730,6 +778,32 @@ export class Hook_Webhook extends Message<Hook_Webhook> {
}
}
/**
* @generated from enum v1.Hook.Webhook.Method
*/
export enum Hook_Webhook_Method {
/**
* @generated from enum value: UNKNOWN = 0;
*/
UNKNOWN = 0,
/**
* @generated from enum value: GET = 1;
*/
GET = 1,
/**
* @generated from enum value: POST = 2;
*/
POST = 2,
}
// Retrieve enum metadata with: proto3.getEnumType(Hook_Webhook_Method)
proto3.util.setEnumType(Hook_Webhook_Method, "v1.Hook.Webhook.Method", [
{ no: 0, name: "UNKNOWN" },
{ no: 1, name: "GET" },
{ no: 2, name: "POST" },
]);
/**
* @generated from message v1.Hook.Discord
*/
+27 -8
View File
@@ -1,8 +1,9 @@
import React, { useState } from 'react';
import { Hook, Hook_Command, Hook_Condition, Hook_Discord, Hook_Gotify, Hook_Webhook } from '../../gen/ts/v1/config_pb';
import { Hook, Hook_Command, Hook_Condition, Hook_Discord, Hook_Gotify, Hook_OnError, Hook_Webhook } from '../../gen/ts/v1/config_pb';
import { Button, Card, Collapse, CollapseProps, Form, FormListFieldData, Input, Popover, Radio, Row, Select, Tooltip } from 'antd';
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
import { Rule } from 'antd/es/form';
import { proto3 } from '@bufbuild/protobuf';
export interface HookFormData {
hooks: {
@@ -64,7 +65,7 @@ export const HooksFormList = () => {
const hookData = form.getFieldValue(["hooks", field.name]) as HookFields;
return <Card key={index} title={<>
Hook {index} <small>{findHookTypeName(hookData)}</small>
Hook {index} {findHookTypeName(hookData)}
<MinusCircleOutlined
className="dynamic-delete-button"
onClick={() => remove(field.name)}
@@ -78,12 +79,7 @@ export const HooksFormList = () => {
allowClear
style={{ width: '100%' }}
placeholder="Runs when..."
options={[
{ label: "On Finish Snapshot", value: Hook_Condition.SNAPSHOT_END },
{ label: "On Start Snapshot", value: Hook_Condition.SNAPSHOT_START },
{ label: "On Snapshot Error", value: Hook_Condition.SNAPSHOT_ERROR },
{ label: "On Any Error", value: Hook_Condition.ANY_ERROR },
]}
options={proto3.getEnumType(Hook_Condition).values.map(v => ({ label: v.name, value: v.name }))}
/>
</Form.Item>
<Form.Item shouldUpdate={(prevValues, curValues) => {
@@ -140,6 +136,7 @@ const hookTypes: {
<Form.Item name={[field.name, "actionCommand", "command"]} rules={[requiredField("command is required")]}>
<Input.TextArea style={{ width: "100%", fontFamily: "monospace" }} />
</Form.Item>
<ItemOnErrorSelector field={field} />
</>
}
},
@@ -271,4 +268,26 @@ const HookBuilder = ({ field }: { field: FormListFieldData }) => {
return <p>Unknown hook type</p>;
}
const ItemOnErrorSelector = ({ field }: { field: FormListFieldData }) => {
return <>
<Tooltip title={<>
What happens when the hook fails (currently only has effect on backup start hooks)
<ul>
<li>IGNORE - the failure is ignored, subsequent hooks and the backup operation will run as normal.</li>
<li>FATAL - stops the backup with an error status (triggers an error notification). Skips running all subsequent hooks.</li>
<li>CANCEL - marks the backup as cancelled but does not trigger any error notification. Skips running all subsequent hooks.</li>
</ul>
</>}>Error Behavior:
</Tooltip>
<Form.Item name={[field.name, "onError"]}>
<Select
allowClear
style={{ width: '100%' }}
placeholder={"Specify what happens when this hook fails..."}
options={proto3.getEnumType(Hook_OnError).values.map(v => ({ label: v.name, value: v.name }))}
/>
</Form.Item>
</>
}
const requiredField = (message: string, extra?: Rule) => ({ required: true, message: message });
+3 -24
View File
@@ -121,7 +121,7 @@ export const OperationRow = ({
visible={true} footer={null} onCancel={() => { showModal(null); }}>
<BigOperationDataVerbatim logref={operation.logref!} />
</Modal>);
}}>[View Restic Logs]</Button>
}}>[View Logs]</Button>
</small >
</>
}
@@ -194,15 +194,14 @@ export const OperationRow = ({
</>
);
} else if (operation.op.case === "operationRunHook") {
const hook = operation.op.value;
body = <RunHookOperationStatus op={operation} />
body = <></>
}
const children = [];
if (operation.displayMessage) {
children.push(<>
<pre>{details.state}: {operation.displayMessage}</pre>
<pre>{details.state ? details.state + ": " : null}{operation.displayMessage}</pre>
</>);
}
@@ -410,26 +409,6 @@ const ForgetOperationDetails = ({ forgetOp }: { forgetOp: OperationForget }) =>
);
}
const RunHookOperationStatus = ({ op }: { op: Operation }) => {
if (op.op.case !== "operationRunHook") {
return <>Wrong operation type</>;
}
const hook = op.op.value;
return <>
<Collapse size="small" destroyInactivePanel items={[
{
key: 1,
label: "Logs for hook " + hook.name,
children: <>
<BigOperationDataVerbatim logref={hook.outputLogref} />
</>
},
]} />
</>
}
// TODO: refactor this to use the provider pattern
const BigOperationDataVerbatim = ({ logref }: { logref: string }) => {
const [output, setOutput] = useState<string | undefined>(undefined);