diff --git a/components/registry-facade/pkg/handover/handover.go b/components/registry-facade/pkg/handover/handover.go index eccdd0ada64ae2..af2896078b130a 100644 --- a/components/registry-facade/pkg/handover/handover.go +++ b/components/registry-facade/pkg/handover/handover.go @@ -1,3 +1,7 @@ +// Copyright (c) 2021 Gitpod GmbH. All rights reserved. +// Licensed under the GNU Affero General Public License (AGPL). +// See License-AGPL.txt in the project root for license information. + package handover import ( diff --git a/components/registry-facade/pkg/handover/handover_test.go b/components/registry-facade/pkg/handover/handover_test.go index 58c2e75f3aa8b4..7544525df8022c 100644 --- a/components/registry-facade/pkg/handover/handover_test.go +++ b/components/registry-facade/pkg/handover/handover_test.go @@ -1,3 +1,7 @@ +// Copyright (c) 2021 Gitpod GmbH. All rights reserved. +// Licensed under the GNU Affero General Public License (AGPL). +// See License-AGPL.txt in the project root for license information. + package handover_test import ( diff --git a/components/supervisor-api/go/info.pb.gw.go b/components/supervisor-api/go/info.pb.gw.go index f36f9ed5438ba3..ea1385211580c9 100644 --- a/components/supervisor-api/go/info.pb.gw.go +++ b/components/supervisor-api/go/info.pb.gw.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Gitpod GmbH. All rights reserved. +// Copyright (c) 2021 Gitpod GmbH. All rights reserved. // Licensed under the GNU Affero General Public License (AGPL). // See License-AGPL.txt in the project root for license information. diff --git a/components/supervisor-api/go/status.pb.gw.go b/components/supervisor-api/go/status.pb.gw.go index 3447559ba7e908..3f84ec67fe4859 100644 --- a/components/supervisor-api/go/status.pb.gw.go +++ b/components/supervisor-api/go/status.pb.gw.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Gitpod GmbH. All rights reserved. +// Copyright (c) 2021 Gitpod GmbH. All rights reserved. // Licensed under the GNU Affero General Public License (AGPL). // See License-AGPL.txt in the project root for license information. diff --git a/components/supervisor-api/go/terminal.pb.go b/components/supervisor-api/go/terminal.pb.go index f262261d4f80ab..21ef45dd742634 100644 --- a/components/supervisor-api/go/terminal.pb.go +++ b/components/supervisor-api/go/terminal.pb.go @@ -39,7 +39,9 @@ type OpenTerminalRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Env map[string]string `protobuf:"bytes,2,rep,name=env,proto3" json:"env,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Workdir string `protobuf:"bytes,1,opt,name=workdir,proto3" json:"workdir,omitempty"` + Env map[string]string `protobuf:"bytes,2,rep,name=env,proto3" json:"env,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Annotations map[string]string `protobuf:"bytes,3,rep,name=annotations,proto3" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *OpenTerminalRequest) Reset() { @@ -74,6 +76,13 @@ func (*OpenTerminalRequest) Descriptor() ([]byte, []int) { return file_terminal_proto_rawDescGZIP(), []int{0} } +func (x *OpenTerminalRequest) GetWorkdir() string { + if x != nil { + return x.Workdir + } + return "" +} + func (x *OpenTerminalRequest) GetEnv() map[string]string { if x != nil { return x.Env @@ -81,6 +90,13 @@ func (x *OpenTerminalRequest) GetEnv() map[string]string { return nil } +func (x *OpenTerminalRequest) GetAnnotations() map[string]string { + if x != nil { + return x.Annotations + } + return nil +} + type OpenTerminalResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -705,15 +721,19 @@ type ListTerminalsResponse_Terminal struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Alias string `protobuf:"bytes,1,opt,name=alias,proto3" json:"alias,omitempty"` - Command []string `protobuf:"bytes,2,rep,name=command,proto3" json:"command,omitempty"` - Title string `protobuf:"bytes,3,opt,name=title,proto3" json:"title,omitempty"` + Alias string `protobuf:"bytes,1,opt,name=alias,proto3" json:"alias,omitempty"` + Command []string `protobuf:"bytes,2,rep,name=command,proto3" json:"command,omitempty"` + Title string `protobuf:"bytes,3,opt,name=title,proto3" json:"title,omitempty"` + Pid int64 `protobuf:"varint,4,opt,name=pid,proto3" json:"pid,omitempty"` + InitialWorkdir string `protobuf:"bytes,5,opt,name=initial_workdir,json=initialWorkdir,proto3" json:"initial_workdir,omitempty"` + CurrentWorkdir string `protobuf:"bytes,6,opt,name=current_workdir,json=currentWorkdir,proto3" json:"current_workdir,omitempty"` + Annotations map[string]string `protobuf:"bytes,7,rep,name=annotations,proto3" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *ListTerminalsResponse_Terminal) Reset() { *x = ListTerminalsResponse_Terminal{} if protoimpl.UnsafeEnabled { - mi := &file_terminal_proto_msgTypes[13] + mi := &file_terminal_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -726,7 +746,7 @@ func (x *ListTerminalsResponse_Terminal) String() string { func (*ListTerminalsResponse_Terminal) ProtoMessage() {} func (x *ListTerminalsResponse_Terminal) ProtoReflect() protoreflect.Message { - mi := &file_terminal_proto_msgTypes[13] + mi := &file_terminal_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -763,116 +783,171 @@ func (x *ListTerminalsResponse_Terminal) GetTitle() string { return "" } +func (x *ListTerminalsResponse_Terminal) GetPid() int64 { + if x != nil { + return x.Pid + } + return 0 +} + +func (x *ListTerminalsResponse_Terminal) GetInitialWorkdir() string { + if x != nil { + return x.InitialWorkdir + } + return "" +} + +func (x *ListTerminalsResponse_Terminal) GetCurrentWorkdir() string { + if x != nil { + return x.CurrentWorkdir + } + return "" +} + +func (x *ListTerminalsResponse_Terminal) GetAnnotations() map[string]string { + if x != nil { + return x.Annotations + } + return nil +} + var File_terminal_proto protoreflect.FileDescriptor var file_terminal_proto_rawDesc = []byte{ 0x0a, 0x0e, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x89, 0x01, 0x0a, 0x13, 0x4f, + 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb7, 0x02, 0x0a, 0x13, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x28, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x4f, 0x70, 0x65, - 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x2e, 0x45, 0x6e, 0x76, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x03, 0x65, 0x6e, 0x76, 0x1a, 0x36, - 0x0a, 0x08, 0x45, 0x6e, 0x76, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x51, 0x0a, 0x14, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, - 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, - 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, - 0x6c, 0x69, 0x61, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x72, 0x5f, - 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x74, 0x61, - 0x72, 0x74, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x2c, 0x0a, 0x14, 0x43, 0x6c, 0x6f, - 0x73, 0x65, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x22, 0x17, 0x0a, 0x15, 0x43, 0x6c, 0x6f, 0x73, 0x65, - 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x16, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xb3, 0x01, 0x0a, 0x15, 0x4c, 0x69, 0x73, - 0x74, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x48, 0x0a, 0x09, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, - 0x6f, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, - 0x6c, 0x52, 0x09, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x73, 0x1a, 0x50, 0x0a, 0x08, - 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x61, - 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x18, - 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x22, 0x2d, - 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x22, 0x56, 0x0a, - 0x16, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x06, 0x73, 0x74, 0x64, 0x6f, 0x75, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x64, 0x6f, 0x75, - 0x74, 0x12, 0x18, 0x0a, 0x06, 0x73, 0x74, 0x64, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x64, 0x65, 0x72, 0x72, 0x42, 0x08, 0x0a, 0x06, 0x6f, - 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x42, 0x0a, 0x14, 0x57, 0x72, 0x69, 0x74, 0x65, 0x54, 0x65, - 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, - 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x6c, - 0x69, 0x61, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x64, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x64, 0x69, 0x6e, 0x22, 0x3c, 0x0a, 0x15, 0x57, 0x72, 0x69, - 0x74, 0x65, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x77, 0x72, 0x69, 0x74, - 0x74, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x62, 0x79, 0x74, 0x65, 0x73, - 0x57, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x22, 0xc8, 0x01, 0x0a, 0x16, 0x53, 0x65, 0x74, 0x54, - 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x53, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, - 0x12, 0x16, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x48, - 0x00, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x77, 0x73, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x12, 0x12, 0x0a, 0x04, - 0x63, 0x6f, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x63, 0x6f, 0x6c, 0x73, - 0x12, 0x18, 0x0a, 0x07, 0x77, 0x69, 0x64, 0x74, 0x68, 0x50, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x07, 0x77, 0x69, 0x64, 0x74, 0x68, 0x50, 0x78, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x65, - 0x69, 0x67, 0x68, 0x74, 0x50, 0x78, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x68, 0x65, - 0x69, 0x67, 0x68, 0x74, 0x50, 0x78, 0x42, 0x0a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, - 0x74, 0x79, 0x22, 0x19, 0x0a, 0x17, 0x53, 0x65, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, - 0x6c, 0x53, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xf8, 0x04, - 0x0a, 0x0f, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x12, 0x4b, 0x0a, 0x04, 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x1f, 0x2e, 0x73, 0x75, 0x70, 0x65, + 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x77, 0x6f, 0x72, 0x6b, 0x64, 0x69, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x77, 0x6f, 0x72, 0x6b, 0x64, 0x69, 0x72, 0x12, 0x3a, 0x0a, 0x03, + 0x65, 0x6e, 0x76, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x69, - 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x73, 0x75, 0x70, - 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x72, 0x6d, - 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x70, - 0x0a, 0x05, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x12, 0x20, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, - 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, - 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x73, 0x75, 0x70, 0x65, + 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x45, 0x6e, 0x76, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x03, 0x65, 0x6e, 0x76, 0x12, 0x52, 0x0a, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, + 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x54, + 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41, + 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x36, 0x0a, 0x08, + 0x45, 0x6e, 0x76, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3e, 0x0a, 0x10, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x22, 0x51, 0x0a, 0x14, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x72, 0x6d, + 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, + 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x6c, 0x69, + 0x61, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x72, 0x5f, 0x74, 0x6f, + 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x2c, 0x0a, 0x14, 0x43, 0x6c, 0x6f, 0x73, 0x65, + 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x61, 0x6c, 0x69, 0x61, 0x73, 0x22, 0x17, 0x0a, 0x15, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x54, 0x65, + 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, + 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xb7, 0x03, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x54, + 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x48, 0x0a, 0x09, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x52, + 0x09, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x73, 0x1a, 0xd3, 0x02, 0x0a, 0x08, 0x54, + 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x18, 0x0a, + 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, + 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x10, 0x0a, + 0x03, 0x70, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x70, 0x69, 0x64, 0x12, + 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x64, + 0x69, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, + 0x6c, 0x57, 0x6f, 0x72, 0x6b, 0x64, 0x69, 0x72, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x75, 0x72, 0x72, + 0x65, 0x6e, 0x74, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x64, 0x69, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x64, 0x69, + 0x72, 0x12, 0x5d, 0x0a, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, + 0x73, 0x6f, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, + 0x61, 0x6c, 0x2e, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x1a, 0x3e, 0x0a, 0x10, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x22, 0x2d, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, + 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, + 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x22, + 0x56, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, + 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x06, 0x73, 0x74, 0x64, + 0x6f, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x64, + 0x6f, 0x75, 0x74, 0x12, 0x18, 0x0a, 0x06, 0x73, 0x74, 0x64, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x64, 0x65, 0x72, 0x72, 0x42, 0x08, 0x0a, + 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x42, 0x0a, 0x14, 0x57, 0x72, 0x69, 0x74, 0x65, + 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x61, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x64, 0x69, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x64, 0x69, 0x6e, 0x22, 0x3c, 0x0a, 0x15, 0x57, + 0x72, 0x69, 0x74, 0x65, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x77, 0x72, + 0x69, 0x74, 0x74, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x62, 0x79, 0x74, + 0x65, 0x73, 0x57, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x22, 0xc8, 0x01, 0x0a, 0x16, 0x53, 0x65, + 0x74, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x53, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, + 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x12, 0x16, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x08, 0x48, 0x00, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, + 0x77, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x12, 0x12, + 0x0a, 0x04, 0x63, 0x6f, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x63, 0x6f, + 0x6c, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x77, 0x69, 0x64, 0x74, 0x68, 0x50, 0x78, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x07, 0x77, 0x69, 0x64, 0x74, 0x68, 0x50, 0x78, 0x12, 0x1a, 0x0a, 0x08, + 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x50, 0x78, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, + 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x50, 0x78, 0x42, 0x0a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x22, 0x19, 0x0a, 0x17, 0x53, 0x65, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x69, + 0x6e, 0x61, 0x6c, 0x53, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, + 0xf8, 0x04, 0x0a, 0x0f, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x12, 0x4b, 0x0a, 0x04, 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x1f, 0x2e, 0x73, 0x75, + 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x72, + 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x73, + 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, + 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x70, 0x0a, 0x05, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x12, 0x20, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x54, 0x65, 0x72, 0x6d, - 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x1c, 0x12, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, - 0x61, 0x6c, 0x2f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x2f, 0x7b, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x7d, - 0x12, 0x66, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x20, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, - 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, - 0x61, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x73, 0x75, 0x70, - 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x65, 0x72, 0x6d, - 0x69, 0x6e, 0x61, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x65, 0x72, 0x6d, 0x69, - 0x6e, 0x61, 0x6c, 0x2f, 0x6c, 0x69, 0x73, 0x74, 0x12, 0x76, 0x0a, 0x06, 0x4c, 0x69, 0x73, 0x74, - 0x65, 0x6e, 0x12, 0x21, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, - 0x6f, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, - 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x2f, - 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x2f, 0x7b, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x7d, 0x30, 0x01, - 0x12, 0x70, 0x0a, 0x05, 0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x20, 0x2e, 0x73, 0x75, 0x70, 0x65, - 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x73, 0x75, - 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x54, 0x65, + 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x22, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x65, 0x72, 0x6d, - 0x69, 0x6e, 0x61, 0x6c, 0x2f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x2f, 0x7b, 0x61, 0x6c, 0x69, 0x61, - 0x73, 0x7d, 0x12, 0x54, 0x0a, 0x07, 0x53, 0x65, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x2e, - 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x65, - 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x53, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x23, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x53, - 0x65, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x53, 0x69, 0x7a, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x07, 0x5a, 0x05, 0x2e, 0x3b, 0x61, 0x70, - 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x12, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x65, 0x72, 0x6d, + 0x69, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x2f, 0x7b, 0x61, 0x6c, 0x69, 0x61, + 0x73, 0x7d, 0x12, 0x66, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x20, 0x2e, 0x73, 0x75, 0x70, + 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x65, 0x72, 0x6d, + 0x69, 0x6e, 0x61, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x73, + 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x65, + 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x65, 0x72, + 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x2f, 0x6c, 0x69, 0x73, 0x74, 0x12, 0x76, 0x0a, 0x06, 0x4c, 0x69, + 0x73, 0x74, 0x65, 0x6e, 0x12, 0x21, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, + 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, + 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x69, + 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, + 0x6c, 0x2f, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x2f, 0x7b, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x7d, + 0x30, 0x01, 0x12, 0x70, 0x0a, 0x05, 0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x20, 0x2e, 0x73, 0x75, + 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x54, 0x65, + 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, + 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, + 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x22, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x65, + 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x2f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x2f, 0x7b, 0x61, 0x6c, + 0x69, 0x61, 0x73, 0x7d, 0x12, 0x54, 0x0a, 0x07, 0x53, 0x65, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x12, + 0x22, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x53, 0x65, 0x74, + 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x53, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, + 0x2e, 0x53, 0x65, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x53, 0x69, 0x7a, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x07, 0x5a, 0x05, 0x2e, 0x3b, + 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -887,7 +962,7 @@ func file_terminal_proto_rawDescGZIP() []byte { return file_terminal_proto_rawDescData } -var file_terminal_proto_msgTypes = make([]protoimpl.MessageInfo, 14) +var file_terminal_proto_msgTypes = make([]protoimpl.MessageInfo, 16) var file_terminal_proto_goTypes = []interface{}{ (*OpenTerminalRequest)(nil), // 0: supervisor.OpenTerminalRequest (*OpenTerminalResponse)(nil), // 1: supervisor.OpenTerminalResponse @@ -902,28 +977,32 @@ var file_terminal_proto_goTypes = []interface{}{ (*SetTerminalSizeRequest)(nil), // 10: supervisor.SetTerminalSizeRequest (*SetTerminalSizeResponse)(nil), // 11: supervisor.SetTerminalSizeResponse nil, // 12: supervisor.OpenTerminalRequest.EnvEntry - (*ListTerminalsResponse_Terminal)(nil), // 13: supervisor.ListTerminalsResponse.Terminal + nil, // 13: supervisor.OpenTerminalRequest.AnnotationsEntry + (*ListTerminalsResponse_Terminal)(nil), // 14: supervisor.ListTerminalsResponse.Terminal + nil, // 15: supervisor.ListTerminalsResponse.Terminal.AnnotationsEntry } var file_terminal_proto_depIdxs = []int32{ 12, // 0: supervisor.OpenTerminalRequest.env:type_name -> supervisor.OpenTerminalRequest.EnvEntry - 13, // 1: supervisor.ListTerminalsResponse.terminals:type_name -> supervisor.ListTerminalsResponse.Terminal - 0, // 2: supervisor.TerminalService.Open:input_type -> supervisor.OpenTerminalRequest - 2, // 3: supervisor.TerminalService.Close:input_type -> supervisor.CloseTerminalRequest - 4, // 4: supervisor.TerminalService.List:input_type -> supervisor.ListTerminalsRequest - 6, // 5: supervisor.TerminalService.Listen:input_type -> supervisor.ListenTerminalRequest - 8, // 6: supervisor.TerminalService.Write:input_type -> supervisor.WriteTerminalRequest - 10, // 7: supervisor.TerminalService.SetSize:input_type -> supervisor.SetTerminalSizeRequest - 1, // 8: supervisor.TerminalService.Open:output_type -> supervisor.OpenTerminalResponse - 3, // 9: supervisor.TerminalService.Close:output_type -> supervisor.CloseTerminalResponse - 5, // 10: supervisor.TerminalService.List:output_type -> supervisor.ListTerminalsResponse - 7, // 11: supervisor.TerminalService.Listen:output_type -> supervisor.ListenTerminalResponse - 9, // 12: supervisor.TerminalService.Write:output_type -> supervisor.WriteTerminalResponse - 11, // 13: supervisor.TerminalService.SetSize:output_type -> supervisor.SetTerminalSizeResponse - 8, // [8:14] is the sub-list for method output_type - 2, // [2:8] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name + 13, // 1: supervisor.OpenTerminalRequest.annotations:type_name -> supervisor.OpenTerminalRequest.AnnotationsEntry + 14, // 2: supervisor.ListTerminalsResponse.terminals:type_name -> supervisor.ListTerminalsResponse.Terminal + 15, // 3: supervisor.ListTerminalsResponse.Terminal.annotations:type_name -> supervisor.ListTerminalsResponse.Terminal.AnnotationsEntry + 0, // 4: supervisor.TerminalService.Open:input_type -> supervisor.OpenTerminalRequest + 2, // 5: supervisor.TerminalService.Close:input_type -> supervisor.CloseTerminalRequest + 4, // 6: supervisor.TerminalService.List:input_type -> supervisor.ListTerminalsRequest + 6, // 7: supervisor.TerminalService.Listen:input_type -> supervisor.ListenTerminalRequest + 8, // 8: supervisor.TerminalService.Write:input_type -> supervisor.WriteTerminalRequest + 10, // 9: supervisor.TerminalService.SetSize:input_type -> supervisor.SetTerminalSizeRequest + 1, // 10: supervisor.TerminalService.Open:output_type -> supervisor.OpenTerminalResponse + 3, // 11: supervisor.TerminalService.Close:output_type -> supervisor.CloseTerminalResponse + 5, // 12: supervisor.TerminalService.List:output_type -> supervisor.ListTerminalsResponse + 7, // 13: supervisor.TerminalService.Listen:output_type -> supervisor.ListenTerminalResponse + 9, // 14: supervisor.TerminalService.Write:output_type -> supervisor.WriteTerminalResponse + 11, // 15: supervisor.TerminalService.SetSize:output_type -> supervisor.SetTerminalSizeResponse + 10, // [10:16] is the sub-list for method output_type + 4, // [4:10] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name } func init() { file_terminal_proto_init() } @@ -1076,7 +1155,7 @@ func file_terminal_proto_init() { return nil } } - file_terminal_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + file_terminal_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListTerminalsResponse_Terminal); i { case 0: return &v.state @@ -1103,7 +1182,7 @@ func file_terminal_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_terminal_proto_rawDesc, NumEnums: 0, - NumMessages: 14, + NumMessages: 16, NumExtensions: 0, NumServices: 1, }, diff --git a/components/supervisor-api/go/terminal.pb.gw.go b/components/supervisor-api/go/terminal.pb.gw.go index 6d199ca059a6b4..fbe4df7a154bc7 100644 --- a/components/supervisor-api/go/terminal.pb.gw.go +++ b/components/supervisor-api/go/terminal.pb.gw.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Gitpod GmbH. All rights reserved. +// Copyright (c) 2021 Gitpod GmbH. All rights reserved. // Licensed under the GNU Affero General Public License (AGPL). // See License-AGPL.txt in the project root for license information. diff --git a/components/supervisor-api/go/token.pb.go b/components/supervisor-api/go/token.pb.go index 6504552944a26c..b3702ef1c5f164 100644 --- a/components/supervisor-api/go/token.pb.go +++ b/components/supervisor-api/go/token.pb.go @@ -167,7 +167,8 @@ type GetTokenResponse struct { unknownFields protoimpl.UnknownFields Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` - User string `protobuf:"bytes,2,opt,name=user,proto3" json:"user,omitempty"` + //* The username of the account associated with the token. + User string `protobuf:"bytes,2,opt,name=user,proto3" json:"user,omitempty"` } func (x *GetTokenResponse) Reset() { diff --git a/components/supervisor-api/go/token.pb.gw.go b/components/supervisor-api/go/token.pb.gw.go index b69dc1d8b4a638..1830985d303a3d 100644 --- a/components/supervisor-api/go/token.pb.gw.go +++ b/components/supervisor-api/go/token.pb.gw.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Gitpod GmbH. All rights reserved. +// Copyright (c) 2021 Gitpod GmbH. All rights reserved. // Licensed under the GNU Affero General Public License (AGPL). // See License-AGPL.txt in the project root for license information. diff --git a/components/supervisor-api/terminal.proto b/components/supervisor-api/terminal.proto index 6b68a24ab5c909..8067a534c8db85 100644 --- a/components/supervisor-api/terminal.proto +++ b/components/supervisor-api/terminal.proto @@ -48,7 +48,9 @@ service TerminalService { } message OpenTerminalRequest { + string workdir = 1; map env = 2; + map annotations = 3; } message OpenTerminalResponse { string alias = 1; @@ -69,6 +71,10 @@ message ListTerminalsResponse { string alias = 1; repeated string command = 2; string title = 3; + int64 pid = 4; + string initial_workdir = 5; + string current_workdir = 6; + map annotations = 7; } repeated Terminal terminals = 1; diff --git a/components/supervisor/cmd/terminal-list.go b/components/supervisor/cmd/terminal-list.go index 1a156ffdea0451..9bea1add261edd 100644 --- a/components/supervisor/cmd/terminal-list.go +++ b/components/supervisor/cmd/terminal-list.go @@ -8,6 +8,7 @@ import ( "context" "fmt" "os" + "sort" "strings" "text/tabwriter" "time" @@ -34,9 +35,14 @@ var terminalListCmd = &cobra.Command{ tw := tabwriter.NewWriter(os.Stdout, 2, 4, 1, ' ', 0) defer tw.Flush() - fmt.Fprintf(tw, "ALIAS\tCOMMAND\n") + fmt.Fprintf(tw, "ALIAS\tPID\tCOMMAND\tANNOTATIONS\n") for _, term := range resp.Terminals { - fmt.Fprintf(tw, "%s\t%s\n", term.Alias, strings.Join(term.Command, " ")) + annotations := make([]string, 0, len(term.Annotations)) + for k, v := range term.Annotations { + annotations = append(annotations, fmt.Sprintf("%s=%s", k, v)) + } + sort.Slice(annotations, func(i, j int) bool { return annotations[i] < annotations[j] }) + fmt.Fprintf(tw, "%s\t%d\t%s\t%s\n", term.Alias, term.Pid, strings.Join(term.Command, " "), strings.Join(annotations, ",")) } }, } diff --git a/components/supervisor/pkg/ports/ports.go b/components/supervisor/pkg/ports/ports.go index 7d975fc1e141fd..f4034c30c655fb 100644 --- a/components/supervisor/pkg/ports/ports.go +++ b/components/supervisor/pkg/ports/ports.go @@ -103,8 +103,11 @@ func (s *Subscription) Updates() <-chan []*api.PortsStatus { } // Run starts the port manager which keeps running until one of its observers stops. -func (pm *Manager) Run() { - ctx, cancel := context.WithCancel(context.Background()) +func (pm *Manager) Run(ctx context.Context, wg *sync.WaitGroup) { + defer wg.Done() + defer log.Debug("portManager shutdown") + + ctx, cancel := context.WithCancel(ctx) defer func() { // We copy the subscriptions to a list prior to closing them, to prevent a data race // between the map iteration and entry removal when closing the subscription. diff --git a/components/supervisor/pkg/ports/ports_test.go b/components/supervisor/pkg/ports/ports_test.go index c097e23560eecd..7961dfea1bbbe7 100644 --- a/components/supervisor/pkg/ports/ports_test.go +++ b/components/supervisor/pkg/ports/ports_test.go @@ -471,12 +471,11 @@ func TestPortsUpdateState(t *testing.T) { return ioutil.NopCloser(nil), nil } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() var wg sync.WaitGroup wg.Add(3) - go func() { - defer wg.Done() - pm.Run() - }() + go pm.Run(ctx, &wg) sub, err := pm.Subscribe() if err != nil { t.Fatal(err) @@ -607,12 +606,11 @@ func TestPortsConcurrentSubscribe(t *testing.T) { return ioutil.NopCloser(nil), nil } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() var wg sync.WaitGroup wg.Add(2) - go func() { - defer wg.Done() - pm.Run() - }() + go pm.Run(ctx, &wg) go func() { defer wg.Done() defer close(config.Error) diff --git a/components/supervisor/pkg/supervisor/supervisor.go b/components/supervisor/pkg/supervisor/supervisor.go index bfee1f0330a8e4..b15d482c22a427 100644 --- a/components/supervisor/pkg/supervisor/supervisor.go +++ b/components/supervisor/pkg/supervisor/supervisor.go @@ -5,6 +5,7 @@ package supervisor import ( + "bufio" "context" "encoding/json" "fmt" @@ -14,6 +15,7 @@ import ( "os" "os/exec" "os/signal" + "path/filepath" "runtime" "strconv" "strings" @@ -169,20 +171,30 @@ func Run(options ...RunOption) { } apiServices = append(apiServices, additionalServices...) + // The reaper can be turned into a terminating reaper by writing true to this channel. + // When in terminating mode, the reaper will send SIGTERM to each child that gets reparented + // to us and is still running. We use this mechanism to send SIGTERM to a shell child processes + // that get reparented once their parent shell terminates during shutdown. + terminatingReaper := make(chan bool) + // We keep the reaper until the bitter end because: + // - it doesn't need graceful shutdown + // - we want to do as much work as possible (SIGTERM'ing reparented processes during shutdown). + go reaper(terminatingReaper) + + var ideWG sync.WaitGroup + ideWG.Add(1) + go startAndWatchIDE(ctx, cfg, &ideWG, ideReady) + var wg sync.WaitGroup - wg.Add(6) - go reaper(ctx, &wg) - go startAndWatchIDE(ctx, cfg, &wg, ideReady) + wg.Add(4) go startContentInit(ctx, cfg, &wg, cstate) go startAPIEndpoint(ctx, cfg, &wg, apiServices, apiEndpointOpts...) go taskManager.Run(ctx, &wg) - go func() { - defer wg.Done() - if cfg.isHeadless() { - return - } - portMgmt.Run() - }() + + if !cfg.isHeadless() { + wg.Add(1) + go portMgmt.Run(ctx, &wg) + } if cfg.PreventMetadataAccess { go func() { @@ -203,15 +215,21 @@ func Run(options ...RunOption) { } log.Info("received SIGTERM - tearing down") + terminatingReaper <- true + cancel() err = termMux.Close() if err != nil { log.WithError(err).Error("terminal closure failed") } + + // terminate all child processes once the IDE is gone + ideWG.Wait() + terminateChildProcesses() + if !opts.InNamespace { callDaemonTeardown() } - cancel() wg.Wait() } @@ -305,16 +323,17 @@ func hasMetadataAccess() bool { return false } -func reaper(ctx context.Context, wg *sync.WaitGroup) { - defer wg.Done() +func reaper(terminatingReaper <-chan bool) { + defer log.Debug("reaper shutdown") + var terminating bool sigs := make(chan os.Signal, 128) signal.Notify(sigs, syscall.SIGCHLD) for { select { - case <-ctx.Done(): - return case <-sigs: + case terminating = <-terminatingReaper: + continue } pid, err := unix.Wait4(-1, nil, 0, nil) @@ -325,12 +344,33 @@ func reaper(ctx context.Context, wg *sync.WaitGroup) { } if err != nil { log.WithField("pid", pid).WithError(err).Debug("cannot call waitpid() for re-parented child") + continue + } + + if !terminating { + continue + } + proc, err := os.FindProcess(pid) + if err != nil { + log.WithField("pid", pid).WithError(err).Debug("cannot find re-parented process") + continue } + err = proc.Signal(syscall.SIGTERM) + if err != nil { + if !strings.Contains(err.Error(), "os: process already finished") { + log.WithField("pid", pid).WithError(err).Debug("cannot send SIGTERM to re-parented process") + } + + continue + } + log.WithField("pid", pid).Debug("SIGTERM'ed reparented child process") } } func startAndWatchIDE(ctx context.Context, cfg *Config, wg *sync.WaitGroup, ideReady *ideReadyState) { defer wg.Done() + defer log.Debug("startAndWatchIDE shutdown") + if cfg.isHeadless() { ideReady.Set(true) return @@ -383,7 +423,7 @@ supervisorLoop: }() err = cmd.Wait() - if err != nil && !strings.Contains(err.Error(), "signal: interrupt") { + if err != nil && !(strings.Contains(err.Error(), "signal: interrupt") || strings.Contains(err.Error(), "wait: no child processes")) { log.WithError(err).Warn("IDE was stopped") } @@ -411,7 +451,7 @@ supervisorLoop: case <-ideStopped: return case <-time.After(timeBudgetIDEShutdown): - log.Error("IDE did not stop in time - sending SIGKILL") + log.WithField("timeBudgetIDEShutdown", timeBudgetIDEShutdown.String()).Error("IDE did not stop in time - sending SIGKILL") cmd.Process.Signal(syscall.SIGKILL) } } @@ -530,6 +570,7 @@ func isBlacklistedEnvvar(name string) bool { func startAPIEndpoint(ctx context.Context, cfg *Config, wg *sync.WaitGroup, services []RegisterableService, opts ...grpc.ServerOption) { defer wg.Done() + defer log.Debug("startAPIEndpoint shutdown") l, err := net.Listen("tcp", fmt.Sprintf(":%d", cfg.APIEndpointPort)) if err != nil { @@ -642,6 +683,52 @@ func startContentInit(ctx context.Context, cfg *Config, wg *sync.WaitGroup, cst cst.MarkContentReady(src) } +func terminateChildProcesses() { + ppid := strconv.Itoa(os.Getpid()) + dirs, err := ioutil.ReadDir("/proc") + if err != nil { + log.WithError(err).Warn("cannot terminate child processes") + return + } + for _, d := range dirs { + pid, err := strconv.Atoi(d.Name()) + if err != nil { + // not a PID + continue + } + proc, err := os.FindProcess(pid) + if err != nil { + continue + } + + var isChild bool + f, err := os.Open(filepath.Join("/proc", d.Name(), "status")) + if err != nil { + continue + } + scan := bufio.NewScanner(f) + for scan.Scan() { + l := strings.TrimSpace(scan.Text()) + if !strings.HasPrefix(l, "PPid:") { + continue + } + + isChild = strings.HasSuffix(l, ppid) + break + } + if !isChild { + continue + } + + err = proc.Signal(unix.SIGTERM) + if err != nil { + log.WithError(err).WithField("pid", pid).Warn("cannot terminate child processe") + continue + } + log.WithField("pid", pid).Debug("SIGTERM'ed child process") + } +} + func callDaemonTeardown() { log.Info("asking ws-daemon to tear down this workspace") ctx, cancel := context.WithTimeout(context.Background(), timeBudgetDaemonTeardown) diff --git a/components/supervisor/pkg/supervisor/tasks.go b/components/supervisor/pkg/supervisor/tasks.go index 283f527920f78b..7c4702b0ca15ab 100644 --- a/components/supervisor/pkg/supervisor/tasks.go +++ b/components/supervisor/pkg/supervisor/tasks.go @@ -200,6 +200,8 @@ func (tm *tasksManager) init(ctx context.Context) { func (tm *tasksManager) Run(ctx context.Context, wg *sync.WaitGroup) { defer wg.Done() + defer log.Debug("tasksManager shutdown") + tm.init(ctx) for _, t := range tm.tasks { diff --git a/components/supervisor/pkg/terminal/service.go b/components/supervisor/pkg/terminal/service.go index 98e1161c3fb7d2..3f248dfb450adb 100644 --- a/components/supervisor/pkg/terminal/service.go +++ b/components/supervisor/pkg/terminal/service.go @@ -6,9 +6,11 @@ package terminal import ( "context" + "fmt" "io" "os" "os/exec" + "path/filepath" "time" "github.com/creack/pty" @@ -65,17 +67,26 @@ func (srv *MuxTerminalService) RegisterREST(mux *runtime.ServeMux, grpcEndpoint func (srv *MuxTerminalService) Open(ctx context.Context, req *api.OpenTerminalRequest) (*api.OpenTerminalResponse, error) { return srv.OpenWithOptions(ctx, req, TermOptions{ ReadTimeout: 5 * time.Second, + Annotations: req.Annotations, }) } -// OpenWithOptions opens a new terminal running the shell with given options +// OpenWithOptions opens a new terminal running the shell with given options. +// req.Annotations override options.Annotations. func (srv *MuxTerminalService) OpenWithOptions(ctx context.Context, req *api.OpenTerminalRequest, options TermOptions) (*api.OpenTerminalResponse, error) { cmd := exec.Command(srv.DefaultShell) - cmd.Dir = srv.DefaultWorkdir + if req.Workdir == "" { + cmd.Dir = srv.DefaultWorkdir + } else { + cmd.Dir = req.Workdir + } cmd.Env = append(srv.Env, "TERM=xterm-color") for key, value := range req.Env { cmd.Env = append(cmd.Env, key+"="+value) } + for k, v := range req.Annotations { + options.Annotations[k] = v + } alias, err := srv.Mux.Start(cmd, options) if err != nil { return nil, status.Error(codes.Internal, err.Error()) @@ -110,9 +121,27 @@ func (srv *MuxTerminalService) List(ctx context.Context, req *api.ListTerminalsR res := make([]*api.ListTerminalsResponse_Terminal, 0, len(srv.Mux.terms)) for alias, term := range srv.Mux.terms { + var ( + pid int64 + cwd string + err error + ) + if proc := term.Command.Process; proc != nil { + pid = int64(proc.Pid) + cwd, err = filepath.EvalSymlinks(fmt.Sprintf("/proc/%d/cwd", pid)) + if err != nil { + log.WithError(err).WithField("pid", pid).Warn("unable to resolve terminal's current working dir") + cwd = term.Command.Dir + } + } + res = append(res, &api.ListTerminalsResponse_Terminal{ - Alias: alias, - Command: term.Command.Args, + Alias: alias, + Command: term.Command.Args, + Pid: pid, + InitialWorkdir: term.Command.Dir, + CurrentWorkdir: cwd, + Annotations: term.Annotations, }) } diff --git a/components/supervisor/pkg/terminal/terminal.go b/components/supervisor/pkg/terminal/terminal.go index 0714d894e9a597..b039e91b4f5a6e 100644 --- a/components/supervisor/pkg/terminal/terminal.go +++ b/components/supervisor/pkg/terminal/terminal.go @@ -85,8 +85,8 @@ func (m *Mux) Close() error { var err error for k := range m.terms { cerr := m.doClose(k, closeTerminaldefaultGracePeriod) - if cerr == nil { - log.WithError(err).WithField("alias", k).Warn("cannot properly close terminal") + if cerr != nil { + log.WithError(cerr).WithField("alias", k).Warn("cannot properly close terminal") if err != nil { err = cerr } @@ -142,7 +142,7 @@ func gracefullyShutdownProcess(p *os.Process, gracePeriod time.Duration) error { return p.Kill() } - err := p.Signal(unix.SIGINT) + err := p.Signal(unix.SIGTERM) if err != nil { return err } @@ -192,6 +192,7 @@ func newTerm(pty *os.File, cmd *exec.Cmd, options TermOptions) (*Term, error) { listener: make(map[*multiWriterListener]struct{}), recorder: recorder, }, + Annotations: options.Annotations, StarterToken: token.String(), @@ -205,6 +206,9 @@ func newTerm(pty *os.File, cmd *exec.Cmd, options TermOptions) (*Term, error) { type TermOptions struct { // timeout after which a listener is dropped. Use 0 for no timeout. ReadTimeout time.Duration + + // Annotations are user-defined metadata that's attached to a terminal + Annotations map[string]string } // Term is a pseudo-terminal @@ -213,6 +217,7 @@ type Term struct { Command *exec.Cmd Title string StarterToken string + Annotations map[string]string Stdout *multiWriter diff --git a/components/supervisor/pkg/terminal/terminal_test.go b/components/supervisor/pkg/terminal/terminal_test.go index bf736755e7447c..166202378f15ae 100644 --- a/components/supervisor/pkg/terminal/terminal_test.go +++ b/components/supervisor/pkg/terminal/terminal_test.go @@ -18,6 +18,86 @@ import ( "golang.org/x/sync/errgroup" ) +func TestAnnotations(t *testing.T) { + tests := []struct { + Desc string + Req *api.OpenTerminalRequest + Opts *TermOptions + Expectation map[string]string + }{ + { + Desc: "no annotations", + Req: &api.OpenTerminalRequest{ + Annotations: map[string]string{}, + }, + Expectation: map[string]string{}, + }, + { + Desc: "request annotation", + Req: &api.OpenTerminalRequest{ + Annotations: map[string]string{ + "hello": "world", + }, + }, + Expectation: map[string]string{ + "hello": "world", + }, + }, + { + Desc: "option annotation", + Req: &api.OpenTerminalRequest{ + Annotations: map[string]string{ + "hello": "world", + }, + }, + Opts: &TermOptions{ + Annotations: map[string]string{ + "hello": "foo", + "bar": "baz", + }, + }, + Expectation: map[string]string{ + "hello": "world", + "bar": "baz", + }, + }, + } + + for _, test := range tests { + t.Run(test.Desc, func(t *testing.T) { + mux := NewMux() + defer mux.Close() + + terminalService := NewMuxTerminalService(mux) + var err error + if test.Opts == nil { + _, err = terminalService.Open(context.Background(), test.Req) + } else { + _, err = terminalService.OpenWithOptions(context.Background(), test.Req, *test.Opts) + } + if err != nil { + t.Fatal(err) + return + } + + lr, err := terminalService.List(context.Background(), &api.ListTerminalsRequest{}) + if err != nil { + t.Fatal(err) + return + } + if len(lr.Terminals) != 1 { + t.Fatalf("expected exactly one terminal, got %d", len(lr.Terminals)) + return + } + + if diff := cmp.Diff(test.Expectation, lr.Terminals[0].Annotations); diff != "" { + t.Errorf("unexpected output (-want +got):\n%s", diff) + } + }) + + } +} + func TestTerminals(t *testing.T) { tests := []struct { Desc string diff --git a/dev/addlicense/BUILD.yaml b/dev/addlicense/BUILD.yaml index 8afcf20d00e66d..d058205e54025e 100644 --- a/dev/addlicense/BUILD.yaml +++ b/dev/addlicense/BUILD.yaml @@ -9,3 +9,6 @@ packages: env: - CGO_ENABLED=0 - GOOS=linux + config: + dontLint: true + dontTest: true \ No newline at end of file diff --git a/test/leeway-build.sh b/test/leeway-build.sh index 8dc467793dba6d..29bb7333a32824 100755 --- a/test/leeway-build.sh +++ b/test/leeway-build.sh @@ -1,4 +1,8 @@ #!/bin/bash +# Copyright (c) 2021 Gitpod GmbH. All rights reserved. +# Licensed under the GNU Affero General Public License (AGPL). +# See License-AGPL.txt in the project root for license information. + mkdir -p bin