diff --git a/agent/proto/agent.pb.go b/agent/proto/agent.pb.go index 11d7fe59a1bfd..7e3f824d27344 100644 --- a/agent/proto/agent.pb.go +++ b/agent/proto/agent.pb.go @@ -620,6 +620,101 @@ func (Connection_Type) EnumDescriptor() ([]byte, []int) { return file_agent_proto_agent_proto_rawDescGZIP(), []int{33, 1} } +type CreateSubAgentRequest_App_OpenIn int32 + +const ( + CreateSubAgentRequest_App_SLIM_WINDOW CreateSubAgentRequest_App_OpenIn = 0 + CreateSubAgentRequest_App_TAB CreateSubAgentRequest_App_OpenIn = 1 +) + +// Enum value maps for CreateSubAgentRequest_App_OpenIn. +var ( + CreateSubAgentRequest_App_OpenIn_name = map[int32]string{ + 0: "SLIM_WINDOW", + 1: "TAB", + } + CreateSubAgentRequest_App_OpenIn_value = map[string]int32{ + "SLIM_WINDOW": 0, + "TAB": 1, + } +) + +func (x CreateSubAgentRequest_App_OpenIn) Enum() *CreateSubAgentRequest_App_OpenIn { + p := new(CreateSubAgentRequest_App_OpenIn) + *p = x + return p +} + +func (x CreateSubAgentRequest_App_OpenIn) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CreateSubAgentRequest_App_OpenIn) Descriptor() protoreflect.EnumDescriptor { + return file_agent_proto_agent_proto_enumTypes[11].Descriptor() +} + +func (CreateSubAgentRequest_App_OpenIn) Type() protoreflect.EnumType { + return &file_agent_proto_agent_proto_enumTypes[11] +} + +func (x CreateSubAgentRequest_App_OpenIn) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use CreateSubAgentRequest_App_OpenIn.Descriptor instead. +func (CreateSubAgentRequest_App_OpenIn) EnumDescriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{36, 0, 0} +} + +type CreateSubAgentRequest_App_Share int32 + +const ( + CreateSubAgentRequest_App_OWNER CreateSubAgentRequest_App_Share = 0 + CreateSubAgentRequest_App_AUTHENTICATED CreateSubAgentRequest_App_Share = 1 + CreateSubAgentRequest_App_PUBLIC CreateSubAgentRequest_App_Share = 2 +) + +// Enum value maps for CreateSubAgentRequest_App_Share. +var ( + CreateSubAgentRequest_App_Share_name = map[int32]string{ + 0: "OWNER", + 1: "AUTHENTICATED", + 2: "PUBLIC", + } + CreateSubAgentRequest_App_Share_value = map[string]int32{ + "OWNER": 0, + "AUTHENTICATED": 1, + "PUBLIC": 2, + } +) + +func (x CreateSubAgentRequest_App_Share) Enum() *CreateSubAgentRequest_App_Share { + p := new(CreateSubAgentRequest_App_Share) + *p = x + return p +} + +func (x CreateSubAgentRequest_App_Share) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CreateSubAgentRequest_App_Share) Descriptor() protoreflect.EnumDescriptor { + return file_agent_proto_agent_proto_enumTypes[12].Descriptor() +} + +func (CreateSubAgentRequest_App_Share) Type() protoreflect.EnumType { + return &file_agent_proto_agent_proto_enumTypes[12] +} + +func (x CreateSubAgentRequest_App_Share) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use CreateSubAgentRequest_App_Share.Descriptor instead. +func (CreateSubAgentRequest_App_Share) EnumDescriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{36, 0, 1} +} + type WorkspaceApp struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2892,10 +2987,11 @@ type CreateSubAgentRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Directory string `protobuf:"bytes,2,opt,name=directory,proto3" json:"directory,omitempty"` - Architecture string `protobuf:"bytes,3,opt,name=architecture,proto3" json:"architecture,omitempty"` - OperatingSystem string `protobuf:"bytes,4,opt,name=operating_system,json=operatingSystem,proto3" json:"operating_system,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Directory string `protobuf:"bytes,2,opt,name=directory,proto3" json:"directory,omitempty"` + Architecture string `protobuf:"bytes,3,opt,name=architecture,proto3" json:"architecture,omitempty"` + OperatingSystem string `protobuf:"bytes,4,opt,name=operating_system,json=operatingSystem,proto3" json:"operating_system,omitempty"` + Apps []*CreateSubAgentRequest_App `protobuf:"bytes,5,rep,name=apps,proto3" json:"apps,omitempty"` } func (x *CreateSubAgentRequest) Reset() { @@ -2958,12 +3054,20 @@ func (x *CreateSubAgentRequest) GetOperatingSystem() string { return "" } +func (x *CreateSubAgentRequest) GetApps() []*CreateSubAgentRequest_App { + if x != nil { + return x.Apps + } + return nil +} + type CreateSubAgentResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Agent *SubAgent `protobuf:"bytes,1,opt,name=agent,proto3" json:"agent,omitempty"` + Agent *SubAgent `protobuf:"bytes,1,opt,name=agent,proto3" json:"agent,omitempty"` + AppCreationErrors []*CreateSubAgentResponse_AppCreationError `protobuf:"bytes,2,rep,name=app_creation_errors,json=appCreationErrors,proto3" json:"app_creation_errors,omitempty"` } func (x *CreateSubAgentResponse) Reset() { @@ -3005,6 +3109,13 @@ func (x *CreateSubAgentResponse) GetAgent() *SubAgent { return nil } +func (x *CreateSubAgentResponse) GetAppCreationErrors() []*CreateSubAgentResponse_AppCreationError { + if x != nil { + return x.AppCreationErrors + } + return nil +} + type DeleteSubAgentRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3907,6 +4018,275 @@ func (x *PushResourcesMonitoringUsageRequest_Datapoint_VolumeUsage) GetTotal() i return 0 } +type CreateSubAgentRequest_App struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Slug string `protobuf:"bytes,1,opt,name=slug,proto3" json:"slug,omitempty"` + Command *string `protobuf:"bytes,2,opt,name=command,proto3,oneof" json:"command,omitempty"` + DisplayName *string `protobuf:"bytes,3,opt,name=display_name,json=displayName,proto3,oneof" json:"display_name,omitempty"` + External *bool `protobuf:"varint,4,opt,name=external,proto3,oneof" json:"external,omitempty"` + Group *string `protobuf:"bytes,5,opt,name=group,proto3,oneof" json:"group,omitempty"` + Healthcheck *CreateSubAgentRequest_App_Healthcheck `protobuf:"bytes,6,opt,name=healthcheck,proto3,oneof" json:"healthcheck,omitempty"` + Hidden *bool `protobuf:"varint,7,opt,name=hidden,proto3,oneof" json:"hidden,omitempty"` + Icon *string `protobuf:"bytes,8,opt,name=icon,proto3,oneof" json:"icon,omitempty"` + OpenIn *CreateSubAgentRequest_App_OpenIn `protobuf:"varint,9,opt,name=open_in,json=openIn,proto3,enum=coder.agent.v2.CreateSubAgentRequest_App_OpenIn,oneof" json:"open_in,omitempty"` + Order *int32 `protobuf:"varint,10,opt,name=order,proto3,oneof" json:"order,omitempty"` + Share *CreateSubAgentRequest_App_Share `protobuf:"varint,11,opt,name=share,proto3,enum=coder.agent.v2.CreateSubAgentRequest_App_Share,oneof" json:"share,omitempty"` + Subdomain *bool `protobuf:"varint,12,opt,name=subdomain,proto3,oneof" json:"subdomain,omitempty"` + Url *string `protobuf:"bytes,13,opt,name=url,proto3,oneof" json:"url,omitempty"` +} + +func (x *CreateSubAgentRequest_App) Reset() { + *x = CreateSubAgentRequest_App{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[56] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateSubAgentRequest_App) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateSubAgentRequest_App) ProtoMessage() {} + +func (x *CreateSubAgentRequest_App) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[56] + 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 CreateSubAgentRequest_App.ProtoReflect.Descriptor instead. +func (*CreateSubAgentRequest_App) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{36, 0} +} + +func (x *CreateSubAgentRequest_App) GetSlug() string { + if x != nil { + return x.Slug + } + return "" +} + +func (x *CreateSubAgentRequest_App) GetCommand() string { + if x != nil && x.Command != nil { + return *x.Command + } + return "" +} + +func (x *CreateSubAgentRequest_App) GetDisplayName() string { + if x != nil && x.DisplayName != nil { + return *x.DisplayName + } + return "" +} + +func (x *CreateSubAgentRequest_App) GetExternal() bool { + if x != nil && x.External != nil { + return *x.External + } + return false +} + +func (x *CreateSubAgentRequest_App) GetGroup() string { + if x != nil && x.Group != nil { + return *x.Group + } + return "" +} + +func (x *CreateSubAgentRequest_App) GetHealthcheck() *CreateSubAgentRequest_App_Healthcheck { + if x != nil { + return x.Healthcheck + } + return nil +} + +func (x *CreateSubAgentRequest_App) GetHidden() bool { + if x != nil && x.Hidden != nil { + return *x.Hidden + } + return false +} + +func (x *CreateSubAgentRequest_App) GetIcon() string { + if x != nil && x.Icon != nil { + return *x.Icon + } + return "" +} + +func (x *CreateSubAgentRequest_App) GetOpenIn() CreateSubAgentRequest_App_OpenIn { + if x != nil && x.OpenIn != nil { + return *x.OpenIn + } + return CreateSubAgentRequest_App_SLIM_WINDOW +} + +func (x *CreateSubAgentRequest_App) GetOrder() int32 { + if x != nil && x.Order != nil { + return *x.Order + } + return 0 +} + +func (x *CreateSubAgentRequest_App) GetShare() CreateSubAgentRequest_App_Share { + if x != nil && x.Share != nil { + return *x.Share + } + return CreateSubAgentRequest_App_OWNER +} + +func (x *CreateSubAgentRequest_App) GetSubdomain() bool { + if x != nil && x.Subdomain != nil { + return *x.Subdomain + } + return false +} + +func (x *CreateSubAgentRequest_App) GetUrl() string { + if x != nil && x.Url != nil { + return *x.Url + } + return "" +} + +type CreateSubAgentRequest_App_Healthcheck struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Interval int32 `protobuf:"varint,1,opt,name=interval,proto3" json:"interval,omitempty"` + Threshold int32 `protobuf:"varint,2,opt,name=threshold,proto3" json:"threshold,omitempty"` + Url string `protobuf:"bytes,3,opt,name=url,proto3" json:"url,omitempty"` +} + +func (x *CreateSubAgentRequest_App_Healthcheck) Reset() { + *x = CreateSubAgentRequest_App_Healthcheck{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[57] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateSubAgentRequest_App_Healthcheck) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateSubAgentRequest_App_Healthcheck) ProtoMessage() {} + +func (x *CreateSubAgentRequest_App_Healthcheck) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[57] + 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 CreateSubAgentRequest_App_Healthcheck.ProtoReflect.Descriptor instead. +func (*CreateSubAgentRequest_App_Healthcheck) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{36, 0, 0} +} + +func (x *CreateSubAgentRequest_App_Healthcheck) GetInterval() int32 { + if x != nil { + return x.Interval + } + return 0 +} + +func (x *CreateSubAgentRequest_App_Healthcheck) GetThreshold() int32 { + if x != nil { + return x.Threshold + } + return 0 +} + +func (x *CreateSubAgentRequest_App_Healthcheck) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +type CreateSubAgentResponse_AppCreationError struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Index int32 `protobuf:"varint,1,opt,name=index,proto3" json:"index,omitempty"` + Field *string `protobuf:"bytes,2,opt,name=field,proto3,oneof" json:"field,omitempty"` + Error string `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *CreateSubAgentResponse_AppCreationError) Reset() { + *x = CreateSubAgentResponse_AppCreationError{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[58] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateSubAgentResponse_AppCreationError) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateSubAgentResponse_AppCreationError) ProtoMessage() {} + +func (x *CreateSubAgentResponse_AppCreationError) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[58] + 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 CreateSubAgentResponse_AppCreationError.ProtoReflect.Descriptor instead. +func (*CreateSubAgentResponse_AppCreationError) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{37, 0} +} + +func (x *CreateSubAgentResponse_AppCreationError) GetIndex() int32 { + if x != nil { + return x.Index + } + return 0 +} + +func (x *CreateSubAgentResponse_AppCreationError) GetField() string { + if x != nil && x.Field != nil { + return *x.Field + } + return "" +} + +func (x *CreateSubAgentResponse_AppCreationError) GetError() string { + if x != nil { + return x.Error + } + return "" +} + var File_agent_proto_agent_proto protoreflect.FileDescriptor var file_agent_proto_agent_proto_rawDesc = []byte{ @@ -4433,7 +4813,7 @@ var file_agent_proto_agent_proto_rawDesc = []byte{ 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, - 0x98, 0x01, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, 0x41, 0x67, 0x65, + 0xbb, 0x08, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, @@ -4442,137 +4822,208 @@ var file_agent_proto_agent_proto_rawDesc = []byte{ 0x09, 0x52, 0x0c, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6f, 0x70, 0x65, 0x72, 0x61, - 0x74, 0x69, 0x6e, 0x67, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x22, 0x48, 0x0a, 0x16, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x05, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, - 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x22, 0x27, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x75, - 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, - 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x22, 0x18, 0x0a, - 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x53, - 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, - 0x49, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x06, 0x61, 0x67, 0x65, 0x6e, - 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, - 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x75, 0x62, 0x41, 0x67, 0x65, - 0x6e, 0x74, 0x52, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x2a, 0x63, 0x0a, 0x09, 0x41, 0x70, - 0x70, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x16, 0x41, 0x50, 0x50, 0x5f, 0x48, - 0x45, 0x41, 0x4c, 0x54, 0x48, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, - 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x49, 0x53, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, - 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x49, 0x5a, 0x49, 0x4e, - 0x47, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x48, 0x45, 0x41, 0x4c, 0x54, 0x48, 0x59, 0x10, 0x03, - 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x48, 0x45, 0x41, 0x4c, 0x54, 0x48, 0x59, 0x10, 0x04, 0x32, - 0x91, 0x0d, 0x0a, 0x05, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x4b, 0x0a, 0x0b, 0x47, 0x65, 0x74, - 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, 0x22, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, - 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x6e, - 0x69, 0x66, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x63, - 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x4d, 0x61, - 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, 0x5a, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x27, 0x2e, 0x63, 0x6f, 0x64, - 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, - 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x42, 0x61, 0x6e, 0x6e, - 0x65, 0x72, 0x12, 0x56, 0x0a, 0x0b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, - 0x73, 0x12, 0x22, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, - 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, - 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0f, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x66, 0x65, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x12, 0x26, 0x2e, - 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x66, 0x65, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x66, 0x65, 0x63, 0x79, 0x63, 0x6c, 0x65, - 0x12, 0x72, 0x0a, 0x15, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, - 0x70, 0x70, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x73, 0x12, 0x2b, 0x2e, 0x63, 0x6f, 0x64, 0x65, - 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, - 0x61, 0x72, 0x74, 0x75, 0x70, 0x12, 0x24, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, - 0x72, 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x63, 0x6f, - 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x61, - 0x72, 0x74, 0x75, 0x70, 0x12, 0x6e, 0x0a, 0x13, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x2a, 0x2e, 0x63, 0x6f, + 0x74, 0x69, 0x6e, 0x67, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x3d, 0x0a, 0x04, 0x61, 0x70, + 0x70, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, + 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x53, 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, + 0x41, 0x70, 0x70, 0x52, 0x04, 0x61, 0x70, 0x70, 0x73, 0x1a, 0xe1, 0x06, 0x0a, 0x03, 0x41, 0x70, + 0x70, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x73, 0x6c, 0x75, 0x67, 0x12, 0x1d, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x88, 0x01, 0x01, 0x12, 0x26, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x0b, 0x64, 0x69, + 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, 0x08, + 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x48, 0x02, + 0x52, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, + 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x05, + 0x67, 0x72, 0x6f, 0x75, 0x70, 0x88, 0x01, 0x01, 0x12, 0x5c, 0x0a, 0x0b, 0x68, 0x65, 0x61, 0x6c, + 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, + 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, + 0x68, 0x65, 0x63, 0x6b, 0x48, 0x04, 0x52, 0x0b, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, + 0x65, 0x63, 0x6b, 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, 0x06, 0x68, 0x69, 0x64, 0x64, 0x65, 0x6e, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x48, 0x05, 0x52, 0x06, 0x68, 0x69, 0x64, 0x64, 0x65, 0x6e, + 0x88, 0x01, 0x01, 0x12, 0x17, 0x0a, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x06, 0x52, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x4e, 0x0a, 0x07, + 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x69, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x30, 0x2e, + 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x49, 0x6e, 0x48, + 0x07, 0x52, 0x06, 0x6f, 0x70, 0x65, 0x6e, 0x49, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, + 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x48, 0x08, 0x52, 0x05, 0x6f, + 0x72, 0x64, 0x65, 0x72, 0x88, 0x01, 0x01, 0x12, 0x4a, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72, 0x65, + 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, + 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x75, + 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41, 0x70, + 0x70, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x48, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x65, + 0x88, 0x01, 0x01, 0x12, 0x21, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, + 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x48, 0x0a, 0x52, 0x09, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, + 0x61, 0x69, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x15, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x0d, 0x20, + 0x01, 0x28, 0x09, 0x48, 0x0b, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x88, 0x01, 0x01, 0x1a, 0x59, 0x0a, + 0x0b, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x1a, 0x0a, 0x08, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68, 0x72, 0x65, + 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x74, 0x68, 0x72, + 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x22, 0x0a, 0x06, 0x4f, 0x70, 0x65, 0x6e, + 0x49, 0x6e, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x4c, 0x49, 0x4d, 0x5f, 0x57, 0x49, 0x4e, 0x44, 0x4f, + 0x57, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x41, 0x42, 0x10, 0x01, 0x22, 0x31, 0x0a, 0x05, + 0x53, 0x68, 0x61, 0x72, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x57, 0x4e, 0x45, 0x52, 0x10, 0x00, + 0x12, 0x11, 0x0a, 0x0d, 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x44, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x10, 0x02, 0x42, + 0x0a, 0x0a, 0x08, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, + 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x0b, 0x0a, 0x09, + 0x5f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, + 0x65, 0x63, 0x6b, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x68, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x42, 0x07, + 0x0a, 0x05, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x6f, 0x70, 0x65, 0x6e, + 0x5f, 0x69, 0x6e, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x42, 0x08, 0x0a, + 0x06, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x73, 0x75, 0x62, 0x64, + 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x75, 0x72, 0x6c, 0x22, 0x96, 0x02, + 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x05, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, + 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, + 0x74, 0x52, 0x05, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x67, 0x0a, 0x13, 0x61, 0x70, 0x70, 0x5f, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, + 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x41, 0x70, + 0x70, 0x43, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x11, + 0x61, 0x70, 0x70, 0x43, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x73, 0x1a, 0x63, 0x0a, 0x10, 0x41, 0x70, 0x70, 0x43, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x19, 0x0a, 0x05, 0x66, + 0x69, 0x65, 0x6c, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x66, 0x69, + 0x65, 0x6c, 0x64, 0x88, 0x01, 0x01, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, 0x08, 0x0a, 0x06, + 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x22, 0x27, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x53, 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x22, + 0x18, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x0a, 0x14, 0x4c, 0x69, 0x73, + 0x74, 0x53, 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x22, 0x49, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, + 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x06, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6f, 0x64, + 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x75, 0x62, 0x41, + 0x67, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x2a, 0x63, 0x0a, 0x09, + 0x41, 0x70, 0x70, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x16, 0x41, 0x50, 0x50, + 0x5f, 0x48, 0x45, 0x41, 0x4c, 0x54, 0x48, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, + 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x49, 0x53, 0x41, 0x42, 0x4c, 0x45, + 0x44, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x49, 0x5a, + 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x48, 0x45, 0x41, 0x4c, 0x54, 0x48, 0x59, + 0x10, 0x03, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x48, 0x45, 0x41, 0x4c, 0x54, 0x48, 0x59, 0x10, + 0x04, 0x32, 0x91, 0x0d, 0x0a, 0x05, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x4b, 0x0a, 0x0b, 0x47, + 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, 0x22, 0x2e, 0x63, 0x6f, 0x64, + 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x4d, + 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, + 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, + 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, 0x5a, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x27, 0x2e, 0x63, + 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, + 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x42, 0x61, + 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x56, 0x0a, 0x0b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, + 0x61, 0x74, 0x73, 0x12, 0x22, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, + 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, + 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0f, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x66, 0x65, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x12, + 0x26, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, + 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x66, 0x65, 0x63, 0x79, 0x63, 0x6c, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, + 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x66, 0x65, 0x63, 0x79, 0x63, + 0x6c, 0x65, 0x12, 0x72, 0x0a, 0x15, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x41, 0x70, 0x70, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x73, 0x12, 0x2b, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x61, 0x74, - 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, - 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x0f, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x26, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, - 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x27, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, - 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x77, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x41, - 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x61, 0x6e, 0x6e, 0x65, - 0x72, 0x73, 0x12, 0x2d, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, - 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x6d, - 0x65, 0x6e, 0x74, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x2e, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, - 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x6d, 0x65, - 0x6e, 0x74, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x7e, 0x0a, 0x0f, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x6c, - 0x65, 0x74, 0x65, 0x64, 0x12, 0x34, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, - 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x41, - 0x67, 0x65, 0x6e, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, - 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x63, 0x6f, 0x64, - 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x57, 0x6f, 0x72, 0x6b, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x9e, 0x01, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x2e, 0x63, 0x6f, 0x64, 0x65, - 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, - 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x89, 0x01, 0x0a, 0x1c, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x48, 0x65, 0x61, 0x6c, 0x74, + 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, + 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x12, 0x24, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, + 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, + 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, + 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x53, + 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x12, 0x6e, 0x0a, 0x13, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x2a, 0x2e, + 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x42, + 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x63, 0x6f, 0x64, 0x65, + 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x0f, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x26, 0x2e, 0x63, 0x6f, 0x64, 0x65, + 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x27, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, + 0x76, 0x32, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, + 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x77, 0x0a, 0x16, 0x47, 0x65, + 0x74, 0x41, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x61, 0x6e, + 0x6e, 0x65, 0x72, 0x73, 0x12, 0x2d, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, + 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x7e, 0x0a, 0x0f, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x43, 0x6f, 0x6d, + 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x34, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, + 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x43, 0x6f, 0x6d, 0x70, + 0x6c, 0x65, 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x63, + 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x57, 0x6f, + 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x53, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x9e, 0x01, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x2e, 0x63, 0x6f, + 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, + 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, + 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x89, 0x01, 0x0a, 0x1c, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, + 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x33, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x55, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x33, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, - 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x55, 0x73, 0x61, 0x67, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, - 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, - 0x67, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, - 0x0a, 0x10, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x27, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, - 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 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, 0x12, 0x5f, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, - 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x25, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, - 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x63, - 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x75, - 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x25, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x75, - 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, - 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5c, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, - 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x24, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x41, - 0x67, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x63, - 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x53, 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x76, 0x32, - 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x63, 0x6f, 0x64, + 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x75, 0x73, 0x68, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, + 0x69, 0x6e, 0x67, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x53, 0x0a, 0x10, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, + 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 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, 0x12, 0x5f, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, + 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x25, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, + 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, + 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, + 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x53, 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x25, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, + 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x53, 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x26, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, + 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5c, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x53, + 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x24, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, + 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, + 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, + 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, + 0x76, 0x32, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -4587,8 +5038,8 @@ func file_agent_proto_agent_proto_rawDescGZIP() []byte { return file_agent_proto_agent_proto_rawDescData } -var file_agent_proto_agent_proto_enumTypes = make([]protoimpl.EnumInfo, 11) -var file_agent_proto_agent_proto_msgTypes = make([]protoimpl.MessageInfo, 56) +var file_agent_proto_agent_proto_enumTypes = make([]protoimpl.EnumInfo, 13) +var file_agent_proto_agent_proto_msgTypes = make([]protoimpl.MessageInfo, 59) var file_agent_proto_agent_proto_goTypes = []interface{}{ (AppHealth)(0), // 0: coder.agent.v2.AppHealth (WorkspaceApp_SharingLevel)(0), // 1: coder.agent.v2.WorkspaceApp.SharingLevel @@ -4601,158 +5052,168 @@ var file_agent_proto_agent_proto_goTypes = []interface{}{ (Timing_Status)(0), // 8: coder.agent.v2.Timing.Status (Connection_Action)(0), // 9: coder.agent.v2.Connection.Action (Connection_Type)(0), // 10: coder.agent.v2.Connection.Type - (*WorkspaceApp)(nil), // 11: coder.agent.v2.WorkspaceApp - (*WorkspaceAgentScript)(nil), // 12: coder.agent.v2.WorkspaceAgentScript - (*WorkspaceAgentMetadata)(nil), // 13: coder.agent.v2.WorkspaceAgentMetadata - (*Manifest)(nil), // 14: coder.agent.v2.Manifest - (*WorkspaceAgentDevcontainer)(nil), // 15: coder.agent.v2.WorkspaceAgentDevcontainer - (*GetManifestRequest)(nil), // 16: coder.agent.v2.GetManifestRequest - (*ServiceBanner)(nil), // 17: coder.agent.v2.ServiceBanner - (*GetServiceBannerRequest)(nil), // 18: coder.agent.v2.GetServiceBannerRequest - (*Stats)(nil), // 19: coder.agent.v2.Stats - (*UpdateStatsRequest)(nil), // 20: coder.agent.v2.UpdateStatsRequest - (*UpdateStatsResponse)(nil), // 21: coder.agent.v2.UpdateStatsResponse - (*Lifecycle)(nil), // 22: coder.agent.v2.Lifecycle - (*UpdateLifecycleRequest)(nil), // 23: coder.agent.v2.UpdateLifecycleRequest - (*BatchUpdateAppHealthRequest)(nil), // 24: coder.agent.v2.BatchUpdateAppHealthRequest - (*BatchUpdateAppHealthResponse)(nil), // 25: coder.agent.v2.BatchUpdateAppHealthResponse - (*Startup)(nil), // 26: coder.agent.v2.Startup - (*UpdateStartupRequest)(nil), // 27: coder.agent.v2.UpdateStartupRequest - (*Metadata)(nil), // 28: coder.agent.v2.Metadata - (*BatchUpdateMetadataRequest)(nil), // 29: coder.agent.v2.BatchUpdateMetadataRequest - (*BatchUpdateMetadataResponse)(nil), // 30: coder.agent.v2.BatchUpdateMetadataResponse - (*Log)(nil), // 31: coder.agent.v2.Log - (*BatchCreateLogsRequest)(nil), // 32: coder.agent.v2.BatchCreateLogsRequest - (*BatchCreateLogsResponse)(nil), // 33: coder.agent.v2.BatchCreateLogsResponse - (*GetAnnouncementBannersRequest)(nil), // 34: coder.agent.v2.GetAnnouncementBannersRequest - (*GetAnnouncementBannersResponse)(nil), // 35: coder.agent.v2.GetAnnouncementBannersResponse - (*BannerConfig)(nil), // 36: coder.agent.v2.BannerConfig - (*WorkspaceAgentScriptCompletedRequest)(nil), // 37: coder.agent.v2.WorkspaceAgentScriptCompletedRequest - (*WorkspaceAgentScriptCompletedResponse)(nil), // 38: coder.agent.v2.WorkspaceAgentScriptCompletedResponse - (*Timing)(nil), // 39: coder.agent.v2.Timing - (*GetResourcesMonitoringConfigurationRequest)(nil), // 40: coder.agent.v2.GetResourcesMonitoringConfigurationRequest - (*GetResourcesMonitoringConfigurationResponse)(nil), // 41: coder.agent.v2.GetResourcesMonitoringConfigurationResponse - (*PushResourcesMonitoringUsageRequest)(nil), // 42: coder.agent.v2.PushResourcesMonitoringUsageRequest - (*PushResourcesMonitoringUsageResponse)(nil), // 43: coder.agent.v2.PushResourcesMonitoringUsageResponse - (*Connection)(nil), // 44: coder.agent.v2.Connection - (*ReportConnectionRequest)(nil), // 45: coder.agent.v2.ReportConnectionRequest - (*SubAgent)(nil), // 46: coder.agent.v2.SubAgent - (*CreateSubAgentRequest)(nil), // 47: coder.agent.v2.CreateSubAgentRequest - (*CreateSubAgentResponse)(nil), // 48: coder.agent.v2.CreateSubAgentResponse - (*DeleteSubAgentRequest)(nil), // 49: coder.agent.v2.DeleteSubAgentRequest - (*DeleteSubAgentResponse)(nil), // 50: coder.agent.v2.DeleteSubAgentResponse - (*ListSubAgentsRequest)(nil), // 51: coder.agent.v2.ListSubAgentsRequest - (*ListSubAgentsResponse)(nil), // 52: coder.agent.v2.ListSubAgentsResponse - (*WorkspaceApp_Healthcheck)(nil), // 53: coder.agent.v2.WorkspaceApp.Healthcheck - (*WorkspaceAgentMetadata_Result)(nil), // 54: coder.agent.v2.WorkspaceAgentMetadata.Result - (*WorkspaceAgentMetadata_Description)(nil), // 55: coder.agent.v2.WorkspaceAgentMetadata.Description - nil, // 56: coder.agent.v2.Manifest.EnvironmentVariablesEntry - nil, // 57: coder.agent.v2.Stats.ConnectionsByProtoEntry - (*Stats_Metric)(nil), // 58: coder.agent.v2.Stats.Metric - (*Stats_Metric_Label)(nil), // 59: coder.agent.v2.Stats.Metric.Label - (*BatchUpdateAppHealthRequest_HealthUpdate)(nil), // 60: coder.agent.v2.BatchUpdateAppHealthRequest.HealthUpdate - (*GetResourcesMonitoringConfigurationResponse_Config)(nil), // 61: coder.agent.v2.GetResourcesMonitoringConfigurationResponse.Config - (*GetResourcesMonitoringConfigurationResponse_Memory)(nil), // 62: coder.agent.v2.GetResourcesMonitoringConfigurationResponse.Memory - (*GetResourcesMonitoringConfigurationResponse_Volume)(nil), // 63: coder.agent.v2.GetResourcesMonitoringConfigurationResponse.Volume - (*PushResourcesMonitoringUsageRequest_Datapoint)(nil), // 64: coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint - (*PushResourcesMonitoringUsageRequest_Datapoint_MemoryUsage)(nil), // 65: coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint.MemoryUsage - (*PushResourcesMonitoringUsageRequest_Datapoint_VolumeUsage)(nil), // 66: coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint.VolumeUsage - (*durationpb.Duration)(nil), // 67: google.protobuf.Duration - (*proto.DERPMap)(nil), // 68: coder.tailnet.v2.DERPMap - (*timestamppb.Timestamp)(nil), // 69: google.protobuf.Timestamp - (*emptypb.Empty)(nil), // 70: google.protobuf.Empty + (CreateSubAgentRequest_App_OpenIn)(0), // 11: coder.agent.v2.CreateSubAgentRequest.App.OpenIn + (CreateSubAgentRequest_App_Share)(0), // 12: coder.agent.v2.CreateSubAgentRequest.App.Share + (*WorkspaceApp)(nil), // 13: coder.agent.v2.WorkspaceApp + (*WorkspaceAgentScript)(nil), // 14: coder.agent.v2.WorkspaceAgentScript + (*WorkspaceAgentMetadata)(nil), // 15: coder.agent.v2.WorkspaceAgentMetadata + (*Manifest)(nil), // 16: coder.agent.v2.Manifest + (*WorkspaceAgentDevcontainer)(nil), // 17: coder.agent.v2.WorkspaceAgentDevcontainer + (*GetManifestRequest)(nil), // 18: coder.agent.v2.GetManifestRequest + (*ServiceBanner)(nil), // 19: coder.agent.v2.ServiceBanner + (*GetServiceBannerRequest)(nil), // 20: coder.agent.v2.GetServiceBannerRequest + (*Stats)(nil), // 21: coder.agent.v2.Stats + (*UpdateStatsRequest)(nil), // 22: coder.agent.v2.UpdateStatsRequest + (*UpdateStatsResponse)(nil), // 23: coder.agent.v2.UpdateStatsResponse + (*Lifecycle)(nil), // 24: coder.agent.v2.Lifecycle + (*UpdateLifecycleRequest)(nil), // 25: coder.agent.v2.UpdateLifecycleRequest + (*BatchUpdateAppHealthRequest)(nil), // 26: coder.agent.v2.BatchUpdateAppHealthRequest + (*BatchUpdateAppHealthResponse)(nil), // 27: coder.agent.v2.BatchUpdateAppHealthResponse + (*Startup)(nil), // 28: coder.agent.v2.Startup + (*UpdateStartupRequest)(nil), // 29: coder.agent.v2.UpdateStartupRequest + (*Metadata)(nil), // 30: coder.agent.v2.Metadata + (*BatchUpdateMetadataRequest)(nil), // 31: coder.agent.v2.BatchUpdateMetadataRequest + (*BatchUpdateMetadataResponse)(nil), // 32: coder.agent.v2.BatchUpdateMetadataResponse + (*Log)(nil), // 33: coder.agent.v2.Log + (*BatchCreateLogsRequest)(nil), // 34: coder.agent.v2.BatchCreateLogsRequest + (*BatchCreateLogsResponse)(nil), // 35: coder.agent.v2.BatchCreateLogsResponse + (*GetAnnouncementBannersRequest)(nil), // 36: coder.agent.v2.GetAnnouncementBannersRequest + (*GetAnnouncementBannersResponse)(nil), // 37: coder.agent.v2.GetAnnouncementBannersResponse + (*BannerConfig)(nil), // 38: coder.agent.v2.BannerConfig + (*WorkspaceAgentScriptCompletedRequest)(nil), // 39: coder.agent.v2.WorkspaceAgentScriptCompletedRequest + (*WorkspaceAgentScriptCompletedResponse)(nil), // 40: coder.agent.v2.WorkspaceAgentScriptCompletedResponse + (*Timing)(nil), // 41: coder.agent.v2.Timing + (*GetResourcesMonitoringConfigurationRequest)(nil), // 42: coder.agent.v2.GetResourcesMonitoringConfigurationRequest + (*GetResourcesMonitoringConfigurationResponse)(nil), // 43: coder.agent.v2.GetResourcesMonitoringConfigurationResponse + (*PushResourcesMonitoringUsageRequest)(nil), // 44: coder.agent.v2.PushResourcesMonitoringUsageRequest + (*PushResourcesMonitoringUsageResponse)(nil), // 45: coder.agent.v2.PushResourcesMonitoringUsageResponse + (*Connection)(nil), // 46: coder.agent.v2.Connection + (*ReportConnectionRequest)(nil), // 47: coder.agent.v2.ReportConnectionRequest + (*SubAgent)(nil), // 48: coder.agent.v2.SubAgent + (*CreateSubAgentRequest)(nil), // 49: coder.agent.v2.CreateSubAgentRequest + (*CreateSubAgentResponse)(nil), // 50: coder.agent.v2.CreateSubAgentResponse + (*DeleteSubAgentRequest)(nil), // 51: coder.agent.v2.DeleteSubAgentRequest + (*DeleteSubAgentResponse)(nil), // 52: coder.agent.v2.DeleteSubAgentResponse + (*ListSubAgentsRequest)(nil), // 53: coder.agent.v2.ListSubAgentsRequest + (*ListSubAgentsResponse)(nil), // 54: coder.agent.v2.ListSubAgentsResponse + (*WorkspaceApp_Healthcheck)(nil), // 55: coder.agent.v2.WorkspaceApp.Healthcheck + (*WorkspaceAgentMetadata_Result)(nil), // 56: coder.agent.v2.WorkspaceAgentMetadata.Result + (*WorkspaceAgentMetadata_Description)(nil), // 57: coder.agent.v2.WorkspaceAgentMetadata.Description + nil, // 58: coder.agent.v2.Manifest.EnvironmentVariablesEntry + nil, // 59: coder.agent.v2.Stats.ConnectionsByProtoEntry + (*Stats_Metric)(nil), // 60: coder.agent.v2.Stats.Metric + (*Stats_Metric_Label)(nil), // 61: coder.agent.v2.Stats.Metric.Label + (*BatchUpdateAppHealthRequest_HealthUpdate)(nil), // 62: coder.agent.v2.BatchUpdateAppHealthRequest.HealthUpdate + (*GetResourcesMonitoringConfigurationResponse_Config)(nil), // 63: coder.agent.v2.GetResourcesMonitoringConfigurationResponse.Config + (*GetResourcesMonitoringConfigurationResponse_Memory)(nil), // 64: coder.agent.v2.GetResourcesMonitoringConfigurationResponse.Memory + (*GetResourcesMonitoringConfigurationResponse_Volume)(nil), // 65: coder.agent.v2.GetResourcesMonitoringConfigurationResponse.Volume + (*PushResourcesMonitoringUsageRequest_Datapoint)(nil), // 66: coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint + (*PushResourcesMonitoringUsageRequest_Datapoint_MemoryUsage)(nil), // 67: coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint.MemoryUsage + (*PushResourcesMonitoringUsageRequest_Datapoint_VolumeUsage)(nil), // 68: coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint.VolumeUsage + (*CreateSubAgentRequest_App)(nil), // 69: coder.agent.v2.CreateSubAgentRequest.App + (*CreateSubAgentRequest_App_Healthcheck)(nil), // 70: coder.agent.v2.CreateSubAgentRequest.App.Healthcheck + (*CreateSubAgentResponse_AppCreationError)(nil), // 71: coder.agent.v2.CreateSubAgentResponse.AppCreationError + (*durationpb.Duration)(nil), // 72: google.protobuf.Duration + (*proto.DERPMap)(nil), // 73: coder.tailnet.v2.DERPMap + (*timestamppb.Timestamp)(nil), // 74: google.protobuf.Timestamp + (*emptypb.Empty)(nil), // 75: google.protobuf.Empty } var file_agent_proto_agent_proto_depIdxs = []int32{ 1, // 0: coder.agent.v2.WorkspaceApp.sharing_level:type_name -> coder.agent.v2.WorkspaceApp.SharingLevel - 53, // 1: coder.agent.v2.WorkspaceApp.healthcheck:type_name -> coder.agent.v2.WorkspaceApp.Healthcheck + 55, // 1: coder.agent.v2.WorkspaceApp.healthcheck:type_name -> coder.agent.v2.WorkspaceApp.Healthcheck 2, // 2: coder.agent.v2.WorkspaceApp.health:type_name -> coder.agent.v2.WorkspaceApp.Health - 67, // 3: coder.agent.v2.WorkspaceAgentScript.timeout:type_name -> google.protobuf.Duration - 54, // 4: coder.agent.v2.WorkspaceAgentMetadata.result:type_name -> coder.agent.v2.WorkspaceAgentMetadata.Result - 55, // 5: coder.agent.v2.WorkspaceAgentMetadata.description:type_name -> coder.agent.v2.WorkspaceAgentMetadata.Description - 56, // 6: coder.agent.v2.Manifest.environment_variables:type_name -> coder.agent.v2.Manifest.EnvironmentVariablesEntry - 68, // 7: coder.agent.v2.Manifest.derp_map:type_name -> coder.tailnet.v2.DERPMap - 12, // 8: coder.agent.v2.Manifest.scripts:type_name -> coder.agent.v2.WorkspaceAgentScript - 11, // 9: coder.agent.v2.Manifest.apps:type_name -> coder.agent.v2.WorkspaceApp - 55, // 10: coder.agent.v2.Manifest.metadata:type_name -> coder.agent.v2.WorkspaceAgentMetadata.Description - 15, // 11: coder.agent.v2.Manifest.devcontainers:type_name -> coder.agent.v2.WorkspaceAgentDevcontainer - 57, // 12: coder.agent.v2.Stats.connections_by_proto:type_name -> coder.agent.v2.Stats.ConnectionsByProtoEntry - 58, // 13: coder.agent.v2.Stats.metrics:type_name -> coder.agent.v2.Stats.Metric - 19, // 14: coder.agent.v2.UpdateStatsRequest.stats:type_name -> coder.agent.v2.Stats - 67, // 15: coder.agent.v2.UpdateStatsResponse.report_interval:type_name -> google.protobuf.Duration + 72, // 3: coder.agent.v2.WorkspaceAgentScript.timeout:type_name -> google.protobuf.Duration + 56, // 4: coder.agent.v2.WorkspaceAgentMetadata.result:type_name -> coder.agent.v2.WorkspaceAgentMetadata.Result + 57, // 5: coder.agent.v2.WorkspaceAgentMetadata.description:type_name -> coder.agent.v2.WorkspaceAgentMetadata.Description + 58, // 6: coder.agent.v2.Manifest.environment_variables:type_name -> coder.agent.v2.Manifest.EnvironmentVariablesEntry + 73, // 7: coder.agent.v2.Manifest.derp_map:type_name -> coder.tailnet.v2.DERPMap + 14, // 8: coder.agent.v2.Manifest.scripts:type_name -> coder.agent.v2.WorkspaceAgentScript + 13, // 9: coder.agent.v2.Manifest.apps:type_name -> coder.agent.v2.WorkspaceApp + 57, // 10: coder.agent.v2.Manifest.metadata:type_name -> coder.agent.v2.WorkspaceAgentMetadata.Description + 17, // 11: coder.agent.v2.Manifest.devcontainers:type_name -> coder.agent.v2.WorkspaceAgentDevcontainer + 59, // 12: coder.agent.v2.Stats.connections_by_proto:type_name -> coder.agent.v2.Stats.ConnectionsByProtoEntry + 60, // 13: coder.agent.v2.Stats.metrics:type_name -> coder.agent.v2.Stats.Metric + 21, // 14: coder.agent.v2.UpdateStatsRequest.stats:type_name -> coder.agent.v2.Stats + 72, // 15: coder.agent.v2.UpdateStatsResponse.report_interval:type_name -> google.protobuf.Duration 4, // 16: coder.agent.v2.Lifecycle.state:type_name -> coder.agent.v2.Lifecycle.State - 69, // 17: coder.agent.v2.Lifecycle.changed_at:type_name -> google.protobuf.Timestamp - 22, // 18: coder.agent.v2.UpdateLifecycleRequest.lifecycle:type_name -> coder.agent.v2.Lifecycle - 60, // 19: coder.agent.v2.BatchUpdateAppHealthRequest.updates:type_name -> coder.agent.v2.BatchUpdateAppHealthRequest.HealthUpdate + 74, // 17: coder.agent.v2.Lifecycle.changed_at:type_name -> google.protobuf.Timestamp + 24, // 18: coder.agent.v2.UpdateLifecycleRequest.lifecycle:type_name -> coder.agent.v2.Lifecycle + 62, // 19: coder.agent.v2.BatchUpdateAppHealthRequest.updates:type_name -> coder.agent.v2.BatchUpdateAppHealthRequest.HealthUpdate 5, // 20: coder.agent.v2.Startup.subsystems:type_name -> coder.agent.v2.Startup.Subsystem - 26, // 21: coder.agent.v2.UpdateStartupRequest.startup:type_name -> coder.agent.v2.Startup - 54, // 22: coder.agent.v2.Metadata.result:type_name -> coder.agent.v2.WorkspaceAgentMetadata.Result - 28, // 23: coder.agent.v2.BatchUpdateMetadataRequest.metadata:type_name -> coder.agent.v2.Metadata - 69, // 24: coder.agent.v2.Log.created_at:type_name -> google.protobuf.Timestamp + 28, // 21: coder.agent.v2.UpdateStartupRequest.startup:type_name -> coder.agent.v2.Startup + 56, // 22: coder.agent.v2.Metadata.result:type_name -> coder.agent.v2.WorkspaceAgentMetadata.Result + 30, // 23: coder.agent.v2.BatchUpdateMetadataRequest.metadata:type_name -> coder.agent.v2.Metadata + 74, // 24: coder.agent.v2.Log.created_at:type_name -> google.protobuf.Timestamp 6, // 25: coder.agent.v2.Log.level:type_name -> coder.agent.v2.Log.Level - 31, // 26: coder.agent.v2.BatchCreateLogsRequest.logs:type_name -> coder.agent.v2.Log - 36, // 27: coder.agent.v2.GetAnnouncementBannersResponse.announcement_banners:type_name -> coder.agent.v2.BannerConfig - 39, // 28: coder.agent.v2.WorkspaceAgentScriptCompletedRequest.timing:type_name -> coder.agent.v2.Timing - 69, // 29: coder.agent.v2.Timing.start:type_name -> google.protobuf.Timestamp - 69, // 30: coder.agent.v2.Timing.end:type_name -> google.protobuf.Timestamp + 33, // 26: coder.agent.v2.BatchCreateLogsRequest.logs:type_name -> coder.agent.v2.Log + 38, // 27: coder.agent.v2.GetAnnouncementBannersResponse.announcement_banners:type_name -> coder.agent.v2.BannerConfig + 41, // 28: coder.agent.v2.WorkspaceAgentScriptCompletedRequest.timing:type_name -> coder.agent.v2.Timing + 74, // 29: coder.agent.v2.Timing.start:type_name -> google.protobuf.Timestamp + 74, // 30: coder.agent.v2.Timing.end:type_name -> google.protobuf.Timestamp 7, // 31: coder.agent.v2.Timing.stage:type_name -> coder.agent.v2.Timing.Stage 8, // 32: coder.agent.v2.Timing.status:type_name -> coder.agent.v2.Timing.Status - 61, // 33: coder.agent.v2.GetResourcesMonitoringConfigurationResponse.config:type_name -> coder.agent.v2.GetResourcesMonitoringConfigurationResponse.Config - 62, // 34: coder.agent.v2.GetResourcesMonitoringConfigurationResponse.memory:type_name -> coder.agent.v2.GetResourcesMonitoringConfigurationResponse.Memory - 63, // 35: coder.agent.v2.GetResourcesMonitoringConfigurationResponse.volumes:type_name -> coder.agent.v2.GetResourcesMonitoringConfigurationResponse.Volume - 64, // 36: coder.agent.v2.PushResourcesMonitoringUsageRequest.datapoints:type_name -> coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint + 63, // 33: coder.agent.v2.GetResourcesMonitoringConfigurationResponse.config:type_name -> coder.agent.v2.GetResourcesMonitoringConfigurationResponse.Config + 64, // 34: coder.agent.v2.GetResourcesMonitoringConfigurationResponse.memory:type_name -> coder.agent.v2.GetResourcesMonitoringConfigurationResponse.Memory + 65, // 35: coder.agent.v2.GetResourcesMonitoringConfigurationResponse.volumes:type_name -> coder.agent.v2.GetResourcesMonitoringConfigurationResponse.Volume + 66, // 36: coder.agent.v2.PushResourcesMonitoringUsageRequest.datapoints:type_name -> coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint 9, // 37: coder.agent.v2.Connection.action:type_name -> coder.agent.v2.Connection.Action 10, // 38: coder.agent.v2.Connection.type:type_name -> coder.agent.v2.Connection.Type - 69, // 39: coder.agent.v2.Connection.timestamp:type_name -> google.protobuf.Timestamp - 44, // 40: coder.agent.v2.ReportConnectionRequest.connection:type_name -> coder.agent.v2.Connection - 46, // 41: coder.agent.v2.CreateSubAgentResponse.agent:type_name -> coder.agent.v2.SubAgent - 46, // 42: coder.agent.v2.ListSubAgentsResponse.agents:type_name -> coder.agent.v2.SubAgent - 67, // 43: coder.agent.v2.WorkspaceApp.Healthcheck.interval:type_name -> google.protobuf.Duration - 69, // 44: coder.agent.v2.WorkspaceAgentMetadata.Result.collected_at:type_name -> google.protobuf.Timestamp - 67, // 45: coder.agent.v2.WorkspaceAgentMetadata.Description.interval:type_name -> google.protobuf.Duration - 67, // 46: coder.agent.v2.WorkspaceAgentMetadata.Description.timeout:type_name -> google.protobuf.Duration - 3, // 47: coder.agent.v2.Stats.Metric.type:type_name -> coder.agent.v2.Stats.Metric.Type - 59, // 48: coder.agent.v2.Stats.Metric.labels:type_name -> coder.agent.v2.Stats.Metric.Label - 0, // 49: coder.agent.v2.BatchUpdateAppHealthRequest.HealthUpdate.health:type_name -> coder.agent.v2.AppHealth - 69, // 50: coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint.collected_at:type_name -> google.protobuf.Timestamp - 65, // 51: coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint.memory:type_name -> coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint.MemoryUsage - 66, // 52: coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint.volumes:type_name -> coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint.VolumeUsage - 16, // 53: coder.agent.v2.Agent.GetManifest:input_type -> coder.agent.v2.GetManifestRequest - 18, // 54: coder.agent.v2.Agent.GetServiceBanner:input_type -> coder.agent.v2.GetServiceBannerRequest - 20, // 55: coder.agent.v2.Agent.UpdateStats:input_type -> coder.agent.v2.UpdateStatsRequest - 23, // 56: coder.agent.v2.Agent.UpdateLifecycle:input_type -> coder.agent.v2.UpdateLifecycleRequest - 24, // 57: coder.agent.v2.Agent.BatchUpdateAppHealths:input_type -> coder.agent.v2.BatchUpdateAppHealthRequest - 27, // 58: coder.agent.v2.Agent.UpdateStartup:input_type -> coder.agent.v2.UpdateStartupRequest - 29, // 59: coder.agent.v2.Agent.BatchUpdateMetadata:input_type -> coder.agent.v2.BatchUpdateMetadataRequest - 32, // 60: coder.agent.v2.Agent.BatchCreateLogs:input_type -> coder.agent.v2.BatchCreateLogsRequest - 34, // 61: coder.agent.v2.Agent.GetAnnouncementBanners:input_type -> coder.agent.v2.GetAnnouncementBannersRequest - 37, // 62: coder.agent.v2.Agent.ScriptCompleted:input_type -> coder.agent.v2.WorkspaceAgentScriptCompletedRequest - 40, // 63: coder.agent.v2.Agent.GetResourcesMonitoringConfiguration:input_type -> coder.agent.v2.GetResourcesMonitoringConfigurationRequest - 42, // 64: coder.agent.v2.Agent.PushResourcesMonitoringUsage:input_type -> coder.agent.v2.PushResourcesMonitoringUsageRequest - 45, // 65: coder.agent.v2.Agent.ReportConnection:input_type -> coder.agent.v2.ReportConnectionRequest - 47, // 66: coder.agent.v2.Agent.CreateSubAgent:input_type -> coder.agent.v2.CreateSubAgentRequest - 49, // 67: coder.agent.v2.Agent.DeleteSubAgent:input_type -> coder.agent.v2.DeleteSubAgentRequest - 51, // 68: coder.agent.v2.Agent.ListSubAgents:input_type -> coder.agent.v2.ListSubAgentsRequest - 14, // 69: coder.agent.v2.Agent.GetManifest:output_type -> coder.agent.v2.Manifest - 17, // 70: coder.agent.v2.Agent.GetServiceBanner:output_type -> coder.agent.v2.ServiceBanner - 21, // 71: coder.agent.v2.Agent.UpdateStats:output_type -> coder.agent.v2.UpdateStatsResponse - 22, // 72: coder.agent.v2.Agent.UpdateLifecycle:output_type -> coder.agent.v2.Lifecycle - 25, // 73: coder.agent.v2.Agent.BatchUpdateAppHealths:output_type -> coder.agent.v2.BatchUpdateAppHealthResponse - 26, // 74: coder.agent.v2.Agent.UpdateStartup:output_type -> coder.agent.v2.Startup - 30, // 75: coder.agent.v2.Agent.BatchUpdateMetadata:output_type -> coder.agent.v2.BatchUpdateMetadataResponse - 33, // 76: coder.agent.v2.Agent.BatchCreateLogs:output_type -> coder.agent.v2.BatchCreateLogsResponse - 35, // 77: coder.agent.v2.Agent.GetAnnouncementBanners:output_type -> coder.agent.v2.GetAnnouncementBannersResponse - 38, // 78: coder.agent.v2.Agent.ScriptCompleted:output_type -> coder.agent.v2.WorkspaceAgentScriptCompletedResponse - 41, // 79: coder.agent.v2.Agent.GetResourcesMonitoringConfiguration:output_type -> coder.agent.v2.GetResourcesMonitoringConfigurationResponse - 43, // 80: coder.agent.v2.Agent.PushResourcesMonitoringUsage:output_type -> coder.agent.v2.PushResourcesMonitoringUsageResponse - 70, // 81: coder.agent.v2.Agent.ReportConnection:output_type -> google.protobuf.Empty - 48, // 82: coder.agent.v2.Agent.CreateSubAgent:output_type -> coder.agent.v2.CreateSubAgentResponse - 50, // 83: coder.agent.v2.Agent.DeleteSubAgent:output_type -> coder.agent.v2.DeleteSubAgentResponse - 52, // 84: coder.agent.v2.Agent.ListSubAgents:output_type -> coder.agent.v2.ListSubAgentsResponse - 69, // [69:85] is the sub-list for method output_type - 53, // [53:69] is the sub-list for method input_type - 53, // [53:53] is the sub-list for extension type_name - 53, // [53:53] is the sub-list for extension extendee - 0, // [0:53] is the sub-list for field type_name + 74, // 39: coder.agent.v2.Connection.timestamp:type_name -> google.protobuf.Timestamp + 46, // 40: coder.agent.v2.ReportConnectionRequest.connection:type_name -> coder.agent.v2.Connection + 69, // 41: coder.agent.v2.CreateSubAgentRequest.apps:type_name -> coder.agent.v2.CreateSubAgentRequest.App + 48, // 42: coder.agent.v2.CreateSubAgentResponse.agent:type_name -> coder.agent.v2.SubAgent + 71, // 43: coder.agent.v2.CreateSubAgentResponse.app_creation_errors:type_name -> coder.agent.v2.CreateSubAgentResponse.AppCreationError + 48, // 44: coder.agent.v2.ListSubAgentsResponse.agents:type_name -> coder.agent.v2.SubAgent + 72, // 45: coder.agent.v2.WorkspaceApp.Healthcheck.interval:type_name -> google.protobuf.Duration + 74, // 46: coder.agent.v2.WorkspaceAgentMetadata.Result.collected_at:type_name -> google.protobuf.Timestamp + 72, // 47: coder.agent.v2.WorkspaceAgentMetadata.Description.interval:type_name -> google.protobuf.Duration + 72, // 48: coder.agent.v2.WorkspaceAgentMetadata.Description.timeout:type_name -> google.protobuf.Duration + 3, // 49: coder.agent.v2.Stats.Metric.type:type_name -> coder.agent.v2.Stats.Metric.Type + 61, // 50: coder.agent.v2.Stats.Metric.labels:type_name -> coder.agent.v2.Stats.Metric.Label + 0, // 51: coder.agent.v2.BatchUpdateAppHealthRequest.HealthUpdate.health:type_name -> coder.agent.v2.AppHealth + 74, // 52: coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint.collected_at:type_name -> google.protobuf.Timestamp + 67, // 53: coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint.memory:type_name -> coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint.MemoryUsage + 68, // 54: coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint.volumes:type_name -> coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint.VolumeUsage + 70, // 55: coder.agent.v2.CreateSubAgentRequest.App.healthcheck:type_name -> coder.agent.v2.CreateSubAgentRequest.App.Healthcheck + 11, // 56: coder.agent.v2.CreateSubAgentRequest.App.open_in:type_name -> coder.agent.v2.CreateSubAgentRequest.App.OpenIn + 12, // 57: coder.agent.v2.CreateSubAgentRequest.App.share:type_name -> coder.agent.v2.CreateSubAgentRequest.App.Share + 18, // 58: coder.agent.v2.Agent.GetManifest:input_type -> coder.agent.v2.GetManifestRequest + 20, // 59: coder.agent.v2.Agent.GetServiceBanner:input_type -> coder.agent.v2.GetServiceBannerRequest + 22, // 60: coder.agent.v2.Agent.UpdateStats:input_type -> coder.agent.v2.UpdateStatsRequest + 25, // 61: coder.agent.v2.Agent.UpdateLifecycle:input_type -> coder.agent.v2.UpdateLifecycleRequest + 26, // 62: coder.agent.v2.Agent.BatchUpdateAppHealths:input_type -> coder.agent.v2.BatchUpdateAppHealthRequest + 29, // 63: coder.agent.v2.Agent.UpdateStartup:input_type -> coder.agent.v2.UpdateStartupRequest + 31, // 64: coder.agent.v2.Agent.BatchUpdateMetadata:input_type -> coder.agent.v2.BatchUpdateMetadataRequest + 34, // 65: coder.agent.v2.Agent.BatchCreateLogs:input_type -> coder.agent.v2.BatchCreateLogsRequest + 36, // 66: coder.agent.v2.Agent.GetAnnouncementBanners:input_type -> coder.agent.v2.GetAnnouncementBannersRequest + 39, // 67: coder.agent.v2.Agent.ScriptCompleted:input_type -> coder.agent.v2.WorkspaceAgentScriptCompletedRequest + 42, // 68: coder.agent.v2.Agent.GetResourcesMonitoringConfiguration:input_type -> coder.agent.v2.GetResourcesMonitoringConfigurationRequest + 44, // 69: coder.agent.v2.Agent.PushResourcesMonitoringUsage:input_type -> coder.agent.v2.PushResourcesMonitoringUsageRequest + 47, // 70: coder.agent.v2.Agent.ReportConnection:input_type -> coder.agent.v2.ReportConnectionRequest + 49, // 71: coder.agent.v2.Agent.CreateSubAgent:input_type -> coder.agent.v2.CreateSubAgentRequest + 51, // 72: coder.agent.v2.Agent.DeleteSubAgent:input_type -> coder.agent.v2.DeleteSubAgentRequest + 53, // 73: coder.agent.v2.Agent.ListSubAgents:input_type -> coder.agent.v2.ListSubAgentsRequest + 16, // 74: coder.agent.v2.Agent.GetManifest:output_type -> coder.agent.v2.Manifest + 19, // 75: coder.agent.v2.Agent.GetServiceBanner:output_type -> coder.agent.v2.ServiceBanner + 23, // 76: coder.agent.v2.Agent.UpdateStats:output_type -> coder.agent.v2.UpdateStatsResponse + 24, // 77: coder.agent.v2.Agent.UpdateLifecycle:output_type -> coder.agent.v2.Lifecycle + 27, // 78: coder.agent.v2.Agent.BatchUpdateAppHealths:output_type -> coder.agent.v2.BatchUpdateAppHealthResponse + 28, // 79: coder.agent.v2.Agent.UpdateStartup:output_type -> coder.agent.v2.Startup + 32, // 80: coder.agent.v2.Agent.BatchUpdateMetadata:output_type -> coder.agent.v2.BatchUpdateMetadataResponse + 35, // 81: coder.agent.v2.Agent.BatchCreateLogs:output_type -> coder.agent.v2.BatchCreateLogsResponse + 37, // 82: coder.agent.v2.Agent.GetAnnouncementBanners:output_type -> coder.agent.v2.GetAnnouncementBannersResponse + 40, // 83: coder.agent.v2.Agent.ScriptCompleted:output_type -> coder.agent.v2.WorkspaceAgentScriptCompletedResponse + 43, // 84: coder.agent.v2.Agent.GetResourcesMonitoringConfiguration:output_type -> coder.agent.v2.GetResourcesMonitoringConfigurationResponse + 45, // 85: coder.agent.v2.Agent.PushResourcesMonitoringUsage:output_type -> coder.agent.v2.PushResourcesMonitoringUsageResponse + 75, // 86: coder.agent.v2.Agent.ReportConnection:output_type -> google.protobuf.Empty + 50, // 87: coder.agent.v2.Agent.CreateSubAgent:output_type -> coder.agent.v2.CreateSubAgentResponse + 52, // 88: coder.agent.v2.Agent.DeleteSubAgent:output_type -> coder.agent.v2.DeleteSubAgentResponse + 54, // 89: coder.agent.v2.Agent.ListSubAgents:output_type -> coder.agent.v2.ListSubAgentsResponse + 74, // [74:90] is the sub-list for method output_type + 58, // [58:74] is the sub-list for method input_type + 58, // [58:58] is the sub-list for extension type_name + 58, // [58:58] is the sub-list for extension extendee + 0, // [0:58] is the sub-list for field type_name } func init() { file_agent_proto_agent_proto_init() } @@ -5409,18 +5870,56 @@ func file_agent_proto_agent_proto_init() { return nil } } + file_agent_proto_agent_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateSubAgentRequest_App); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_agent_proto_agent_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateSubAgentRequest_App_Healthcheck); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_agent_proto_agent_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateSubAgentResponse_AppCreationError); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_agent_proto_agent_proto_msgTypes[3].OneofWrappers = []interface{}{} file_agent_proto_agent_proto_msgTypes[30].OneofWrappers = []interface{}{} file_agent_proto_agent_proto_msgTypes[33].OneofWrappers = []interface{}{} file_agent_proto_agent_proto_msgTypes[53].OneofWrappers = []interface{}{} + file_agent_proto_agent_proto_msgTypes[56].OneofWrappers = []interface{}{} + file_agent_proto_agent_proto_msgTypes[58].OneofWrappers = []interface{}{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_agent_proto_agent_proto_rawDesc, - NumEnums: 11, - NumMessages: 56, + NumEnums: 13, + NumMessages: 59, NumExtensions: 0, NumServices: 1, }, diff --git a/agent/proto/agent.proto b/agent/proto/agent.proto index 53385d97f8b29..67da0ef7787fc 100644 --- a/agent/proto/agent.proto +++ b/agent/proto/agent.proto @@ -388,10 +388,52 @@ message CreateSubAgentRequest { string directory = 2; string architecture = 3; string operating_system = 4; + + message App { + message Healthcheck { + int32 interval = 1; + int32 threshold = 2; + string url = 3; + } + + enum OpenIn { + SLIM_WINDOW = 0; + TAB = 1; + } + + enum Share { + OWNER = 0; + AUTHENTICATED = 1; + PUBLIC = 2; + } + + string slug = 1; + optional string command = 2; + optional string display_name = 3; + optional bool external = 4; + optional string group = 5; + optional Healthcheck healthcheck = 6; + optional bool hidden = 7; + optional string icon = 8; + optional OpenIn open_in = 9; + optional int32 order = 10; + optional Share share = 11; + optional bool subdomain = 12; + optional string url = 13; + } + + repeated App apps = 5; } message CreateSubAgentResponse { + message AppCreationError { + int32 index = 1; + optional string field = 2; + string error = 3; + } + SubAgent agent = 1; + repeated AppCreationError app_creation_errors = 2; } message DeleteSubAgentRequest { diff --git a/cli/server.go b/cli/server.go index 62b430cf22781..9f55b63fc765c 100644 --- a/cli/server.go +++ b/cli/server.go @@ -651,9 +651,9 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. AppHostname: appHostname, AppHostnameRegex: appHostnameRegex, Logger: logger.Named("coderd"), - Database: dbmem.New(), + Database: nil, BaseDERPMap: derpMap, - Pubsub: pubsub.NewInMemory(), + Pubsub: nil, CacheDir: cacheDir, GoogleTokenValidator: googleTokenValidator, ExternalAuthConfigs: externalAuthConfigs, diff --git a/cli/server_test.go b/cli/server_test.go index e4d71e0c3f794..eb3eac8fa5cd4 100644 --- a/cli/server_test.go +++ b/cli/server_test.go @@ -58,6 +58,15 @@ import ( "github.com/coder/coder/v2/testutil" ) +func dbArg(t *testing.T) string { + if !dbtestutil.WillUsePostgres() { + return "--in-memory" + } + dbURL, err := dbtestutil.Open(t) + require.NoError(t, err) + return "--postgres-url=" + dbURL +} + func TestReadExternalAuthProvidersFromEnv(t *testing.T) { t.Parallel() t.Run("Valid", func(t *testing.T) { @@ -267,7 +276,7 @@ func TestServer(t *testing.T) { t.Parallel() inv, cfg := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "http://localhost:3000/", "--cache-dir", t.TempDir(), @@ -475,7 +484,7 @@ func TestServer(t *testing.T) { t.Parallel() inv, cfg := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "http://localhost:3000/", "--cache-dir", t.TempDir(), @@ -498,7 +507,7 @@ func TestServer(t *testing.T) { inv, cfg := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "https://foobarbaz.mydomain", "--cache-dir", t.TempDir(), @@ -519,7 +528,7 @@ func TestServer(t *testing.T) { t.Parallel() inv, cfg := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "https://google.com", "--cache-dir", t.TempDir(), @@ -541,7 +550,7 @@ func TestServer(t *testing.T) { root, _ := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "google.com", "--cache-dir", t.TempDir(), @@ -557,7 +566,7 @@ func TestServer(t *testing.T) { root, _ := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", "", "--access-url", "http://example.com", "--tls-enable", @@ -575,7 +584,7 @@ func TestServer(t *testing.T) { root, _ := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", "", "--access-url", "http://example.com", "--tls-enable", @@ -628,7 +637,7 @@ func TestServer(t *testing.T) { args := []string{ "server", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "http://example.com", "--cache-dir", t.TempDir(), @@ -650,7 +659,7 @@ func TestServer(t *testing.T) { certPath, keyPath := generateTLSCertificate(t) root, cfg := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", "", "--access-url", "https://example.com", "--tls-enable", @@ -686,7 +695,7 @@ func TestServer(t *testing.T) { cert2Path, key2Path := generateTLSCertificate(t, "*.llama.com") root, cfg := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", "", "--access-url", "https://example.com", "--tls-enable", @@ -766,7 +775,7 @@ func TestServer(t *testing.T) { certPath, keyPath := generateTLSCertificate(t) inv, _ := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "https://example.com", "--tls-enable", @@ -894,7 +903,7 @@ func TestServer(t *testing.T) { certPath, keyPath := generateTLSCertificate(t) flags := []string{ "server", - "--in-memory", + dbArg(t), "--cache-dir", t.TempDir(), "--http-address", httpListenAddr, } @@ -1004,33 +1013,19 @@ func TestServer(t *testing.T) { t.Run("CanListenUnspecifiedv4", func(t *testing.T) { t.Parallel() - ctx, cancelFunc := context.WithCancel(context.Background()) - defer cancelFunc() - root, _ := clitest.New(t, + inv, _ := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", "0.0.0.0:0", "--access-url", "http://example.com", ) - pty := ptytest.New(t) - root.Stdout = pty.Output() - root.Stderr = pty.Output() - serverStop := make(chan error, 1) - go func() { - err := root.WithContext(ctx).Run() - if err != nil { - t.Error(err) - } - close(serverStop) - }() + pty := ptytest.New(t).Attach(inv) + clitest.Start(t, inv) pty.ExpectMatch("Started HTTP listener") pty.ExpectMatch("http://0.0.0.0:") - - cancelFunc() - <-serverStop }) t.Run("CanListenUnspecifiedv6", func(t *testing.T) { @@ -1038,7 +1033,7 @@ func TestServer(t *testing.T) { inv, _ := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", "[::]:0", "--access-url", "http://example.com", ) @@ -1057,7 +1052,7 @@ func TestServer(t *testing.T) { inv, _ := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", ":80", "--tls-enable=false", "--tls-address", "", @@ -1074,7 +1069,7 @@ func TestServer(t *testing.T) { inv, _ := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--tls-enable=true", "--tls-address", "", ) @@ -1097,7 +1092,7 @@ func TestServer(t *testing.T) { inv, cfg := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--address", ":0", "--access-url", "http://example.com", "--cache-dir", t.TempDir(), @@ -1124,7 +1119,7 @@ func TestServer(t *testing.T) { certPath, keyPath := generateTLSCertificate(t) root, cfg := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--address", ":0", "--access-url", "https://example.com", "--tls-enable", @@ -1161,7 +1156,7 @@ func TestServer(t *testing.T) { inv, _ := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "http://example.com", "--trace=true", @@ -1180,7 +1175,7 @@ func TestServer(t *testing.T) { inv, cfg := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "http://example.com", "--telemetry", @@ -1220,7 +1215,7 @@ func TestServer(t *testing.T) { ctx := testutil.Context(t, testutil.WaitLong) inv, _ := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "http://example.com", "--provisioner-daemons", "1", @@ -1282,7 +1277,7 @@ func TestServer(t *testing.T) { ctx := testutil.Context(t, testutil.WaitLong) inv, _ := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "http://example.com", "--provisioner-daemons", "1", @@ -1339,7 +1334,7 @@ func TestServer(t *testing.T) { fakeRedirect := "https://fake-url.com" inv, cfg := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "http://example.com", "--oauth2-github-allow-everyone", @@ -1386,7 +1381,7 @@ func TestServer(t *testing.T) { inv, cfg := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "http://example.com", "--oidc-client-id", "fake", @@ -1462,7 +1457,7 @@ func TestServer(t *testing.T) { inv, cfg := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "http://example.com", "--oidc-client-id", "fake", @@ -1556,7 +1551,7 @@ func TestServer(t *testing.T) { root, cfg := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "http://example.com", ) @@ -1584,7 +1579,7 @@ func TestServer(t *testing.T) { val := "100" root, cfg := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "http://example.com", "--api-rate-limit", val, @@ -1612,7 +1607,7 @@ func TestServer(t *testing.T) { root, cfg := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "http://example.com", "--api-rate-limit", "-1", @@ -1644,7 +1639,7 @@ func TestServer(t *testing.T) { root, _ := clitest.New(t, "server", "--log-filter=.*", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "http://example.com", "--provisioner-daemons=3", @@ -1663,7 +1658,7 @@ func TestServer(t *testing.T) { root, _ := clitest.New(t, "server", "--log-filter=.*", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "http://example.com", "--provisioner-daemons=3", @@ -1682,7 +1677,7 @@ func TestServer(t *testing.T) { root, _ := clitest.New(t, "server", "--log-filter=.*", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "http://example.com", "--provisioner-daemons=3", @@ -1706,7 +1701,7 @@ func TestServer(t *testing.T) { args := []string{ "server", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "http://example.com", "--log-human", filepath.Join(t.TempDir(), "coder-logging-test-human"), @@ -1750,7 +1745,7 @@ func TestServer(t *testing.T) { ctx = testutil.Context(t, testutil.WaitMedium) // Finally, we restart the server with just the config and no flags // and ensure that the live configuration is equivalent. - inv, cfg = clitest.New(t, "server", "--config="+fi.Name()) + inv, cfg = clitest.New(t, "server", "--config="+fi.Name(), dbArg(t)) w = clitest.StartWithWaiter(t, inv) client = codersdk.New(waitAccessURL(t, cfg)) _ = coderdtest.CreateFirstUser(t, client) @@ -1820,7 +1815,7 @@ func TestServer_Logging_NoParallel(t *testing.T) { inv, _ := clitest.New(t, "server", "--log-filter=.*", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "http://example.com", "--provisioner-daemons=3", @@ -1855,7 +1850,7 @@ func TestServer_Logging_NoParallel(t *testing.T) { inv, _ := clitest.New(t, "server", "--log-filter=.*", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "http://example.com", "--provisioner-daemons=3", @@ -1906,8 +1901,6 @@ func TestServer_Production(t *testing.T) { // Skip on non-Linux because it spawns a PostgreSQL instance. t.SkipNow() } - connectionURL, err := dbtestutil.Open(t) - require.NoError(t, err) // Postgres + race detector + CI = slow. ctx, cancelFunc := context.WithTimeout(context.Background(), testutil.WaitSuperLong*3) @@ -1917,14 +1910,14 @@ func TestServer_Production(t *testing.T) { "server", "--http-address", ":0", "--access-url", "http://example.com", - "--postgres-url", connectionURL, + dbArg(t), "--cache-dir", t.TempDir(), ) clitest.Start(t, inv.WithContext(ctx)) accessURL := waitAccessURL(t, cfg) client := codersdk.New(accessURL) - _, err = client.CreateFirstUser(ctx, coderdtest.FirstUserParams) + _, err := client.CreateFirstUser(ctx, coderdtest.FirstUserParams) require.NoError(t, err) } @@ -1974,7 +1967,7 @@ func TestServer_InterruptShutdown(t *testing.T) { root, cfg := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "http://example.com", "--provisioner-daemons", "1", @@ -2006,7 +1999,7 @@ func TestServer_GracefulShutdown(t *testing.T) { root, cfg := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "http://example.com", "--provisioner-daemons", "1", @@ -2190,9 +2183,10 @@ func TestServer_InvalidDERP(t *testing.T) { // Try to start a server with the built-in DERP server disabled and no // external DERP map. + inv, _ := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "http://example.com", "--derp-server-enable=false", @@ -2220,7 +2214,7 @@ func TestServer_DisabledDERP(t *testing.T) { // external DERP map. inv, cfg := clitest.New(t, "server", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "http://example.com", "--derp-server-enable=false", diff --git a/coderd/agentapi/subagent.go b/coderd/agentapi/subagent.go index 3b9ae9674d91e..43399fed16e77 100644 --- a/coderd/agentapi/subagent.go +++ b/coderd/agentapi/subagent.go @@ -2,6 +2,9 @@ package agentapi import ( "context" + "database/sql" + "errors" + "fmt" "github.com/google/uuid" "github.com/sqlc-dev/pqtype" @@ -11,6 +14,7 @@ import ( agentproto "github.com/coder/coder/v2/agent/proto" "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbauthz" + "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/provisioner" "github.com/coder/quartz" ) @@ -37,10 +41,16 @@ func (a *SubAgentAPI) CreateSubAgent(ctx context.Context, req *agentproto.Create agentName := req.Name if agentName == "" { - return nil, xerrors.Errorf("agent name cannot be empty") + return nil, codersdk.ValidationError{ + Field: "name", + Detail: "agent name cannot be empty", + } } if !provisioner.AgentNameRegex.MatchString(agentName) { - return nil, xerrors.Errorf("agent name %q does not match regex %q", agentName, provisioner.AgentNameRegex.String()) + return nil, codersdk.ValidationError{ + Field: "name", + Detail: fmt.Sprintf("agent name %q does not match regex %q", agentName, provisioner.AgentNameRegex), + } } createdAt := a.Clock.Now() @@ -71,12 +81,127 @@ func (a *SubAgentAPI) CreateSubAgent(ctx context.Context, req *agentproto.Create return nil, xerrors.Errorf("insert sub agent: %w", err) } + var appCreationErrors []*agentproto.CreateSubAgentResponse_AppCreationError + appSlugs := make(map[string]struct{}) + + for i, app := range req.Apps { + err := func() error { + slug := app.Slug + if slug == "" { + return codersdk.ValidationError{ + Field: "slug", + Detail: "must not be empty", + } + } + if !provisioner.AppSlugRegex.MatchString(slug) { + return codersdk.ValidationError{ + Field: "slug", + Detail: fmt.Sprintf("%q does not match regex %q", slug, provisioner.AppSlugRegex), + } + } + if _, exists := appSlugs[slug]; exists { + return codersdk.ValidationError{ + Field: "slug", + Detail: fmt.Sprintf("%q is already in use", slug), + } + } + appSlugs[slug] = struct{}{} + + health := database.WorkspaceAppHealthDisabled + if app.Healthcheck == nil { + app.Healthcheck = &agentproto.CreateSubAgentRequest_App_Healthcheck{} + } + if app.Healthcheck.Url != "" { + health = database.WorkspaceAppHealthInitializing + } + + var sharingLevel database.AppSharingLevel + switch app.GetShare() { + case agentproto.CreateSubAgentRequest_App_OWNER: + sharingLevel = database.AppSharingLevelOwner + case agentproto.CreateSubAgentRequest_App_AUTHENTICATED: + sharingLevel = database.AppSharingLevelAuthenticated + case agentproto.CreateSubAgentRequest_App_PUBLIC: + sharingLevel = database.AppSharingLevelPublic + default: + return codersdk.ValidationError{ + Field: "share", + Detail: fmt.Sprintf("%q is not a valid app sharing level", app.GetShare()), + } + } + + var openIn database.WorkspaceAppOpenIn + switch app.GetOpenIn() { + case agentproto.CreateSubAgentRequest_App_SLIM_WINDOW: + openIn = database.WorkspaceAppOpenInSlimWindow + case agentproto.CreateSubAgentRequest_App_TAB: + openIn = database.WorkspaceAppOpenInTab + default: + return codersdk.ValidationError{ + Field: "open_in", + Detail: fmt.Sprintf("%q is not an open in setting", app.GetOpenIn()), + } + } + + _, err := a.Database.InsertWorkspaceApp(ctx, database.InsertWorkspaceAppParams{ + ID: uuid.New(), + CreatedAt: createdAt, + AgentID: subAgent.ID, + Slug: app.Slug, + DisplayName: app.GetDisplayName(), + Icon: app.GetIcon(), + Command: sql.NullString{ + Valid: app.GetCommand() != "", + String: app.GetCommand(), + }, + Url: sql.NullString{ + Valid: app.GetUrl() != "", + String: app.GetUrl(), + }, + External: app.GetExternal(), + Subdomain: app.GetSubdomain(), + SharingLevel: sharingLevel, + HealthcheckUrl: app.Healthcheck.Url, + HealthcheckInterval: app.Healthcheck.Interval, + HealthcheckThreshold: app.Healthcheck.Threshold, + Health: health, + DisplayOrder: app.GetOrder(), + Hidden: app.GetHidden(), + OpenIn: openIn, + DisplayGroup: sql.NullString{ + Valid: app.GetGroup() != "", + String: app.GetGroup(), + }, + }) + if err != nil { + return xerrors.Errorf("insert workspace app: %w", err) + } + + return nil + }() + if err != nil { + appErr := &agentproto.CreateSubAgentResponse_AppCreationError{ + Index: int32(i), //nolint:gosec // This would only overflow if we created 2 billion apps. + Error: err.Error(), + } + + var validationErr codersdk.ValidationError + if errors.As(err, &validationErr) { + appErr.Field = &validationErr.Field + appErr.Error = validationErr.Detail + } + + appCreationErrors = append(appCreationErrors, appErr) + } + } + return &agentproto.CreateSubAgentResponse{ Agent: &agentproto.SubAgent{ Name: subAgent.Name, Id: subAgent.ID[:], AuthToken: subAgent.AuthToken[:], }, + AppCreationErrors: appCreationErrors, }, nil } diff --git a/coderd/agentapi/subagent_test.go b/coderd/agentapi/subagent_test.go index 2ca1b35451945..e202b62df8fb2 100644 --- a/coderd/agentapi/subagent_test.go +++ b/coderd/agentapi/subagent_test.go @@ -21,6 +21,8 @@ import ( "github.com/coder/coder/v2/coderd/database/dbgen" "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/rbac" + "github.com/coder/coder/v2/coderd/util/ptr" + "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/testutil" "github.com/coder/quartz" ) @@ -92,12 +94,12 @@ func TestSubAgentAPI(t *testing.T) { t.Parallel() tests := []struct { - name string - agentName string - agentDir string - agentArch string - agentOS string - shouldErr bool + name string + agentName string + agentDir string + agentArch string + agentOS string + expectedError *codersdk.ValidationError }{ { name: "Ok", @@ -112,7 +114,10 @@ func TestSubAgentAPI(t *testing.T) { agentDir: "/workspaces/wibble", agentArch: "amd64", agentOS: "linux", - shouldErr: true, + expectedError: &codersdk.ValidationError{ + Field: "name", + Detail: "agent name \"some_child_agent\" does not match regex \"(?i)^[a-z0-9](-?[a-z0-9])*$\"", + }, }, { name: "EmptyName", @@ -120,7 +125,10 @@ func TestSubAgentAPI(t *testing.T) { agentDir: "/workspaces/wibble", agentArch: "amd64", agentOS: "linux", - shouldErr: true, + expectedError: &codersdk.ValidationError{ + Field: "name", + Detail: "agent name cannot be empty", + }, }, } @@ -142,8 +150,11 @@ func TestSubAgentAPI(t *testing.T) { Architecture: tt.agentArch, OperatingSystem: tt.agentOS, }) - if tt.shouldErr { + if tt.expectedError != nil { require.Error(t, err) + var validationErr codersdk.ValidationError + require.ErrorAs(t, err, &validationErr) + require.Equal(t, *tt.expectedError, validationErr) } else { require.NoError(t, err) @@ -164,6 +175,590 @@ func TestSubAgentAPI(t *testing.T) { } }) + type expectedAppError struct { + index int32 + field string + error string + } + + t.Run("CreateSubAgentWithApps", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + apps []*proto.CreateSubAgentRequest_App + expectApps []database.WorkspaceApp + expectedAppErrors []expectedAppError + }{ + { + name: "OK", + apps: []*proto.CreateSubAgentRequest_App{ + { + Slug: "code-server", + DisplayName: ptr.Ref("VS Code"), + Icon: ptr.Ref("/icon/code.svg"), + Url: ptr.Ref("http://localhost:13337"), + Share: proto.CreateSubAgentRequest_App_OWNER.Enum(), + Subdomain: ptr.Ref(false), + OpenIn: proto.CreateSubAgentRequest_App_SLIM_WINDOW.Enum(), + Healthcheck: &proto.CreateSubAgentRequest_App_Healthcheck{ + Interval: 5, + Threshold: 6, + Url: "http://localhost:13337/healthz", + }, + }, + { + Slug: "vim", + Command: ptr.Ref("vim"), + DisplayName: ptr.Ref("Vim"), + Icon: ptr.Ref("/icon/vim.svg"), + }, + }, + expectApps: []database.WorkspaceApp{ + { + Slug: "code-server", + DisplayName: "VS Code", + Icon: "/icon/code.svg", + Command: sql.NullString{}, + Url: sql.NullString{Valid: true, String: "http://localhost:13337"}, + HealthcheckUrl: "http://localhost:13337/healthz", + HealthcheckInterval: 5, + HealthcheckThreshold: 6, + Health: database.WorkspaceAppHealthInitializing, + Subdomain: false, + SharingLevel: database.AppSharingLevelOwner, + External: false, + DisplayOrder: 0, + Hidden: false, + OpenIn: database.WorkspaceAppOpenInSlimWindow, + DisplayGroup: sql.NullString{}, + }, + { + Slug: "vim", + DisplayName: "Vim", + Icon: "/icon/vim.svg", + Command: sql.NullString{Valid: true, String: "vim"}, + Health: database.WorkspaceAppHealthDisabled, + SharingLevel: database.AppSharingLevelOwner, + OpenIn: database.WorkspaceAppOpenInSlimWindow, + }, + }, + }, + { + name: "EmptyAppSlug", + apps: []*proto.CreateSubAgentRequest_App{ + { + Slug: "", + DisplayName: ptr.Ref("App"), + }, + }, + expectApps: []database.WorkspaceApp{}, + expectedAppErrors: []expectedAppError{ + { + index: 0, + field: "slug", + error: "must not be empty", + }, + }, + }, + { + name: "InvalidAppSlugWithUnderscores", + apps: []*proto.CreateSubAgentRequest_App{ + { + Slug: "invalid_slug_with_underscores", + DisplayName: ptr.Ref("App"), + }, + }, + expectApps: []database.WorkspaceApp{}, + expectedAppErrors: []expectedAppError{ + { + index: 0, + field: "slug", + error: "\"invalid_slug_with_underscores\" does not match regex \"^[a-z0-9](-?[a-z0-9])*$\"", + }, + }, + }, + { + name: "InvalidAppSlugWithUppercase", + apps: []*proto.CreateSubAgentRequest_App{ + { + Slug: "InvalidSlug", + DisplayName: ptr.Ref("App"), + }, + }, + expectApps: []database.WorkspaceApp{}, + expectedAppErrors: []expectedAppError{ + { + index: 0, + field: "slug", + error: "\"InvalidSlug\" does not match regex \"^[a-z0-9](-?[a-z0-9])*$\"", + }, + }, + }, + { + name: "InvalidAppSlugStartsWithHyphen", + apps: []*proto.CreateSubAgentRequest_App{ + { + Slug: "-invalid-app", + DisplayName: ptr.Ref("App"), + }, + }, + expectApps: []database.WorkspaceApp{}, + expectedAppErrors: []expectedAppError{ + { + index: 0, + field: "slug", + error: "\"-invalid-app\" does not match regex \"^[a-z0-9](-?[a-z0-9])*$\"", + }, + }, + }, + { + name: "InvalidAppSlugEndsWithHyphen", + apps: []*proto.CreateSubAgentRequest_App{ + { + Slug: "invalid-app-", + DisplayName: ptr.Ref("App"), + }, + }, + expectApps: []database.WorkspaceApp{}, + expectedAppErrors: []expectedAppError{ + { + index: 0, + field: "slug", + error: "\"invalid-app-\" does not match regex \"^[a-z0-9](-?[a-z0-9])*$\"", + }, + }, + }, + { + name: "InvalidAppSlugWithDoubleHyphens", + apps: []*proto.CreateSubAgentRequest_App{ + { + Slug: "invalid--app", + DisplayName: ptr.Ref("App"), + }, + }, + expectApps: []database.WorkspaceApp{}, + expectedAppErrors: []expectedAppError{ + { + index: 0, + field: "slug", + error: "\"invalid--app\" does not match regex \"^[a-z0-9](-?[a-z0-9])*$\"", + }, + }, + }, + { + name: "InvalidAppSlugWithSpaces", + apps: []*proto.CreateSubAgentRequest_App{ + { + Slug: "invalid app", + DisplayName: ptr.Ref("App"), + }, + }, + expectApps: []database.WorkspaceApp{}, + expectedAppErrors: []expectedAppError{ + { + index: 0, + field: "slug", + error: "\"invalid app\" does not match regex \"^[a-z0-9](-?[a-z0-9])*$\"", + }, + }, + }, + { + name: "MultipleAppsWithErrorInSecond", + apps: []*proto.CreateSubAgentRequest_App{ + { + Slug: "valid-app", + DisplayName: ptr.Ref("Valid App"), + }, + { + Slug: "Invalid_App", + DisplayName: ptr.Ref("Invalid App"), + }, + }, + expectApps: []database.WorkspaceApp{ + { + Slug: "valid-app", + DisplayName: "Valid App", + SharingLevel: database.AppSharingLevelOwner, + Health: database.WorkspaceAppHealthDisabled, + OpenIn: database.WorkspaceAppOpenInSlimWindow, + }, + }, + expectedAppErrors: []expectedAppError{ + { + index: 1, + field: "slug", + error: "\"Invalid_App\" does not match regex \"^[a-z0-9](-?[a-z0-9])*$\"", + }, + }, + }, + { + name: "AppWithAllSharingLevels", + apps: []*proto.CreateSubAgentRequest_App{ + { + Slug: "owner-app", + Share: proto.CreateSubAgentRequest_App_OWNER.Enum(), + }, + { + Slug: "authenticated-app", + Share: proto.CreateSubAgentRequest_App_AUTHENTICATED.Enum(), + }, + { + Slug: "public-app", + Share: proto.CreateSubAgentRequest_App_PUBLIC.Enum(), + }, + }, + expectApps: []database.WorkspaceApp{ + { + Slug: "authenticated-app", + SharingLevel: database.AppSharingLevelAuthenticated, + Health: database.WorkspaceAppHealthDisabled, + OpenIn: database.WorkspaceAppOpenInSlimWindow, + }, + { + Slug: "owner-app", + SharingLevel: database.AppSharingLevelOwner, + Health: database.WorkspaceAppHealthDisabled, + OpenIn: database.WorkspaceAppOpenInSlimWindow, + }, + { + Slug: "public-app", + SharingLevel: database.AppSharingLevelPublic, + Health: database.WorkspaceAppHealthDisabled, + OpenIn: database.WorkspaceAppOpenInSlimWindow, + }, + }, + }, + { + name: "AppWithDifferentOpenInOptions", + apps: []*proto.CreateSubAgentRequest_App{ + { + Slug: "window-app", + OpenIn: proto.CreateSubAgentRequest_App_SLIM_WINDOW.Enum(), + }, + { + Slug: "tab-app", + OpenIn: proto.CreateSubAgentRequest_App_TAB.Enum(), + }, + }, + expectApps: []database.WorkspaceApp{ + { + Slug: "tab-app", + SharingLevel: database.AppSharingLevelOwner, + Health: database.WorkspaceAppHealthDisabled, + OpenIn: database.WorkspaceAppOpenInTab, + }, + { + Slug: "window-app", + SharingLevel: database.AppSharingLevelOwner, + Health: database.WorkspaceAppHealthDisabled, + OpenIn: database.WorkspaceAppOpenInSlimWindow, + }, + }, + }, + { + name: "AppWithAllOptionalFields", + apps: []*proto.CreateSubAgentRequest_App{ + { + Slug: "full-app", + Command: ptr.Ref("echo hello"), + DisplayName: ptr.Ref("Full Featured App"), + External: ptr.Ref(true), + Group: ptr.Ref("Development"), + Hidden: ptr.Ref(true), + Icon: ptr.Ref("/icon/app.svg"), + Order: ptr.Ref(int32(10)), + Subdomain: ptr.Ref(true), + Url: ptr.Ref("http://localhost:8080"), + Healthcheck: &proto.CreateSubAgentRequest_App_Healthcheck{ + Interval: 30, + Threshold: 3, + Url: "http://localhost:8080/health", + }, + }, + }, + expectApps: []database.WorkspaceApp{ + { + Slug: "full-app", + Command: sql.NullString{Valid: true, String: "echo hello"}, + DisplayName: "Full Featured App", + External: true, + DisplayGroup: sql.NullString{Valid: true, String: "Development"}, + Hidden: true, + Icon: "/icon/app.svg", + DisplayOrder: 10, + Subdomain: true, + Url: sql.NullString{Valid: true, String: "http://localhost:8080"}, + HealthcheckUrl: "http://localhost:8080/health", + HealthcheckInterval: 30, + HealthcheckThreshold: 3, + Health: database.WorkspaceAppHealthInitializing, + SharingLevel: database.AppSharingLevelOwner, + OpenIn: database.WorkspaceAppOpenInSlimWindow, + }, + }, + }, + { + name: "AppWithoutHealthcheck", + apps: []*proto.CreateSubAgentRequest_App{ + { + Slug: "no-health-app", + }, + }, + expectApps: []database.WorkspaceApp{ + { + Slug: "no-health-app", + Health: database.WorkspaceAppHealthDisabled, + SharingLevel: database.AppSharingLevelOwner, + OpenIn: database.WorkspaceAppOpenInSlimWindow, + HealthcheckUrl: "", + HealthcheckInterval: 0, + HealthcheckThreshold: 0, + }, + }, + }, + { + name: "DuplicateAppSlugs", + apps: []*proto.CreateSubAgentRequest_App{ + { + Slug: "duplicate-app", + DisplayName: ptr.Ref("First App"), + }, + { + Slug: "duplicate-app", + DisplayName: ptr.Ref("Second App"), + }, + }, + expectApps: []database.WorkspaceApp{ + { + Slug: "duplicate-app", + DisplayName: "First App", + SharingLevel: database.AppSharingLevelOwner, + Health: database.WorkspaceAppHealthDisabled, + OpenIn: database.WorkspaceAppOpenInSlimWindow, + }, + }, + expectedAppErrors: []expectedAppError{ + { + index: 1, + field: "slug", + error: "\"duplicate-app\" is already in use", + }, + }, + }, + { + name: "MultipleDuplicateAppSlugs", + apps: []*proto.CreateSubAgentRequest_App{ + { + Slug: "valid-app", + DisplayName: ptr.Ref("Valid App"), + }, + { + Slug: "duplicate-app", + DisplayName: ptr.Ref("First Duplicate"), + }, + { + Slug: "duplicate-app", + DisplayName: ptr.Ref("Second Duplicate"), + }, + { + Slug: "duplicate-app", + DisplayName: ptr.Ref("Third Duplicate"), + }, + }, + expectApps: []database.WorkspaceApp{ + { + Slug: "duplicate-app", + DisplayName: "First Duplicate", + SharingLevel: database.AppSharingLevelOwner, + Health: database.WorkspaceAppHealthDisabled, + OpenIn: database.WorkspaceAppOpenInSlimWindow, + }, + { + Slug: "valid-app", + DisplayName: "Valid App", + SharingLevel: database.AppSharingLevelOwner, + Health: database.WorkspaceAppHealthDisabled, + OpenIn: database.WorkspaceAppOpenInSlimWindow, + }, + }, + expectedAppErrors: []expectedAppError{ + { + index: 2, + field: "slug", + error: "\"duplicate-app\" is already in use", + }, + { + index: 3, + field: "slug", + error: "\"duplicate-app\" is already in use", + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + log := testutil.Logger(t) + ctx := testutil.Context(t, testutil.WaitShort) + clock := quartz.NewMock(t) + + db, org := newDatabaseWithOrg(t) + user, agent := newUserWithWorkspaceAgent(t, db, org) + api := newAgentAPI(t, log, db, clock, user, org, agent) + + createResp, err := api.CreateSubAgent(ctx, &proto.CreateSubAgentRequest{ + Name: "child-agent", + Directory: "/workspaces/coder", + Architecture: "amd64", + OperatingSystem: "linux", + Apps: tt.apps, + }) + require.NoError(t, err) + + agentID, err := uuid.FromBytes(createResp.Agent.Id) + require.NoError(t, err) + + apps, err := api.Database.GetWorkspaceAppsByAgentID(dbauthz.AsSystemRestricted(ctx), agentID) //nolint:gocritic // this is a test. + require.NoError(t, err) + + // Sort the apps for determinism + slices.SortFunc(apps, func(a, b database.WorkspaceApp) int { + return cmp.Compare(a.Slug, b.Slug) + }) + slices.SortFunc(tt.expectApps, func(a, b database.WorkspaceApp) int { + return cmp.Compare(a.Slug, b.Slug) + }) + + require.Len(t, apps, len(tt.expectApps)) + + for idx, app := range apps { + assert.Equal(t, tt.expectApps[idx].Slug, app.Slug) + assert.Equal(t, tt.expectApps[idx].Command, app.Command) + assert.Equal(t, tt.expectApps[idx].DisplayName, app.DisplayName) + assert.Equal(t, tt.expectApps[idx].External, app.External) + assert.Equal(t, tt.expectApps[idx].DisplayGroup, app.DisplayGroup) + assert.Equal(t, tt.expectApps[idx].HealthcheckInterval, app.HealthcheckInterval) + assert.Equal(t, tt.expectApps[idx].HealthcheckThreshold, app.HealthcheckThreshold) + assert.Equal(t, tt.expectApps[idx].HealthcheckUrl, app.HealthcheckUrl) + assert.Equal(t, tt.expectApps[idx].Hidden, app.Hidden) + assert.Equal(t, tt.expectApps[idx].Icon, app.Icon) + assert.Equal(t, tt.expectApps[idx].OpenIn, app.OpenIn) + assert.Equal(t, tt.expectApps[idx].DisplayOrder, app.DisplayOrder) + assert.Equal(t, tt.expectApps[idx].SharingLevel, app.SharingLevel) + assert.Equal(t, tt.expectApps[idx].Subdomain, app.Subdomain) + assert.Equal(t, tt.expectApps[idx].Url, app.Url) + } + + // Verify expected app creation errors + require.Len(t, createResp.AppCreationErrors, len(tt.expectedAppErrors), "Number of app creation errors should match expected") + + // Build a map of actual errors by index for easier testing + actualErrorMap := make(map[int32]*proto.CreateSubAgentResponse_AppCreationError) + for _, appErr := range createResp.AppCreationErrors { + actualErrorMap[appErr.Index] = appErr + } + + // Verify each expected error + for _, expectedErr := range tt.expectedAppErrors { + actualErr, exists := actualErrorMap[expectedErr.index] + require.True(t, exists, "Expected app creation error at index %d", expectedErr.index) + + require.NotNil(t, actualErr.Field, "Field should be set for validation error at index %d", expectedErr.index) + require.Equal(t, expectedErr.field, *actualErr.Field, "Field name should match for error at index %d", expectedErr.index) + require.Contains(t, actualErr.Error, expectedErr.error, "Error message should contain expected text for error at index %d", expectedErr.index) + } + }) + } + + t.Run("ValidationErrorFieldMapping", func(t *testing.T) { + t.Parallel() + + log := testutil.Logger(t) + ctx := testutil.Context(t, testutil.WaitShort) + clock := quartz.NewMock(t) + + db, org := newDatabaseWithOrg(t) + user, agent := newUserWithWorkspaceAgent(t, db, org) + api := newAgentAPI(t, log, db, clock, user, org, agent) + + // Test different types of validation errors to ensure field mapping works correctly + createResp, err := api.CreateSubAgent(ctx, &proto.CreateSubAgentRequest{ + Name: "validation-test-agent", + Directory: "/workspace", + Architecture: "amd64", + OperatingSystem: "linux", + Apps: []*proto.CreateSubAgentRequest_App{ + { + Slug: "", // Empty slug - should error on apps[0].slug + DisplayName: ptr.Ref("Empty Slug App"), + }, + { + Slug: "Invalid_Slug_With_Underscores", // Invalid characters - should error on apps[1].slug + DisplayName: ptr.Ref("Invalid Characters App"), + }, + { + Slug: "duplicate-slug", // First occurrence - should succeed + DisplayName: ptr.Ref("First Duplicate"), + }, + { + Slug: "duplicate-slug", // Duplicate - should error on apps[3].slug + DisplayName: ptr.Ref("Second Duplicate"), + }, + { + Slug: "-invalid-start", // Invalid start character - should error on apps[4].slug + DisplayName: ptr.Ref("Invalid Start App"), + }, + }, + }) + + // Agent should be created successfully + require.NoError(t, err) + require.NotNil(t, createResp.Agent) + + // Should have 4 app creation errors (indices 0, 1, 3, 4) + require.Len(t, createResp.AppCreationErrors, 4) + + errorMap := make(map[int32]*proto.CreateSubAgentResponse_AppCreationError) + for _, appErr := range createResp.AppCreationErrors { + errorMap[appErr.Index] = appErr + } + + // Verify each specific validation error and its field + require.Contains(t, errorMap, int32(0)) + require.NotNil(t, errorMap[0].Field) + require.Equal(t, "slug", *errorMap[0].Field) + require.Contains(t, errorMap[0].Error, "must not be empty") + + require.Contains(t, errorMap, int32(1)) + require.NotNil(t, errorMap[1].Field) + require.Equal(t, "slug", *errorMap[1].Field) + require.Contains(t, errorMap[1].Error, "Invalid_Slug_With_Underscores") + + require.Contains(t, errorMap, int32(3)) + require.NotNil(t, errorMap[3].Field) + require.Equal(t, "slug", *errorMap[3].Field) + require.Contains(t, errorMap[3].Error, "duplicate-slug") + + require.Contains(t, errorMap, int32(4)) + require.NotNil(t, errorMap[4].Field) + require.Equal(t, "slug", *errorMap[4].Field) + require.Contains(t, errorMap[4].Error, "-invalid-start") + + // Verify only the valid app (index 2) was created + agentID, err := uuid.FromBytes(createResp.Agent.Id) + require.NoError(t, err) + + apps, err := db.GetWorkspaceAppsByAgentID(dbauthz.AsSystemRestricted(ctx), agentID) //nolint:gocritic // this is a test. + require.NoError(t, err) + require.Len(t, apps, 1) + require.Equal(t, "duplicate-slug", apps[0].Slug) + require.Equal(t, "First Duplicate", apps[0].DisplayName) + }) + }) + t.Run("DeleteSubAgent", func(t *testing.T) { t.Parallel() @@ -279,6 +874,69 @@ func TestSubAgentAPI(t *testing.T) { _, err = db.GetWorkspaceAgentByID(dbauthz.AsSystemRestricted(ctx), childAgentOne.ID) //nolint:gocritic // this is a test. require.NoError(t, err) }) + + t.Run("DeletesWorkspaceApps", func(t *testing.T) { + t.Parallel() + + // Skip test on in-memory database since CASCADE DELETE is not implemented + if !dbtestutil.WillUsePostgres() { + t.Skip("CASCADE DELETE behavior requires PostgreSQL") + } + + log := testutil.Logger(t) + ctx := testutil.Context(t, testutil.WaitShort) + clock := quartz.NewMock(t) + + db, org := newDatabaseWithOrg(t) + user, agent := newUserWithWorkspaceAgent(t, db, org) + api := newAgentAPI(t, log, db, clock, user, org, agent) + + // Given: A sub agent with workspace apps + createResp, err := api.CreateSubAgent(ctx, &proto.CreateSubAgentRequest{ + Name: "child-agent-with-apps", + Directory: "/workspaces/coder", + Architecture: "amd64", + OperatingSystem: "linux", + Apps: []*proto.CreateSubAgentRequest_App{ + { + Slug: "code-server", + DisplayName: ptr.Ref("VS Code"), + Icon: ptr.Ref("/icon/code.svg"), + Url: ptr.Ref("http://localhost:13337"), + }, + { + Slug: "vim", + Command: ptr.Ref("vim"), + DisplayName: ptr.Ref("Vim"), + }, + }, + }) + require.NoError(t, err) + + subAgentID, err := uuid.FromBytes(createResp.Agent.Id) + require.NoError(t, err) + + // Verify that the apps were created + apps, err := api.Database.GetWorkspaceAppsByAgentID(dbauthz.AsSystemRestricted(ctx), subAgentID) //nolint:gocritic // this is a test. + require.NoError(t, err) + require.Len(t, apps, 2) + + // When: We delete the sub agent + _, err = api.DeleteSubAgent(ctx, &proto.DeleteSubAgentRequest{ + Id: createResp.Agent.Id, + }) + require.NoError(t, err) + + // Then: The agent is deleted + _, err = api.Database.GetWorkspaceAgentByID(dbauthz.AsSystemRestricted(ctx), subAgentID) //nolint:gocritic // this is a test. + require.ErrorIs(t, err, sql.ErrNoRows) + + // And: The apps are also deleted (due to CASCADE DELETE) + // Use raw database since authorization layer requires agent to exist + appsAfterDeletion, err := db.GetWorkspaceAppsByAgentID(ctx, subAgentID) + require.NoError(t, err) + require.Empty(t, appsAfterDeletion) + }) }) t.Run("ListSubAgents", func(t *testing.T) { diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 5290d65823117..5bfa015af3d78 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -333,7 +333,7 @@ var ( orgID.String(): {}, }, User: rbac.Permissions(map[string][]policy.Action{ - rbac.ResourceWorkspace.Type: {policy.ActionRead, policy.ActionCreateAgent, policy.ActionDeleteAgent}, + rbac.ResourceWorkspace.Type: {policy.ActionRead, policy.ActionUpdate, policy.ActionCreateAgent, policy.ActionDeleteAgent}, }), }, }), diff --git a/coderd/prometheusmetrics/prometheusmetrics_test.go b/coderd/prometheusmetrics/prometheusmetrics_test.go index be804b3a855b0..34309042c5f55 100644 --- a/coderd/prometheusmetrics/prometheusmetrics_test.go +++ b/coderd/prometheusmetrics/prometheusmetrics_test.go @@ -4,6 +4,7 @@ import ( "context" "database/sql" "encoding/json" + "errors" "fmt" "os" "reflect" @@ -25,7 +26,6 @@ import ( "github.com/coder/coder/v2/coderd/coderdtest" "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbgen" - "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/prometheusmetrics" @@ -51,13 +51,15 @@ func TestActiveUsers(t *testing.T) { }{{ Name: "None", Database: func(t *testing.T) database.Store { - return dbmem.New() + db, _ := dbtestutil.NewDB(t) + return db }, Count: 0, }, { Name: "One", Database: func(t *testing.T) database.Store { - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) + dbtestutil.DisableForeignKeysAndTriggers(t, db) dbgen.APIKey(t, db, database.APIKey{ LastUsed: dbtime.Now(), }) @@ -67,7 +69,8 @@ func TestActiveUsers(t *testing.T) { }, { Name: "OneWithExpired", Database: func(t *testing.T) database.Store { - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) + dbtestutil.DisableForeignKeysAndTriggers(t, db) dbgen.APIKey(t, db, database.APIKey{ LastUsed: dbtime.Now(), @@ -84,7 +87,8 @@ func TestActiveUsers(t *testing.T) { }, { Name: "Multiple", Database: func(t *testing.T) database.Store { - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) + dbtestutil.DisableForeignKeysAndTriggers(t, db) dbgen.APIKey(t, db, database.APIKey{ LastUsed: dbtime.Now(), }) @@ -123,13 +127,14 @@ func TestUsers(t *testing.T) { }{{ Name: "None", Database: func(t *testing.T) database.Store { - return dbmem.New() + db, _ := dbtestutil.NewDB(t) + return db }, Count: map[database.UserStatus]int{}, }, { Name: "One", Database: func(t *testing.T) database.Store { - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) dbgen.User(t, db, database.User{Status: database.UserStatusActive}) return db }, @@ -137,7 +142,7 @@ func TestUsers(t *testing.T) { }, { Name: "MultipleStatuses", Database: func(t *testing.T) database.Store { - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) dbgen.User(t, db, database.User{Status: database.UserStatusActive}) dbgen.User(t, db, database.User{Status: database.UserStatusDormant}) @@ -148,7 +153,7 @@ func TestUsers(t *testing.T) { }, { Name: "MultipleActive", Database: func(t *testing.T) database.Store { - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) dbgen.User(t, db, database.User{Status: database.UserStatusActive}) dbgen.User(t, db, database.User{Status: database.UserStatusActive}) dbgen.User(t, db, database.User{Status: database.UserStatusActive}) @@ -216,20 +221,25 @@ func TestWorkspaceLatestBuildTotals(t *testing.T) { Total int Status map[codersdk.ProvisionerJobStatus]int }{{ - Name: "None", - Database: dbmem.New, - Total: 0, + Name: "None", + Database: func() database.Store { + db, _ := dbtestutil.NewDB(t) + return db + }, + Total: 0, }, { Name: "Multiple", Database: func() database.Store { - db := dbmem.New() - insertCanceled(t, db) - insertFailed(t, db) - insertFailed(t, db) - insertSuccess(t, db) - insertSuccess(t, db) - insertSuccess(t, db) - insertRunning(t, db) + db, _ := dbtestutil.NewDB(t) + u := dbgen.User(t, db, database.User{}) + org := dbgen.Organization(t, db, database.Organization{}) + insertCanceled(t, db, u, org) + insertFailed(t, db, u, org) + insertFailed(t, db, u, org) + insertSuccess(t, db, u, org) + insertSuccess(t, db, u, org) + insertSuccess(t, db, u, org) + insertRunning(t, db, u, org) return db }, Total: 7, @@ -287,21 +297,26 @@ func TestWorkspaceLatestBuildStatuses(t *testing.T) { ExpectedWorkspaces int ExpectedStatuses map[codersdk.ProvisionerJobStatus]int }{{ - Name: "None", - Database: dbmem.New, + Name: "None", + Database: func() database.Store { + db, _ := dbtestutil.NewDB(t) + return db + }, ExpectedWorkspaces: 0, }, { Name: "Multiple", Database: func() database.Store { - db := dbmem.New() - insertTemplates(t, db) - insertCanceled(t, db) - insertFailed(t, db) - insertFailed(t, db) - insertSuccess(t, db) - insertSuccess(t, db) - insertSuccess(t, db) - insertRunning(t, db) + db, _ := dbtestutil.NewDB(t) + u := dbgen.User(t, db, database.User{}) + org := dbgen.Organization(t, db, database.Organization{}) + insertTemplates(t, db, u, org) + insertCanceled(t, db, u, org) + insertFailed(t, db, u, org) + insertFailed(t, db, u, org) + insertSuccess(t, db, u, org) + insertSuccess(t, db, u, org) + insertSuccess(t, db, u, org) + insertRunning(t, db, u, org) return db }, ExpectedWorkspaces: 7, @@ -727,18 +742,24 @@ var ( templateVersionB = uuid.New() ) -func insertTemplates(t *testing.T, db database.Store) { +func insertTemplates(t *testing.T, db database.Store, u database.User, org database.Organization) { require.NoError(t, db.InsertTemplate(context.Background(), database.InsertTemplateParams{ ID: templateA, Name: "template-a", Provisioner: database.ProvisionerTypeTerraform, MaxPortSharingLevel: database.AppSharingLevelAuthenticated, + CreatedBy: u.ID, + OrganizationID: org.ID, })) + pj := dbgen.ProvisionerJob(t, db, nil, database.ProvisionerJob{}) require.NoError(t, db.InsertTemplateVersion(context.Background(), database.InsertTemplateVersionParams{ - ID: templateVersionA, - TemplateID: uuid.NullUUID{UUID: templateA}, - Name: "version-1a", + ID: templateVersionA, + TemplateID: uuid.NullUUID{UUID: templateA}, + Name: "version-1a", + JobID: pj.ID, + OrganizationID: org.ID, + CreatedBy: u.ID, })) require.NoError(t, db.InsertTemplate(context.Background(), database.InsertTemplateParams{ @@ -746,57 +767,77 @@ func insertTemplates(t *testing.T, db database.Store) { Name: "template-b", Provisioner: database.ProvisionerTypeTerraform, MaxPortSharingLevel: database.AppSharingLevelAuthenticated, + CreatedBy: u.ID, + OrganizationID: org.ID, })) require.NoError(t, db.InsertTemplateVersion(context.Background(), database.InsertTemplateVersionParams{ - ID: templateVersionB, - TemplateID: uuid.NullUUID{UUID: templateB}, - Name: "version-1b", + ID: templateVersionB, + TemplateID: uuid.NullUUID{UUID: templateB}, + Name: "version-1b", + JobID: pj.ID, + OrganizationID: org.ID, + CreatedBy: u.ID, })) } -func insertUser(t *testing.T, db database.Store) database.User { - username, err := cryptorand.String(8) - require.NoError(t, err) - - user, err := db.InsertUser(context.Background(), database.InsertUserParams{ - ID: uuid.New(), - Username: username, - LoginType: database.LoginTypeNone, - }) +func insertRunning(t *testing.T, db database.Store, u database.User, org database.Organization) database.ProvisionerJob { + var templateID, templateVersionID uuid.UUID + rnd, err := cryptorand.Intn(10) require.NoError(t, err) - return user -} + pairs := []struct { + tplID uuid.UUID + versionID uuid.UUID + }{ + {templateA, templateVersionA}, + {templateB, templateVersionB}, + } + for _, pair := range pairs { + _, err := db.GetTemplateByID(context.Background(), pair.tplID) + if errors.Is(err, sql.ErrNoRows) { + _ = dbgen.Template(t, db, database.Template{ + ID: pair.tplID, + OrganizationID: org.ID, + CreatedBy: u.ID, + }) + _ = dbgen.TemplateVersion(t, db, database.TemplateVersion{ + ID: pair.versionID, + OrganizationID: org.ID, + CreatedBy: u.ID, + }) + } else { + require.NoError(t, err) + } + } -func insertRunning(t *testing.T, db database.Store) database.ProvisionerJob { - var template, templateVersion uuid.UUID - rnd, err := cryptorand.Intn(10) - require.NoError(t, err) if rnd > 5 { - template = templateB - templateVersion = templateVersionB + templateID = templateB + templateVersionID = templateVersionB } else { - template = templateA - templateVersion = templateVersionA + templateID = templateA + templateVersionID = templateVersionA } workspace, err := db.InsertWorkspace(context.Background(), database.InsertWorkspaceParams{ ID: uuid.New(), - OwnerID: insertUser(t, db).ID, + OwnerID: u.ID, Name: uuid.NewString(), - TemplateID: template, + TemplateID: templateID, AutomaticUpdates: database.AutomaticUpdatesNever, + OrganizationID: org.ID, }) require.NoError(t, err) job, err := db.InsertProvisionerJob(context.Background(), database.InsertProvisionerJobParams{ - ID: uuid.New(), - CreatedAt: dbtime.Now(), - UpdatedAt: dbtime.Now(), - Provisioner: database.ProvisionerTypeEcho, - StorageMethod: database.ProvisionerStorageMethodFile, - Type: database.ProvisionerJobTypeWorkspaceBuild, + ID: uuid.New(), + CreatedAt: dbtime.Now(), + UpdatedAt: dbtime.Now(), + Provisioner: database.ProvisionerTypeEcho, + StorageMethod: database.ProvisionerStorageMethodFile, + Type: database.ProvisionerJobTypeWorkspaceBuild, + Input: json.RawMessage("{}"), + OrganizationID: org.ID, }) require.NoError(t, err) err = db.InsertWorkspaceBuild(context.Background(), database.InsertWorkspaceBuildParams{ @@ -806,7 +847,7 @@ func insertRunning(t *testing.T, db database.Store) database.ProvisionerJob { BuildNumber: 1, Transition: database.WorkspaceTransitionStart, Reason: database.BuildReasonInitiator, - TemplateVersionID: templateVersion, + TemplateVersionID: templateVersionID, }) require.NoError(t, err) // This marks the job as started. @@ -816,14 +857,15 @@ func insertRunning(t *testing.T, db database.Store) database.ProvisionerJob { Time: dbtime.Now(), Valid: true, }, - Types: []database.ProvisionerType{database.ProvisionerTypeEcho}, + Types: []database.ProvisionerType{database.ProvisionerTypeEcho}, + ProvisionerTags: must(json.Marshal(job.Tags)), }) require.NoError(t, err) return job } -func insertCanceled(t *testing.T, db database.Store) { - job := insertRunning(t, db) +func insertCanceled(t *testing.T, db database.Store, u database.User, org database.Organization) { + job := insertRunning(t, db, u, org) err := db.UpdateProvisionerJobWithCancelByID(context.Background(), database.UpdateProvisionerJobWithCancelByIDParams{ ID: job.ID, CanceledAt: sql.NullTime{ @@ -842,8 +884,8 @@ func insertCanceled(t *testing.T, db database.Store) { require.NoError(t, err) } -func insertFailed(t *testing.T, db database.Store) { - job := insertRunning(t, db) +func insertFailed(t *testing.T, db database.Store, u database.User, org database.Organization) { + job := insertRunning(t, db, u, org) err := db.UpdateProvisionerJobWithCompleteByID(context.Background(), database.UpdateProvisionerJobWithCompleteByIDParams{ ID: job.ID, CompletedAt: sql.NullTime{ @@ -858,8 +900,8 @@ func insertFailed(t *testing.T, db database.Store) { require.NoError(t, err) } -func insertSuccess(t *testing.T, db database.Store) { - job := insertRunning(t, db) +func insertSuccess(t *testing.T, db database.Store, u database.User, org database.Organization) { + job := insertRunning(t, db, u, org) err := db.UpdateProvisionerJobWithCompleteByID(context.Background(), database.UpdateProvisionerJobWithCompleteByIDParams{ ID: job.ID, CompletedAt: sql.NullTime{