summaryrefslogtreecommitdiffhomepage
path: root/runsc/container
diff options
context:
space:
mode:
authorFabricio Voznika <fvoznika@google.com>2018-10-11 11:55:45 -0700
committerShentubot <shentubot@google.com>2018-10-11 11:56:54 -0700
commitf413e4b11794cd71cc3b2b64c8f6861f5394a3f1 (patch)
treeff9af373751ee40db971ae6dd23a6c752e8d43fe /runsc/container
parent0bfa03d61c7791aad03da5ac021bc60e4578858e (diff)
Add bare bones unsupported syscall logging
This change introduces a new flags to create/run called --user-log. Logs to this files are visible to users and are meant to help debugging problems with their images and containers. For now only unsupported syscalls are sent to this log, and only minimum support was added. We can build more infrastructure around it as needed. PiperOrigin-RevId: 216735977 Change-Id: I54427ca194604991c407d49943ab3680470de2d0
Diffstat (limited to 'runsc/container')
-rw-r--r--runsc/container/container.go8
-rw-r--r--runsc/container/container_test.go93
-rw-r--r--runsc/container/multi_container_test.go2
-rw-r--r--runsc/container/test_app.go36
4 files changed, 103 insertions, 36 deletions
diff --git a/runsc/container/container.go b/runsc/container/container.go
index eaa62daf1..10108db5a 100644
--- a/runsc/container/container.go
+++ b/runsc/container/container.go
@@ -230,7 +230,7 @@ func List(rootDir string) ([]string, error) {
// Create creates the container in a new Sandbox process, unless the metadata
// indicates that an existing Sandbox should be used. The caller must call
// Destroy() on the container.
-func Create(id string, spec *specs.Spec, conf *boot.Config, bundleDir, consoleSocket, pidFile string) (*Container, error) {
+func Create(id string, spec *specs.Spec, conf *boot.Config, bundleDir, consoleSocket, pidFile, userLog string) (*Container, error) {
log.Debugf("Create container %q in root dir: %s", id, conf.RootDir)
if err := validateID(id); err != nil {
return nil, err
@@ -278,7 +278,7 @@ func Create(id string, spec *specs.Spec, conf *boot.Config, bundleDir, consoleSo
// Start a new sandbox for this container. Any errors after this point
// must destroy the container.
- c.Sandbox, err = sandbox.Create(id, spec, conf, bundleDir, consoleSocket, ioFiles)
+ c.Sandbox, err = sandbox.Create(id, spec, conf, bundleDir, consoleSocket, userLog, ioFiles)
if err != nil {
return nil, err
}
@@ -396,9 +396,9 @@ func (c *Container) Restore(spec *specs.Spec, conf *boot.Config, restoreFile str
}
// Run is a helper that calls Create + Start + Wait.
-func Run(id string, spec *specs.Spec, conf *boot.Config, bundleDir, consoleSocket, pidFile string) (syscall.WaitStatus, error) {
+func Run(id string, spec *specs.Spec, conf *boot.Config, bundleDir, consoleSocket, pidFile, userLog string) (syscall.WaitStatus, error) {
log.Debugf("Run container %q in root dir: %s", id, conf.RootDir)
- c, err := Create(id, spec, conf, bundleDir, consoleSocket, pidFile)
+ c, err := Create(id, spec, conf, bundleDir, consoleSocket, pidFile, userLog)
if err != nil {
return 0, fmt.Errorf("error creating container: %v", err)
}
diff --git a/runsc/container/container_test.go b/runsc/container/container_test.go
index 84b59ffd8..7ea99d06b 100644
--- a/runsc/container/container_test.go
+++ b/runsc/container/container_test.go
@@ -210,18 +210,9 @@ func run(spec *specs.Spec, conf *boot.Config) error {
defer os.RemoveAll(bundleDir)
// Create, start and wait for the container.
- c, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ ws, err := Run(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "", "")
if err != nil {
- return fmt.Errorf("error creating container: %v", err)
- }
- defer c.Destroy()
- if err := c.Start(conf); err != nil {
- return fmt.Errorf("error starting container: %v", err)
- }
-
- ws, err := c.Wait()
- if err != nil {
- return fmt.Errorf("error waiting on container: %v", err)
+ return fmt.Errorf("running container: %v", err)
}
if !ws.Exited() || ws.ExitStatus() != 0 {
return fmt.Errorf("container failed, waitStatus: %v", ws)
@@ -299,7 +290,7 @@ func TestLifecycle(t *testing.T) {
}
// Create the container.
id := testutil.UniqueContainerID()
- c, err := Create(id, spec, conf, bundleDir, "", "")
+ c, err := Create(id, spec, conf, bundleDir, "", "", "")
if err != nil {
t.Fatalf("error creating container: %v", err)
}
@@ -420,7 +411,7 @@ func TestExePath(t *testing.T) {
t.Fatalf("exec: %s, error setting up container: %v", test.path, err)
}
- ws, err := Run(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ ws, err := Run(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "", "")
os.RemoveAll(rootDir)
os.RemoveAll(bundleDir)
@@ -453,7 +444,7 @@ func TestAppExitStatus(t *testing.T) {
defer os.RemoveAll(rootDir)
defer os.RemoveAll(bundleDir)
- ws, err := Run(testutil.UniqueContainerID(), succSpec, conf, bundleDir, "", "")
+ ws, err := Run(testutil.UniqueContainerID(), succSpec, conf, bundleDir, "", "", "")
if err != nil {
t.Fatalf("error running container: %v", err)
}
@@ -472,7 +463,7 @@ func TestAppExitStatus(t *testing.T) {
defer os.RemoveAll(rootDir2)
defer os.RemoveAll(bundleDir2)
- ws, err = Run(testutil.UniqueContainerID(), succSpec, conf, bundleDir2, "", "")
+ ws, err = Run(testutil.UniqueContainerID(), succSpec, conf, bundleDir2, "", "", "")
if err != nil {
t.Fatalf("error running container: %v", err)
}
@@ -497,7 +488,7 @@ func TestExec(t *testing.T) {
defer os.RemoveAll(bundleDir)
// Create and start the container.
- cont, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ cont, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "", "")
if err != nil {
t.Fatalf("error creating container: %v", err)
}
@@ -603,7 +594,7 @@ func TestCheckpointRestore(t *testing.T) {
defer os.RemoveAll(bundleDir)
// Create and start the container.
- cont, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ cont, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "", "")
if err != nil {
t.Fatalf("error creating container: %v", err)
}
@@ -649,7 +640,7 @@ func TestCheckpointRestore(t *testing.T) {
defer outputFile2.Close()
// Restore into a new container.
- cont2, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ cont2, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "", "")
if err != nil {
t.Fatalf("error creating container: %v", err)
}
@@ -688,7 +679,7 @@ func TestCheckpointRestore(t *testing.T) {
defer outputFile3.Close()
// Restore into a new container.
- cont3, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ cont3, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "", "")
if err != nil {
t.Fatalf("error creating container: %v", err)
}
@@ -767,7 +758,7 @@ func TestUnixDomainSockets(t *testing.T) {
defer os.RemoveAll(bundleDir)
// Create and start the container.
- cont, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ cont, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "", "")
if err != nil {
t.Fatalf("error creating container: %v", err)
}
@@ -814,7 +805,7 @@ func TestUnixDomainSockets(t *testing.T) {
defer outputFile2.Close()
// Restore into a new container.
- contRestore, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ contRestore, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "", "")
if err != nil {
t.Fatalf("error creating container: %v", err)
}
@@ -868,7 +859,7 @@ func TestPauseResume(t *testing.T) {
defer os.RemoveAll(bundleDir)
// Create and start the container.
- cont, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ cont, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "", "")
if err != nil {
t.Fatalf("error creating container: %v", err)
}
@@ -973,7 +964,7 @@ func TestPauseResumeStatus(t *testing.T) {
defer os.RemoveAll(bundleDir)
// Create and start the container.
- cont, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ cont, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "", "")
if err != nil {
t.Fatalf("error creating container: %v", err)
}
@@ -1037,7 +1028,7 @@ func TestCapabilities(t *testing.T) {
defer os.RemoveAll(bundleDir)
// Create and start the container.
- cont, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ cont, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "", "")
if err != nil {
t.Fatalf("error creating container: %v", err)
}
@@ -1138,7 +1129,7 @@ func TestConsoleSocket(t *testing.T) {
// Create the container and pass the socket name.
id := testutil.UniqueContainerID()
- c, err := Create(id, spec, conf, bundleDir, socketRelPath, "")
+ c, err := Create(id, spec, conf, bundleDir, socketRelPath, "", "")
if err != nil {
t.Fatalf("error creating container: %v", err)
}
@@ -1262,7 +1253,7 @@ func TestReadonlyRoot(t *testing.T) {
defer os.RemoveAll(bundleDir)
// Create, start and wait for the container.
- c, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ c, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "", "")
if err != nil {
t.Fatalf("error creating container: %v", err)
}
@@ -1306,7 +1297,7 @@ func TestReadonlyMount(t *testing.T) {
defer os.RemoveAll(bundleDir)
// Create, start and wait for the container.
- c, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ c, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "", "")
if err != nil {
t.Fatalf("error creating container: %v", err)
}
@@ -1349,7 +1340,7 @@ func TestAbbreviatedIDs(t *testing.T) {
defer os.RemoveAll(bundleDir)
// Create and start the container.
- cont, err := Create(cid, spec, conf, bundleDir, "", "")
+ cont, err := Create(cid, spec, conf, bundleDir, "", "", "")
if err != nil {
t.Fatalf("error creating container: %v", err)
}
@@ -1409,7 +1400,7 @@ func TestContainerVolumeContentsShared(t *testing.T) {
defer os.RemoveAll(bundleDir)
// Create and start the container.
- c, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ c, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "", "")
if err != nil {
t.Fatalf("error creating container: %v", err)
}
@@ -1531,7 +1522,7 @@ func TestGoferExits(t *testing.T) {
defer os.RemoveAll(bundleDir)
// Create and start the container.
- c, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ c, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "", "")
if err != nil {
t.Fatalf("error creating container: %v", err)
}
@@ -1591,7 +1582,7 @@ func TestJobControlSignalExec(t *testing.T) {
defer os.RemoveAll(bundleDir)
// Create and start the container.
- c, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ c, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "", "")
if err != nil {
t.Fatalf("error creating container: %v", err)
}
@@ -1694,6 +1685,46 @@ func TestJobControlSignalExec(t *testing.T) {
}
}
+func TestUserLog(t *testing.T) {
+ app, err := testutil.FindFile("runsc/container/test_app")
+ if err != nil {
+ t.Fatal("error finding test_app:", err)
+ }
+
+ // sched_rr_get_interval = 148 - not implemented in gvisor.
+ spec := testutil.NewSpecWithArgs(app, "syscall", "--syscall=148")
+ conf := testutil.TestConfig()
+ rootDir, bundleDir, err := testutil.SetupContainer(spec, conf)
+ if err != nil {
+ t.Fatalf("error setting up container: %v", err)
+ }
+ defer os.RemoveAll(rootDir)
+ defer os.RemoveAll(bundleDir)
+
+ dir, err := ioutil.TempDir(testutil.TmpDir(), "user_log_test")
+ if err != nil {
+ t.Fatalf("error creating tmp dir: %v", err)
+ }
+ userLog := filepath.Join(dir, "user.log")
+
+ // Create, start and wait for the container.
+ ws, err := Run(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "", userLog)
+ if err != nil {
+ t.Fatalf("error running container: %v", err)
+ }
+ if !ws.Exited() || ws.ExitStatus() != 0 {
+ t.Fatalf("container failed, waitStatus: %v", ws)
+ }
+
+ out, err := ioutil.ReadFile(userLog)
+ if err != nil {
+ t.Fatalf("error opening user log file %q: %v", userLog, err)
+ }
+ if want := "Unsupported syscall: sched_rr_get_interval"; !strings.Contains(string(out), want) {
+ t.Errorf("user log file doesn't contain %q, out: %s", want, string(out))
+ }
+}
+
// executeSync synchronously executes a new process.
func (cont *Container) executeSync(args *control.ExecArgs) (syscall.WaitStatus, error) {
pid, err := cont.Execute(args)
diff --git a/runsc/container/multi_container_test.go b/runsc/container/multi_container_test.go
index d23d36c37..77f8da8b0 100644
--- a/runsc/container/multi_container_test.go
+++ b/runsc/container/multi_container_test.go
@@ -83,7 +83,7 @@ func startContainers(conf *boot.Config, specs []*specs.Spec, ids []string) ([]*C
}
bundles = append(bundles, bundleDir)
- cont, err := Create(ids[i], spec, conf, bundleDir, "", "")
+ cont, err := Create(ids[i], spec, conf, bundleDir, "", "", "")
if err != nil {
cleanup()
return nil, nil, fmt.Errorf("error creating container: %v", err)
diff --git a/runsc/container/test_app.go b/runsc/container/test_app.go
index f69cfdf83..9e4b5326d 100644
--- a/runsc/container/test_app.go
+++ b/runsc/container/test_app.go
@@ -24,6 +24,7 @@ import (
"os"
"os/exec"
"strconv"
+ sys "syscall"
"time"
"flag"
@@ -38,6 +39,7 @@ func main() {
subcommands.Register(new(taskTree), "")
subcommands.Register(new(forkBomb), "")
subcommands.Register(new(reaper), "")
+ subcommands.Register(new(syscall), "")
flag.Parse()
@@ -241,3 +243,37 @@ func (c *reaper) Execute(ctx context.Context, f *flag.FlagSet, args ...interface
defer stop()
select {}
}
+
+type syscall struct {
+ sysno uint64
+}
+
+// Name implements subcommands.Command.
+func (*syscall) Name() string {
+ return "syscall"
+}
+
+// Synopsis implements subcommands.Command.
+func (*syscall) Synopsis() string {
+ return "syscall makes a syscall"
+}
+
+// Usage implements subcommands.Command.
+func (*syscall) Usage() string {
+ return "syscall <flags>"
+}
+
+// SetFlags implements subcommands.Command.
+func (s *syscall) SetFlags(f *flag.FlagSet) {
+ f.Uint64Var(&s.sysno, "syscall", 0, "syscall to call")
+}
+
+// Execute implements subcommands.Command.
+func (s *syscall) Execute(ctx context.Context, f *flag.FlagSet, args ...interface{}) subcommands.ExitStatus {
+ if _, _, errno := sys.Syscall(uintptr(s.sysno), 0, 0, 0); errno != 0 {
+ fmt.Printf("syscall(%d, 0, 0...) failed: %v\n", s.sysno, errno)
+ } else {
+ fmt.Printf("syscall(%d, 0, 0...) success\n", s.sysno)
+ }
+ return subcommands.ExitSuccess
+}