Skip to content

Commit d2c460c

Browse files
Merge pull request #2194 from kunalkushwaha/cherry-pick-runtime-root
[release/1.0] linux: fix runtime-root propagation
2 parents 9b4bbcc + ee089eb commit d2c460c

5 files changed

Lines changed: 205 additions & 19 deletions

File tree

client_test.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@ import (
2222
)
2323

2424
var (
25-
address string
26-
noDaemon bool
27-
noCriu bool
28-
supportsCriu bool
25+
address string
26+
noDaemon bool
27+
noCriu bool
28+
supportsCriu bool
29+
testNamespace = "testing"
2930

3031
ctrd = &daemon{}
3132
)
@@ -42,7 +43,7 @@ func init() {
4243

4344
func testContext() (context.Context, context.CancelFunc) {
4445
ctx, cancel := context.WithCancel(context.Background())
45-
ctx = namespaces.WithNamespace(ctx, "testing")
46+
ctx = namespaces.WithNamespace(ctx, testNamespace)
4647
return ctx, cancel
4748
}
4849

daemon_config_linux_test.go

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
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+
func newDaemonWithConfig(t *testing.T, configTOML string) (*Client, *daemon, func()) {
37+
if testing.Short() {
38+
t.Skip()
39+
}
40+
testutil.RequiresRoot(t)
41+
var (
42+
ctrd = daemon{}
43+
configTOMLDecoded server.Config
44+
buf = bytes.NewBuffer(nil)
45+
)
46+
47+
tempDir, err := ioutil.TempDir("", "containerd-test-new-daemon-with-config")
48+
if err != nil {
49+
t.Fatal(err)
50+
}
51+
defer func() {
52+
if err != nil {
53+
os.RemoveAll(tempDir)
54+
}
55+
}()
56+
57+
configTOMLFile := filepath.Join(tempDir, "config.toml")
58+
if err = ioutil.WriteFile(configTOMLFile, []byte(configTOML), 0600); err != nil {
59+
t.Fatal(err)
60+
}
61+
62+
if err = server.LoadConfig(configTOMLFile, &configTOMLDecoded); err != nil {
63+
t.Fatal(err)
64+
}
65+
66+
address := configTOMLDecoded.GRPC.Address
67+
if address == "" {
68+
address = filepath.Join(tempDir, "containerd.sock")
69+
}
70+
args := []string{"-c", configTOMLFile}
71+
if configTOMLDecoded.Root == "" {
72+
args = append(args, "--root", filepath.Join(tempDir, "root"))
73+
}
74+
if configTOMLDecoded.State == "" {
75+
args = append(args, "--state", filepath.Join(tempDir, "state"))
76+
}
77+
if err = ctrd.start("containerd", address, args, buf, buf); err != nil {
78+
t.Fatalf("%v: %s", err, buf.String())
79+
}
80+
81+
waitCtx, waitCancel := context.WithTimeout(context.TODO(), 2*time.Second)
82+
client, err := ctrd.waitForStart(waitCtx)
83+
waitCancel()
84+
if err != nil {
85+
ctrd.Kill()
86+
ctrd.Wait()
87+
t.Fatalf("%v: %s", err, buf.String())
88+
}
89+
90+
cleanup := func() {
91+
if err := client.Close(); err != nil {
92+
t.Fatalf("failed to close client: %v", err)
93+
}
94+
if err := ctrd.Stop(); err != nil {
95+
if err := ctrd.Kill(); err != nil {
96+
t.Fatalf("failed to signal containerd: %v", err)
97+
}
98+
}
99+
if err := ctrd.Wait(); err != nil {
100+
if _, ok := err.(*exec.ExitError); !ok {
101+
t.Fatalf("failed to wait for: %v", err)
102+
}
103+
}
104+
if err := os.RemoveAll(tempDir); err != nil {
105+
t.Fatalf("failed to remove %s: %v", tempDir, err)
106+
}
107+
// cleaning config-specific resources is up to the caller
108+
}
109+
return client, &ctrd, cleanup
110+
111+
}
112+
113+
func testDaemonRuntimeRoot(t *testing.T, noShim bool) {
114+
runtimeRoot, err := ioutil.TempDir("", "containerd-test-runtime-root")
115+
if err != nil {
116+
t.Fatal(err)
117+
}
118+
defer func() {
119+
if err != nil {
120+
os.RemoveAll(runtimeRoot)
121+
}
122+
}()
123+
configTOML := fmt.Sprintf(`
124+
[plugins]
125+
[plugins.linux]
126+
no_shim = %v
127+
runtime_root = "%s"
128+
`, noShim, runtimeRoot)
129+
130+
client, _, cleanup := newDaemonWithConfig(t, configTOML)
131+
defer cleanup()
132+
133+
ctx, cancel := testContext()
134+
defer cancel()
135+
// FIXME(AkihiroSuda): import locally frozen image?
136+
image, err := client.Pull(ctx, testImage, WithPullUnpack)
137+
if err != nil {
138+
t.Fatal(err)
139+
}
140+
141+
id := t.Name()
142+
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image), withProcessArgs("top")), WithNewSnapshot(id, image))
143+
if err != nil {
144+
t.Fatal(err)
145+
}
146+
defer container.Delete(ctx, WithSnapshotCleanup)
147+
148+
task, err := container.NewTask(ctx, empty())
149+
if err != nil {
150+
t.Fatal(err)
151+
}
152+
defer task.Delete(ctx)
153+
154+
if err = task.Start(ctx); err != nil {
155+
t.Fatal(err)
156+
}
157+
158+
stateJSONPath := filepath.Join(runtimeRoot, testNamespace, id, "state.json")
159+
if _, err = os.Stat(stateJSONPath); err != nil {
160+
t.Errorf("error while getting stat for %s: %v", stateJSONPath, err)
161+
}
162+
163+
finishedC, err := task.Wait(ctx)
164+
if err != nil {
165+
t.Fatal(err)
166+
}
167+
if err = task.Kill(ctx, syscall.SIGKILL); err != nil {
168+
t.Error(err)
169+
}
170+
<-finishedC
171+
}
172+
173+
// TestDaemonRuntimeRoot ensures plugin.linux.runtime_root is not ignored
174+
func TestDaemonRuntimeRoot(t *testing.T) {
175+
testDaemonRuntimeRoot(t, false)
176+
}
177+
178+
// TestDaemonRuntimeRootNoShim ensures plugin.linux.runtime_root is not ignored when no_shim is true
179+
func TestDaemonRuntimeRootNoShim(t *testing.T) {
180+
t.Skip("no_shim is not functional now: https://github.com/containerd/containerd/issues/2181")
181+
testDaemonRuntimeRoot(t, true)
182+
}

daemon_test.go

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

45-
client, err = New(address)
45+
client, err = New(d.addr)
4646
if err != nil {
4747
return nil, err
4848
}

linux/bundle.go

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,24 +69,25 @@ type bundle struct {
6969
type ShimOpt func(*bundle, string, *runctypes.RuncOptions) (shim.Config, client.Opt)
7070

7171
// ShimRemote is a ShimOpt for connecting and starting a remote shim
72-
func ShimRemote(shimBinary, daemonAddress, cgroup string, debug bool, exitHandler func()) ShimOpt {
72+
func ShimRemote(c *Config, daemonAddress, cgroup string, exitHandler func()) ShimOpt {
7373
return func(b *bundle, ns string, ropts *runctypes.RuncOptions) (shim.Config, client.Opt) {
74-
return b.shimConfig(ns, ropts),
75-
client.WithStart(shimBinary, b.shimAddress(ns), daemonAddress, cgroup, debug, exitHandler)
74+
config := b.shimConfig(ns, c, ropts)
75+
return config,
76+
client.WithStart(c.Shim, b.shimAddress(ns), daemonAddress, cgroup, c.ShimDebug, exitHandler)
7677
}
7778
}
7879

7980
// ShimLocal is a ShimOpt for using an in process shim implementation
80-
func ShimLocal(exchange *exchange.Exchange) ShimOpt {
81+
func ShimLocal(c *Config, exchange *exchange.Exchange) ShimOpt {
8182
return func(b *bundle, ns string, ropts *runctypes.RuncOptions) (shim.Config, client.Opt) {
82-
return b.shimConfig(ns, ropts), client.WithLocal(exchange)
83+
return b.shimConfig(ns, c, ropts), client.WithLocal(exchange)
8384
}
8485
}
8586

8687
// ShimConnect is a ShimOpt for connecting to an existing remote shim
87-
func ShimConnect(onClose func()) ShimOpt {
88+
func ShimConnect(c *Config, onClose func()) ShimOpt {
8889
return func(b *bundle, ns string, ropts *runctypes.RuncOptions) (shim.Config, client.Opt) {
89-
return b.shimConfig(ns, ropts), client.WithConnect(b.shimAddress(ns), onClose)
90+
return b.shimConfig(ns, c, ropts), client.WithConnect(b.shimAddress(ns), onClose)
9091
}
9192
}
9293

@@ -114,16 +115,18 @@ func (b *bundle) shimAddress(namespace string) string {
114115
return filepath.Join(string(filepath.Separator), "containerd-shim", namespace, b.id, "shim.sock")
115116
}
116117

117-
func (b *bundle) shimConfig(namespace string, runcOptions *runctypes.RuncOptions) shim.Config {
118+
func (b *bundle) shimConfig(namespace string, c *Config, runcOptions *runctypes.RuncOptions) shim.Config {
118119
var (
119120
criuPath string
120-
runtimeRoot string
121+
runtimeRoot = c.RuntimeRoot
121122
systemdCgroup bool
122123
)
123124
if runcOptions != nil {
124125
criuPath = runcOptions.CriuPath
125126
systemdCgroup = runcOptions.SystemdCgroup
126-
runtimeRoot = runcOptions.RuntimeRoot
127+
if runcOptions.RuntimeRoot != "" {
128+
runtimeRoot = runcOptions.RuntimeRoot
129+
}
127130
}
128131
return shim.Config{
129132
Path: b.path,

linux/runtime.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ func (r *Runtime) Create(ctx context.Context, id string, opts runtime.CreateOpts
170170
}
171171
}()
172172

173-
shimopt := ShimLocal(r.events)
173+
shimopt := ShimLocal(r.config, r.events)
174174
if !r.config.NoShim {
175175
var cgroup string
176176
if opts.Options != nil {
@@ -208,7 +208,7 @@ func (r *Runtime) Create(ctx context.Context, id string, opts runtime.CreateOpts
208208
}).Warn("failed to clen up after killed shim")
209209
}
210210
}
211-
shimopt = ShimRemote(r.config.Shim, r.address, cgroup, r.config.ShimDebug, exitHandler)
211+
shimopt = ShimRemote(r.config, r.address, cgroup, exitHandler)
212212
}
213213

214214
s, err := bundle.NewShimClient(ctx, namespace, shimopt, ropts)
@@ -380,7 +380,7 @@ func (r *Runtime) loadTasks(ctx context.Context, ns string) ([]*Task, error) {
380380
)
381381
ctx = namespaces.WithNamespace(ctx, ns)
382382
pid, _ := runc.ReadPidFile(filepath.Join(bundle.path, proc.InitPidFile))
383-
s, err := bundle.NewShimClient(ctx, ns, ShimConnect(func() {
383+
s, err := bundle.NewShimClient(ctx, ns, ShimConnect(r.config, func() {
384384
log.G(ctx).WithError(err).WithFields(logrus.Fields{
385385
"id": id,
386386
"namespace": ns,

0 commit comments

Comments
 (0)