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  }