diff --git a/internal/app/wwctl/container/exec/child/main.go b/internal/app/wwctl/container/exec/child/main.go new file mode 100644 index 00000000..e718c0bc --- /dev/null +++ b/internal/app/wwctl/container/exec/child/main.go @@ -0,0 +1,48 @@ +// + build linux + +package child + +import ( + "fmt" + "github.com/hpcng/warewulf/internal/pkg/container" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "github.com/spf13/cobra" + "os" + "syscall" +) + +func CobraRunE(cmd *cobra.Command, args []string) error { + + if os.Getpid() != 1 { + wwlog.Printf(wwlog.ERROR, "PID is not 1: %d\n", os.Getpid()) + os.Exit(1) + } + + containerName := args[0] + + if container.ValidSource(containerName) == false { + wwlog.Printf(wwlog.ERROR, "Unknown Warewulf container: %s\n", containerName) + os.Exit(1) + } + + syscall.Mount("", "/", "", syscall.MS_PRIVATE, "") + + containerPath := container.RootFsDir(containerName) + + syscall.Chroot(containerPath) + os.Chdir("/") + + syscall.Mount("rootfs", "rootfs", "", syscall.MS_BIND, "") + syscall.Mount("/proc", "/proc", "proc", 0, "") + + ps1string := fmt.Sprintf("[%s] Warewulf> ", containerName) + os.Setenv("PS1", ps1string) + + err := syscall.Exec(args[1], args[1:], os.Environ()) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + + return nil +} diff --git a/internal/app/wwctl/container/exec/child/root.go b/internal/app/wwctl/container/exec/child/root.go new file mode 100644 index 00000000..6df31ff4 --- /dev/null +++ b/internal/app/wwctl/container/exec/child/root.go @@ -0,0 +1,21 @@ +package child + +import "github.com/spf13/cobra" + +var ( + baseCmd = &cobra.Command{ + Use: "__child", + Hidden: true, + RunE: CobraRunE, + Args: cobra.MinimumNArgs(1), + } +) + +func init() { + +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/container/exec/main.go b/internal/app/wwctl/container/exec/main.go new file mode 100644 index 00000000..23db6553 --- /dev/null +++ b/internal/app/wwctl/container/exec/main.go @@ -0,0 +1,40 @@ +// +build linux + +package exec + +import ( + "fmt" + "github.com/hpcng/warewulf/internal/pkg/container" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "github.com/spf13/cobra" + "os" + "os/exec" + "syscall" +) + +func CobraRunE(cmd *cobra.Command, args []string) error { + + containerName := args[0] + + if container.ValidSource(containerName) == false { + wwlog.Printf(wwlog.ERROR, "Unknown Warewulf container: %s\n", containerName) + os.Exit(1) + } + + c := exec.Command("/proc/self/exe", append([]string{"container", "exec", "__child"}, args...)...) + + //c := exec.Command("/bin/sh") + c.SysProcAttr = &syscall.SysProcAttr{ + Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS, + } + c.Stdin = os.Stdin + c.Stdout = os.Stdout + c.Stderr = os.Stderr + + if err := c.Run(); err != nil { + fmt.Println("ERROR", err) + os.Exit(1) + } + + return nil +} diff --git a/internal/app/wwctl/container/exec/non-linux.go b/internal/app/wwctl/container/exec/non-linux.go new file mode 100644 index 00000000..a391ec15 --- /dev/null +++ b/internal/app/wwctl/container/exec/non-linux.go @@ -0,0 +1,14 @@ +// +build !linux + +package exec + +import ( + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "github.com/spf13/cobra" +) + +func CobraRunE(cmd *cobra.Command, args []string) error { + wwlog.Printf(wwlog.ERROR, "This command does not work on non-Linux hosts\n") + + return nil +} diff --git a/internal/app/wwctl/container/exec/root.go b/internal/app/wwctl/container/exec/root.go new file mode 100644 index 00000000..049ca014 --- /dev/null +++ b/internal/app/wwctl/container/exec/root.go @@ -0,0 +1,26 @@ +package exec + +import ( + "github.com/hpcng/warewulf/internal/app/wwctl/container/exec/child" + "github.com/spf13/cobra" +) + +var ( + baseCmd = &cobra.Command{ + Use: "exec", + Short: "Spawn any command inside a Warewulf container", + Long: "Run a command inside a Warewulf container ", + RunE: CobraRunE, + Args: cobra.MinimumNArgs(1), + } +) + +func init() { + baseCmd.AddCommand(child.GetCommand()) + +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/container/root.go b/internal/app/wwctl/container/root.go index 3044c66a..9bda463a 100644 --- a/internal/app/wwctl/container/root.go +++ b/internal/app/wwctl/container/root.go @@ -2,6 +2,7 @@ package container import ( "github.com/hpcng/warewulf/internal/app/wwctl/container/build" + "github.com/hpcng/warewulf/internal/app/wwctl/container/exec" "github.com/hpcng/warewulf/internal/app/wwctl/container/list" "github.com/hpcng/warewulf/internal/app/wwctl/container/pull" "github.com/spf13/cobra" @@ -10,7 +11,7 @@ import ( var ( baseCmd = &cobra.Command{ Use: "container", - Short: "VNFS image management", + Short: "Container / VNFS image management", Long: "Virtual Node File System (VNFS) image management", } test bool @@ -20,6 +21,7 @@ func init() { baseCmd.AddCommand(build.GetCommand()) baseCmd.AddCommand(list.GetCommand()) baseCmd.AddCommand(pull.GetCommand()) + baseCmd.AddCommand(exec.GetCommand()) }