From dc03d536a98a8a01323aeb72347cda0fdca8ee0a Mon Sep 17 00:00:00 2001 From: Gero Posmyk-Leinemann Date: Wed, 30 Jun 2021 15:22:05 +0000 Subject: [PATCH] [content-service] Introduce log entity --- components/content-service-api/go/log.pb.go | 406 +++++++++ .../content-service-api/go/log_grpc.pb.go | 145 ++++ components/content-service-api/log.proto | 36 + .../typescript/src/log_grpc_pb.d.ts | 65 ++ .../typescript/src/log_grpc_pb.js | 84 ++ .../typescript/src/log_pb.d.ts | 110 +++ .../typescript/src/log_pb.js | 808 ++++++++++++++++++ components/content-service/cmd/run.go | 6 + .../pkg/layer/provider_test.go | 4 + components/content-service/pkg/logs/logs.go | 18 +- .../pkg/service/logs-service.go | 86 ++ .../content-service/pkg/storage/gcloud.go | 27 +- .../content-service/pkg/storage/minio.go | 30 +- .../content-service/pkg/storage/noop.go | 10 + .../content-service/pkg/storage/storage.go | 19 +- components/gitpod-protocol/src/wsready.ts | 2 +- components/supervisor/go.sum | 1 + .../ws-daemon/pkg/content/initializer.go | 5 + components/ws-daemon/pkg/content/service.go | 6 +- test/go.sum | 1 + 20 files changed, 1847 insertions(+), 22 deletions(-) create mode 100644 components/content-service-api/go/log.pb.go create mode 100644 components/content-service-api/go/log_grpc.pb.go create mode 100644 components/content-service-api/log.proto create mode 100644 components/content-service-api/typescript/src/log_grpc_pb.d.ts create mode 100644 components/content-service-api/typescript/src/log_grpc_pb.js create mode 100644 components/content-service-api/typescript/src/log_pb.d.ts create mode 100644 components/content-service-api/typescript/src/log_pb.js create mode 100644 components/content-service/pkg/service/logs-service.go diff --git a/components/content-service-api/go/log.pb.go b/components/content-service-api/go/log.pb.go new file mode 100644 index 00000000000000..a219c575adfa97 --- /dev/null +++ b/components/content-service-api/go/log.pb.go @@ -0,0 +1,406 @@ +// 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. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.15.5 +// source: log.proto + +package api + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type LogDownloadURLRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OwnerId string `protobuf:"bytes,1,opt,name=owner_id,json=ownerId,proto3" json:"owner_id,omitempty"` + WorkspaceId string `protobuf:"bytes,2,opt,name=workspace_id,json=workspaceId,proto3" json:"workspace_id,omitempty"` + InstanceId string `protobuf:"bytes,3,opt,name=instance_id,json=instanceId,proto3" json:"instance_id,omitempty"` + TaskId string `protobuf:"bytes,4,opt,name=task_id,json=taskId,proto3" json:"task_id,omitempty"` +} + +func (x *LogDownloadURLRequest) Reset() { + *x = LogDownloadURLRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_log_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LogDownloadURLRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LogDownloadURLRequest) ProtoMessage() {} + +func (x *LogDownloadURLRequest) ProtoReflect() protoreflect.Message { + mi := &file_log_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LogDownloadURLRequest.ProtoReflect.Descriptor instead. +func (*LogDownloadURLRequest) Descriptor() ([]byte, []int) { + return file_log_proto_rawDescGZIP(), []int{0} +} + +func (x *LogDownloadURLRequest) GetOwnerId() string { + if x != nil { + return x.OwnerId + } + return "" +} + +func (x *LogDownloadURLRequest) GetWorkspaceId() string { + if x != nil { + return x.WorkspaceId + } + return "" +} + +func (x *LogDownloadURLRequest) GetInstanceId() string { + if x != nil { + return x.InstanceId + } + return "" +} + +func (x *LogDownloadURLRequest) GetTaskId() string { + if x != nil { + return x.TaskId + } + return "" +} + +type LogDownloadURLResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` +} + +func (x *LogDownloadURLResponse) Reset() { + *x = LogDownloadURLResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_log_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LogDownloadURLResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LogDownloadURLResponse) ProtoMessage() {} + +func (x *LogDownloadURLResponse) ProtoReflect() protoreflect.Message { + mi := &file_log_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LogDownloadURLResponse.ProtoReflect.Descriptor instead. +func (*LogDownloadURLResponse) Descriptor() ([]byte, []int) { + return file_log_proto_rawDescGZIP(), []int{1} +} + +func (x *LogDownloadURLResponse) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +type ListPrebuildLogsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OwnerId string `protobuf:"bytes,1,opt,name=owner_id,json=ownerId,proto3" json:"owner_id,omitempty"` + WorkspaceId string `protobuf:"bytes,2,opt,name=workspace_id,json=workspaceId,proto3" json:"workspace_id,omitempty"` + InstanceId string `protobuf:"bytes,3,opt,name=instance_id,json=instanceId,proto3" json:"instance_id,omitempty"` +} + +func (x *ListPrebuildLogsRequest) Reset() { + *x = ListPrebuildLogsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_log_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListPrebuildLogsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListPrebuildLogsRequest) ProtoMessage() {} + +func (x *ListPrebuildLogsRequest) ProtoReflect() protoreflect.Message { + mi := &file_log_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListPrebuildLogsRequest.ProtoReflect.Descriptor instead. +func (*ListPrebuildLogsRequest) Descriptor() ([]byte, []int) { + return file_log_proto_rawDescGZIP(), []int{2} +} + +func (x *ListPrebuildLogsRequest) GetOwnerId() string { + if x != nil { + return x.OwnerId + } + return "" +} + +func (x *ListPrebuildLogsRequest) GetWorkspaceId() string { + if x != nil { + return x.WorkspaceId + } + return "" +} + +func (x *ListPrebuildLogsRequest) GetInstanceId() string { + if x != nil { + return x.InstanceId + } + return "" +} + +type ListPrebuildLogsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TaskId []string `protobuf:"bytes,1,rep,name=taskId,proto3" json:"taskId,omitempty"` +} + +func (x *ListPrebuildLogsResponse) Reset() { + *x = ListPrebuildLogsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_log_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListPrebuildLogsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListPrebuildLogsResponse) ProtoMessage() {} + +func (x *ListPrebuildLogsResponse) ProtoReflect() protoreflect.Message { + mi := &file_log_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListPrebuildLogsResponse.ProtoReflect.Descriptor instead. +func (*ListPrebuildLogsResponse) Descriptor() ([]byte, []int) { + return file_log_proto_rawDescGZIP(), []int{3} +} + +func (x *ListPrebuildLogsResponse) GetTaskId() []string { + if x != nil { + return x.TaskId + } + return nil +} + +var File_log_proto protoreflect.FileDescriptor + +var file_log_proto_rawDesc = []byte{ + 0x0a, 0x09, 0x6c, 0x6f, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x8f, 0x01, 0x0a, 0x15, + 0x4c, 0x6f, 0x67, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x55, 0x52, 0x4c, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, + 0x12, 0x21, 0x0a, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, + 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x22, 0x2a, 0x0a, + 0x16, 0x4c, 0x6f, 0x67, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x55, 0x52, 0x4c, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x78, 0x0a, 0x17, 0x4c, 0x69, 0x73, + 0x74, 0x50, 0x72, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, + 0x21, 0x0a, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 0x49, 0x64, 0x22, 0x32, 0x0a, 0x18, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x65, 0x62, 0x75, + 0x69, 0x6c, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x16, 0x0a, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x32, 0xd8, 0x01, 0x0a, 0x0a, 0x4c, 0x6f, 0x67, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x61, 0x0a, 0x0e, 0x4c, 0x6f, 0x67, 0x44, 0x6f, 0x77, + 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x55, 0x52, 0x4c, 0x12, 0x25, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4c, 0x6f, 0x67, 0x44, 0x6f, 0x77, + 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x55, 0x52, 0x4c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x26, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x2e, 0x4c, 0x6f, 0x67, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x55, 0x52, 0x4c, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x67, 0x0a, 0x10, 0x4c, 0x69, 0x73, + 0x74, 0x50, 0x72, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x27, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x50, 0x72, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x65, 0x62, + 0x75, 0x69, 0x6c, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x67, 0x69, 0x74, 0x70, 0x6f, 0x64, 0x2d, 0x69, 0x6f, 0x2f, 0x67, 0x69, 0x74, 0x70, 0x6f, + 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x2f, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_log_proto_rawDescOnce sync.Once + file_log_proto_rawDescData = file_log_proto_rawDesc +) + +func file_log_proto_rawDescGZIP() []byte { + file_log_proto_rawDescOnce.Do(func() { + file_log_proto_rawDescData = protoimpl.X.CompressGZIP(file_log_proto_rawDescData) + }) + return file_log_proto_rawDescData +} + +var file_log_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_log_proto_goTypes = []interface{}{ + (*LogDownloadURLRequest)(nil), // 0: contentservice.LogDownloadURLRequest + (*LogDownloadURLResponse)(nil), // 1: contentservice.LogDownloadURLResponse + (*ListPrebuildLogsRequest)(nil), // 2: contentservice.ListPrebuildLogsRequest + (*ListPrebuildLogsResponse)(nil), // 3: contentservice.ListPrebuildLogsResponse +} +var file_log_proto_depIdxs = []int32{ + 0, // 0: contentservice.LogService.LogDownloadURL:input_type -> contentservice.LogDownloadURLRequest + 2, // 1: contentservice.LogService.ListPrebuildLogs:input_type -> contentservice.ListPrebuildLogsRequest + 1, // 2: contentservice.LogService.LogDownloadURL:output_type -> contentservice.LogDownloadURLResponse + 3, // 3: contentservice.LogService.ListPrebuildLogs:output_type -> contentservice.ListPrebuildLogsResponse + 2, // [2:4] is the sub-list for method output_type + 0, // [0:2] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_log_proto_init() } +func file_log_proto_init() { + if File_log_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_log_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LogDownloadURLRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_log_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LogDownloadURLResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_log_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListPrebuildLogsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_log_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListPrebuildLogsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_log_proto_rawDesc, + NumEnums: 0, + NumMessages: 4, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_log_proto_goTypes, + DependencyIndexes: file_log_proto_depIdxs, + MessageInfos: file_log_proto_msgTypes, + }.Build() + File_log_proto = out.File + file_log_proto_rawDesc = nil + file_log_proto_goTypes = nil + file_log_proto_depIdxs = nil +} diff --git a/components/content-service-api/go/log_grpc.pb.go b/components/content-service-api/go/log_grpc.pb.go new file mode 100644 index 00000000000000..ffbaab501ece43 --- /dev/null +++ b/components/content-service-api/go/log_grpc.pb.go @@ -0,0 +1,145 @@ +// 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. + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. + +package api + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// LogServiceClient is the client API for LogService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type LogServiceClient interface { + // LogDownloadURL provides a URL from where the content of a workspace can be downloaded from + LogDownloadURL(ctx context.Context, in *LogDownloadURLRequest, opts ...grpc.CallOption) (*LogDownloadURLResponse, error) + // ListPrebuildLogs returns a list of taskIds for the specified workspace instance + ListPrebuildLogs(ctx context.Context, in *ListPrebuildLogsRequest, opts ...grpc.CallOption) (*ListPrebuildLogsResponse, error) +} + +type logServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewLogServiceClient(cc grpc.ClientConnInterface) LogServiceClient { + return &logServiceClient{cc} +} + +func (c *logServiceClient) LogDownloadURL(ctx context.Context, in *LogDownloadURLRequest, opts ...grpc.CallOption) (*LogDownloadURLResponse, error) { + out := new(LogDownloadURLResponse) + err := c.cc.Invoke(ctx, "/contentservice.LogService/LogDownloadURL", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *logServiceClient) ListPrebuildLogs(ctx context.Context, in *ListPrebuildLogsRequest, opts ...grpc.CallOption) (*ListPrebuildLogsResponse, error) { + out := new(ListPrebuildLogsResponse) + err := c.cc.Invoke(ctx, "/contentservice.LogService/ListPrebuildLogs", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// LogServiceServer is the server API for LogService service. +// All implementations must embed UnimplementedLogServiceServer +// for forward compatibility +type LogServiceServer interface { + // LogDownloadURL provides a URL from where the content of a workspace can be downloaded from + LogDownloadURL(context.Context, *LogDownloadURLRequest) (*LogDownloadURLResponse, error) + // ListPrebuildLogs returns a list of taskIds for the specified workspace instance + ListPrebuildLogs(context.Context, *ListPrebuildLogsRequest) (*ListPrebuildLogsResponse, error) + mustEmbedUnimplementedLogServiceServer() +} + +// UnimplementedLogServiceServer must be embedded to have forward compatible implementations. +type UnimplementedLogServiceServer struct { +} + +func (UnimplementedLogServiceServer) LogDownloadURL(context.Context, *LogDownloadURLRequest) (*LogDownloadURLResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method LogDownloadURL not implemented") +} +func (UnimplementedLogServiceServer) ListPrebuildLogs(context.Context, *ListPrebuildLogsRequest) (*ListPrebuildLogsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListPrebuildLogs not implemented") +} +func (UnimplementedLogServiceServer) mustEmbedUnimplementedLogServiceServer() {} + +// UnsafeLogServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to LogServiceServer will +// result in compilation errors. +type UnsafeLogServiceServer interface { + mustEmbedUnimplementedLogServiceServer() +} + +func RegisterLogServiceServer(s grpc.ServiceRegistrar, srv LogServiceServer) { + s.RegisterService(&LogService_ServiceDesc, srv) +} + +func _LogService_LogDownloadURL_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LogDownloadURLRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(LogServiceServer).LogDownloadURL(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/contentservice.LogService/LogDownloadURL", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(LogServiceServer).LogDownloadURL(ctx, req.(*LogDownloadURLRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _LogService_ListPrebuildLogs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListPrebuildLogsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(LogServiceServer).ListPrebuildLogs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/contentservice.LogService/ListPrebuildLogs", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(LogServiceServer).ListPrebuildLogs(ctx, req.(*ListPrebuildLogsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// LogService_ServiceDesc is the grpc.ServiceDesc for LogService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var LogService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "contentservice.LogService", + HandlerType: (*LogServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "LogDownloadURL", + Handler: _LogService_LogDownloadURL_Handler, + }, + { + MethodName: "ListPrebuildLogs", + Handler: _LogService_ListPrebuildLogs_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "log.proto", +} diff --git a/components/content-service-api/log.proto b/components/content-service-api/log.proto new file mode 100644 index 00000000000000..062042064403ee --- /dev/null +++ b/components/content-service-api/log.proto @@ -0,0 +1,36 @@ +// 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. + +syntax = "proto3"; + +package contentservice; + +option go_package = "github.com/gitpod-io/gitpod/content-service/api"; + +service LogService { + // LogDownloadURL provides a URL from where the content of a workspace can be downloaded from + rpc LogDownloadURL(LogDownloadURLRequest) returns (LogDownloadURLResponse) {}; + + // ListPrebuildLogs returns a list of taskIds for the specified workspace instance + rpc ListPrebuildLogs(ListPrebuildLogsRequest) returns (ListPrebuildLogsResponse) {}; +} + +message LogDownloadURLRequest { + string owner_id = 1; + string workspace_id = 2; + string instance_id = 3; + string task_id = 4; +} +message LogDownloadURLResponse { + string url = 1; +} + +message ListPrebuildLogsRequest { + string owner_id = 1; + string workspace_id = 2; + string instance_id = 3; +} +message ListPrebuildLogsResponse { + repeated string taskId = 1; +} \ No newline at end of file diff --git a/components/content-service-api/typescript/src/log_grpc_pb.d.ts b/components/content-service-api/typescript/src/log_grpc_pb.d.ts new file mode 100644 index 00000000000000..5213aff5e79f73 --- /dev/null +++ b/components/content-service-api/typescript/src/log_grpc_pb.d.ts @@ -0,0 +1,65 @@ +/** + * 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: contentservice +// file: log.proto + +/* tslint:disable */ +/* eslint-disable */ + +import * as grpc from "@grpc/grpc-js"; +import {handleClientStreamingCall} from "@grpc/grpc-js/build/src/server-call"; +import * as log_pb from "./log_pb"; + +interface ILogServiceService extends grpc.ServiceDefinition { + logDownloadURL: ILogServiceService_ILogDownloadURL; + listPrebuildLogs: ILogServiceService_IListPrebuildLogs; +} + +interface ILogServiceService_ILogDownloadURL extends grpc.MethodDefinition { + path: "/contentservice.LogService/LogDownloadURL"; + requestStream: false; + responseStream: false; + requestSerialize: grpc.serialize; + requestDeserialize: grpc.deserialize; + responseSerialize: grpc.serialize; + responseDeserialize: grpc.deserialize; +} +interface ILogServiceService_IListPrebuildLogs extends grpc.MethodDefinition { + path: "/contentservice.LogService/ListPrebuildLogs"; + requestStream: false; + responseStream: false; + requestSerialize: grpc.serialize; + requestDeserialize: grpc.deserialize; + responseSerialize: grpc.serialize; + responseDeserialize: grpc.deserialize; +} + +export const LogServiceService: ILogServiceService; + +export interface ILogServiceServer extends grpc.UntypedServiceImplementation { + logDownloadURL: grpc.handleUnaryCall; + listPrebuildLogs: grpc.handleUnaryCall; +} + +export interface ILogServiceClient { + logDownloadURL(request: log_pb.LogDownloadURLRequest, callback: (error: grpc.ServiceError | null, response: log_pb.LogDownloadURLResponse) => void): grpc.ClientUnaryCall; + logDownloadURL(request: log_pb.LogDownloadURLRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: log_pb.LogDownloadURLResponse) => void): grpc.ClientUnaryCall; + logDownloadURL(request: log_pb.LogDownloadURLRequest, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: log_pb.LogDownloadURLResponse) => void): grpc.ClientUnaryCall; + listPrebuildLogs(request: log_pb.ListPrebuildLogsRequest, callback: (error: grpc.ServiceError | null, response: log_pb.ListPrebuildLogsResponse) => void): grpc.ClientUnaryCall; + listPrebuildLogs(request: log_pb.ListPrebuildLogsRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: log_pb.ListPrebuildLogsResponse) => void): grpc.ClientUnaryCall; + listPrebuildLogs(request: log_pb.ListPrebuildLogsRequest, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: log_pb.ListPrebuildLogsResponse) => void): grpc.ClientUnaryCall; +} + +export class LogServiceClient extends grpc.Client implements ILogServiceClient { + constructor(address: string, credentials: grpc.ChannelCredentials, options?: Partial); + public logDownloadURL(request: log_pb.LogDownloadURLRequest, callback: (error: grpc.ServiceError | null, response: log_pb.LogDownloadURLResponse) => void): grpc.ClientUnaryCall; + public logDownloadURL(request: log_pb.LogDownloadURLRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: log_pb.LogDownloadURLResponse) => void): grpc.ClientUnaryCall; + public logDownloadURL(request: log_pb.LogDownloadURLRequest, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: log_pb.LogDownloadURLResponse) => void): grpc.ClientUnaryCall; + public listPrebuildLogs(request: log_pb.ListPrebuildLogsRequest, callback: (error: grpc.ServiceError | null, response: log_pb.ListPrebuildLogsResponse) => void): grpc.ClientUnaryCall; + public listPrebuildLogs(request: log_pb.ListPrebuildLogsRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: log_pb.ListPrebuildLogsResponse) => void): grpc.ClientUnaryCall; + public listPrebuildLogs(request: log_pb.ListPrebuildLogsRequest, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: log_pb.ListPrebuildLogsResponse) => void): grpc.ClientUnaryCall; +} diff --git a/components/content-service-api/typescript/src/log_grpc_pb.js b/components/content-service-api/typescript/src/log_grpc_pb.js new file mode 100644 index 00000000000000..468b8e602fdd82 --- /dev/null +++ b/components/content-service-api/typescript/src/log_grpc_pb.js @@ -0,0 +1,84 @@ +// GENERATED CODE -- DO NOT EDIT! + +// Original file comments: +// 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. +// +'use strict'; +var grpc = require('@grpc/grpc-js'); +var log_pb = require('./log_pb.js'); + +function serialize_contentservice_ListPrebuildLogsRequest(arg) { + if (!(arg instanceof log_pb.ListPrebuildLogsRequest)) { + throw new Error('Expected argument of type contentservice.ListPrebuildLogsRequest'); + } + return Buffer.from(arg.serializeBinary()); +} + +function deserialize_contentservice_ListPrebuildLogsRequest(buffer_arg) { + return log_pb.ListPrebuildLogsRequest.deserializeBinary(new Uint8Array(buffer_arg)); +} + +function serialize_contentservice_ListPrebuildLogsResponse(arg) { + if (!(arg instanceof log_pb.ListPrebuildLogsResponse)) { + throw new Error('Expected argument of type contentservice.ListPrebuildLogsResponse'); + } + return Buffer.from(arg.serializeBinary()); +} + +function deserialize_contentservice_ListPrebuildLogsResponse(buffer_arg) { + return log_pb.ListPrebuildLogsResponse.deserializeBinary(new Uint8Array(buffer_arg)); +} + +function serialize_contentservice_LogDownloadURLRequest(arg) { + if (!(arg instanceof log_pb.LogDownloadURLRequest)) { + throw new Error('Expected argument of type contentservice.LogDownloadURLRequest'); + } + return Buffer.from(arg.serializeBinary()); +} + +function deserialize_contentservice_LogDownloadURLRequest(buffer_arg) { + return log_pb.LogDownloadURLRequest.deserializeBinary(new Uint8Array(buffer_arg)); +} + +function serialize_contentservice_LogDownloadURLResponse(arg) { + if (!(arg instanceof log_pb.LogDownloadURLResponse)) { + throw new Error('Expected argument of type contentservice.LogDownloadURLResponse'); + } + return Buffer.from(arg.serializeBinary()); +} + +function deserialize_contentservice_LogDownloadURLResponse(buffer_arg) { + return log_pb.LogDownloadURLResponse.deserializeBinary(new Uint8Array(buffer_arg)); +} + + +var LogServiceService = exports.LogServiceService = { + // LogDownloadURL provides a URL from where the content of a workspace can be downloaded from +logDownloadURL: { + path: '/contentservice.LogService/LogDownloadURL', + requestStream: false, + responseStream: false, + requestType: log_pb.LogDownloadURLRequest, + responseType: log_pb.LogDownloadURLResponse, + requestSerialize: serialize_contentservice_LogDownloadURLRequest, + requestDeserialize: deserialize_contentservice_LogDownloadURLRequest, + responseSerialize: serialize_contentservice_LogDownloadURLResponse, + responseDeserialize: deserialize_contentservice_LogDownloadURLResponse, + }, + // ListPrebuildLogs returns a list of taskIds for the specified workspace instance +listPrebuildLogs: { + path: '/contentservice.LogService/ListPrebuildLogs', + requestStream: false, + responseStream: false, + requestType: log_pb.ListPrebuildLogsRequest, + responseType: log_pb.ListPrebuildLogsResponse, + requestSerialize: serialize_contentservice_ListPrebuildLogsRequest, + requestDeserialize: deserialize_contentservice_ListPrebuildLogsRequest, + responseSerialize: serialize_contentservice_ListPrebuildLogsResponse, + responseDeserialize: deserialize_contentservice_ListPrebuildLogsResponse, + }, +}; + +exports.LogServiceClient = grpc.makeGenericClientConstructor(LogServiceService); diff --git a/components/content-service-api/typescript/src/log_pb.d.ts b/components/content-service-api/typescript/src/log_pb.d.ts new file mode 100644 index 00000000000000..d2a4ccaa61f5d9 --- /dev/null +++ b/components/content-service-api/typescript/src/log_pb.d.ts @@ -0,0 +1,110 @@ +/** + * 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: contentservice +// file: log.proto + +/* tslint:disable */ +/* eslint-disable */ + +import * as jspb from "google-protobuf"; + +export class LogDownloadURLRequest extends jspb.Message { + getOwnerId(): string; + setOwnerId(value: string): LogDownloadURLRequest; + getWorkspaceId(): string; + setWorkspaceId(value: string): LogDownloadURLRequest; + getInstanceId(): string; + setInstanceId(value: string): LogDownloadURLRequest; + getTaskId(): string; + setTaskId(value: string): LogDownloadURLRequest; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): LogDownloadURLRequest.AsObject; + static toObject(includeInstance: boolean, msg: LogDownloadURLRequest): LogDownloadURLRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: LogDownloadURLRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): LogDownloadURLRequest; + static deserializeBinaryFromReader(message: LogDownloadURLRequest, reader: jspb.BinaryReader): LogDownloadURLRequest; +} + +export namespace LogDownloadURLRequest { + export type AsObject = { + ownerId: string, + workspaceId: string, + instanceId: string, + taskId: string, + } +} + +export class LogDownloadURLResponse extends jspb.Message { + getUrl(): string; + setUrl(value: string): LogDownloadURLResponse; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): LogDownloadURLResponse.AsObject; + static toObject(includeInstance: boolean, msg: LogDownloadURLResponse): LogDownloadURLResponse.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: LogDownloadURLResponse, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): LogDownloadURLResponse; + static deserializeBinaryFromReader(message: LogDownloadURLResponse, reader: jspb.BinaryReader): LogDownloadURLResponse; +} + +export namespace LogDownloadURLResponse { + export type AsObject = { + url: string, + } +} + +export class ListPrebuildLogsRequest extends jspb.Message { + getOwnerId(): string; + setOwnerId(value: string): ListPrebuildLogsRequest; + getWorkspaceId(): string; + setWorkspaceId(value: string): ListPrebuildLogsRequest; + getInstanceId(): string; + setInstanceId(value: string): ListPrebuildLogsRequest; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): ListPrebuildLogsRequest.AsObject; + static toObject(includeInstance: boolean, msg: ListPrebuildLogsRequest): ListPrebuildLogsRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: ListPrebuildLogsRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): ListPrebuildLogsRequest; + static deserializeBinaryFromReader(message: ListPrebuildLogsRequest, reader: jspb.BinaryReader): ListPrebuildLogsRequest; +} + +export namespace ListPrebuildLogsRequest { + export type AsObject = { + ownerId: string, + workspaceId: string, + instanceId: string, + } +} + +export class ListPrebuildLogsResponse extends jspb.Message { + clearTaskidList(): void; + getTaskidList(): Array; + setTaskidList(value: Array): ListPrebuildLogsResponse; + addTaskid(value: string, index?: number): string; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): ListPrebuildLogsResponse.AsObject; + static toObject(includeInstance: boolean, msg: ListPrebuildLogsResponse): ListPrebuildLogsResponse.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: ListPrebuildLogsResponse, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): ListPrebuildLogsResponse; + static deserializeBinaryFromReader(message: ListPrebuildLogsResponse, reader: jspb.BinaryReader): ListPrebuildLogsResponse; +} + +export namespace ListPrebuildLogsResponse { + export type AsObject = { + taskidList: Array, + } +} diff --git a/components/content-service-api/typescript/src/log_pb.js b/components/content-service-api/typescript/src/log_pb.js new file mode 100644 index 00000000000000..c98831a535f036 --- /dev/null +++ b/components/content-service-api/typescript/src/log_pb.js @@ -0,0 +1,808 @@ +/** + * 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. + */ + +// source: log.proto +/** + * @fileoverview + * @enhanceable + * @suppress {missingRequire} reports error on implicit type usages. + * @suppress {messageConventions} JS Compiler reports an error if a variable or + * field starts with 'MSG_' and isn't a translatable message. + * @public + */ +// GENERATED CODE -- DO NOT EDIT! +/* eslint-disable */ +// @ts-nocheck + +var jspb = require('google-protobuf'); +var goog = jspb; +var global = Function('return this')(); + +goog.exportSymbol('proto.contentservice.ListPrebuildLogsRequest', null, global); +goog.exportSymbol('proto.contentservice.ListPrebuildLogsResponse', null, global); +goog.exportSymbol('proto.contentservice.LogDownloadURLRequest', null, global); +goog.exportSymbol('proto.contentservice.LogDownloadURLResponse', null, global); +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.contentservice.LogDownloadURLRequest = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.contentservice.LogDownloadURLRequest, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.contentservice.LogDownloadURLRequest.displayName = 'proto.contentservice.LogDownloadURLRequest'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.contentservice.LogDownloadURLResponse = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.contentservice.LogDownloadURLResponse, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.contentservice.LogDownloadURLResponse.displayName = 'proto.contentservice.LogDownloadURLResponse'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.contentservice.ListPrebuildLogsRequest = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.contentservice.ListPrebuildLogsRequest, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.contentservice.ListPrebuildLogsRequest.displayName = 'proto.contentservice.ListPrebuildLogsRequest'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.contentservice.ListPrebuildLogsResponse = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.contentservice.ListPrebuildLogsResponse.repeatedFields_, null); +}; +goog.inherits(proto.contentservice.ListPrebuildLogsResponse, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.contentservice.ListPrebuildLogsResponse.displayName = 'proto.contentservice.ListPrebuildLogsResponse'; +} + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.contentservice.LogDownloadURLRequest.prototype.toObject = function(opt_includeInstance) { + return proto.contentservice.LogDownloadURLRequest.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.contentservice.LogDownloadURLRequest} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.contentservice.LogDownloadURLRequest.toObject = function(includeInstance, msg) { + var f, obj = { + ownerId: jspb.Message.getFieldWithDefault(msg, 1, ""), + workspaceId: jspb.Message.getFieldWithDefault(msg, 2, ""), + instanceId: jspb.Message.getFieldWithDefault(msg, 3, ""), + taskId: jspb.Message.getFieldWithDefault(msg, 4, "") + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.contentservice.LogDownloadURLRequest} + */ +proto.contentservice.LogDownloadURLRequest.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.contentservice.LogDownloadURLRequest; + return proto.contentservice.LogDownloadURLRequest.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.contentservice.LogDownloadURLRequest} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.contentservice.LogDownloadURLRequest} + */ +proto.contentservice.LogDownloadURLRequest.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.setOwnerId(value); + break; + case 2: + var value = /** @type {string} */ (reader.readString()); + msg.setWorkspaceId(value); + break; + case 3: + var value = /** @type {string} */ (reader.readString()); + msg.setInstanceId(value); + break; + case 4: + var value = /** @type {string} */ (reader.readString()); + msg.setTaskId(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.contentservice.LogDownloadURLRequest.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.contentservice.LogDownloadURLRequest.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.contentservice.LogDownloadURLRequest} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.contentservice.LogDownloadURLRequest.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getOwnerId(); + if (f.length > 0) { + writer.writeString( + 1, + f + ); + } + f = message.getWorkspaceId(); + if (f.length > 0) { + writer.writeString( + 2, + f + ); + } + f = message.getInstanceId(); + if (f.length > 0) { + writer.writeString( + 3, + f + ); + } + f = message.getTaskId(); + if (f.length > 0) { + writer.writeString( + 4, + f + ); + } +}; + + +/** + * optional string owner_id = 1; + * @return {string} + */ +proto.contentservice.LogDownloadURLRequest.prototype.getOwnerId = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); +}; + + +/** + * @param {string} value + * @return {!proto.contentservice.LogDownloadURLRequest} returns this + */ +proto.contentservice.LogDownloadURLRequest.prototype.setOwnerId = function(value) { + return jspb.Message.setProto3StringField(this, 1, value); +}; + + +/** + * optional string workspace_id = 2; + * @return {string} + */ +proto.contentservice.LogDownloadURLRequest.prototype.getWorkspaceId = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** + * @param {string} value + * @return {!proto.contentservice.LogDownloadURLRequest} returns this + */ +proto.contentservice.LogDownloadURLRequest.prototype.setWorkspaceId = function(value) { + return jspb.Message.setProto3StringField(this, 2, value); +}; + + +/** + * optional string instance_id = 3; + * @return {string} + */ +proto.contentservice.LogDownloadURLRequest.prototype.getInstanceId = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, "")); +}; + + +/** + * @param {string} value + * @return {!proto.contentservice.LogDownloadURLRequest} returns this + */ +proto.contentservice.LogDownloadURLRequest.prototype.setInstanceId = function(value) { + return jspb.Message.setProto3StringField(this, 3, value); +}; + + +/** + * optional string task_id = 4; + * @return {string} + */ +proto.contentservice.LogDownloadURLRequest.prototype.getTaskId = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 4, "")); +}; + + +/** + * @param {string} value + * @return {!proto.contentservice.LogDownloadURLRequest} returns this + */ +proto.contentservice.LogDownloadURLRequest.prototype.setTaskId = function(value) { + return jspb.Message.setProto3StringField(this, 4, value); +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.contentservice.LogDownloadURLResponse.prototype.toObject = function(opt_includeInstance) { + return proto.contentservice.LogDownloadURLResponse.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.contentservice.LogDownloadURLResponse} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.contentservice.LogDownloadURLResponse.toObject = function(includeInstance, msg) { + var f, obj = { + url: jspb.Message.getFieldWithDefault(msg, 1, "") + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.contentservice.LogDownloadURLResponse} + */ +proto.contentservice.LogDownloadURLResponse.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.contentservice.LogDownloadURLResponse; + return proto.contentservice.LogDownloadURLResponse.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.contentservice.LogDownloadURLResponse} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.contentservice.LogDownloadURLResponse} + */ +proto.contentservice.LogDownloadURLResponse.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.setUrl(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.contentservice.LogDownloadURLResponse.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.contentservice.LogDownloadURLResponse.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.contentservice.LogDownloadURLResponse} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.contentservice.LogDownloadURLResponse.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getUrl(); + if (f.length > 0) { + writer.writeString( + 1, + f + ); + } +}; + + +/** + * optional string url = 1; + * @return {string} + */ +proto.contentservice.LogDownloadURLResponse.prototype.getUrl = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); +}; + + +/** + * @param {string} value + * @return {!proto.contentservice.LogDownloadURLResponse} returns this + */ +proto.contentservice.LogDownloadURLResponse.prototype.setUrl = function(value) { + return jspb.Message.setProto3StringField(this, 1, value); +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.contentservice.ListPrebuildLogsRequest.prototype.toObject = function(opt_includeInstance) { + return proto.contentservice.ListPrebuildLogsRequest.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.contentservice.ListPrebuildLogsRequest} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.contentservice.ListPrebuildLogsRequest.toObject = function(includeInstance, msg) { + var f, obj = { + ownerId: jspb.Message.getFieldWithDefault(msg, 1, ""), + workspaceId: jspb.Message.getFieldWithDefault(msg, 2, ""), + instanceId: jspb.Message.getFieldWithDefault(msg, 3, "") + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.contentservice.ListPrebuildLogsRequest} + */ +proto.contentservice.ListPrebuildLogsRequest.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.contentservice.ListPrebuildLogsRequest; + return proto.contentservice.ListPrebuildLogsRequest.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.contentservice.ListPrebuildLogsRequest} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.contentservice.ListPrebuildLogsRequest} + */ +proto.contentservice.ListPrebuildLogsRequest.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.setOwnerId(value); + break; + case 2: + var value = /** @type {string} */ (reader.readString()); + msg.setWorkspaceId(value); + break; + case 3: + var value = /** @type {string} */ (reader.readString()); + msg.setInstanceId(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.contentservice.ListPrebuildLogsRequest.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.contentservice.ListPrebuildLogsRequest.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.contentservice.ListPrebuildLogsRequest} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.contentservice.ListPrebuildLogsRequest.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getOwnerId(); + if (f.length > 0) { + writer.writeString( + 1, + f + ); + } + f = message.getWorkspaceId(); + if (f.length > 0) { + writer.writeString( + 2, + f + ); + } + f = message.getInstanceId(); + if (f.length > 0) { + writer.writeString( + 3, + f + ); + } +}; + + +/** + * optional string owner_id = 1; + * @return {string} + */ +proto.contentservice.ListPrebuildLogsRequest.prototype.getOwnerId = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); +}; + + +/** + * @param {string} value + * @return {!proto.contentservice.ListPrebuildLogsRequest} returns this + */ +proto.contentservice.ListPrebuildLogsRequest.prototype.setOwnerId = function(value) { + return jspb.Message.setProto3StringField(this, 1, value); +}; + + +/** + * optional string workspace_id = 2; + * @return {string} + */ +proto.contentservice.ListPrebuildLogsRequest.prototype.getWorkspaceId = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** + * @param {string} value + * @return {!proto.contentservice.ListPrebuildLogsRequest} returns this + */ +proto.contentservice.ListPrebuildLogsRequest.prototype.setWorkspaceId = function(value) { + return jspb.Message.setProto3StringField(this, 2, value); +}; + + +/** + * optional string instance_id = 3; + * @return {string} + */ +proto.contentservice.ListPrebuildLogsRequest.prototype.getInstanceId = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, "")); +}; + + +/** + * @param {string} value + * @return {!proto.contentservice.ListPrebuildLogsRequest} returns this + */ +proto.contentservice.ListPrebuildLogsRequest.prototype.setInstanceId = function(value) { + return jspb.Message.setProto3StringField(this, 3, value); +}; + + + +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.contentservice.ListPrebuildLogsResponse.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.contentservice.ListPrebuildLogsResponse.prototype.toObject = function(opt_includeInstance) { + return proto.contentservice.ListPrebuildLogsResponse.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.contentservice.ListPrebuildLogsResponse} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.contentservice.ListPrebuildLogsResponse.toObject = function(includeInstance, msg) { + var f, obj = { + taskidList: (f = jspb.Message.getRepeatedField(msg, 1)) == null ? undefined : f + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.contentservice.ListPrebuildLogsResponse} + */ +proto.contentservice.ListPrebuildLogsResponse.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.contentservice.ListPrebuildLogsResponse; + return proto.contentservice.ListPrebuildLogsResponse.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.contentservice.ListPrebuildLogsResponse} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.contentservice.ListPrebuildLogsResponse} + */ +proto.contentservice.ListPrebuildLogsResponse.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.addTaskid(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.contentservice.ListPrebuildLogsResponse.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.contentservice.ListPrebuildLogsResponse.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.contentservice.ListPrebuildLogsResponse} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.contentservice.ListPrebuildLogsResponse.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getTaskidList(); + if (f.length > 0) { + writer.writeRepeatedString( + 1, + f + ); + } +}; + + +/** + * repeated string taskId = 1; + * @return {!Array} + */ +proto.contentservice.ListPrebuildLogsResponse.prototype.getTaskidList = function() { + return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 1)); +}; + + +/** + * @param {!Array} value + * @return {!proto.contentservice.ListPrebuildLogsResponse} returns this + */ +proto.contentservice.ListPrebuildLogsResponse.prototype.setTaskidList = function(value) { + return jspb.Message.setField(this, 1, value || []); +}; + + +/** + * @param {string} value + * @param {number=} opt_index + * @return {!proto.contentservice.ListPrebuildLogsResponse} returns this + */ +proto.contentservice.ListPrebuildLogsResponse.prototype.addTaskid = function(value, opt_index) { + return jspb.Message.addToRepeatedField(this, 1, value, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.contentservice.ListPrebuildLogsResponse} returns this + */ +proto.contentservice.ListPrebuildLogsResponse.prototype.clearTaskidList = function() { + return this.setTaskidList([]); +}; + + +goog.object.extend(exports, proto.contentservice); diff --git a/components/content-service/cmd/run.go b/components/content-service/cmd/run.go index d81f45309dfd5a..7c2afeac818966 100644 --- a/components/content-service/cmd/run.go +++ b/components/content-service/cmd/run.go @@ -90,6 +90,12 @@ var runCmd = &cobra.Command{ } api.RegisterWorkspaceServiceServer(server, workspaceService) + logService, err := service.NewLogService(cfg.Storage) + if err != nil { + log.WithError(err).Fatalf("cannot create log service") + } + api.RegisterLogServiceServer(server, logService) + idePluginService, err := service.NewIDEPluginService(cfg.Storage) if err != nil { log.WithError(err).Fatalf("cannot create IDE Plugin service") diff --git a/components/content-service/pkg/layer/provider_test.go b/components/content-service/pkg/layer/provider_test.go index a88ed07a0c9b57..543ba1246bb250 100644 --- a/components/content-service/pkg/layer/provider_test.go +++ b/components/content-service/pkg/layer/provider_test.go @@ -248,6 +248,10 @@ func (*testStorage) BackupObject(workspaceID string, name string) string { return "" } +func (*testStorage) InstanceObject(workspaceID string, instanceID string, name string) string { + return "" +} + func (*testStorage) ObjectHash(ctx context.Context, bucket string, obj string) (string, error) { return "", nil } diff --git a/components/content-service/pkg/logs/logs.go b/components/content-service/pkg/logs/logs.go index a8bbb840156626..df8444e5647a9b 100644 --- a/components/content-service/pkg/logs/logs.go +++ b/components/content-service/pkg/logs/logs.go @@ -21,15 +21,23 @@ const ( legacyTerminalStoreLocation = "/workspace" legacyPrebuildLogFilePrefix = ".prebuild-log-" + + // UploadedPrebuildLogPathPrefix is the prefix under which workspace logs are stored inside an instance + UploadedPrebuildLogPathPrefix = "logs" ) -// PrebuildLogFileName is the absolute path to the file containing the outpuit of the prebuild log for the given task +// UploadedPrebuildLogPath returns the path relative to the +func UploadedPrebuildLogPath(taskID string) string { + return fmt.Sprintf("%s/%s", UploadedPrebuildLogPathPrefix, taskID) +} + +// PrebuildLogFileName is the absolute path to the file containing the output of the prebuild log for the given task in recent workspaces func PrebuildLogFileName(storeLocation string, taskId string) string { return storeLocation + "/" + prebuildLogFilePrefix + taskId } -// LegacyPrebuildLogFileName is the absolute path to the file containing the outpuit of the prebuild log for the given -// task for older workspaces +// LegacyPrebuildLogFileName is the absolute path to the file containing the output of the prebuild log for the given +// task in older workspaces func LegacyPrebuildLogFileName(taskId string) string { return legacyTerminalStoreLocation + "/" + legacyPrebuildLogFilePrefix + taskId } @@ -65,8 +73,8 @@ func ListPrebuildLogFiles(ctx context.Context, location string) (filePaths []str return filePaths, nil } -// ParseStreamID tries to parse the streamID from the given file name path -func ParseStreamID(filePath string) (string, error) { +// ParseTaskID tries to parse the streamID from the given file name path +func ParseTaskID(filePath string) (string, error) { fileName := filepath.Base(filePath) var streamID string diff --git a/components/content-service/pkg/service/logs-service.go b/components/content-service/pkg/service/logs-service.go new file mode 100644 index 00000000000000..25df940bafdc2b --- /dev/null +++ b/components/content-service/pkg/service/logs-service.go @@ -0,0 +1,86 @@ +// 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 service + +import ( + "context" + + "github.com/opentracing/opentracing-go" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/gitpod-io/gitpod/common-go/log" + "github.com/gitpod-io/gitpod/common-go/tracing" + "github.com/gitpod-io/gitpod/content-service/api" + "github.com/gitpod-io/gitpod/content-service/pkg/logs" + "github.com/gitpod-io/gitpod/content-service/pkg/storage" +) + +// LogService implements LogServiceServer +type LogService struct { + cfg storage.Config + s storage.PresignedAccess + d storage.DirectAccess + + api.UnimplementedLogServiceServer +} + +// NewLogService create a new content service +func NewLogService(cfg storage.Config) (res *LogService, err error) { + s, err := storage.NewPresignedAccess(&cfg) + if err != nil { + return nil, err + } + d, err := storage.NewDirectAccess(&cfg) + if err != nil { + return nil, err + } + return &LogService{ + cfg: cfg, + s: s, + d: d, + }, nil +} + +// LogDownloadURL provides a URL from where the content of a workspace log stream can be downloaded from +func (ls *LogService) LogDownloadURL(ctx context.Context, req *api.LogDownloadURLRequest) (resp *api.LogDownloadURLResponse, err error) { + span, ctx := opentracing.StartSpanFromContext(ctx, "WorkspaceDownloadURL") + span.SetTag("user", req.OwnerId) + span.SetTag("workspaceId", req.WorkspaceId) + span.SetTag("instanceId", req.InstanceId) + defer tracing.FinishSpan(span, &err) + + blobName := ls.s.InstanceObject(req.WorkspaceId, req.InstanceId, logs.UploadedPrebuildLogPath(req.TaskId)) + info, err := ls.s.SignDownload(ctx, ls.s.Bucket(req.OwnerId), blobName, &storage.SignedURLOptions{}) + if err != nil { + log.WithFields(log.OWI(req.OwnerId, req.WorkspaceId, "")). + WithField("bucket", ls.s.Bucket(req.OwnerId)). + WithField("blobName", blobName). + WithError(err). + Error("error getting SignDownload URL") + if err == storage.ErrNotFound { + return nil, status.Error(codes.NotFound, err.Error()) + } + return nil, status.Error(codes.Unknown, err.Error()) + } + + return &api.LogDownloadURLResponse{ + Url: info.URL, + }, nil +} + +// ListPrebuildLogs returns a list of taskIds for the specified workspace instance +func (ls *LogService) ListPrebuildLogs(ctx context.Context, req *api.ListPrebuildLogsRequest) (resp *api.ListPrebuildLogsResponse, err error) { + // all files under this prefix are logs prebuild log files, named after their respective taskIds + prefix := ls.s.InstanceObject(req.WorkspaceId, req.InstanceId, logs.UploadedPrebuildLogPathPrefix) + objects, err := ls.d.ListObjects(ctx, prefix) + if err != nil { + return nil, err + } + + return &api.ListPrebuildLogsResponse{ + TaskId: objects, + }, nil +} diff --git a/components/content-service/pkg/storage/gcloud.go b/components/content-service/pkg/storage/gcloud.go index 4859f90c46b10e..5f80e946c8707b 100644 --- a/components/content-service/pkg/storage/gcloud.go +++ b/components/content-service/pkg/storage/gcloud.go @@ -287,6 +287,21 @@ func ParseSnapshotName(name string) (bkt, obj string, err error) { return } +// ListObjects returns all objects found with the given prefix +func (rs *DirectGCPStorage) ListObjects(ctx context.Context, prefix string) (objects []string, err error) { + bkt := rs.client.Bucket(rs.bucketName()) + iter := bkt.Objects(ctx, &gcpstorage.Query{Prefix: prefix}) + var obj *gcpstorage.ObjectAttrs + for obj, err = iter.Next(); obj != nil; obj, err = iter.Next() { + objects = append(objects, obj.Name) + } + if err != iterator.Done && err != nil { + return nil, err + } + + return objects, nil +} + // Qualify fully qualifies a snapshot name so that it can be downloaded using DownloadSnapshot func (rs *DirectGCPStorage) Qualify(name string) string { return fmt.Sprintf("%s@%s", rs.objectName(name), rs.bucketName()) @@ -294,11 +309,10 @@ func (rs *DirectGCPStorage) Qualify(name string) string { // UploadInstance takes all files from a local location and uploads it to the per-instance remote storage func (rs *DirectGCPStorage) UploadInstance(ctx context.Context, source string, name string, opts ...UploadOption) (bucket, object string, err error) { - objName, err := InstanceObjectName(rs.InstanceID, name) - if err != nil { - return "", "", err + if rs.InstanceID == "" { + return "", "", fmt.Errorf("instanceID is required to comput object name") } - return rs.Upload(ctx, source, objName, opts...) + return rs.Upload(ctx, source, InstanceObjectName(rs.InstanceID, name), opts...) } // Upload takes all files from a local location and uploads it to the remote storage @@ -999,3 +1013,8 @@ func (p *PresignedGCPStorage) ObjectHash(ctx context.Context, bucket string, obj func (p *PresignedGCPStorage) BackupObject(workspaceID string, name string) string { return fmt.Sprintf("workspaces/%s", gcpWorkspaceBackupObjectName(workspaceID, name)) } + +// InstanceObject returns a instance's object name that a direct downloader would download +func (p *PresignedGCPStorage) InstanceObject(workspaceID string, instanceID string, name string) string { + return p.BackupObject(workspaceID, InstanceObjectName(instanceID, name)) +} diff --git a/components/content-service/pkg/storage/minio.go b/components/content-service/pkg/storage/minio.go index 2615f4db1a64f2..dfe6a19f3c4b1d 100644 --- a/components/content-service/pkg/storage/minio.go +++ b/components/content-service/pkg/storage/minio.go @@ -212,6 +212,24 @@ func (rs *DirectMinIOStorage) DownloadSnapshot(ctx context.Context, destination return rs.download(ctx, destination, bkt, obj, mappings) } +// ListObjects returns all objects found with the given prefix +func (rs *DirectMinIOStorage) ListObjects(ctx context.Context, prefix string) (objects []string, err error) { + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + + objectCh := rs.client.ListObjects(ctx, rs.bucketName(), minio.ListObjectsOptions{ + Prefix: prefix, + Recursive: true, + }) + for object := range objectCh { + if object.Err != nil { + return nil, object.Err + } + objects = append(objects, object.Key) + } + return objects, nil +} + // Qualify fully qualifies a snapshot name so that it can be downloaded using DownloadSnapshot func (rs *DirectMinIOStorage) Qualify(name string) string { return fmt.Sprintf("%s@%s", rs.objectName(name), rs.bucketName()) @@ -219,11 +237,10 @@ func (rs *DirectMinIOStorage) Qualify(name string) string { // UploadInstance takes all files from a local location and uploads it to the per-instance remote storage func (rs *DirectMinIOStorage) UploadInstance(ctx context.Context, source string, name string, opts ...UploadOption) (bucket, object string, err error) { - objName, err := InstanceObjectName(rs.InstanceID, name) - if err != nil { - return "", "", err + if rs.InstanceID == "" { + return "", "", fmt.Errorf("instanceID is required to comput object name") } - return rs.Upload(ctx, source, objName, opts...) + return rs.Upload(ctx, source, InstanceObjectName(rs.InstanceID, name), opts...) } // Upload takes all files from a local location and uploads it to the remote storage @@ -463,6 +480,11 @@ func (s *presignedMinIOStorage) BackupObject(workspaceID string, name string) st return minioWorkspaceBackupObjectName(workspaceID, name) } +// InstanceObject returns a instance's object name that a direct downloader would download +func (s *presignedMinIOStorage) InstanceObject(workspaceID string, instanceID string, name string) string { + return s.BackupObject(workspaceID, InstanceObjectName(instanceID, name)) +} + func translateMinioError(err error) error { if err == nil { return nil diff --git a/components/content-service/pkg/storage/noop.go b/components/content-service/pkg/storage/noop.go index 4d5b2e01bd81cc..8136b636cc27fc 100644 --- a/components/content-service/pkg/storage/noop.go +++ b/components/content-service/pkg/storage/noop.go @@ -35,6 +35,11 @@ func (rs *DirectNoopStorage) DownloadSnapshot(ctx context.Context, destination s return false, nil } +// ListObjects returns all objects found with the given prefix +func (rs *DirectNoopStorage) ListObjects(ctx context.Context, prefix string) (objects []string, err error) { + return nil, nil +} + // Qualify just returns the name func (rs *DirectNoopStorage) Qualify(name string) string { return name @@ -115,3 +120,8 @@ func (*PresignedNoopStorage) ObjectHash(ctx context.Context, bucket string, obj func (*PresignedNoopStorage) BackupObject(workspaceID string, name string) string { return "" } + +// InstanceObject returns a instance's object name that a direct downloader would download +func (*PresignedNoopStorage) InstanceObject(workspaceID string, instanceID string, name string) string { + return "" +} diff --git a/components/content-service/pkg/storage/storage.go b/components/content-service/pkg/storage/storage.go index 736ece18fbcd0b..72e513b01908ce 100644 --- a/components/content-service/pkg/storage/storage.go +++ b/components/content-service/pkg/storage/storage.go @@ -45,6 +45,12 @@ type BackupObjectNamer interface { BackupObject(name string) string } +// InstanceObjectNamer provides names for objects per workspace instance +type InstanceObjectNamer interface { + // InstanceObject returns a instance's object name that a direct downloader would download + InstanceObject(name string) string +} + // BlobObjectNamer provides names for blob objects type BlobObjectNamer interface { // BlobObject returns a blob's object name @@ -79,6 +85,9 @@ type PresignedAccess interface { // BackupObject returns a backup's object name that a direct downloader would download BackupObject(workspaceID string, name string) string + + // InstanceObject returns a instance's object name that a direct downloader would download + InstanceObject(workspaceID string, instanceID string, name string) string } // ObjectMeta describtes the metadata of a remote object @@ -136,6 +145,9 @@ type DirectAccess interface { // EnsureExists makes sure that the remote storage location exists and can be up- or downloaded from EnsureExists(ctx context.Context) error + // ListObjects returns all objects found with the given prefix + ListObjects(ctx context.Context, prefix string) ([]string, error) + // Fully qualifies a snapshot name so that it can be downloaded using DownloadSnapshot Qualify(name string) string @@ -352,9 +364,6 @@ func blobObjectName(name string) (string, error) { return fmt.Sprintf("blobs/%s", name), nil } -func InstanceObjectName(instanceID, name string) (string, error) { - if instanceID == "" { - return "", fmt.Errorf("instanceID is required to comput object name") - } - return "instances/" + instanceID + "/" + name, nil +func InstanceObjectName(instanceID, name string) string { + return fmt.Sprintf("instances/%s/%s", instanceID, name) } diff --git a/components/gitpod-protocol/src/wsready.ts b/components/gitpod-protocol/src/wsready.ts index b235301e828cdc..d950c7d25c92a4 100644 --- a/components/gitpod-protocol/src/wsready.ts +++ b/components/gitpod-protocol/src/wsready.ts @@ -4,7 +4,7 @@ * See License-AGPL.txt in the project root for license information. */ -// generated using github.com/32leaves/bel on 2021-06-11 12:57:53.834879928 +0000 UTC m=+0.008335102 +// generated using github.com/32leaves/bel on 2021-06-30 15:17:12.411118468 +0000 UTC m=+0.009646252 // DO NOT MODIFY export enum WorkspaceInitSource { diff --git a/components/supervisor/go.sum b/components/supervisor/go.sum index fd4db84352ddca..72266344a2db19 100644 --- a/components/supervisor/go.sum +++ b/components/supervisor/go.sum @@ -554,6 +554,7 @@ github.com/minio/md5-simd v1.1.1 h1:9ojcLbuZ4gXbB2sX53MKn8JUZ0sB/2wfwsEcRw+I08U= github.com/minio/md5-simd v1.1.1/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= github.com/minio/minio-go/v7 v7.0.10 h1:1oUKe4EOPUEhw2qnPQaPsJ0lmVTYLFu03SiItauXs94= github.com/minio/minio-go/v7 v7.0.10/go.mod h1:td4gW1ldOsj1PbSNS+WYK43j+P1XVhX/8W8awaYlBFo= +github.com/minio/minio-go/v7 v7.0.11/go.mod h1:WoyW+ySKAKjY98B9+7ZbI8z8S3jaxaisdcvj9TGlazA= github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= diff --git a/components/ws-daemon/pkg/content/initializer.go b/components/ws-daemon/pkg/content/initializer.go index ee5ca6ae693da6..b449bfcc89c737 100644 --- a/components/ws-daemon/pkg/content/initializer.go +++ b/components/ws-daemon/pkg/content/initializer.go @@ -372,6 +372,11 @@ func (rs *remoteContentStorage) BackupObject(name string) string { return "" } +// InstanceObject returns a instance's object name that a direct downloader would download +func (rs *remoteContentStorage) InstanceObject(workspaceID string, instanceID string, name string) string { + return "" +} + // SnapshotObject returns a snapshot's object name that a direct downloer would download func (rs *remoteContentStorage) SnapshotObject(name string) string { return "" diff --git a/components/ws-daemon/pkg/content/service.go b/components/ws-daemon/pkg/content/service.go index 6af485978e7b85..ab43e12c34a261 100644 --- a/components/ws-daemon/pkg/content/service.go +++ b/components/ws-daemon/pkg/content/service.go @@ -359,7 +359,6 @@ func (s *WorkspaceService) DisposeWorkspace(ctx context.Context, req *api.Dispos if err != nil { log.WithError(err).WithFields(sess.OWI()).Error("log backup failed") // atm we do not fail the workspace here, yet, because we still might succeed with its content! - return nil, status.Error(codes.DataLoss, "log backup failed") } if req.Backup { @@ -613,14 +612,15 @@ func (s *WorkspaceService) uploadWorkspaceLogs(ctx context.Context, sess *sessio return err } for _, absLogPath := range logFiles { - streamID, parseErr := logs.ParseStreamID(absLogPath) + taskID, parseErr := logs.ParseTaskID(absLogPath) if parseErr != nil { log.WithError(parseErr).Warn("cannot parse workspace log file name") continue } err = retryIfErr(ctx, s.config.Backup.Attempts, log.WithFields(sess.OWI()).WithField("op", "upload log"), func(ctx context.Context) (err error) { - _, _, err = rs.UploadInstance(ctx, absLogPath, streamID) + // TODO(gpl) We name the log file by taskID bc that's the only thing we have readily available. It would be more consistent to use terminalID instead, which we don't have at our disposal here. + _, _, err = rs.UploadInstance(ctx, absLogPath, logs.UploadedWorkspaceLogPath(taskID)) if err != nil { return } diff --git a/test/go.sum b/test/go.sum index 2bff970e66e5c3..255923bafd4fa3 100644 --- a/test/go.sum +++ b/test/go.sum @@ -515,6 +515,7 @@ github.com/minio/md5-simd v1.1.1 h1:9ojcLbuZ4gXbB2sX53MKn8JUZ0sB/2wfwsEcRw+I08U= github.com/minio/md5-simd v1.1.1/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= github.com/minio/minio-go/v7 v7.0.10 h1:1oUKe4EOPUEhw2qnPQaPsJ0lmVTYLFu03SiItauXs94= github.com/minio/minio-go/v7 v7.0.10/go.mod h1:td4gW1ldOsj1PbSNS+WYK43j+P1XVhX/8W8awaYlBFo= +github.com/minio/minio-go/v7 v7.0.11/go.mod h1:WoyW+ySKAKjY98B9+7ZbI8z8S3jaxaisdcvj9TGlazA= github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=