github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/runsc/container/multi_container_test.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package container
    16  
    17  import (
    18  	"fmt"
    19  	"io/ioutil"
    20  	"math"
    21  	"os"
    22  	"path"
    23  	"path/filepath"
    24  	"strings"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/cenkalti/backoff"
    29  	specs "github.com/opencontainers/runtime-spec/specs-go"
    30  	"golang.org/x/sys/unix"
    31  	"github.com/SagerNet/gvisor/pkg/cleanup"
    32  	"github.com/SagerNet/gvisor/pkg/sentry/control"
    33  	"github.com/SagerNet/gvisor/pkg/sentry/kernel"
    34  	"github.com/SagerNet/gvisor/pkg/sync"
    35  	"github.com/SagerNet/gvisor/pkg/test/testutil"
    36  	"github.com/SagerNet/gvisor/runsc/boot"
    37  	"github.com/SagerNet/gvisor/runsc/config"
    38  	"github.com/SagerNet/gvisor/runsc/specutils"
    39  )
    40  
    41  func createSpecs(cmds ...[]string) ([]*specs.Spec, []string) {
    42  	var specs []*specs.Spec
    43  	var ids []string
    44  	rootID := testutil.RandomContainerID()
    45  
    46  	for i, cmd := range cmds {
    47  		spec := testutil.NewSpecWithArgs(cmd...)
    48  		if i == 0 {
    49  			spec.Annotations = map[string]string{
    50  				specutils.ContainerdContainerTypeAnnotation: specutils.ContainerdContainerTypeSandbox,
    51  			}
    52  			ids = append(ids, rootID)
    53  		} else {
    54  			spec.Annotations = map[string]string{
    55  				specutils.ContainerdContainerTypeAnnotation: specutils.ContainerdContainerTypeContainer,
    56  				specutils.ContainerdSandboxIDAnnotation:     rootID,
    57  			}
    58  			ids = append(ids, testutil.RandomContainerID())
    59  		}
    60  		specs = append(specs, spec)
    61  	}
    62  	return specs, ids
    63  }
    64  
    65  func startContainers(conf *config.Config, specs []*specs.Spec, ids []string) ([]*Container, func(), error) {
    66  	if len(conf.RootDir) == 0 {
    67  		panic("conf.RootDir not set. Call testutil.SetupRootDir() to set.")
    68  	}
    69  
    70  	cu := cleanup.Cleanup{}
    71  	defer cu.Clean()
    72  
    73  	var containers []*Container
    74  	for i, spec := range specs {
    75  		bundleDir, cleanup, err := testutil.SetupBundleDir(spec)
    76  		if err != nil {
    77  			return nil, nil, fmt.Errorf("error setting up container: %v", err)
    78  		}
    79  		cu.Add(cleanup)
    80  
    81  		args := Args{
    82  			ID:        ids[i],
    83  			Spec:      spec,
    84  			BundleDir: bundleDir,
    85  		}
    86  		cont, err := New(conf, args)
    87  		if err != nil {
    88  			return nil, nil, fmt.Errorf("error creating container: %v", err)
    89  		}
    90  		cu.Add(func() { cont.Destroy() })
    91  		containers = append(containers, cont)
    92  
    93  		if err := cont.Start(conf); err != nil {
    94  			return nil, nil, fmt.Errorf("error starting container: %v", err)
    95  		}
    96  	}
    97  
    98  	return containers, cu.Release(), nil
    99  }
   100  
   101  type execDesc struct {
   102  	c    *Container
   103  	cmd  []string
   104  	want int
   105  	name string
   106  }
   107  
   108  func execMany(t *testing.T, execs []execDesc) {
   109  	for _, exec := range execs {
   110  		t.Run(exec.name, func(t *testing.T) {
   111  			args := &control.ExecArgs{Argv: exec.cmd}
   112  			if ws, err := exec.c.executeSync(args); err != nil {
   113  				t.Errorf("error executing %+v: %v", args, err)
   114  			} else if ws.ExitStatus() != exec.want {
   115  				t.Errorf("%q: exec %q got exit status: %d, want: %d", exec.name, exec.cmd, ws.ExitStatus(), exec.want)
   116  			}
   117  		})
   118  	}
   119  }
   120  
   121  func createSharedMount(mount specs.Mount, name string, pod ...*specs.Spec) {
   122  	for _, spec := range pod {
   123  		spec.Annotations[boot.MountPrefix+name+".source"] = mount.Source
   124  		spec.Annotations[boot.MountPrefix+name+".type"] = mount.Type
   125  		spec.Annotations[boot.MountPrefix+name+".share"] = "pod"
   126  		if len(mount.Options) > 0 {
   127  			spec.Annotations[boot.MountPrefix+name+".options"] = strings.Join(mount.Options, ",")
   128  		}
   129  	}
   130  }
   131  
   132  // TestMultiContainerSanity checks that it is possible to run 2 dead-simple
   133  // containers in the same sandbox.
   134  func TestMultiContainerSanity(t *testing.T) {
   135  	for name, conf := range configs(t, all...) {
   136  		t.Run(name, func(t *testing.T) {
   137  			rootDir, cleanup, err := testutil.SetupRootDir()
   138  			if err != nil {
   139  				t.Fatalf("error creating root dir: %v", err)
   140  			}
   141  			defer cleanup()
   142  			conf.RootDir = rootDir
   143  
   144  			// Setup the containers.
   145  			sleep := []string{"sleep", "100"}
   146  			specs, ids := createSpecs(sleep, sleep)
   147  			containers, cleanup, err := startContainers(conf, specs, ids)
   148  			if err != nil {
   149  				t.Fatalf("error starting containers: %v", err)
   150  			}
   151  			defer cleanup()
   152  
   153  			// Check via ps that multiple processes are running.
   154  			expectedPL := []*control.Process{
   155  				newProcessBuilder().PID(1).PPID(0).Cmd("sleep").Process(),
   156  			}
   157  			if err := waitForProcessList(containers[0], expectedPL); err != nil {
   158  				t.Errorf("failed to wait for sleep to start: %v", err)
   159  			}
   160  			expectedPL = []*control.Process{
   161  				newProcessBuilder().PID(2).PPID(0).Cmd("sleep").Process(),
   162  			}
   163  			if err := waitForProcessList(containers[1], expectedPL); err != nil {
   164  				t.Errorf("failed to wait for sleep to start: %v", err)
   165  			}
   166  		})
   167  	}
   168  }
   169  
   170  // TestMultiPIDNS checks that it is possible to run 2 dead-simple containers in
   171  // the same sandbox with different pidns.
   172  func TestMultiPIDNS(t *testing.T) {
   173  	for name, conf := range configs(t, all...) {
   174  		t.Run(name, func(t *testing.T) {
   175  			rootDir, cleanup, err := testutil.SetupRootDir()
   176  			if err != nil {
   177  				t.Fatalf("error creating root dir: %v", err)
   178  			}
   179  			defer cleanup()
   180  			conf.RootDir = rootDir
   181  
   182  			// Setup the containers.
   183  			sleep := []string{"sleep", "100"}
   184  			testSpecs, ids := createSpecs(sleep, sleep)
   185  			testSpecs[1].Linux = &specs.Linux{
   186  				Namespaces: []specs.LinuxNamespace{
   187  					{
   188  						Type: "pid",
   189  					},
   190  				},
   191  			}
   192  
   193  			containers, cleanup, err := startContainers(conf, testSpecs, ids)
   194  			if err != nil {
   195  				t.Fatalf("error starting containers: %v", err)
   196  			}
   197  			defer cleanup()
   198  
   199  			// Check via ps that multiple processes are running.
   200  			expectedPL := []*control.Process{
   201  				newProcessBuilder().PID(1).Cmd("sleep").Process(),
   202  			}
   203  			if err := waitForProcessList(containers[0], expectedPL); err != nil {
   204  				t.Errorf("failed to wait for sleep to start: %v", err)
   205  			}
   206  			expectedPL = []*control.Process{
   207  				newProcessBuilder().PID(2).Cmd("sleep").Process(),
   208  			}
   209  			if err := waitForProcessList(containers[1], expectedPL); err != nil {
   210  				t.Errorf("failed to wait for sleep to start: %v", err)
   211  			}
   212  
   213  			// Root container runs in the root PID namespace and can see all
   214  			// processes.
   215  			expectedPL = []*control.Process{
   216  				newProcessBuilder().PID(1).Cmd("sleep").Process(),
   217  				newProcessBuilder().PID(2).Cmd("sleep").Process(),
   218  				newProcessBuilder().Cmd("ps").Process(),
   219  			}
   220  			got, err := execPS(containers[0])
   221  			if err != nil {
   222  				t.Fatal(err)
   223  			}
   224  			if !procListsEqual(got, expectedPL) {
   225  				t.Errorf("container got process list: %s, want: %s", procListToString(got), procListToString(expectedPL))
   226  			}
   227  
   228  			expectedPL = []*control.Process{
   229  				newProcessBuilder().PID(1).Cmd("sleep").Process(),
   230  				newProcessBuilder().Cmd("ps").Process(),
   231  			}
   232  			got, err = execPS(containers[1])
   233  			if err != nil {
   234  				t.Fatal(err)
   235  			}
   236  			if !procListsEqual(got, expectedPL) {
   237  				t.Errorf("container got process list: %s, want: %s", procListToString(got), procListToString(expectedPL))
   238  			}
   239  		})
   240  	}
   241  }
   242  
   243  // TestMultiPIDNSPath checks the pidns path.
   244  func TestMultiPIDNSPath(t *testing.T) {
   245  	for name, conf := range configs(t, all...) {
   246  		t.Run(name, func(t *testing.T) {
   247  			rootDir, cleanup, err := testutil.SetupRootDir()
   248  			if err != nil {
   249  				t.Fatalf("error creating root dir: %v", err)
   250  			}
   251  			defer cleanup()
   252  			conf.RootDir = rootDir
   253  
   254  			// Setup the containers.
   255  			sleep := []string{"sleep", "100"}
   256  			testSpecs, ids := createSpecs(sleep, sleep, sleep)
   257  			testSpecs[0].Linux = &specs.Linux{
   258  				Namespaces: []specs.LinuxNamespace{
   259  					{
   260  						Type: "pid",
   261  						Path: "/proc/1/ns/pid",
   262  					},
   263  				},
   264  			}
   265  			testSpecs[1].Linux = &specs.Linux{
   266  				Namespaces: []specs.LinuxNamespace{
   267  					{
   268  						Type: "pid",
   269  						Path: "/proc/1/ns/pid",
   270  					},
   271  				},
   272  			}
   273  			testSpecs[2].Linux = &specs.Linux{
   274  				Namespaces: []specs.LinuxNamespace{
   275  					{
   276  						Type: "pid",
   277  						Path: "/proc/2/ns/pid",
   278  					},
   279  				},
   280  			}
   281  
   282  			containers, cleanup, err := startContainers(conf, testSpecs, ids)
   283  			if err != nil {
   284  				t.Fatalf("error starting containers: %v", err)
   285  			}
   286  			defer cleanup()
   287  
   288  			// Check via ps that multiple processes are running.
   289  			expectedPL := []*control.Process{
   290  				newProcessBuilder().PID(1).PPID(0).Cmd("sleep").Process(),
   291  			}
   292  			if err := waitForProcessList(containers[0], expectedPL); err != nil {
   293  				t.Errorf("failed to wait for sleep to start: %v", err)
   294  			}
   295  			expectedPL = []*control.Process{
   296  				newProcessBuilder().PID(2).PPID(0).Cmd("sleep").Process(),
   297  			}
   298  			if err := waitForProcessList(containers[1], expectedPL); err != nil {
   299  				t.Errorf("failed to wait for sleep to start: %v", err)
   300  			}
   301  			expectedPL = []*control.Process{
   302  				newProcessBuilder().PID(3).PPID(0).Cmd("sleep").Process(),
   303  			}
   304  			if err := waitForProcessList(containers[2], expectedPL); err != nil {
   305  				t.Errorf("failed to wait for sleep to start: %v", err)
   306  			}
   307  
   308  			// Root container runs in the root PID namespace and can see all
   309  			// processes.
   310  			expectedPL = []*control.Process{
   311  				newProcessBuilder().PID(1).Cmd("sleep").Process(),
   312  				newProcessBuilder().PID(2).Cmd("sleep").Process(),
   313  				newProcessBuilder().PID(3).Cmd("sleep").Process(),
   314  				newProcessBuilder().Cmd("ps").Process(),
   315  			}
   316  			got, err := execPS(containers[0])
   317  			if err != nil {
   318  				t.Fatal(err)
   319  			}
   320  			if !procListsEqual(got, expectedPL) {
   321  				t.Errorf("container got process list: %s, want: %s", procListToString(got), procListToString(expectedPL))
   322  			}
   323  
   324  			// Container 1 runs in the same PID namespace as the root container.
   325  			expectedPL = []*control.Process{
   326  				newProcessBuilder().PID(1).Cmd("sleep").Process(),
   327  				newProcessBuilder().PID(2).Cmd("sleep").Process(),
   328  				newProcessBuilder().PID(3).Cmd("sleep").Process(),
   329  				newProcessBuilder().Cmd("ps").Process(),
   330  			}
   331  			got, err = execPS(containers[1])
   332  			if err != nil {
   333  				t.Fatal(err)
   334  			}
   335  			if !procListsEqual(got, expectedPL) {
   336  				t.Errorf("container got process list: %s, want: %s", procListToString(got), procListToString(expectedPL))
   337  			}
   338  
   339  			// Container 2 runs on its own namespace.
   340  			expectedPL = []*control.Process{
   341  				newProcessBuilder().PID(1).Cmd("sleep").Process(),
   342  				newProcessBuilder().Cmd("ps").Process(),
   343  			}
   344  			got, err = execPS(containers[2])
   345  			if err != nil {
   346  				t.Fatal(err)
   347  			}
   348  			if !procListsEqual(got, expectedPL) {
   349  				t.Errorf("container got process list: %s, want: %s", procListToString(got), procListToString(expectedPL))
   350  			}
   351  		})
   352  	}
   353  }
   354  
   355  // TestMultiPIDNSKill kills processes using PID when containers are using
   356  // different PID namespaces to ensure PID is taken from the root namespace.
   357  func TestMultiPIDNSKill(t *testing.T) {
   358  	app, err := testutil.FindFile("test/cmd/test_app/test_app")
   359  	if err != nil {
   360  		t.Fatal("error finding test_app:", err)
   361  	}
   362  
   363  	for name, conf := range configs(t, all...) {
   364  		t.Run(name, func(t *testing.T) {
   365  			rootDir, cleanup, err := testutil.SetupRootDir()
   366  			if err != nil {
   367  				t.Fatalf("error creating root dir: %v", err)
   368  			}
   369  			defer cleanup()
   370  			conf.RootDir = rootDir
   371  
   372  			// Setup the containers.
   373  			cmd := []string{app, "task-tree", "--depth=1", "--width=2", "--pause=true"}
   374  			const processes = 3
   375  			testSpecs, ids := createSpecs(cmd, cmd)
   376  
   377  			testSpecs[1].Linux = &specs.Linux{
   378  				Namespaces: []specs.LinuxNamespace{
   379  					{
   380  						Type: "pid",
   381  					},
   382  				},
   383  			}
   384  
   385  			containers, cleanup, err := startContainers(conf, testSpecs, ids)
   386  			if err != nil {
   387  				t.Fatalf("error starting containers: %v", err)
   388  			}
   389  			defer cleanup()
   390  
   391  			// Wait until all processes are created.
   392  			for _, c := range containers {
   393  				if err := waitForProcessCount(c, processes); err != nil {
   394  					t.Fatalf("error waitting for processes: %v", err)
   395  				}
   396  			}
   397  
   398  			for i, c := range containers {
   399  				// First, kill a process that belongs to the container.
   400  				procs, err := c.Processes()
   401  				if err != nil {
   402  					t.Fatalf("container.Processes(): %v", err)
   403  				}
   404  				t.Logf("Container %q procs: %s", c.ID, procListToString(procs))
   405  				pidToKill := procs[processes-1].PID
   406  				t.Logf("PID to kill: %d", pidToKill)
   407  				if err := c.SignalProcess(unix.SIGKILL, int32(pidToKill)); err != nil {
   408  					t.Errorf("container.SignalProcess: %v", err)
   409  				}
   410  				// Wait for the process to get killed.
   411  				if err := waitForProcessCount(c, processes-1); err != nil {
   412  					t.Fatalf("error waitting for processes: %v", err)
   413  				}
   414  				procs, err = c.Processes()
   415  				if err != nil {
   416  					t.Fatalf("container.Processes(): %v", err)
   417  				}
   418  				t.Logf("Container %q procs after kill: %s", c.ID, procListToString(procs))
   419  				for _, proc := range procs {
   420  					if proc.PID == pidToKill {
   421  						t.Errorf("process %d not killed: %+v", pidToKill, proc)
   422  					}
   423  				}
   424  
   425  				// Next, attempt to kill a process from another container and check that
   426  				// it fails.
   427  				other := containers[(i+1)%len(containers)]
   428  				procs, err = other.Processes()
   429  				if err != nil {
   430  					t.Fatalf("container.Processes(): %v", err)
   431  				}
   432  				t.Logf("Other container %q procs: %s", other.ID, procListToString(procs))
   433  
   434  				pidToKill = procs[len(procs)-1].PID
   435  				t.Logf("PID that should not be killed: %d", pidToKill)
   436  				err = c.SignalProcess(unix.SIGKILL, int32(pidToKill))
   437  				if err == nil {
   438  					t.Fatalf("killing another container's process should fail")
   439  				}
   440  				if !strings.Contains(err.Error(), "belongs to a different container") {
   441  					t.Errorf("wrong error message from killing another container's: %v", err)
   442  				}
   443  			}
   444  		})
   445  	}
   446  }
   447  
   448  func TestMultiContainerWait(t *testing.T) {
   449  	rootDir, cleanup, err := testutil.SetupRootDir()
   450  	if err != nil {
   451  		t.Fatalf("error creating root dir: %v", err)
   452  	}
   453  	defer cleanup()
   454  
   455  	conf := testutil.TestConfig(t)
   456  	conf.RootDir = rootDir
   457  
   458  	// The first container should run the entire duration of the test.
   459  	cmd1 := []string{"sleep", "100"}
   460  	// We'll wait on the second container, which is much shorter lived.
   461  	cmd2 := []string{"sleep", "1"}
   462  	specs, ids := createSpecs(cmd1, cmd2)
   463  
   464  	containers, cleanup, err := startContainers(conf, specs, ids)
   465  	if err != nil {
   466  		t.Fatalf("error starting containers: %v", err)
   467  	}
   468  	defer cleanup()
   469  
   470  	// Check that we can wait for the sub-container.
   471  	c := containers[1]
   472  	if ws, err := c.Wait(); err != nil {
   473  		t.Errorf("failed to wait for process %s: %v", c.Spec.Process.Args, err)
   474  	} else if es := ws.ExitStatus(); es != 0 {
   475  		t.Errorf("process %s exited with non-zero status %d", c.Spec.Process.Args, es)
   476  	}
   477  	if _, err := c.Wait(); err != nil {
   478  		t.Errorf("wait for stopped container %s shouldn't fail: %v", c.Spec.Process.Args, err)
   479  	}
   480  
   481  	// After Wait returns, ensure that the root container is running and
   482  	// the child has finished.
   483  	expectedPL := []*control.Process{
   484  		newProcessBuilder().Cmd("sleep").PID(1).Process(),
   485  	}
   486  	if err := waitForProcessList(containers[0], expectedPL); err != nil {
   487  		t.Errorf("failed to wait for %q to start: %v", strings.Join(containers[0].Spec.Process.Args, " "), err)
   488  	}
   489  }
   490  
   491  // TestExecWait ensures what we can wait on containers and individual processes
   492  // in the sandbox that have already exited.
   493  func TestExecWait(t *testing.T) {
   494  	rootDir, cleanup, err := testutil.SetupRootDir()
   495  	if err != nil {
   496  		t.Fatalf("error creating root dir: %v", err)
   497  	}
   498  	defer cleanup()
   499  
   500  	conf := testutil.TestConfig(t)
   501  	conf.RootDir = rootDir
   502  
   503  	// The first container should run the entire duration of the test.
   504  	cmd1 := []string{"sleep", "100"}
   505  	// We'll wait on the second container, which is much shorter lived.
   506  	cmd2 := []string{"sleep", "1"}
   507  	specs, ids := createSpecs(cmd1, cmd2)
   508  	containers, cleanup, err := startContainers(conf, specs, ids)
   509  	if err != nil {
   510  		t.Fatalf("error starting containers: %v", err)
   511  	}
   512  	defer cleanup()
   513  
   514  	// Check via ps that process is running.
   515  	expectedPL := []*control.Process{
   516  		newProcessBuilder().Cmd("sleep").Process(),
   517  	}
   518  	if err := waitForProcessList(containers[1], expectedPL); err != nil {
   519  		t.Fatalf("failed to wait for sleep to start: %v", err)
   520  	}
   521  
   522  	// Wait for the second container to finish.
   523  	if err := waitForProcessCount(containers[1], 0); err != nil {
   524  		t.Fatalf("failed to wait for second container to stop: %v", err)
   525  	}
   526  
   527  	// Get the second container exit status.
   528  	if ws, err := containers[1].Wait(); err != nil {
   529  		t.Fatalf("failed to wait for process %s: %v", containers[1].Spec.Process.Args, err)
   530  	} else if es := ws.ExitStatus(); es != 0 {
   531  		t.Fatalf("process %s exited with non-zero status %d", containers[1].Spec.Process.Args, es)
   532  	}
   533  	if _, err := containers[1].Wait(); err != nil {
   534  		t.Fatalf("wait for stopped container %s shouldn't fail: %v", containers[1].Spec.Process.Args, err)
   535  	}
   536  
   537  	// Execute another process in the first container.
   538  	args := &control.ExecArgs{
   539  		Filename:         "/bin/sleep",
   540  		Argv:             []string{"/bin/sleep", "1"},
   541  		WorkingDirectory: "/",
   542  		KUID:             0,
   543  	}
   544  	pid, err := containers[0].Execute(args)
   545  	if err != nil {
   546  		t.Fatalf("error executing: %v", err)
   547  	}
   548  
   549  	// Wait for the exec'd process to exit.
   550  	expectedPL = []*control.Process{
   551  		newProcessBuilder().PID(1).Cmd("sleep").Process(),
   552  	}
   553  	if err := waitForProcessList(containers[0], expectedPL); err != nil {
   554  		t.Fatalf("failed to wait for second container to stop: %v", err)
   555  	}
   556  
   557  	// Get the exit status from the exec'd process.
   558  	if ws, err := containers[0].WaitPID(pid); err != nil {
   559  		t.Fatalf("failed to wait for process %+v with pid %d: %v", args, pid, err)
   560  	} else if es := ws.ExitStatus(); es != 0 {
   561  		t.Fatalf("process %+v exited with non-zero status %d", args, es)
   562  	}
   563  	if _, err := containers[0].WaitPID(pid); err == nil {
   564  		t.Fatalf("wait for stopped process %+v should fail", args)
   565  	}
   566  }
   567  
   568  // TestMultiContainerMount tests that bind mounts can be used with multiple
   569  // containers.
   570  func TestMultiContainerMount(t *testing.T) {
   571  	cmd1 := []string{"sleep", "100"}
   572  
   573  	// 'src != dst' ensures that 'dst' doesn't exist in the host and must be
   574  	// properly mapped inside the container to work.
   575  	src, err := ioutil.TempDir(testutil.TmpDir(), "container")
   576  	if err != nil {
   577  		t.Fatal("ioutil.TempDir failed:", err)
   578  	}
   579  	dst := src + ".dst"
   580  	cmd2 := []string{"touch", filepath.Join(dst, "file")}
   581  
   582  	sps, ids := createSpecs(cmd1, cmd2)
   583  	sps[1].Mounts = append(sps[1].Mounts, specs.Mount{
   584  		Source:      src,
   585  		Destination: dst,
   586  		Type:        "bind",
   587  	})
   588  
   589  	// Setup the containers.
   590  	rootDir, cleanup, err := testutil.SetupRootDir()
   591  	if err != nil {
   592  		t.Fatalf("error creating root dir: %v", err)
   593  	}
   594  	defer cleanup()
   595  
   596  	conf := testutil.TestConfig(t)
   597  	conf.RootDir = rootDir
   598  
   599  	containers, cleanup, err := startContainers(conf, sps, ids)
   600  	if err != nil {
   601  		t.Fatalf("error starting containers: %v", err)
   602  	}
   603  	defer cleanup()
   604  
   605  	ws, err := containers[1].Wait()
   606  	if err != nil {
   607  		t.Error("error waiting on container:", err)
   608  	}
   609  	if !ws.Exited() || ws.ExitStatus() != 0 {
   610  		t.Error("container failed, waitStatus:", ws)
   611  	}
   612  }
   613  
   614  // TestMultiContainerSignal checks that it is possible to signal individual
   615  // containers without killing the entire sandbox.
   616  func TestMultiContainerSignal(t *testing.T) {
   617  	for name, conf := range configs(t, all...) {
   618  		t.Run(name, func(t *testing.T) {
   619  			rootDir, cleanup, err := testutil.SetupRootDir()
   620  			if err != nil {
   621  				t.Fatalf("error creating root dir: %v", err)
   622  			}
   623  			defer cleanup()
   624  			conf.RootDir = rootDir
   625  
   626  			// Setup the containers.
   627  			sleep := []string{"sleep", "100"}
   628  			specs, ids := createSpecs(sleep, sleep)
   629  			containers, cleanup, err := startContainers(conf, specs, ids)
   630  			if err != nil {
   631  				t.Fatalf("error starting containers: %v", err)
   632  			}
   633  			defer cleanup()
   634  
   635  			// Check via ps that container 1 process is running.
   636  			expectedPL := []*control.Process{
   637  				newProcessBuilder().Cmd("sleep").Process(),
   638  			}
   639  			if err := waitForProcessList(containers[1], expectedPL); err != nil {
   640  				t.Errorf("failed to wait for sleep to start: %v", err)
   641  			}
   642  
   643  			// Kill process 2.
   644  			if err := containers[1].SignalContainer(unix.SIGKILL, false); err != nil {
   645  				t.Errorf("failed to kill process 2: %v", err)
   646  			}
   647  
   648  			// Make sure process 1 is still running.
   649  			expectedPL = []*control.Process{
   650  				newProcessBuilder().PID(1).Cmd("sleep").Process(),
   651  			}
   652  			if err := waitForProcessList(containers[0], expectedPL); err != nil {
   653  				t.Errorf("failed to wait for sleep to start: %v", err)
   654  			}
   655  
   656  			// goferPid is reset when container is destroyed.
   657  			goferPid := containers[1].GoferPid
   658  
   659  			// Destroy container and ensure container's gofer process has exited.
   660  			if err := containers[1].Destroy(); err != nil {
   661  				t.Errorf("failed to destroy container: %v", err)
   662  			}
   663  			_, _, err = specutils.RetryEintr(func() (uintptr, uintptr, error) {
   664  				cpid, err := unix.Wait4(goferPid, nil, 0, nil)
   665  				return uintptr(cpid), 0, err
   666  			})
   667  			if err != unix.ECHILD {
   668  				t.Errorf("error waiting for gofer to exit: %v", err)
   669  			}
   670  			// Make sure process 1 is still running.
   671  			if err := waitForProcessList(containers[0], expectedPL); err != nil {
   672  				t.Errorf("failed to wait for sleep to start: %v", err)
   673  			}
   674  
   675  			// Now that process 2 is gone, ensure we get an error trying to
   676  			// signal it again.
   677  			if err := containers[1].SignalContainer(unix.SIGKILL, false); err == nil {
   678  				t.Errorf("container %q shouldn't exist, but we were able to signal it", containers[1].ID)
   679  			}
   680  
   681  			// Kill process 1.
   682  			if err := containers[0].SignalContainer(unix.SIGKILL, false); err != nil {
   683  				t.Errorf("failed to kill process 1: %v", err)
   684  			}
   685  
   686  			// Ensure that container's gofer and sandbox process are no more.
   687  			err = blockUntilWaitable(containers[0].GoferPid)
   688  			if err != nil && err != unix.ECHILD {
   689  				t.Errorf("error waiting for gofer to exit: %v", err)
   690  			}
   691  
   692  			err = blockUntilWaitable(containers[0].Sandbox.Pid)
   693  			if err != nil && err != unix.ECHILD {
   694  				t.Errorf("error waiting for sandbox to exit: %v", err)
   695  			}
   696  
   697  			// The sentry should be gone, so signaling should yield an error.
   698  			if err := containers[0].SignalContainer(unix.SIGKILL, false); err == nil {
   699  				t.Errorf("sandbox %q shouldn't exist, but we were able to signal it", containers[0].Sandbox.ID)
   700  			}
   701  
   702  			if err := containers[0].Destroy(); err != nil {
   703  				t.Errorf("failed to destroy container: %v", err)
   704  			}
   705  		})
   706  	}
   707  }
   708  
   709  // TestMultiContainerDestroy checks that container are properly cleaned-up when
   710  // they are destroyed.
   711  func TestMultiContainerDestroy(t *testing.T) {
   712  	app, err := testutil.FindFile("test/cmd/test_app/test_app")
   713  	if err != nil {
   714  		t.Fatal("error finding test_app:", err)
   715  	}
   716  
   717  	for name, conf := range configs(t, all...) {
   718  		t.Run(name, func(t *testing.T) {
   719  			rootDir, cleanup, err := testutil.SetupRootDir()
   720  			if err != nil {
   721  				t.Fatalf("error creating root dir: %v", err)
   722  			}
   723  			defer cleanup()
   724  			conf.RootDir = rootDir
   725  
   726  			// First container will remain intact while the second container is killed.
   727  			podSpecs, ids := createSpecs(
   728  				[]string{"sleep", "100"},
   729  				[]string{app, "fork-bomb"})
   730  
   731  			// Run the fork bomb in a PID namespace to prevent processes to be
   732  			// re-parented to PID=1 in the root container.
   733  			podSpecs[1].Linux = &specs.Linux{
   734  				Namespaces: []specs.LinuxNamespace{{Type: "pid"}},
   735  			}
   736  			containers, cleanup, err := startContainers(conf, podSpecs, ids)
   737  			if err != nil {
   738  				t.Fatalf("error starting containers: %v", err)
   739  			}
   740  			defer cleanup()
   741  
   742  			// Exec more processes to ensure signal all works for exec'd processes too.
   743  			args := &control.ExecArgs{
   744  				Filename: app,
   745  				Argv:     []string{app, "fork-bomb"},
   746  			}
   747  			if _, err := containers[1].Execute(args); err != nil {
   748  				t.Fatalf("error exec'ing: %v", err)
   749  			}
   750  
   751  			// Let it brew...
   752  			time.Sleep(500 * time.Millisecond)
   753  
   754  			if err := containers[1].Destroy(); err != nil {
   755  				t.Fatalf("error destroying container: %v", err)
   756  			}
   757  
   758  			// Check that destroy killed all processes belonging to the container and
   759  			// waited for them to exit before returning.
   760  			pss, err := containers[0].Sandbox.Processes("")
   761  			if err != nil {
   762  				t.Fatalf("error getting process data from sandbox: %v", err)
   763  			}
   764  			expectedPL := []*control.Process{
   765  				newProcessBuilder().PID(1).Cmd("sleep").Process(),
   766  			}
   767  			if !procListsEqual(pss, expectedPL) {
   768  				t.Errorf("container got process list: %s, want: %s: error: %v",
   769  					procListToString(pss), procListToString(expectedPL), err)
   770  			}
   771  
   772  			// Check that cont.Destroy is safe to call multiple times.
   773  			if err := containers[1].Destroy(); err != nil {
   774  				t.Errorf("error destroying container: %v", err)
   775  			}
   776  		})
   777  	}
   778  }
   779  
   780  func TestMultiContainerProcesses(t *testing.T) {
   781  	rootDir, cleanup, err := testutil.SetupRootDir()
   782  	if err != nil {
   783  		t.Fatalf("error creating root dir: %v", err)
   784  	}
   785  	defer cleanup()
   786  
   787  	conf := testutil.TestConfig(t)
   788  	conf.RootDir = rootDir
   789  
   790  	// Note: use curly braces to keep 'sh' process around. Otherwise, shell
   791  	// will just execve into 'sleep' and both containers will look the
   792  	// same.
   793  	specs, ids := createSpecs(
   794  		[]string{"sleep", "100"},
   795  		[]string{"sh", "-c", "{ sleep 100; }"})
   796  	containers, cleanup, err := startContainers(conf, specs, ids)
   797  	if err != nil {
   798  		t.Fatalf("error starting containers: %v", err)
   799  	}
   800  	defer cleanup()
   801  
   802  	// Check root's container process list doesn't include other containers.
   803  	expectedPL0 := []*control.Process{
   804  		newProcessBuilder().PID(1).Cmd("sleep").Process(),
   805  	}
   806  	if err := waitForProcessList(containers[0], expectedPL0); err != nil {
   807  		t.Errorf("failed to wait for process to start: %v", err)
   808  	}
   809  
   810  	// Same for the other container.
   811  	expectedPL1 := []*control.Process{
   812  		newProcessBuilder().PID(2).Cmd("sh").Process(),
   813  		newProcessBuilder().PID(3).PPID(2).Cmd("sleep").Process(),
   814  	}
   815  	if err := waitForProcessList(containers[1], expectedPL1); err != nil {
   816  		t.Errorf("failed to wait for process to start: %v", err)
   817  	}
   818  
   819  	// Now exec into the second container and verify it shows up in the container.
   820  	args := &control.ExecArgs{
   821  		Filename: "/bin/sleep",
   822  		Argv:     []string{"/bin/sleep", "100"},
   823  	}
   824  	if _, err := containers[1].Execute(args); err != nil {
   825  		t.Fatalf("error exec'ing: %v", err)
   826  	}
   827  	expectedPL1 = append(expectedPL1, newProcessBuilder().PID(4).Cmd("sleep").Process())
   828  	if err := waitForProcessList(containers[1], expectedPL1); err != nil {
   829  		t.Errorf("failed to wait for process to start: %v", err)
   830  	}
   831  	// Root container should remain unchanged.
   832  	if err := waitForProcessList(containers[0], expectedPL0); err != nil {
   833  		t.Errorf("failed to wait for process to start: %v", err)
   834  	}
   835  }
   836  
   837  // TestMultiContainerKillAll checks that all process that belong to a container
   838  // are killed when SIGKILL is sent to *all* processes in that container.
   839  func TestMultiContainerKillAll(t *testing.T) {
   840  	rootDir, cleanup, err := testutil.SetupRootDir()
   841  	if err != nil {
   842  		t.Fatalf("error creating root dir: %v", err)
   843  	}
   844  	defer cleanup()
   845  
   846  	conf := testutil.TestConfig(t)
   847  	conf.RootDir = rootDir
   848  
   849  	for _, tc := range []struct {
   850  		killContainer bool
   851  	}{
   852  		{killContainer: true},
   853  		{killContainer: false},
   854  	} {
   855  		app, err := testutil.FindFile("test/cmd/test_app/test_app")
   856  		if err != nil {
   857  			t.Fatal("error finding test_app:", err)
   858  		}
   859  
   860  		// First container will remain intact while the second container is killed.
   861  		specs, ids := createSpecs(
   862  			[]string{app, "task-tree", "--depth=2", "--width=2"},
   863  			[]string{app, "task-tree", "--depth=4", "--width=2"})
   864  		containers, cleanup, err := startContainers(conf, specs, ids)
   865  		if err != nil {
   866  			t.Fatalf("error starting containers: %v", err)
   867  		}
   868  		defer cleanup()
   869  
   870  		// Wait until all processes are created.
   871  		rootProcCount := int(math.Pow(2, 3) - 1)
   872  		if err := waitForProcessCount(containers[0], rootProcCount); err != nil {
   873  			t.Fatalf("error waitting for processes: %v", err)
   874  		}
   875  		procCount := int(math.Pow(2, 5) - 1)
   876  		if err := waitForProcessCount(containers[1], procCount); err != nil {
   877  			t.Fatalf("error waiting for processes: %v", err)
   878  		}
   879  
   880  		// Exec more processes to ensure signal works for exec'd processes too.
   881  		args := &control.ExecArgs{
   882  			Filename: app,
   883  			Argv:     []string{app, "task-tree", "--depth=2", "--width=2"},
   884  		}
   885  		if _, err := containers[1].Execute(args); err != nil {
   886  			t.Fatalf("error exec'ing: %v", err)
   887  		}
   888  		// Wait for these new processes to start.
   889  		procCount += int(math.Pow(2, 3) - 1)
   890  		if err := waitForProcessCount(containers[1], procCount); err != nil {
   891  			t.Fatalf("error waiting for processes: %v", err)
   892  		}
   893  
   894  		if tc.killContainer {
   895  			// First kill the init process to make the container be stopped with
   896  			// processes still running inside.
   897  			containers[1].SignalContainer(unix.SIGKILL, false)
   898  			op := func() error {
   899  				c, err := Load(conf.RootDir, FullID{ContainerID: ids[1]}, LoadOpts{})
   900  				if err != nil {
   901  					return err
   902  				}
   903  				if c.Status != Stopped {
   904  					return fmt.Errorf("container is not stopped")
   905  				}
   906  				return nil
   907  			}
   908  			if err := testutil.Poll(op, 5*time.Second); err != nil {
   909  				t.Fatalf("container did not stop %q: %v", containers[1].ID, err)
   910  			}
   911  		}
   912  
   913  		c, err := Load(conf.RootDir, FullID{ContainerID: ids[1]}, LoadOpts{})
   914  		if err != nil {
   915  			t.Fatalf("failed to load child container %q: %v", c.ID, err)
   916  		}
   917  		// Kill'Em All
   918  		if err := c.SignalContainer(unix.SIGKILL, true); err != nil {
   919  			t.Fatalf("failed to send SIGKILL to container %q: %v", c.ID, err)
   920  		}
   921  
   922  		// Check that all processes are gone.
   923  		if err := waitForProcessCount(containers[1], 0); err != nil {
   924  			t.Fatalf("error waiting for processes: %v", err)
   925  		}
   926  		// Check that root container was not affected.
   927  		if err := waitForProcessCount(containers[0], rootProcCount); err != nil {
   928  			t.Fatalf("error waiting for processes: %v", err)
   929  		}
   930  	}
   931  }
   932  
   933  func TestMultiContainerDestroyNotStarted(t *testing.T) {
   934  	specs, ids := createSpecs(
   935  		[]string{"/bin/sleep", "100"},
   936  		[]string{"/bin/sleep", "100"})
   937  
   938  	conf := testutil.TestConfig(t)
   939  	_, bundleDir, cleanup, err := testutil.SetupContainer(specs[0], conf)
   940  	if err != nil {
   941  		t.Fatalf("error setting up container: %v", err)
   942  	}
   943  	defer cleanup()
   944  
   945  	rootArgs := Args{
   946  		ID:        ids[0],
   947  		Spec:      specs[0],
   948  		BundleDir: bundleDir,
   949  	}
   950  	root, err := New(conf, rootArgs)
   951  	if err != nil {
   952  		t.Fatalf("error creating root container: %v", err)
   953  	}
   954  	defer root.Destroy()
   955  	if err := root.Start(conf); err != nil {
   956  		t.Fatalf("error starting root container: %v", err)
   957  	}
   958  
   959  	// Create and destroy sub-container.
   960  	bundleDir, cleanupSub, err := testutil.SetupBundleDir(specs[1])
   961  	if err != nil {
   962  		t.Fatalf("error setting up container: %v", err)
   963  	}
   964  	defer cleanupSub()
   965  
   966  	args := Args{
   967  		ID:        ids[1],
   968  		Spec:      specs[1],
   969  		BundleDir: bundleDir,
   970  	}
   971  	cont, err := New(conf, args)
   972  	if err != nil {
   973  		t.Fatalf("error creating container: %v", err)
   974  	}
   975  
   976  	// Check that container can be destroyed.
   977  	if err := cont.Destroy(); err != nil {
   978  		t.Fatalf("deleting non-started container failed: %v", err)
   979  	}
   980  }
   981  
   982  // TestMultiContainerDestroyStarting attempts to force a race between start
   983  // and destroy.
   984  func TestMultiContainerDestroyStarting(t *testing.T) {
   985  	cmds := make([][]string, 10)
   986  	for i := range cmds {
   987  		cmds[i] = []string{"/bin/sleep", "100"}
   988  	}
   989  	specs, ids := createSpecs(cmds...)
   990  
   991  	conf := testutil.TestConfig(t)
   992  	rootDir, bundleDir, cleanup, err := testutil.SetupContainer(specs[0], conf)
   993  	if err != nil {
   994  		t.Fatalf("error setting up container: %v", err)
   995  	}
   996  	defer cleanup()
   997  
   998  	rootArgs := Args{
   999  		ID:        ids[0],
  1000  		Spec:      specs[0],
  1001  		BundleDir: bundleDir,
  1002  	}
  1003  	root, err := New(conf, rootArgs)
  1004  	if err != nil {
  1005  		t.Fatalf("error creating root container: %v", err)
  1006  	}
  1007  	defer root.Destroy()
  1008  	if err := root.Start(conf); err != nil {
  1009  		t.Fatalf("error starting root container: %v", err)
  1010  	}
  1011  
  1012  	wg := sync.WaitGroup{}
  1013  	for i := range cmds {
  1014  		if i == 0 {
  1015  			continue // skip root container
  1016  		}
  1017  
  1018  		bundleDir, cleanup, err := testutil.SetupBundleDir(specs[i])
  1019  		if err != nil {
  1020  			t.Fatalf("error setting up container: %v", err)
  1021  		}
  1022  		defer cleanup()
  1023  
  1024  		rootArgs := Args{
  1025  			ID:        ids[i],
  1026  			Spec:      specs[i],
  1027  			BundleDir: bundleDir,
  1028  		}
  1029  		cont, err := New(conf, rootArgs)
  1030  		if err != nil {
  1031  			t.Fatalf("error creating container: %v", err)
  1032  		}
  1033  
  1034  		// Container is not thread safe, so load another instance to run in
  1035  		// concurrently.
  1036  		startCont, err := Load(rootDir, FullID{ContainerID: ids[i]}, LoadOpts{})
  1037  		if err != nil {
  1038  			t.Fatalf("error loading container: %v", err)
  1039  		}
  1040  		wg.Add(1)
  1041  		go func() {
  1042  			defer wg.Done()
  1043  			startCont.Start(conf) // ignore failures, start can fail if destroy runs first.
  1044  		}()
  1045  
  1046  		wg.Add(1)
  1047  		go func() {
  1048  			defer wg.Done()
  1049  			if err := cont.Destroy(); err != nil {
  1050  				t.Errorf("deleting non-started container failed: %v", err)
  1051  			}
  1052  		}()
  1053  	}
  1054  	wg.Wait()
  1055  }
  1056  
  1057  // TestMultiContainerDifferentFilesystems tests that different containers have
  1058  // different root filesystems.
  1059  func TestMultiContainerDifferentFilesystems(t *testing.T) {
  1060  	filename := "/foo"
  1061  	// Root container will create file and then sleep.
  1062  	cmdRoot := []string{"sh", "-c", fmt.Sprintf("touch %q && sleep 100", filename)}
  1063  
  1064  	// Child containers will assert that the file does not exist, and will
  1065  	// then create it.
  1066  	script := fmt.Sprintf("if [ -f %q ]; then exit 1; else touch %q; fi", filename, filename)
  1067  	cmd := []string{"sh", "-c", script}
  1068  
  1069  	rootDir, cleanup, err := testutil.SetupRootDir()
  1070  	if err != nil {
  1071  		t.Fatalf("error creating root dir: %v", err)
  1072  	}
  1073  	defer cleanup()
  1074  
  1075  	conf := testutil.TestConfig(t)
  1076  	conf.RootDir = rootDir
  1077  
  1078  	// Make sure overlay is enabled, and none of the root filesystems are
  1079  	// read-only, otherwise we won't be able to create the file.
  1080  	conf.Overlay = true
  1081  	specs, ids := createSpecs(cmdRoot, cmd, cmd)
  1082  	for _, s := range specs {
  1083  		s.Root.Readonly = false
  1084  	}
  1085  
  1086  	containers, cleanup, err := startContainers(conf, specs, ids)
  1087  	if err != nil {
  1088  		t.Fatalf("error starting containers: %v", err)
  1089  	}
  1090  	defer cleanup()
  1091  
  1092  	// Both child containers should exit successfully.
  1093  	for i, c := range containers {
  1094  		if i == 0 {
  1095  			// Don't wait on the root.
  1096  			continue
  1097  		}
  1098  		if ws, err := c.Wait(); err != nil {
  1099  			t.Errorf("failed to wait for process %s: %v", c.Spec.Process.Args, err)
  1100  		} else if es := ws.ExitStatus(); es != 0 {
  1101  			t.Errorf("process %s exited with non-zero status %d", c.Spec.Process.Args, es)
  1102  		}
  1103  	}
  1104  }
  1105  
  1106  // TestMultiContainerContainerDestroyStress tests that IO operations continue
  1107  // to work after containers have been stopped and gofers killed.
  1108  func TestMultiContainerContainerDestroyStress(t *testing.T) {
  1109  	app, err := testutil.FindFile("test/cmd/test_app/test_app")
  1110  	if err != nil {
  1111  		t.Fatal("error finding test_app:", err)
  1112  	}
  1113  
  1114  	// Setup containers. Root container just reaps children, while the others
  1115  	// perform some IOs. Children are executed in 3 batches of 10. Within the
  1116  	// batch there is overlap between containers starting and being destroyed. In
  1117  	// between batches all containers stop before starting another batch.
  1118  	cmds := [][]string{{app, "reaper"}}
  1119  	const batchSize = 10
  1120  	for i := 0; i < 3*batchSize; i++ {
  1121  		dir, err := ioutil.TempDir(testutil.TmpDir(), "gofer-stop-test")
  1122  		if err != nil {
  1123  			t.Fatal("ioutil.TempDir failed:", err)
  1124  		}
  1125  		defer os.RemoveAll(dir)
  1126  
  1127  		cmd := "find /bin -type f | head | xargs -I SRC cp SRC " + dir
  1128  		cmds = append(cmds, []string{"sh", "-c", cmd})
  1129  	}
  1130  	allSpecs, allIDs := createSpecs(cmds...)
  1131  
  1132  	// Split up the specs and IDs.
  1133  	rootSpec := allSpecs[0]
  1134  	rootID := allIDs[0]
  1135  	childrenSpecs := allSpecs[1:]
  1136  	childrenIDs := allIDs[1:]
  1137  
  1138  	conf := testutil.TestConfig(t)
  1139  	_, bundleDir, cleanup, err := testutil.SetupContainer(rootSpec, conf)
  1140  	if err != nil {
  1141  		t.Fatalf("error setting up container: %v", err)
  1142  	}
  1143  	defer cleanup()
  1144  
  1145  	// Start root container.
  1146  	rootArgs := Args{
  1147  		ID:        rootID,
  1148  		Spec:      rootSpec,
  1149  		BundleDir: bundleDir,
  1150  	}
  1151  	root, err := New(conf, rootArgs)
  1152  	if err != nil {
  1153  		t.Fatalf("error creating root container: %v", err)
  1154  	}
  1155  	if err := root.Start(conf); err != nil {
  1156  		t.Fatalf("error starting root container: %v", err)
  1157  	}
  1158  	defer root.Destroy()
  1159  
  1160  	// Run batches. Each batch starts containers in parallel, then wait and
  1161  	// destroy them before starting another batch.
  1162  	for i := 0; i < len(childrenSpecs); i += batchSize {
  1163  		t.Logf("Starting batch from %d to %d", i, i+batchSize)
  1164  		specs := childrenSpecs[i : i+batchSize]
  1165  		ids := childrenIDs[i : i+batchSize]
  1166  
  1167  		var children []*Container
  1168  		for j, spec := range specs {
  1169  			bundleDir, cleanup, err := testutil.SetupBundleDir(spec)
  1170  			if err != nil {
  1171  				t.Fatalf("error setting up container: %v", err)
  1172  			}
  1173  			defer cleanup()
  1174  
  1175  			args := Args{
  1176  				ID:        ids[j],
  1177  				Spec:      spec,
  1178  				BundleDir: bundleDir,
  1179  			}
  1180  			child, err := New(conf, args)
  1181  			if err != nil {
  1182  				t.Fatalf("error creating container: %v", err)
  1183  			}
  1184  			children = append(children, child)
  1185  
  1186  			if err := child.Start(conf); err != nil {
  1187  				t.Fatalf("error starting container: %v", err)
  1188  			}
  1189  
  1190  			// Give a small gap between containers.
  1191  			time.Sleep(50 * time.Millisecond)
  1192  		}
  1193  		for _, child := range children {
  1194  			ws, err := child.Wait()
  1195  			if err != nil {
  1196  				t.Fatalf("waiting for container: %v", err)
  1197  			}
  1198  			if !ws.Exited() || ws.ExitStatus() != 0 {
  1199  				t.Fatalf("container failed, waitStatus: %x (%d)", ws, ws.ExitStatus())
  1200  			}
  1201  			if err := child.Destroy(); err != nil {
  1202  				t.Fatalf("error destroying container: %v", err)
  1203  			}
  1204  		}
  1205  	}
  1206  }
  1207  
  1208  // Test that pod shared mounts are properly mounted in 2 containers and that
  1209  // changes from one container is reflected in the other.
  1210  func TestMultiContainerSharedMount(t *testing.T) {
  1211  	for name, conf := range configs(t, all...) {
  1212  		t.Run(name, func(t *testing.T) {
  1213  			rootDir, cleanup, err := testutil.SetupRootDir()
  1214  			if err != nil {
  1215  				t.Fatalf("error creating root dir: %v", err)
  1216  			}
  1217  			defer cleanup()
  1218  			conf.RootDir = rootDir
  1219  
  1220  			// Setup the containers.
  1221  			sleep := []string{"sleep", "100"}
  1222  			podSpec, ids := createSpecs(sleep, sleep)
  1223  			mnt0 := specs.Mount{
  1224  				Destination: "/mydir/test",
  1225  				Source:      "/some/dir",
  1226  				Type:        "tmpfs",
  1227  				Options:     nil,
  1228  			}
  1229  			podSpec[0].Mounts = append(podSpec[0].Mounts, mnt0)
  1230  
  1231  			mnt1 := mnt0
  1232  			mnt1.Destination = "/mydir2/test2"
  1233  			podSpec[1].Mounts = append(podSpec[1].Mounts, mnt1)
  1234  
  1235  			createSharedMount(mnt0, "test-mount", podSpec...)
  1236  
  1237  			containers, cleanup, err := startContainers(conf, podSpec, ids)
  1238  			if err != nil {
  1239  				t.Fatalf("error starting containers: %v", err)
  1240  			}
  1241  			defer cleanup()
  1242  
  1243  			file0 := path.Join(mnt0.Destination, "abc")
  1244  			file1 := path.Join(mnt1.Destination, "abc")
  1245  			execs := []execDesc{
  1246  				{
  1247  					c:    containers[0],
  1248  					cmd:  []string{"/usr/bin/test", "-d", mnt0.Destination},
  1249  					name: "directory is mounted in container0",
  1250  				},
  1251  				{
  1252  					c:    containers[1],
  1253  					cmd:  []string{"/usr/bin/test", "-d", mnt1.Destination},
  1254  					name: "directory is mounted in container1",
  1255  				},
  1256  				{
  1257  					c:    containers[0],
  1258  					cmd:  []string{"/bin/touch", file0},
  1259  					name: "create file in container0",
  1260  				},
  1261  				{
  1262  					c:    containers[0],
  1263  					cmd:  []string{"/usr/bin/test", "-f", file0},
  1264  					name: "file appears in container0",
  1265  				},
  1266  				{
  1267  					c:    containers[1],
  1268  					cmd:  []string{"/usr/bin/test", "-f", file1},
  1269  					name: "file appears in container1",
  1270  				},
  1271  				{
  1272  					c:    containers[1],
  1273  					cmd:  []string{"/bin/rm", file1},
  1274  					name: "remove file from container1",
  1275  				},
  1276  				{
  1277  					c:    containers[0],
  1278  					cmd:  []string{"/usr/bin/test", "!", "-f", file0},
  1279  					name: "file removed from container0",
  1280  				},
  1281  				{
  1282  					c:    containers[1],
  1283  					cmd:  []string{"/usr/bin/test", "!", "-f", file1},
  1284  					name: "file removed from container1",
  1285  				},
  1286  				{
  1287  					c:    containers[1],
  1288  					cmd:  []string{"/bin/mkdir", file1},
  1289  					name: "create directory in container1",
  1290  				},
  1291  				{
  1292  					c:    containers[0],
  1293  					cmd:  []string{"/usr/bin/test", "-d", file0},
  1294  					name: "dir appears in container0",
  1295  				},
  1296  				{
  1297  					c:    containers[1],
  1298  					cmd:  []string{"/usr/bin/test", "-d", file1},
  1299  					name: "dir appears in container1",
  1300  				},
  1301  				{
  1302  					c:    containers[0],
  1303  					cmd:  []string{"/bin/rmdir", file0},
  1304  					name: "remove directory from container0",
  1305  				},
  1306  				{
  1307  					c:    containers[0],
  1308  					cmd:  []string{"/usr/bin/test", "!", "-d", file0},
  1309  					name: "dir removed from container0",
  1310  				},
  1311  				{
  1312  					c:    containers[1],
  1313  					cmd:  []string{"/usr/bin/test", "!", "-d", file1},
  1314  					name: "dir removed from container1",
  1315  				},
  1316  			}
  1317  			execMany(t, execs)
  1318  		})
  1319  	}
  1320  }
  1321  
  1322  // Test that pod mounts are mounted as readonly when requested.
  1323  func TestMultiContainerSharedMountReadonly(t *testing.T) {
  1324  	for name, conf := range configs(t, all...) {
  1325  		t.Run(name, func(t *testing.T) {
  1326  			rootDir, cleanup, err := testutil.SetupRootDir()
  1327  			if err != nil {
  1328  				t.Fatalf("error creating root dir: %v", err)
  1329  			}
  1330  			defer cleanup()
  1331  			conf.RootDir = rootDir
  1332  
  1333  			// Setup the containers.
  1334  			sleep := []string{"sleep", "100"}
  1335  			podSpec, ids := createSpecs(sleep, sleep)
  1336  			mnt0 := specs.Mount{
  1337  				Destination: "/mydir/test",
  1338  				Source:      "/some/dir",
  1339  				Type:        "tmpfs",
  1340  				Options:     []string{"ro"},
  1341  			}
  1342  			podSpec[0].Mounts = append(podSpec[0].Mounts, mnt0)
  1343  
  1344  			mnt1 := mnt0
  1345  			mnt1.Destination = "/mydir2/test2"
  1346  			podSpec[1].Mounts = append(podSpec[1].Mounts, mnt1)
  1347  
  1348  			createSharedMount(mnt0, "test-mount", podSpec...)
  1349  
  1350  			containers, cleanup, err := startContainers(conf, podSpec, ids)
  1351  			if err != nil {
  1352  				t.Fatalf("error starting containers: %v", err)
  1353  			}
  1354  			defer cleanup()
  1355  
  1356  			file0 := path.Join(mnt0.Destination, "abc")
  1357  			file1 := path.Join(mnt1.Destination, "abc")
  1358  			execs := []execDesc{
  1359  				{
  1360  					c:    containers[0],
  1361  					cmd:  []string{"/usr/bin/test", "-d", mnt0.Destination},
  1362  					name: "directory is mounted in container0",
  1363  				},
  1364  				{
  1365  					c:    containers[1],
  1366  					cmd:  []string{"/usr/bin/test", "-d", mnt1.Destination},
  1367  					name: "directory is mounted in container1",
  1368  				},
  1369  				{
  1370  					c:    containers[0],
  1371  					cmd:  []string{"/bin/touch", file0},
  1372  					want: 1,
  1373  					name: "fails to write to container0",
  1374  				},
  1375  				{
  1376  					c:    containers[1],
  1377  					cmd:  []string{"/bin/touch", file1},
  1378  					want: 1,
  1379  					name: "fails to write to container1",
  1380  				},
  1381  			}
  1382  			execMany(t, execs)
  1383  		})
  1384  	}
  1385  }
  1386  
  1387  // Test that shared pod mounts continue to work after container is restarted.
  1388  func TestMultiContainerSharedMountRestart(t *testing.T) {
  1389  	for name, conf := range configs(t, all...) {
  1390  		t.Run(name, func(t *testing.T) {
  1391  			rootDir, cleanup, err := testutil.SetupRootDir()
  1392  			if err != nil {
  1393  				t.Fatalf("error creating root dir: %v", err)
  1394  			}
  1395  			defer cleanup()
  1396  			conf.RootDir = rootDir
  1397  
  1398  			// Setup the containers.
  1399  			sleep := []string{"sleep", "100"}
  1400  			podSpec, ids := createSpecs(sleep, sleep)
  1401  			mnt0 := specs.Mount{
  1402  				Destination: "/mydir/test",
  1403  				Source:      "/some/dir",
  1404  				Type:        "tmpfs",
  1405  				Options:     nil,
  1406  			}
  1407  			podSpec[0].Mounts = append(podSpec[0].Mounts, mnt0)
  1408  
  1409  			mnt1 := mnt0
  1410  			mnt1.Destination = "/mydir2/test2"
  1411  			podSpec[1].Mounts = append(podSpec[1].Mounts, mnt1)
  1412  
  1413  			createSharedMount(mnt0, "test-mount", podSpec...)
  1414  
  1415  			containers, cleanup, err := startContainers(conf, podSpec, ids)
  1416  			if err != nil {
  1417  				t.Fatalf("error starting containers: %v", err)
  1418  			}
  1419  			defer cleanup()
  1420  
  1421  			file0 := path.Join(mnt0.Destination, "abc")
  1422  			file1 := path.Join(mnt1.Destination, "abc")
  1423  			execs := []execDesc{
  1424  				{
  1425  					c:    containers[0],
  1426  					cmd:  []string{"/bin/touch", file0},
  1427  					name: "create file in container0",
  1428  				},
  1429  				{
  1430  					c:    containers[0],
  1431  					cmd:  []string{"/usr/bin/test", "-f", file0},
  1432  					name: "file appears in container0",
  1433  				},
  1434  				{
  1435  					c:    containers[1],
  1436  					cmd:  []string{"/usr/bin/test", "-f", file1},
  1437  					name: "file appears in container1",
  1438  				},
  1439  			}
  1440  			execMany(t, execs)
  1441  
  1442  			containers[1].Destroy()
  1443  
  1444  			bundleDir, cleanup, err := testutil.SetupBundleDir(podSpec[1])
  1445  			if err != nil {
  1446  				t.Fatalf("error restarting container: %v", err)
  1447  			}
  1448  			defer cleanup()
  1449  
  1450  			args := Args{
  1451  				ID:        ids[1],
  1452  				Spec:      podSpec[1],
  1453  				BundleDir: bundleDir,
  1454  			}
  1455  			containers[1], err = New(conf, args)
  1456  			if err != nil {
  1457  				t.Fatalf("error creating container: %v", err)
  1458  			}
  1459  			if err := containers[1].Start(conf); err != nil {
  1460  				t.Fatalf("error starting container: %v", err)
  1461  			}
  1462  
  1463  			execs = []execDesc{
  1464  				{
  1465  					c:    containers[0],
  1466  					cmd:  []string{"/usr/bin/test", "-f", file0},
  1467  					name: "file is still in container0",
  1468  				},
  1469  				{
  1470  					c:    containers[1],
  1471  					cmd:  []string{"/usr/bin/test", "-f", file1},
  1472  					name: "file is still in container1",
  1473  				},
  1474  				{
  1475  					c:    containers[1],
  1476  					cmd:  []string{"/bin/rm", file1},
  1477  					name: "file removed from container1",
  1478  				},
  1479  				{
  1480  					c:    containers[0],
  1481  					cmd:  []string{"/usr/bin/test", "!", "-f", file0},
  1482  					name: "file removed from container0",
  1483  				},
  1484  				{
  1485  					c:    containers[1],
  1486  					cmd:  []string{"/usr/bin/test", "!", "-f", file1},
  1487  					name: "file removed from container1",
  1488  				},
  1489  			}
  1490  			execMany(t, execs)
  1491  		})
  1492  	}
  1493  }
  1494  
  1495  // Test that unsupported pod mounts options are ignored when matching master and
  1496  // replica mounts.
  1497  func TestMultiContainerSharedMountUnsupportedOptions(t *testing.T) {
  1498  	for name, conf := range configs(t, all...) {
  1499  		t.Run(name, func(t *testing.T) {
  1500  			rootDir, cleanup, err := testutil.SetupRootDir()
  1501  			if err != nil {
  1502  				t.Fatalf("error creating root dir: %v", err)
  1503  			}
  1504  			defer cleanup()
  1505  			conf.RootDir = rootDir
  1506  
  1507  			// Setup the containers.
  1508  			sleep := []string{"/bin/sleep", "100"}
  1509  			podSpec, ids := createSpecs(sleep, sleep)
  1510  			mnt0 := specs.Mount{
  1511  				Destination: "/mydir/test",
  1512  				Source:      "/some/dir",
  1513  				Type:        "tmpfs",
  1514  				Options:     []string{"rw", "relatime"},
  1515  			}
  1516  			podSpec[0].Mounts = append(podSpec[0].Mounts, mnt0)
  1517  
  1518  			mnt1 := mnt0
  1519  			mnt1.Destination = "/mydir2/test2"
  1520  			mnt1.Options = []string{"rw", "nosuid"}
  1521  			podSpec[1].Mounts = append(podSpec[1].Mounts, mnt1)
  1522  
  1523  			createSharedMount(mnt0, "test-mount", podSpec...)
  1524  
  1525  			containers, cleanup, err := startContainers(conf, podSpec, ids)
  1526  			if err != nil {
  1527  				t.Fatalf("error starting containers: %v", err)
  1528  			}
  1529  			defer cleanup()
  1530  
  1531  			execs := []execDesc{
  1532  				{
  1533  					c:    containers[0],
  1534  					cmd:  []string{"/usr/bin/test", "-d", mnt0.Destination},
  1535  					name: "directory is mounted in container0",
  1536  				},
  1537  				{
  1538  					c:    containers[1],
  1539  					cmd:  []string{"/usr/bin/test", "-d", mnt1.Destination},
  1540  					name: "directory is mounted in container1",
  1541  				},
  1542  			}
  1543  			execMany(t, execs)
  1544  		})
  1545  	}
  1546  }
  1547  
  1548  // Test that one container can send an FD to another container, even though
  1549  // they have distinct MountNamespaces.
  1550  func TestMultiContainerMultiRootCanHandleFDs(t *testing.T) {
  1551  	app, err := testutil.FindFile("test/cmd/test_app/test_app")
  1552  	if err != nil {
  1553  		t.Fatal("error finding test_app:", err)
  1554  	}
  1555  
  1556  	// We set up two containers with one shared mount that is used for a
  1557  	// shared socket. The first container will send an FD over the socket
  1558  	// to the second container. The FD corresponds to a file in the first
  1559  	// container's mount namespace that is not part of the second
  1560  	// container's mount namespace. However, the second container still
  1561  	// should be able to read the FD.
  1562  
  1563  	// Create a shared mount where we will put the socket.
  1564  	sharedMnt := specs.Mount{
  1565  		Destination: "/mydir/test",
  1566  		Type:        "tmpfs",
  1567  		// Shared mounts need a Source, even for tmpfs. It is only used
  1568  		// to match up different shared mounts inside the pod.
  1569  		Source: "/some/dir",
  1570  	}
  1571  	socketPath := filepath.Join(sharedMnt.Destination, "socket")
  1572  
  1573  	// Create a writeable tmpfs mount where the FD sender app will create
  1574  	// files to send. This will only be mounted in the FD sender.
  1575  	writeableMnt := specs.Mount{
  1576  		Destination: "/tmp",
  1577  		Type:        "tmpfs",
  1578  	}
  1579  
  1580  	rootDir, cleanup, err := testutil.SetupRootDir()
  1581  	if err != nil {
  1582  		t.Fatalf("error creating root dir: %v", err)
  1583  	}
  1584  	defer cleanup()
  1585  
  1586  	conf := testutil.TestConfig(t)
  1587  	conf.RootDir = rootDir
  1588  
  1589  	// Create the specs.
  1590  	specs, ids := createSpecs(
  1591  		[]string{"sleep", "1000"},
  1592  		[]string{app, "fd_sender", "--socket", socketPath},
  1593  		[]string{app, "fd_receiver", "--socket", socketPath},
  1594  	)
  1595  	createSharedMount(sharedMnt, "shared-mount", specs...)
  1596  	specs[1].Mounts = append(specs[2].Mounts, sharedMnt, writeableMnt)
  1597  	specs[2].Mounts = append(specs[1].Mounts, sharedMnt)
  1598  
  1599  	containers, cleanup, err := startContainers(conf, specs, ids)
  1600  	if err != nil {
  1601  		t.Fatalf("error starting containers: %v", err)
  1602  	}
  1603  	defer cleanup()
  1604  
  1605  	// Both containers should exit successfully.
  1606  	for _, c := range containers[1:] {
  1607  		if ws, err := c.Wait(); err != nil {
  1608  			t.Errorf("failed to wait for process %s: %v", c.Spec.Process.Args, err)
  1609  		} else if es := ws.ExitStatus(); es != 0 {
  1610  			t.Errorf("process %s exited with non-zero status %d", c.Spec.Process.Args, es)
  1611  		}
  1612  	}
  1613  }
  1614  
  1615  // Test that container is destroyed when Gofer is killed.
  1616  func TestMultiContainerGoferKilled(t *testing.T) {
  1617  	rootDir, cleanup, err := testutil.SetupRootDir()
  1618  	if err != nil {
  1619  		t.Fatalf("error creating root dir: %v", err)
  1620  	}
  1621  	defer cleanup()
  1622  
  1623  	conf := testutil.TestConfig(t)
  1624  	conf.RootDir = rootDir
  1625  
  1626  	sleep := []string{"sleep", "100"}
  1627  	specs, ids := createSpecs(sleep, sleep, sleep)
  1628  	containers, cleanup, err := startContainers(conf, specs, ids)
  1629  	if err != nil {
  1630  		t.Fatalf("error starting containers: %v", err)
  1631  	}
  1632  	defer cleanup()
  1633  
  1634  	// Ensure container is running
  1635  	c := containers[2]
  1636  	expectedPL := []*control.Process{
  1637  		newProcessBuilder().PID(3).Cmd("sleep").Process(),
  1638  	}
  1639  	if err := waitForProcessList(c, expectedPL); err != nil {
  1640  		t.Errorf("failed to wait for sleep to start: %v", err)
  1641  	}
  1642  
  1643  	// Kill container's gofer.
  1644  	if err := unix.Kill(c.GoferPid, unix.SIGKILL); err != nil {
  1645  		t.Fatalf("unix.Kill(%d, SIGKILL)=%v", c.GoferPid, err)
  1646  	}
  1647  
  1648  	// Wait until container stops.
  1649  	if err := waitForProcessList(c, nil); err != nil {
  1650  		t.Errorf("Container %q was not stopped after gofer death: %v", c.ID, err)
  1651  	}
  1652  
  1653  	// Check that container isn't running anymore.
  1654  	if _, err := execute(c, "/bin/true"); err == nil {
  1655  		t.Fatalf("Container %q was not stopped after gofer death", c.ID)
  1656  	}
  1657  
  1658  	// Check that other containers are unaffected.
  1659  	for i, c := range containers {
  1660  		if i == 2 {
  1661  			continue // container[2] has been killed.
  1662  		}
  1663  		pl := []*control.Process{
  1664  			newProcessBuilder().PID(kernel.ThreadID(i + 1)).Cmd("sleep").Process(),
  1665  		}
  1666  		if err := waitForProcessList(c, pl); err != nil {
  1667  			t.Errorf("Container %q was affected by another container: %v", c.ID, err)
  1668  		}
  1669  		if _, err := execute(c, "/bin/true"); err != nil {
  1670  			t.Fatalf("Container %q was affected by another container: %v", c.ID, err)
  1671  		}
  1672  	}
  1673  
  1674  	// Kill root container's gofer to bring entire sandbox down.
  1675  	c = containers[0]
  1676  	if err := unix.Kill(c.GoferPid, unix.SIGKILL); err != nil {
  1677  		t.Fatalf("unix.Kill(%d, SIGKILL)=%v", c.GoferPid, err)
  1678  	}
  1679  
  1680  	// Wait until sandbox stops. waitForProcessList will loop until sandbox exits
  1681  	// and RPC errors out.
  1682  	impossiblePL := []*control.Process{
  1683  		newProcessBuilder().Cmd("non-existent-process").Process(),
  1684  	}
  1685  	if err := waitForProcessList(c, impossiblePL); err == nil {
  1686  		t.Fatalf("Sandbox was not killed after gofer death")
  1687  	}
  1688  
  1689  	// Check that entire sandbox isn't running anymore.
  1690  	for _, c := range containers {
  1691  		if _, err := execute(c, "/bin/true"); err == nil {
  1692  			t.Fatalf("Container %q was not stopped after gofer death", c.ID)
  1693  		}
  1694  	}
  1695  }
  1696  
  1697  func TestMultiContainerLoadSandbox(t *testing.T) {
  1698  	sleep := []string{"sleep", "100"}
  1699  	specs, ids := createSpecs(sleep, sleep, sleep)
  1700  
  1701  	rootDir, cleanup, err := testutil.SetupRootDir()
  1702  	if err != nil {
  1703  		t.Fatalf("error creating root dir: %v", err)
  1704  	}
  1705  	defer cleanup()
  1706  
  1707  	conf := testutil.TestConfig(t)
  1708  	conf.RootDir = rootDir
  1709  
  1710  	// Create containers for the sandbox.
  1711  	wants, cleanup, err := startContainers(conf, specs, ids)
  1712  	if err != nil {
  1713  		t.Fatalf("error starting containers: %v", err)
  1714  	}
  1715  	defer cleanup()
  1716  
  1717  	// Then create unrelated containers.
  1718  	for i := 0; i < 3; i++ {
  1719  		specs, ids = createSpecs(sleep, sleep, sleep)
  1720  		_, cleanup, err = startContainers(conf, specs, ids)
  1721  		if err != nil {
  1722  			t.Fatalf("error starting containers: %v", err)
  1723  		}
  1724  		defer cleanup()
  1725  	}
  1726  
  1727  	// Create an unrelated directory under root.
  1728  	dir := filepath.Join(conf.RootDir, "not-a-container")
  1729  	if err := os.MkdirAll(dir, 0755); err != nil {
  1730  		t.Fatalf("os.MkdirAll(%q)=%v", dir, err)
  1731  	}
  1732  
  1733  	// Create a valid but empty container directory.
  1734  	randomCID := testutil.RandomContainerID()
  1735  	dir = filepath.Join(conf.RootDir, randomCID)
  1736  	if err := os.MkdirAll(dir, 0755); err != nil {
  1737  		t.Fatalf("os.MkdirAll(%q)=%v", dir, err)
  1738  	}
  1739  
  1740  	// Load the sandbox and check that the correct containers were returned.
  1741  	id := wants[0].Sandbox.ID
  1742  	gots, err := loadSandbox(conf.RootDir, id)
  1743  	if err != nil {
  1744  		t.Fatalf("loadSandbox()=%v", err)
  1745  	}
  1746  	wantIDs := make(map[string]struct{})
  1747  	for _, want := range wants {
  1748  		wantIDs[want.ID] = struct{}{}
  1749  	}
  1750  	for _, got := range gots {
  1751  		if got.Sandbox.ID != id {
  1752  			t.Errorf("wrong sandbox ID, got: %v, want: %v", got.Sandbox.ID, id)
  1753  		}
  1754  		if _, ok := wantIDs[got.ID]; !ok {
  1755  			t.Errorf("wrong container ID, got: %v, wants: %v", got.ID, wantIDs)
  1756  		}
  1757  		delete(wantIDs, got.ID)
  1758  	}
  1759  	if len(wantIDs) != 0 {
  1760  		t.Errorf("containers not found: %v", wantIDs)
  1761  	}
  1762  }
  1763  
  1764  // TestMultiContainerRunNonRoot checks that child container can be configured
  1765  // when running as non-privileged user.
  1766  func TestMultiContainerRunNonRoot(t *testing.T) {
  1767  	cmdRoot := []string{"/bin/sleep", "100"}
  1768  	cmdSub := []string{"/bin/true"}
  1769  	podSpecs, ids := createSpecs(cmdRoot, cmdSub)
  1770  
  1771  	// User running inside container can't list '$TMP/blocked' and would fail to
  1772  	// mount it.
  1773  	blocked, err := ioutil.TempDir(testutil.TmpDir(), "blocked")
  1774  	if err != nil {
  1775  		t.Fatalf("ioutil.TempDir() failed: %v", err)
  1776  	}
  1777  	if err := os.Chmod(blocked, 0700); err != nil {
  1778  		t.Fatalf("os.MkDir(%q) failed: %v", blocked, err)
  1779  	}
  1780  	dir := path.Join(blocked, "test")
  1781  	if err := os.Mkdir(dir, 0755); err != nil {
  1782  		t.Fatalf("os.MkDir(%q) failed: %v", dir, err)
  1783  	}
  1784  
  1785  	src, err := ioutil.TempDir(testutil.TmpDir(), "src")
  1786  	if err != nil {
  1787  		t.Fatalf("ioutil.TempDir() failed: %v", err)
  1788  	}
  1789  
  1790  	// Set a random user/group with no access to "blocked" dir.
  1791  	podSpecs[1].Process.User.UID = 343
  1792  	podSpecs[1].Process.User.GID = 2401
  1793  	podSpecs[1].Process.Capabilities = nil
  1794  
  1795  	podSpecs[1].Mounts = append(podSpecs[1].Mounts, specs.Mount{
  1796  		Destination: dir,
  1797  		Source:      src,
  1798  		Type:        "bind",
  1799  	})
  1800  
  1801  	rootDir, cleanup, err := testutil.SetupRootDir()
  1802  	if err != nil {
  1803  		t.Fatalf("error creating root dir: %v", err)
  1804  	}
  1805  	defer cleanup()
  1806  
  1807  	conf := testutil.TestConfig(t)
  1808  	conf.RootDir = rootDir
  1809  
  1810  	pod, cleanup, err := startContainers(conf, podSpecs, ids)
  1811  	if err != nil {
  1812  		t.Fatalf("error starting containers: %v", err)
  1813  	}
  1814  	defer cleanup()
  1815  
  1816  	// Once all containers are started, wait for the child container to exit.
  1817  	// This means that the volume was mounted properly.
  1818  	ws, err := pod[1].Wait()
  1819  	if err != nil {
  1820  		t.Fatalf("running child container: %v", err)
  1821  	}
  1822  	if !ws.Exited() || ws.ExitStatus() != 0 {
  1823  		t.Fatalf("child container failed, waitStatus: %v", ws)
  1824  	}
  1825  }
  1826  
  1827  // TestMultiContainerHomeEnvDir tests that the HOME environment variable is set
  1828  // for root containers, sub-containers, and exec'ed processes.
  1829  func TestMultiContainerHomeEnvDir(t *testing.T) {
  1830  	// NOTE: Don't use overlay since we need changes to persist to the temp dir
  1831  	// outside the sandbox.
  1832  	for testName, conf := range configs(t, noOverlay...) {
  1833  		t.Run(testName, func(t *testing.T) {
  1834  
  1835  			rootDir, cleanup, err := testutil.SetupRootDir()
  1836  			if err != nil {
  1837  				t.Fatalf("error creating root dir: %v", err)
  1838  			}
  1839  			defer cleanup()
  1840  			conf.RootDir = rootDir
  1841  
  1842  			// Create temp files we can write the value of $HOME to.
  1843  			homeDirs := map[string]*os.File{}
  1844  			for _, name := range []string{"root", "sub", "exec"} {
  1845  				homeFile, err := ioutil.TempFile(testutil.TmpDir(), name)
  1846  				if err != nil {
  1847  					t.Fatalf("creating temp file: %v", err)
  1848  				}
  1849  				homeDirs[name] = homeFile
  1850  			}
  1851  
  1852  			// We will sleep in the root container in order to ensure that the root
  1853  			//container doesn't terminate before sub containers can be created.
  1854  			rootCmd := []string{"/bin/sh", "-c", fmt.Sprintf(`printf "$HOME" > %s; sleep 1000`, homeDirs["root"].Name())}
  1855  			subCmd := []string{"/bin/sh", "-c", fmt.Sprintf(`printf "$HOME" > %s`, homeDirs["sub"].Name())}
  1856  			execCmd := fmt.Sprintf(`printf "$HOME" > %s`, homeDirs["exec"].Name())
  1857  
  1858  			// Setup the containers, a root container and sub container.
  1859  			specConfig, ids := createSpecs(rootCmd, subCmd)
  1860  			containers, cleanup, err := startContainers(conf, specConfig, ids)
  1861  			if err != nil {
  1862  				t.Fatalf("error starting containers: %v", err)
  1863  			}
  1864  			defer cleanup()
  1865  
  1866  			// Exec into the root container synchronously.
  1867  			if _, err := execute(containers[0], "/bin/sh", "-c", execCmd); err != nil {
  1868  				t.Errorf("error executing %+v: %v", execCmd, err)
  1869  			}
  1870  
  1871  			// Wait for the subcontainer to finish.
  1872  			_, err = containers[1].Wait()
  1873  			if err != nil {
  1874  				t.Errorf("wait on child container: %v", err)
  1875  			}
  1876  
  1877  			// Wait until after `env` has executed.
  1878  			expectedProc := newProcessBuilder().Cmd("sleep").Process()
  1879  			if err := waitForProcess(containers[0], expectedProc); err != nil {
  1880  				t.Errorf("failed to wait for sleep to start: %v", err)
  1881  			}
  1882  
  1883  			// Check the written files.
  1884  			for name, tmpFile := range homeDirs {
  1885  				dirBytes, err := ioutil.ReadAll(tmpFile)
  1886  				if err != nil {
  1887  					t.Fatalf("reading %s temp file: %v", name, err)
  1888  				}
  1889  				got := string(dirBytes)
  1890  
  1891  				want := "/"
  1892  				if got != want {
  1893  					t.Errorf("%s $HOME incorrect: got: %q, want: %q", name, got, want)
  1894  				}
  1895  			}
  1896  
  1897  		})
  1898  	}
  1899  }
  1900  
  1901  func TestMultiContainerEvent(t *testing.T) {
  1902  	conf := testutil.TestConfig(t)
  1903  	rootDir, cleanup, err := testutil.SetupRootDir()
  1904  	if err != nil {
  1905  		t.Fatalf("error creating root dir: %v", err)
  1906  	}
  1907  	defer cleanup()
  1908  	conf.RootDir = rootDir
  1909  
  1910  	// Setup the containers.
  1911  	sleep := []string{"/bin/sleep", "100"}
  1912  	busy := []string{"/bin/bash", "-c", "i=0 ; while true ; do (( i += 1 )) ; done"}
  1913  	quick := []string{"/bin/true"}
  1914  	podSpec, ids := createSpecs(sleep, busy, quick)
  1915  	containers, cleanup, err := startContainers(conf, podSpec, ids)
  1916  	if err != nil {
  1917  		t.Fatalf("error starting containers: %v", err)
  1918  	}
  1919  	defer cleanup()
  1920  
  1921  	t.Logf("Running container sleep %s", containers[0].ID)
  1922  	t.Logf("Running container busy %s", containers[1].ID)
  1923  	t.Logf("Running container quick %s", containers[2].ID)
  1924  
  1925  	// Wait for last container to stabilize the process count that is
  1926  	// checked further below.
  1927  	if ws, err := containers[2].Wait(); err != nil || ws != 0 {
  1928  		t.Fatalf("Container.Wait, status: %v, err: %v", ws, err)
  1929  	}
  1930  	expectedPL := []*control.Process{
  1931  		newProcessBuilder().Cmd("sleep").Process(),
  1932  	}
  1933  	if err := waitForProcessList(containers[0], expectedPL); err != nil {
  1934  		t.Errorf("failed to wait for sleep to start: %v", err)
  1935  	}
  1936  	expectedPL = []*control.Process{
  1937  		newProcessBuilder().Cmd("bash").Process(),
  1938  	}
  1939  	if err := waitForProcessList(containers[1], expectedPL); err != nil {
  1940  		t.Errorf("failed to wait for bash to start: %v", err)
  1941  	}
  1942  
  1943  	// Check events for running containers.
  1944  	for _, cont := range containers[:2] {
  1945  		ret, err := cont.Event()
  1946  		if err != nil {
  1947  			t.Errorf("Container.Event(%q): %v", cont.ID, err)
  1948  		}
  1949  		evt := ret.Event
  1950  		if want := "stats"; evt.Type != want {
  1951  			t.Errorf("Wrong event type, cid: %q, want: %s, got: %s", cont.ID, want, evt.Type)
  1952  		}
  1953  		if cont.ID != evt.ID {
  1954  			t.Errorf("Wrong container ID, want: %s, got: %s", cont.ID, evt.ID)
  1955  		}
  1956  		// One process per remaining container.
  1957  		if got, want := evt.Data.Pids.Current, uint64(2); got != want {
  1958  			t.Errorf("Wrong number of PIDs, cid: %q, want: %d, got: %d", cont.ID, want, got)
  1959  		}
  1960  
  1961  		// The exited container should always have a usage of zero.
  1962  		if exited := ret.ContainerUsage[containers[2].ID]; exited != 0 {
  1963  			t.Errorf("Exited container should report 0 CPU usage, got: %d", exited)
  1964  		}
  1965  	}
  1966  
  1967  	// Check that CPU reported by busy container is higher than sleep.
  1968  	cb := func() error {
  1969  		sleepEvt, err := containers[0].Event()
  1970  		if err != nil {
  1971  			return &backoff.PermanentError{Err: err}
  1972  		}
  1973  		sleepUsage := sleepEvt.Event.Data.CPU.Usage.Total
  1974  
  1975  		busyEvt, err := containers[1].Event()
  1976  		if err != nil {
  1977  			return &backoff.PermanentError{Err: err}
  1978  		}
  1979  		busyUsage := busyEvt.Event.Data.CPU.Usage.Total
  1980  
  1981  		if busyUsage <= sleepUsage {
  1982  			t.Logf("Busy container usage lower than sleep (busy: %d, sleep: %d), retrying...", busyUsage, sleepUsage)
  1983  			return fmt.Errorf("Busy container should have higher usage than sleep, busy: %d, sleep: %d", busyUsage, sleepUsage)
  1984  		}
  1985  		return nil
  1986  	}
  1987  	// Give time for busy container to run and use more CPU than sleep.
  1988  	if err := testutil.Poll(cb, 10*time.Second); err != nil {
  1989  		t.Fatal(err)
  1990  	}
  1991  
  1992  	// Check that stopped and destroyed containers return error.
  1993  	if err := containers[1].Destroy(); err != nil {
  1994  		t.Fatalf("container.Destroy: %v", err)
  1995  	}
  1996  	for _, cont := range containers[1:] {
  1997  		if _, err := cont.Event(); err == nil {
  1998  			t.Errorf("Container.Event() should have failed, cid: %q, state: %v", cont.ID, cont.Status)
  1999  		}
  2000  	}
  2001  }
  2002  
  2003  // Tests that duplicate variables in the spec are merged into a single one.
  2004  func TestDuplicateEnvVariable(t *testing.T) {
  2005  	conf := testutil.TestConfig(t)
  2006  
  2007  	rootDir, cleanup, err := testutil.SetupRootDir()
  2008  	if err != nil {
  2009  		t.Fatalf("error creating root dir: %v", err)
  2010  	}
  2011  	defer cleanup()
  2012  	conf.RootDir = rootDir
  2013  
  2014  	// Create files to dump `env` output.
  2015  	files := [3]*os.File{}
  2016  	for i := 0; i < len(files); i++ {
  2017  		var err error
  2018  		files[i], err = ioutil.TempFile(testutil.TmpDir(), "env-var-test")
  2019  		if err != nil {
  2020  			t.Fatalf("creating temp file: %v", err)
  2021  		}
  2022  		defer files[i].Close()
  2023  		defer os.Remove(files[i].Name())
  2024  	}
  2025  
  2026  	// Setup the containers. Use root container to test exec too.
  2027  	cmd1 := fmt.Sprintf("env > %q; sleep 1000", files[0].Name())
  2028  	cmd2 := fmt.Sprintf("env > %q", files[1].Name())
  2029  	cmdExec := fmt.Sprintf("env > %q", files[2].Name())
  2030  	testSpecs, ids := createSpecs([]string{"/bin/sh", "-c", cmd1}, []string{"/bin/sh", "-c", cmd2})
  2031  	testSpecs[0].Process.Env = append(testSpecs[0].Process.Env, "VAR=foo", "VAR=bar")
  2032  	testSpecs[1].Process.Env = append(testSpecs[1].Process.Env, "VAR=foo", "VAR=bar")
  2033  
  2034  	containers, cleanup, err := startContainers(conf, testSpecs, ids)
  2035  	if err != nil {
  2036  		t.Fatalf("error starting containers: %v", err)
  2037  	}
  2038  	defer cleanup()
  2039  
  2040  	// Wait until after `env` has executed.
  2041  	expectedProc := newProcessBuilder().Cmd("sleep").Process()
  2042  	if err := waitForProcess(containers[0], expectedProc); err != nil {
  2043  		t.Errorf("failed to wait for sleep to start: %v", err)
  2044  	}
  2045  	if ws, err := containers[1].Wait(); err != nil {
  2046  		t.Errorf("failed to wait container 1: %v", err)
  2047  	} else if es := ws.ExitStatus(); es != 0 {
  2048  		t.Errorf("container %s exited with non-zero status: %v", containers[1].ID, es)
  2049  	}
  2050  
  2051  	execArgs := &control.ExecArgs{
  2052  		Filename: "/bin/sh",
  2053  		Argv:     []string{"/bin/sh", "-c", cmdExec},
  2054  		Envv:     []string{"VAR=foo", "VAR=bar"},
  2055  	}
  2056  	if ws, err := containers[0].executeSync(execArgs); err != nil || ws.ExitStatus() != 0 {
  2057  		t.Fatalf("exec failed, ws: %v, err: %v", ws, err)
  2058  	}
  2059  
  2060  	// Now read and check that none of the env has repeated values.
  2061  	for _, file := range files {
  2062  		out, err := ioutil.ReadAll(file)
  2063  		if err != nil {
  2064  			t.Fatal(err)
  2065  		}
  2066  		t.Logf("Checking env %q:\n%s", file.Name(), out)
  2067  		envs := make(map[string]string)
  2068  		for _, line := range strings.Split(string(out), "\n") {
  2069  			if len(line) == 0 {
  2070  				continue
  2071  			}
  2072  			envVar := strings.SplitN(line, "=", 2)
  2073  			if len(envVar) != 2 {
  2074  				t.Fatalf("invalid env variable: %s", line)
  2075  			}
  2076  			key := envVar[0]
  2077  			if val, ok := envs[key]; ok {
  2078  				t.Errorf("env variable %q is duplicated: %q and %q", key, val, envVar[1])
  2079  			}
  2080  			envs[key] = envVar[1]
  2081  		}
  2082  		if _, ok := envs["VAR"]; !ok {
  2083  			t.Errorf("variable VAR missing: %v", envs)
  2084  		}
  2085  	}
  2086  }