Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/content-service/pkg/service/workspace-service.go
2499 views
1
// Copyright (c) 2021 Gitpod GmbH. All rights reserved.
2
// Licensed under the GNU Affero General Public License (AGPL).
3
// See License.AGPL.txt in the project root for license information.
4
5
package service
6
7
import (
8
"context"
9
"errors"
10
"strings"
11
12
"github.com/opentracing/opentracing-go"
13
"google.golang.org/grpc/codes"
14
"google.golang.org/grpc/status"
15
16
"github.com/gitpod-io/gitpod/common-go/log"
17
"github.com/gitpod-io/gitpod/common-go/tracing"
18
"github.com/gitpod-io/gitpod/content-service/api"
19
"github.com/gitpod-io/gitpod/content-service/api/config"
20
"github.com/gitpod-io/gitpod/content-service/pkg/storage"
21
)
22
23
// WorkspaceService implements WorkspaceServiceServer
24
type WorkspaceService struct {
25
cfg config.StorageConfig
26
s storage.PresignedAccess
27
28
api.UnimplementedWorkspaceServiceServer
29
}
30
31
// NewWorkspaceService create a new content service
32
func NewWorkspaceService(cfg config.StorageConfig) (res *WorkspaceService, err error) {
33
s, err := storage.NewPresignedAccess(&cfg)
34
if err != nil {
35
return nil, err
36
}
37
return &WorkspaceService{cfg: cfg, s: s}, nil
38
}
39
40
// WorkspaceDownloadURL provides a URL from where the content of a workspace can be downloaded from
41
func (cs *WorkspaceService) WorkspaceDownloadURL(ctx context.Context, req *api.WorkspaceDownloadURLRequest) (resp *api.WorkspaceDownloadURLResponse, err error) {
42
span, ctx := opentracing.StartSpanFromContext(ctx, "WorkspaceDownloadURL")
43
span.SetTag("user", req.OwnerId)
44
span.SetTag("workspaceId", req.WorkspaceId)
45
defer tracing.FinishSpan(span, &err)
46
47
blobName := cs.s.BackupObject(req.OwnerId, req.WorkspaceId, storage.DefaultBackup)
48
49
info, err := cs.s.SignDownload(ctx, cs.s.Bucket(req.OwnerId), blobName, &storage.SignedURLOptions{})
50
if err != nil {
51
log.WithFields(log.OWI(req.OwnerId, req.WorkspaceId, "")).
52
WithField("bucket", cs.s.Bucket(req.OwnerId)).
53
WithField("blobName", blobName).
54
WithError(err).
55
Error("error getting SignDownload URL")
56
if errors.Is(err, storage.ErrNotFound) {
57
return nil, status.Error(codes.NotFound, err.Error())
58
}
59
return nil, status.Error(codes.Unknown, err.Error())
60
}
61
62
return &api.WorkspaceDownloadURLResponse{
63
Url: info.URL,
64
}, nil
65
}
66
67
// DeleteWorkspace deletes the content of a single workspace
68
func (cs *WorkspaceService) DeleteWorkspace(ctx context.Context, req *api.DeleteWorkspaceRequest) (resp *api.DeleteWorkspaceResponse, err error) {
69
span, ctx := opentracing.StartSpanFromContext(ctx, "DeleteWorkspace")
70
span.SetTag("user", req.OwnerId)
71
span.SetTag("workspaceId", req.WorkspaceId)
72
span.SetTag("includeSnapshots", req.IncludeSnapshots)
73
defer tracing.FinishSpan(span, &err)
74
75
if req.IncludeSnapshots {
76
prefix := cs.s.BackupObject(req.OwnerId, req.WorkspaceId, "")
77
if !strings.HasSuffix(prefix, "/") {
78
prefix = prefix + "/"
79
}
80
err = cs.s.DeleteObject(ctx, cs.s.Bucket(req.OwnerId), &storage.DeleteObjectQuery{Prefix: prefix})
81
if err != nil {
82
if errors.Is(err, storage.ErrNotFound) {
83
log.WithError(err).Debug("deleting workspace backup: NotFound")
84
return &api.DeleteWorkspaceResponse{}, nil
85
}
86
log.WithError(err).Error("error deleting workspace backup")
87
return nil, status.Error(codes.Unknown, err.Error())
88
}
89
return &api.DeleteWorkspaceResponse{}, nil
90
}
91
92
blobName := cs.s.BackupObject(req.OwnerId, req.WorkspaceId, storage.DefaultBackup)
93
err = cs.s.DeleteObject(ctx, cs.s.Bucket(req.OwnerId), &storage.DeleteObjectQuery{Name: blobName})
94
if err != nil {
95
if errors.Is(err, storage.ErrNotFound) {
96
log.WithError(err).Debug("deleting workspace backup: NotFound, ", blobName)
97
return &api.DeleteWorkspaceResponse{}, nil
98
}
99
log.WithError(err).Error("error deleting workspace backup: ", blobName)
100
return nil, status.Error(codes.Unknown, err.Error())
101
}
102
103
trailPrefix := cs.s.BackupObject(req.OwnerId, req.WorkspaceId, "trail-")
104
err = cs.s.DeleteObject(ctx, cs.s.Bucket(req.OwnerId), &storage.DeleteObjectQuery{Prefix: trailPrefix})
105
if err != nil {
106
if errors.Is(err, storage.ErrNotFound) {
107
log.WithError(err).Debug("deleting workspace backup: NotFound, ", trailPrefix)
108
return &api.DeleteWorkspaceResponse{}, nil
109
}
110
log.WithError(err).Error("error deleting workspace backup: ", trailPrefix)
111
return nil, status.Error(codes.Unknown, err.Error())
112
}
113
114
return &api.DeleteWorkspaceResponse{}, nil
115
}
116
117
func (cs *WorkspaceService) WorkspaceSnapshotExists(ctx context.Context, req *api.WorkspaceSnapshotExistsRequest) (resp *api.WorkspaceSnapshotExistsResponse, err error) {
118
span, ctx := opentracing.StartSpanFromContext(ctx, "WorkspaceObjectExists")
119
span.SetTag("user", req.OwnerId)
120
span.SetTag("workspaceId", req.WorkspaceId)
121
span.SetTag("filename", req.Filename)
122
defer tracing.FinishSpan(span, &err)
123
124
exists, err := cs.s.ObjectExists(ctx, cs.s.Bucket(req.OwnerId), cs.s.BackupObject(req.OwnerId, req.WorkspaceId, req.Filename))
125
if err != nil {
126
return nil, status.Error(codes.Unknown, err.Error())
127
}
128
return &api.WorkspaceSnapshotExistsResponse{
129
Exists: exists,
130
}, nil
131
}
132
133