Files
weave/prog/weaveutil/container.go
T

305 lines
7.6 KiB
Go

package main
import (
"fmt"
"os"
"strings"
docker "github.com/fsouza/go-dockerclient"
)
func inspectContainer(containerNameOrID string) (*docker.Container, error) {
c, err := newVersionedDockerClientFromEnv(defaulDockerAPIVersion)
if err != nil {
return nil, fmt.Errorf("unable to connect to docker: %s", err)
}
container, err := c.InspectContainer(containerNameOrID)
if err != nil {
return nil, fmt.Errorf("unable to inspect container %s: %s", containerNameOrID, err)
}
return container, nil
}
func containerPid(containerID string) (int, error) {
container, err := inspectContainer(containerID)
if err != nil {
return 0, err
}
if container.State.Pid == 0 {
return 0, fmt.Errorf("container %s not running", containerID)
}
return container.State.Pid, nil
}
func containerID(args []string) error {
if len(args) < 1 {
cmdUsage("container-id", "<container-name-or-short-id>")
}
container, err := inspectContainer(args[0])
if err != nil {
return err
}
fmt.Print(container.ID)
return nil
}
func containerState(args []string) error {
if len(args) < 1 {
cmdUsage("container-state", "<container-id> [<image-prefix>]")
}
container, err := inspectContainer(args[0])
if err != nil {
return err
}
if len(args) == 1 {
fmt.Print(container.State.StateString())
} else {
imagePrefix := args[1]
if strings.HasPrefix(container.Config.Image, imagePrefix) {
fmt.Print(container.State.StateString())
} else {
if container.State.Running {
fmt.Print("running image mismatch: ", container.Config.Image)
} else {
fmt.Print("image mismatch: ", container.Config.Image)
}
}
}
return nil
}
func containerFQDN(args []string) error {
if len(args) < 1 {
cmdUsage("container-fqdn", "<container-id>")
}
container, err := inspectContainer(args[0])
if err != nil {
return err
}
fmt.Print(container.Config.Hostname, ".", container.Config.Domainname)
return nil
}
func parseContainerArgs(args []string) docker.CreateContainerOptions {
env := []string{}
labels := map[string]string{}
name := ""
net := ""
pid := ""
privileged := false
restart := docker.NeverRestart()
volumes := []string{}
volumesFrom := []string{}
done := false
for i := 0; i < len(args) && !done; {
switch args[i] {
case "-e", "--env":
if v := os.Getenv(args[i+1]); v != "" {
env = append(env, args[i+1]+"="+v)
} else {
env = append(env, args[i+1])
}
args = append(args[:i], args[i+2:]...)
case "-l", "--label":
key, value := parseLabel(args[i+1])
labels[key] = value
args = append(args[:i], args[i+2:]...)
case "--name":
name = args[i+1]
args = append(args[:i], args[i+2:]...)
case "--net":
net = args[i+1]
args = append(args[:i], args[i+2:]...)
case "--pid":
pid = args[i+1]
args = append(args[:i], args[i+2:]...)
case "--privileged":
privileged = true
args = append(args[:i], args[i+1:]...)
case "--restart":
restart = docker.RestartPolicy{Name: args[i+1]}
args = append(args[:i], args[i+2:]...)
case "-v", "--volume":
// Must dedup binds, otherwise, container fails creation
skip := false
for _, v := range volumes {
if v == args[i+1] {
skip = true
}
}
if !skip {
volumes = append(volumes, args[i+1])
}
args = append(args[:i], args[i+2:]...)
case "--volumes-from":
volumesFrom = append(volumesFrom, args[i+1])
args = append(args[:i], args[i+2:]...)
default:
done = true
}
}
if len(args) < 2 {
cmdUsage("run-container", `[options] <image> <cmd> [[<cmd-options>] <cmd-arg1> [<cmd-arg2> ...]]
-e, --env list Set environment variables
--name string Assign a name to the container
--net string Network Mode
--pid string PID namespace to use
--privileged Give extended privileges to this container
--restart string Restart policy to apply when a container exits (default "no")
-v, --volume list Bind mount a volume
--volumes-from list Mount volumes from the specified container(s)
`)
}
image := args[0]
cmds := args[1:]
config := docker.Config{Image: image, Env: env, Cmd: cmds, Labels: labels}
hostConfig := docker.HostConfig{NetworkMode: net, PidMode: pid, Privileged: privileged, RestartPolicy: restart, Binds: volumes, VolumesFrom: volumesFrom}
return docker.CreateContainerOptions{Name: name, Config: &config, HostConfig: &hostConfig}
}
func runContainer(args []string) error {
containerOptions := parseContainerArgs(args)
c, err := newVersionedDockerClientFromEnv(defaulDockerAPIVersion)
if err != nil {
return fmt.Errorf("unable to connect to docker: %s", err)
}
container, err := c.CreateContainer(containerOptions)
if err != nil {
return fmt.Errorf("unable to create container: %s", err)
}
err = c.StartContainer(container.ID, containerOptions.HostConfig)
if err != nil {
return fmt.Errorf("unable to start container: %s", err)
}
fmt.Print(container.ID)
return nil
}
func parseLabel(s string) (key, value string) {
pos := strings.Index(s, "=")
if pos == -1 { // no value - set it to blank
return s, ""
}
return s[:pos], s[pos+1:]
}
func listContainers(args []string) error {
if len(args) > 1 {
cmdUsage("list-containers", "[<label>]")
}
c, err := newVersionedDockerClientFromEnv(defaulDockerAPIVersion)
if err != nil {
return fmt.Errorf("unable to connect to docker: %s", err)
}
opts := docker.ListContainersOptions{All: true}
if len(args) == 1 {
label := args[0]
opts.Filters = map[string][]string{"label": {label}}
}
containers, err := c.ListContainers(opts)
if err != nil {
return fmt.Errorf("unable to list containers: %s", err)
}
for _, container := range containers {
fmt.Println(container.ID)
}
return nil
}
func stopContainer(args []string) error {
if len(args) < 1 {
cmdUsage("stop-container", "<container-id> [<container-id2> ...]")
}
c, err := newVersionedDockerClientFromEnv(defaulDockerAPIVersion)
if err != nil {
return fmt.Errorf("unable to connect to docker: %s", err)
}
for _, containerID := range args {
err = c.StopContainer(containerID, 10)
if err != nil {
return fmt.Errorf("unable to stop container %s: %s", containerID, err)
}
}
return nil
}
func killContainer(args []string) error {
if len(args) < 1 {
cmdUsage("kill-container", "<container-id> [<container-id2> ...]")
}
c, err := newVersionedDockerClientFromEnv(defaulDockerAPIVersion)
if err != nil {
return fmt.Errorf("unable to connect to docker: %s", err)
}
for _, containerID := range args {
err = c.KillContainer(docker.KillContainerOptions{ID: containerID, Signal: docker.SIGKILL})
if err != nil {
return fmt.Errorf("unable to stop container %s: %s", containerID, err)
}
}
return nil
}
func removeContainer(args []string) error {
if len(args) < 1 {
cmdUsage("remove-container", "[-f | --force] [-v | --volumes] <container-id> [<container-id2> ...]")
}
force := false
volumes := false
for i := 0; i < len(args); {
switch args[i] {
case "--force":
case "-f":
force = true
args = append(args[:i], args[i+1:]...)
case "--volumes":
case "-v":
volumes = true
args = append(args[:i], args[i+1:]...)
default:
i++
}
}
c, err := newVersionedDockerClientFromEnv(defaulDockerAPIVersion)
if err != nil {
return fmt.Errorf("unable to connect to docker: %s", err)
}
for _, containerID := range args {
err = c.RemoveContainer(docker.RemoveContainerOptions{
ID: containerID, Force: force, RemoveVolumes: volumes})
if err != nil {
return fmt.Errorf("unable to stop container %s: %s", containerID, err)
}
}
return nil
}