Skip to content

Commit 856ea51

Browse files
Merge pull request containerd#2182 from AkihiroSuda/shimtest
linux: fix runtime-root propagation
2 parents 77a5804 + 125fdef commit 856ea51

File tree

5 files changed

+203
-19
lines changed

5 files changed

+203
-19
lines changed

client_test.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,11 @@ import (
3838
)
3939

4040
var (
41-
address string
42-
noDaemon bool
43-
noCriu bool
44-
supportsCriu bool
41+
address string
42+
noDaemon bool
43+
noCriu bool
44+
supportsCriu bool
45+
testNamespace = "testing"
4546

4647
ctrd = &daemon{}
4748
)
@@ -58,7 +59,7 @@ func init() {
5859

5960
func testContext() (context.Context, context.CancelFunc) {
6061
ctx, cancel := context.WithCancel(context.Background())
61-
ctx = namespaces.WithNamespace(ctx, "testing")
62+
ctx = namespaces.WithNamespace(ctx, testNamespace)
6263
return ctx, cancel
6364
}
6465

daemon_config_linux_test.go

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
/*
2+
Copyright The containerd Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package containerd
18+
19+
import (
20+
"bytes"
21+
"context"
22+
"fmt"
23+
"io/ioutil"
24+
"os"
25+
"os/exec"
26+
"path/filepath"
27+
"syscall"
28+
"testing"
29+
"time"
30+
31+
"github.com/containerd/containerd/oci"
32+
"github.com/containerd/containerd/server"
33+
"github.com/containerd/containerd/testutil"
34+
)
35+
36+
// the following nolint is for shutting up gometalinter on non-linux.
37+
// nolint: unused
38+
func newDaemonWithConfig(t *testing.T, configTOML string) (*Client, *daemon, func()) {
39+
if testing.Short() {
40+
t.Skip()
41+
}
42+
testutil.RequiresRoot(t)
43+
var (
44+
ctrd = daemon{}
45+
configTOMLDecoded server.Config
46+
buf = bytes.NewBuffer(nil)
47+
)
48+
49+
tempDir, err := ioutil.TempDir("", "containerd-test-new-daemon-with-config")
50+
if err != nil {
51+
t.Fatal(err)
52+
}
53+
defer func() {
54+
if err != nil {
55+
os.RemoveAll(tempDir)
56+
}
57+
}()
58+
59+
configTOMLFile := filepath.Join(tempDir, "config.toml")
60+
if err = ioutil.WriteFile(configTOMLFile, []byte(configTOML), 0600); err != nil {
61+
t.Fatal(err)
62+
}
63+
64+
if err = server.LoadConfig(configTOMLFile, &configTOMLDecoded); err != nil {
65+
t.Fatal(err)
66+
}
67+
68+
address := configTOMLDecoded.GRPC.Address
69+
if address == "" {
70+
address = filepath.Join(tempDir, "containerd.sock")
71+
}
72+
args := []string{"-c", configTOMLFile}
73+
if configTOMLDecoded.Root == "" {
74+
args = append(args, "--root", filepath.Join(tempDir, "root"))
75+
}
76+
if configTOMLDecoded.State == "" {
77+
args = append(args, "--state", filepath.Join(tempDir, "state"))
78+
}
79+
if err = ctrd.start("containerd", address, args, buf, buf); err != nil {
80+
t.Fatalf("%v: %s", err, buf.String())
81+
}
82+
83+
waitCtx, waitCancel := context.WithTimeout(context.TODO(), 2*time.Second)
84+
client, err := ctrd.waitForStart(waitCtx)
85+
waitCancel()
86+
if err != nil {
87+
ctrd.Kill()
88+
ctrd.Wait()
89+
t.Fatalf("%v: %s", err, buf.String())
90+
}
91+
92+
cleanup := func() {
93+
if err := client.Close(); err != nil {
94+
t.Fatalf("failed to close client: %v", err)
95+
}
96+
if err := ctrd.Stop(); err != nil {
97+
if err := ctrd.Kill(); err != nil {
98+
t.Fatalf("failed to signal containerd: %v", err)
99+
}
100+
}
101+
if err := ctrd.Wait(); err != nil {
102+
if _, ok := err.(*exec.ExitError); !ok {
103+
t.Fatalf("failed to wait for: %v", err)
104+
}
105+
}
106+
if err := os.RemoveAll(tempDir); err != nil {
107+
t.Fatalf("failed to remove %s: %v", tempDir, err)
108+
}
109+
// cleaning config-specific resources is up to the caller
110+
}
111+
return client, &ctrd, cleanup
112+
113+
}
114+
115+
func testDaemonRuntimeRoot(t *testing.T, noShim bool) {
116+
runtimeRoot, err := ioutil.TempDir("", "containerd-test-runtime-root")
117+
if err != nil {
118+
t.Fatal(err)
119+
}
120+
defer func() {
121+
if err != nil {
122+
os.RemoveAll(runtimeRoot)
123+
}
124+
}()
125+
configTOML := fmt.Sprintf(`
126+
[plugins]
127+
[plugins.linux]
128+
no_shim = %v
129+
runtime_root = "%s"
130+
`, noShim, runtimeRoot)
131+
132+
client, _, cleanup := newDaemonWithConfig(t, configTOML)
133+
defer cleanup()
134+
135+
ctx, cancel := testContext()
136+
defer cancel()
137+
// FIXME(AkihiroSuda): import locally frozen image?
138+
image, err := client.Pull(ctx, testImage, WithPullUnpack)
139+
if err != nil {
140+
t.Fatal(err)
141+
}
142+
143+
id := t.Name()
144+
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image), withProcessArgs("top")), WithNewSnapshot(id, image))
145+
if err != nil {
146+
t.Fatal(err)
147+
}
148+
defer container.Delete(ctx, WithSnapshotCleanup)
149+
150+
task, err := container.NewTask(ctx, empty())
151+
if err != nil {
152+
t.Fatal(err)
153+
}
154+
defer task.Delete(ctx)
155+
156+
if err = task.Start(ctx); err != nil {
157+
t.Fatal(err)
158+
}
159+
160+
stateJSONPath := filepath.Join(runtimeRoot, testNamespace, id, "state.json")
161+
if _, err = os.Stat(stateJSONPath); err != nil {
162+
t.Errorf("error while getting stat for %s: %v", stateJSONPath, err)
163+
}
164+
165+
finishedC, err := task.Wait(ctx)
166+
if err != nil {
167+
t.Fatal(err)
168+
}
169+
if err = task.Kill(ctx, syscall.SIGKILL); err != nil {
170+
t.Error(err)
171+
}
172+
<-finishedC
173+
}
174+
175+
// TestDaemonRuntimeRoot ensures plugin.linux.runtime_root is not ignored
176+
func TestDaemonRuntimeRoot(t *testing.T) {
177+
testDaemonRuntimeRoot(t, false)
178+
}
179+
180+
// TestDaemonRuntimeRootNoShim ensures plugin.linux.runtime_root is not ignored when no_shim is true
181+
func TestDaemonRuntimeRootNoShim(t *testing.T) {
182+
t.Skip("no_shim is not functional now: https://github.com/containerd/containerd/issues/2181")
183+
testDaemonRuntimeRoot(t, true)
184+
}

daemon_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func (d *daemon) waitForStart(ctx context.Context) (*Client, error) {
5858
err error
5959
)
6060

61-
client, err = New(address)
61+
client, err = New(d.addr)
6262
if err != nil {
6363
return nil, err
6464
}

linux/bundle.go

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -87,26 +87,23 @@ type ShimOpt func(*bundle, string, *runctypes.RuncOptions) (shim.Config, client.
8787
// ShimRemote is a ShimOpt for connecting and starting a remote shim
8888
func ShimRemote(c *Config, daemonAddress, cgroup string, exitHandler func()) ShimOpt {
8989
return func(b *bundle, ns string, ropts *runctypes.RuncOptions) (shim.Config, client.Opt) {
90-
config := b.shimConfig(ns, ropts)
91-
if config.RuntimeRoot == "" {
92-
config.RuntimeRoot = c.RuntimeRoot
93-
}
90+
config := b.shimConfig(ns, c, ropts)
9491
return config,
9592
client.WithStart(c.Shim, b.shimAddress(ns), daemonAddress, cgroup, c.ShimDebug, exitHandler)
9693
}
9794
}
9895

9996
// ShimLocal is a ShimOpt for using an in process shim implementation
100-
func ShimLocal(exchange *exchange.Exchange) ShimOpt {
97+
func ShimLocal(c *Config, exchange *exchange.Exchange) ShimOpt {
10198
return func(b *bundle, ns string, ropts *runctypes.RuncOptions) (shim.Config, client.Opt) {
102-
return b.shimConfig(ns, ropts), client.WithLocal(exchange)
99+
return b.shimConfig(ns, c, ropts), client.WithLocal(exchange)
103100
}
104101
}
105102

106103
// ShimConnect is a ShimOpt for connecting to an existing remote shim
107-
func ShimConnect(onClose func()) ShimOpt {
104+
func ShimConnect(c *Config, onClose func()) ShimOpt {
108105
return func(b *bundle, ns string, ropts *runctypes.RuncOptions) (shim.Config, client.Opt) {
109-
return b.shimConfig(ns, ropts), client.WithConnect(b.shimAddress(ns), onClose)
106+
return b.shimConfig(ns, c, ropts), client.WithConnect(b.shimAddress(ns), onClose)
110107
}
111108
}
112109

@@ -134,16 +131,18 @@ func (b *bundle) shimAddress(namespace string) string {
134131
return filepath.Join(string(filepath.Separator), "containerd-shim", namespace, b.id, "shim.sock")
135132
}
136133

137-
func (b *bundle) shimConfig(namespace string, runcOptions *runctypes.RuncOptions) shim.Config {
134+
func (b *bundle) shimConfig(namespace string, c *Config, runcOptions *runctypes.RuncOptions) shim.Config {
138135
var (
139136
criuPath string
140-
runtimeRoot string
137+
runtimeRoot = c.RuntimeRoot
141138
systemdCgroup bool
142139
)
143140
if runcOptions != nil {
144141
criuPath = runcOptions.CriuPath
145142
systemdCgroup = runcOptions.SystemdCgroup
146-
runtimeRoot = runcOptions.RuntimeRoot
143+
if runcOptions.RuntimeRoot != "" {
144+
runtimeRoot = runcOptions.RuntimeRoot
145+
}
147146
}
148147
return shim.Config{
149148
Path: b.path,

linux/runtime.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ func (r *Runtime) Create(ctx context.Context, id string, opts runtime.CreateOpts
186186
}
187187
}()
188188

189-
shimopt := ShimLocal(r.events)
189+
shimopt := ShimLocal(r.config, r.events)
190190
if !r.config.NoShim {
191191
var cgroup string
192192
if opts.Options != nil {
@@ -396,7 +396,7 @@ func (r *Runtime) loadTasks(ctx context.Context, ns string) ([]*Task, error) {
396396
)
397397
ctx = namespaces.WithNamespace(ctx, ns)
398398
pid, _ := runc.ReadPidFile(filepath.Join(bundle.path, proc.InitPidFile))
399-
s, err := bundle.NewShimClient(ctx, ns, ShimConnect(func() {
399+
s, err := bundle.NewShimClient(ctx, ns, ShimConnect(r.config, func() {
400400
err := r.cleanupAfterDeadShim(ctx, bundle, ns, id, pid)
401401
if err != nil {
402402
log.G(ctx).WithError(err).WithField("bundle", bundle.path).

0 commit comments

Comments
 (0)