From 711a9869e54743b05fc3478be5adce31d45cefe5 Mon Sep 17 00:00:00 2001 From: Brielle Broder Date: Tue, 12 Jun 2018 13:24:22 -0700 Subject: Runsc checkpoint works. This is the first iteration of checkpoint that actually saves to a file. Tests for checkpoint are included. Ran into an issue when private unix sockets are enabled. An error message was added for this case and the mutex state was set. PiperOrigin-RevId: 200269470 Change-Id: I28d29a9f92c44bf73dc4a4b12ae0509ee4070e93 --- runsc/container/container.go | 5 ++-- runsc/container/container_test.go | 53 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 3 deletions(-) (limited to 'runsc/container') 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 -- cgit v1.2.3