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