diff options
Diffstat (limited to 'runsc/container')
-rw-r--r-- | runsc/container/BUILD | 1 | ||||
-rw-r--r-- | runsc/container/container.go | 66 | ||||
-rw-r--r-- | runsc/container/container_test.go | 73 |
3 files changed, 120 insertions, 20 deletions
diff --git a/runsc/container/BUILD b/runsc/container/BUILD index fe477abf2..61e05e1c3 100644 --- a/runsc/container/BUILD +++ b/runsc/container/BUILD @@ -37,6 +37,7 @@ go_test( "//pkg/sentry/kernel/auth", "//pkg/unet", "//runsc/container", + "//runsc/specutils", "//runsc/test/testutil", "@com_github_opencontainers_runtime-spec//specs-go:go_default_library", "@org_golang_x_sys//unix:go_default_library", diff --git a/runsc/container/container.go b/runsc/container/container.go index 571784e07..3b7f95af9 100644 --- a/runsc/container/container.go +++ b/runsc/container/container.go @@ -214,22 +214,43 @@ func Create(id string, spec *specs.Spec, conf *boot.Config, bundleDir, consoleSo Owner: os.Getenv("USER"), } - // TODO: If the metadata annotations indicate that this - // container should be started in another sandbox, we must do so. The - // metadata will indicate the ID of the sandbox, which is the same as - // the ID of the init container in the sandbox. We can look up that - // init container by ID to get the sandbox, then we need to expose a - // way to run a new container in the sandbox. - - // Start a new sandbox for this container. Any errors after this point - // must destroy the container. - s, err := sandbox.Create(id, spec, conf, bundleDir, consoleSocket) - if err != nil { - c.Destroy() - return nil, err - } + // If the metadata annotations indicate that this container should be + // started in an existing sandbox, we must do so. The metadata will + // indicate the ID of the sandbox, which is the same as the ID of the + // init container in the sandbox. + if specutils.ShouldCreateSandbox(spec) { + log.Debugf("Creating new sandbox for container %q", id) + // Start a new sandbox for this container. Any errors after this point + // must destroy the container. + s, err := sandbox.Create(id, spec, conf, bundleDir, consoleSocket) + if err != nil { + c.Destroy() + return nil, err + } + c.Sandbox = s + } else { + // This is sort of confusing. For a sandbox with a root + // container and a child container in it, runsc sees: + // * A container struct whose sandbox ID is equal to the + // container ID. This is the root container that is tied to + // the creation of the sandbox. + // * A container struct whose sandbox ID is equal to the above + // container/sandbox ID, but that has a different container + // ID. This is the child container. + sbid, ok := specutils.SandboxID(spec) + if !ok { + return nil, fmt.Errorf("no sandbox ID found when creating container") + } + log.Debugf("Creating new container %q in sandbox %q", c.ID, sbid) - c.Sandbox = s + // Find the sandbox associated with this ID. + sb, err := Load(conf.RootDir, sbid) + if err != nil { + c.Destroy() + return nil, err + } + c.Sandbox = sb.Sandbox + } c.Status = Created // Save the metadata file. @@ -242,7 +263,7 @@ func Create(id string, spec *specs.Spec, conf *boot.Config, bundleDir, consoleSo // this file is created, so it must be the last thing we do. if pidFile != "" { if err := ioutil.WriteFile(pidFile, []byte(strconv.Itoa(c.Pid())), 0644); err != nil { - s.Destroy() + c.Destroy() return nil, fmt.Errorf("error writing pid file: %v", err) } } @@ -266,9 +287,16 @@ func (c *Container) Start(conf *boot.Config) error { } } - if err := c.Sandbox.Start(c.ID, c.Spec, conf); err != nil { - c.Destroy() - return err + if specutils.ShouldCreateSandbox(c.Spec) { + if err := c.Sandbox.StartRoot(c.Spec, conf); err != nil { + c.Destroy() + return err + } + } else { + if err := c.Sandbox.Start(c.Spec, conf); err != nil { + c.Destroy() + return err + } } // "If any poststart hook fails, the runtime MUST log a warning, but diff --git a/runsc/container/container_test.go b/runsc/container/container_test.go index 7f87ea5ab..1116ca170 100644 --- a/runsc/container/container_test.go +++ b/runsc/container/container_test.go @@ -36,6 +36,7 @@ import ( "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/auth" "gvisor.googlesource.com/gvisor/pkg/unet" "gvisor.googlesource.com/gvisor/runsc/container" + "gvisor.googlesource.com/gvisor/runsc/specutils" "gvisor.googlesource.com/gvisor/runsc/test/testutil" ) @@ -51,7 +52,7 @@ func waitForProcessList(s *container.Container, expected []*control.Process) err var got []*control.Process for start := time.Now(); time.Now().Sub(start) < 10*time.Second; { var err error - got, err := s.Processes() + got, err = s.Processes() if err != nil { return fmt.Errorf("error getting process data from container: %v", err) } @@ -946,3 +947,73 @@ func TestAbbreviatedIDs(t *testing.T) { } } } + +// TestMultiContainerSanity checks that it is possible to run 2 dead-simple +// containers in the same sandbox. +func TestMultiContainerSanity(t *testing.T) { + containerIDs := []string{ + testutil.UniqueContainerID(), + testutil.UniqueContainerID(), + } + containerAnnotations := []map[string]string{ + // The first container creates a sandbox. + map[string]string{ + specutils.ContainerdContainerTypeAnnotation: specutils.ContainerdContainerTypeSandbox, + }, + // The second container creates a container within the first + // container's sandbox. + map[string]string{ + specutils.ContainerdContainerTypeAnnotation: specutils.ContainerdContainerTypeContainer, + specutils.ContainerdSandboxIDAnnotation: containerIDs[0], + }, + } + + rootDir, err := testutil.SetupRootDir() + if err != nil { + t.Fatalf("error creating root dir: %v", err) + } + defer os.RemoveAll(rootDir) + + // Setup the containers. + containers := make([]*container.Container, 0, len(containerIDs)) + for i, annotations := range containerAnnotations { + spec := testutil.NewSpecWithArgs("sleep", "100") + spec.Annotations = annotations + bundleDir, conf, err := testutil.SetupContainerInRoot(rootDir, spec) + if err != nil { + t.Fatalf("error setting up container: %v", err) + } + defer os.RemoveAll(bundleDir) + cont, err := container.Create(containerIDs[i], spec, conf, bundleDir, "", "") + if err != nil { + t.Fatalf("error creating container: %v", err) + } + defer cont.Destroy() + if err := cont.Start(conf); err != nil { + t.Fatalf("error starting container: %v", err) + } + containers = append(containers, cont) + } + + expectedPL := []*control.Process{ + { + UID: 0, + PID: 1, + PPID: 0, + C: 0, + Cmd: "sleep", + }, + { + UID: 0, + PID: 2, + PPID: 0, + C: 0, + Cmd: "sleep", + }, + } + + // Check via ps that multiple processes are running. + if err := waitForProcessList(containers[0], expectedPL); err != nil { + t.Errorf("failed to wait for sleep to start: %v", err) + } +} |