Skip to content

Commit

Permalink
Merge pull request warewulf#1182 from mslacken/CleanupAfterShell
Browse files Browse the repository at this point in the history
Fix overlay directory location/creation
  • Loading branch information
anderbubble authored Jun 7, 2024
2 parents bc94076 + 2c5e079 commit 28ba479
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 45 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Fix the issue that warewulf.conf parse does not support CIDR format. #1130
- Reduce the number of times syncuser walks the container file system. #1209
- Create ssh key also when calling `wwctl configure --all` #1250
- Remove the temporary overlay dir. #1180
- Remove the temporary overlayfs dir and create them besides rootfs #1180

### Security

Expand All @@ -71,6 +73,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

- Allow specification of the ssh-keys to be to be created. #1185

### Changed

- The command `wwctl container exec` locks now this container during execution. #830

### Fixed

- Fix nightly release build failure issue. #1195
Expand Down
39 changes: 23 additions & 16 deletions internal/app/wwctl/container/exec/child/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,45 +34,55 @@ func CobraRunE(cmd *cobra.Command, args []string) (err error) {
os.Exit(1)
}
conf := warewulfconf.Get()
runDir := container.RunDir(containerName)
if _, err := os.Stat(runDir); os.IsNotExist(err) {
return errors.Wrap(err, "container run directory does not exist")
}
mountPts := conf.MountsContainer
mountPts = append(container.InitMountPnts(binds), mountPts...)
// check for valid mount points
lowerObjects := checkMountPoints(containerName, mountPts)
overlayDir := conf.Paths.WWChrootdir + "/overlays"
// need to create a overlay, where the lower layer contains
// the missing mount points
wwlog.Verbose("for ephermal mount use tempdir %s", overlayDir)
// ignore errors as we are doomed if a tmp dir couldn't be written
_ = os.MkdirAll(path.Join(overlayDir, "work"), os.ModePerm)
_ = os.MkdirAll(path.Join(overlayDir, "lower"), os.ModePerm)
_ = os.MkdirAll(path.Join(overlayDir, "nodeoverlay"), os.ModePerm)
wwlog.Verbose("for ephermal mount use tempdir %s", runDir)
if err = os.Mkdir(path.Join(runDir, "work"), os.ModePerm); err != nil {
return err
}
if err = os.Mkdir(path.Join(runDir, "lower"), os.ModePerm); err != nil {
return err
}
if err = os.Mkdir(path.Join(runDir, "nodeoverlay"), os.ModePerm); err != nil {
return err
}
// handle all lower object, have some extra logic if the object is a file
for _, obj := range lowerObjects {
newFile := ""
if !strings.HasSuffix(obj, "/") {
newFile = filepath.Base(obj)
obj = filepath.Dir(obj)
}
err = os.MkdirAll(filepath.Join(overlayDir, "lower", obj), os.ModePerm)
err = os.Mkdir(filepath.Join(runDir, "lower", obj), os.ModePerm)
if err != nil {
wwlog.Warn("couldn't create directory for mounts: %s", err)
}
if newFile != "" {
desc, err := os.Create(filepath.Join(overlayDir, "lower", obj, newFile))
desc, err := os.Create(filepath.Join(runDir, "lower", obj, newFile))
if err != nil {
wwlog.Warn("couldn't create directory for mounts: %s", err)
}
defer desc.Close()
}
}
containerPath := container.RootFsDir(containerName)
// running in a private PID space, so also make / private, so that nothing gets out from here
err = syscall.Mount("", "/", "", syscall.MS_PRIVATE|syscall.MS_REC, "")
if err != nil {
return errors.Wrap(err, "failed to mount")
}
ps1Str := fmt.Sprintf("[%s] Warewulf> ", containerName)
if len(lowerObjects) != 0 && nodename == "" {
options := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s",
path.Join(overlayDir, "lower"), containerPath, path.Join(overlayDir, "work"))
path.Join(runDir, "lower"), containerPath, path.Join(runDir, "work"))
wwlog.Debug("overlay options: %s", options)
err = syscall.Mount("overlay", containerPath, "overlay", 0, options)
if err != nil {
Expand All @@ -97,13 +107,13 @@ func CobraRunE(cmd *cobra.Command, args []string) (err error) {
}
overlays := nodes[0].SystemOverlay.GetSlice()
overlays = append(overlays, nodes[0].RuntimeOverlay.GetSlice()...)
err = overlay.BuildOverlayIndir(nodes[0], overlays, path.Join(overlayDir, "nodeoverlay"))
err = overlay.BuildOverlayIndir(nodes[0], overlays, path.Join(runDir, "nodeoverlay"))
if err != nil {
wwlog.Error("Could not build overlay: %s", err)
os.Exit(1)
}
options := fmt.Sprintf("lowerdir=%s:%s:%s",
path.Join(overlayDir, "lower"), containerPath, path.Join(overlayDir, "nodeoverlay"))
path.Join(runDir, "lower"), containerPath, path.Join(runDir, "nodeoverlay"))
wwlog.Debug("overlay options: %s", options)
err = syscall.Mount("overlay", containerPath, "overlay", 0, options)
if err != nil {
Expand Down Expand Up @@ -165,11 +175,8 @@ func CobraRunE(cmd *cobra.Command, args []string) (err error) {
os.Setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin")
os.Setenv("HISTFILE", "/dev/null")

_ = syscall.Exec(args[1], args[1:], os.Environ())
/*
Exec replaces the actual program, so nothing to do here afterwards
*/
return nil
wwlog.Debug("Exec: %s %s", args[1], args[1:])
return syscall.Exec(args[1], args[1:], os.Environ())
}

/*
Expand Down
42 changes: 19 additions & 23 deletions internal/app/wwctl/container/exec/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
package exec

import (
"errors"
"fmt"
"os"
"os/exec"
"path"
"syscall"
"time"

warewulfconf "github.com/warewulf/warewulf/internal/pkg/config"

"github.com/spf13/cobra"
"github.com/warewulf/warewulf/internal/pkg/container"
"github.com/warewulf/warewulf/internal/pkg/util"
Expand All @@ -20,23 +23,25 @@ import (
/*
fork off a process with a new PID space
*/
func runContainedCmd(args []string) error {
var err error
if tempDir == "" {
tempDir, err = os.MkdirTemp(os.TempDir(), "overlay")
if err != nil {
wwlog.Warn("couldn't create temp dir for overlay", err)
func runContainedCmd(args []string) (err error) {
conf := warewulfconf.Get()
containerName := args[0]
runDir := container.RunDir(containerName)
if err := os.Mkdir(runDir, 0750); err != nil {
if _, existerr := os.Stat(runDir); !os.IsNotExist(existerr) {
return errors.New("run directory already exists: another container command may already be running")
} else {
return fmt.Errorf("unable to create run directory: %w", err)
}
defer func() {
err = os.RemoveAll(tempDir)
if err != nil {
wwlog.Warn("Couldn't remove temp dir for ephermal mounts:", err)
}
}()
}
defer func() {
if err := errors.Join(os.RemoveAll(runDir), err); err != nil {
wwlog.Error("error removing run directory: %w", err)
}
}()
logStr := fmt.Sprint(wwlog.GetLogLevel())
wwlog.Verbose("Running contained command: %s", args[1:])
c := exec.Command("/proc/self/exe", append([]string{"--loglevel", logStr, "--tempdir", tempDir, "container", "exec", "__child"}, args...)...)
c := exec.Command("/proc/self/exe", append([]string{"--warewulfconf", conf.GetWarewulfConf(), "--loglevel", logStr, "container", "exec", "__child"}, args...)...)

c.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS,
Expand All @@ -45,16 +50,7 @@ func runContainedCmd(args []string) error {
c.Stdout = os.Stdout
c.Stderr = os.Stderr

if err := c.Run(); err != nil {
fmt.Printf("Command exited non-zero, not rebuilding/updating VNFS image\n")
// defer is not called before os.Exit(0)
err = os.RemoveAll(tempDir)
if err != nil {
wwlog.Warn("Couldn't remove temp dir for ephermal mounts:", err)
}
os.Exit(0)
}
return nil
return c.Run()
}

func CobraRunE(cmd *cobra.Command, args []string) error {
Expand Down
2 changes: 0 additions & 2 deletions internal/app/wwctl/container/exec/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,13 @@ var (
}
SyncUser bool
binds []string
tempDir string
nodeName string
)

func init() {
baseCmd.AddCommand(child.GetCommand())
baseCmd.PersistentFlags().StringArrayVarP(&binds, "bind", "b", []string{}, "Bind a local path into the container (must exist)")
baseCmd.PersistentFlags().BoolVar(&SyncUser, "syncuser", false, "Synchronize UIDs/GIDs from host to container")
baseCmd.PersistentFlags().StringVar(&tempDir, "tempdir", "", "Use tempdir for constructing the overlay fs (only used if mount points don't exist in container)")
baseCmd.PersistentFlags().StringVarP(&nodeName, "node", "n", "", "Create a read only view of the container for the given node")
}

Expand Down
12 changes: 8 additions & 4 deletions internal/pkg/config/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ type RootConf struct {
MountsContainer []*MountEntry `yaml:"container mounts" default:"[{\"source\": \"/etc/resolv.conf\", \"dest\": \"/etc/resolv.conf\"}]"`
Paths *BuildConfig `yaml:"paths"`

fromFile bool
warewulfconf string
}

// New caches and returns a new [RootConf] initialized with empty
// values, clearing replacing any previously cached value.
func New() *RootConf {
cachedConf = RootConf{}
cachedConf.fromFile = false
cachedConf.warewulfconf = ""
cachedConf.Warewulf = new(WarewulfConf)
cachedConf.DHCP = new(DHCPConf)
cachedConf.TFTP = new(TFTPConf)
Expand Down Expand Up @@ -77,12 +77,12 @@ func Get() *RootConf {
// file.
func (conf *RootConf) Read(confFileName string) error {
wwlog.Debug("Reading warewulf.conf from: %s", confFileName)
conf.warewulfconf = confFileName
if data, err := os.ReadFile(confFileName); err != nil {
return err
} else if err := conf.Parse(data); err != nil {
return err
} else {
conf.fromFile = true
return nil
}
}
Expand Down Expand Up @@ -200,5 +200,9 @@ func (conf *RootConf) SetDynamicDefaults() (err error) {
// InitializedFromFile returns true if [RootConf] memory was read from
// a file, or false otherwise.
func (conf *RootConf) InitializedFromFile() bool {
return conf.fromFile
return conf.warewulfconf != ""
}

func (conf *RootConf) GetWarewulfConf() string {
return conf.warewulfconf
}
1 change: 1 addition & 0 deletions internal/pkg/config/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ func TestInitializedFromFile(t *testing.T) {
assert.False(t, conf.InitializedFromFile())
assert.NoError(t, conf.Read(tempWarewulfConf.Name()))
assert.True(t, conf.InitializedFromFile())
assert.Equal(t, conf.GetWarewulfConf(), tempWarewulfConf.Name())
}

func TestExampleRootConf(t *testing.T) {
Expand Down
4 changes: 4 additions & 0 deletions internal/pkg/container/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ func RootFsDir(name string) string {
return path.Join(SourceDir(name), "rootfs")
}

func RunDir(name string) string {
return path.Join(SourceDir(name), "run")
}

func ImageParentDir() string {
conf := warewulfconf.Get()
return path.Join(conf.Paths.WWProvisiondir, "container/")
Expand Down

0 comments on commit 28ba479

Please sign in to comment.