Skip to content

Commit 18dc437

Browse files
authored
Merge pull request #631 from kzys/volume-runc
Make volume package usable from non-Firecracker runtimes
2 parents 2782bd5 + 82603a1 commit 18dc437

File tree

3 files changed

+80
-21
lines changed

3 files changed

+80
-21
lines changed

runtime/volume_integ_test.go

+34-14
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"os"
2121
"path/filepath"
2222
"strconv"
23+
"strings"
2324
"testing"
2425

2526
"github.com/containerd/containerd"
@@ -39,11 +40,22 @@ const mib = 1024 * 1024
3940
func TestVolumes_Isolated(t *testing.T) {
4041
integtest.Prepare(t)
4142

43+
runtimes := []string{firecrackerRuntime, "io.containerd.runc.v2"}
44+
45+
for _, rt := range runtimes {
46+
t.Run(rt, func(t *testing.T) {
47+
testVolumes(t, rt)
48+
})
49+
}
50+
}
51+
52+
func testVolumes(t *testing.T, runtime string) {
4253
const vmID = 0
54+
testName := strings.ReplaceAll(t.Name(), "/", "_")
4355

4456
ctx := namespaces.WithNamespace(context.Background(), "default")
4557

46-
client, err := containerd.New(containerdSockPath, containerd.WithDefaultRuntime(firecrackerRuntime))
58+
client, err := containerd.New(containerdSockPath, containerd.WithDefaultRuntime(runtime))
4759
require.NoError(t, err, "unable to create client to containerd service at %s, is containerd running?", containerdSockPath)
4860
defer client.Close()
4961

@@ -54,7 +66,7 @@ func TestVolumes_Isolated(t *testing.T) {
5466
require.NoError(t, err, "failed to create fccontrol client")
5567

5668
// Make volumes.
57-
path, err := os.MkdirTemp("", t.Name())
69+
path, err := os.MkdirTemp("", testName)
5870
require.NoError(t, err)
5971

6072
f, err := os.Create(filepath.Join(path, "hello.txt"))
@@ -64,22 +76,27 @@ func TestVolumes_Isolated(t *testing.T) {
6476
require.NoError(t, err)
6577

6678
const volName = "volume1"
67-
vs := volume.NewSet()
79+
vs := volume.NewSet(runtime)
6880
vs.Add(volume.FromHost(volName, path))
6981

70-
// Since CreateVM doesn't take functional options, we need to explicitly create
71-
// a FirecrackerDriveMount
72-
mount, err := vs.PrepareDriveMount(ctx, 10*mib)
73-
require.NoError(t, err)
74-
7582
containers := []string{"c1", "c2"}
7683

77-
_, err = fcClient.CreateVM(ctx, &proto.CreateVMRequest{
78-
VMID: strconv.Itoa(vmID),
79-
ContainerCount: int32(len(containers)),
80-
DriveMounts: []*proto.FirecrackerDriveMount{mount},
81-
})
82-
require.NoError(t, err, "failed to create VM")
84+
if runtime == firecrackerRuntime {
85+
// Since CreateVM doesn't take functional options, we need to explicitly create
86+
// a FirecrackerDriveMount
87+
mount, err := vs.PrepareDriveMount(ctx, 10*mib)
88+
require.NoError(t, err)
89+
90+
_, err = fcClient.CreateVM(ctx, &proto.CreateVMRequest{
91+
VMID: strconv.Itoa(vmID),
92+
ContainerCount: int32(len(containers)),
93+
DriveMounts: []*proto.FirecrackerDriveMount{mount},
94+
})
95+
require.NoError(t, err, "failed to create VM")
96+
} else {
97+
err := vs.PrepareDirectory(ctx)
98+
require.NoError(t, err)
99+
}
83100

84101
// Make containers with the volume.
85102
dir := "/path/in/container"
@@ -103,6 +120,8 @@ func TestVolumes_Isolated(t *testing.T) {
103120
)
104121
require.NoError(t, err, "failed to create container %s", name)
105122

123+
defer container.Delete(ctx, containerd.WithSnapshotCleanup)
124+
106125
var stdout, stderr bytes.Buffer
107126

108127
task, err := container.NewTask(ctx, cio.NewCreator(cio.WithStreams(nil, &stdout, &stderr)))
@@ -135,6 +154,7 @@ func TestVolumes_Isolated(t *testing.T) {
135154
),
136155
)
137156
require.NoError(t, err, "failed to create container %s", name)
157+
defer container.Delete(ctx, containerd.WithSnapshotCleanup)
138158

139159
var stdout, stderr bytes.Buffer
140160
task, err := container.NewTask(ctx, cio.NewCreator(cio.WithStreams(nil, &stdout, &stderr)))

tools/docker/Dockerfile.integ-test

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ RUN mkdir -p \
2828
${FICD_LOG_DIR} \
2929
/etc/cni/net.d
3030

31+
RUN wget https://github.com/containerd/containerd/releases/download/v1.6.4/containerd-1.6.4-linux-amd64.tar.gz && \
32+
tar zxvf containerd-1.6.4-linux-amd64.tar.gz -C /tmp/ && \
33+
install -D -o root -g root -m755 -t /usr/local/bin /tmp/bin/containerd-shim-runc-v2 && \
34+
rm -rf containerd-1.6.4-linux-amd64.tar.gz /tmp/bin
3135

3236
# Pull the images the tests need into the content store so we don't need internet
3337
# access during the tests themselves. This runs as a seperate step before the other

volume/set.go

+42-7
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,20 @@ const (
3636

3737
// Set is a set of volumes.
3838
type Set struct {
39-
volumes map[string]*Volume
40-
tempDir string
39+
volumes map[string]*Volume
40+
tempDir string
41+
runtime string
42+
volumeDir string
4143
}
4244

4345
// NewSet returns a new volume set.
44-
func NewSet() *Set {
45-
return NewSetWithTempDir(os.TempDir())
46+
func NewSet(runtime string) *Set {
47+
return NewSetWithTempDir(runtime, os.TempDir())
4648
}
4749

4850
// NewSetWithTempDir returns a new volume set and creates all temporary files under the tempDir.
49-
func NewSetWithTempDir(tempDir string) *Set {
50-
return &Set{volumes: make(map[string]*Volume), tempDir: tempDir}
51+
func NewSetWithTempDir(runtime, tempDir string) *Set {
52+
return &Set{runtime: runtime, volumes: make(map[string]*Volume), tempDir: tempDir}
5153
}
5254

5355
// Add a volume to the set.
@@ -96,6 +98,38 @@ func mountDiskImage(source, target string) error {
9698
return mount.All([]mount.Mount{{Type: fsType, Source: source, Options: []string{"loop"}}}, target)
9799
}
98100

101+
// PrepareDirectory creates a directory that have volumes.
102+
func (vs *Set) PrepareDirectory(ctx context.Context) (retErr error) {
103+
dir, err := os.MkdirTemp(vs.tempDir, "Prepare")
104+
if err != nil {
105+
retErr = err
106+
return
107+
}
108+
defer func() {
109+
if retErr != nil {
110+
err := os.Remove(dir)
111+
if err != nil {
112+
retErr = multierror.Append(retErr, err)
113+
}
114+
}
115+
}()
116+
117+
for _, v := range vs.volumes {
118+
path := filepath.Join(dir, v.name)
119+
if v.hostPath == "" {
120+
continue
121+
}
122+
err := fs.CopyDir(path, v.hostPath)
123+
if err != nil {
124+
retErr = fmt.Errorf("failed to copy volume %q: %w", v.name, err)
125+
return
126+
}
127+
}
128+
129+
vs.volumeDir = dir
130+
return
131+
}
132+
99133
// PrepareDriveMount returns a FirecrackerDriveMount that could be used with CreateVM.
100134
func (vs *Set) PrepareDriveMount(ctx context.Context, size int64) (dm *proto.FirecrackerDriveMount, retErr error) {
101135
path, err := vs.createDiskImage(ctx, size)
@@ -155,6 +189,7 @@ func (vs *Set) PrepareDriveMount(ctx context.Context, size int64) (dm *proto.Fir
155189
FilesystemType: fsType,
156190
IsWritable: true,
157191
}
192+
vs.volumeDir = vmVolumePath
158193
return
159194
}
160195

@@ -186,7 +221,7 @@ func (vs *Set) WithMounts(mountpoints []Mount) (oci.SpecOpts, error) {
186221
mounts = append(mounts, specs.Mount{
187222
// TODO: for volumes that are provided by the guest (e.g. in-VM snapshotters)
188223
// We may be able to have bind-mounts from in-VM snapshotters' mount points.
189-
Source: filepath.Join(vmVolumePath, v.name),
224+
Source: filepath.Join(vs.volumeDir, v.name),
190225
Destination: mp.Destination,
191226
Type: "bind",
192227
Options: options,

0 commit comments

Comments
 (0)