2019-03-14 23:44:18 -04:00
|
|
|
package build // import "github.com/docker/docker/integration/build"
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"io"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/docker/docker/api/types"
|
|
|
|
"github.com/docker/docker/integration/internal/requirement"
|
|
|
|
"github.com/docker/docker/pkg/jsonmessage"
|
2019-08-29 16:52:40 -04:00
|
|
|
"github.com/docker/docker/testutil/daemon"
|
|
|
|
"github.com/docker/docker/testutil/fakecontext"
|
2020-02-07 08:39:24 -05:00
|
|
|
"gotest.tools/v3/assert"
|
|
|
|
"gotest.tools/v3/skip"
|
2019-03-14 23:44:18 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
// Finds the output of `readlink /proc/<pid>/ns/cgroup` in build output
|
|
|
|
func getCgroupFromBuildOutput(buildOutput io.Reader) (string, error) {
|
|
|
|
const prefix = "cgroup:"
|
|
|
|
|
|
|
|
dec := json.NewDecoder(buildOutput)
|
|
|
|
for {
|
|
|
|
m := jsonmessage.JSONMessage{}
|
|
|
|
err := dec.Decode(&m)
|
|
|
|
if err == io.EOF {
|
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
if ix := strings.Index(m.Stream, prefix); ix == 0 {
|
|
|
|
return strings.TrimSpace(m.Stream), nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Runs a docker build against a daemon with the given cgroup namespace default value.
|
|
|
|
// Returns the container cgroup and daemon cgroup.
|
|
|
|
func testBuildWithCgroupNs(t *testing.T, daemonNsMode string) (string, string) {
|
|
|
|
d := daemon.New(t, daemon.WithDefaultCgroupNamespaceMode(daemonNsMode))
|
|
|
|
d.StartWithBusybox(t)
|
|
|
|
defer d.Stop(t)
|
|
|
|
|
|
|
|
dockerfile := `
|
|
|
|
FROM busybox
|
|
|
|
RUN readlink /proc/self/ns/cgroup
|
|
|
|
`
|
|
|
|
ctx := context.Background()
|
|
|
|
source := fakecontext.New(t, "", fakecontext.WithDockerfile(dockerfile))
|
|
|
|
defer source.Close()
|
|
|
|
|
|
|
|
client := d.NewClientT(t)
|
|
|
|
resp, err := client.ImageBuild(ctx,
|
|
|
|
source.AsTarReader(t),
|
|
|
|
types.ImageBuildOptions{
|
|
|
|
Remove: true,
|
|
|
|
ForceRemove: true,
|
|
|
|
Tags: []string{"buildcgroupns"},
|
|
|
|
})
|
|
|
|
assert.NilError(t, err)
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
containerCgroup, err := getCgroupFromBuildOutput(resp.Body)
|
|
|
|
assert.NilError(t, err)
|
|
|
|
daemonCgroup := d.CgroupNamespace(t)
|
|
|
|
|
|
|
|
return containerCgroup, daemonCgroup
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCgroupNamespacesBuild(t *testing.T) {
|
|
|
|
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
|
|
|
skip.If(t, testEnv.IsRemoteDaemon())
|
|
|
|
skip.If(t, !requirement.CgroupNamespacesEnabled())
|
|
|
|
|
|
|
|
// When the daemon defaults to private cgroup namespaces, containers launched
|
|
|
|
// should be in their own private cgroup namespace by default
|
|
|
|
containerCgroup, daemonCgroup := testBuildWithCgroupNs(t, "private")
|
|
|
|
assert.Assert(t, daemonCgroup != containerCgroup)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCgroupNamespacesBuildDaemonHostMode(t *testing.T) {
|
|
|
|
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
|
|
|
skip.If(t, testEnv.IsRemoteDaemon())
|
|
|
|
skip.If(t, !requirement.CgroupNamespacesEnabled())
|
|
|
|
|
|
|
|
// When the daemon defaults to host cgroup namespaces, containers
|
|
|
|
// launched should not be inside their own cgroup namespaces
|
|
|
|
containerCgroup, daemonCgroup := testBuildWithCgroupNs(t, "host")
|
|
|
|
assert.Assert(t, daemonCgroup == containerCgroup)
|
|
|
|
}
|