Merge pull request #51675 from robmry/nri-mounts

NRI: allow plugins to add mounts
This commit is contained in:
Rob Murray
2025-12-12 18:37:29 +00:00
committed by GitHub
2 changed files with 167 additions and 1 deletions

View File

@@ -1,10 +1,12 @@
package nri
import (
"os"
"path/filepath"
"testing"
"github.com/containerd/nri/pkg/api"
"github.com/moby/moby/api/types/mount"
"github.com/moby/moby/client"
"github.com/moby/moby/v2/integration/internal/container"
"github.com/moby/moby/v2/internal/testutil"
@@ -68,3 +70,123 @@ func TestNRIContainerCreateEnvVarMod(t *testing.T) {
})
}
}
func TestNRIContainerCreateAddMount(t *testing.T) {
skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon")
skip.If(t, testEnv.DaemonInfo.OSType == "windows", "cannot start a separate daemon with NRI enabled on Windows")
skip.If(t, testEnv.IsRootless)
ctx := testutil.StartSpan(baseContext, t)
sockPath := filepath.Join(t.TempDir(), "nri.sock")
d := daemon.New(t)
d.StartWithBusybox(ctx, t,
"--nri-opts=enable=true,socket-path="+sockPath,
"--iptables=false", "--ip6tables=false",
)
defer d.Stop(t)
c := d.NewClientT(t)
// Create and populate a directory for containers to mount.
dirToMount := t.TempDir()
if err := os.WriteFile(filepath.Join(dirToMount, "testfile.txt"), []byte("hello\n"), 0o644); err != nil {
assert.NilError(t, err)
}
const (
mountPoint = "/mountpoint"
ctrTestFile = "/mountpoint/testfile.txt"
exitOk = 0
exitFail = 1
)
// Create and populate a volume.
const volName = "nri-test-volume"
_, err := c.VolumeCreate(ctx, client.VolumeCreateOptions{Name: volName})
assert.NilError(t, err)
defer func() {
_, _ = c.VolumeRemove(ctx, volName, client.VolumeRemoveOptions{Force: true})
}()
// Populate the volume with a test file.
_ = container.Run(ctx, t, c,
container.WithAutoRemove,
container.WithMount(mount.Mount{Type: "volume", Source: volName, Target: mountPoint}),
container.WithCmd("sh", "-c", "echo hello > "+ctrTestFile),
)
tests := []struct {
name string
ctrCreateAdj *api.ContainerAdjustment
expMountRead int
expMountWrite int
}{
{
name: "mount/bind/ro",
ctrCreateAdj: &api.ContainerAdjustment{Mounts: []*api.Mount{{
Type: "bind",
Source: dirToMount,
Destination: mountPoint,
Options: []string{"ro"},
}}},
expMountRead: exitOk,
expMountWrite: exitFail,
},
{
name: "mount/bind/rw",
ctrCreateAdj: &api.ContainerAdjustment{Mounts: []*api.Mount{{
Type: "bind",
Source: dirToMount,
Destination: mountPoint,
}}},
expMountRead: exitOk,
expMountWrite: exitOk,
},
{
name: "mount/volume/ro",
ctrCreateAdj: &api.ContainerAdjustment{Mounts: []*api.Mount{{
Type: "volume",
Source: volName,
Destination: mountPoint,
Options: []string{"ro"},
}}},
expMountRead: exitOk,
expMountWrite: exitFail,
},
{
name: "mount/volume/rw",
ctrCreateAdj: &api.ContainerAdjustment{Mounts: []*api.Mount{{
Type: "volume",
Source: volName,
Destination: mountPoint,
}}},
expMountRead: exitOk,
expMountWrite: exitOk,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
stopPlugin := startBuiltinPlugin(ctx, t, builtinPluginConfig{
pluginName: "nri-test-plugin",
pluginIdx: "00",
sockPath: sockPath,
ctrCreateAdj: tc.ctrCreateAdj,
})
defer stopPlugin()
ctrId := container.Run(ctx, t, c)
defer func() { _, _ = c.ContainerRemove(ctx, ctrId, client.ContainerRemoveOptions{Force: true}) }()
res, err := container.Exec(ctx, c, ctrId, []string{"cat", ctrTestFile})
if assert.Check(t, err) {
assert.Check(t, is.Equal(res.ExitCode, tc.expMountRead))
assert.Check(t, is.Equal(res.Stdout(), "hello\n"))
}
res, err = container.Exec(ctx, c, ctrId, []string{"touch", ctrTestFile})
if assert.Check(t, err) {
assert.Check(t, is.Equal(res.ExitCode, tc.expMountWrite))
}
})
}
}