diff options
Diffstat (limited to 'runsc')
-rw-r--r-- | runsc/boot/loader.go | 4 | ||||
-rw-r--r-- | runsc/cmd/checkpoint.go | 17 | ||||
-rw-r--r-- | runsc/container/container.go | 5 | ||||
-rw-r--r-- | runsc/container/container_test.go | 53 | ||||
-rw-r--r-- | runsc/sandbox/sandbox.go | 11 |
5 files changed, 83 insertions, 7 deletions
diff --git a/runsc/boot/loader.go b/runsc/boot/loader.go index 41d1ee50d..4a6528307 100644 --- a/runsc/boot/loader.go +++ b/runsc/boot/loader.go @@ -100,7 +100,9 @@ func New(spec *specs.Spec, conf *Config, controllerFD int, ioFDs []int, console } // Create VDSO. - vdso, err := loader.PrepareVDSO(p) + // + // Pass k as the platform since it is savable, unlike the actual platform. + vdso, err := loader.PrepareVDSO(k) if err != nil { return nil, fmt.Errorf("error creating vdso: %v", err) } diff --git a/runsc/cmd/checkpoint.go b/runsc/cmd/checkpoint.go index 9b045da1c..927027c2b 100644 --- a/runsc/cmd/checkpoint.go +++ b/runsc/cmd/checkpoint.go @@ -15,6 +15,8 @@ package cmd import ( + "os" + "context" "flag" "github.com/google/subcommands" @@ -24,6 +26,7 @@ import ( // Checkpoint implements subcommands.Command for the "checkpoint" command. type Checkpoint struct { + imagePath string } // Name implements subcommands.Command.Name. @@ -44,6 +47,7 @@ func (*Checkpoint) Usage() string { // SetFlags implements subcommands.Command.SetFlags. func (c *Checkpoint) SetFlags(f *flag.FlagSet) { + f.StringVar(&c.imagePath, "image-path", "", "path to saved container image") } // Execute implements subcommands.Command.Execute. @@ -62,7 +66,18 @@ func (c *Checkpoint) Execute(_ context.Context, f *flag.FlagSet, args ...interfa Fatalf("error loading container: %v", err) } - if err := cont.Checkpoint(); err != nil { + if c.imagePath == "" { + Fatalf("image-path flag must be provided") + } + + // Create the image file and open for writing. + file, err := os.OpenFile(c.imagePath, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0644) + if err != nil { + Fatalf("os.OpenFile(%q) failed: %v", c.imagePath, err) + } + defer file.Close() + + if err := cont.Checkpoint(file); err != nil { Fatalf("checkpoint failed: %v", err) } diff --git a/runsc/container/container.go b/runsc/container/container.go index 66a2f27a1..d323388fb 100644 --- a/runsc/container/container.go +++ b/runsc/container/container.go @@ -339,13 +339,14 @@ func (c *Container) Signal(sig syscall.Signal) error { } // Checkpoint sends the checkpoint call to the container. -func (c *Container) Checkpoint() error { +// The statefile will be written to f, the file at the specified image-path. +func (c *Container) Checkpoint(f *os.File) error { log.Debugf("Checkpoint container %q", c.ID) if c.Status == Stopped { log.Warningf("container %q not running, not checkpointing", c.ID) return nil } - return c.Sandbox.Checkpoint(c.ID) + return c.Sandbox.Checkpoint(c.ID, f) } // State returns the metadata of the container. diff --git a/runsc/container/container_test.go b/runsc/container/container_test.go index 43cd177ce..b6d19bf33 100644 --- a/runsc/container/container_test.go +++ b/runsc/container/container_test.go @@ -408,6 +408,57 @@ func TestExec(t *testing.T) { } } +// TestCheckpoint verifies that calling checkpoint with an image-path flag succeeds. +// Since there is no current default image path, confirming that calling +// checkpoint without an image path fails. +// Checks that there is a file with the name and location given by image path. +func TestCheckpoint(t *testing.T) { + // Container will succeed. + spec := testutil.NewSpecWithArgs("sleep", "100") + + rootDir, bundleDir, conf, err := testutil.SetupContainer(spec) + if err != nil { + t.Fatalf("error setting up container: %v", err) + } + defer os.RemoveAll(rootDir) + defer os.RemoveAll(bundleDir) + + // Create and start the container. + cont, err := container.Create(testutil.UniqueContainerID(), 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) + } + + // Set the image path, which is where the checkpoint image will be saved. + imagePath := filepath.Join(os.TempDir(), "test-image-file") + + // Create the image file and open for writing. + file, err := os.OpenFile(imagePath, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0644) + if err != nil { + t.Fatalf("error opening new file at imagePath: %v", err) + } + defer file.Close() + + // Checkpoint running container; save state into new file. + if err := cont.Checkpoint(file); err != nil { + t.Fatalf("error checkpointing container to empty file: %v", err) + } + defer os.RemoveAll(imagePath) + + // Check to see if file exists and contains data. + fileInfo, err := os.Stat(imagePath) + if err != nil { + t.Fatalf("error checkpointing container: %v", err) + } + if size := fileInfo.Size(); size == 0 { + t.Fatalf("failed checkpoint, file still appears empty: %v", err) + } +} + // TestCapabilities verifies that: // - Running exec as non-root UID and GID will result in an error (because the // executable file can't be read). @@ -602,7 +653,7 @@ func TestSpecUnsupported(t *testing.T) { } // TestRunNonRoot checks that sandbox can be configured when running as -// non-priviledged user. +// non-privileged user. func TestRunNonRoot(t *testing.T) { spec := testutil.NewSpecWithArgs("/bin/true") spec.Process.User.UID = 343 diff --git a/runsc/sandbox/sandbox.go b/runsc/sandbox/sandbox.go index 48388aa7f..c1efab7f5 100644 --- a/runsc/sandbox/sandbox.go +++ b/runsc/sandbox/sandbox.go @@ -441,7 +441,8 @@ func (s *Sandbox) Signal(cid string, sig syscall.Signal) error { } // Checkpoint sends the checkpoint call for a container in the sandbox. -func (s *Sandbox) Checkpoint(cid string) error { +// The statefile will be written to f. +func (s *Sandbox) Checkpoint(cid string, f *os.File) error { log.Debugf("Checkpoint sandbox %q", s.ID) conn, err := s.connect() if err != nil { @@ -449,7 +450,13 @@ func (s *Sandbox) Checkpoint(cid string) error { } defer conn.Close() - if err := conn.Call(boot.ContainerCheckpoint, nil, nil); err != nil { + opt := control.SaveOpts{ + FilePayload: urpc.FilePayload{ + Files: []*os.File{f}, + }, + } + + if err := conn.Call(boot.ContainerCheckpoint, &opt, nil); err != nil { return fmt.Errorf("err checkpointing container %q: %v", cid, err) } return nil |