1 package libcontainer
2
3 import (
4 "errors"
5 "os"
6 "path/filepath"
7 "reflect"
8 "testing"
9
10 "github.com/moby/sys/mountinfo"
11 "github.com/opencontainers/runc/libcontainer/configs"
12 "github.com/opencontainers/runc/libcontainer/utils"
13 "github.com/opencontainers/runtime-spec/specs-go"
14
15 "golang.org/x/sys/unix"
16 )
17
18 func TestFactoryNew(t *testing.T) {
19 root := t.TempDir()
20 factory, err := New(root)
21 if err != nil {
22 t.Fatal(err)
23 }
24 if factory == nil {
25 t.Fatal("factory should not be nil")
26 }
27 lfactory, ok := factory.(*LinuxFactory)
28 if !ok {
29 t.Fatal("expected linux factory returned on linux based systems")
30 }
31 if lfactory.Root != root {
32 t.Fatalf("expected factory root to be %q but received %q", root, lfactory.Root)
33 }
34
35 if factory.Type() != "libcontainer" {
36 t.Fatalf("unexpected factory type: %q, expected %q", factory.Type(), "libcontainer")
37 }
38 }
39
40 func TestFactoryNewTmpfs(t *testing.T) {
41 root := t.TempDir()
42 factory, err := New(root, TmpfsRoot)
43 if err != nil {
44 t.Fatal(err)
45 }
46 if factory == nil {
47 t.Fatal("factory should not be nil")
48 }
49 lfactory, ok := factory.(*LinuxFactory)
50 if !ok {
51 t.Fatal("expected linux factory returned on linux based systems")
52 }
53 if lfactory.Root != root {
54 t.Fatalf("expected factory root to be %q but received %q", root, lfactory.Root)
55 }
56
57 if factory.Type() != "libcontainer" {
58 t.Fatalf("unexpected factory type: %q, expected %q", factory.Type(), "libcontainer")
59 }
60 mounted, err := mountinfo.Mounted(lfactory.Root)
61 if err != nil {
62 t.Fatal(err)
63 }
64 if !mounted {
65 t.Fatalf("Factory Root is not mounted")
66 }
67 mounts, err := mountinfo.GetMounts(mountinfo.SingleEntryFilter(lfactory.Root))
68 if err != nil {
69 t.Fatal(err)
70 }
71 if len(mounts) != 1 {
72 t.Fatalf("Factory Root is not listed in mounts list")
73 }
74 m := mounts[0]
75 if m.FSType != "tmpfs" {
76 t.Fatalf("FSType of root: %s, expected %s", m.FSType, "tmpfs")
77 }
78 if m.Source != "tmpfs" {
79 t.Fatalf("Source of root: %s, expected %s", m.Source, "tmpfs")
80 }
81 err = unix.Unmount(root, unix.MNT_DETACH)
82 if err != nil {
83 t.Error("failed to unmount root:", err)
84 }
85 }
86
87 func TestFactoryLoadNotExists(t *testing.T) {
88 factory, err := New(t.TempDir())
89 if err != nil {
90 t.Fatal(err)
91 }
92 _, err = factory.Load("nocontainer")
93 if err == nil {
94 t.Fatal("expected nil error loading non-existing container")
95 }
96 if !errors.Is(err, ErrNotExist) {
97 t.Fatalf("expected ErrNotExist, got %v", err)
98 }
99 }
100
101 func TestFactoryLoadContainer(t *testing.T) {
102 root := t.TempDir()
103
104 var (
105 id = "1"
106 expectedHooks = configs.Hooks{
107 configs.Prestart: configs.HookList{
108 configs.CommandHook{Command: configs.Command{Path: "prestart-hook"}},
109 },
110 configs.Poststart: configs.HookList{
111 configs.CommandHook{Command: configs.Command{Path: "poststart-hook"}},
112 },
113 configs.Poststop: configs.HookList{
114 unserializableHook{},
115 configs.CommandHook{Command: configs.Command{Path: "poststop-hook"}},
116 },
117 }
118 expectedConfig = &configs.Config{
119 Rootfs: "/mycontainer/root",
120 Hooks: expectedHooks,
121 Cgroups: &configs.Cgroup{
122 Resources: &configs.Resources{},
123 },
124 }
125 expectedState = &State{
126 BaseState: BaseState{
127 InitProcessPid: 1024,
128 Config: *expectedConfig,
129 },
130 }
131 )
132 if err := os.Mkdir(filepath.Join(root, id), 0o700); err != nil {
133 t.Fatal(err)
134 }
135 if err := marshal(filepath.Join(root, id, stateFilename), expectedState); err != nil {
136 t.Fatal(err)
137 }
138 factory, err := New(root)
139 if err != nil {
140 t.Fatal(err)
141 }
142 container, err := factory.Load(id)
143 if err != nil {
144 t.Fatal(err)
145 }
146 if container.ID() != id {
147 t.Fatalf("expected container id %q but received %q", id, container.ID())
148 }
149 config := container.Config()
150 if config.Rootfs != expectedConfig.Rootfs {
151 t.Fatalf("expected rootfs %q but received %q", expectedConfig.Rootfs, config.Rootfs)
152 }
153 expectedHooks[configs.Poststop] = expectedHooks[configs.Poststop][1:]
154 if !reflect.DeepEqual(config.Hooks, expectedHooks) {
155 t.Fatalf("expects hooks %q but received %q", expectedHooks, config.Hooks)
156 }
157 lcontainer, ok := container.(*linuxContainer)
158 if !ok {
159 t.Fatal("expected linux container on linux based systems")
160 }
161 if lcontainer.initProcess.pid() != expectedState.InitProcessPid {
162 t.Fatalf("expected init pid %d but received %d", expectedState.InitProcessPid, lcontainer.initProcess.pid())
163 }
164 }
165
166 func marshal(path string, v interface{}) error {
167 f, err := os.Create(path)
168 if err != nil {
169 return err
170 }
171 defer f.Close()
172 return utils.WriteJSON(f, v)
173 }
174
175 type unserializableHook struct{}
176
177 func (unserializableHook) Run(*specs.State) error {
178 return nil
179 }
180
View as plain text