Skip to content
This repository has been archived by the owner on Dec 13, 2021. It is now read-only.

add support for both attach mode and detach mode #158

Merged
merged 2 commits into from
Jun 27, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions nmz/cli/container/run/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (
"github.com/osrg/namazu/nmz/util/config"
)

func prepare(args []string) (dockerOpt *docker.CreateContainerOptions, removeOnExit bool, nmzCfg config.Config, err error) {
func prepare(args []string) (dockerOpt *docker.CreateContainerOptions, removeOnExit bool, detach bool, nmzCfg config.Config, err error) {
if len(args) < 3 {
// FIXME
err = fmt.Errorf("bad argument: %s", args)
Expand All @@ -39,6 +39,7 @@ func prepare(args []string) (dockerOpt *docker.CreateContainerOptions, removeOnE
return
}
removeOnExit = flagSet.IsSet("-rm")
detach = flagSet.IsSet("d") || flag.IsSet("-detach")

nmzCfgPath := flagSet.Lookup("-nmz-autopilot").Value.String()
nmzCfg, err = newConfig(nmzCfgPath)
Expand All @@ -61,12 +62,15 @@ func help() string {
Run a command in a new Namazu Container

Docker-compatible options:
-d, --detach [NOT SUPPORTED] Run container in background and print container ID
-d, --detach Run container in background and print container ID
-i, --interactive Keep STDIN open even if not attached
-p Publish a container's port(s) to the host
--name Assign a name to the container
--rm Automatically remove the container when it exits
-t, --tty Allocate a pseudo-TTY
-v, --volume=[] Bind mount a volume
--volumes-from Mount volumes from the specified container(s)
--privileged Give extended privileges to this container

Namazu-specific options:
-nmz-autopilot Namazu configuration file
Expand All @@ -77,7 +81,7 @@ NOTE: Unlike docker, COMMAND is mandatory at the moment.
}

func Run(args []string) int {
dockerOpt, removeOnExit, nmzCfg, err := prepare(args)
dockerOpt, removeOnExit, detach, nmzCfg, err := prepare(args)
if err != nil {
// do not panic here
fmt.Fprintf(os.Stderr, "%s\n", err)
Expand All @@ -91,7 +95,7 @@ func Run(args []string) int {
}

containerExitStatusChan := make(chan error)
c, err := ns.Boot(client, dockerOpt, containerExitStatusChan)
c, err := ns.Boot(client, dockerOpt, detach, containerExitStatusChan)
if err == docker.ErrNoSuchImage {
log.Critical(err)
// TODO: pull the image automatically
Expand Down
96 changes: 74 additions & 22 deletions nmz/cli/container/run/runflag.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,56 +20,108 @@ import (
// FIXME: we should not rely on internal docker packages..
"github.com/docker/docker/opts"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/go-connections/nat"
docker "github.com/fsouza/go-dockerclient"
)

// TODO: we should support more options..
func parseRun(cmd *flag.FlagSet, args []string) (*docker.CreateContainerOptions, error) {
var (
flStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Keep STDIN open even if not attached")
flTty = cmd.Bool([]string{"t", "-tty"}, false, "Allocate a pseudo-TTY")
flDetach = cmd.Bool([]string{"d", "-detach"}, false, "[NOT SUPPORTED] Run container in background and print container ID")
attachStdin = true
attachStdout = true
attachStderr = true
stdinOnce = true

flVolumes = opts.NewListOpts(nil)
flVolumesFrom = opts.NewListOpts(nil)
flPublish = opts.NewListOpts(nil)

flStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Keep STDIN open even if not attached")
flTty = cmd.Bool([]string{"t", "-tty"}, false, "Allocate a pseudo-TTY")
flPrivileged = cmd.Bool([]string{"-privileged"}, false, "Give extended privileges to this container")
flDetach = cmd.Bool([]string{"d", "-detach"}, false, "Run container in background and print container ID")
flAutoRemove = cmd.Bool([]string{"-rm"}, false, "Automatically remove the container when it exits")

flName = cmd.String([]string{"-name"}, "", "Assign a name to the container")
flVolumes = opts.NewListOpts(nil)
// the caller should handle "-rm" with cmd.IsSet()
_ = cmd.Bool([]string{"-rm"}, false, "Automatically remove the container when it exits")
flNetMode = cmd.String([]string{"-net"}, "default", "Connect a container to a network")

// the caller should handle "-nmz-autopilot"
_ = cmd.String([]string{"-nmz-autopilot"}, "", "Namazu configuration file")
)
cmd.Var(&flVolumes, []string{"v", "-volume"}, "Bind mount a volume")
cmd.Var(&flPublish, []string{"p"}, "Publish a container's port(s) to the host")
cmd.Var(&flVolumesFrom, []string{"-volumes-from"}, "Mount volumes from the specified container(s)")

if err := cmd.Parse(args); err != nil {
return nil, err
}
if !*flStdin {
return nil, fmt.Errorf("--interactive is expected.")
}
if !*flTty {
return nil, fmt.Errorf("--tty is expected.")
}
if *flDetach {
return nil, fmt.Errorf("Currently, --detach is not supported.")
}

parsedArgs := cmd.Args()
if len(parsedArgs) < 2 {
return nil, fmt.Errorf("requires a minimum of 2 arguments")

if !*flDetach {
if !*flStdin {
return nil, fmt.Errorf("--interactive is expected in attach mode.")
}
if !*flTty {
return nil, fmt.Errorf("--tty is expected in attach mode.")
}
if len(parsedArgs) < 2 {
return nil, fmt.Errorf("requires a minimum of 2 arguments in attach mode.")
}
} else {
if *flAutoRemove {
return nil, fmt.Errorf("--rm is not availible in detach mode.")
}
attachStdin = false
attachStdout = false
attachStderr = false
stdinOnce = false
}

image := parsedArgs[0]
execCmd := parsedArgs[1:]

// FIXME: we should implement this parse function ourselves..
_, portMap, err := nat.ParsePortSpecs(flPublish.GetAll())
if err != nil {
return nil, err
}

// Transform nat.PortMap to docker.PortMap(map[string][]PortBindings).
portBindings := make(map[docker.Port][]docker.PortBinding)
for port, bindings := range portMap {
for _, binding := range bindings {
// nat.Port string
bindingSlice, exists := portBindings[docker.Port(port)]
if !exists {
bindingSlice = []docker.PortBinding{}
}

portBindings[docker.Port(port)] = append(bindingSlice, docker.PortBinding{
HostIP: binding.HostIP,
HostPort: binding.HostPort,
})
}
}

dockerOpt := docker.CreateContainerOptions{
Name: *flName,
Config: &docker.Config{
Image: image,
Cmd: execCmd,
OpenStdin: *flStdin,
StdinOnce: true,
AttachStdin: true,
AttachStdout: true,
AttachStderr: true,
StdinOnce: stdinOnce,
AttachStdin: attachStdin,
AttachStdout: attachStdout,
AttachStderr: attachStderr,
Tty: *flTty,
},
HostConfig: &docker.HostConfig{
Binds: flVolumes.GetAllOrEmpty(),
Binds: flVolumes.GetAllOrEmpty(),
Privileged: *flPrivileged,
PortBindings: portBindings,
NetworkMode: *flNetMode,
VolumesFrom: flVolumesFrom.GetAllOrEmpty(),
},
}
return &dockerOpt, nil
Expand Down
12 changes: 10 additions & 2 deletions nmz/container/ns/boot.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
docker "github.com/fsouza/go-dockerclient"
)

func Boot(client *docker.Client, opt *docker.CreateContainerOptions,
func Boot(client *docker.Client, opt *docker.CreateContainerOptions, detach bool,
exitCh chan error) (*docker.Container, error) {
log.Debugf("Creating container for image %s", opt.Config.Image)
container, err := client.CreateContainer(*opt)
Expand All @@ -34,7 +34,15 @@ func Boot(client *docker.Client, opt *docker.CreateContainerOptions,

log.Debugf("Starting container %s", container.ID)
go func() {
exitCh <- dockerpty.Start(client, container, opt.HostConfig)
if detach {
err = client.StartContainer(container.ID, opt.HostConfig)
if err == nil {
_, err = client.WaitContainer(container.ID)
}
exitCh <- err
} else {
exitCh <- dockerpty.Start(client, container, opt.HostConfig)
}
}()

trial := 0
Expand Down