Skip to content

Commit

Permalink
refactor: Move runc/conmon functionality out of app/singularity
Browse files Browse the repository at this point in the history
In preparation for further OCI runtime work, move the code that calls
out to runc/conmon from internal/app/singularity into
internal/pkg/runtime/launcher/oci

The oci.Launcher will make use of the basic OCI operations to run
containers from its Exec function, so this is a good location while
that work proceeds. The functions will be likely be modified
considerably, and potentially moved again in future, as the
design/implementation of the OCI runtime interaction is developed.

The internal/app/singularity OCI* functions are left as a minimal shim
layer, between the CLI layer and the launcher, at this time.

Signed-off-by: Edita Kizinevic <[email protected]>
  • Loading branch information
dtrudg authored and edytuk committed Jul 21, 2023
1 parent 542da09 commit 673e9d8
Show file tree
Hide file tree
Showing 16 changed files with 460 additions and 529 deletions.
3 changes: 2 additions & 1 deletion cmd/internal/cli/oci_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ package cli
import (
"github.com/apptainer/apptainer/docs"
"github.com/apptainer/apptainer/internal/app/apptainer"
"github.com/apptainer/apptainer/internal/pkg/runtime/launcher/oci"
"github.com/apptainer/apptainer/pkg/cmdline"
"github.com/apptainer/apptainer/pkg/sylog"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -241,7 +242,7 @@ var OciAttachCmd = &cobra.Command{
DisableFlagsInUseLine: true,
PreRun: CheckRoot,
Run: func(cmd *cobra.Command, args []string) {
if err := apptainer.OciAttach(cmd.Context(), args[0]); err != nil {
if err := oci.Attach(cmd.Context(), args[0]); err != nil {
sylog.Fatalf("%s", err)
}
},
Expand Down
63 changes: 0 additions & 63 deletions internal/app/apptainer/oci_delete_linux.go

This file was deleted.

38 changes: 0 additions & 38 deletions internal/app/apptainer/oci_exec_linux.go

This file was deleted.

39 changes: 0 additions & 39 deletions internal/app/apptainer/oci_kill_linux.go

This file was deleted.

165 changes: 50 additions & 115 deletions internal/app/apptainer/oci_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,36 +13,10 @@
package apptainer

import (
"fmt"
"io"
"os"
"path"
"path/filepath"
"time"

"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/util/fs/lock"
securejoin "github.com/cyphar/filepath-securejoin"
)
"context"

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
containerPidFile = "container.pid"
containerLogFile = "container.log"
runcLogFile = "runc.log"
conmonPidFile = "conmon.pid"
bundleLink = "bundle"
// Files in the OCI bundle root
bundleLock = ".apptainer-oci.lock"
attachSocket = "attach"
// Timeouts
createTimeout = 30 * time.Second
"github.com/apptainer/apptainer/internal/pkg/runtime/launcher/oci"
ocibundle "github.com/apptainer/apptainer/pkg/ocibundle/sif"
)

// OciArgs contains CLI arguments
Expand All @@ -58,109 +32,70 @@ type OciArgs struct {
ForceKill bool
}

// AttachStreams contains streams that will be attached to the container
type AttachStreams struct {
// OutputStream will be attached to container's STDOUT
OutputStream io.Writer
// ErrorStream will be attached to container's STDERR
ErrorStream io.Writer
// InputStream will be attached to container's STDIN
InputStream io.Reader
// AttachOutput is whether to attach to STDOUT
// If false, stdout will not be attached
AttachOutput bool
// AttachError is whether to attach to STDERR
// If false, stdout will not be attached
AttachError bool
// AttachInput is whether to attach to STDIN
// If false, stdout will not be attached
AttachInput bool
// OciRun runs a container (equivalent to create/start/delete)
func OciRun(ctx context.Context, containerID string, args *OciArgs) error {
return oci.Run(ctx, containerID, args.BundlePath, args.PidFile)
}

/* Sync with stdpipe_t in conmon.c */
const (
AttachPipeStdin = 1
AttachPipeStdout = 2
AttachPipeStderr = 3
)

type ociError struct {
Level string `json:"level,omitempty"`
Time string `json:"time,omitempty"`
Msg string `json:"msg,omitempty"`
// OciCreate creates a container from an OCI bundle
func OciCreate(containerID string, args *OciArgs) error {
return oci.Create(containerID, args.BundlePath)
}

// stateDir returns the path to container state handled by conmon/apptainer
// (as opposed to runc's state in RuncStateDir)
func stateDir(containerID string) (string, error) {
hostname, err := os.Hostname()
if err != nil {
return "", err
}
// OciStart starts a previously create container
func OciStart(containerID string) error {
return oci.Start(containerID)
}

u, err := user.CurrentOriginal()
if err != nil {
return "", err
}
// OciDelete deletes container resources
func OciDelete(ctx context.Context, containerID string) error {
return oci.Delete(ctx, containerID)
}

configDir, err := syfs.ConfigDirForUsername(u.Name)
if err != nil {
return "", err
}
// OciExec executes a command in a container
func OciExec(containerID string, cmdArgs []string) error {
return oci.Exec(containerID, cmdArgs)
}

rootPath := filepath.Join(configDir, ociPath)
containerPath := filepath.Join(hostname, containerID)
path, err := securejoin.SecureJoin(rootPath, containerPath)
if err != nil {
return "", err
}
return path, err
// OciKill kills container process
func OciKill(containerID string, killSignal string) error {
return oci.Kill(containerID, killSignal)
}

// lockBundle creates a lock file in a bundle directory
func lockBundle(bundlePath string) error {
bl := path.Join(bundlePath, bundleLock)
_, err := os.Stat(bl)
if err == nil {
return fmt.Errorf("bundle is locked by another process")
}
if !os.IsNotExist(err) {
return fmt.Errorf("while stat-ing lock file: %w", err)
}
// OciPause pauses processes in a container
func OciPause(containerID string) error {
return oci.Pause(containerID)
}

fd, err := lock.Exclusive(bundlePath)
if err != nil {
return fmt.Errorf("while acquiring directory lock: %w", err)
}
defer lock.Release(fd)
// OciResume pauses processes in a container
func OciResume(containerID string) error {
return oci.Resume(containerID)
}

err = fs.EnsureFileWithPermission(bl, 0o600)
if err != nil {
return fmt.Errorf("while creating lock file: %w", err)
}
return nil
// OciState queries container state
func OciState(containerID string, args *OciArgs) error {
return oci.State(containerID)
}

// releaseBundle removes a lock file in a bundle directory
func releaseBundle(bundlePath string) error {
bl := path.Join(bundlePath, bundleLock)
_, err := os.Stat(bl)
if os.IsNotExist(err) {
return fmt.Errorf("bundle is not locked")
}
if err != nil {
return fmt.Errorf("while stat-ing lock file: %w", err)
}
// OciUpdate updates container cgroups resources
func OciUpdate(containerID string, args *OciArgs) error {
return oci.Update(containerID, args.FromFile)
}

fd, err := lock.Exclusive(bundlePath)
// OciMount mount a SIF image to create an OCI bundle
func OciMount(image string, bundle string) error {
d, err := ocibundle.FromSif(image, bundle, true)
if err != nil {
return fmt.Errorf("while acquiring directory lock: %w", err)
return err
}
defer lock.Release(fd)
return d.Create(nil)
}

err = os.Remove(bl)
// OciUmount umount SIF and delete OCI bundle
func OciUmount(bundle string) error {
d, err := ocibundle.FromSif("", bundle, true)
if err != nil {
return fmt.Errorf("while removing lock file: %w", err)
return err
}
return nil
return d.Delete()
}
32 changes: 0 additions & 32 deletions internal/app/apptainer/oci_mount_linux.go

This file was deleted.

Loading

0 comments on commit 673e9d8

Please sign in to comment.