From 4f5595429b40449fb7456b738c491b5f1c731ab0 Mon Sep 17 00:00:00 2001 From: David Trudgian Date: Thu, 27 Oct 2022 12:57:20 +0100 Subject: [PATCH] feat: run action for OCI bundle As a first step toward run/shell/exec actions on native OCI images, implement a minimal `singularity run --oci mybundle` which: * Requires an on-disk bundle with appropriate `config.json`. * Runs this bundle using `crun` or `runc`. * Makes no attempt to handle any arguments or options. * Does not modify the `config.json` - i.e. it must match namespace / mapping requirements for rootless execution etc. At this stage, the functionality is essentially equivalent to `singularity oci run` and is not yet useful. The primary purpose of the PR is to refactor some of the code that passes args for launching a container. In addition, we now use `crun` in preference to `runc` if available. `crun` supports e.g. single uid->uid mapping in a usernamespace (without root mapping). Closes sylabs/singularity#598 Signed-off-by: Edita Kizinevic --- .github/workflows/ci.yml | 6 +- CHANGELOG.md | 3 + cmd/internal/cli/actions.go | 55 ++++++++--- cmd/internal/cli/instance_start_linux.go | 8 +- cmd/internal/cli/startvm.go | 6 +- e2e/actions/actions.go | 23 +---- e2e/actions/oci.go | 82 ++++++++++++++++ internal/pkg/runtime/launcher/launcher.go | 2 +- .../runtime/launcher/native/launcher_linux.go | 5 +- .../runtime/launcher/oci/launcher_linux.go | 23 ++++- .../launcher/oci/launcher_linux_test.go | 12 --- .../runtime/launcher/oci/oci_conmon_linux.go | 6 +- .../pkg/runtime/launcher/oci/oci_linux.go | 25 ++++- .../runtime/launcher/oci/oci_runc_linux.go | 96 +++++++++---------- internal/pkg/util/bin/bin.go | 1 + 15 files changed, 239 insertions(+), 114 deletions(-) create mode 100644 e2e/actions/oci.go diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e0929215c3..c2f26021bc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -169,7 +169,7 @@ jobs: go-version: 1.19.2 - name: Fetch deps - run: sudo apt-get -q update && sudo apt-get install -y build-essential squashfs-tools squashfuse fuse-overlayfs fakeroot fuse2fs libseccomp-dev cryptsetup conmon runc + run: sudo apt-get -q update && sudo apt-get install -y build-essential squashfs-tools squashfuse fuse-overlayfs fakeroot fuse2fs libseccomp-dev cryptsetup conmon crun - name: Build and install Apptainer run: | @@ -199,7 +199,7 @@ jobs: go-version: 1.19.2 - name: Fetch deps - run: sudo apt-get -q update && sudo apt-get install -y build-essential squashfs-tools libseccomp-dev cryptsetup conmon runc + run: sudo apt-get -q update && sudo apt-get install -y build-essential squashfs-tools libseccomp-dev cryptsetup conmon crun - name: Build and install Apptainer run: | @@ -244,7 +244,7 @@ jobs: - name: Fetch deps if: env.run_tests - run: sudo apt-get -q update && sudo apt-get install -y build-essential uidmap squashfs-tools squashfuse fuse-overlayfs fakeroot fuse2fs libseccomp-dev cryptsetup conmon runc + run: sudo apt-get -q update && sudo apt-get install -y build-essential uidmap squashfs-tools squashfuse fuse-overlayfs fakeroot fuse2fs libseccomp-dev cryptsetup conmon crun - name: Build and install Apptainer if: env.run_tests diff --git a/CHANGELOG.md b/CHANGELOG.md index ac90ab54bc..4436edc9b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,9 @@ For older changes see the [archived Singularity change log](https://github.com/a - The `apptainer oci` command group now uses `runc` to manage containers. - The `apptainer oci` flags `--sync-socket`, `--empty-process`, and `--timeout` have been removed. +- `crun` will be used as the low-level OCI runtime, when available, rather than + `runc`. `runc` will not support all rootless OCI runtime functionality used by + Apptainer. ### New features / functionalities diff --git a/cmd/internal/cli/actions.go b/cmd/internal/cli/actions.go index f47fdb294f..2e13f2a9a3 100644 --- a/cmd/internal/cli/actions.go +++ b/cmd/internal/cli/actions.go @@ -187,13 +187,21 @@ var ExecCmd = &cobra.Command{ Args: cobra.MinimumNArgs(2), PreRun: actionPreRun, Run: func(cmd *cobra.Command, args []string) { - a := append([]string{"/.singularity.d/actions/exec"}, args[1:]...) + // apptainer exec [args...] + image := args[0] + containerCmd := "/.singularity.d/actions/exec" + containerArgs := args[1:] + // OCI runtime does not use an action script + if ociRuntime { + containerCmd = args[1] + containerArgs = args[2:] + } setVM(cmd) if vm { - execVM(cmd, args[0], a) + execVM(cmd, image, containerCmd, containerArgs) return } - if err := launchContainer(cmd, args[0], a, ""); err != nil { + if err := launchContainer(cmd, image, containerCmd, containerArgs, ""); err != nil { sylog.Fatalf("%s", err) } }, @@ -211,13 +219,21 @@ var ShellCmd = &cobra.Command{ Args: cobra.MinimumNArgs(1), PreRun: actionPreRun, Run: func(cmd *cobra.Command, args []string) { - a := []string{"/.singularity.d/actions/shell"} + // apptainer shell + image := args[0] + containerCmd := "/.singularity.d/actions/shell" + containerArgs := []string{} + // OCI runtime does not use an action script + if ociRuntime { + // TODO - needs to have bash -> sh fallback logic implemented somewhere. + containerCmd = "/bin/sh" + } setVM(cmd) if vm { - execVM(cmd, args[0], a) + execVM(cmd, image, containerCmd, containerArgs) return } - if err := launchContainer(cmd, args[0], a, ""); err != nil { + if err := launchContainer(cmd, image, containerCmd, containerArgs, ""); err != nil { sylog.Fatalf("%s", err) } }, @@ -235,13 +251,20 @@ var RunCmd = &cobra.Command{ Args: cobra.MinimumNArgs(1), PreRun: actionPreRun, Run: func(cmd *cobra.Command, args []string) { - a := append([]string{"/.singularity.d/actions/run"}, args[1:]...) + // apptainer run [args...] + image := args[0] + containerCmd := "/.singularity.d/actions/run" + containerArgs := args[1:] + // OCI runtime does not use an action script + if ociRuntime { + containerCmd = "" + } setVM(cmd) if vm { - execVM(cmd, args[0], a) + execVM(cmd, args[0], containerCmd, containerArgs) return } - if err := launchContainer(cmd, args[0], a, ""); err != nil { + if err := launchContainer(cmd, image, containerCmd, containerArgs, ""); err != nil { sylog.Fatalf("%s", err) } }, @@ -259,13 +282,15 @@ var TestCmd = &cobra.Command{ Args: cobra.MinimumNArgs(1), PreRun: actionPreRun, Run: func(cmd *cobra.Command, args []string) { - a := append([]string{"/.singularity.d/actions/test"}, args[1:]...) - setVM(cmd) + // apptainer test [args...] + image := args[0] + containerCmd := "/.singularity.d/actions/test" + containerArgs := args[1:] if vm { - execVM(cmd, args[0], a) + execVM(cmd, image, containerCmd, containerArgs) return } - if err := launchContainer(cmd, args[0], a, ""); err != nil { + if err := launchContainer(cmd, image, containerCmd, containerArgs, ""); err != nil { sylog.Fatalf("%s", err) } }, @@ -276,7 +301,7 @@ var TestCmd = &cobra.Command{ Example: docs.RunTestExample, } -func launchContainer(cmd *cobra.Command, image string, args []string, instanceName string) error { +func launchContainer(cmd *cobra.Command, image string, containerCmd string, containerArgs []string, instanceName string) error { ns := launcher.Namespaces{ User: userNamespace, UTS: utsNamespace, @@ -363,5 +388,5 @@ func launchContainer(cmd *cobra.Command, image string, args []string, instanceNa } } - return l.Exec(cmd.Context(), image, args, instanceName) + return l.Exec(cmd.Context(), image, containerCmd, containerArgs, instanceName) } diff --git a/cmd/internal/cli/instance_start_linux.go b/cmd/internal/cli/instance_start_linux.go index 4f5b87eb03..290df76777 100644 --- a/cmd/internal/cli/instance_start_linux.go +++ b/cmd/internal/cli/instance_start_linux.go @@ -45,14 +45,14 @@ var instanceStartCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { image := args[0] name := args[1] - - a := append([]string{"/.singularity.d/actions/start"}, args[2:]...) + containerCmd := "/.singularity.d/actions/start" + containerArgs := args[2:] setVM(cmd) if vm { - execVM(cmd, image, a) + execVM(cmd, image, containerCmd, containerArgs) return } - if err := launchContainer(cmd, image, a, name); err != nil { + if err := launchContainer(cmd, image, containerCmd, containerArgs, name); err != nil { sylog.Fatalf("%s", err) } diff --git a/cmd/internal/cli/startvm.go b/cmd/internal/cli/startvm.go index 53d050d99f..b1917bfbff 100644 --- a/cmd/internal/cli/startvm.go +++ b/cmd/internal/cli/startvm.go @@ -32,7 +32,7 @@ func getHypervisorArgs(sifImage, bzImage, initramfs, singAction, cliExtra string return args } -func execVM(cmd *cobra.Command, image string, args []string) { +func execVM(cmd *cobra.Command, image string, containerCmd string, containerArgs []string) { // SIF image we are running sifImage := image @@ -46,8 +46,8 @@ func execVM(cmd *cobra.Command, image string, args []string) { isInternal = true } else { // Get our "action" (run, exec, shell) based on the action script being called - singAction = filepath.Base(args[0]) - cliExtra = strings.Join(args[1:], " ") + singAction = filepath.Base(containerCmd) + cliExtra = strings.Join(containerArgs, " ") } if err := startVM(sifImage, singAction, cliExtra, isInternal); err != nil { diff --git a/e2e/actions/actions.go b/e2e/actions/actions.go index c92026b25b..3fee85f440 100644 --- a/e2e/actions/actions.go +++ b/e2e/actions/actions.go @@ -2504,24 +2504,6 @@ func (c actionTests) actionFakerootHome(t *testing.T) { } } -func (c actionTests) ociRuntime(t *testing.T) { - e2e.EnsureImage(t, c.env) - - for _, p := range []e2e.Profile{e2e.OCIUserProfile, e2e.OCIRootProfile} { - c.env.RunApptainer( - t, - e2e.AsSubtest(p.String()), - e2e.WithProfile(p), - e2e.WithCommand("exec"), - e2e.WithArgs(c.env.ImagePath, "/bin/true"), - e2e.ExpectExit( - 255, - e2e.ExpectError(e2e.ContainMatch, "not implemented"), - ), - ) - } -} - // E2ETests is the main func to trigger the test suite func E2ETests(env e2e.TestEnv) testhelper.Tests { c := actionTests{ @@ -2567,8 +2549,11 @@ func E2ETests(env e2e.TestEnv) testhelper.Tests { "unsquash": c.actionUnsquash, // test --unsquash "no-mount": c.actionNoMount, // test --no-mount "compat": c.actionCompat, // test --compat - "ociRuntime": c.ociRuntime, // test --oci (unimplemented) "invalidRemote": np(c.invalidRemote), // GHSA-5mv9-q7fq-9394 "fakeroot home": c.actionFakerootHome, // test home dir in fakeroot + // + // OCI Runtime Mode + // + "ociRun": c.actionOciRun, // apptainer run --oci } } diff --git a/e2e/actions/oci.go b/e2e/actions/oci.go new file mode 100644 index 0000000000..c49c9d3f26 --- /dev/null +++ b/e2e/actions/oci.go @@ -0,0 +1,82 @@ +// Copyright (c) Contributors to the Apptainer project, established as +// Apptainer a Series of LF Projects LLC. +// For website terms of use, trademark policy, privacy policy and other +// project policies see https://lfprojects.org/policies +// Copyright (c) 2022, Sylabs Inc. All rights reserved. +// This software is licensed under a 3-clause BSD license. Please consult the +// LICENSE.md file distributed with the sources of this project regarding your +// rights to use or distribute this software. + +package actions + +import ( + "os" + "testing" + + "github.com/apptainer/apptainer/e2e/internal/e2e" + "github.com/apptainer/apptainer/internal/pkg/test/tool/require" + "github.com/pkg/errors" +) + +func (c actionTests) ociBundle(t *testing.T) (string, func()) { + require.Seccomp(t) + require.Filesystem(t, "overlay") + + bundleDir, err := os.MkdirTemp(c.env.TestDir, "bundle-") + if err != nil { + err = errors.Wrapf(err, "creating temporary bundle directory at %q", c.env.TestDir) + t.Fatalf("failed to create bundle directory: %+v", err) + } + c.env.RunApptainer( + t, + e2e.WithProfile(e2e.RootProfile), + e2e.WithCommand("oci mount"), + e2e.WithArgs(c.env.ImagePath, bundleDir), + e2e.ExpectExit(0), + ) + + cleanup := func() { + c.env.RunApptainer( + t, + e2e.WithProfile(e2e.RootProfile), + e2e.WithCommand("oci umount"), + e2e.WithArgs(bundleDir), + e2e.ExpectExit(0), + ) + os.RemoveAll(bundleDir) + } + + return bundleDir, cleanup +} + +func (c actionTests) actionOciRun(t *testing.T) { + e2e.EnsureImage(t, c.env) + + bundle, cleanup := c.ociBundle(t) + defer cleanup() + + tests := []struct { + name string + argv []string + exit int + }{ + { + name: "NoCommand", + argv: []string{bundle}, + exit: 0, + }, + } + + for _, tt := range tests { + c.env.RunApptainer( + t, + e2e.AsSubtest(tt.name), + e2e.WithProfile(e2e.OCIRootProfile), + e2e.WithCommand("run"), + // While we don't support args we are entering a /bin/sh interactively, so we need to exit. + e2e.ConsoleRun(e2e.ConsoleSendLine("exit")), + e2e.WithArgs(tt.argv...), + e2e.ExpectExit(tt.exit), + ) + } +} diff --git a/internal/pkg/runtime/launcher/launcher.go b/internal/pkg/runtime/launcher/launcher.go index 1a79a55889..177dc373b2 100644 --- a/internal/pkg/runtime/launcher/launcher.go +++ b/internal/pkg/runtime/launcher/launcher.go @@ -29,5 +29,5 @@ type Launcher interface { // the container#s initial process. If instanceName is specified, the // container must be launched as a background instance, otherwist it must // run interactively, attached to the console. - Exec(ctx context.Context, image string, args []string, instanceName string) error + Exec(ctx context.Context, image string, cmd string, args []string, instanceName string) error } diff --git a/internal/pkg/runtime/launcher/native/launcher_linux.go b/internal/pkg/runtime/launcher/native/launcher_linux.go index a384458b07..3770733fac 100644 --- a/internal/pkg/runtime/launcher/native/launcher_linux.go +++ b/internal/pkg/runtime/launcher/native/launcher_linux.go @@ -104,7 +104,7 @@ func NewLauncher(opts ...launcher.Option) (*Launcher, error) { // This includes interactive containers, instances, and joining an existing instance. // //nolint:maintidx -func (l *Launcher) Exec(ctx context.Context, image string, args []string, instanceName string) error { +func (l *Launcher) Exec(ctx context.Context, image string, cmd string, args []string, instanceName string) error { var err error var fakerootPath string @@ -165,6 +165,9 @@ func (l *Launcher) Exec(ctx context.Context, image string, args []string, instan } } + // Native runtime expects command to execute as arg[0] + args = append([]string{cmd}, args...) + // Set arguments to pass to contained process. l.generator.SetProcessArgs(args) diff --git a/internal/pkg/runtime/launcher/oci/launcher_linux.go b/internal/pkg/runtime/launcher/oci/launcher_linux.go index 8169dda206..62c4cb2303 100644 --- a/internal/pkg/runtime/launcher/oci/launcher_linux.go +++ b/internal/pkg/runtime/launcher/oci/launcher_linux.go @@ -18,6 +18,7 @@ import ( "fmt" "strings" + "github.com/google/uuid" "github.com/apptainer/apptainer/internal/pkg/buildcfg" "github.com/apptainer/apptainer/internal/pkg/runtime/launcher" ) @@ -233,7 +234,23 @@ func checkOpts(lo launcher.Options) error { return nil } -// Exec is not yet implemented. -func (l *Launcher) Exec(ctx context.Context, image string, args []string, instanceName string) error { - return ErrNotImplemented +// Exec will interactively execute a container via the runc low-level runtime. +func (l *Launcher) Exec(ctx context.Context, image string, cmd string, args []string, instanceName string) error { + if instanceName != "" { + return fmt.Errorf("%w: instanceName", ErrNotImplemented) + } + + if cmd != "" { + return fmt.Errorf("%w: cmd %v", ErrNotImplemented, cmd) + } + + if len(args) > 0 { + return fmt.Errorf("%w: args %v", ErrNotImplemented, args) + } + + id, err := uuid.NewRandom() + if err != nil { + return fmt.Errorf("while generating container id: %w", err) + } + return Run(ctx, id.String(), image, "") } diff --git a/internal/pkg/runtime/launcher/oci/launcher_linux_test.go b/internal/pkg/runtime/launcher/oci/launcher_linux_test.go index e75452fb41..a64b87e1be 100644 --- a/internal/pkg/runtime/launcher/oci/launcher_linux_test.go +++ b/internal/pkg/runtime/launcher/oci/launcher_linux_test.go @@ -10,7 +10,6 @@ package oci import ( - "context" "reflect" "testing" @@ -58,14 +57,3 @@ func TestNewLauncher(t *testing.T) { }) } } - -func TestExec(t *testing.T) { - l, err := NewLauncher([]launcher.Option{}...) - if err != nil { - t.Errorf("Couldn't initialize launcher: %s", err) - } - - if err := l.Exec(context.Background(), "", []string{}, ""); err != ErrNotImplemented { - t.Errorf("Expected %v, got %v", ErrNotImplemented, err) - } -} diff --git a/internal/pkg/runtime/launcher/oci/oci_conmon_linux.go b/internal/pkg/runtime/launcher/oci/oci_conmon_linux.go index dcf2cde0cd..0649c83172 100644 --- a/internal/pkg/runtime/launcher/oci/oci_conmon_linux.go +++ b/internal/pkg/runtime/launcher/oci/oci_conmon_linux.go @@ -43,7 +43,7 @@ func Create(containerID, bundlePath string) error { if err != nil { return err } - runc, err := bin.FindBin("runc") + runtimeBin, err := runtime() if err != nil { return err } @@ -96,12 +96,12 @@ func Create(containerID, bundlePath string) error { "--cid", containerID, "--name", containerID, "--cuuid", containerUUID.String(), - "--runtime", runc, + "--runtime", runtimeBin, "--conmon-pidfile", path.Join(sd, conmonPidFile), "--container-pidfile", path.Join(sd, containerPidFile), "--log-path", path.Join(sd, containerLogFile), "--runtime-arg", "--root", - "--runtime-arg", runcStateDir, + "--runtime-arg", runtimeStateDir(), "--runtime-arg", "--log", "--runtime-arg", path.Join(sd, runcLogFile), "--full-attach", diff --git a/internal/pkg/runtime/launcher/oci/oci_linux.go b/internal/pkg/runtime/launcher/oci/oci_linux.go index 5298bf2849..50166f151d 100644 --- a/internal/pkg/runtime/launcher/oci/oci_linux.go +++ b/internal/pkg/runtime/launcher/oci/oci_linux.go @@ -19,16 +19,16 @@ import ( "path/filepath" "time" + "github.com/apptainer/apptainer/internal/pkg/util/bin" "github.com/apptainer/apptainer/internal/pkg/util/fs" "github.com/apptainer/apptainer/internal/pkg/util/user" "github.com/apptainer/apptainer/pkg/syfs" + "github.com/apptainer/apptainer/pkg/sylog" "github.com/apptainer/apptainer/pkg/util/fs/lock" securejoin "github.com/cyphar/filepath-securejoin" ) const ( - // Absolute path for the runc state - runcStateDir = "/run/apptainer-oci" // Relative path inside ~/.apptainer for conmon and apptainer state ociPath = "oci" // State directory files @@ -45,6 +45,27 @@ const ( ) // stateDir returns the path to container state handled by conmon/apptainer + +// runtime returns path to the OCI runtime - crun (preferred), or runc. +func runtime() (path string, err error) { + path, err = bin.FindBin("crun") + if err == nil { + return + } + sylog.Debugf("While finding crun: %s", err) + sylog.Warningf("crun not found. Will attempt to use runc, but not all functionality is supported.") + return bin.FindBin("runc") +} + +// runtimeStateDir returns path to use for crun/runc's state handling. +func runtimeStateDir() string { + uid := os.Getuid() + if uid == 0 { + return "/run/apptainer-oci" + } + return fmt.Sprintf("/run/user/%d/apptainer-oci", uid) +} + // (as opposed to runc's state in RuncStateDir) func stateDir(containerID string) (string, error) { hostname, err := os.Hostname() diff --git a/internal/pkg/runtime/launcher/oci/oci_runc_linux.go b/internal/pkg/runtime/launcher/oci/oci_runc_linux.go index d96a1a702e..cb1fff97b9 100644 --- a/internal/pkg/runtime/launcher/oci/oci_runc_linux.go +++ b/internal/pkg/runtime/launcher/oci/oci_runc_linux.go @@ -25,21 +25,21 @@ import ( // Delete deletes container resources func Delete(ctx context.Context, containerID string) error { - runc, err := bin.FindBin("runc") + runtimeBin, err := runtime() if err != nil { return err } - runcArgs := []string{ - "--root", runcStateDir, + runtimeArgs := []string{ + "--root", runtimeStateDir(), "delete", containerID, } - cmd := exec.Command(runc, runcArgs...) + cmd := exec.Command(runtimeBin, runtimeArgs...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Stdin = os.Stdout - sylog.Debugf("Calling runc with args %v", runcArgs) + sylog.Debugf("Calling %s with args %v", runtimeBin, runtimeArgs) err = cmd.Run() if err != nil { return fmt.Errorf("while calling runc delete: %w", err) @@ -67,88 +67,88 @@ func Delete(ctx context.Context, containerID string) error { // Exec executes a command in a container func Exec(containerID string, cmdArgs []string) error { - runc, err := bin.FindBin("runc") + runtimeBin, err := runtime() if err != nil { return err } - runcArgs := []string{ - "--root", runcStateDir, + runtimeArgs := []string{ + "--root", runtimeStateDir(), "exec", containerID, } - runcArgs = append(runcArgs, cmdArgs...) - cmd := exec.Command(runc, runcArgs...) + runtimeArgs = append(runtimeArgs, cmdArgs...) + cmd := exec.Command(runtimeBin, runtimeArgs...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Stdin = os.Stdout - sylog.Debugf("Calling runc with args %v", runcArgs) + sylog.Debugf("Calling %s with args %v", runtimeBin, runtimeArgs) return cmd.Run() } // Kill kills container process func Kill(containerID string, killSignal string) error { - runc, err := bin.FindBin("runc") + runtimeBin, err := runtime() if err != nil { return err } - runcArgs := []string{ - "--root", runcStateDir, + runtimeArgs := []string{ + "--root", runtimeStateDir(), "kill", containerID, killSignal, } - cmd := exec.Command(runc, runcArgs...) + cmd := exec.Command(runtimeBin, runtimeArgs...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Stdin = os.Stdout - sylog.Debugf("Calling runc with args %v", runcArgs) + sylog.Debugf("Calling %s with args %v", runtimeBin, runtimeArgs) return cmd.Run() } // Pause pauses processes in a container func Pause(containerID string) error { - runc, err := bin.FindBin("runc") + runtimeBin, err := runtime() if err != nil { return err } - runcArgs := []string{ - "--root", runcStateDir, + runtimeArgs := []string{ + "--root", runtimeStateDir(), "pause", containerID, } - cmd := exec.Command(runc, runcArgs...) + cmd := exec.Command(runtimeBin, runtimeArgs...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Stdin = os.Stdout - sylog.Debugf("Calling runc with args %v", runcArgs) + sylog.Debugf("Calling %s with args %v", runtimeBin, runtimeArgs) return cmd.Run() } // Resume pauses processes in a container func Resume(containerID string) error { - runc, err := bin.FindBin("runc") + runtimeBin, err := runtime() if err != nil { return err } - runcArgs := []string{ - "--root", runcStateDir, + runtimeArgs := []string{ + "--root", runtimeStateDir(), "resume", containerID, } - cmd := exec.Command(runc, runcArgs...) + cmd := exec.Command(runtimeBin, runtimeArgs...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Stdin = os.Stdout - sylog.Debugf("Calling runc with args %v", runcArgs) + sylog.Debugf("Calling %s with args %v", runtimeBin, runtimeArgs) return cmd.Run() } // Run runs a container (equivalent to create/start/delete) func Run(ctx context.Context, containerID, bundlePath, pidFile string) error { - runc, err := bin.FindBin("runc") + runtimeBin, err := runtime() if err != nil { return err } @@ -161,80 +161,80 @@ func Run(ctx context.Context, containerID, bundlePath, pidFile string) error { return fmt.Errorf("failed to change directory to %s: %s", absBundle, err) } - runcArgs := []string{ - "--root", runcStateDir, + runtimeArgs := []string{ + "--root", runtimeStateDir(), "run", "-b", absBundle, } if pidFile != "" { - runcArgs = append(runcArgs, "--pid-file="+pidFile) + runtimeArgs = append(runtimeArgs, "--pid-file="+pidFile) } - runcArgs = append(runcArgs, containerID) - cmd := exec.Command(runc, runcArgs...) + runtimeArgs = append(runtimeArgs, containerID) + cmd := exec.Command(runtimeBin, runtimeArgs...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Stdin = os.Stdout - sylog.Debugf("Calling runc with args %v", runcArgs) + sylog.Debugf("Calling %s with args %v", runtimeBin, runtimeArgs) return cmd.Run() } // Start starts a previously created container func Start(containerID string) error { - runc, err := bin.FindBin("runc") + runtimeBin, err := bin.FindBin("crun") if err != nil { return err } - runcArgs := []string{ - "--root", runcStateDir, + runtimeArgs := []string{ + "--root", runtimeStateDir(), "start", containerID, } - cmd := exec.Command(runc, runcArgs...) + cmd := exec.Command(runtimeBin, runtimeArgs...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Stdin = os.Stdout - sylog.Debugf("Calling runc with args %v", runcArgs) + sylog.Debugf("Calling %s with args %v", runtimeBin, runtimeArgs) return cmd.Run() } // State queries container state func State(containerID string) error { - runc, err := bin.FindBin("runc") + runtimeBin, err := runtime() if err != nil { return err } - runcArgs := []string{ - "--root", runcStateDir, + runtimeArgs := []string{ + "--root", runtimeStateDir(), "state", containerID, } - cmd := exec.Command(runc, runcArgs...) + cmd := exec.Command(runtimeBin, runtimeArgs...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Stdin = os.Stdout - sylog.Debugf("Calling runc with args %v", runcArgs) + sylog.Debugf("Calling %s with args %v", runtimeBin, runtimeArgs) return cmd.Run() } // Update updates container cgroups resources func Update(containerID, cgFile string) error { - runc, err := bin.FindBin("runc") + runtimeBin, err := runtime() if err != nil { return err } - runcArgs := []string{ - "--root", runcStateDir, + runtimeArgs := []string{ + "--root", runtimeStateDir(), "update", "-r", cgFile, containerID, } - cmd := exec.Command(runc, runcArgs...) + cmd := exec.Command(runtimeBin, runtimeArgs...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Stdin = os.Stdout - sylog.Debugf("Calling runc with args %v", runcArgs) + sylog.Debugf("Calling %s with args %v", runtimeBin, runtimeArgs) return cmd.Run() } diff --git a/internal/pkg/util/bin/bin.go b/internal/pkg/util/bin/bin.go index ce334dee90..84481bee5e 100644 --- a/internal/pkg/util/bin/bin.go +++ b/internal/pkg/util/bin/bin.go @@ -48,6 +48,7 @@ func FindBin(name string) (path string, err error) { // All other executables // We will always search the user's PATH first for these case "conmon", + "crun", "curl", "debootstrap", "dnf",