Skip to content

Commit

Permalink
feat: implement oom score adj
Browse files Browse the repository at this point in the history
  • Loading branch information
nixpig committed Oct 26, 2024
1 parent 16a122a commit 0f6b73e
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 20 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ My goal is for `brownie` to (eventually) pass all tests in the [opencontainers O
- [x] prestart_fail
- [x] process
- [x] process_capabilities
- [x] process_oom_score_adj
- [x] start
- [x] state

Expand Down Expand Up @@ -207,7 +208,6 @@ My goal is for `brownie` to (eventually) pass all tests in the [opencontainers O
- [ ] poststop
- [ ] poststop_fail
- [ ] process_capabilities_fail
- [ ] process_oom_score_adj
- [ ] process_rlimits
- [ ] process_rlimits_fail
- [ ] process_user
Expand Down
3 changes: 3 additions & 0 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,12 +193,15 @@ func forkCmd(log *zerolog.Logger, db *sql.DB) *cobra.Command {
ConsoleSocketFD: consoleSocketFD,
}

log.Info().Msg("loading container")
cntr, err := container.Load(opts.ID, log, db)
if err != nil {
return err
}

log.Info().Msg("forking container")
if err := cntr.Fork(opts, log, db); err != nil {
log.Error().Err(err).Msg("failed to fork container")
cntr.State.Status = specs.StateStopped
if err := cntr.Save(); err != nil {
log.Error().Err(err).Msg("failed to write state file")
Expand Down
57 changes: 40 additions & 17 deletions internal/container/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,22 +203,24 @@ func (c *Container) Init(opts *InitOpts, log *zerolog.Logger) error {
var uidMappings []syscall.SysProcIDMap
var gidMappings []syscall.SysProcIDMap

var unshareFlags uintptr
// TODO: review if this is needed
// if c.Spec.Process != nil {
// cloneFlags |= syscall.CLONE_NEWUSER

// uidMappings = append(uidMappings, syscall.SysProcIDMap{
// ContainerID: int(c.Spec.Process.User.UID),
// HostID: os.Geteuid(),
// Size: 1,
// })
//
// gidMappings = append(gidMappings, syscall.SysProcIDMap{
// ContainerID: int(c.Spec.Process.User.GID),
// HostID: os.Getegid(),
// Size: 1,
// })
// }
if c.Spec.Process != nil {

Check failure on line 208 in internal/container/container.go

View workflow job for this annotation

GitHub Actions / build

empty branch (SA9003)
// cloneFlags |= syscall.CLONE_NEWUSER
// unshareFlags |= syscall.CLONE_NEWUSER
//
// uidMappings = append(uidMappings, syscall.SysProcIDMap{
// ContainerID: int(c.Spec.Process.User.UID),
// HostID: os.Geteuid(),
// Size: 1,
// })
//
// gidMappings = append(gidMappings, syscall.SysProcIDMap{
// ContainerID: int(c.Spec.Process.User.GID),
// HostID: os.Getegid(),
// Size: 1,
// })
}

if c.Spec.Linux.UIDMappings != nil {
for _, uidMapping := range c.Spec.Linux.UIDMappings {
Expand All @@ -243,7 +245,7 @@ func (c *Container) Init(opts *InitOpts, log *zerolog.Logger) error {
c.forkCmd.SysProcAttr = &syscall.SysProcAttr{
AmbientCaps: ambientCapsFlags,
Cloneflags: cloneFlags,
Unshareflags: syscall.CLONE_NEWNS,
Unshareflags: unshareFlags | syscall.CLONE_NEWNS,
GidMappingsEnableSetgroups: false,
UidMappings: uidMappings,
GidMappings: gidMappings,
Expand Down Expand Up @@ -309,6 +311,7 @@ func (c *Container) Init(opts *InitOpts, log *zerolog.Logger) error {

func (c *Container) Fork(opts *ForkOpts, log *zerolog.Logger, db *sql.DB) error {
var err error
log.Info().Msg("creating new init sender")
c.initIPC.ch, c.initIPC.closer, err = ipc.NewSender(opts.InitSockAddr)
if err != nil {
log.Error().Err(err).Msg("failed creating ipc sender")
Expand All @@ -317,49 +320,69 @@ func (c *Container) Fork(opts *ForkOpts, log *zerolog.Logger, db *sql.DB) error
defer c.initIPC.closer()

if opts.ConsoleSocketFD != 0 {
log.Info().Msg("creating new terminal pty")
pty, err := terminal.NewPty()
if err != nil {
return err
}
defer pty.Close()

log.Info().Msg("connecting to terminal pty")
if err := pty.Connect(); err != nil {
return err
}

log.Info().Msg("opening terminal pty socket")
consoleSocketPty := terminal.OpenPtySocket(
opts.ConsoleSocketFD,
opts.ConsoleSocketPath,
)
defer consoleSocketPty.Close()

// FIXME: how do we pass ptysocket struct between fork?
log.Info().Msg("send message over terminal pty socket")
if err := consoleSocketPty.SendMsg(pty); err != nil {
return err
}
}

// set up the socket _before_ pivot root
log.Info().Msg("remove existing container socket")
if err := os.RemoveAll(
filepath.Join(c.State.Bundle, containerSockFilename),
); err != nil {
return err
}

log.Info().Msg("create new container socket receiver")
listCh, listCloser, err := ipc.NewReceiver(filepath.Join(c.State.Bundle, containerSockFilename))
if err != nil {
log.Error().Err(err).Msg("failed to create new ipc receiver")
return err
}
defer listCloser()

if err := filesystem.SetupRootfs(c.State.Bundle, c.Spec); err != nil {
log.Info().Msg("setup root filesystem")
if err := filesystem.SetupRootfs(c.State.Bundle, c.Spec, log); err != nil {
log.Error().Err(err).Msg("failed to setup rootfs")
return err
}

if c.Spec.Process != nil && c.Spec.Process.OOMScoreAdj != nil {
if err := os.WriteFile(
"/proc/self/oom_score_adj",
[]byte(strconv.Itoa(*c.Spec.Process.OOMScoreAdj)),
0644,
); err != nil {
log.Error().Err(err).Msg("failed to write oom_score_adj")
return err
}
}

log.Info().Msg("sending 'ready' msg")
c.initIPC.ch <- []byte("ready")

log.Info().Msg("waiting for 'start' msg")
startErr := ipc.WaitForMsg(listCh, "start", func() error {
if err := filesystem.PivotRoot(c.State.Bundle); err != nil {
log.Error().Err(err).Msg("failed to pivot root")
Expand Down
15 changes: 14 additions & 1 deletion internal/container/filesystem/devices.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"strings"

"github.com/opencontainers/runtime-spec/specs-go"
"github.com/rs/zerolog"
"golang.org/x/sys/unix"
)

Expand Down Expand Up @@ -92,8 +93,10 @@ func mountDefaultDevices(rootfs string) error {
return mountDevices(defaultDevices, rootfs)
}

func mountSpecDevices(devices []specs.LinuxDevice, rootfs string) error {
func mountSpecDevices(devices []specs.LinuxDevice, rootfs string, log *zerolog.Logger) error {
for _, dev := range devices {
log.Info().Any("dev", dev).Msg("setup device")

var absPath string
if strings.Index(dev.Path, "/") == 0 {
relPath := strings.TrimPrefix(dev.Path, "/")
Expand All @@ -102,6 +105,11 @@ func mountSpecDevices(devices []specs.LinuxDevice, rootfs string) error {
absPath = filepath.Join(rootfs, dev.Path)
}

log.Info().
Str("path", absPath).
Uint32("filemode", uint32(*dev.FileMode)).
Int("dev", int(unix.Mkdev(uint32(dev.Major), uint32(dev.Minor)))).
Msg("make node")
if err := unix.Mknod(
absPath,
uint32(*dev.FileMode),
Expand All @@ -110,6 +118,11 @@ func mountSpecDevices(devices []specs.LinuxDevice, rootfs string) error {
return err
}

log.Info().
Str("path", absPath).
Int("uid", int(*dev.UID)).
Int("gid", int(*dev.GID)).
Msg("chown")
if err := os.Chown(
absPath,
int(*dev.UID),
Expand Down
10 changes: 9 additions & 1 deletion internal/container/filesystem/rootfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,49 @@ import (
"path/filepath"

"github.com/opencontainers/runtime-spec/specs-go"
"github.com/rs/zerolog"
)

func SetupRootfs(root string, spec *specs.Spec) error {
func SetupRootfs(root string, spec *specs.Spec, log *zerolog.Logger) error {
rootfs := root

if spec.Root != nil {
rootfs = filepath.Join(root, spec.Root.Path)
}

log.Info().Msg("mount rootfs")
if err := mountRootfs(rootfs); err != nil {
return fmt.Errorf("mount rootfs: %w", err)
}

log.Info().Msg("mount proc")
if err := mountProc(rootfs); err != nil {
return fmt.Errorf("mount proc: %w", err)
}

log.Info().Msg("mount spec mounts")
if err := mountSpecMounts(
spec.Mounts,
rootfs,
); err != nil {
return fmt.Errorf("mount spec mounts: %w", err)
}

log.Info().Msg("mount default devices")
if err := mountDefaultDevices(rootfs); err != nil {
return fmt.Errorf("mount default devices: %w", err)
}

log.Info().Msg("mount spec devices")
if err := mountSpecDevices(
spec.Linux.Devices,
rootfs,
log,
); err != nil {
return fmt.Errorf("mount spec devices: %w", err)
}

log.Info().Msg("create default symlinks")
if err := createSymlinks(
defaultSymlinks,
rootfs,
Expand Down
1 change: 1 addition & 0 deletions oci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ RUNTIME=${RUNTIME:-./brownie}
./validation/prestart_fail/prestart_fail.t 2>&1 | tee -a results.tap
./validation/process/process.t 2>&1 | tee -a results.tap
./validation/process_capabilities/process_capabilities.t 2>&1 | tee -a results.tap
./validation/process_oom_score_adj/process_oom_score_adj.t 2>&1 | tee -a results.tap
./validation/start/start.t 2>&1 | tee -a results.tap
./validation/state/state.t 2>&1 | tee -a results.tap
(! grep -F "not ok" results.tap)

0 comments on commit 0f6b73e

Please sign in to comment.