github.com/rumpl/bof@v23.0.0-rc.2+incompatible/integration/container/run_linux_test.go (about) 1 package container // import "github.com/docker/docker/integration/container" 2 3 import ( 4 "bytes" 5 "context" 6 "io" 7 "os" 8 "os/exec" 9 "path/filepath" 10 "strings" 11 "testing" 12 "time" 13 14 "github.com/docker/docker/api/types" 15 containertypes "github.com/docker/docker/api/types/container" 16 "github.com/docker/docker/api/types/versions" 17 "github.com/docker/docker/integration/internal/container" 18 net "github.com/docker/docker/integration/internal/network" 19 "github.com/docker/docker/pkg/stdcopy" 20 "github.com/docker/docker/pkg/system" 21 "github.com/docker/docker/testutil/daemon" 22 "golang.org/x/sys/unix" 23 "gotest.tools/v3/assert" 24 is "gotest.tools/v3/assert/cmp" 25 "gotest.tools/v3/poll" 26 "gotest.tools/v3/skip" 27 ) 28 29 func TestNISDomainname(t *testing.T) { 30 // Older versions of the daemon would concatenate hostname and domainname, 31 // so hostname "foobar" and domainname "baz.cyphar.com" would produce 32 // `foobar.baz.cyphar.com` as hostname. 33 skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.40"), "skip test from new feature") 34 skip.If(t, testEnv.DaemonInfo.OSType != "linux") 35 36 // Rootless supports custom Hostname but doesn't support custom Domainname 37 // OCI runtime create failed: container_linux.go:349: starting container process caused "process_linux.go:449: container init caused \ 38 // "write sysctl key kernel.domainname: open /proc/sys/kernel/domainname: permission denied\"": unknown. 39 skip.If(t, testEnv.IsRootless, "rootless mode doesn't support setting Domainname (TODO: https://github.com/moby/moby/issues/40632)") 40 41 defer setupTest(t)() 42 client := testEnv.APIClient() 43 ctx := context.Background() 44 45 const ( 46 hostname = "foobar" 47 domainname = "baz.cyphar.com" 48 ) 49 50 cID := container.Run(ctx, t, client, func(c *container.TestContainerConfig) { 51 c.Config.Hostname = hostname 52 c.Config.Domainname = domainname 53 }) 54 55 poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond)) 56 57 inspect, err := client.ContainerInspect(ctx, cID) 58 assert.NilError(t, err) 59 assert.Check(t, is.Equal(hostname, inspect.Config.Hostname)) 60 assert.Check(t, is.Equal(domainname, inspect.Config.Domainname)) 61 62 // Check hostname. 63 res, err := container.Exec(ctx, client, cID, 64 []string{"cat", "/proc/sys/kernel/hostname"}) 65 assert.NilError(t, err) 66 assert.Assert(t, is.Len(res.Stderr(), 0)) 67 assert.Equal(t, 0, res.ExitCode) 68 assert.Check(t, is.Equal(hostname, strings.TrimSpace(res.Stdout()))) 69 70 // Check domainname. 71 res, err = container.Exec(ctx, client, cID, 72 []string{"cat", "/proc/sys/kernel/domainname"}) 73 assert.NilError(t, err) 74 assert.Assert(t, is.Len(res.Stderr(), 0)) 75 assert.Equal(t, 0, res.ExitCode) 76 assert.Check(t, is.Equal(domainname, strings.TrimSpace(res.Stdout()))) 77 } 78 79 func TestHostnameDnsResolution(t *testing.T) { 80 skip.If(t, testEnv.DaemonInfo.OSType != "linux") 81 82 defer setupTest(t)() 83 client := testEnv.APIClient() 84 ctx := context.Background() 85 86 const ( 87 hostname = "foobar" 88 ) 89 90 // using user defined network as we want to use internal DNS 91 netName := "foobar-net" 92 net.CreateNoError(context.Background(), t, client, netName, net.WithDriver("bridge")) 93 94 cID := container.Run(ctx, t, client, func(c *container.TestContainerConfig) { 95 c.Config.Hostname = hostname 96 c.HostConfig.NetworkMode = containertypes.NetworkMode(netName) 97 }) 98 99 poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond)) 100 101 inspect, err := client.ContainerInspect(ctx, cID) 102 assert.NilError(t, err) 103 assert.Check(t, is.Equal(hostname, inspect.Config.Hostname)) 104 105 // Clear hosts file so ping will use DNS for hostname resolution 106 res, err := container.Exec(ctx, client, cID, 107 []string{"sh", "-c", "echo 127.0.0.1 localhost | tee /etc/hosts && ping -c 1 foobar"}) 108 assert.NilError(t, err) 109 assert.Check(t, is.Equal("", res.Stderr())) 110 assert.Equal(t, 0, res.ExitCode) 111 } 112 113 func TestUnprivilegedPortsAndPing(t *testing.T) { 114 skip.If(t, testEnv.DaemonInfo.OSType != "linux") 115 skip.If(t, testEnv.IsRootless, "rootless mode doesn't support setting net.ipv4.ping_group_range and net.ipv4.ip_unprivileged_port_start") 116 117 defer setupTest(t)() 118 client := testEnv.APIClient() 119 ctx := context.Background() 120 121 cID := container.Run(ctx, t, client, func(c *container.TestContainerConfig) { 122 c.Config.User = "1000:1000" 123 }) 124 125 poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond)) 126 127 // Check net.ipv4.ping_group_range. 128 res, err := container.Exec(ctx, client, cID, []string{"cat", "/proc/sys/net/ipv4/ping_group_range"}) 129 assert.NilError(t, err) 130 assert.Assert(t, is.Len(res.Stderr(), 0)) 131 assert.Equal(t, 0, res.ExitCode) 132 assert.Equal(t, `0 2147483647`, strings.TrimSpace(res.Stdout())) 133 134 // Check net.ipv4.ip_unprivileged_port_start. 135 res, err = container.Exec(ctx, client, cID, []string{"cat", "/proc/sys/net/ipv4/ip_unprivileged_port_start"}) 136 assert.NilError(t, err) 137 assert.Assert(t, is.Len(res.Stderr(), 0)) 138 assert.Equal(t, 0, res.ExitCode) 139 assert.Equal(t, "0", strings.TrimSpace(res.Stdout())) 140 } 141 142 func TestPrivilegedHostDevices(t *testing.T) { 143 // Host devices are linux only. Also it creates host devices, 144 // so needs to be same host. 145 skip.If(t, testEnv.IsRemoteDaemon) 146 skip.If(t, testEnv.DaemonInfo.OSType != "linux") 147 148 defer setupTest(t)() 149 client := testEnv.APIClient() 150 ctx := context.Background() 151 152 const ( 153 devTest = "/dev/test" 154 devRootOnlyTest = "/dev/root-only/test" 155 ) 156 157 // Create Null devices. 158 if err := system.Mknod(devTest, unix.S_IFCHR|0600, int(system.Mkdev(1, 3))); err != nil { 159 t.Fatal(err) 160 } 161 defer os.Remove(devTest) 162 if err := os.Mkdir(filepath.Dir(devRootOnlyTest), 0700); err != nil { 163 t.Fatal(err) 164 } 165 defer os.RemoveAll(filepath.Dir(devRootOnlyTest)) 166 if err := system.Mknod(devRootOnlyTest, unix.S_IFCHR|0600, int(system.Mkdev(1, 3))); err != nil { 167 t.Fatal(err) 168 } 169 defer os.Remove(devRootOnlyTest) 170 171 cID := container.Run(ctx, t, client, container.WithPrivileged(true)) 172 173 poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond)) 174 175 // Check test device. 176 res, err := container.Exec(ctx, client, cID, []string{"ls", devTest}) 177 assert.NilError(t, err) 178 assert.Equal(t, 0, res.ExitCode) 179 assert.Check(t, is.Equal(strings.TrimSpace(res.Stdout()), devTest)) 180 181 // Check root-only test device. 182 res, err = container.Exec(ctx, client, cID, []string{"ls", devRootOnlyTest}) 183 assert.NilError(t, err) 184 if testEnv.IsRootless() { 185 assert.Equal(t, 1, res.ExitCode) 186 assert.Check(t, is.Contains(res.Stderr(), "No such file or directory")) 187 } else { 188 assert.Equal(t, 0, res.ExitCode) 189 assert.Check(t, is.Equal(strings.TrimSpace(res.Stdout()), devRootOnlyTest)) 190 } 191 } 192 193 func TestRunConsoleSize(t *testing.T) { 194 skip.If(t, testEnv.DaemonInfo.OSType != "linux") 195 skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.42"), "skip test from new feature") 196 197 defer setupTest(t)() 198 client := testEnv.APIClient() 199 ctx := context.Background() 200 201 cID := container.Run(ctx, t, client, 202 container.WithTty(true), 203 container.WithImage("busybox"), 204 container.WithCmd("stty", "size"), 205 container.WithConsoleSize(57, 123), 206 ) 207 208 poll.WaitOn(t, container.IsStopped(ctx, client, cID), poll.WithDelay(100*time.Millisecond)) 209 210 out, err := client.ContainerLogs(ctx, cID, types.ContainerLogsOptions{ShowStdout: true}) 211 assert.NilError(t, err) 212 defer out.Close() 213 214 var b bytes.Buffer 215 _, err = io.Copy(&b, out) 216 assert.NilError(t, err) 217 218 assert.Equal(t, strings.TrimSpace(b.String()), "123 57") 219 } 220 221 func TestRunWithAlternativeContainerdShim(t *testing.T) { 222 skip.If(t, testEnv.IsRemoteDaemon) 223 skip.If(t, testEnv.DaemonInfo.OSType != "linux") 224 225 realShimPath, err := exec.LookPath("containerd-shim-runc-v2") 226 assert.Assert(t, err) 227 realShimPath, err = filepath.Abs(realShimPath) 228 assert.Assert(t, err) 229 230 // t.TempDir() can't be used here as the temporary directory returned by 231 // that function cannot be accessed by the fake-root user for rootless 232 // Docker. It creates a nested hierarchy of directories where the 233 // outermost has permission 0700. 234 shimDir, err := os.MkdirTemp("", t.Name()) 235 assert.Assert(t, err) 236 t.Cleanup(func() { 237 if err := os.RemoveAll(shimDir); err != nil { 238 t.Errorf("shimDir RemoveAll cleanup: %v", err) 239 } 240 }) 241 assert.Assert(t, os.Chmod(shimDir, 0777)) 242 shimDir, err = filepath.Abs(shimDir) 243 assert.Assert(t, err) 244 assert.Assert(t, os.Symlink(realShimPath, filepath.Join(shimDir, "containerd-shim-realfake-v42"))) 245 246 d := daemon.New(t, 247 daemon.WithEnvVars("PATH="+shimDir+":"+os.Getenv("PATH")), 248 daemon.WithContainerdSocket(""), // A new containerd instance needs to be started which inherits the PATH env var defined above. 249 ) 250 d.StartWithBusybox(t) 251 defer d.Stop(t) 252 253 client := d.NewClientT(t) 254 ctx := context.Background() 255 256 cID := container.Run(ctx, t, client, 257 container.WithImage("busybox"), 258 container.WithCmd("sh", "-c", `echo 'Hello, world!'`), 259 container.WithRuntime("io.containerd.realfake.v42"), 260 ) 261 262 poll.WaitOn(t, container.IsStopped(ctx, client, cID), poll.WithDelay(100*time.Millisecond)) 263 264 out, err := client.ContainerLogs(ctx, cID, types.ContainerLogsOptions{ShowStdout: true}) 265 assert.NilError(t, err) 266 defer out.Close() 267 268 var b bytes.Buffer 269 _, err = stdcopy.StdCopy(&b, io.Discard, out) 270 assert.NilError(t, err) 271 272 assert.Equal(t, strings.TrimSpace(b.String()), "Hello, world!") 273 274 d.Stop(t) 275 d.Start(t, "--default-runtime="+"io.containerd.realfake.v42") 276 277 cID = container.Run(ctx, t, client, 278 container.WithImage("busybox"), 279 container.WithCmd("sh", "-c", `echo 'Hello, world!'`), 280 ) 281 282 poll.WaitOn(t, container.IsStopped(ctx, client, cID), poll.WithDelay(100*time.Millisecond)) 283 284 out, err = client.ContainerLogs(ctx, cID, types.ContainerLogsOptions{ShowStdout: true}) 285 assert.NilError(t, err) 286 defer out.Close() 287 288 b.Reset() 289 _, err = stdcopy.StdCopy(&b, io.Discard, out) 290 assert.NilError(t, err) 291 292 assert.Equal(t, strings.TrimSpace(b.String()), "Hello, world!") 293 }