Refactor to remove cmd from container
Pass the container's command via args Remove execin function and just look for an existing nspid file to join the namespace Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)
This commit is contained in:
parent
39fe4b4712
commit
d236be61b0
|
@ -5,17 +5,12 @@ type Container struct {
|
||||||
ReadonlyFs bool `json:"readonly_fs,omitempty"`
|
ReadonlyFs bool `json:"readonly_fs,omitempty"`
|
||||||
User string `json:"user,omitempty"`
|
User string `json:"user,omitempty"`
|
||||||
WorkingDir string `json:"working_dir,omitempty"`
|
WorkingDir string `json:"working_dir,omitempty"`
|
||||||
Command *Command `json:"command,omitempty"`
|
Env []string `json:"environment,omitempty"`
|
||||||
Namespaces Namespaces `json:"namespaces,omitempty"`
|
Namespaces Namespaces `json:"namespaces,omitempty"`
|
||||||
Capabilities Capabilities `json:"capabilities,omitempty"`
|
Capabilities Capabilities `json:"capabilities,omitempty"`
|
||||||
Network *Network `json:"network,omitempty"`
|
Network *Network `json:"network,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Command struct {
|
|
||||||
Args []string `json:"args,omitempty"`
|
|
||||||
Env []string `json:"environment,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Network struct {
|
type Network struct {
|
||||||
IP string `json:"ip,omitempty"`
|
IP string `json:"ip,omitempty"`
|
||||||
Gateway string `json:"gateway,omitempty"`
|
Gateway string `json:"gateway,omitempty"`
|
||||||
|
|
|
@ -1,16 +1,11 @@
|
||||||
{
|
{
|
||||||
"hostname": "koye",
|
"hostname": "koye",
|
||||||
"command": {
|
"environment": [
|
||||||
"args": [
|
"HOME=/",
|
||||||
"/bin/bash"
|
"PATH=PATH=$PATH:/bin:/usr/bin:/sbin:/usr/sbin",
|
||||||
],
|
"container=docker",
|
||||||
"environment": [
|
"TERM=xterm-256color"
|
||||||
"HOME=/",
|
],
|
||||||
"PATH=PATH=$PATH:/bin:/usr/bin:/sbin:/usr/sbin",
|
|
||||||
"container=docker",
|
|
||||||
"TERM=xterm-256color"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"namespaces": [
|
"namespaces": [
|
||||||
"NEWIPC",
|
"NEWIPC",
|
||||||
"NEWNS",
|
"NEWNS",
|
||||||
|
|
|
@ -16,17 +16,13 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
func execCommand(container *libcontainer.Container) (int, error) {
|
func execCommand(container *libcontainer.Container, args []string) (int, error) {
|
||||||
master, console, err := createMasterAndConsole()
|
master, console, err := createMasterAndConsole()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
|
|
||||||
command := exec.Command("nsinit", "init", console)
|
command := createCommand(container, console, args)
|
||||||
command.SysProcAttr = &syscall.SysProcAttr{
|
|
||||||
Cloneflags: uintptr(getNamespaceFlags(container.Namespaces) | syscall.CLONE_VFORK), // we need CLONE_VFORK so we can wait on the child
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a pipe so that we can syncronize with the namespaced process and
|
// create a pipe so that we can syncronize with the namespaced process and
|
||||||
// pass the veth name to the child
|
// pass the veth name to the child
|
||||||
inPipe, err := command.StdinPipe()
|
inPipe, err := command.StdinPipe()
|
||||||
|
@ -39,6 +35,7 @@ func execCommand(container *libcontainer.Container) (int, error) {
|
||||||
if err := writePidFile(command); err != nil {
|
if err := writePidFile(command); err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
|
defer deletePidFile()
|
||||||
|
|
||||||
if container.Network != nil {
|
if container.Network != nil {
|
||||||
vethPair, err := setupVeth(container.Network.Bridge, command.Process.Pid)
|
vethPair, err := setupVeth(container.Network.Bridge, command.Process.Pid)
|
||||||
|
@ -134,3 +131,15 @@ func createVethPair() (name1 string, name2 string, err error) {
|
||||||
func writePidFile(command *exec.Cmd) error {
|
func writePidFile(command *exec.Cmd) error {
|
||||||
return ioutil.WriteFile(".nspid", []byte(fmt.Sprint(command.Process.Pid)), 0655)
|
return ioutil.WriteFile(".nspid", []byte(fmt.Sprint(command.Process.Pid)), 0655)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func deletePidFile() error {
|
||||||
|
return os.Remove(".nspid")
|
||||||
|
}
|
||||||
|
|
||||||
|
func createCommand(container *libcontainer.Container, console string, args []string) *exec.Cmd {
|
||||||
|
command := exec.Command("nsinit", append([]string{"init", console}, args...)...)
|
||||||
|
command.SysProcAttr = &syscall.SysProcAttr{
|
||||||
|
Cloneflags: uintptr(getNamespaceFlags(container.Namespaces) | syscall.CLONE_VFORK), // we need CLONE_VFORK so we can wait on the child
|
||||||
|
}
|
||||||
|
return command
|
||||||
|
}
|
||||||
|
|
|
@ -5,19 +5,13 @@ import (
|
||||||
"github.com/dotcloud/docker/pkg/libcontainer"
|
"github.com/dotcloud/docker/pkg/libcontainer"
|
||||||
"github.com/dotcloud/docker/pkg/libcontainer/capabilities"
|
"github.com/dotcloud/docker/pkg/libcontainer/capabilities"
|
||||||
"github.com/dotcloud/docker/pkg/system"
|
"github.com/dotcloud/docker/pkg/system"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
func execinCommand(container *libcontainer.Container) (int, error) {
|
func execinCommand(container *libcontainer.Container, nspid int, args []string) (int, error) {
|
||||||
nspid, err := readPid()
|
|
||||||
if err != nil {
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ns := range container.Namespaces {
|
for _, ns := range container.Namespaces {
|
||||||
if err := system.Unshare(namespaceMap[ns]); err != nil {
|
if err := system.Unshare(namespaceMap[ns]); err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
|
@ -67,7 +61,7 @@ func execinCommand(container *libcontainer.Container) (int, error) {
|
||||||
if err := capabilities.DropCapabilities(container); err != nil {
|
if err := capabilities.DropCapabilities(container); err != nil {
|
||||||
return -1, fmt.Errorf("drop capabilities %s", err)
|
return -1, fmt.Errorf("drop capabilities %s", err)
|
||||||
}
|
}
|
||||||
if err := system.Exec(container.Command.Args[0], container.Command.Args[0:], container.Command.Env); err != nil {
|
if err := system.Exec(args[0], args[0:], container.Env); err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,24 +78,12 @@ func execinCommand(container *libcontainer.Container) (int, error) {
|
||||||
if err := capabilities.DropCapabilities(container); err != nil {
|
if err := capabilities.DropCapabilities(container); err != nil {
|
||||||
return -1, fmt.Errorf("drop capabilities %s", err)
|
return -1, fmt.Errorf("drop capabilities %s", err)
|
||||||
}
|
}
|
||||||
if err := system.Exec(container.Command.Args[0], container.Command.Args[0:], container.Command.Env); err != nil {
|
if err := system.Exec(args[0], args[0:], container.Env); err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
}
|
}
|
||||||
|
|
||||||
func readPid() (int, error) {
|
|
||||||
data, err := ioutil.ReadFile(".nspid")
|
|
||||||
if err != nil {
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
pid, err := strconv.Atoi(string(data))
|
|
||||||
if err != nil {
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
return pid, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getNsFds(pid int, container *libcontainer.Container) ([]uintptr, error) {
|
func getNsFds(pid int, container *libcontainer.Container) ([]uintptr, error) {
|
||||||
fds := make([]uintptr, len(container.Namespaces))
|
fds := make([]uintptr, len(container.Namespaces))
|
||||||
for i, ns := range container.Namespaces {
|
for i, ns := range container.Namespaces {
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
func initCommand(container *libcontainer.Container, console string) error {
|
func initCommand(container *libcontainer.Container, console string, args []string) error {
|
||||||
rootfs, err := resolveRootfs()
|
rootfs, err := resolveRootfs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -72,7 +72,7 @@ func initCommand(container *libcontainer.Container, console string) error {
|
||||||
return fmt.Errorf("chdir to %s %s", container.WorkingDir, err)
|
return fmt.Errorf("chdir to %s %s", container.WorkingDir, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := system.Exec(container.Command.Args[0], container.Command.Args[0:], container.Command.Env); err != nil {
|
if err := system.Exec(args[0], args[0:], container.Env); err != nil {
|
||||||
return fmt.Errorf("exec %s", err)
|
return fmt.Errorf("exec %s", err)
|
||||||
}
|
}
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
|
|
|
@ -4,8 +4,10 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/dotcloud/docker/pkg/libcontainer"
|
"github.com/dotcloud/docker/pkg/libcontainer"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -25,24 +27,29 @@ func main() {
|
||||||
}
|
}
|
||||||
switch os.Args[1] {
|
switch os.Args[1] {
|
||||||
case "exec":
|
case "exec":
|
||||||
exitCode, err := execCommand(container)
|
var exitCode int
|
||||||
|
nspid, err := readPid()
|
||||||
|
if err != nil {
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if nspid > 0 {
|
||||||
|
exitCode, err = execinCommand(container, nspid, os.Args[2:])
|
||||||
|
} else {
|
||||||
|
exitCode, err = execCommand(container, os.Args[2:])
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
os.Exit(exitCode)
|
os.Exit(exitCode)
|
||||||
case "init":
|
case "init":
|
||||||
if argc != 3 {
|
if argc < 3 {
|
||||||
log.Fatal(ErrWrongArguments)
|
log.Fatal(ErrWrongArguments)
|
||||||
}
|
}
|
||||||
if err := initCommand(container, os.Args[2]); err != nil {
|
if err := initCommand(container, os.Args[2], os.Args[3:]); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
case "execin":
|
|
||||||
exitCode, err := execinCommand(container)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
os.Exit(exitCode)
|
|
||||||
default:
|
default:
|
||||||
log.Fatalf("command not supported for nsinit %s", os.Args[1])
|
log.Fatalf("command not supported for nsinit %s", os.Args[1])
|
||||||
}
|
}
|
||||||
|
@ -61,3 +68,15 @@ func loadContainer() (*libcontainer.Container, error) {
|
||||||
}
|
}
|
||||||
return container, nil
|
return container, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readPid() (int, error) {
|
||||||
|
data, err := ioutil.ReadFile(".nspid")
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
pid, err := strconv.Atoi(string(data))
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
return pid, nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue