Skip to content

Commit 4d3947d

Browse files
author
Christian Weichel
committed
[content-service] Remove docker dependency
by moving archive creation back to ws-daemon
1 parent 3328fc6 commit 4d3947d

File tree

9 files changed

+285
-288
lines changed

9 files changed

+285
-288
lines changed

components/content-service/go.mod

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,8 @@ module github.com/gitpod-io/gitpod/content-service
22

33
go 1.14
44

5-
// containerd, see https://github.com/containerd/containerd/issues/3031
6-
replace github.com/docker/distribution v2.7.1+incompatible => github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible // leeway ignore
7-
8-
replace github.com/docker/docker v1.13.1 => github.com/docker/engine v0.0.0-20190822205725-ed20165a37b4 // leeway ignore
9-
10-
replace github.com/Sirupsen/logrus v1.6.0 => github.com/sirupsen/logrus v1.6.0 // leeway ignore
11-
125
require (
136
cloud.google.com/go/storage v1.10.0
14-
github.com/Microsoft/go-winio v0.4.16 // indirect
15-
github.com/Microsoft/hcsshim v0.8.14 // indirect
16-
github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7 // indirect
17-
github.com/docker/docker v1.13.1
18-
github.com/docker/go-units v0.4.0 // indirect
197
github.com/gitpod-io/gitpod/common-go v0.0.0-00010101000000-000000000000
208
github.com/gitpod-io/gitpod/content-service/api v0.0.0-00010101000000-000000000000
219
github.com/go-ozzo/ozzo-validation v3.5.0+incompatible
@@ -27,7 +15,6 @@ require (
2715
github.com/minio/minio-go/v7 v7.0.7
2816
github.com/opencontainers/go-digest v1.0.0
2917
github.com/opencontainers/image-spec v1.0.1
30-
github.com/opencontainers/runc v0.1.1 // indirect
3118
github.com/opentracing/opentracing-go v1.1.0
3219
github.com/prometheus/client_golang v1.1.0
3320
github.com/spf13/cobra v1.1.1
@@ -38,9 +25,7 @@ require (
3825
golang.org/x/text v0.3.5 // indirect
3926
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
4027
google.golang.org/api v0.32.0
41-
google.golang.org/appengine v1.6.6
4228
google.golang.org/grpc v1.34.0
43-
google.golang.org/protobuf v1.25.0
4429
gopkg.in/ini.v1 v1.62.0 // indirect
4530
)
4631

components/content-service/go.sum

Lines changed: 16 additions & 43 deletions
Large diffs are not rendered by default.

components/content-service/pkg/archive/tar.go

Lines changed: 12 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -6,36 +6,33 @@ package archive
66

77
import (
88
"archive/tar"
9-
"bufio"
109
"context"
11-
"fmt"
1210
"io"
1311
"os"
1412
"os/exec"
1513
"path"
1614
"sort"
1715
"time"
1816

19-
"github.com/docker/docker/pkg/archive"
20-
"github.com/docker/docker/pkg/idtools"
2117
"github.com/gitpod-io/gitpod/common-go/log"
2218
"github.com/gitpod-io/gitpod/common-go/tracing"
2319
"github.com/opentracing/opentracing-go"
2420
"golang.org/x/xerrors"
2521
)
2622

27-
type tarConfig struct {
23+
// TarConfig configures tarbal creation/extraction
24+
type TarConfig struct {
2825
MaxSizeBytes int64
29-
UIDMaps []idtools.IDMap
30-
GIDMaps []idtools.IDMap
26+
UIDMaps []IDMapping
27+
GIDMaps []IDMapping
3128
}
3229

3330
// BuildTarbalOption configures the tarbal creation
34-
type TarOption func(o *tarConfig)
31+
type TarOption func(o *TarConfig)
3532

3633
// TarbalMaxSize limits the size of a tarbal
3734
func TarbalMaxSize(n int64) TarOption {
38-
return func(o *tarConfig) {
35+
return func(o *TarConfig) {
3936
o.MaxSizeBytes = n
4037
}
4138
}
@@ -49,35 +46,21 @@ type IDMapping struct {
4946

5047
// WithUIDMapping reverses the given user ID mapping during archive creation
5148
func WithUIDMapping(mappings []IDMapping) TarOption {
52-
return func(o *tarConfig) {
53-
o.UIDMaps = make([]idtools.IDMap, len(mappings))
54-
for i, m := range mappings {
55-
o.UIDMaps[i] = idtools.IDMap{
56-
ContainerID: m.ContainerID,
57-
HostID: m.HostID,
58-
Size: m.Size,
59-
}
60-
}
49+
return func(o *TarConfig) {
50+
o.UIDMaps = mappings
6151
}
6252
}
6353

6454
// WithGIDMapping reverses the given user ID mapping during archive creation
6555
func WithGIDMapping(mappings []IDMapping) TarOption {
66-
return func(o *tarConfig) {
67-
o.GIDMaps = make([]idtools.IDMap, len(mappings))
68-
for i, m := range mappings {
69-
o.GIDMaps[i] = idtools.IDMap{
70-
ContainerID: m.ContainerID,
71-
HostID: m.HostID,
72-
Size: m.Size,
73-
}
74-
}
56+
return func(o *TarConfig) {
57+
o.GIDMaps = mappings
7558
}
7659
}
7760

7861
// ExtractTarbal extracts an OCI compatible tar file src to the folder dst, expecting the overlay whiteout format
7962
func ExtractTarbal(ctx context.Context, src io.Reader, dst string, opts ...TarOption) (err error) {
80-
var cfg tarConfig
63+
var cfg TarConfig
8164
start := time.Now()
8265
for _, opt := range opts {
8366
opt(&cfg)
@@ -145,7 +128,7 @@ func ExtractTarbal(ctx context.Context, src io.Reader, dst string, opts ...TarOp
145128
return nil
146129
}
147130

148-
func toHostID(containerID int, idMap []idtools.IDMap) int {
131+
func toHostID(containerID int, idMap []IDMapping) int {
149132
for _, m := range idMap {
150133
if (containerID >= m.ContainerID) && (containerID <= (m.ContainerID + m.Size - 1)) {
151134
hostID := m.HostID + (containerID - m.ContainerID)
@@ -154,98 +137,3 @@ func toHostID(containerID int, idMap []idtools.IDMap) int {
154137
}
155138
return containerID
156139
}
157-
158-
// BuildTarbal creates an OCI compatible tar file dst from the folder src, expecting the overlay whiteout format
159-
func BuildTarbal(ctx context.Context, src string, dst string, opts ...TarOption) (err error) {
160-
var cfg tarConfig
161-
for _, opt := range opts {
162-
opt(&cfg)
163-
}
164-
165-
//nolint:staticcheck,ineffassign
166-
span, ctx := opentracing.StartSpanFromContext(ctx, "buildTarbal")
167-
span.LogKV("src", src, "dst", dst)
168-
defer tracing.FinishSpan(span, &err)
169-
170-
// ensure the src actually exists before trying to tar it
171-
if _, err := os.Stat(src); err != nil {
172-
return fmt.Errorf("Unable to tar files: %v", err.Error())
173-
}
174-
175-
tarout, err := archive.TarWithOptions(src, &archive.TarOptions{
176-
Compression: archive.Uncompressed,
177-
WhiteoutFormat: archive.OverlayWhiteoutFormat,
178-
InUserNS: true,
179-
UIDMaps: cfg.UIDMaps,
180-
GIDMaps: cfg.GIDMaps,
181-
})
182-
if err != nil {
183-
return xerrors.Errorf("cannot create tar: %w", err)
184-
}
185-
186-
fout, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE, 0744)
187-
if err != nil {
188-
return xerrors.Errorf("cannot open archive for writing: %w", err)
189-
}
190-
defer fout.Close()
191-
fbout := bufio.NewWriter(fout)
192-
defer fbout.Flush()
193-
194-
targetOut := newLimitWriter(fbout, cfg.MaxSizeBytes)
195-
defer func(e *error) {
196-
if targetOut.DidMaxOut() {
197-
*e = ErrMaxSizeExceeded
198-
}
199-
}(&err)
200-
201-
_, err = io.Copy(targetOut, tarout)
202-
if err != nil {
203-
return xerrors.Errorf("cannot write tar file: %w")
204-
}
205-
if err = fbout.Flush(); err != nil {
206-
return xerrors.Errorf("cannot flush tar out stream: %w", err)
207-
}
208-
209-
return nil
210-
}
211-
212-
// ErrMaxSizeExceeded is emitted by LimitWriter when a write tries to write beyond the max number of bytes allowed
213-
var ErrMaxSizeExceeded = fmt.Errorf("maximum size exceeded")
214-
215-
// newLimitWriter wraps a writer such that a maximum of N bytes can be written. Once that limit is exceeded
216-
// the writer returns io.ErrClosedPipe
217-
func newLimitWriter(out io.Writer, maxSizeBytes int64) *limitWriter {
218-
return &limitWriter{
219-
MaxSizeBytes: maxSizeBytes,
220-
Out: out,
221-
}
222-
}
223-
224-
type limitWriter struct {
225-
MaxSizeBytes int64
226-
Out io.Writer
227-
BytesWritten int64
228-
229-
didMaxOut bool
230-
}
231-
232-
func (s *limitWriter) Write(b []byte) (n int, err error) {
233-
if s.MaxSizeBytes == 0 {
234-
return s.Out.Write(b)
235-
}
236-
237-
bsize := int64(len(b))
238-
if bsize+s.BytesWritten > s.MaxSizeBytes {
239-
s.didMaxOut = true
240-
return 0, ErrMaxSizeExceeded
241-
}
242-
243-
n, err = s.Out.Write(b)
244-
s.BytesWritten += int64(n)
245-
246-
return n, err
247-
}
248-
249-
func (s *limitWriter) DidMaxOut() bool {
250-
return s.didMaxOut
251-
}

components/content-service/pkg/archive/tar_test.go

Lines changed: 24 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
package archive
66

77
import (
8+
"archive/tar"
9+
"bytes"
810
"context"
911
"io/ioutil"
1012
"os"
@@ -13,91 +15,8 @@ import (
1315
"testing"
1416
)
1517

16-
func TestSizeLimitingWriter(t *testing.T) {
17-
tests := []struct {
18-
MaxSize int64
19-
BlockSize int64
20-
BlockCount int
21-
ExpectWritten int
22-
Err error
23-
}{
24-
{30, 10, 1, 10, nil},
25-
{30, 10, 3, 30, nil},
26-
{20, 10, 3, 20, ErrMaxSizeExceeded},
27-
}
28-
29-
for _, test := range tests {
30-
var (
31-
written int
32-
n int
33-
err error
34-
)
35-
w := newLimitWriter(ioutil.Discard, test.MaxSize)
36-
37-
for i := 0; i < test.BlockCount; i++ {
38-
n, err = w.Write(make([]byte, test.BlockSize))
39-
written += n
40-
if err != nil {
41-
break
42-
}
43-
}
44-
45-
if err != test.Err {
46-
t.Errorf("unexpected error: expected %v, actual %v", test.Err, err)
47-
}
48-
if written != test.ExpectWritten {
49-
t.Errorf("wrote unexpected number of bytes: expected %v, actual %v", test.ExpectWritten, written)
50-
}
51-
}
52-
}
53-
54-
func TestBuildTarbalMaxSize(t *testing.T) {
55-
tests := []struct {
56-
Name string
57-
MaxSize int64
58-
ContentSize int64
59-
Err error
60-
}{
61-
{"positive", 1024 * 1024, 512, nil},
62-
{"too-big", 512, 1024, ErrMaxSizeExceeded},
63-
}
64-
65-
var cleanup []string
66-
for _, test := range tests {
67-
wd, err := ioutil.TempDir("", "")
68-
if err != nil {
69-
t.Errorf("cannot prepare test: %v", err)
70-
continue
71-
}
72-
cleanup = append(cleanup, wd)
73-
74-
err = ioutil.WriteFile(filepath.Join(wd, "content.txt"), make([]byte, test.ContentSize), 0644)
75-
if err != nil {
76-
t.Errorf("cannot prepare test: %v", err)
77-
continue
78-
}
79-
80-
tgt, err := ioutil.TempFile("", "")
81-
if err != nil {
82-
t.Errorf("cannot prepare test: %v", err)
83-
continue
84-
}
85-
tgt.Close()
86-
cleanup = append(cleanup, tgt.Name())
87-
88-
err = BuildTarbal(context.Background(), wd, tgt.Name(), TarbalMaxSize(test.MaxSize))
89-
if (err == nil && test.Err != nil) || (err != nil && test.Err == nil) || (err != nil && test.Err != nil && err.Error() != test.Err.Error()) {
90-
t.Errorf("%s: unexpected error: expected \"%v\", actual \"%v\"", test.Name, test.Err, err)
91-
}
92-
}
93-
94-
for _, c := range cleanup {
95-
os.RemoveAll(c)
96-
}
97-
}
98-
9918
func TestExtractTarbal(t *testing.T) {
100-
type file = struct {
19+
type file struct {
10120
Name string
10221
ContentSize int64
10322
Uid int
@@ -121,37 +40,38 @@ func TestExtractTarbal(t *testing.T) {
12140

12241
for _, test := range tests {
12342
t.Run(test.Name, func(t *testing.T) {
124-
wd, err := ioutil.TempDir("", "")
125-
defer os.RemoveAll(wd)
126-
if err != nil {
127-
t.Errorf("cannot prepare test: %v", err)
128-
t.FailNow()
129-
}
130-
sourceFolder := filepath.Join(wd, "source")
131-
os.MkdirAll(sourceFolder, 0777)
132-
43+
var (
44+
buf = bytes.NewBuffer(nil)
45+
tw = tar.NewWriter(buf)
46+
)
13347
for _, file := range test.Files {
134-
fileName := filepath.Join(sourceFolder, file.Name)
135-
err = ioutil.WriteFile(fileName, make([]byte, file.ContentSize), 0644)
48+
err := tw.WriteHeader(&tar.Header{
49+
Name: file.Name,
50+
Size: file.ContentSize,
51+
Uid: file.Uid,
52+
Gid: file.Uid,
53+
Mode: 0644,
54+
Typeflag: tar.TypeReg,
55+
})
13656
if err != nil {
137-
t.Errorf("cannot prepare test: %v", err)
138-
continue
57+
t.Fatalf("cannot prepare archive: %q", err)
13958
}
140-
err = os.Chown(fileName, file.Uid, file.Uid)
59+
_, err = tw.Write(make([]byte, file.ContentSize))
14160
if err != nil {
142-
t.Errorf("Cannot chown %s to %d: %s", file.Name, file.Uid, err)
61+
t.Fatalf("cannot prepare archive: %q", err)
14362
}
14463
}
145-
tarFile := filepath.Join(wd, "my.tar")
146-
BuildTarbal(context.Background(), sourceFolder, tarFile)
64+
tw.Flush()
65+
tw.Close()
14766

148-
reader, err := os.Open(tarFile)
67+
wd, err := ioutil.TempDir("", "")
68+
defer os.RemoveAll(wd)
14969
if err != nil {
150-
t.Errorf("Cannot open %s", tarFile)
70+
t.Fatalf("cannot prepare test: %v", err)
15171
}
15272
targetFolder := filepath.Join(wd, "target")
15373
os.MkdirAll(targetFolder, 0777)
154-
ExtractTarbal(context.Background(), reader, targetFolder)
74+
ExtractTarbal(context.Background(), buf, targetFolder)
15575

15676
for _, file := range test.Files {
15777
stat, err := os.Stat(filepath.Join(targetFolder, file.Name))

components/ws-daemon/go.sum

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.
125125
github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
126126
github.com/containerd/containerd v1.4.1 h1:pASeJT3R3YyVn+94qEPk0SnU1OQ20Jd/T+SPKy9xehY=
127127
github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
128+
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc h1:TP+534wVlf61smEIq1nwLLAjQVEK2EADoW3CX9AuT+8=
128129
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
129130
github.com/containerd/continuity v0.0.0-20200928162600-f2cc35102c2a h1:jEIoR0aA5GogXZ8pP3DUzE+zrhaF6/1rYZy+7KkYEWM=
130131
github.com/containerd/continuity v0.0.0-20200928162600-f2cc35102c2a/go.mod h1:W0qIOTD7mp2He++YVq+kgfXezRYqzP1uDuMVH1bITDY=

0 commit comments

Comments
 (0)