Przeglądaj źródła

Merge pull request #5640 from crosbymichael/bump_v0.11.0

Bump version to v0.11.0
Michael Crosby 11 lat temu
rodzic
commit
57aa2f2ef4
100 zmienionych plików z 3587 dodań i 1248 usunięć
  1. 3 0
      .gitignore
  2. 2 14
      .travis.yml
  3. 2 0
      AUTHORS
  4. 12 0
      CHANGELOG.md
  5. 5 1
      CONTRIBUTING.md
  6. 4 0
      Dockerfile
  7. 1 1
      MAINTAINERS
  8. 19 6
      Makefile
  9. 1 1
      README.md
  10. 1 1
      VERSION
  11. 7 0
      api/client/cli.go
  12. 24 15
      api/client/commands.go
  13. 133 0
      api/client/hijack.go
  14. 27 160
      api/client/utils.go
  15. 1 1
      api/common.go
  16. 65 5
      api/server/server.go
  17. 40 72
      api/server/server_unit_test.go
  18. 1 1
      archive/diff.go
  19. 17 9
      builtins/builtins.go
  20. 18 11
      contrib/check-config.sh
  21. 1 1
      contrib/docker-device-tool/device_tool.go
  22. 2 0
      contrib/man/.gitignore
  23. 5 0
      contrib/man/md/Dockerfile
  24. 71 0
      contrib/man/md/README.md
  25. 57 0
      contrib/man/md/docker-attach.1.md
  26. 82 0
      contrib/man/md/docker-build.1.md
  27. 34 0
      contrib/man/md/docker-commit.1.md
  28. 24 0
      contrib/man/md/docker-cp.1.md
  29. 44 0
      contrib/man/md/docker-diff.1.md
  30. 46 0
      contrib/man/md/docker-events.1.md
  31. 26 0
      contrib/man/md/docker-export.1.md
  32. 32 0
      contrib/man/md/docker-history.1.md
  33. 99 0
      contrib/man/md/docker-images.1.md
  34. 39 0
      contrib/man/md/docker-import.1.md
  35. 46 0
      contrib/man/md/docker-info.1.md
  36. 229 0
      contrib/man/md/docker-inspect.1.md
  37. 21 0
      contrib/man/md/docker-kill.1.md
  38. 36 0
      contrib/man/md/docker-load.1.md
  39. 35 0
      contrib/man/md/docker-login.1.md
  40. 26 0
      contrib/man/md/docker-logs.1.md
  41. 15 0
      contrib/man/md/docker-port.1.md
  42. 68 0
      contrib/man/md/docker-ps.1.md
  43. 37 0
      contrib/man/md/docker-pull.1.md
  44. 44 0
      contrib/man/md/docker-push.1.md
  45. 21 0
      contrib/man/md/docker-restart.1.md
  46. 56 0
      contrib/man/md/docker-rm.1.md
  47. 35 0
      contrib/man/md/docker-rmi.1.md
  48. 343 0
      contrib/man/md/docker-run.1.md
  49. 35 0
      contrib/man/md/docker-save.1.md
  50. 55 0
      contrib/man/md/docker-search.1.md
  51. 25 0
      contrib/man/md/docker-start.1.md
  52. 22 0
      contrib/man/md/docker-stop.1.md
  53. 48 0
      contrib/man/md/docker-tag.1.md
  54. 27 0
      contrib/man/md/docker-top.1.md
  55. 23 0
      contrib/man/md/docker-wait.1.md
  56. 187 0
      contrib/man/md/docker.1.md
  57. 22 0
      contrib/man/md/md2man-all.sh
  58. 0 0
      contrib/man/old-man/docker-attach.1
  59. 0 0
      contrib/man/old-man/docker-build.1
  60. 0 0
      contrib/man/old-man/docker-images.1
  61. 0 0
      contrib/man/old-man/docker-info.1
  62. 0 0
      contrib/man/old-man/docker-inspect.1
  63. 0 0
      contrib/man/old-man/docker-rm.1
  64. 50 0
      contrib/man/old-man/docker-rm.md
  65. 0 0
      contrib/man/old-man/docker-rmi.1
  66. 0 0
      contrib/man/old-man/docker-run.1
  67. 0 0
      contrib/man/old-man/docker-tag.1
  68. 0 0
      contrib/man/old-man/docker.1
  69. 82 0
      contrib/mkimage-alpine.sh
  70. 1 0
      contrib/mkimage-arch.sh
  71. 0 1
      contrib/zfs/MAINTAINERS
  72. 0 23
      contrib/zfs/README.md
  73. 153 0
      daemon/attach.go
  74. 405 528
      daemon/container.go
  75. 1 1
      daemon/container_unit_test.go
  76. 215 214
      daemon/daemon.go
  77. 3 3
      daemon/daemon_aufs.go
  78. 7 0
      daemon/daemon_btrfs.go
  79. 7 0
      daemon/daemon_devicemapper.go
  80. 2 2
      daemon/daemon_no_aufs.go
  81. 0 0
      daemon/execdriver/MAINTAINERS
  82. 4 2
      daemon/execdriver/driver.go
  83. 3 3
      daemon/execdriver/execdrivers/execdrivers.go
  84. 24 9
      daemon/execdriver/lxc/driver.go
  85. 0 0
      daemon/execdriver/lxc/info.go
  86. 0 0
      daemon/execdriver/lxc/info_test.go
  87. 6 4
      daemon/execdriver/lxc/init.go
  88. 0 0
      daemon/execdriver/lxc/lxc_init_linux.go
  89. 0 0
      daemon/execdriver/lxc/lxc_init_unsupported.go
  90. 11 10
      daemon/execdriver/lxc/lxc_template.go
  91. 1 1
      daemon/execdriver/lxc/lxc_template_unit_test.go
  92. 36 26
      daemon/execdriver/native/configuration/parse.go
  93. 27 10
      daemon/execdriver/native/configuration/parse_test.go
  94. 44 17
      daemon/execdriver/native/create.go
  95. 56 94
      daemon/execdriver/native/driver.go
  96. 0 0
      daemon/execdriver/native/info.go
  97. 47 0
      daemon/execdriver/native/template/default_template.go
  98. 1 1
      daemon/execdriver/native/term.go
  99. 0 0
      daemon/execdriver/pipes.go
  100. 0 0
      daemon/execdriver/termconsole.go

+ 3 - 0
.gitignore

@@ -23,3 +23,6 @@ bundles/
 vendor/pkg/
 pyenv
 Vagrantfile
+docs/AWS_S3_BUCKET
+docs/GIT_BRANCH
+docs/VERSION

+ 2 - 14
.travis.yml

@@ -10,21 +10,9 @@ install: true
 
 before_script:
   - env | sort
-  - sudo apt-get update -qq
-  - sudo apt-get install -qq python-yaml
-  - git remote add upstream git://github.com/dotcloud/docker.git
-  - upstream=master;
-    if [ "$TRAVIS_PULL_REQUEST" != false ]; then
-      upstream=$TRAVIS_BRANCH;
-    fi;
-    git fetch --append --no-tags upstream refs/heads/$upstream:refs/remotes/upstream/$upstream
-# sometimes we have upstream master already as origin/master (PRs), but other times we don't, so let's just make sure we have a completely unambiguous way to specify "upstream master" from here out
-# but if it's a PR against non-master, we need that upstream branch instead :)
-  - sudo pip install -r docs/requirements.txt
 
 script:
-  - hack/travis/dco.py
-  - hack/travis/gofmt.py
-  - make -sC docs SPHINXOPTS=-qW docs man
+  - hack/make.sh validate-dco
+  - hack/make.sh validate-gofmt
 
 # vim:set sw=2 ts=2:

+ 2 - 0
AUTHORS

@@ -20,6 +20,7 @@ Andrew Munsell <andrew@wizardapps.net>
 Andrews Medina <andrewsmedina@gmail.com>
 Andy Chambers <anchambers@paypal.com>
 andy diller <dillera@gmail.com>
+Andy Goldstein <agoldste@redhat.com>
 Andy Rothfusz <github@metaliveblog.com>
 Andy Smith <github@anarkystic.com>
 Anthony Bishopric <git@anthonybishopric.com>
@@ -44,6 +45,7 @@ Brian Olsen <brian@maven-group.org>
 Brian Shumate <brian@couchbase.com>
 Briehan Lombaard <briehan.lombaard@gmail.com>
 Bruno Bigras <bigras.bruno@gmail.com>
+Bryan Matsuo <bryan.matsuo@gmail.com>
 Caleb Spare <cespare@gmail.com>
 Calen Pennington <cale@edx.org>
 Carl X. Su <bcbcarl@gmail.com>

+ 12 - 0
CHANGELOG.md

@@ -1,5 +1,17 @@
 # Changelog
 
+## 0.11.0 (2014-05-07)
+
+#### Notable features since 0.10.0
+
+* SELinux support for mount and process labels
+* Linked containers can be accessed by hostname
+* Use the net `--net` flag to allow advanced network configuration such as host networking so that containers can use the host's network interfaces
+* Add a ping endpoint to the Remote API to do healthchecks of your docker daemon
+* Logs can now be returned with an optional timestamp
+* Docker now works with registries that support SHA-512
+* Multiple registry endpoints are supported to allow registry mirrors
+
 ## 0.10.0 (2014-04-08)
 
 #### Builder

+ 5 - 1
CONTRIBUTING.md

@@ -82,7 +82,7 @@ editors have plugins that do this automatically, and there's also a git
 pre-commit hook:
 
 ```
-curl -o .git/hooks/pre-commit https://raw.github.com/edsrzf/gofmt-git-hook/master/fmt-check && chmod +x .git/hooks/pre-commit
+curl -o .git/hooks/pre-commit https://raw.githubusercontent.com/edsrzf/gofmt-git-hook/master/fmt-check && chmod +x .git/hooks/pre-commit
 ```
 
 Pull requests descriptions should be as clear as possible and include a
@@ -90,6 +90,10 @@ reference to all the issues that they address.
 
 Pull requests must not contain commits from other users or branches.
 
+Commit messages must start with a capitalized and short summary (max. 50
+chars) written in the imperative, followed by an optional, more detailed
+explanatory text which is separated from the summary by an empty line.
+
 Code review comments may be added to your pull request. Discuss, then make the
 suggested modifications and push additional commits to your feature branch. Be
 sure to post a comment after pushing. The new commits will show up in the pull

+ 4 - 0
Dockerfile

@@ -42,6 +42,7 @@ RUN	apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -yq \
 	libcap-dev \
 	libsqlite3-dev \
 	mercurial \
+	pandoc \
 	reprepro \
 	ruby1.9.1 \
 	ruby1.9.1-dev \
@@ -82,6 +83,9 @@ RUN	go get code.google.com/p/go.tools/cmd/cover
 # TODO replace FPM with some very minimal debhelper stuff
 RUN	gem install --no-rdoc --no-ri fpm --version 1.0.2
 
+# Get the "busybox" image source so we can build locally instead of pulling
+RUN	git clone https://github.com/jpetazzo/docker-busybox.git /docker-busybox
+
 # Setup s3cmd config
 RUN	/bin/echo -e '[default]\naccess_key=$AWS_ACCESS_KEY\nsecret_key=$AWS_SECRET_KEY' > /.s3cfg
 

+ 1 - 1
MAINTAINERS

@@ -1,4 +1,4 @@
-Solomon Hykes <solomon@dotcloud.com> (@shykes)
+Solomon Hykes <solomon@docker.com> (@shykes)
 Guillaume J. Charmes <guillaume@docker.com> (@creack)
 Victor Vieux <vieux@docker.com> (@vieux)
 Michael Crosby <michael@crosbymichael.com> (@crosbymichael)

+ 19 - 6
Makefile

@@ -1,4 +1,4 @@
-.PHONY: all binary build cross default docs docs-build docs-shell shell test test-integration test-integration-cli
+.PHONY: all binary build cross default docs docs-build docs-shell shell test test-unit test-integration test-integration-cli validate
 
 # to allow `make BINDDIR=. shell` or `make BINDDIR= test`
 BINDDIR := bundles
@@ -10,8 +10,9 @@ DOCKER_IMAGE := docker$(if $(GIT_BRANCH),:$(GIT_BRANCH))
 DOCKER_DOCS_IMAGE := docker-docs$(if $(GIT_BRANCH),:$(GIT_BRANCH))
 DOCKER_MOUNT := $(if $(BINDDIR),-v "$(CURDIR)/$(BINDDIR):/go/src/github.com/dotcloud/docker/$(BINDDIR)")
 
-DOCKER_RUN_DOCKER := docker run --rm -it --privileged -e TESTFLAGS -e DOCKER_GRAPHDRIVER -e DOCKER_EXECDRIVER $(DOCKER_MOUNT) "$(DOCKER_IMAGE)"
-DOCKER_RUN_DOCS := docker run --rm -it -p $(if $(DOCSPORT),$(DOCSPORT):)8000 "$(DOCKER_DOCS_IMAGE)"
+DOCKER_RUN_DOCKER := docker run --rm -it --privileged -e TESTFLAGS -e TESTDIRS -e DOCKER_GRAPHDRIVER -e DOCKER_EXECDRIVER $(DOCKER_MOUNT) "$(DOCKER_IMAGE)"
+# to allow `make DOCSDIR=docs docs-shell`
+DOCKER_RUN_DOCS := docker run --rm -it $(if $(DOCSDIR),-v $(CURDIR)/$(DOCSDIR):/$(DOCSDIR)) -e AWS_S3_BUCKET
 
 default: binary
 
@@ -25,13 +26,19 @@ cross: build
 	$(DOCKER_RUN_DOCKER) hack/make.sh binary cross
 
 docs: docs-build
-	$(DOCKER_RUN_DOCS)
+	$(DOCKER_RUN_DOCS) -p $(if $(DOCSPORT),$(DOCSPORT):)8000 "$(DOCKER_DOCS_IMAGE)" mkdocs serve
 
 docs-shell: docs-build
-	$(DOCKER_RUN_DOCS) bash
+	$(DOCKER_RUN_DOCS) -p $(if $(DOCSPORT),$(DOCSPORT):)8000 "$(DOCKER_DOCS_IMAGE)" bash
+
+docs-release: docs-build
+	$(DOCKER_RUN_DOCS) "$(DOCKER_DOCS_IMAGE)" ./release.sh
 
 test: build
-	$(DOCKER_RUN_DOCKER) hack/make.sh binary test test-integration test-integration-cli
+	$(DOCKER_RUN_DOCKER) hack/make.sh binary test-unit test-integration test-integration-cli
+
+test-unit: build
+	$(DOCKER_RUN_DOCKER) hack/make.sh test-unit
 
 test-integration: build
 	$(DOCKER_RUN_DOCKER) hack/make.sh test-integration
@@ -39,6 +46,9 @@ test-integration: build
 test-integration-cli: build
 	$(DOCKER_RUN_DOCKER) hack/make.sh binary test-integration-cli
 
+validate: build
+	$(DOCKER_RUN_DOCKER) hack/make.sh validate-gofmt validate-dco
+
 shell: build
 	$(DOCKER_RUN_DOCKER) bash
 
@@ -46,6 +56,9 @@ build: bundles
 	docker build -t "$(DOCKER_IMAGE)" .
 
 docs-build:
+	cp ./VERSION docs/VERSION
+	echo "$(GIT_BRANCH)" > docs/GIT_BRANCH
+	echo "$(AWS_S3_BUCKET)" > docs/AWS_S3_BUCKET
 	docker build -t "$(DOCKER_DOCS_IMAGE)" docs
 
 bundles:

+ 1 - 1
README.md

@@ -18,7 +18,7 @@ It benefits directly from the experience accumulated over several years
 of large-scale operation and support of hundreds of thousands of
 applications and databases.
 
-![Docker L](docs/theme/docker/static/img/dockerlogo-h.png "Docker")
+![Docker L](docs/theme/mkdocs/img/logo_compressed.png "Docker")
 
 ## Better than VMs
 

+ 1 - 1
VERSION

@@ -1 +1 @@
-0.10.0
+0.11.0

+ 7 - 0
api/client/cli.go

@@ -65,8 +65,13 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, proto, addr string, tlsC
 	var (
 		isTerminal = false
 		terminalFd uintptr
+		scheme     = "http"
 	)
 
+	if tlsConfig != nil {
+		scheme = "https"
+	}
+
 	if in != nil {
 		if file, ok := in.(*os.File); ok {
 			terminalFd = file.Fd()
@@ -86,6 +91,7 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, proto, addr string, tlsC
 		isTerminal: isTerminal,
 		terminalFd: terminalFd,
 		tlsConfig:  tlsConfig,
+		scheme:     scheme,
 	}
 }
 
@@ -99,4 +105,5 @@ type DockerCli struct {
 	isTerminal bool
 	terminalFd uintptr
 	tlsConfig  *tls.Config
+	scheme     string
 }

+ 24 - 15
api/client/commands.go

@@ -1491,7 +1491,8 @@ func (cli *DockerCli) CmdCommit(args ...string) error {
 
 func (cli *DockerCli) CmdEvents(args ...string) error {
 	cmd := cli.Subcmd("events", "[OPTIONS]", "Get real time events from the server")
-	since := cmd.String([]string{"#since", "-since"}, "", "Show previously created events and then stream.")
+	since := cmd.String([]string{"#since", "-since"}, "", "Show all events created since timestamp")
+	until := cmd.String([]string{"-until"}, "", "Stream events until this timestamp")
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
@@ -1500,22 +1501,27 @@ func (cli *DockerCli) CmdEvents(args ...string) error {
 		cmd.Usage()
 		return nil
 	}
-
-	v := url.Values{}
-	if *since != "" {
-		loc := time.FixedZone(time.Now().Zone())
+	var (
+		v   = url.Values{}
+		loc = time.FixedZone(time.Now().Zone())
+	)
+	var setTime = func(key, value string) {
 		format := "2006-01-02 15:04:05 -0700 MST"
-		if len(*since) < len(format) {
-			format = format[:len(*since)]
+		if len(value) < len(format) {
+			format = format[:len(value)]
 		}
-
-		if t, err := time.ParseInLocation(format, *since, loc); err == nil {
-			v.Set("since", strconv.FormatInt(t.Unix(), 10))
+		if t, err := time.ParseInLocation(format, value, loc); err == nil {
+			v.Set(key, strconv.FormatInt(t.Unix(), 10))
 		} else {
-			v.Set("since", *since)
+			v.Set(key, value)
 		}
 	}
-
+	if *since != "" {
+		setTime("since", *since)
+	}
+	if *until != "" {
+		setTime("until", *until)
+	}
 	if err := cli.stream("GET", "/events?"+v.Encode(), nil, cli.out, nil); err != nil {
 		return err
 	}
@@ -1577,6 +1583,7 @@ func (cli *DockerCli) CmdDiff(args ...string) error {
 func (cli *DockerCli) CmdLogs(args ...string) error {
 	cmd := cli.Subcmd("logs", "CONTAINER", "Fetch the logs of a container")
 	follow := cmd.Bool([]string{"f", "-follow"}, false, "Follow log output")
+	times := cmd.Bool([]string{"t", "-timestamps"}, false, "Show timestamps")
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
@@ -1597,14 +1604,16 @@ func (cli *DockerCli) CmdLogs(args ...string) error {
 	}
 
 	v := url.Values{}
-	v.Set("logs", "1")
 	v.Set("stdout", "1")
 	v.Set("stderr", "1")
+	if *times {
+		v.Set("timestamps", "1")
+	}
 	if *follow && container.State.Running {
-		v.Set("stream", "1")
+		v.Set("follow", "1")
 	}
 
-	if err := cli.hijack("POST", "/containers/"+name+"/attach?"+v.Encode(), container.Config.Tty, nil, cli.out, cli.err, nil); err != nil {
+	if err := cli.streamHelper("GET", "/containers/"+name+"/logs?"+v.Encode(), container.Config.Tty, nil, cli.out, cli.err, nil); err != nil {
 		return err
 	}
 	return nil

+ 133 - 0
api/client/hijack.go

@@ -0,0 +1,133 @@
+package client
+
+import (
+	"crypto/tls"
+	"fmt"
+	"io"
+	"net"
+	"net/http"
+	"net/http/httputil"
+	"os"
+	"runtime"
+	"strings"
+
+	"github.com/dotcloud/docker/api"
+	"github.com/dotcloud/docker/dockerversion"
+	"github.com/dotcloud/docker/pkg/term"
+	"github.com/dotcloud/docker/utils"
+)
+
+func (cli *DockerCli) dial() (net.Conn, error) {
+	if cli.tlsConfig != nil && cli.proto != "unix" {
+		return tls.Dial(cli.proto, cli.addr, cli.tlsConfig)
+	}
+	return net.Dial(cli.proto, cli.addr)
+}
+
+func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.ReadCloser, stdout, stderr io.Writer, started chan io.Closer) error {
+	defer func() {
+		if started != nil {
+			close(started)
+		}
+	}()
+
+	req, err := http.NewRequest(method, fmt.Sprintf("/v%s%s", api.APIVERSION, path), nil)
+	if err != nil {
+		return err
+	}
+	req.Header.Set("User-Agent", "Docker-Client/"+dockerversion.VERSION)
+	req.Header.Set("Content-Type", "plain/text")
+	req.Host = cli.addr
+
+	dial, err := cli.dial()
+	if err != nil {
+		if strings.Contains(err.Error(), "connection refused") {
+			return fmt.Errorf("Cannot connect to the Docker daemon. Is 'docker -d' running on this host?")
+		}
+		return err
+	}
+	clientconn := httputil.NewClientConn(dial, nil)
+	defer clientconn.Close()
+
+	// Server hijacks the connection, error 'connection closed' expected
+	clientconn.Do(req)
+
+	rwc, br := clientconn.Hijack()
+	defer rwc.Close()
+
+	if started != nil {
+		started <- rwc
+	}
+
+	var receiveStdout chan error
+
+	var oldState *term.State
+
+	if in != nil && setRawTerminal && cli.isTerminal && os.Getenv("NORAW") == "" {
+		oldState, err = term.SetRawTerminal(cli.terminalFd)
+		if err != nil {
+			return err
+		}
+		defer term.RestoreTerminal(cli.terminalFd, oldState)
+	}
+
+	if stdout != nil || stderr != nil {
+		receiveStdout = utils.Go(func() (err error) {
+			defer func() {
+				if in != nil {
+					if setRawTerminal && cli.isTerminal {
+						term.RestoreTerminal(cli.terminalFd, oldState)
+					}
+					// For some reason this Close call blocks on darwin..
+					// As the client exists right after, simply discard the close
+					// until we find a better solution.
+					if runtime.GOOS != "darwin" {
+						in.Close()
+					}
+				}
+			}()
+
+			// When TTY is ON, use regular copy
+			if setRawTerminal {
+				_, err = io.Copy(stdout, br)
+			} else {
+				_, err = utils.StdCopy(stdout, stderr, br)
+			}
+			utils.Debugf("[hijack] End of stdout")
+			return err
+		})
+	}
+
+	sendStdin := utils.Go(func() error {
+		if in != nil {
+			io.Copy(rwc, in)
+			utils.Debugf("[hijack] End of stdin")
+		}
+		if tcpc, ok := rwc.(*net.TCPConn); ok {
+			if err := tcpc.CloseWrite(); err != nil {
+				utils.Debugf("Couldn't send EOF: %s\n", err)
+			}
+		} else if unixc, ok := rwc.(*net.UnixConn); ok {
+			if err := unixc.CloseWrite(); err != nil {
+				utils.Debugf("Couldn't send EOF: %s\n", err)
+			}
+		}
+		// Discard errors due to pipe interruption
+		return nil
+	})
+
+	if stdout != nil || stderr != nil {
+		if err := <-receiveStdout; err != nil {
+			utils.Debugf("Error receiveStdout: %s", err)
+			return err
+		}
+	}
+
+	if !cli.isTerminal {
+		if err := <-sendStdin; err != nil {
+			utils.Debugf("Error sendStdin: %s", err)
+			return err
+		}
+	}
+	return nil
+}

+ 27 - 160
api/client/utils.go

@@ -2,7 +2,6 @@ package client
 
 import (
 	"bytes"
-	"crypto/tls"
 	"encoding/base64"
 	"encoding/json"
 	"errors"
@@ -11,12 +10,9 @@ import (
 	"io/ioutil"
 	"net"
 	"net/http"
-	"net/http/httputil"
 	"net/url"
 	"os"
 	gosignal "os/signal"
-	"regexp"
-	goruntime "runtime"
 	"strconv"
 	"strings"
 	"syscall"
@@ -33,11 +29,14 @@ var (
 	ErrConnectionRefused = errors.New("Cannot connect to the Docker daemon. Is 'docker -d' running on this host?")
 )
 
-func (cli *DockerCli) dial() (net.Conn, error) {
-	if cli.tlsConfig != nil && cli.proto != "unix" {
-		return tls.Dial(cli.proto, cli.addr, cli.tlsConfig)
+func (cli *DockerCli) HTTPClient() *http.Client {
+	tr := &http.Transport{
+		TLSClientConfig: cli.tlsConfig,
+		Dial: func(network, addr string) (net.Conn, error) {
+			return net.Dial(cli.proto, cli.addr)
+		},
 	}
-	return net.Dial(cli.proto, cli.addr)
+	return &http.Client{Transport: tr}
 }
 
 func (cli *DockerCli) call(method, path string, data interface{}, passAuthInfo bool) (io.ReadCloser, int, error) {
@@ -57,9 +56,6 @@ func (cli *DockerCli) call(method, path string, data interface{}, passAuthInfo b
 			}
 		}
 	}
-	// fixme: refactor client to support redirect
-	re := regexp.MustCompile("/+")
-	path = re.ReplaceAllString(path, "/")
 
 	req, err := http.NewRequest(method, fmt.Sprintf("/v%s%s", api.APIVERSION, path), params)
 	if err != nil {
@@ -86,28 +82,20 @@ func (cli *DockerCli) call(method, path string, data interface{}, passAuthInfo b
 		}
 	}
 	req.Header.Set("User-Agent", "Docker-Client/"+dockerversion.VERSION)
-	req.Host = cli.addr
+	req.URL.Host = cli.addr
+	req.URL.Scheme = cli.scheme
 	if data != nil {
 		req.Header.Set("Content-Type", "application/json")
 	} else if method == "POST" {
 		req.Header.Set("Content-Type", "plain/text")
 	}
-	dial, err := cli.dial()
+	resp, err := cli.HTTPClient().Do(req)
 	if err != nil {
 		if strings.Contains(err.Error(), "connection refused") {
 			return nil, -1, ErrConnectionRefused
 		}
 		return nil, -1, err
 	}
-	clientconn := httputil.NewClientConn(dial, nil)
-	resp, err := clientconn.Do(req)
-	if err != nil {
-		clientconn.Close()
-		if strings.Contains(err.Error(), "connection refused") {
-			return nil, -1, ErrConnectionRefused
-		}
-		return nil, -1, err
-	}
 
 	if resp.StatusCode < 200 || resp.StatusCode >= 400 {
 		body, err := ioutil.ReadAll(resp.Body)
@@ -119,31 +107,25 @@ func (cli *DockerCli) call(method, path string, data interface{}, passAuthInfo b
 		}
 		return nil, resp.StatusCode, fmt.Errorf("Error: %s", bytes.TrimSpace(body))
 	}
-
-	wrapper := utils.NewReadCloserWrapper(resp.Body, func() error {
-		if resp != nil && resp.Body != nil {
-			resp.Body.Close()
-		}
-		return clientconn.Close()
-	})
-	return wrapper, resp.StatusCode, nil
+	return resp.Body, resp.StatusCode, nil
 }
 
 func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer, headers map[string][]string) error {
+	return cli.streamHelper(method, path, true, in, out, nil, headers)
+}
+
+func (cli *DockerCli) streamHelper(method, path string, setRawTerminal bool, in io.Reader, stdout, stderr io.Writer, headers map[string][]string) error {
 	if (method == "POST" || method == "PUT") && in == nil {
 		in = bytes.NewReader([]byte{})
 	}
 
-	// fixme: refactor client to support redirect
-	re := regexp.MustCompile("/+")
-	path = re.ReplaceAllString(path, "/")
-
-	req, err := http.NewRequest(method, fmt.Sprintf("/v%s%s", api.APIVERSION, path), in)
+	req, err := http.NewRequest(method, fmt.Sprintf("http://v%s%s", api.APIVERSION, path), in)
 	if err != nil {
 		return err
 	}
 	req.Header.Set("User-Agent", "Docker-Client/"+dockerversion.VERSION)
-	req.Host = cli.addr
+	req.URL.Host = cli.addr
+	req.URL.Scheme = cli.scheme
 	if method == "POST" {
 		req.Header.Set("Content-Type", "plain/text")
 	}
@@ -153,17 +135,7 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer, h
 			req.Header[k] = v
 		}
 	}
-
-	dial, err := cli.dial()
-	if err != nil {
-		if strings.Contains(err.Error(), "connection refused") {
-			return fmt.Errorf("Cannot connect to the Docker daemon. Is 'docker -d' running on this host?")
-		}
-		return err
-	}
-	clientconn := httputil.NewClientConn(dial, nil)
-	resp, err := clientconn.Do(req)
-	defer clientconn.Close()
+	resp, err := cli.HTTPClient().Do(req)
 	if err != nil {
 		if strings.Contains(err.Error(), "connection refused") {
 			return fmt.Errorf("Cannot connect to the Docker daemon. Is 'docker -d' running on this host?")
@@ -184,124 +156,19 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer, h
 	}
 
 	if api.MatchesContentType(resp.Header.Get("Content-Type"), "application/json") {
-		return utils.DisplayJSONMessagesStream(resp.Body, out, cli.terminalFd, cli.isTerminal)
+		return utils.DisplayJSONMessagesStream(resp.Body, stdout, cli.terminalFd, cli.isTerminal)
 	}
-	if _, err := io.Copy(out, resp.Body); err != nil {
-		return err
-	}
-	return nil
-}
-
-func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.ReadCloser, stdout, stderr io.Writer, started chan io.Closer) error {
-	defer func() {
-		if started != nil {
-			close(started)
-		}
-	}()
-	// fixme: refactor client to support redirect
-	re := regexp.MustCompile("/+")
-	path = re.ReplaceAllString(path, "/")
-
-	req, err := http.NewRequest(method, fmt.Sprintf("/v%s%s", api.APIVERSION, path), nil)
-	if err != nil {
-		return err
-	}
-	req.Header.Set("User-Agent", "Docker-Client/"+dockerversion.VERSION)
-	req.Header.Set("Content-Type", "plain/text")
-	req.Host = cli.addr
-
-	dial, err := cli.dial()
-	if err != nil {
-		if strings.Contains(err.Error(), "connection refused") {
-			return fmt.Errorf("Cannot connect to the Docker daemon. Is 'docker -d' running on this host?")
-		}
-		return err
-	}
-	clientconn := httputil.NewClientConn(dial, nil)
-	defer clientconn.Close()
-
-	// Server hijacks the connection, error 'connection closed' expected
-	clientconn.Do(req)
-
-	rwc, br := clientconn.Hijack()
-	defer rwc.Close()
-
-	if started != nil {
-		started <- rwc
-	}
-
-	var receiveStdout chan error
-
-	var oldState *term.State
-
-	if in != nil && setRawTerminal && cli.isTerminal && os.Getenv("NORAW") == "" {
-		oldState, err = term.SetRawTerminal(cli.terminalFd)
-		if err != nil {
-			return err
-		}
-		defer term.RestoreTerminal(cli.terminalFd, oldState)
-	}
-
-	if stdout != nil || stderr != nil {
-		receiveStdout = utils.Go(func() (err error) {
-			defer func() {
-				if in != nil {
-					if setRawTerminal && cli.isTerminal {
-						term.RestoreTerminal(cli.terminalFd, oldState)
-					}
-					// For some reason this Close call blocks on darwin..
-					// As the client exists right after, simply discard the close
-					// until we find a better solution.
-					if goruntime.GOOS != "darwin" {
-						in.Close()
-					}
-				}
-			}()
-
-			// When TTY is ON, use regular copy
-			if setRawTerminal {
-				_, err = io.Copy(stdout, br)
-			} else {
-				_, err = utils.StdCopy(stdout, stderr, br)
-			}
-			utils.Debugf("[hijack] End of stdout")
-			return err
-		})
-	}
-
-	sendStdin := utils.Go(func() error {
-		if in != nil {
-			io.Copy(rwc, in)
-			utils.Debugf("[hijack] End of stdin")
-		}
-		if tcpc, ok := rwc.(*net.TCPConn); ok {
-			if err := tcpc.CloseWrite(); err != nil {
-				utils.Debugf("Couldn't send EOF: %s\n", err)
-			}
-		} else if unixc, ok := rwc.(*net.UnixConn); ok {
-			if err := unixc.CloseWrite(); err != nil {
-				utils.Debugf("Couldn't send EOF: %s\n", err)
-			}
-		}
-		// Discard errors due to pipe interruption
-		return nil
-	})
-
 	if stdout != nil || stderr != nil {
-		if err := <-receiveStdout; err != nil {
-			utils.Debugf("Error receiveStdout: %s", err)
-			return err
-		}
-	}
-
-	if !cli.isTerminal {
-		if err := <-sendStdin; err != nil {
-			utils.Debugf("Error sendStdin: %s", err)
-			return err
+		// When TTY is ON, use regular copy
+		if setRawTerminal {
+			_, err = io.Copy(stdout, resp.Body)
+		} else {
+			_, err = utils.StdCopy(stdout, stderr, resp.Body)
 		}
+		utils.Debugf("[stream] End of stdout")
+		return err
 	}
 	return nil
-
 }
 
 func (cli *DockerCli) resizeTty(id string) {

+ 1 - 1
api/common.go

@@ -10,7 +10,7 @@ import (
 )
 
 const (
-	APIVERSION        version.Version = "1.10"
+	APIVERSION        version.Version = "1.11"
 	DEFAULTHTTPHOST                   = "127.0.0.1"
 	DEFAULTUNIXSOCKET                 = "/var/run/docker.sock"
 )

+ 65 - 5
api/server/server.go

@@ -3,7 +3,6 @@ package server
 import (
 	"bufio"
 	"bytes"
-	"code.google.com/p/go.net/websocket"
 	"crypto/tls"
 	"crypto/x509"
 	"encoding/base64"
@@ -21,6 +20,8 @@ import (
 	"strings"
 	"syscall"
 
+	"code.google.com/p/go.net/websocket"
+
 	"github.com/dotcloud/docker/api"
 	"github.com/dotcloud/docker/engine"
 	"github.com/dotcloud/docker/pkg/listenbuffer"
@@ -246,6 +247,7 @@ func getEvents(eng *engine.Engine, version version.Version, w http.ResponseWrite
 	var job = eng.Job("events", r.RemoteAddr)
 	streamJSON(job, w, true)
 	job.Setenv("since", r.Form.Get("since"))
+	job.Setenv("until", r.Form.Get("until"))
 	return job.Run()
 }
 
@@ -327,6 +329,48 @@ func getContainersJSON(eng *engine.Engine, version version.Version, w http.Respo
 	return nil
 }
 
+func getContainersLogs(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := parseForm(r); err != nil {
+		return err
+	}
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+
+	var (
+		job    = eng.Job("inspect", vars["name"], "container")
+		c, err = job.Stdout.AddEnv()
+	)
+	if err != nil {
+		return err
+	}
+	if err = job.Run(); err != nil {
+		return err
+	}
+
+	var outStream, errStream io.Writer
+	outStream = utils.NewWriteFlusher(w)
+
+	if c.GetSubEnv("Config") != nil && !c.GetSubEnv("Config").GetBool("Tty") && version.GreaterThanOrEqualTo("1.6") {
+		errStream = utils.NewStdWriter(outStream, utils.Stderr)
+		outStream = utils.NewStdWriter(outStream, utils.Stdout)
+	} else {
+		errStream = outStream
+	}
+
+	job = eng.Job("logs", vars["name"])
+	job.Setenv("follow", r.Form.Get("follow"))
+	job.Setenv("stdout", r.Form.Get("stdout"))
+	job.Setenv("stderr", r.Form.Get("stderr"))
+	job.Setenv("timestamps", r.Form.Get("timestamps"))
+	job.Stdout.Add(outStream)
+	job.Stderr.Set(errStream)
+	if err := job.Run(); err != nil {
+		fmt.Fprintf(outStream, "Error: %s\n", err)
+	}
+	return nil
+}
+
 func postImagesTag(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := parseForm(r); err != nil {
 		return err
@@ -828,8 +872,6 @@ func postBuild(eng *engine.Engine, version version.Version, w http.ResponseWrite
 		return fmt.Errorf("Multipart upload for build is no longer supported. Please upgrade your docker client.")
 	}
 	var (
-		authEncoded       = r.Header.Get("X-Registry-Auth")
-		authConfig        = &registry.AuthConfig{}
 		configFileEncoded = r.Header.Get("X-Registry-Config")
 		configFile        = &registry.ConfigFile{}
 		job               = eng.Job("build")
@@ -839,12 +881,18 @@ func postBuild(eng *engine.Engine, version version.Version, w http.ResponseWrite
 	// Both headers will be parsed and sent along to the daemon, but if a non-empty
 	// ConfigFile is present, any value provided as an AuthConfig directly will
 	// be overridden. See BuildFile::CmdFrom for details.
+	var (
+		authEncoded = r.Header.Get("X-Registry-Auth")
+		authConfig  = &registry.AuthConfig{}
+	)
 	if version.LessThan("1.9") && authEncoded != "" {
 		authJson := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
 		if err := json.NewDecoder(authJson).Decode(authConfig); err != nil {
 			// for a pull it is not an error if no auth was given
 			// to increase compatibility with the existing api it is defaulting to be empty
 			authConfig = &registry.AuthConfig{}
+		} else {
+			configFile.Configs[authConfig.ServerAddress] = *authConfig
 		}
 	}
 
@@ -869,8 +917,7 @@ func postBuild(eng *engine.Engine, version version.Version, w http.ResponseWrite
 	job.Setenv("q", r.FormValue("q"))
 	job.Setenv("nocache", r.FormValue("nocache"))
 	job.Setenv("rm", r.FormValue("rm"))
-	job.SetenvJson("authConfig", authConfig)
-	job.SetenvJson("configFile", configFile)
+	job.SetenvJson("auth", configFile)
 
 	if err := job.Run(); err != nil {
 		if !job.Stdout.Used() {
@@ -930,6 +977,11 @@ func writeCorsHeaders(w http.ResponseWriter, r *http.Request) {
 	w.Header().Add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS")
 }
 
+func ping(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	_, err := w.Write([]byte{'O', 'K'})
+	return err
+}
+
 func makeHttpHandler(eng *engine.Engine, logging bool, localMethod string, localRoute string, handlerFunc HttpApiFunc, enableCors bool, dockerVersion version.Version) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		// log the request
@@ -998,6 +1050,7 @@ func createRouter(eng *engine.Engine, logging, enableCors bool, dockerVersion st
 	}
 	m := map[string]map[string]HttpApiFunc{
 		"GET": {
+			"/_ping":                          ping,
 			"/events":                         getEvents,
 			"/info":                           getInfo,
 			"/version":                        getVersion,
@@ -1013,6 +1066,7 @@ func createRouter(eng *engine.Engine, logging, enableCors bool, dockerVersion st
 			"/containers/{name:.*}/changes":   getContainersChanges,
 			"/containers/{name:.*}/json":      getContainersByName,
 			"/containers/{name:.*}/top":       getContainersTop,
+			"/containers/{name:.*}/logs":      getContainersLogs,
 			"/containers/{name:.*}/attach/ws": wsContainersAttach,
 		},
 		"POST": {
@@ -1220,6 +1274,9 @@ func ListenAndServe(proto, addr string, job *engine.Job) error {
 // ServeApi loops through all of the protocols sent in to docker and spawns
 // off a go routine to setup a serving http.Server for each.
 func ServeApi(job *engine.Job) engine.Status {
+	if len(job.Args) == 0 {
+		return job.Errorf("usage: %s PROTO://ADDR [PROTO://ADDR ...]", job.Name)
+	}
 	var (
 		protoAddrs = job.Args
 		chErrors   = make(chan error, len(protoAddrs))
@@ -1232,6 +1289,9 @@ func ServeApi(job *engine.Job) engine.Status {
 
 	for _, protoAddr := range protoAddrs {
 		protoAddrParts := strings.SplitN(protoAddr, "://", 2)
+		if len(protoAddrParts) != 2 {
+			return job.Errorf("usage: %s PROTO://ADDR [PROTO://ADDR ...]", job.Name)
+		}
 		go func() {
 			log.Printf("Listening for HTTP on %s (%s)\n", protoAddrParts[0], protoAddrParts[1])
 			chErrors <- ListenAndServe(protoAddrParts[0], protoAddrParts[1], job)

+ 40 - 72
api/server/server_unit_test.go

@@ -1,14 +1,14 @@
 package server
 
 import (
+	"bytes"
+	"encoding/json"
 	"fmt"
 	"github.com/dotcloud/docker/api"
 	"github.com/dotcloud/docker/engine"
-	"github.com/dotcloud/docker/utils"
 	"io"
 	"net/http"
 	"net/http/httptest"
-	"os"
 	"testing"
 )
 
@@ -57,15 +57,7 @@ func TesthttpError(t *testing.T) {
 }
 
 func TestGetVersion(t *testing.T) {
-	tmp, err := utils.TestDirectory("")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(tmp)
-	eng, err := engine.New(tmp)
-	if err != nil {
-		t.Fatal(err)
-	}
+	eng := engine.New()
 	var called bool
 	eng.Register("version", func(job *engine.Job) engine.Status {
 		called = true
@@ -80,49 +72,21 @@ func TestGetVersion(t *testing.T) {
 		}
 		return engine.StatusOK
 	})
-
-	r := httptest.NewRecorder()
-	req, err := http.NewRequest("GET", "/version", nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	// FIXME getting the version should require an actual running Server
-	if err := ServeRequest(eng, api.APIVERSION, r, req); err != nil {
-		t.Fatal(err)
-	}
+	r := serveRequest("GET", "/version", nil, eng, t)
 	if !called {
 		t.Fatalf("handler was not called")
 	}
-	out := engine.NewOutput()
-	v, err := out.AddEnv()
-	if err != nil {
-		t.Fatal(err)
-	}
-	if _, err := io.Copy(out, r.Body); err != nil {
-		t.Fatal(err)
-	}
-	out.Close()
-	expected := "42.1"
-	if result := v.Get("Version"); result != expected {
-		t.Errorf("Expected version %s, %s found", expected, result)
+	v := readEnv(r.Body, t)
+	if v.Get("Version") != "42.1" {
+		t.Fatalf("%#v\n", v)
 	}
-	expected = "application/json"
-	if result := r.HeaderMap.Get("Content-Type"); result != expected {
-		t.Errorf("Expected Content-Type %s, %s found", expected, result)
+	if r.HeaderMap.Get("Content-Type") != "application/json" {
+		t.Fatalf("%#v\n", r)
 	}
 }
 
 func TestGetInfo(t *testing.T) {
-	tmp, err := utils.TestDirectory("")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(tmp)
-	eng, err := engine.New(tmp)
-	if err != nil {
-		t.Fatal(err)
-	}
-
+	eng := engine.New()
 	var called bool
 	eng.Register("info", func(job *engine.Job) engine.Status {
 		called = true
@@ -134,47 +98,51 @@ func TestGetInfo(t *testing.T) {
 		}
 		return engine.StatusOK
 	})
+	r := serveRequest("GET", "/info", nil, eng, t)
+	if !called {
+		t.Fatalf("handler was not called")
+	}
+	v := readEnv(r.Body, t)
+	if v.GetInt("Images") != 42000 {
+		t.Fatalf("%#v\n", v)
+	}
+	if v.GetInt("Containers") != 1 {
+		t.Fatalf("%#v\n", v)
+	}
+	if r.HeaderMap.Get("Content-Type") != "application/json" {
+		t.Fatalf("%#v\n", r)
+	}
+}
 
+func serveRequest(method, target string, body io.Reader, eng *engine.Engine, t *testing.T) *httptest.ResponseRecorder {
 	r := httptest.NewRecorder()
-	req, err := http.NewRequest("GET", "/info", nil)
+	req, err := http.NewRequest(method, target, body)
 	if err != nil {
 		t.Fatal(err)
 	}
-	// FIXME getting the version should require an actual running Server
 	if err := ServeRequest(eng, api.APIVERSION, r, req); err != nil {
 		t.Fatal(err)
 	}
-	if !called {
-		t.Fatalf("handler was not called")
-	}
+	return r
+}
 
+func readEnv(src io.Reader, t *testing.T) *engine.Env {
 	out := engine.NewOutput()
-	i, err := out.AddEnv()
+	v, err := out.AddEnv()
 	if err != nil {
 		t.Fatal(err)
 	}
-	if _, err := io.Copy(out, r.Body); err != nil {
+	if _, err := io.Copy(out, src); err != nil {
 		t.Fatal(err)
 	}
 	out.Close()
-	{
-		expected := 42000
-		result := i.GetInt("Images")
-		if expected != result {
-			t.Fatalf("%#v\n", result)
-		}
-	}
-	{
-		expected := 1
-		result := i.GetInt("Containers")
-		if expected != result {
-			t.Fatalf("%#v\n", result)
-		}
-	}
-	{
-		expected := "application/json"
-		if result := r.HeaderMap.Get("Content-Type"); result != expected {
-			t.Fatalf("%#v\n", result)
-		}
+	return v
+}
+
+func toJson(data interface{}, t *testing.T) io.Reader {
+	var buf bytes.Buffer
+	if err := json.NewEncoder(&buf).Encode(data); err != nil {
+		t.Fatal(err)
 	}
+	return &buf
 }

+ 1 - 1
archive/diff.go

@@ -68,7 +68,7 @@ func ApplyLayer(dest string, layer ArchiveReader) error {
 			parent := filepath.Dir(hdr.Name)
 			parentPath := filepath.Join(dest, parent)
 			if _, err := os.Lstat(parentPath); err != nil && os.IsNotExist(err) {
-				err = os.MkdirAll(parentPath, 600)
+				err = os.MkdirAll(parentPath, 0600)
 				if err != nil {
 					return err
 				}

+ 17 - 9
builtins/builtins.go

@@ -2,19 +2,25 @@ package builtins
 
 import (
 	api "github.com/dotcloud/docker/api/server"
+	"github.com/dotcloud/docker/daemon/networkdriver/bridge"
 	"github.com/dotcloud/docker/engine"
-	"github.com/dotcloud/docker/runtime/networkdriver/bridge"
+	"github.com/dotcloud/docker/registry"
 	"github.com/dotcloud/docker/server"
 )
 
-func Register(eng *engine.Engine) {
-	daemon(eng)
-	remote(eng)
+func Register(eng *engine.Engine) error {
+	if err := daemon(eng); err != nil {
+		return err
+	}
+	if err := remote(eng); err != nil {
+		return err
+	}
+	return registry.NewService().Install(eng)
 }
 
 // remote: a RESTful api for cross-docker communication
-func remote(eng *engine.Engine) {
-	eng.Register("serveapi", api.ServeApi)
+func remote(eng *engine.Engine) error {
+	return eng.Register("serveapi", api.ServeApi)
 }
 
 // daemon: a default execution and storage backend for Docker on Linux,
@@ -32,7 +38,9 @@ func remote(eng *engine.Engine) {
 //
 // These components should be broken off into plugins of their own.
 //
-func daemon(eng *engine.Engine) {
-	eng.Register("initserver", server.InitServer)
-	eng.Register("init_networkdriver", bridge.InitDriver)
+func daemon(eng *engine.Engine) error {
+	if err := eng.Register("initserver", server.InitServer); err != nil {
+		return err
+	}
+	return eng.Register("init_networkdriver", bridge.InitDriver)
 }

+ 18 - 11
contrib/check-config.sh

@@ -4,7 +4,13 @@ set -e
 # bits of this were adapted from lxc-checkconfig
 # see also https://github.com/lxc/lxc/blob/lxc-1.0.2/src/lxc/lxc-checkconfig.in
 
-: ${CONFIG:=/proc/config.gz}
+possibleConfigs=(
+	'/proc/config.gz'
+	"/boot/config-$(uname -r)"
+	"/usr/src/linux-$(uname -r)/.config"
+	'/usr/src/linux/.config'
+)
+: ${CONFIG:="${possibleConfigs[0]}"}
 
 if ! command -v zgrep &> /dev/null; then
 	zgrep() {
@@ -74,11 +80,7 @@ check_flags() {
 
 if [ ! -e "$CONFIG" ]; then
 	wrap_warning "warning: $CONFIG does not exist, searching other paths for kernel config..."
-	for tryConfig in \
-		'/proc/config.gz' \
-		"/boot/config-$(uname -r)" \
-		'/usr/src/linux/.config' \
-	; do
+	for tryConfig in "${possibleConfigs[@]}"; do
 		if [ -e "$tryConfig" ]; then
 			CONFIG="$tryConfig"
 			break
@@ -98,12 +100,16 @@ echo
 echo 'Generally Necessary:'
 
 echo -n '- '
-cgroupCpuDir="$(awk '/[, ]cpu([, ]|$)/ && $8 == "cgroup" { print $5 }' /proc/$$/mountinfo | head -n1)"
-cgroupDir="$(dirname "$cgroupCpuDir")"
-if [ -d "$cgroupDir/cpu" ]; then
+cgroupSubsystemDir="$(awk '/[, ](cpu|cpuacct|cpuset|devices|freezer|memory)([, ]|$)/ && $8 == "cgroup" { print $5 }' /proc/$$/mountinfo | head -n1)"
+cgroupDir="$(dirname "$cgroupSubsystemDir")"
+if [ -d "$cgroupDir/cpu" -o -d "$cgroupDir/cpuacct" -o -d "$cgroupDir/cpuset" -o -d "$cgroupDir/devices" -o -d "$cgroupDir/freezer" -o -d "$cgroupDir/memory" ]; then
 	echo "$(wrap_good 'cgroup hierarchy' 'properly mounted') [$cgroupDir]"
 else
-	echo "$(wrap_bad 'cgroup hierarchy' 'single mountpoint!') [$cgroupCpuDir]"
+	if [ "$cgroupSubsystemDir" ]; then
+		echo "$(wrap_bad 'cgroup hierarchy' 'single mountpoint!') [$cgroupSubsystemDir]"
+	else
+		echo "$(wrap_bad 'cgroup hierarchy' 'nonexistent??')"
+	fi
 	echo "    $(wrap_color '(see https://github.com/tianon/cgroupfs-mount)' yellow)"
 fi
 
@@ -112,7 +118,8 @@ flags=(
 	DEVPTS_MULTIPLE_INSTANCES
 	CGROUPS CGROUP_DEVICE
 	MACVLAN VETH BRIDGE
-	IP_NF_TARGET_MASQUERADE NETFILTER_XT_MATCH_{ADDRTYPE,CONNTRACK}
+	NF_NAT_IPV4 IP_NF_TARGET_MASQUERADE
+	NETFILTER_XT_MATCH_{ADDRTYPE,CONNTRACK}
 	NF_NAT NF_NAT_NEEDED
 )
 check_flags "${flags[@]}"

+ 1 - 1
contrib/docker-device-tool/device_tool.go

@@ -3,7 +3,7 @@ package main
 import (
 	"flag"
 	"fmt"
-	"github.com/dotcloud/docker/runtime/graphdriver/devmapper"
+	"github.com/dotcloud/docker/daemon/graphdriver/devmapper"
 	"os"
 	"path"
 	"sort"

+ 2 - 0
contrib/man/.gitignore

@@ -0,0 +1,2 @@
+# these are generated by the md/md2man-all.sh script
+man*

+ 5 - 0
contrib/man/md/Dockerfile

@@ -0,0 +1,5 @@
+FROM fedora:20
+MAINTAINER ipbabble <emailwhenry@redhat.com>
+# Update and install pandoc
+RUN yum -y update; yum clean all;
+RUN yum -y install pandoc;

+ 71 - 0
contrib/man/md/README.md

@@ -0,0 +1,71 @@
+Docker Documentation
+====================
+
+This directory contains the Docker user manual in the Markdown format.
+Do *not* edit the man pages in the man1 directory. Instead, amend the
+Markdown (*.md) files.
+
+# File List
+
+    docker.md
+    docker-attach.md
+    docker-build.md
+    docker-commit.md
+    docker-cp.md
+    docker-diff.md
+    docker-events.md
+    docker-export.md
+    docker-history.md
+    docker-images.md
+    docker-import.md
+    docker-info.md
+    docker-inspect.md
+    docker-kill.md
+    docker-load.md
+    docker-login.md
+    docker-logs.md
+    docker-port.md
+    docker-ps.md
+    docker-pull.md
+    docker-push.md
+    docker-restart.md
+    docker-rmi.md
+    docker-rm.md
+    docker-run.md
+    docker-save.md
+    docker-search.md
+    docker-start.md
+    docker-stop.md
+    docker-tag.md
+    docker-top.md
+    docker-wait.md
+    Dockerfile
+    md2man-all.sh
+
+# Generating man pages from the Markdown files
+
+The recommended approach for generating the man pages is via a  Docker 
+container. Using the supplied Dockerfile, Docker will create a Fedora based 
+container and isolate the Pandoc installation. This is a seamless process, 
+saving you from dealing with Pandoc and dependencies on your own computer.
+
+## Building the Fedora / Pandoc image
+
+There is a Dockerfile provided in the `docker/contrib/man/md` directory.
+
+Using this Dockerfile, create a Docker image tagged `fedora/pandoc`:
+
+    docker build  -t fedora/pandoc .
+
+## Utilizing the Fedora / Pandoc image
+
+Once the image is built, run a container using the image with *volumes*:
+
+    docker run -v /<path-to-git-dir>/docker/contrib/man:/pandoc:rw \
+    -w /pandoc -i fedora/pandoc /pandoc/md/md2man-all.sh
+
+The Pandoc Docker container will process the Markdown files and generate
+the man pages inside the `docker/contrib/man/man1` directory using
+Docker volumes. For more information on Docker volumes see the man page for
+`docker run` and also look at the article [Sharing Directories via Volumes]
+(http://docs.docker.io/use/working_with_volumes/).

+ 57 - 0
contrib/man/md/docker-attach.1.md

@@ -0,0 +1,57 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-attach - Attach to a running container
+
+# SYNOPSIS
+**docker attach** **--no-stdin**[=*false*] **--sig-proxy**[=*true*] CONTAINER
+
+# DESCRIPTION
+If you **docker run** a container in detached mode (**-d**), you can reattach to
+ the detached container with **docker attach** using the container's ID or name.
+
+You can detach from the container again (and leave it running) with `CTRL-c` (for
+a quiet exit) or `CTRL-\` to get a stacktrace of the Docker client when it quits.
+When you detach from a container the exit code will be returned to
+the client.
+
+# OPTIONS
+**--no-stdin**=*true*|*false*
+When set to true, do not attach to stdin. The default is *false*.
+
+**--sig-proxy**=*true*|*false*:
+When set to true, proxify all received signal to the process (even in non-tty
+mode). The default is *true*.
+
+# EXAMPLES
+
+## Attaching to a container
+
+In this example the top command is run inside a container, from an image called
+fedora, in detached mode. The ID from the container is passed into the **docker
+attach** command:
+
+    # ID=$(sudo docker run -d fedora /usr/bin/top -b)
+    # sudo docker attach $ID
+    top - 02:05:52 up  3:05,  0 users,  load average: 0.01, 0.02, 0.05
+    Tasks:   1 total,   1 running,   0 sleeping,   0 stopped,   0 zombie
+    Cpu(s):  0.1%us,  0.2%sy,  0.0%ni, 99.7%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
+    Mem:    373572k total,   355560k used,    18012k free,    27872k buffers
+    Swap:   786428k total,        0k used,   786428k free,   221740k cached
+
+    PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
+    1 root      20   0 17200 1116  912 R    0  0.3   0:00.03 top
+
+    top - 02:05:55 up  3:05,  0 users,  load average: 0.01, 0.02, 0.05
+    Tasks:   1 total,   1 running,   0 sleeping,   0 stopped,   0 zombie
+    Cpu(s):  0.0%us,  0.2%sy,  0.0%ni, 99.8%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
+    Mem:    373572k total,   355244k used,    18328k free,    27872k buffers
+    Swap:   786428k total,        0k used,   786428k free,   221776k cached
+
+    PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
+    1 root      20   0 17208 1144  932 R    0  0.3   0:00.03 top
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.

+ 82 - 0
contrib/man/md/docker-build.1.md

@@ -0,0 +1,82 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-build - Build a container image from a Dockerfile source at PATH
+
+# SYNOPSIS
+**docker build** [**--no-cache**[=*false*]] [**-q**|**--quiet**[=*false*]]
+ [**--rm**] [**-t**|**--tag**=TAG] PATH | URL | -
+
+# DESCRIPTION
+This will read the Dockerfile from the directory specified in **PATH**.
+It also sends any other files and directories found in the current
+directory to the Docker daemon. The contents of this directory would
+be used by **ADD** commands found within the Dockerfile.
+
+Warning, this will send a lot of data to the Docker daemon depending
+on the contents of the current directory. The build is run by the Docker 
+daemon, not by the CLI, so the whole context must be transferred to the daemon. 
+The Docker CLI reports "Uploading context" when the context is sent to 
+the daemon.
+
+When a single Dockerfile is given as the URL, then no context is set.
+When a Git repository is set as the **URL**, the repository is used
+as context.
+
+# OPTIONS
+
+**-q**, **--quiet**=*true*|*false*
+   When set to true, suppress verbose build output. Default is *false*.
+
+**--rm**=*true*|*false*
+   When true, remove intermediate containers that are created during the
+build process. The default is true.
+
+**-t**, **--tag**=*tag*
+   Tag to be applied to the resulting image on successful completion of
+the build.
+
+**--no-cache**=*true*|*false*
+   When set to true, do not use a cache when building the image. The
+default is *false*.
+
+# EXAMPLES
+
+## Building an image using a Dockefile located inside the current directory
+
+Docker images can be built using the build command and a Dockerfile:
+
+    docker build .
+
+During the build process Docker creates intermediate images. In order to
+keep them, you must explicitly set `--rm=false`.
+
+    docker build --rm=false .
+
+A good practice is to make a sub-directory with a related name and create
+the Dockerfile in that directory. For example, a directory called mongo may
+contain a Dockerfile to create a Docker MongoDB image. Likewise, another
+directory called httpd may be used to store Dockerfiles for Apache web
+server images.
+
+It is also a good practice to add the files required for the image to the
+sub-directory. These files will then be specified with the `ADD` instruction
+in the Dockerfile. Note: If you include a tar file (a good practice!), then
+Docker will automatically extract the contents of the tar file
+specified within the `ADD` instruction into the specified target.
+
+## Building an image using a URL
+
+This will clone the specified Github repository from the URL and use it
+as context. The Dockerfile at the root of the repository is used as
+Dockerfile. This only works if the Github repository is a dedicated
+repository.
+
+    docker build github.com/scollier/Fedora-Dockerfiles/tree/master/apache
+
+Note: You can set an arbitrary Git repository via the `git://` schema.
+
+# HISTORY
+March 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.

+ 34 - 0
contrib/man/md/docker-commit.1.md

@@ -0,0 +1,34 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-commit - Create a new image from the changes to an existing
+container
+
+# SYNOPSIS
+**docker commit** **-a**|**--author**[=""] **-m**|**--message**[=""]
+CONTAINER [REPOSITORY[:TAG]]
+
+# DESCRIPTION
+Using an existing container's name or ID you can create a new image.
+
+# OPTIONS
+**-a, --author**=""
+   Author name. (eg. "John Hannibal Smith <hannibal@a-team.com>"
+
+**-m, --message**=""
+   Commit message
+
+# EXAMPLES
+
+## Creating a new image from an existing container
+An existing Fedora based container has had Apache installed while running
+in interactive mode with the bash shell. Apache is also running. To
+create a new image run docker ps to find the container's ID and then run:
+
+    # docker commit -me= "Added Apache to Fedora base image" \
+      --a="A D Ministrator" 98bd7fc99854 fedora/fedora_httpd:20
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and in

+ 24 - 0
contrib/man/md/docker-cp.1.md

@@ -0,0 +1,24 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-cp - Copy files/folders from the PATH to the HOSTPATH
+
+# SYNOPSIS
+**docker cp** CONTAINER:PATH HOSTPATH
+
+# DESCRIPTION
+Copy files/folders from the containers filesystem to the host
+path. Paths are relative to the root of the filesystem. Files
+can be copied from a running or stopped container.
+
+# EXAMPLE
+An important shell script file, created in a bash shell, is copied from
+the exited container to the current dir on the host:
+
+    # docker cp c071f3c3ee81:setup.sh .
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.
+

+ 44 - 0
contrib/man/md/docker-diff.1.md

@@ -0,0 +1,44 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-diff - Inspect changes on a container's filesystem
+
+# SYNOPSIS
+**docker diff** CONTAINER
+
+# DESCRIPTION
+Inspect changes on a container's filesystem. You can use the full or
+shortened container ID or the container name set using
+**docker run --name** option.
+
+# EXAMPLE
+Inspect the changes to on a nginx container:
+
+    # docker diff 1fdfd1f54c1b
+    C /dev
+    C /dev/console
+    C /dev/core
+    C /dev/stdout
+    C /dev/fd
+    C /dev/ptmx
+    C /dev/stderr
+    C /dev/stdin
+    C /run
+    A /run/nginx.pid
+    C /var/lib/nginx/tmp
+    A /var/lib/nginx/tmp/client_body
+    A /var/lib/nginx/tmp/fastcgi
+    A /var/lib/nginx/tmp/proxy
+    A /var/lib/nginx/tmp/scgi
+    A /var/lib/nginx/tmp/uwsgi
+    C /var/log/nginx
+    A /var/log/nginx/access.log
+    A /var/log/nginx/error.log
+
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.
+
+

+ 46 - 0
contrib/man/md/docker-events.1.md

@@ -0,0 +1,46 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-events - Get real time events from the server
+
+**docker events** **--since**=""|*epoch-time*
+
+# DESCRIPTION
+Get event information from the Docker daemon. Information can include historical
+information and real-time information.
+
+# OPTIONS
+**--since**=""
+Show previously created events and then stream. This can be in either
+seconds since epoch, or date string.
+
+# EXAMPLES
+
+## Listening for Docker events
+
+After running docker events a container 786d698004576 is started and stopped
+(The container name has been shortened in the ouput below):
+
+    # docker events
+    [2014-04-12 18:23:04 -0400 EDT] 786d69800457: (from whenry/testimage:latest) start
+    [2014-04-12 18:23:13 -0400 EDT] 786d69800457: (from whenry/testimage:latest) die
+    [2014-04-12 18:23:13 -0400 EDT] 786d69800457: (from whenry/testimage:latest) stop
+
+## Listening for events since a given date
+Again the output container IDs have been shortened for the purposes of this document:
+
+    # docker events --since '2014-04-12'
+    [2014-04-12 18:11:28 -0400 EDT] c655dbf640dc: (from whenry/testimage:latest) create
+    [2014-04-12 18:11:28 -0400 EDT] c655dbf640dc: (from whenry/testimage:latest) start
+    [2014-04-12 18:14:13 -0400 EDT] 786d69800457: (from whenry/testimage:latest) create
+    [2014-04-12 18:14:13 -0400 EDT] 786d69800457: (from whenry/testimage:latest) start
+    [2014-04-12 18:22:44 -0400 EDT] 786d69800457: (from whenry/testimage:latest) die
+    [2014-04-12 18:22:44 -0400 EDT] 786d69800457: (from whenry/testimage:latest) stop
+    [2014-04-12 18:23:04 -0400 EDT] 786d69800457: (from whenry/testimage:latest) start
+    [2014-04-12 18:23:13 -0400 EDT] 786d69800457: (from whenry/testimage:latest) die
+    [2014-04-12 18:23:13 -0400 EDT] 786d69800457: (from whenry/testimage:latest) stop
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.

+ 26 - 0
contrib/man/md/docker-export.1.md

@@ -0,0 +1,26 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-export - Export the contents of a filesystem as a tar archive to
+STDOUT.
+
+# SYNOPSIS
+**docker export** CONTAINER
+
+# DESCRIPTION
+Export the contents of a container's filesystem using the full or shortened
+container ID or container name. The output is exported to STDOUT and can be
+redirected to a tar file.
+
+# EXAMPLE
+Export the contents of the container called angry_bell to a tar file
+called test.tar:
+
+    # docker export angry_bell > test.tar
+    # ls *.tar
+    test.tar
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.

+ 32 - 0
contrib/man/md/docker-history.1.md

@@ -0,0 +1,32 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-history - Show the history of an image
+
+# SYNOPSIS
+**docker history** **--no-trunc**[=*false*] [**-q**|**--quiet**[=*false*]]
+ IMAGE
+
+# DESCRIPTION
+
+Show the history of when and how an image was created.
+
+# OPTIONS
+
+**--no-trunc**=*true*|*false*
+   When true don't truncate output. Default is false
+
+**-q**, **--quiet=*true*|*false*
+   When true only show numeric IDs. Default is false.
+
+# EXAMPLE
+    $ sudo docker history fedora
+    IMAGE          CREATED          CREATED BY                                      SIZE
+    105182bb5e8b   5 days ago       /bin/sh -c #(nop) ADD file:71356d2ad59aa3119d   372.7 MB
+    73bd853d2ea5   13 days ago      /bin/sh -c #(nop) MAINTAINER Lokesh Mandvekar   0 B
+    511136ea3c5a   10 months ago                                                    0 B
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.

+ 99 - 0
contrib/man/md/docker-images.1.md

@@ -0,0 +1,99 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-images - List the images in the local repository
+
+# SYNOPSIS
+**docker images**
+[**-a**|**--all**=*false*]
+[**--no-trunc**[=*false*]
+[**-q**|**--quiet**[=*false*]
+[**-t**|**--tree**=*false*]
+[**-v**|**--viz**=*false*]
+[NAME]
+
+# DESCRIPTION
+This command lists the images stored in the local Docker repository.
+
+By default, intermediate images, used during builds, are not listed. Some of the
+output, e.g. image ID, is truncated, for space reasons. However the truncated
+image ID, and often the first few characters, are enough to be used in other
+Docker commands that use the image ID. The output includes repository, tag, image
+ID, date created and the virtual size.
+
+The title REPOSITORY for the first title may seem confusing. It is essentially
+the image name. However, because you can tag a specific image, and multiple tags
+(image instances) can be associated with a single name, the name is really a
+repository for all tagged images of the same name. For example consider an image
+called fedora. It may be tagged with 18, 19, or 20, etc. to manage different
+versions.
+
+# OPTIONS
+
+**-a**, **--all**=*true*|*false*
+   When set to true, also include all intermediate images in the list. The
+default is false.
+
+**--no-trunc**=*true*|*false*
+   When set to true, list the full image ID and not the truncated ID. The
+default is false.
+
+**-q**, **--quiet**=*true*|*false*
+   When set to true, list the complete image ID as part of the output. The
+default is false.
+
+**-t**, **--tree**=*true*|*false*
+   When set to true, list the images in a tree dependency tree (hierarchy)
+format. The default is false.
+
+**-v**, **--viz**=*true*|*false*
+   When set to true, list the graph in graphviz format. The default is
+*false*.
+
+# EXAMPLES
+
+## Listing the images
+
+To list the images in a local repository (not the registry) run:
+
+    docker images
+
+The list will contain the image repository name, a tag for the image, and an
+image ID, when it was created and its virtual size. Columns: REPOSITORY, TAG,
+IMAGE ID, CREATED, and VIRTUAL SIZE.
+
+To get a verbose list of images which contains all the intermediate images
+used in builds use **-a**:
+
+    docker images -a
+
+## List images dependency tree hierarchy
+
+To list the images in the local repository (not the registry) in a dependency
+tree format, use the **-t** option.
+
+    docker images -t
+
+This displays a staggered hierarchy tree where the less indented image is
+the oldest with dependent image layers branching inward (to the right) on
+subsequent lines. The newest or top level image layer is listed last in
+any tree branch.
+
+## List images in GraphViz format
+
+To display the list in a format consumable by a GraphViz tools run with
+**-v**. For example to produce a .png graph file of the hierarchy use:
+
+    docker images --viz | dot -Tpng -o docker.png
+
+## Listing only the shortened image IDs
+
+Listing just the shortened image IDs. This can be useful for some automated
+tools.
+
+    docker images -q
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.

+ 39 - 0
contrib/man/md/docker-import.1.md

@@ -0,0 +1,39 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-import - Create an empty filesystem image and import the contents
+of the tarball into it.
+
+# SYNOPSIS
+**docker import** URL|- [REPOSITORY[:TAG]]
+
+# DESCRIPTION
+Create a new filesystem image from the contents of a tarball (.tar,
+.tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then optionally tag it.
+
+# EXAMPLES
+
+## Import from a remote location
+
+    # docker import http://example.com/exampleimage.tgz example/imagerepo
+
+## Import from a local file
+
+Import to docker via pipe and stdin:
+
+    # cat exampleimage.tgz | docker import - example/imagelocal
+
+## Import from a local file and tag
+
+Import to docker via pipe and stdin:
+
+    # cat exampleimageV2.tgz | docker import - example/imagelocal:V-2.0
+
+## Import from a local directory
+
+    # tar -c . | docker import - exampleimagedir
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.

+ 46 - 0
contrib/man/md/docker-info.1.md

@@ -0,0 +1,46 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-info - Display system wide information
+
+# SYNOPSIS
+**docker info**
+
+# DESCRIPTION
+This command displays system wide information regarding the Docker installation.
+Information displayed includes the number of containers and images, pool name,
+data file, metadata file, data space used, total data space, metadata space used
+, total metadata space, execution driver, and the kernel version.
+
+The data file is where the images are stored and the metadata file is where the
+meta data regarding those images are stored. When run for the first time Docker
+allocates a certain amount of data space and meta data space from the space
+available on the volume where `/var/lib/docker` is mounted.
+
+# OPTIONS
+There are no available options.
+
+# EXAMPLES
+
+## Display Docker system information
+
+Here is a sample output:
+
+    # docker info
+    Containers: 18
+    Images: 95
+    Storage Driver: devicemapper
+     Pool Name: docker-8:1-170408448-pool
+     Data file: /var/lib/docker/devicemapper/devicemapper/data
+     Metadata file: /var/lib/docker/devicemapper/devicemapper/metadata
+     Data Space Used: 9946.3 Mb
+     Data Space Total: 102400.0 Mb
+     Metadata Space Used: 9.9 Mb
+     Metadata Space Total: 2048.0 Mb
+    Execution Driver: native-0.1
+    Kernel Version: 3.10.0-116.el7.x86_64
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.

+ 229 - 0
contrib/man/md/docker-inspect.1.md

@@ -0,0 +1,229 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-inspect - Return low-level information on a container/image
+
+# SYNOPSIS
+**docker inspect** [**-f**|**--format**="" CONTAINER|IMAGE
+[CONTAINER|IMAGE...]
+
+# DESCRIPTION
+
+This displays all the information available in Docker for a given
+container or image. By default, this will render all results in a JSON
+array. If a format is specified, the given template will be executed for
+each result.
+
+# OPTIONS
+**-f**, **--format**=""
+   The text/template package of Go describes all the details of the
+format. See examples section
+
+# EXAMPLES
+
+## Getting information on a container
+
+To get information on a container use it's ID or instance name:
+
+    #docker inspect 1eb5fabf5a03
+    [{
+       "ID": "1eb5fabf5a03807136561b3c00adcd2992b535d624d5e18b6cdc6a6844d9767b",
+       "Created": "2014-04-04T21:33:52.02361335Z",
+       "Path": "/usr/sbin/nginx",
+       "Args": [],
+       "Config": {
+            "Hostname": "1eb5fabf5a03",
+            "Domainname": "",
+            "User": "",
+            "Memory": 0,
+            "MemorySwap": 0,
+            "CpuShares": 0,
+            "AttachStdin": false,
+            "AttachStdout": false,
+            "AttachStderr": false,
+            "PortSpecs": null,
+            "ExposedPorts": {
+                "80/tcp": {}
+        },
+	    "Tty": true,
+            "OpenStdin": false,
+            "StdinOnce": false,
+            "Env": [
+               "HOME=/",
+	       "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
+            ],
+            "Cmd": [
+                "/usr/sbin/nginx"
+            ],
+            "Dns": null,
+            "DnsSearch": null,
+            "Image": "summit/nginx",
+            "Volumes": null,
+            "VolumesFrom": "",
+            "WorkingDir": "",
+            "Entrypoint": null,
+            "NetworkDisabled": false,
+            "OnBuild": null,
+            "Context": {
+               "mount_label": "system_u:object_r:svirt_sandbox_file_t:s0:c0,c650",
+	       "process_label": "system_u:system_r:svirt_lxc_net_t:s0:c0,c650"
+	    }
+        },
+        "State": {
+            "Running": true,
+            "Pid": 858,
+            "ExitCode": 0,
+            "StartedAt": "2014-04-04T21:33:54.16259207Z",
+            "FinishedAt": "0001-01-01T00:00:00Z",
+            "Ghost": false
+        },
+        "Image": "df53773a4390e25936f9fd3739e0c0e60a62d024ea7b669282b27e65ae8458e6",
+        "NetworkSettings": {
+            "IPAddress": "172.17.0.2",
+            "IPPrefixLen": 16,
+            "Gateway": "172.17.42.1",
+            "Bridge": "docker0",
+            "PortMapping": null,
+            "Ports": {
+                "80/tcp": [
+                    {
+                        "HostIp": "0.0.0.0",
+                        "HostPort": "80"
+                    }
+                ]
+            }
+        },
+        "ResolvConfPath": "/etc/resolv.conf",
+        "HostnamePath": "/var/lib/docker/containers/1eb5fabf5a03807136561b3c00adcd2992b535d624d5e18b6cdc6a6844d9767b/hostname",
+        "HostsPath": "/var/lib/docker/containers/1eb5fabf5a03807136561b3c00adcd2992b535d624d5e18b6cdc6a6844d9767b/hosts",
+        "Name": "/ecstatic_ptolemy",
+        "Driver": "devicemapper",
+        "ExecDriver": "native-0.1",
+        "Volumes": {},
+        "VolumesRW": {},
+        "HostConfig": {
+        "Binds": null,
+            "ContainerIDFile": "",
+            "LxcConf": [],
+            "Privileged": false,
+            "PortBindings": {
+                "80/tcp": [
+                    {
+                        "HostIp": "0.0.0.0",
+                        "HostPort": "80"
+                    }
+                ]
+            },
+            "Links": null,
+            "PublishAllPorts": false,
+            "DriverOptions": {
+                "lxc": null
+            },
+            "CliAddress": ""
+        }
+
+## Getting the IP address of a container instance
+
+To get the IP address of a container use:
+
+    # docker inspect --format='{{.NetworkSettings.IPAddress}}' 1eb5fabf5a03
+    172.17.0.2
+
+## Listing all port bindings
+
+One can loop over arrays and maps in the results to produce simple text
+output:
+
+    # docker inspect --format='{{range $p, $conf := .NetworkSettings.Ports}} \
+     {{$p}} -> {{(index $conf 0).HostPort}} {{end}}' 1eb5fabf5a03
+
+    80/tcp -> 80
+
+## Getting information on an image
+
+Use an image's ID or name (e.g. repository/name[:tag]) to get information
+ on it.
+
+    # docker inspect 58394af37342
+    [{
+        "id": "58394af373423902a1b97f209a31e3777932d9321ef10e64feaaa7b4df609cf9",
+        "parent": "8abc22bad04266308ff408ca61cb8f6f4244a59308f7efc64e54b08b496c58db",
+        "created": "2014-02-03T16:10:40.500814677Z",
+        "container": "f718f19a28a5147da49313c54620306243734bafa63c76942ef6f8c4b4113bc5",
+        "container_config": {
+            "Hostname": "88807319f25e",
+            "Domainname": "",
+            "User": "",
+            "Memory": 0,
+            "MemorySwap": 0,
+            "CpuShares": 0,
+            "AttachStdin": false,
+            "AttachStdout": false,
+            "AttachStderr": false,
+            "PortSpecs": null,
+            "ExposedPorts": null,
+            "Tty": false,
+            "OpenStdin": false,
+            "StdinOnce": false,
+            "Env": [
+                "HOME=/",
+                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
+            ],
+            "Cmd": [
+                "/bin/sh",
+                "-c",
+		 "#(nop) ADD fedora-20-dummy.tar.xz in /"
+            ],
+            "Dns": null,
+            "DnsSearch": null,
+            "Image": "8abc22bad04266308ff408ca61cb8f6f4244a59308f7efc64e54b08b496c58db",
+            "Volumes": null,
+            "VolumesFrom": "",
+            "WorkingDir": "",
+            "Entrypoint": null,
+            "NetworkDisabled": false,
+            "OnBuild": null,
+            "Context": null
+        },
+        "docker_version": "0.6.3",
+        "author": "I P Babble \u003clsm5@ipbabble.com\u003e - ./buildcontainers.sh",
+        "config": {
+            "Hostname": "88807319f25e",
+            "Domainname": "",
+            "User": "",
+            "Memory": 0,
+            "MemorySwap": 0,
+            "CpuShares": 0,
+            "AttachStdin": false,
+            "AttachStdout": false,
+            "AttachStderr": false,
+            "PortSpecs": null,
+            "ExposedPorts": null,
+            "Tty": false,
+            "OpenStdin": false,
+            "StdinOnce": false,
+            "Env": [
+                "HOME=/",
+		        "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
+            ],
+            "Cmd": null,
+            "Dns": null,
+            "DnsSearch": null,
+            "Image": "8abc22bad04266308ff408ca61cb8f6f4244a59308f7efc64e54b08b496c58db",
+            "Volumes": null,
+            "VolumesFrom": "",
+            "WorkingDir": "",
+            "Entrypoint": null,
+            "NetworkDisabled": false,
+            "OnBuild": null,
+            "Context": null
+        },
+	"architecture": "x86_64",
+	"Size": 385520098
+    }]
+
+# HISTORY
+
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.

+ 21 - 0
contrib/man/md/docker-kill.1.md

@@ -0,0 +1,21 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-kill - Kill a running container (send SIGKILL, or specified signal)
+
+# SYNOPSIS
+**docker kill** **--signal**[=*"KILL"*] CONTAINER [CONTAINER...]
+
+# DESCRIPTION
+
+The main process inside each container specified will be sent SIGKILL,
+ or any signal specified with option --signal.
+
+# OPTIONS
+**-s**, **--signal**=*"KILL"*
+   Signal to send to the container
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+ based on docker.io source material and internal work.

+ 36 - 0
contrib/man/md/docker-load.1.md

@@ -0,0 +1,36 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-load - Load an image from a tar archive on STDIN
+
+# SYNOPSIS
+**docker load**  **--input**=""
+
+# DESCRIPTION
+
+Loads a tarred repository from a file or the standard input stream.
+Restores both images and tags.
+
+# OPTIONS
+
+**-i**, **--input**=""
+   Read from a tar archive file, instead of STDIN
+
+# EXAMPLE
+
+    $ sudo docker images
+    REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
+    busybox             latest              769b9341d937        7 weeks ago         2.489 MB
+    $ sudo docker load --input fedora.tar
+    $ sudo docker images
+    REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
+    busybox             latest              769b9341d937        7 weeks ago         2.489 MB
+    fedora              rawhide             0d20aec6529d        7 weeks ago         387 MB
+    fedora              20                  58394af37342        7 weeks ago         385.5 MB
+    fedora              heisenbug           58394af37342        7 weeks ago         385.5 MB
+    fedora              latest              58394af37342        7 weeks ago         385.5 MB
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.

+ 35 - 0
contrib/man/md/docker-login.1.md

@@ -0,0 +1,35 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-login - Register or Login to a docker registry server.
+
+# SYNOPSIS
+**docker login** [**-e**|**-email**=""] [**-p**|**--password**=""]
+ [**-u**|**--username**=""] [SERVER]
+
+# DESCRIPTION
+Register or Login to a docker registry server, if no server is
+specified "https://index.docker.io/v1/" is the default. If you want to
+login to a private registry you can specify this by adding the server name.
+
+# OPTIONS
+**-e**, **--email**=""
+   Email address
+
+**-p**, **--password**=""
+   Password
+
+**-u**, **--username**=""
+   Username
+
+# EXAMPLE
+
+## Login to a local registry
+
+    # docker login localhost:8080
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.
+

+ 26 - 0
contrib/man/md/docker-logs.1.md

@@ -0,0 +1,26 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-logs - Fetch the logs of a container
+
+# SYNOPSIS
+**docker logs** **--follow**[=*false*] CONTAINER
+
+# DESCRIPTION
+The **docker logs** command batch-retrieves whatever logs are present for
+a container at the time of execution. This does not guarantee execution
+order when combined with a docker run (i.e. your run may not have generated
+any logs at the time you execute docker logs).
+
+The **docker logs --follow** command combines commands **docker logs** and
+**docker attach**. It will first return all logs from the beginning and
+then continue streaming new output from the container’s stdout and stderr.
+
+# OPTIONS
+**-f, --follow**=*true*|*false*
+   When *true*, follow log output. The default is false.
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.

+ 15 - 0
contrib/man/md/docker-port.1.md

@@ -0,0 +1,15 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-port - Lookup the public-facing port which is NAT-ed to PRIVATE_PORT
+
+# SYNOPSIS
+**docker port** CONTAINER PRIVATE_PORT
+
+# DESCRIPTION
+Lookup the public-facing port which is NAT-ed to PRIVATE_PORT
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.

+ 68 - 0
contrib/man/md/docker-ps.1.md

@@ -0,0 +1,68 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-ps - List containers
+
+# SYNOPSIS
+**docker ps** [**-a**|**--all**=*false*] [**--before**=""]
+[**-l**|**--latest**=*false*] [**-n**=*-1*] [**--no-trunc**=*false*]
+[**-q**|**--quiet**=*false*] [**-s**|**--size**=*false*]
+[**--since**=""]
+
+# DESCRIPTION
+
+List the containers in the local repository. By default this show only
+the running containers.
+
+# OPTIONS
+
+**-a**, **--all**=*true*|*false*
+   When true show all containers. Only running containers are shown by
+default. Default is false.
+
+**--before**=""
+   Show only container created before Id or Name, include non-running
+ones.
+
+**-l**, **--latest**=*true*|*false*
+   When true show only the latest created container, include non-running
+ones. The default is false.
+
+**-n**=NUM
+   Show NUM (integer) last created containers, include non-running ones.
+The default is -1 (none)
+
+**--no-trunc**=*true*|*false*
+   When true truncate output. Default is false.
+
+**-q**, **--quiet**=*true*|*false*
+   When false only display numeric IDs. Default is false.
+
+**-s**, **--size**=*true*|*false*
+   When true display container sizes. Default is false.
+
+**--since**=""
+   Show only containers created since Id or Name, include non-running ones.
+
+# EXAMPLE
+# Display all containers, including non-running
+
+    # docker ps -a
+    CONTAINER ID        IMAGE                 COMMAND                CREATED             STATUS      PORTS    NAMES
+    a87ecb4f327c        fedora:20             /bin/sh -c #(nop) MA   20 minutes ago      Exit 0               desperate_brattain
+    01946d9d34d8        vpavlin/rhel7:latest  /bin/sh -c #(nop) MA   33 minutes ago      Exit 0               thirsty_bell
+    c1d3b0166030        acffc0358b9e          /bin/sh -c yum -y up   2 weeks ago         Exit 1               determined_torvalds
+    41d50ecd2f57        fedora:20             /bin/sh -c #(nop) MA   2 weeks ago         Exit 0               drunk_pike
+
+# Display only IDs of all containers, including non-running
+
+    # docker ps -a -q
+    a87ecb4f327c
+    01946d9d34d8
+    c1d3b0166030
+    41d50ecd2f57
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.

+ 37 - 0
contrib/man/md/docker-pull.1.md

@@ -0,0 +1,37 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-pull - Pull an image or a repository from the registry
+
+# SYNOPSIS
+**docker pull** NAME[:TAG]
+
+# DESCRIPTION
+
+This command pulls down an image or a repository from the registry. If
+there is more than one image for a repository (e.g. fedora) then all
+images for that repository name are pulled down including any tags.
+
+# EXAMPLE
+
+# Pull a reposiotry with multiple images
+
+    $ sudo docker pull fedora
+    Pulling repository fedora
+    ad57ef8d78d7: Download complete
+    105182bb5e8b: Download complete
+    511136ea3c5a: Download complete
+    73bd853d2ea5: Download complete
+
+    $ sudo docker images
+    REPOSITORY   TAG         IMAGE ID        CREATED      VIRTUAL SIZE
+    fedora       rawhide     ad57ef8d78d7    5 days ago   359.3 MB
+    fedora       20          105182bb5e8b    5 days ago   372.7 MB
+    fedora       heisenbug   105182bb5e8b    5 days ago   372.7 MB
+    fedora       latest      105182bb5e8b    5 days ago   372.7 MB
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.
+

+ 44 - 0
contrib/man/md/docker-push.1.md

@@ -0,0 +1,44 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-push - Push an image or a repository to the registry
+
+# SYNOPSIS
+**docker push** NAME[:TAG]
+
+# DESCRIPTION
+Push an image or a repository to a registry. The default registry is the Docker 
+Index located at [index.docker.io](https://index.docker.io/v1/). However the 
+image can be pushed to another, perhaps private, registry as demonstrated in 
+the example below.
+
+# EXAMPLE
+
+# Pushing a new image to a registry
+
+First save the new image by finding the container ID (using **docker ps**)
+and then committing it to a new image name:
+
+    # docker commit c16378f943fe rhel-httpd
+
+Now push the image to the registry using the image ID. In this example
+the registry is on host named registry-host and listening on port 5000.
+Default Docker commands will push to the default `index.docker.io`
+registry. Instead, push to the local registry, which is on a host called
+registry-host*. To do this, tag the image with the host name or IP
+address, and the port of the registry:
+
+    # docker tag rhel-httpd registry-host:5000/myadmin/rhel-httpd
+    # docker push registry-host:5000/myadmin/rhel-httpd
+
+Check that this worked by running:
+
+    # docker images
+
+You should see both `rhel-httpd` and `registry-host:5000/myadmin/rhel-httpd`
+listed.
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.

+ 21 - 0
contrib/man/md/docker-restart.1.md

@@ -0,0 +1,21 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-restart - Restart a running container
+
+# SYNOPSIS
+**docker restart** [**-t**|**--time**[=*10*]] CONTAINER [CONTAINER...]
+
+# DESCRIPTION
+Restart each container listed.
+
+# OPTIONS
+**-t**, **--time**=NUM
+   Number of seconds to try to stop for before killing the container. Once
+killed it will then be restarted. Default=10
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.
+

+ 56 - 0
contrib/man/md/docker-rm.1.md

@@ -0,0 +1,56 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+
+# NAME
+
+docker-rm - Remove one or more containers.
+
+# SYNOPSIS
+
+**docker rm** [**-f**|**--force**[=*false*] [**-l**|**--link**[=*false*] [**-v**|
+**--volumes**[=*false*]
+CONTAINER [CONTAINER...]
+
+# DESCRIPTION
+
+**docker rm** will remove one or more containers from the host node. The
+container name or ID can be used. This does not remove images. You cannot
+remove a running container unless you use the \fB-f\fR option. To see all
+containers on a host use the **docker ps -a** command.
+
+# OPTIONS
+
+**-f**, **--force**=*true*|*false*
+   When set to true, force the removal of the container. The default is
+*false*.
+
+**-l**, **--link**=*true*|*false*
+   When set to true, remove the specified link and not the underlying
+container. The default is *false*.
+
+**-v**, **--volumes**=*true*|*false*
+   When set to true, remove the volumes associated to the container. The
+default is *false*.
+
+# EXAMPLES
+
+##Removing a container using its ID##
+
+To remove a container using its ID, find either from a **docker ps -a**
+command, or use the ID returned from the **docker run** command, or retrieve
+it from a file used to store it using the **docker run --cidfile**:
+
+    docker rm abebf7571666
+
+##Removing a container using the container name##
+
+The name of the container can be found using the **docker ps -a**
+command. The use that name as follows:
+
+    docker rm hopeful_morse
+
+# HISTORY
+
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.

+ 35 - 0
contrib/man/md/docker-rmi.1.md

@@ -0,0 +1,35 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-rmi \- Remove one or more images.
+
+# SYNOPSIS
+
+**docker rmi** [**-f**|**--force**[=*false*] IMAGE [IMAGE...]
+
+# DESCRIPTION
+
+This will remove one or more images from the host node. This does not
+remove images from a registry. You cannot remove an image of a running
+container unless you use the **-f** option. To see all images on a host
+use the **docker images** command.
+
+# OPTIONS
+
+**-f**, **--force**=*true*|*false*
+   When set to true, force the removal of the image. The default is
+*false*.
+
+# EXAMPLES
+
+## Removing an image
+
+Here is an example of removing and image:
+
+    docker rmi fedora/httpd
+
+# HISTORY
+
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.

+ 343 - 0
contrib/man/md/docker-run.1.md

@@ -0,0 +1,343 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-run - Run a process in an isolated container
+
+# SYNOPSIS
+**docker run**
+[**-a**|**--attach**[=]] [**-c**|**--cpu-shares**[=0]
+[**-m**|**--memory**=*memory-limit*]
+[**--cidfile**=*file*] [**-d**|**--detach**[=*false*]] [**--dns**=*IP-address*]
+[**--name**=*name*] [**-u**|**--user**=*username*|*uid*]
+[**--link**=*name*:*alias*]
+[**-e**|**--env**=*environment*] [**--entrypoint**=*command*]
+[**--expose**=*port*] [**-P**|**--publish-all**[=*false*]]
+[**-p**|**--publish**=*port-mappping*] [**-h**|**--hostname**=*hostname*]
+[**--rm**[=*false*]] [**--priviledged**[=*false*]
+[**-i**|**--interactive**[=*false*]
+[**-t**|**--tty**[=*false*]] [**--lxc-conf**=*options*]
+[**-n**|**--networking**[=*true*]]
+[**-v**|**--volume**=*volume*] [**--volumes-from**=*container-id*]
+[**-w**|**--workdir**=*directory*] [**--sig-proxy**[=*true*]]
+IMAGE [COMMAND] [ARG...]
+
+# DESCRIPTION
+
+Run a process in a new container. **docker run** starts a process with its own
+file system, its own networking, and its own isolated process tree. The IMAGE
+which starts the process may define defaults related to the process that will be
+run in the container, the networking to expose, and more, but **docker run**
+gives final control to the operator or administrator who starts the container
+from the image. For that reason **docker run** has more options than any other
+Docker command.
+
+If the IMAGE is not already loaded then **docker run** will pull the IMAGE, and
+all image dependencies, from the repository in the same way running **docker
+pull** IMAGE, before it starts the container from that image.
+
+# OPTIONS
+
+**-a**, **--attach**=*stdin*|*stdout*|*stderr*
+   Attach to stdin, stdout or stderr. In foreground mode (the default when
+**-d** is not specified), **docker run** can start the process in the container
+and attach the console to the process’s standard input, output, and standard
+error. It can even pretend to be a TTY (this is what most commandline
+executables expect) and pass along signals. The **-a** option can be set for
+each of stdin, stdout, and stderr.
+
+**-c**, **--cpu-shares**=0
+   CPU shares in relative weight. You can increase the priority of a container
+with the -c option. By default, all containers run at the same priority and get
+the same proportion of CPU cycles, but you can tell the kernel to give more
+shares of CPU time to one or more containers when you start them via **docker
+run**.
+
+**--cidfile**=*file*
+   Write the container ID to the file specified.
+
+
+**-d**, **-detach**=*true*|*false*
+   Detached mode. This runs the container in the background. It outputs the new
+container's ID and any error messages. At any time you can run **docker ps** in
+the other shell to view a list of the running containers. You can reattach to a
+detached container with **docker attach**. If you choose to run a container in
+the detached mode, then you cannot use the **-rm** option.
+
+
+**--dns**=*IP-address*
+   Set custom DNS servers. This option can be used to override the DNS
+configuration passed to the container. Typically this is necessary when the
+host DNS configuration is invalid for the container (eg. 127.0.0.1). When this
+is the case the **-dns** flags is necessary for every run.
+
+
+**-e**, **-env**=*environment*
+   Set environment variables. This option allows you to specify arbitrary
+environment variables that are available for the process that will be launched
+inside of the container.
+
+
+**--entrypoint**=*command*
+   This option allows you to overwrite the default entrypoint of the image that
+is set in the Dockerfile. The ENTRYPOINT of an image is similar to a COMMAND
+because it specifies what executable to run when the container starts, but it is
+(purposely) more difficult to override. The ENTRYPOINT gives a container its
+default nature or behavior, so that when you set an ENTRYPOINT you can run the
+container as if it were that binary, complete with default options, and you can
+pass in more options via the COMMAND. But, sometimes an operator may want to run
+something else inside the container, so you can override the default ENTRYPOINT
+at runtime by using a **--entrypoint** and a string to specify the new
+ENTRYPOINT.
+
+**--expose**=*port*
+   Expose a port from the container without publishing it to your host. A
+containers port can be exposed to other containers in three ways: 1) The
+developer can expose the port using the EXPOSE parameter of the Dockerfile, 2)
+the operator can use the **--expose** option with **docker run**, or 3) the
+container can be started with the **--link**.
+
+**-m**, **-memory**=*memory-limit*
+   Allows you to constrain the memory available to a container. If the host
+supports swap memory, then the -m memory setting can be larger than physical
+RAM. The memory limit format: <number><optional unit>, where unit = b, k, m or
+g.
+
+**-P**, **-publish-all**=*true*|*false*
+   When set to true publish all exposed ports to the host interfaces. The
+default is false. If the operator uses -P (or -p) then Docker will make the
+exposed port accessible on the host and the ports will be available to any
+client that can reach the host. To find the map between the host ports and the
+exposed ports, use **docker port**.
+
+
+**-p**, **-publish**=[]
+   Publish a container's port to the host (format: ip:hostPort:containerPort |
+ip::containerPort | hostPort:containerPort) (use **docker port** to see the
+actual mapping)
+
+
+**-h**, **-hostname**=*hostname*
+   Sets the container host name that is available inside the container.
+
+
+**-i**, **-interactive**=*true*|*false*
+   When set to true, keep stdin open even if not attached. The default is false.
+
+
+**--link**=*name*:*alias*
+   Add link to another container. The format is name:alias. If the operator
+uses **--link** when starting the new client container, then the client
+container can access the exposed port via a private networking interface. Docker
+will set some environment variables in the client container to help indicate
+which interface and port to use.
+
+
+**-n**, **-networking**=*true*|*false*
+   By default, all containers have networking enabled (true) and can make
+outgoing connections. The operator can disable networking with **--networking**
+to false. This disables all incoming and outgoing networking. In cases like this
+, I/O can only be performed through files or by using STDIN/STDOUT.
+
+Also by default, the container will use the same DNS servers as the host. The
+operator may override this with **-dns**.
+
+
+**--name**=*name*
+   Assign a name to the container. The operator can identify a container in
+three ways:
+
+    UUID long identifier (“f78375b1c487e03c9438c729345e54db9d20cfa2ac1fc3494b6eb60872e74778”)
+    UUID short identifier (“f78375b1c487”)
+    Name (“jonah”)
+
+The UUID identifiers come from the Docker daemon, and if a name is not assigned
+to the container with **--name** then the daemon will also generate a random
+string name. The name is useful when defining links (see **--link**) (or any
+other place you need to identify a container). This works for both background
+and foreground Docker containers.
+
+
+**--privileged**=*true*|*false*
+   Give extended privileges to this container. By default, Docker containers are
+“unprivileged” (=false) and cannot, for example, run a Docker daemon inside the
+Docker container. This is because by default a container is not allowed to
+access any devices. A “privileged” container is given access to all devices.
+
+When the operator executes **docker run -privileged**, Docker will enable access
+to all devices on the host as well as set some configuration in AppArmor to
+allow the container nearly all the same access to the host as processes running
+outside of a container on the host.
+
+
+**--rm**=*true*|*false*
+   If set to *true* the container is automatically removed when it exits. The
+default is *false*. This option is incompatible with **-d**.
+
+
+**--sig-proxy**=*true*|*false*
+   When set to true, proxify all received signals to the process (even in
+non-tty mode). The default is true.
+
+
+**-t**, **-tty**=*true*|*false*
+   When set to true Docker can allocate a pseudo-tty and attach to the standard
+input of any container. This can be used, for example, to run a throwaway
+interactive shell. The default is value is false.
+
+
+**-u**, **-user**=*username*,*uid*
+   Set a username or UID for the container.
+
+
+**-v**, **-volume**=*volume*
+   Bind mount a volume to the container. The **-v** option can be used one or
+more times to add one or more mounts to a container. These mounts can then be
+used in other containers using the **--volumes-from** option. See examples.
+
+
+**--volumes-from**=*container-id*
+   Will mount volumes from the specified container identified by container-id.
+Once a volume is mounted in a one container it can be shared with other
+containers using the **--volumes-from** option when running those other
+containers. The volumes can be shared even if the original container with the
+mount is not running.
+
+
+**-w**, **-workdir**=*directory*
+   Working directory inside the container. The default working directory for
+running binaries within a container is the root directory (/). The developer can
+set a different default with the Dockerfile WORKDIR instruction. The operator
+can override the working directory by using the **-w** option.
+
+
+**IMAGE**
+   The image name or ID.
+
+
+**COMMAND**
+   The command or program to run inside the image.
+
+
+**ARG**
+   The arguments for the command to be run in the container.
+
+# EXAMPLES
+
+## Exposing log messages from the container to the host's log
+
+If you want messages that are logged in your container to show up in the host's
+syslog/journal then you should bind mount the /var/log directory as follows.
+
+    # docker run -v /dev/log:/dev/log -i -t fedora /bin/bash
+
+From inside the container you can test this by sending a message to the log.
+
+    (bash)# logger "Hello from my container"
+
+Then exit and check the journal.
+
+    # exit
+
+    # journalctl -b | grep Hello
+
+This should list the message sent to logger.
+
+## Attaching to one or more from STDIN, STDOUT, STDERR
+
+If you do not specify -a then Docker will attach everything (stdin,stdout,stderr)
+. You can specify to which of the three standard streams (stdin, stdout, stderr)
+you’d like to connect instead, as in:
+
+    # docker run -a stdin -a stdout -i -t fedora /bin/bash
+
+## Linking Containers
+
+The link feature allows multiple containers to communicate with each other. For
+example, a container whose Dockerfile has exposed port 80 can be run and named
+as follows:
+
+    # docker run --name=link-test -d -i -t fedora/httpd
+
+A second container, in this case called linker, can communicate with the httpd
+container, named link-test, by running with the **--link=<name>:<alias>**
+
+    # docker run -t -i --link=link-test:lt --name=linker fedora /bin/bash
+
+Now the container linker is linked to container link-test with the alias lt.
+Running the **env** command in the linker container shows environment variables
+ with the LT (alias) context (**LT_**)
+
+    # env
+    HOSTNAME=668231cb0978
+    TERM=xterm
+    LT_PORT_80_TCP=tcp://172.17.0.3:80
+    LT_PORT_80_TCP_PORT=80
+    LT_PORT_80_TCP_PROTO=tcp
+    LT_PORT=tcp://172.17.0.3:80
+    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
+    PWD=/
+    LT_NAME=/linker/lt
+    SHLVL=1
+    HOME=/
+    LT_PORT_80_TCP_ADDR=172.17.0.3
+    _=/usr/bin/env
+
+When linking two containers Docker will use the exposed ports of the container
+to create a secure tunnel for the parent to access.
+
+
+## Mapping Ports for External Usage
+
+The exposed port of an application can be mapped to a host port using the **-p**
+flag. For example a httpd port 80 can be mapped to the host port 8080 using the
+following:
+
+    # docker run -p 8080:80 -d -i -t fedora/httpd
+
+## Creating and Mounting a Data Volume Container
+
+Many applications require the sharing of persistent data across several
+containers. Docker allows you to create a Data Volume Container that other
+containers can mount from. For example, create a named container that contains
+directories /var/volume1 and /tmp/volume2. The image will need to contain these
+directories so a couple of RUN mkdir instructions might be required for you
+fedora-data image:
+
+    # docker run --name=data -v /var/volume1 -v /tmp/volume2 -i -t fedora-data true
+    # docker run --volumes-from=data --name=fedora-container1 -i -t fedora bash
+
+Multiple -volumes-from parameters will bring together multiple data volumes from
+multiple containers. And it's possible to mount the volumes that came from the
+DATA container in yet another container via the fedora-container1 intermidiery
+container, allowing to abstract the actual data source from users of that data:
+
+    # docker run --volumes-from=fedora-container1 --name=fedora-container2 -i -t fedora bash
+
+## Mounting External Volumes
+
+To mount a host directory as a container volume, specify the absolute path to
+the directory and the absolute path for the container directory separated by a
+colon:
+
+    # docker run -v /var/db:/data1 -i -t fedora bash
+
+When using SELinux, be aware that the host has no knowledge of container SELinux
+policy. Therefore, in the above example, if SELinux policy is enforced, the
+`/var/db` directory is not writable to the container. A "Permission Denied"
+message will occur and an avc: message in the host's syslog.
+
+
+To work around this, at time of writing this man page, the following command
+needs to be run in order for the proper SELinux policy type label to be attached
+to the host directory:
+
+    # chcon -Rt svirt_sandbox_file_t /var/db
+
+
+Now, writing to the /data1 volume in the container will be allowed and the
+changes will also be reflected on the host in /var/db.
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.

+ 35 - 0
contrib/man/md/docker-save.1.md

@@ -0,0 +1,35 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-save - Save an image to a tar archive (streamed to STDOUT by default)
+
+# SYNOPSIS
+**docker save** [**-o**|**--output**=""] IMAGE
+
+# DESCRIPTION
+Produces a tarred repository to the standard output stream. Contains all
+parent layers, and all tags + versions, or specified repo:tag.
+
+Stream to a file instead of STDOUT by using **-o**.
+
+# OPTIONS
+**-o**, **--output**=""
+   Write to an file, instead of STDOUT
+
+# EXAMPLE
+
+Save all fedora repository images to a fedora-all.tar and save the latest
+fedora image to a fedora-latest.tar:
+
+    $ sudo docker save fedora > fedora-all.tar
+    $ sudo docker save --output=fedora-latest.tar fedora:latest
+    $ ls -sh fedora-all.tar
+    721M fedora-all.tar
+    $ ls -sh fedora-latest.tar
+    367M fedora-latest.tar
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.
+

+ 55 - 0
contrib/man/md/docker-search.1.md

@@ -0,0 +1,55 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-search - Search the docker index for images
+
+# SYNOPSIS
+**docker search** **--no-trunc**[=*false*] **-t**|**--trusted**[=*false*]
+ **-s**|**--stars**[=*0*] TERM
+
+# DESCRIPTION
+
+Search an index for an image with that matches the term TERM. The table
+of images returned displays the name, description (truncated by default),
+number of stars awarded, whether the image is official, and whether it
+is trusted.
+
+# OPTIONS
+**--no-trunc**=*true*|*false*
+   When true display the complete description. The default is false.
+
+**-s**, **--stars**=NUM
+   Only displays with at least NUM (integer) stars. I.e. only those images
+ranked >=NUM.
+
+**-t**, **--trusted**=*true*|*false*
+   When true only show trusted builds. The default is false.
+
+# EXAMPLE
+
+## Search the registry for ranked images
+
+Search the registry for the term 'fedora' and only display those images
+ranked 3 or higher:
+
+    $ sudo docker search -s 3 fedora
+    NAME                  DESCRIPTION                                    STARS OFFICIAL  TRUSTED
+    mattdm/fedora         A basic Fedora image corresponding roughly...  50
+    fedora                (Semi) Official Fedora base image.             38
+    mattdm/fedora-small   A small Fedora image on which to build. Co...  8
+    goldmann/wildfly      A WildFly application server running on a ...  3               [OK]
+
+## Search the registry for trusted images
+
+Search the registry for the term 'fedora' and only display trusted images
+ranked 1 or higher:
+
+    $ sudo docker search -s 1 -t fedora
+    NAME               DESCRIPTION                                     STARS OFFICIAL  TRUSTED
+    goldmann/wildfly   A WildFly application server running on a ...   3               [OK]
+    tutum/fedora-20    Fedora 20 image with SSH access. For the r...   1               [OK]
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.

+ 25 - 0
contrib/man/md/docker-start.1.md

@@ -0,0 +1,25 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-start - Restart a stopped container
+
+# SYNOPSIS
+**docker start** [**a**|**--attach**[=*false*]] [**-i**|**--interactive**
+[=*true*] CONTAINER [CONTAINER...]
+
+# DESCRIPTION
+
+Start a stopped container.
+
+# OPTION
+**-a**, **--attach**=*true*|*false*
+   When true attach to container's stdout/stderr and forward all signals to
+the process
+
+**-i**, **--interactive**=*true*|*false*
+   When true attach to container's stdin
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.

+ 22 - 0
contrib/man/md/docker-stop.1.md

@@ -0,0 +1,22 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-stop - Stop a running container
+ grace period)
+
+# SYNOPSIS
+**docker stop** [**-t**|**--time**[=*10*]] CONTAINER [CONTAINER...]
+
+# DESCRIPTION
+Stop a running container (Send SIGTERM, and then SIGKILL after
+ grace period)
+
+# OPTIONS
+**-t**, **--time**=NUM
+   Wait NUM number of seconds for the container to stop before killing it.
+The default is 10 seconds.
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.

+ 48 - 0
contrib/man/md/docker-tag.1.md

@@ -0,0 +1,48 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-tag - Tag an image in the repository
+
+# SYNOPSIS
+**docker tag** [**-f**|**--force**[=*false*]
+IMAGE [REGISTRYHOST/][USERNAME/]NAME[:TAG]
+
+# DESCRIPTION
+This will tag an image in the repository.
+
+# "OPTIONS"
+**-f**, **--force**=*true*|*false*
+   When set to true, force the tag name. The default is *false*.
+
+**REGISTRYHOST**
+   The hostname of the registry if required. This may also include the port
+separated by a ':'
+
+**USERNAME**
+   The username or other qualifying identifier for the image.
+
+**NAME**
+   The image name.
+
+**TAG**
+   The tag you are assigning to the image.
+
+# EXAMPLES
+
+## Tagging an image
+
+Here is an example of tagging an image with the tag version1.0 :
+
+    docker tag 0e5574283393 fedora/httpd:version1.0
+
+## Tagging an image for a private repository
+
+To push an image to an private registry and not the central Docker
+registry you must tag it with the registry hostname and port (if needed).
+
+    docker tag 0e5574283393 myregistryhost:5000/fedora/httpd:version1.0
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.

+ 27 - 0
contrib/man/md/docker-top.1.md

@@ -0,0 +1,27 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-top - Lookup the running processes of a container
+
+# SYNOPSIS
+**docker top** CONTAINER [ps-OPTION]
+
+# DESCRIPTION
+
+Look up the running process of the container. ps-OPTION can be any of the
+ options you would pass to a Linux ps command.
+
+# EXAMPLE
+
+Run **docker top** with the ps option of -x:
+
+    $ sudo docker top 8601afda2b -x
+    PID      TTY       STAT       TIME         COMMAND
+    16623    ?         Ss         0:00         sleep 99999
+
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.
+

+ 23 - 0
contrib/man/md/docker-wait.1.md

@@ -0,0 +1,23 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker-wait - Block until a container stops, then print its exit code.
+
+# SYNOPSIS
+**docker wait** CONTAINER [CONTAINER...]
+
+# DESCRIPTION
+Block until a container stops, then print its exit code.
+
+#EXAMPLE
+
+    $ sudo docker run -d fedora sleep 99
+    079b83f558a2bc52ecad6b2a5de13622d584e6bb1aea058c11b36511e85e7622
+    $ sudo docker wait 079b83f558a2bc
+    0
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com)
+based on docker.io source material and internal work.
+

+ 187 - 0
contrib/man/md/docker.1.md

@@ -0,0 +1,187 @@
+% DOCKER(1) Docker User Manuals
+% William Henry
+% APRIL 2014
+# NAME
+docker \- Docker image and container command line interface
+
+# SYNOPSIS
+**docker** [OPTIONS] COMMAND [arg...]
+
+# DESCRIPTION
+**docker** has two distinct functions. It is used for starting the Docker
+daemon and to run the CLI (i.e., to command the daemon to manage images,
+containers etc.) So **docker** is both a server, as a deamon, and a client
+to the daemon, through the CLI.
+
+To run the Docker deamon you do not specify any of the commands listed below but
+must specify the **-d** option.  The other options listed below are for the
+daemon only.
+
+The Docker CLI has over 30 commands. The commands are listed below and each has
+its own man page which explain usage and arguements.
+
+To see the man page for a command run **man docker <command>**.
+
+# OPTIONS
+**-D**=*true*|*false*
+   Enable debug mode. Default is false.
+
+**-H**, **--host**=[unix:///var/run/docker.sock]: tcp://[host[:port]] to bind or
+unix://[/path/to/socket] to use.
+   Enable both the socket support and TCP on localhost. When host=[0.0.0.0],
+port=[4243] or path =[/var/run/docker.sock] is omitted, default values are used.
+
+**--api-enable-cors**=*true*|*false*
+  Enable CORS headers in the remote API. Default is false.
+
+**-b**=""
+  Attach containers to a pre\-existing network bridge; use 'none' to disable container networking
+
+**--bip**=""
+  Use the provided CIDR notation address for the dynamically created bridge (docker0); Mutually exclusive of \-b
+
+**-d**=*true*|*false*
+  Enable daemon mode. Default is false.
+
+**--dns**=""
+  Force Docker to use specific DNS servers
+
+**-g**=""
+  Path to use as the root of the Docker runtime. Default is `/var/lib/docker`.
+
+**--icc**=*true*|*false*
+  Enable inter\-container communication. Default is true.
+
+**--ip**=""
+  Default IP address to use when binding container ports. Default is `0.0.0.0`.
+
+**--iptables**=*true*|*false*
+  Disable Docker's addition of iptables rules. Default is true.
+
+**--mtu**=VALUE
+  Set the containers network mtu. Default is `1500`.
+
+**-p**=""
+  Path to use for daemon PID file. Default is `/var/run/docker.pid`
+
+**-r**=*true*|*false*
+  Restart previously running containers. Default is true.
+
+**-s**=""
+  Force the Docker runtime to use a specific storage driver.
+
+**-v**=*true*|*false*
+  Print version information and quit. Default is false.
+
+**--selinux-enabled=*true*|*false*
+  Enable selinux support. Default is false.
+
+# COMMANDS
+**docker-attach(1)**
+  Attach to a running container
+
+**docker-build(1)**
+  Build a container from a Dockerfile
+
+**docker-commit(1)**
+  Create a new image from a container's changes
+
+**docker-cp(1)**
+  Copy files/folders from the containers filesystem to the host at path
+
+**docker-diff(1)**
+  Inspect changes on a container's filesystem
+
+
+**docker-events(1)**
+  Get real time events from the server
+
+**docker-export(1)**
+  Stream the contents of a container as a tar archive
+
+**docker-history(1)**
+  Show the history of an image
+
+**docker-images(1)**
+  List images
+
+**docker-import(1)**
+  Create a new filesystem image from the contents of a tarball
+
+**docker-info(1)**
+  Display system-wide information
+
+**docker-inspect(1)**
+  Return low-level information on a container
+
+**docker-kill(1)**
+  Kill a running container (which includes the wrapper process and everything
+inside it)
+
+**docker-load(1)**
+  Load an image from a tar archive
+
+**docker-login(1)**
+  Register or Login to a Docker registry server
+
+**docker-logs(1)**
+  Fetch the logs of a container
+
+**docker-port(1)**
+  Lookup the public-facing port which is NAT-ed to PRIVATE_PORT
+
+**docker-ps(1)**
+  List containers
+
+**docker-pull(1)**
+  Pull an image or a repository from a Docker registry server
+
+**docker-push(1)**
+  Push an image or a repository to a Docker registry server
+
+**docker-restart(1)**
+  Restart a running container
+
+**docker-rm(1)**
+  Remove one or more containers
+
+**docker-rmi(1)**
+  Remove one or more images
+
+**docker-run(1)**
+  Run a command in a new container
+
+**docker-save(1)**
+  Save an image to a tar archive
+
+**docker-search(1)**
+  Search for an image in the Docker index
+
+**docker-start(1)**
+  Start a stopped container
+
+**docker-stop(1)**
+  Stop a running container
+
+**docker-tag(1)**
+  Tag an image into a repository
+
+**docker-top(1)**
+  Lookup the running processes of a container
+
+**version**
+  Show the Docker version information
+
+**docker-wait(1)**
+  Block until a container stops, then print its exit code
+
+# EXAMPLES
+
+For specific examples please see the man page for the specific Docker command.
+For example:
+
+    man docker run
+
+# HISTORY
+April 2014, Originally compiled by William Henry (whenry at redhat dot com) based
+ on docker.io source material and internal work.

+ 22 - 0
contrib/man/md/md2man-all.sh

@@ -0,0 +1,22 @@
+#!/bin/bash
+set -e
+
+# get into this script's directory
+cd "$(dirname "$(readlink -f "$BASH_SOURCE")")"
+
+[ "$1" = '-q' ] || {
+	set -x
+	pwd
+}
+
+for FILE in *.md; do
+	base="$(basename "$FILE")"
+	name="${base%.md}"
+	num="${name##*.}"
+	if [ -z "$num" -o "$base" = "$num" ]; then
+		# skip files that aren't of the format xxxx.N.md (like README.md)
+		continue
+	fi
+	mkdir -p "../man${num}"
+	pandoc -s -t man "$FILE" -o "../man${num}/${name}"
+done

+ 0 - 0
contrib/man/man1/docker-attach.1 → contrib/man/old-man/docker-attach.1


+ 0 - 0
contrib/man/man1/docker-build.1 → contrib/man/old-man/docker-build.1


+ 0 - 0
contrib/man/man1/docker-images.1 → contrib/man/old-man/docker-images.1


+ 0 - 0
contrib/man/man1/docker-info.1 → contrib/man/old-man/docker-info.1


+ 0 - 0
contrib/man/man1/docker-inspect.1 → contrib/man/old-man/docker-inspect.1


+ 0 - 0
contrib/man/man1/docker-rm.1 → contrib/man/old-man/docker-rm.1


+ 50 - 0
contrib/man/old-man/docker-rm.md

@@ -0,0 +1,50 @@
+DOCKER "1" "APRIL 2014" "0.1" "Docker"
+=======================================
+
+NAME
+----
+
+docker-rm - Remove one or more containers.
+
+SYNOPSIS
+--------
+
+`docker rm` [`-f`|`--force`[=*false*] [`-l`|`--link`[=*false*] [`-v`|`--volumes`[=*false*] 
+CONTAINER [CONTAINER...]
+
+DESCRIPTION
+-----------
+
+`docker rm` will remove one or more containers from the host node. The container name or ID can be used. This does not remove images. You cannot remove a running container unless you use the \fB-f\fR option. To see all containers on a host use the `docker ps -a` command.
+
+OPTIONS
+-------
+
+`-f`, `--force`=*true*|*false*: 
+  When set to true, force the removal of the container. The default is *false*.
+
+`-l`, `--link`=*true*|*false*: 
+  When set to true, remove the specified link and not the underlying container. The default is *false*.
+
+`-v`, `--volumes`=*true*|*false*: 
+  When set to true, remove the volumes associated to the container. The default is *false*.
+
+EXAMPLES
+--------
+
+##Removing a container using its ID##
+
+To remove a container using its ID, find either from a `docker ps -a` command, or use the ID returned from the `docker run` command, or retrieve it from a file used to store it using the `docker run --cidfile`:
+
+    docker rm abebf7571666
+
+##Removing a container using the container name##
+
+The name of the container can be found using the \fBdocker ps -a\fR command. The use that name as follows:
+
+    docker rm hopeful_morse
+
+HISTORY
+-------
+
+April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on dockier.io source material and internal work.

+ 0 - 0
contrib/man/man1/docker-rmi.1 → contrib/man/old-man/docker-rmi.1


+ 0 - 0
contrib/man/man1/docker-run.1 → contrib/man/old-man/docker-run.1


+ 0 - 0
contrib/man/man1/docker-tag.1 → contrib/man/old-man/docker-tag.1


+ 0 - 0
contrib/man/man1/docker.1 → contrib/man/old-man/docker.1


+ 82 - 0
contrib/mkimage-alpine.sh

@@ -0,0 +1,82 @@
+#!/bin/sh
+
+set -e
+
+[ $(id -u) -eq 0 ] || {
+	printf >&2 '%s requires root\n' "$0"
+	exit 1
+}
+
+usage() {
+	printf >&2 '%s: [-r release] [-m mirror] [-s]\n' "$0"
+	exit 1
+}
+
+tmp() {
+	TMP=$(mktemp -d /tmp/alpine-docker-XXXXXXXXXX)
+	ROOTFS=$(mktemp -d /tmp/alpine-docker-rootfs-XXXXXXXXXX)
+	trap "rm -rf $TMP $ROOTFS" EXIT TERM INT
+}
+
+apkv() {
+	curl -s $REPO/$ARCH/APKINDEX.tar.gz | tar -Oxz |
+		grep '^P:apk-tools-static$' -A1 | tail -n1 | cut -d: -f2
+}
+
+getapk() {
+	curl -s $REPO/$ARCH/apk-tools-static-$(apkv).apk |
+		tar -xz -C $TMP sbin/apk.static
+}
+
+mkbase() {
+	$TMP/sbin/apk.static --repository $REPO --update-cache --allow-untrusted \
+		--root $ROOTFS --initdb add alpine-base
+}
+
+conf() {
+	printf '%s\n' $REPO > $ROOTFS/etc/apk/repositories
+}
+
+pack() {
+	local id
+	id=$(tar --numeric-owner -C $ROOTFS -c . | docker import - alpine:$REL)
+
+	docker tag $id alpine:latest
+	docker run -i -t alpine printf 'alpine:%s with id=%s created!\n' $REL $id
+}
+
+save() {
+	[ $SAVE -eq 1 ] || return
+
+	tar --numeric-owner -C $ROOTFS -c . | xz > rootfs.tar.xz
+}
+
+while getopts "hr:m:s" opt; do
+	case $opt in
+		r)
+			REL=$OPTARG
+			;;
+		m)
+			MIRROR=$OPTARG
+			;;
+		s)
+			SAVE=1
+			;;
+		*)
+			usage
+			;;
+	esac
+done
+
+REL=${REL:-edge}
+MIRROR=${MIRROR:-http://nl.alpinelinux.org/alpine}
+SAVE=${SAVE:-0}
+REPO=$MIRROR/$REL/main
+ARCH=$(uname -m)
+
+tmp
+getapk
+mkbase
+conf
+pack
+save

+ 1 - 0
contrib/mkimage-arch.sh

@@ -57,6 +57,7 @@ mknod -m 666 $DEV/tty0 c 4 0
 mknod -m 666 $DEV/full c 1 7
 mknod -m 600 $DEV/initctl p
 mknod -m 666 $DEV/ptmx c 5 2
+ln -sf /proc/self/fd $DEV/fd
 
 tar --numeric-owner -C $ROOTFS -c . | docker import - archlinux
 docker run -i -t archlinux echo Success.

+ 0 - 1
contrib/zfs/MAINTAINERS

@@ -1 +0,0 @@
-Gurjeet Singh <gurjeet@singh.im> (gurjeet.singh.im)

+ 0 - 23
contrib/zfs/README.md

@@ -1,23 +0,0 @@
-# ZFS Storage Driver
-
-This is a placeholder to declare the presence and status of ZFS storage driver
-for containers.
-
-The current development is done in Gurjeet Singh's fork of Docker, under the
-branch named [zfs_driver].
-
-[zfs_driver]: https://github.com/gurjeet/docker/tree/zfs_driver
-
-
-# Status
-
-Alpha: The code is now capable of creating, running and destroying containers
-and images.
-
-The code is under development. Contributions in the form of suggestions,
-code-reviews, and patches are welcome.
-
-Please send the communication to gurjeet@singh.im and CC at least one Docker
-mailing list.
-
-

+ 153 - 0
daemon/attach.go

@@ -0,0 +1,153 @@
+package daemon
+
+import (
+	"io"
+
+	"github.com/dotcloud/docker/utils"
+)
+
+func (daemon *Daemon) Attach(container *Container, stdin io.ReadCloser, stdinCloser io.Closer, stdout io.Writer, stderr io.Writer) chan error {
+	var (
+		cStdout, cStderr io.ReadCloser
+		nJobs            int
+		errors           = make(chan error, 3)
+	)
+
+	if stdin != nil && container.Config.OpenStdin {
+		nJobs += 1
+		if cStdin, err := container.StdinPipe(); err != nil {
+			errors <- err
+		} else {
+			go func() {
+				utils.Debugf("attach: stdin: begin")
+				defer utils.Debugf("attach: stdin: end")
+				// No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
+				if container.Config.StdinOnce && !container.Config.Tty {
+					defer cStdin.Close()
+				} else {
+					defer func() {
+						if cStdout != nil {
+							cStdout.Close()
+						}
+						if cStderr != nil {
+							cStderr.Close()
+						}
+					}()
+				}
+				if container.Config.Tty {
+					_, err = utils.CopyEscapable(cStdin, stdin)
+				} else {
+					_, err = io.Copy(cStdin, stdin)
+				}
+				if err == io.ErrClosedPipe {
+					err = nil
+				}
+				if err != nil {
+					utils.Errorf("attach: stdin: %s", err)
+				}
+				errors <- err
+			}()
+		}
+	}
+	if stdout != nil {
+		nJobs += 1
+		if p, err := container.StdoutPipe(); err != nil {
+			errors <- err
+		} else {
+			cStdout = p
+			go func() {
+				utils.Debugf("attach: stdout: begin")
+				defer utils.Debugf("attach: stdout: end")
+				// If we are in StdinOnce mode, then close stdin
+				if container.Config.StdinOnce && stdin != nil {
+					defer stdin.Close()
+				}
+				if stdinCloser != nil {
+					defer stdinCloser.Close()
+				}
+				_, err := io.Copy(stdout, cStdout)
+				if err == io.ErrClosedPipe {
+					err = nil
+				}
+				if err != nil {
+					utils.Errorf("attach: stdout: %s", err)
+				}
+				errors <- err
+			}()
+		}
+	} else {
+		go func() {
+			if stdinCloser != nil {
+				defer stdinCloser.Close()
+			}
+			if cStdout, err := container.StdoutPipe(); err != nil {
+				utils.Errorf("attach: stdout pipe: %s", err)
+			} else {
+				io.Copy(&utils.NopWriter{}, cStdout)
+			}
+		}()
+	}
+	if stderr != nil {
+		nJobs += 1
+		if p, err := container.StderrPipe(); err != nil {
+			errors <- err
+		} else {
+			cStderr = p
+			go func() {
+				utils.Debugf("attach: stderr: begin")
+				defer utils.Debugf("attach: stderr: end")
+				// If we are in StdinOnce mode, then close stdin
+				if container.Config.StdinOnce && stdin != nil {
+					defer stdin.Close()
+				}
+				if stdinCloser != nil {
+					defer stdinCloser.Close()
+				}
+				_, err := io.Copy(stderr, cStderr)
+				if err == io.ErrClosedPipe {
+					err = nil
+				}
+				if err != nil {
+					utils.Errorf("attach: stderr: %s", err)
+				}
+				errors <- err
+			}()
+		}
+	} else {
+		go func() {
+			if stdinCloser != nil {
+				defer stdinCloser.Close()
+			}
+
+			if cStderr, err := container.StderrPipe(); err != nil {
+				utils.Errorf("attach: stdout pipe: %s", err)
+			} else {
+				io.Copy(&utils.NopWriter{}, cStderr)
+			}
+		}()
+	}
+
+	return utils.Go(func() error {
+		defer func() {
+			if cStdout != nil {
+				cStdout.Close()
+			}
+			if cStderr != nil {
+				cStderr.Close()
+			}
+		}()
+
+		// FIXME: how to clean up the stdin goroutine without the unwanted side effect
+		// of closing the passed stdin? Add an intermediary io.Pipe?
+		for i := 0; i < nJobs; i += 1 {
+			utils.Debugf("attach: waiting for job %d/%d", i+1, nJobs)
+			if err := <-errors; err != nil {
+				utils.Errorf("attach: job %d returned error %s, aborting all jobs", i+1, err)
+				return err
+			}
+			utils.Debugf("attach: job %d completed successfully", i+1)
+		}
+		utils.Debugf("attach: all jobs completed successfully")
+		return nil
+	})
+}

+ 405 - 528
runtime/container.go → daemon/container.go

@@ -1,18 +1,9 @@
-package runtime
+package daemon
 
 import (
 	"encoding/json"
 	"errors"
 	"fmt"
-	"github.com/dotcloud/docker/archive"
-	"github.com/dotcloud/docker/engine"
-	"github.com/dotcloud/docker/image"
-	"github.com/dotcloud/docker/links"
-	"github.com/dotcloud/docker/nat"
-	"github.com/dotcloud/docker/runconfig"
-	"github.com/dotcloud/docker/runtime/execdriver"
-	"github.com/dotcloud/docker/runtime/graphdriver"
-	"github.com/dotcloud/docker/utils"
 	"io"
 	"io/ioutil"
 	"log"
@@ -22,6 +13,19 @@ import (
 	"sync"
 	"syscall"
 	"time"
+
+	"github.com/dotcloud/docker/archive"
+	"github.com/dotcloud/docker/daemon/execdriver"
+	"github.com/dotcloud/docker/daemon/graphdriver"
+	"github.com/dotcloud/docker/engine"
+	"github.com/dotcloud/docker/image"
+	"github.com/dotcloud/docker/links"
+	"github.com/dotcloud/docker/nat"
+	"github.com/dotcloud/docker/pkg/label"
+	"github.com/dotcloud/docker/pkg/networkfs/etchosts"
+	"github.com/dotcloud/docker/pkg/networkfs/resolvconf"
+	"github.com/dotcloud/docker/runconfig"
+	"github.com/dotcloud/docker/utils"
 )
 
 const DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
@@ -64,7 +68,8 @@ type Container struct {
 	stdin     io.ReadCloser
 	stdinPipe io.WriteCloser
 
-	runtime *Runtime
+	daemon                   *Daemon
+	MountLabel, ProcessLabel string
 
 	waitLock chan struct{}
 	Volumes  map[string]string
@@ -76,42 +81,6 @@ type Container struct {
 	activeLinks map[string]*links.Link
 }
 
-// FIXME: move deprecated port stuff to nat to clean up the core.
-type PortMapping map[string]string // Deprecated
-
-type NetworkSettings struct {
-	IPAddress   string
-	IPPrefixLen int
-	Gateway     string
-	Bridge      string
-	PortMapping map[string]PortMapping // Deprecated
-	Ports       nat.PortMap
-}
-
-func (settings *NetworkSettings) PortMappingAPI() *engine.Table {
-	var outs = engine.NewTable("", 0)
-	for port, bindings := range settings.Ports {
-		p, _ := nat.ParsePort(port.Port())
-		if len(bindings) == 0 {
-			out := &engine.Env{}
-			out.SetInt("PublicPort", p)
-			out.Set("Type", port.Proto())
-			outs.Add(out)
-			continue
-		}
-		for _, binding := range bindings {
-			out := &engine.Env{}
-			h, _ := nat.ParsePort(binding.HostPort)
-			out.SetInt("PrivatePort", p)
-			out.SetInt("PublicPort", h)
-			out.Set("Type", port.Proto())
-			out.Set("IP", binding.HostIp)
-			outs.Add(out)
-		}
-	}
-	return outs
-}
-
 // Inject the io.Reader at the given path. Note: do not close the reader
 func (container *Container) Inject(file io.Reader, pth string) error {
 	if err := container.Mount(); err != nil {
@@ -148,10 +117,6 @@ func (container *Container) Inject(file io.Reader, pth string) error {
 	return nil
 }
 
-func (container *Container) When() time.Time {
-	return container.Created
-}
-
 func (container *Container) FromDisk() error {
 	data, err := ioutil.ReadFile(container.jsonPath())
 	if err != nil {
@@ -162,6 +127,10 @@ func (container *Container) FromDisk() error {
 	if err := json.Unmarshal(data, container); err != nil && !strings.Contains(err.Error(), "docker.PortMapping") {
 		return err
 	}
+
+	if err := label.ReserveLabel(container.ProcessLabel); err != nil {
+		return err
+	}
 	return container.readHostConfig()
 }
 
@@ -201,186 +170,46 @@ func (container *Container) WriteHostConfig() (err error) {
 	return ioutil.WriteFile(container.hostConfigPath(), data, 0666)
 }
 
-func (container *Container) generateEnvConfig(env []string) error {
-	data, err := json.Marshal(env)
-	if err != nil {
-		return err
-	}
-	p, err := container.EnvConfigPath()
-	if err != nil {
-		return err
-	}
-	ioutil.WriteFile(p, data, 0600)
-	return nil
-}
-
-func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, stdout io.Writer, stderr io.Writer) chan error {
-	var cStdout, cStderr io.ReadCloser
-
-	var nJobs int
-	errors := make(chan error, 3)
-	if stdin != nil && container.Config.OpenStdin {
-		nJobs += 1
-		if cStdin, err := container.StdinPipe(); err != nil {
-			errors <- err
-		} else {
-			go func() {
-				utils.Debugf("attach: stdin: begin")
-				defer utils.Debugf("attach: stdin: end")
-				// No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
-				if container.Config.StdinOnce && !container.Config.Tty {
-					defer cStdin.Close()
-				} else {
-					defer func() {
-						if cStdout != nil {
-							cStdout.Close()
-						}
-						if cStderr != nil {
-							cStderr.Close()
-						}
-					}()
-				}
-				if container.Config.Tty {
-					_, err = utils.CopyEscapable(cStdin, stdin)
-				} else {
-					_, err = io.Copy(cStdin, stdin)
-				}
-				if err == io.ErrClosedPipe {
-					err = nil
-				}
-				if err != nil {
-					utils.Errorf("attach: stdin: %s", err)
-				}
-				errors <- err
-			}()
-		}
-	}
-	if stdout != nil {
-		nJobs += 1
-		if p, err := container.StdoutPipe(); err != nil {
-			errors <- err
-		} else {
-			cStdout = p
-			go func() {
-				utils.Debugf("attach: stdout: begin")
-				defer utils.Debugf("attach: stdout: end")
-				// If we are in StdinOnce mode, then close stdin
-				if container.Config.StdinOnce && stdin != nil {
-					defer stdin.Close()
-				}
-				if stdinCloser != nil {
-					defer stdinCloser.Close()
-				}
-				_, err := io.Copy(stdout, cStdout)
-				if err == io.ErrClosedPipe {
-					err = nil
-				}
-				if err != nil {
-					utils.Errorf("attach: stdout: %s", err)
-				}
-				errors <- err
-			}()
-		}
-	} else {
-		go func() {
-			if stdinCloser != nil {
-				defer stdinCloser.Close()
-			}
-			if cStdout, err := container.StdoutPipe(); err != nil {
-				utils.Errorf("attach: stdout pipe: %s", err)
-			} else {
-				io.Copy(&utils.NopWriter{}, cStdout)
-			}
-		}()
-	}
-	if stderr != nil {
-		nJobs += 1
-		if p, err := container.StderrPipe(); err != nil {
-			errors <- err
-		} else {
-			cStderr = p
-			go func() {
-				utils.Debugf("attach: stderr: begin")
-				defer utils.Debugf("attach: stderr: end")
-				// If we are in StdinOnce mode, then close stdin
-				if container.Config.StdinOnce && stdin != nil {
-					defer stdin.Close()
-				}
-				if stdinCloser != nil {
-					defer stdinCloser.Close()
-				}
-				_, err := io.Copy(stderr, cStderr)
-				if err == io.ErrClosedPipe {
-					err = nil
-				}
-				if err != nil {
-					utils.Errorf("attach: stderr: %s", err)
-				}
-				errors <- err
-			}()
-		}
-	} else {
-		go func() {
-			if stdinCloser != nil {
-				defer stdinCloser.Close()
-			}
-
-			if cStderr, err := container.StderrPipe(); err != nil {
-				utils.Errorf("attach: stdout pipe: %s", err)
-			} else {
-				io.Copy(&utils.NopWriter{}, cStderr)
-			}
-		}()
-	}
-
-	return utils.Go(func() error {
-		defer func() {
-			if cStdout != nil {
-				cStdout.Close()
-			}
-			if cStderr != nil {
-				cStderr.Close()
-			}
-		}()
-
-		// FIXME: how to clean up the stdin goroutine without the unwanted side effect
-		// of closing the passed stdin? Add an intermediary io.Pipe?
-		for i := 0; i < nJobs; i += 1 {
-			utils.Debugf("attach: waiting for job %d/%d", i+1, nJobs)
-			if err := <-errors; err != nil {
-				utils.Errorf("attach: job %d returned error %s, aborting all jobs", i+1, err)
-				return err
-			}
-			utils.Debugf("attach: job %d completed successfully", i+1)
-		}
-		utils.Debugf("attach: all jobs completed successfully")
-		return nil
-	})
-}
-
-func populateCommand(c *Container) {
+func populateCommand(c *Container, env []string) error {
 	var (
-		en           *execdriver.Network
-		driverConfig = make(map[string][]string)
+		en      *execdriver.Network
+		context = make(map[string][]string)
 	)
+	context["process_label"] = []string{c.GetProcessLabel()}
+	context["mount_label"] = []string{c.GetMountLabel()}
 
 	en = &execdriver.Network{
-		Mtu:       c.runtime.config.Mtu,
+		Mtu:       c.daemon.config.Mtu,
 		Interface: nil,
 	}
 
-	if !c.Config.NetworkDisabled {
-		network := c.NetworkSettings
-		en.Interface = &execdriver.NetworkInterface{
-			Gateway:     network.Gateway,
-			Bridge:      network.Bridge,
-			IPAddress:   network.IPAddress,
-			IPPrefixLen: network.IPPrefixLen,
+	parts := strings.SplitN(string(c.hostConfig.NetworkMode), ":", 2)
+	switch parts[0] {
+	case "none":
+	case "host":
+		en.HostNetworking = true
+	case "bridge", "": // empty string to support existing containers
+		if !c.Config.NetworkDisabled {
+			network := c.NetworkSettings
+			en.Interface = &execdriver.NetworkInterface{
+				Gateway:     network.Gateway,
+				Bridge:      network.Bridge,
+				IPAddress:   network.IPAddress,
+				IPPrefixLen: network.IPPrefixLen,
+			}
 		}
+	case "container":
+		nc, err := c.getNetworkedContainer()
+		if err != nil {
+			return err
+		}
+		en.ContainerID = nc.ID
+	default:
+		return fmt.Errorf("invalid network mode: %s", c.hostConfig.NetworkMode)
 	}
 
 	// TODO: this can be removed after lxc-conf is fully deprecated
-	mergeLxcConfIntoOptions(c.hostConfig, driverConfig)
+	mergeLxcConfIntoOptions(c.hostConfig, context)
 
 	resources := &execdriver.Resources{
 		Memory:     c.Config.Memory,
@@ -398,22 +227,12 @@ func populateCommand(c *Container) {
 		Network:    en,
 		Tty:        c.Config.Tty,
 		User:       c.Config.User,
-		Config:     driverConfig,
+		Config:     context,
 		Resources:  resources,
 	}
 	c.command.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
-}
-
-func (container *Container) ArgsAsString() string {
-	var args []string
-	for _, arg := range container.Args {
-		if strings.Contains(arg, " ") {
-			args = append(args, fmt.Sprintf("'%s'", arg))
-		} else {
-			args = append(args, arg)
-		}
-	}
-	return strings.Join(args, " ")
+	c.command.Env = env
+	return nil
 }
 
 func (container *Container) Start() (err error) {
@@ -423,186 +242,47 @@ func (container *Container) Start() (err error) {
 	if container.State.IsRunning() {
 		return nil
 	}
-
+	// if we encounter and error during start we need to ensure that any other
+	// setup has been cleaned up properly
 	defer func() {
 		if err != nil {
 			container.cleanup()
 		}
 	}()
 
-	if container.ResolvConfPath == "" {
-		if err := container.setupContainerDns(); err != nil {
-			return err
-		}
+	if err := container.setupContainerDns(); err != nil {
+		return err
 	}
-
 	if err := container.Mount(); err != nil {
 		return err
 	}
-
-	if container.runtime.config.DisableNetwork {
-		container.Config.NetworkDisabled = true
-		container.buildHostnameAndHostsFiles("127.0.1.1")
-	} else {
-		if err := container.allocateNetwork(); err != nil {
-			return err
-		}
-		container.buildHostnameAndHostsFiles(container.NetworkSettings.IPAddress)
-	}
-
-	// Make sure the config is compatible with the current kernel
-	if container.Config.Memory > 0 && !container.runtime.sysInfo.MemoryLimit {
-		log.Printf("WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.\n")
-		container.Config.Memory = 0
-	}
-	if container.Config.Memory > 0 && !container.runtime.sysInfo.SwapLimit {
-		log.Printf("WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.\n")
-		container.Config.MemorySwap = -1
-	}
-
-	if container.runtime.sysInfo.IPv4ForwardingDisabled {
-		log.Printf("WARNING: IPv4 forwarding is disabled. Networking will not work")
+	if err := container.initializeNetworking(); err != nil {
+		return err
 	}
-
+	container.verifyDaemonSettings()
 	if err := prepareVolumesForContainer(container); err != nil {
 		return err
 	}
-
-	// Setup environment
-	env := []string{
-		"HOME=/",
-		"PATH=" + DefaultPathEnv,
-		"HOSTNAME=" + container.Config.Hostname,
-	}
-
-	if container.Config.Tty {
-		env = append(env, "TERM=xterm")
-	}
-
-	// Init any links between the parent and children
-	runtime := container.runtime
-
-	children, err := runtime.Children(container.Name)
+	linkedEnv, err := container.setupLinkedContainers()
 	if err != nil {
 		return err
 	}
-
-	if len(children) > 0 {
-		container.activeLinks = make(map[string]*links.Link, len(children))
-
-		// If we encounter an error make sure that we rollback any network
-		// config and ip table changes
-		rollback := func() {
-			for _, link := range container.activeLinks {
-				link.Disable()
-			}
-			container.activeLinks = nil
-		}
-
-		for linkAlias, child := range children {
-			if !child.State.IsRunning() {
-				return fmt.Errorf("Cannot link to a non running container: %s AS %s", child.Name, linkAlias)
-			}
-
-			link, err := links.NewLink(
-				container.NetworkSettings.IPAddress,
-				child.NetworkSettings.IPAddress,
-				linkAlias,
-				child.Config.Env,
-				child.Config.ExposedPorts,
-				runtime.eng)
-
-			if err != nil {
-				rollback()
-				return err
-			}
-
-			container.activeLinks[link.Alias()] = link
-			if err := link.Enable(); err != nil {
-				rollback()
-				return err
-			}
-
-			for _, envVar := range link.ToEnv() {
-				env = append(env, envVar)
-			}
-		}
-	}
-
-	// because the env on the container can override certain default values
-	// we need to replace the 'env' keys where they match and append anything
-	// else.
-	env = utils.ReplaceOrAppendEnvValues(env, container.Config.Env)
-	if err := container.generateEnvConfig(env); err != nil {
+	if err := container.setupWorkingDirectory(); err != nil {
 		return err
 	}
-
-	if container.Config.WorkingDir != "" {
-		container.Config.WorkingDir = path.Clean(container.Config.WorkingDir)
-
-		pthInfo, err := os.Stat(path.Join(container.basefs, container.Config.WorkingDir))
-		if err != nil {
-			if !os.IsNotExist(err) {
-				return err
-			}
-			if err := os.MkdirAll(path.Join(container.basefs, container.Config.WorkingDir), 0755); err != nil {
-				return err
-			}
-		}
-		if pthInfo != nil && !pthInfo.IsDir() {
-			return fmt.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir)
-		}
-	}
-
-	envPath, err := container.EnvConfigPath()
-	if err != nil {
-		return err
-	}
-
-	populateCommand(container)
-	container.command.Env = env
-
-	if err := setupMountsForContainer(container, envPath); err != nil {
+	env := container.createDaemonEnvironment(linkedEnv)
+	if err := populateCommand(container, env); err != nil {
 		return err
 	}
-
-	// Setup logging of stdout and stderr to disk
-	if err := container.runtime.LogToDisk(container.stdout, container.logPath("json"), "stdout"); err != nil {
+	if err := setupMountsForContainer(container); err != nil {
 		return err
 	}
-	if err := container.runtime.LogToDisk(container.stderr, container.logPath("json"), "stderr"); err != nil {
+	if err := container.startLoggingToDisk(); err != nil {
 		return err
 	}
 	container.waitLock = make(chan struct{})
 
-	callbackLock := make(chan struct{})
-	callback := func(command *execdriver.Command) {
-		container.State.SetRunning(command.Pid())
-		if command.Tty {
-			// The callback is called after the process Start()
-			// so we are in the parent process. In TTY mode, stdin/out/err is the PtySlace
-			// which we close here.
-			if c, ok := command.Stdout.(io.Closer); ok {
-				c.Close()
-			}
-		}
-		if err := container.ToDisk(); err != nil {
-			utils.Debugf("%s", err)
-		}
-		close(callbackLock)
-	}
-
-	// We use a callback here instead of a goroutine and an chan for
-	// syncronization purposes
-	cErr := utils.Go(func() error { return container.monitor(callback) })
-
-	// Start should not return until the process is actually running
-	select {
-	case <-callbackLock:
-	case err := <-cErr:
-		return err
-	}
-	return nil
+	return container.waitForStart()
 }
 
 func (container *Container) Run() error {
@@ -651,74 +331,69 @@ func (container *Container) StderrPipe() (io.ReadCloser, error) {
 	return utils.NewBufReader(reader), nil
 }
 
-func (container *Container) buildHostnameAndHostsFiles(IP string) {
+func (container *Container) StdoutLogPipe() io.ReadCloser {
+	reader, writer := io.Pipe()
+	container.stdout.AddWriter(writer, "stdout")
+	return utils.NewBufReader(reader)
+}
+
+func (container *Container) StderrLogPipe() io.ReadCloser {
+	reader, writer := io.Pipe()
+	container.stderr.AddWriter(writer, "stderr")
+	return utils.NewBufReader(reader)
+}
+
+func (container *Container) buildHostnameFile() error {
 	container.HostnamePath = path.Join(container.root, "hostname")
-	ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644)
+	if container.Config.Domainname != "" {
+		return ioutil.WriteFile(container.HostnamePath, []byte(fmt.Sprintf("%s.%s\n", container.Config.Hostname, container.Config.Domainname)), 0644)
+	}
+	return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644)
+}
 
-	hostsContent := []byte(`
-127.0.0.1	localhost
-::1		localhost ip6-localhost ip6-loopback
-fe00::0		ip6-localnet
-ff00::0		ip6-mcastprefix
-ff02::1		ip6-allnodes
-ff02::2		ip6-allrouters
-`)
+func (container *Container) buildHostnameAndHostsFiles(IP string) error {
+	if err := container.buildHostnameFile(); err != nil {
+		return err
+	}
 
 	container.HostsPath = path.Join(container.root, "hosts")
 
-	if container.Config.Domainname != "" {
-		hostsContent = append([]byte(fmt.Sprintf("%s\t%s.%s %s\n", IP, container.Config.Hostname, container.Config.Domainname, container.Config.Hostname)), hostsContent...)
-	} else if !container.Config.NetworkDisabled {
-		hostsContent = append([]byte(fmt.Sprintf("%s\t%s\n", IP, container.Config.Hostname)), hostsContent...)
+	extraContent := make(map[string]string)
+
+	children, err := container.daemon.Children(container.Name)
+	if err != nil {
+		return err
 	}
 
-	ioutil.WriteFile(container.HostsPath, hostsContent, 0644)
+	for linkAlias, child := range children {
+		_, alias := path.Split(linkAlias)
+		extraContent[alias] = child.NetworkSettings.IPAddress
+	}
+
+	return etchosts.Build(container.HostsPath, IP, container.Config.Hostname, container.Config.Domainname, &extraContent)
 }
 
 func (container *Container) allocateNetwork() error {
-	if container.Config.NetworkDisabled {
+	mode := container.hostConfig.NetworkMode
+	if container.Config.NetworkDisabled || mode.IsContainer() || mode.IsHost() {
 		return nil
 	}
 
 	var (
 		env *engine.Env
 		err error
-		eng = container.runtime.eng
+		eng = container.daemon.eng
 	)
 
-	if container.State.IsGhost() {
-		if container.runtime.config.DisableNetwork {
-			env = &engine.Env{}
-		} else {
-			currentIP := container.NetworkSettings.IPAddress
-
-			job := eng.Job("allocate_interface", container.ID)
-			if currentIP != "" {
-				job.Setenv("RequestIP", currentIP)
-			}
-
-			env, err = job.Stdout.AddEnv()
-			if err != nil {
-				return err
-			}
-
-			if err := job.Run(); err != nil {
-				return err
-			}
-		}
-	} else {
-		job := eng.Job("allocate_interface", container.ID)
-		env, err = job.Stdout.AddEnv()
-		if err != nil {
-			return err
-		}
-		if err := job.Run(); err != nil {
-			return err
-		}
+	job := eng.Job("allocate_interface", container.ID)
+	if env, err = job.Stdout.AddEnv(); err != nil {
+		return err
+	}
+	if err := job.Run(); err != nil {
+		return err
 	}
 
 	if container.Config.PortSpecs != nil {
-		utils.Debugf("Migrating port mappings for container: %s", strings.Join(container.Config.PortSpecs, ", "))
 		if err := migratePortMappings(container.Config, container.hostConfig); err != nil {
 			return err
 		}
@@ -733,58 +408,23 @@ func (container *Container) allocateNetwork() error {
 		bindings  = make(nat.PortMap)
 	)
 
-	if !container.State.IsGhost() {
-		if container.Config.ExposedPorts != nil {
-			portSpecs = container.Config.ExposedPorts
-		}
-		if container.hostConfig.PortBindings != nil {
-			bindings = container.hostConfig.PortBindings
-		}
-	} else {
-		if container.NetworkSettings.Ports != nil {
-			for port, binding := range container.NetworkSettings.Ports {
-				portSpecs[port] = struct{}{}
-				bindings[port] = binding
-			}
-		}
+	if container.Config.ExposedPorts != nil {
+		portSpecs = container.Config.ExposedPorts
+	}
+	if container.hostConfig.PortBindings != nil {
+		bindings = container.hostConfig.PortBindings
 	}
 
 	container.NetworkSettings.PortMapping = nil
 
 	for port := range portSpecs {
-		binding := bindings[port]
-		if container.hostConfig.PublishAllPorts && len(binding) == 0 {
-			binding = append(binding, nat.PortBinding{})
-		}
-
-		for i := 0; i < len(binding); i++ {
-			b := binding[i]
-
-			portJob := eng.Job("allocate_port", container.ID)
-			portJob.Setenv("HostIP", b.HostIp)
-			portJob.Setenv("HostPort", b.HostPort)
-			portJob.Setenv("Proto", port.Proto())
-			portJob.Setenv("ContainerPort", port.Port())
-
-			portEnv, err := portJob.Stdout.AddEnv()
-			if err != nil {
-				return err
-			}
-			if err := portJob.Run(); err != nil {
-				eng.Job("release_interface", container.ID).Run()
-				return err
-			}
-			b.HostIp = portEnv.Get("HostIP")
-			b.HostPort = portEnv.Get("HostPort")
-
-			binding[i] = b
+		if err := container.allocatePort(eng, port, bindings); err != nil {
+			return err
 		}
-		bindings[port] = binding
 	}
 	container.WriteHostConfig()
 
 	container.NetworkSettings.Ports = bindings
-
 	container.NetworkSettings.Bridge = env.Get("Bridge")
 	container.NetworkSettings.IPAddress = env.Get("IP")
 	container.NetworkSettings.IPPrefixLen = env.GetInt("IPPrefixLen")
@@ -797,7 +437,7 @@ func (container *Container) releaseNetwork() {
 	if container.Config.NetworkDisabled {
 		return
 	}
-	eng := container.runtime.eng
+	eng := container.daemon.eng
 
 	eng.Job("release_interface", container.ID).Run()
 	container.NetworkSettings = &NetworkSettings{}
@@ -810,12 +450,12 @@ func (container *Container) monitor(callback execdriver.StartCallback) error {
 	)
 
 	pipes := execdriver.NewPipes(container.stdin, container.stdout, container.stderr, container.Config.OpenStdin)
-	exitCode, err = container.runtime.Run(container, pipes, callback)
+	exitCode, err = container.daemon.Run(container, pipes, callback)
 	if err != nil {
 		utils.Errorf("Error running container: %s", err)
 	}
 
-	if container.runtime != nil && container.runtime.srv != nil && container.runtime.srv.IsRunning() {
+	if container.daemon != nil && container.daemon.srv != nil && container.daemon.srv.IsRunning() {
 		container.State.SetStopped(exitCode)
 
 		// FIXME: there is a race condition here which causes this to fail during the unit tests.
@@ -838,8 +478,8 @@ func (container *Container) monitor(callback execdriver.StartCallback) error {
 		container.stdin, container.stdinPipe = io.Pipe()
 	}
 
-	if container.runtime != nil && container.runtime.srv != nil {
-		container.runtime.srv.LogEvent("die", container.ID, container.runtime.repositories.ImageName(container.Image))
+	if container.daemon != nil && container.daemon.srv != nil {
+		container.daemon.srv.LogEvent("die", container.ID, container.daemon.repositories.ImageName(container.Image))
 	}
 
 	close(container.waitLock)
@@ -885,7 +525,7 @@ func (container *Container) KillSig(sig int) error {
 	if !container.State.IsRunning() {
 		return nil
 	}
-	return container.runtime.Kill(container, sig)
+	return container.daemon.Kill(container, sig)
 }
 
 func (container *Container) Kill() error {
@@ -900,9 +540,12 @@ func (container *Container) Kill() error {
 
 	// 2. Wait for the process to die, in last resort, try to kill the process directly
 	if err := container.WaitTimeout(10 * time.Second); err != nil {
-		log.Printf("Container %s failed to exit within 10 seconds of kill - trying direct SIGKILL", utils.TruncateID(container.ID))
-		if err := syscall.Kill(container.State.Pid, 9); err != nil {
-			return err
+		// Ensure that we don't kill ourselves
+		if pid := container.State.Pid; pid != 0 {
+			log.Printf("Container %s failed to exit within 10 seconds of kill - trying direct SIGKILL", utils.TruncateID(container.ID))
+			if err := syscall.Kill(pid, 9); err != nil {
+				return err
+			}
 		}
 	}
 
@@ -962,10 +605,10 @@ func (container *Container) ExportRw() (archive.Archive, error) {
 	if err := container.Mount(); err != nil {
 		return nil, err
 	}
-	if container.runtime == nil {
+	if container.daemon == nil {
 		return nil, fmt.Errorf("Can't load storage driver for unregistered container %s", container.ID)
 	}
-	archive, err := container.runtime.Diff(container)
+	archive, err := container.daemon.Diff(container)
 	if err != nil {
 		container.Unmount()
 		return nil, err
@@ -1012,22 +655,22 @@ func (container *Container) WaitTimeout(timeout time.Duration) error {
 }
 
 func (container *Container) Mount() error {
-	return container.runtime.Mount(container)
+	return container.daemon.Mount(container)
 }
 
 func (container *Container) Changes() ([]archive.Change, error) {
-	return container.runtime.Changes(container)
+	return container.daemon.Changes(container)
 }
 
 func (container *Container) GetImage() (*image.Image, error) {
-	if container.runtime == nil {
+	if container.daemon == nil {
 		return nil, fmt.Errorf("Can't get image of unregistered container")
 	}
-	return container.runtime.graph.Get(container.Image)
+	return container.daemon.graph.Get(container.Image)
 }
 
 func (container *Container) Unmount() error {
-	return container.runtime.Unmount(container)
+	return container.daemon.Unmount(container)
 }
 
 func (container *Container) logPath(name string) string {
@@ -1046,22 +689,6 @@ func (container *Container) jsonPath() string {
 	return path.Join(container.root, "config.json")
 }
 
-func (container *Container) EnvConfigPath() (string, error) {
-	p := path.Join(container.root, "config.env")
-	if _, err := os.Stat(p); err != nil {
-		if os.IsNotExist(err) {
-			f, err := os.Create(p)
-			if err != nil {
-				return "", err
-			}
-			f.Close()
-		} else {
-			return "", err
-		}
-	}
-	return p, nil
-}
-
 // This method must be exported to be used from the lxc template
 // This directory is only usable when the container is running
 func (container *Container) RootfsPath() string {
@@ -1080,7 +707,7 @@ func (container *Container) GetSize() (int64, int64) {
 	var (
 		sizeRw, sizeRootfs int64
 		err                error
-		driver             = container.runtime.driver
+		driver             = container.daemon.driver
 	)
 
 	if err := container.Mount(); err != nil {
@@ -1089,7 +716,7 @@ func (container *Container) GetSize() (int64, int64) {
 	}
 	defer container.Unmount()
 
-	if differ, ok := container.runtime.driver.(graphdriver.Differ); ok {
+	if differ, ok := container.daemon.driver.(graphdriver.Differ); ok {
 		sizeRw, err = differ.DiffSize(container.ID)
 		if err != nil {
 			utils.Errorf("Warning: driver %s couldn't return diff size of container %s: %s", driver, container.ID, err)
@@ -1182,48 +809,298 @@ func (container *Container) DisableLink(name string) {
 }
 
 func (container *Container) setupContainerDns() error {
+	if container.ResolvConfPath != "" {
+		return nil
+	}
+
 	var (
-		config  = container.hostConfig
-		runtime = container.runtime
+		config = container.hostConfig
+		daemon = container.daemon
 	)
-	resolvConf, err := utils.GetResolvConf()
+
+	if config.NetworkMode == "host" {
+		container.ResolvConfPath = "/etc/resolv.conf"
+		return nil
+	}
+
+	resolvConf, err := resolvconf.Get()
 	if err != nil {
 		return err
 	}
+
 	// If custom dns exists, then create a resolv.conf for the container
-	if len(config.Dns) > 0 || len(runtime.config.Dns) > 0 || len(config.DnsSearch) > 0 || len(runtime.config.DnsSearch) > 0 {
+	if len(config.Dns) > 0 || len(daemon.config.Dns) > 0 || len(config.DnsSearch) > 0 || len(daemon.config.DnsSearch) > 0 {
 		var (
-			dns       = utils.GetNameservers(resolvConf)
-			dnsSearch = utils.GetSearchDomains(resolvConf)
+			dns       = resolvconf.GetNameservers(resolvConf)
+			dnsSearch = resolvconf.GetSearchDomains(resolvConf)
 		)
 		if len(config.Dns) > 0 {
 			dns = config.Dns
-		} else if len(runtime.config.Dns) > 0 {
-			dns = runtime.config.Dns
+		} else if len(daemon.config.Dns) > 0 {
+			dns = daemon.config.Dns
 		}
 		if len(config.DnsSearch) > 0 {
 			dnsSearch = config.DnsSearch
-		} else if len(runtime.config.DnsSearch) > 0 {
-			dnsSearch = runtime.config.DnsSearch
+		} else if len(daemon.config.DnsSearch) > 0 {
+			dnsSearch = daemon.config.DnsSearch
 		}
 		container.ResolvConfPath = path.Join(container.root, "resolv.conf")
-		f, err := os.Create(container.ResolvConfPath)
+		return resolvconf.Build(container.ResolvConfPath, dns, dnsSearch)
+	} else {
+		container.ResolvConfPath = "/etc/resolv.conf"
+	}
+	return nil
+}
+
+func (container *Container) initializeNetworking() error {
+	var err error
+	if container.hostConfig.NetworkMode.IsHost() {
+		container.Config.Hostname, err = os.Hostname()
 		if err != nil {
 			return err
 		}
-		defer f.Close()
-		for _, dns := range dns {
-			if _, err := f.Write([]byte("nameserver " + dns + "\n")); err != nil {
-				return err
+
+		parts := strings.SplitN(container.Config.Hostname, ".", 2)
+		if len(parts) > 1 {
+			container.Config.Hostname = parts[0]
+			container.Config.Domainname = parts[1]
+		}
+		container.HostsPath = "/etc/hosts"
+
+		return container.buildHostnameFile()
+	} else if container.hostConfig.NetworkMode.IsContainer() {
+		// we need to get the hosts files from the container to join
+		nc, err := container.getNetworkedContainer()
+		if err != nil {
+			return err
+		}
+		container.HostsPath = nc.HostsPath
+		container.ResolvConfPath = nc.ResolvConfPath
+		container.Config.Hostname = nc.Config.Hostname
+		container.Config.Domainname = nc.Config.Domainname
+	} else if container.daemon.config.DisableNetwork {
+		container.Config.NetworkDisabled = true
+		return container.buildHostnameAndHostsFiles("127.0.1.1")
+	} else {
+		if err := container.allocateNetwork(); err != nil {
+			return err
+		}
+		return container.buildHostnameAndHostsFiles(container.NetworkSettings.IPAddress)
+	}
+	return nil
+}
+
+// Make sure the config is compatible with the current kernel
+func (container *Container) verifyDaemonSettings() {
+	if container.Config.Memory > 0 && !container.daemon.sysInfo.MemoryLimit {
+		log.Printf("WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.\n")
+		container.Config.Memory = 0
+	}
+	if container.Config.Memory > 0 && !container.daemon.sysInfo.SwapLimit {
+		log.Printf("WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.\n")
+		container.Config.MemorySwap = -1
+	}
+	if container.daemon.sysInfo.IPv4ForwardingDisabled {
+		log.Printf("WARNING: IPv4 forwarding is disabled. Networking will not work")
+	}
+}
+
+func (container *Container) setupLinkedContainers() ([]string, error) {
+	var (
+		env    []string
+		daemon = container.daemon
+	)
+	children, err := daemon.Children(container.Name)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(children) > 0 {
+		container.activeLinks = make(map[string]*links.Link, len(children))
+
+		// If we encounter an error make sure that we rollback any network
+		// config and ip table changes
+		rollback := func() {
+			for _, link := range container.activeLinks {
+				link.Disable()
+			}
+			container.activeLinks = nil
+		}
+
+		for linkAlias, child := range children {
+			if !child.State.IsRunning() {
+				return nil, fmt.Errorf("Cannot link to a non running container: %s AS %s", child.Name, linkAlias)
+			}
+
+			link, err := links.NewLink(
+				container.NetworkSettings.IPAddress,
+				child.NetworkSettings.IPAddress,
+				linkAlias,
+				child.Config.Env,
+				child.Config.ExposedPorts,
+				daemon.eng)
+
+			if err != nil {
+				rollback()
+				return nil, err
+			}
+
+			container.activeLinks[link.Alias()] = link
+			if err := link.Enable(); err != nil {
+				rollback()
+				return nil, err
+			}
+
+			for _, envVar := range link.ToEnv() {
+				env = append(env, envVar)
 			}
 		}
-		if len(dnsSearch) > 0 {
-			if _, err := f.Write([]byte("search " + strings.Join(dnsSearch, " ") + "\n")); err != nil {
+	}
+	return env, nil
+}
+
+func (container *Container) createDaemonEnvironment(linkedEnv []string) []string {
+	// Setup environment
+	env := []string{
+		"HOME=/",
+		"PATH=" + DefaultPathEnv,
+		"HOSTNAME=" + container.Config.Hostname,
+	}
+	if container.Config.Tty {
+		env = append(env, "TERM=xterm")
+	}
+	env = append(env, linkedEnv...)
+	// because the env on the container can override certain default values
+	// we need to replace the 'env' keys where they match and append anything
+	// else.
+	env = utils.ReplaceOrAppendEnvValues(env, container.Config.Env)
+
+	return env
+}
+
+func (container *Container) setupWorkingDirectory() error {
+	if container.Config.WorkingDir != "" {
+		container.Config.WorkingDir = path.Clean(container.Config.WorkingDir)
+
+		pthInfo, err := os.Stat(path.Join(container.basefs, container.Config.WorkingDir))
+		if err != nil {
+			if !os.IsNotExist(err) {
+				return err
+			}
+			if err := os.MkdirAll(path.Join(container.basefs, container.Config.WorkingDir), 0755); err != nil {
 				return err
 			}
 		}
-	} else {
-		container.ResolvConfPath = "/etc/resolv.conf"
+		if pthInfo != nil && !pthInfo.IsDir() {
+			return fmt.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir)
+		}
+	}
+	return nil
+}
+
+func (container *Container) startLoggingToDisk() error {
+	// Setup logging of stdout and stderr to disk
+	if err := container.daemon.LogToDisk(container.stdout, container.logPath("json"), "stdout"); err != nil {
+		return err
+	}
+	if err := container.daemon.LogToDisk(container.stderr, container.logPath("json"), "stderr"); err != nil {
+		return err
 	}
 	return nil
 }
+
+func (container *Container) waitForStart() error {
+	callbackLock := make(chan struct{})
+	callback := func(command *execdriver.Command) {
+		container.State.SetRunning(command.Pid())
+		if command.Tty {
+			// The callback is called after the process Start()
+			// so we are in the parent process. In TTY mode, stdin/out/err is the PtySlace
+			// which we close here.
+			if c, ok := command.Stdout.(io.Closer); ok {
+				c.Close()
+			}
+		}
+		if err := container.ToDisk(); err != nil {
+			utils.Debugf("%s", err)
+		}
+		close(callbackLock)
+	}
+
+	// We use a callback here instead of a goroutine and an chan for
+	// syncronization purposes
+	cErr := utils.Go(func() error { return container.monitor(callback) })
+
+	// Start should not return until the process is actually running
+	select {
+	case <-callbackLock:
+	case err := <-cErr:
+		return err
+	}
+	return nil
+}
+
+func (container *Container) allocatePort(eng *engine.Engine, port nat.Port, bindings nat.PortMap) error {
+	binding := bindings[port]
+	if container.hostConfig.PublishAllPorts && len(binding) == 0 {
+		binding = append(binding, nat.PortBinding{})
+	}
+
+	for i := 0; i < len(binding); i++ {
+		b := binding[i]
+
+		job := eng.Job("allocate_port", container.ID)
+		job.Setenv("HostIP", b.HostIp)
+		job.Setenv("HostPort", b.HostPort)
+		job.Setenv("Proto", port.Proto())
+		job.Setenv("ContainerPort", port.Port())
+
+		portEnv, err := job.Stdout.AddEnv()
+		if err != nil {
+			return err
+		}
+		if err := job.Run(); err != nil {
+			eng.Job("release_interface", container.ID).Run()
+			return err
+		}
+		b.HostIp = portEnv.Get("HostIP")
+		b.HostPort = portEnv.Get("HostPort")
+
+		binding[i] = b
+	}
+	bindings[port] = binding
+	return nil
+}
+
+func (container *Container) GetProcessLabel() string {
+	// even if we have a process label return "" if we are running
+	// in privileged mode
+	if container.hostConfig.Privileged {
+		return ""
+	}
+	return container.ProcessLabel
+}
+
+func (container *Container) GetMountLabel() string {
+	if container.hostConfig.Privileged {
+		return ""
+	}
+	return container.MountLabel
+}
+
+func (container *Container) getNetworkedContainer() (*Container, error) {
+	parts := strings.SplitN(string(container.hostConfig.NetworkMode), ":", 2)
+	switch parts[0] {
+	case "container":
+		nc := container.daemon.Get(parts[1])
+		if nc == nil {
+			return nil, fmt.Errorf("no such container to join network: %s", parts[1])
+		}
+		if !nc.State.IsRunning() {
+			return nil, fmt.Errorf("cannot join network of a non running container: %s", parts[1])
+		}
+		return nc, nil
+	default:
+		return nil, fmt.Errorf("network mode not set to container")
+	}
+}

+ 1 - 1
runtime/container_unit_test.go → daemon/container_unit_test.go

@@ -1,4 +1,4 @@
-package runtime
+package daemon
 
 import (
 	"github.com/dotcloud/docker/nat"

+ 215 - 214
runtime/runtime.go → daemon/daemon.go

@@ -1,36 +1,39 @@
-package runtime
+package daemon
 
 import (
 	"container/list"
 	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+	"path"
+	"regexp"
+	"strings"
+	"sync"
+	"time"
+
 	"github.com/dotcloud/docker/archive"
+	"github.com/dotcloud/docker/daemon/execdriver"
+	"github.com/dotcloud/docker/daemon/execdriver/execdrivers"
+	"github.com/dotcloud/docker/daemon/execdriver/lxc"
+	"github.com/dotcloud/docker/daemon/graphdriver"
+	_ "github.com/dotcloud/docker/daemon/graphdriver/vfs"
+	_ "github.com/dotcloud/docker/daemon/networkdriver/bridge"
+	"github.com/dotcloud/docker/daemon/networkdriver/portallocator"
 	"github.com/dotcloud/docker/daemonconfig"
 	"github.com/dotcloud/docker/dockerversion"
 	"github.com/dotcloud/docker/engine"
 	"github.com/dotcloud/docker/graph"
 	"github.com/dotcloud/docker/image"
 	"github.com/dotcloud/docker/pkg/graphdb"
+	"github.com/dotcloud/docker/pkg/label"
 	"github.com/dotcloud/docker/pkg/mount"
+	"github.com/dotcloud/docker/pkg/networkfs/resolvconf"
 	"github.com/dotcloud/docker/pkg/selinux"
 	"github.com/dotcloud/docker/pkg/sysinfo"
 	"github.com/dotcloud/docker/runconfig"
-	"github.com/dotcloud/docker/runtime/execdriver"
-	"github.com/dotcloud/docker/runtime/execdriver/execdrivers"
-	"github.com/dotcloud/docker/runtime/execdriver/lxc"
-	"github.com/dotcloud/docker/runtime/graphdriver"
-	_ "github.com/dotcloud/docker/runtime/graphdriver/vfs"
-	_ "github.com/dotcloud/docker/runtime/networkdriver/bridge"
-	"github.com/dotcloud/docker/runtime/networkdriver/portallocator"
 	"github.com/dotcloud/docker/utils"
-	"io"
-	"io/ioutil"
-	"log"
-	"os"
-	"path"
-	"regexp"
-	"strings"
-	"sync"
-	"time"
 )
 
 // Set the max depth to the aufs default that most
@@ -44,7 +47,7 @@ var (
 	validContainerNamePattern = regexp.MustCompile(`^/?` + validContainerNameChars + `+$`)
 )
 
-type Runtime struct {
+type Daemon struct {
 	repository     string
 	sysInitPath    string
 	containers     *list.List
@@ -76,17 +79,17 @@ func remountPrivate(mountPoint string) error {
 	return mount.ForceMount("", mountPoint, "none", "private")
 }
 
-// List returns an array of all containers registered in the runtime.
-func (runtime *Runtime) List() []*Container {
+// List returns an array of all containers registered in the daemon.
+func (daemon *Daemon) List() []*Container {
 	containers := new(History)
-	for e := runtime.containers.Front(); e != nil; e = e.Next() {
+	for e := daemon.containers.Front(); e != nil; e = e.Next() {
 		containers.Add(e.Value.(*Container))
 	}
 	return *containers
 }
 
-func (runtime *Runtime) getContainerElement(id string) *list.Element {
-	for e := runtime.containers.Front(); e != nil; e = e.Next() {
+func (daemon *Daemon) getContainerElement(id string) *list.Element {
+	for e := daemon.containers.Front(); e != nil; e = e.Next() {
 		container := e.Value.(*Container)
 		if container.ID == id {
 			return e
@@ -97,17 +100,17 @@ func (runtime *Runtime) getContainerElement(id string) *list.Element {
 
 // Get looks for a container by the specified ID or name, and returns it.
 // If the container is not found, or if an error occurs, nil is returned.
-func (runtime *Runtime) Get(name string) *Container {
-	if c, _ := runtime.GetByName(name); c != nil {
+func (daemon *Daemon) Get(name string) *Container {
+	if c, _ := daemon.GetByName(name); c != nil {
 		return c
 	}
 
-	id, err := runtime.idIndex.Get(name)
+	id, err := daemon.idIndex.Get(name)
 	if err != nil {
 		return nil
 	}
 
-	e := runtime.getContainerElement(id)
+	e := daemon.getContainerElement(id)
 	if e == nil {
 		return nil
 	}
@@ -116,43 +119,40 @@ func (runtime *Runtime) Get(name string) *Container {
 
 // Exists returns a true if a container of the specified ID or name exists,
 // false otherwise.
-func (runtime *Runtime) Exists(id string) bool {
-	return runtime.Get(id) != nil
+func (daemon *Daemon) Exists(id string) bool {
+	return daemon.Get(id) != nil
 }
 
-func (runtime *Runtime) containerRoot(id string) string {
-	return path.Join(runtime.repository, id)
+func (daemon *Daemon) containerRoot(id string) string {
+	return path.Join(daemon.repository, id)
 }
 
 // Load reads the contents of a container from disk
 // This is typically done at startup.
-func (runtime *Runtime) load(id string) (*Container, error) {
-	container := &Container{root: runtime.containerRoot(id)}
+func (daemon *Daemon) load(id string) (*Container, error) {
+	container := &Container{root: daemon.containerRoot(id)}
 	if err := container.FromDisk(); err != nil {
 		return nil, err
 	}
 	if container.ID != id {
 		return container, fmt.Errorf("Container %s is stored at %s", container.ID, id)
 	}
-	if container.State.IsRunning() {
-		container.State.SetGhost(true)
-	}
 	return container, nil
 }
 
-// Register makes a container object usable by the runtime as <container.ID>
-func (runtime *Runtime) Register(container *Container) error {
-	if container.runtime != nil || runtime.Exists(container.ID) {
+// Register makes a container object usable by the daemon as <container.ID>
+func (daemon *Daemon) Register(container *Container) error {
+	if container.daemon != nil || daemon.Exists(container.ID) {
 		return fmt.Errorf("Container is already loaded")
 	}
 	if err := validateID(container.ID); err != nil {
 		return err
 	}
-	if err := runtime.ensureName(container); err != nil {
+	if err := daemon.ensureName(container); err != nil {
 		return err
 	}
 
-	container.runtime = runtime
+	container.daemon = daemon
 
 	// Attach to stdout and stderr
 	container.stderr = utils.NewWriteBroadcaster()
@@ -164,55 +164,50 @@ func (runtime *Runtime) Register(container *Container) error {
 		container.stdinPipe = utils.NopWriteCloser(ioutil.Discard) // Silently drop stdin
 	}
 	// done
-	runtime.containers.PushBack(container)
-	runtime.idIndex.Add(container.ID)
+	daemon.containers.PushBack(container)
+	daemon.idIndex.Add(container.ID)
 
 	// FIXME: if the container is supposed to be running but is not, auto restart it?
 	//        if so, then we need to restart monitor and init a new lock
 	// If the container is supposed to be running, make sure of it
 	if container.State.IsRunning() {
-		if container.State.IsGhost() {
-			utils.Debugf("killing ghost %s", container.ID)
+		utils.Debugf("killing old running container %s", container.ID)
 
-			existingPid := container.State.Pid
-			container.State.SetGhost(false)
-			container.State.SetStopped(0)
+		existingPid := container.State.Pid
+		container.State.SetStopped(0)
 
-			// We only have to handle this for lxc because the other drivers will ensure that
-			// no ghost processes are left when docker dies
-			if container.ExecDriver == "" || strings.Contains(container.ExecDriver, "lxc") {
-				lxc.KillLxc(container.ID, 9)
-			} else {
-				// use the current driver and ensure that the container is dead x.x
-				cmd := &execdriver.Command{
-					ID: container.ID,
-				}
-				var err error
-				cmd.Process, err = os.FindProcess(existingPid)
-				if err != nil {
-					utils.Debugf("cannot find existing process for %d", existingPid)
-				}
-				runtime.execDriver.Terminate(cmd)
-			}
-			if err := container.Unmount(); err != nil {
-				utils.Debugf("ghost unmount error %s", err)
+		// We only have to handle this for lxc because the other drivers will ensure that
+		// no processes are left when docker dies
+		if container.ExecDriver == "" || strings.Contains(container.ExecDriver, "lxc") {
+			lxc.KillLxc(container.ID, 9)
+		} else {
+			// use the current driver and ensure that the container is dead x.x
+			cmd := &execdriver.Command{
+				ID: container.ID,
 			}
-			if err := container.ToDisk(); err != nil {
-				utils.Debugf("saving ghost state to disk %s", err)
+			var err error
+			cmd.Process, err = os.FindProcess(existingPid)
+			if err != nil {
+				utils.Debugf("cannot find existing process for %d", existingPid)
 			}
+			daemon.execDriver.Terminate(cmd)
+		}
+		if err := container.Unmount(); err != nil {
+			utils.Debugf("unmount error %s", err)
+		}
+		if err := container.ToDisk(); err != nil {
+			utils.Debugf("saving stopped state to disk %s", err)
 		}
 
-		info := runtime.execDriver.Info(container.ID)
+		info := daemon.execDriver.Info(container.ID)
 		if !info.IsRunning() {
 			utils.Debugf("Container %s was supposed to be running but is not.", container.ID)
-			if runtime.config.AutoRestart {
+			if daemon.config.AutoRestart {
 				utils.Debugf("Restarting")
 				if err := container.Unmount(); err != nil {
 					utils.Debugf("restart unmount error %s", err)
 				}
 
-				container.State.SetGhost(false)
-				container.State.SetStopped(0)
 				if err := container.Start(); err != nil {
 					return err
 				}
@@ -234,9 +229,9 @@ func (runtime *Runtime) Register(container *Container) error {
 	return nil
 }
 
-func (runtime *Runtime) ensureName(container *Container) error {
+func (daemon *Daemon) ensureName(container *Container) error {
 	if container.Name == "" {
-		name, err := generateRandomName(runtime)
+		name, err := generateRandomName(daemon)
 		if err != nil {
 			name = utils.TruncateID(container.ID)
 		}
@@ -245,8 +240,8 @@ func (runtime *Runtime) ensureName(container *Container) error {
 		if err := container.ToDisk(); err != nil {
 			utils.Debugf("Error saving container name %s", err)
 		}
-		if !runtime.containerGraph.Exists(name) {
-			if _, err := runtime.containerGraph.Set(name, container.ID); err != nil {
+		if !daemon.containerGraph.Exists(name) {
+			if _, err := daemon.containerGraph.Set(name, container.ID); err != nil {
 				utils.Debugf("Setting default id - %s", err)
 			}
 		}
@@ -254,7 +249,7 @@ func (runtime *Runtime) ensureName(container *Container) error {
 	return nil
 }
 
-func (runtime *Runtime) LogToDisk(src *utils.WriteBroadcaster, dst, stream string) error {
+func (daemon *Daemon) LogToDisk(src *utils.WriteBroadcaster, dst, stream string) error {
 	log, err := os.OpenFile(dst, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0600)
 	if err != nil {
 		return err
@@ -263,13 +258,13 @@ func (runtime *Runtime) LogToDisk(src *utils.WriteBroadcaster, dst, stream strin
 	return nil
 }
 
-// Destroy unregisters a container from the runtime and cleanly removes its contents from the filesystem.
-func (runtime *Runtime) Destroy(container *Container) error {
+// Destroy unregisters a container from the daemon and cleanly removes its contents from the filesystem.
+func (daemon *Daemon) Destroy(container *Container) error {
 	if container == nil {
 		return fmt.Errorf("The given container is <nil>")
 	}
 
-	element := runtime.getContainerElement(container.ID)
+	element := daemon.getContainerElement(container.ID)
 	if element == nil {
 		return fmt.Errorf("Container %v not found - maybe it was already destroyed?", container.ID)
 	}
@@ -278,42 +273,45 @@ func (runtime *Runtime) Destroy(container *Container) error {
 		return err
 	}
 
-	if err := runtime.driver.Remove(container.ID); err != nil {
-		return fmt.Errorf("Driver %s failed to remove root filesystem %s: %s", runtime.driver, container.ID, err)
+	// Deregister the container before removing its directory, to avoid race conditions
+	daemon.idIndex.Delete(container.ID)
+	daemon.containers.Remove(element)
+
+	if err := daemon.driver.Remove(container.ID); err != nil {
+		return fmt.Errorf("Driver %s failed to remove root filesystem %s: %s", daemon.driver, container.ID, err)
 	}
 
 	initID := fmt.Sprintf("%s-init", container.ID)
-	if err := runtime.driver.Remove(initID); err != nil {
-		return fmt.Errorf("Driver %s failed to remove init filesystem %s: %s", runtime.driver, initID, err)
+	if err := daemon.driver.Remove(initID); err != nil {
+		return fmt.Errorf("Driver %s failed to remove init filesystem %s: %s", daemon.driver, initID, err)
 	}
 
-	if _, err := runtime.containerGraph.Purge(container.ID); err != nil {
+	if _, err := daemon.containerGraph.Purge(container.ID); err != nil {
 		utils.Debugf("Unable to remove container from link graph: %s", err)
 	}
 
-	// Deregister the container before removing its directory, to avoid race conditions
-	runtime.idIndex.Delete(container.ID)
-	runtime.containers.Remove(element)
 	if err := os.RemoveAll(container.root); err != nil {
 		return fmt.Errorf("Unable to remove filesystem for %v: %v", container.ID, err)
 	}
+	selinux.FreeLxcContexts(container.ProcessLabel)
+
 	return nil
 }
 
-func (runtime *Runtime) restore() error {
+func (daemon *Daemon) restore() error {
 	if os.Getenv("DEBUG") == "" && os.Getenv("TEST") == "" {
 		fmt.Printf("Loading containers: ")
 	}
-	dir, err := ioutil.ReadDir(runtime.repository)
+	dir, err := ioutil.ReadDir(daemon.repository)
 	if err != nil {
 		return err
 	}
 	containers := make(map[string]*Container)
-	currentDriver := runtime.driver.String()
+	currentDriver := daemon.driver.String()
 
 	for _, v := range dir {
 		id := v.Name()
-		container, err := runtime.load(id)
+		container, err := daemon.load(id)
 		if os.Getenv("DEBUG") == "" && os.Getenv("TEST") == "" {
 			fmt.Print(".")
 		}
@@ -332,12 +330,12 @@ func (runtime *Runtime) restore() error {
 	}
 
 	register := func(container *Container) {
-		if err := runtime.Register(container); err != nil {
+		if err := daemon.Register(container); err != nil {
 			utils.Debugf("Failed to register container %s: %s", container.ID, err)
 		}
 	}
 
-	if entities := runtime.containerGraph.List("/", -1); entities != nil {
+	if entities := daemon.containerGraph.List("/", -1); entities != nil {
 		for _, p := range entities.Paths() {
 			if os.Getenv("DEBUG") == "" && os.Getenv("TEST") == "" {
 				fmt.Print(".")
@@ -353,12 +351,12 @@ func (runtime *Runtime) restore() error {
 	// Any containers that are left over do not exist in the graph
 	for _, container := range containers {
 		// Try to set the default name for a container if it exists prior to links
-		container.Name, err = generateRandomName(runtime)
+		container.Name, err = generateRandomName(daemon)
 		if err != nil {
 			container.Name = utils.TruncateID(container.ID)
 		}
 
-		if _, err := runtime.containerGraph.Set(container.Name, container.ID); err != nil {
+		if _, err := daemon.containerGraph.Set(container.Name, container.ID); err != nil {
 			utils.Debugf("Setting default id - %s", err)
 		}
 		register(container)
@@ -372,38 +370,38 @@ func (runtime *Runtime) restore() error {
 }
 
 // Create creates a new container from the given configuration with a given name.
-func (runtime *Runtime) Create(config *runconfig.Config, name string) (*Container, []string, error) {
+func (daemon *Daemon) Create(config *runconfig.Config, name string) (*Container, []string, error) {
 	var (
 		container *Container
 		warnings  []string
 	)
 
-	img, err := runtime.repositories.LookupImage(config.Image)
+	img, err := daemon.repositories.LookupImage(config.Image)
 	if err != nil {
 		return nil, nil, err
 	}
-	if err := runtime.checkImageDepth(img); err != nil {
+	if err := daemon.checkImageDepth(img); err != nil {
 		return nil, nil, err
 	}
-	if warnings, err = runtime.mergeAndVerifyConfig(config, img); err != nil {
+	if warnings, err = daemon.mergeAndVerifyConfig(config, img); err != nil {
 		return nil, nil, err
 	}
-	if container, err = runtime.newContainer(name, config, img); err != nil {
+	if container, err = daemon.newContainer(name, config, img); err != nil {
 		return nil, nil, err
 	}
-	if err := runtime.createRootfs(container, img); err != nil {
+	if err := daemon.createRootfs(container, img); err != nil {
 		return nil, nil, err
 	}
 	if err := container.ToDisk(); err != nil {
 		return nil, nil, err
 	}
-	if err := runtime.Register(container); err != nil {
+	if err := daemon.Register(container); err != nil {
 		return nil, nil, err
 	}
 	return container, warnings, nil
 }
 
-func (runtime *Runtime) checkImageDepth(img *image.Image) error {
+func (daemon *Daemon) checkImageDepth(img *image.Image) error {
 	// We add 2 layers to the depth because the container's rw and
 	// init layer add to the restriction
 	depth, err := img.Depth()
@@ -416,7 +414,7 @@ func (runtime *Runtime) checkImageDepth(img *image.Image) error {
 	return nil
 }
 
-func (runtime *Runtime) checkDeprecatedExpose(config *runconfig.Config) bool {
+func (daemon *Daemon) checkDeprecatedExpose(config *runconfig.Config) bool {
 	if config != nil {
 		if config.PortSpecs != nil {
 			for _, p := range config.PortSpecs {
@@ -429,9 +427,9 @@ func (runtime *Runtime) checkDeprecatedExpose(config *runconfig.Config) bool {
 	return false
 }
 
-func (runtime *Runtime) mergeAndVerifyConfig(config *runconfig.Config, img *image.Image) ([]string, error) {
+func (daemon *Daemon) mergeAndVerifyConfig(config *runconfig.Config, img *image.Image) ([]string, error) {
 	warnings := []string{}
-	if runtime.checkDeprecatedExpose(img.Config) || runtime.checkDeprecatedExpose(config) {
+	if daemon.checkDeprecatedExpose(img.Config) || daemon.checkDeprecatedExpose(config) {
 		warnings = append(warnings, "The mapping to public ports on your host via Dockerfile EXPOSE (host:port:port) has been deprecated. Use -p to publish the ports.")
 	}
 	if img.Config != nil {
@@ -445,14 +443,14 @@ func (runtime *Runtime) mergeAndVerifyConfig(config *runconfig.Config, img *imag
 	return warnings, nil
 }
 
-func (runtime *Runtime) generateIdAndName(name string) (string, string, error) {
+func (daemon *Daemon) generateIdAndName(name string) (string, string, error) {
 	var (
 		err error
 		id  = utils.GenerateRandomID()
 	)
 
 	if name == "" {
-		name, err = generateRandomName(runtime)
+		name, err = generateRandomName(daemon)
 		if err != nil {
 			name = utils.TruncateID(id)
 		}
@@ -465,19 +463,19 @@ func (runtime *Runtime) generateIdAndName(name string) (string, string, error) {
 		name = "/" + name
 	}
 	// Set the enitity in the graph using the default name specified
-	if _, err := runtime.containerGraph.Set(name, id); err != nil {
+	if _, err := daemon.containerGraph.Set(name, id); err != nil {
 		if !graphdb.IsNonUniqueNameError(err) {
 			return "", "", err
 		}
 
-		conflictingContainer, err := runtime.GetByName(name)
+		conflictingContainer, err := daemon.GetByName(name)
 		if err != nil {
 			if strings.Contains(err.Error(), "Could not find entity") {
 				return "", "", err
 			}
 
 			// Remove name and continue starting the container
-			if err := runtime.containerGraph.Delete(name); err != nil {
+			if err := daemon.containerGraph.Delete(name); err != nil {
 				return "", "", err
 			}
 		} else {
@@ -490,7 +488,7 @@ func (runtime *Runtime) generateIdAndName(name string) (string, string, error) {
 	return id, name, nil
 }
 
-func (runtime *Runtime) generateHostname(id string, config *runconfig.Config) {
+func (daemon *Daemon) generateHostname(id string, config *runconfig.Config) {
 	// Generate default hostname
 	// FIXME: the lxc template no longer needs to set a default hostname
 	if config.Hostname == "" {
@@ -498,7 +496,7 @@ func (runtime *Runtime) generateHostname(id string, config *runconfig.Config) {
 	}
 }
 
-func (runtime *Runtime) getEntrypointAndArgs(config *runconfig.Config) (string, []string) {
+func (daemon *Daemon) getEntrypointAndArgs(config *runconfig.Config) (string, []string) {
 	var (
 		entrypoint string
 		args       []string
@@ -513,18 +511,18 @@ func (runtime *Runtime) getEntrypointAndArgs(config *runconfig.Config) (string,
 	return entrypoint, args
 }
 
-func (runtime *Runtime) newContainer(name string, config *runconfig.Config, img *image.Image) (*Container, error) {
+func (daemon *Daemon) newContainer(name string, config *runconfig.Config, img *image.Image) (*Container, error) {
 	var (
 		id  string
 		err error
 	)
-	id, name, err = runtime.generateIdAndName(name)
+	id, name, err = daemon.generateIdAndName(name)
 	if err != nil {
 		return nil, err
 	}
 
-	runtime.generateHostname(id, config)
-	entrypoint, args := runtime.getEntrypointAndArgs(config)
+	daemon.generateHostname(id, config)
+	entrypoint, args := daemon.getEntrypointAndArgs(config)
 
 	container := &Container{
 		// FIXME: we should generate the ID here instead of receiving it as an argument
@@ -537,34 +535,38 @@ func (runtime *Runtime) newContainer(name string, config *runconfig.Config, img
 		Image:           img.ID, // Always use the resolved image id
 		NetworkSettings: &NetworkSettings{},
 		Name:            name,
-		Driver:          runtime.driver.String(),
-		ExecDriver:      runtime.execDriver.Name(),
+		Driver:          daemon.driver.String(),
+		ExecDriver:      daemon.execDriver.Name(),
+	}
+	container.root = daemon.containerRoot(container.ID)
+
+	if container.ProcessLabel, container.MountLabel, err = label.GenLabels(""); err != nil {
+		return nil, err
 	}
-	container.root = runtime.containerRoot(container.ID)
 	return container, nil
 }
 
-func (runtime *Runtime) createRootfs(container *Container, img *image.Image) error {
+func (daemon *Daemon) createRootfs(container *Container, img *image.Image) error {
 	// Step 1: create the container directory.
 	// This doubles as a barrier to avoid race conditions.
 	if err := os.Mkdir(container.root, 0700); err != nil {
 		return err
 	}
 	initID := fmt.Sprintf("%s-init", container.ID)
-	if err := runtime.driver.Create(initID, img.ID, ""); err != nil {
+	if err := daemon.driver.Create(initID, img.ID); err != nil {
 		return err
 	}
-	initPath, err := runtime.driver.Get(initID)
+	initPath, err := daemon.driver.Get(initID, "")
 	if err != nil {
 		return err
 	}
-	defer runtime.driver.Put(initID)
+	defer daemon.driver.Put(initID)
 
 	if err := graph.SetupInitLayer(initPath); err != nil {
 		return err
 	}
 
-	if err := runtime.driver.Create(container.ID, initID, ""); err != nil {
+	if err := daemon.driver.Create(container.ID, initID); err != nil {
 		return err
 	}
 	return nil
@@ -572,7 +574,7 @@ func (runtime *Runtime) createRootfs(container *Container, img *image.Image) err
 
 // Commit creates a new filesystem image from the current state of a container.
 // The image can optionally be tagged into a repository
-func (runtime *Runtime) Commit(container *Container, repository, tag, comment, author string, config *runconfig.Config) (*image.Image, error) {
+func (daemon *Daemon) Commit(container *Container, repository, tag, comment, author string, config *runconfig.Config) (*image.Image, error) {
 	// FIXME: freeze the container before copying it to avoid data corruption?
 	if err := container.Mount(); err != nil {
 		return nil, err
@@ -595,13 +597,13 @@ func (runtime *Runtime) Commit(container *Container, repository, tag, comment, a
 		containerImage = container.Image
 		containerConfig = container.Config
 	}
-	img, err := runtime.graph.Create(rwTar, containerID, containerImage, comment, author, containerConfig, config)
+	img, err := daemon.graph.Create(rwTar, containerID, containerImage, comment, author, containerConfig, config)
 	if err != nil {
 		return nil, err
 	}
 	// Register the image if needed
 	if repository != "" {
-		if err := runtime.repositories.Set(repository, tag, img.ID, true); err != nil {
+		if err := daemon.repositories.Set(repository, tag, img.ID, true); err != nil {
 			return img, err
 		}
 	}
@@ -618,31 +620,31 @@ func GetFullContainerName(name string) (string, error) {
 	return name, nil
 }
 
-func (runtime *Runtime) GetByName(name string) (*Container, error) {
+func (daemon *Daemon) GetByName(name string) (*Container, error) {
 	fullName, err := GetFullContainerName(name)
 	if err != nil {
 		return nil, err
 	}
-	entity := runtime.containerGraph.Get(fullName)
+	entity := daemon.containerGraph.Get(fullName)
 	if entity == nil {
 		return nil, fmt.Errorf("Could not find entity for %s", name)
 	}
-	e := runtime.getContainerElement(entity.ID())
+	e := daemon.getContainerElement(entity.ID())
 	if e == nil {
 		return nil, fmt.Errorf("Could not find container for entity id %s", entity.ID())
 	}
 	return e.Value.(*Container), nil
 }
 
-func (runtime *Runtime) Children(name string) (map[string]*Container, error) {
+func (daemon *Daemon) Children(name string) (map[string]*Container, error) {
 	name, err := GetFullContainerName(name)
 	if err != nil {
 		return nil, err
 	}
 	children := make(map[string]*Container)
 
-	err = runtime.containerGraph.Walk(name, func(p string, e *graphdb.Entity) error {
-		c := runtime.Get(e.ID())
+	err = daemon.containerGraph.Walk(name, func(p string, e *graphdb.Entity) error {
+		c := daemon.Get(e.ID())
 		if c == nil {
 			return fmt.Errorf("Could not get container for name %s and id %s", e.ID(), p)
 		}
@@ -656,29 +658,28 @@ func (runtime *Runtime) Children(name string) (map[string]*Container, error) {
 	return children, nil
 }
 
-func (runtime *Runtime) RegisterLink(parent, child *Container, alias string) error {
+func (daemon *Daemon) RegisterLink(parent, child *Container, alias string) error {
 	fullName := path.Join(parent.Name, alias)
-	if !runtime.containerGraph.Exists(fullName) {
-		_, err := runtime.containerGraph.Set(fullName, child.ID)
+	if !daemon.containerGraph.Exists(fullName) {
+		_, err := daemon.containerGraph.Set(fullName, child.ID)
 		return err
 	}
 	return nil
 }
 
 // FIXME: harmonize with NewGraph()
-func NewRuntime(config *daemonconfig.Config, eng *engine.Engine) (*Runtime, error) {
-	runtime, err := NewRuntimeFromDirectory(config, eng)
+func NewDaemon(config *daemonconfig.Config, eng *engine.Engine) (*Daemon, error) {
+	daemon, err := NewDaemonFromDirectory(config, eng)
 	if err != nil {
 		return nil, err
 	}
-	return runtime, nil
+	return daemon, nil
 }
 
-func NewRuntimeFromDirectory(config *daemonconfig.Config, eng *engine.Engine) (*Runtime, error) {
+func NewDaemonFromDirectory(config *daemonconfig.Config, eng *engine.Engine) (*Daemon, error) {
 	if !config.EnableSelinuxSupport {
 		selinux.SetDisabled()
 	}
-
 	// Set the default driver
 	graphdriver.DefaultDriver = config.GraphDriver
 
@@ -693,9 +694,9 @@ func NewRuntimeFromDirectory(config *daemonconfig.Config, eng *engine.Engine) (*
 		return nil, err
 	}
 
-	runtimeRepo := path.Join(config.Root, "containers")
+	daemonRepo := path.Join(config.Root, "containers")
 
-	if err := os.MkdirAll(runtimeRepo, 0700); err != nil && !os.IsExist(err) {
+	if err := os.MkdirAll(daemonRepo, 0700); err != nil && !os.IsExist(err) {
 		return nil, err
 	}
 
@@ -774,12 +775,12 @@ func NewRuntimeFromDirectory(config *daemonconfig.Config, eng *engine.Engine) (*
 		return nil, err
 	}
 
-	runtime := &Runtime{
-		repository:     runtimeRepo,
+	daemon := &Daemon{
+		repository:     daemonRepo,
 		containers:     list.New(),
 		graph:          g,
 		repositories:   repositories,
-		idIndex:        utils.NewTruncIndex(),
+		idIndex:        utils.NewTruncIndex([]string{}),
 		sysInfo:        sysInfo,
 		volumes:        volumes,
 		config:         config,
@@ -790,19 +791,19 @@ func NewRuntimeFromDirectory(config *daemonconfig.Config, eng *engine.Engine) (*
 		eng:            eng,
 	}
 
-	if err := runtime.checkLocaldns(); err != nil {
+	if err := daemon.checkLocaldns(); err != nil {
 		return nil, err
 	}
-	if err := runtime.restore(); err != nil {
+	if err := daemon.restore(); err != nil {
 		return nil, err
 	}
-	return runtime, nil
+	return daemon, nil
 }
 
-func (runtime *Runtime) shutdown() error {
+func (daemon *Daemon) shutdown() error {
 	group := sync.WaitGroup{}
 	utils.Debugf("starting clean shutdown of all containers...")
-	for _, container := range runtime.List() {
+	for _, container := range daemon.List() {
 		c := container
 		if c.State.IsRunning() {
 			utils.Debugf("stopping %s", c.ID)
@@ -823,22 +824,22 @@ func (runtime *Runtime) shutdown() error {
 	return nil
 }
 
-func (runtime *Runtime) Close() error {
+func (daemon *Daemon) Close() error {
 	errorsStrings := []string{}
-	if err := runtime.shutdown(); err != nil {
-		utils.Errorf("runtime.shutdown(): %s", err)
+	if err := daemon.shutdown(); err != nil {
+		utils.Errorf("daemon.shutdown(): %s", err)
 		errorsStrings = append(errorsStrings, err.Error())
 	}
 	if err := portallocator.ReleaseAll(); err != nil {
 		utils.Errorf("portallocator.ReleaseAll(): %s", err)
 		errorsStrings = append(errorsStrings, err.Error())
 	}
-	if err := runtime.driver.Cleanup(); err != nil {
-		utils.Errorf("runtime.driver.Cleanup(): %s", err.Error())
+	if err := daemon.driver.Cleanup(); err != nil {
+		utils.Errorf("daemon.driver.Cleanup(): %s", err.Error())
 		errorsStrings = append(errorsStrings, err.Error())
 	}
-	if err := runtime.containerGraph.Close(); err != nil {
-		utils.Errorf("runtime.containerGraph.Close(): %s", err.Error())
+	if err := daemon.containerGraph.Close(); err != nil {
+		utils.Errorf("daemon.containerGraph.Close(): %s", err.Error())
 		errorsStrings = append(errorsStrings, err.Error())
 	}
 	if len(errorsStrings) > 0 {
@@ -847,55 +848,55 @@ func (runtime *Runtime) Close() error {
 	return nil
 }
 
-func (runtime *Runtime) Mount(container *Container) error {
-	dir, err := runtime.driver.Get(container.ID)
+func (daemon *Daemon) Mount(container *Container) error {
+	dir, err := daemon.driver.Get(container.ID, container.GetMountLabel())
 	if err != nil {
-		return fmt.Errorf("Error getting container %s from driver %s: %s", container.ID, runtime.driver, err)
+		return fmt.Errorf("Error getting container %s from driver %s: %s", container.ID, daemon.driver, err)
 	}
 	if container.basefs == "" {
 		container.basefs = dir
 	} else if container.basefs != dir {
 		return fmt.Errorf("Error: driver %s is returning inconsistent paths for container %s ('%s' then '%s')",
-			runtime.driver, container.ID, container.basefs, dir)
+			daemon.driver, container.ID, container.basefs, dir)
 	}
 	return nil
 }
 
-func (runtime *Runtime) Unmount(container *Container) error {
-	runtime.driver.Put(container.ID)
+func (daemon *Daemon) Unmount(container *Container) error {
+	daemon.driver.Put(container.ID)
 	return nil
 }
 
-func (runtime *Runtime) Changes(container *Container) ([]archive.Change, error) {
-	if differ, ok := runtime.driver.(graphdriver.Differ); ok {
+func (daemon *Daemon) Changes(container *Container) ([]archive.Change, error) {
+	if differ, ok := daemon.driver.(graphdriver.Differ); ok {
 		return differ.Changes(container.ID)
 	}
-	cDir, err := runtime.driver.Get(container.ID)
+	cDir, err := daemon.driver.Get(container.ID, "")
 	if err != nil {
-		return nil, fmt.Errorf("Error getting container rootfs %s from driver %s: %s", container.ID, container.runtime.driver, err)
+		return nil, fmt.Errorf("Error getting container rootfs %s from driver %s: %s", container.ID, container.daemon.driver, err)
 	}
-	defer runtime.driver.Put(container.ID)
-	initDir, err := runtime.driver.Get(container.ID + "-init")
+	defer daemon.driver.Put(container.ID)
+	initDir, err := daemon.driver.Get(container.ID+"-init", "")
 	if err != nil {
-		return nil, fmt.Errorf("Error getting container init rootfs %s from driver %s: %s", container.ID, container.runtime.driver, err)
+		return nil, fmt.Errorf("Error getting container init rootfs %s from driver %s: %s", container.ID, container.daemon.driver, err)
 	}
-	defer runtime.driver.Put(container.ID + "-init")
+	defer daemon.driver.Put(container.ID + "-init")
 	return archive.ChangesDirs(cDir, initDir)
 }
 
-func (runtime *Runtime) Diff(container *Container) (archive.Archive, error) {
-	if differ, ok := runtime.driver.(graphdriver.Differ); ok {
+func (daemon *Daemon) Diff(container *Container) (archive.Archive, error) {
+	if differ, ok := daemon.driver.(graphdriver.Differ); ok {
 		return differ.Diff(container.ID)
 	}
 
-	changes, err := runtime.Changes(container)
+	changes, err := daemon.Changes(container)
 	if err != nil {
 		return nil, err
 	}
 
-	cDir, err := runtime.driver.Get(container.ID)
+	cDir, err := daemon.driver.Get(container.ID, "")
 	if err != nil {
-		return nil, fmt.Errorf("Error getting container rootfs %s from driver %s: %s", container.ID, container.runtime.driver, err)
+		return nil, fmt.Errorf("Error getting container rootfs %s from driver %s: %s", container.ID, container.daemon.driver, err)
 	}
 
 	archive, err := archive.ExportChanges(cDir, changes)
@@ -904,26 +905,26 @@ func (runtime *Runtime) Diff(container *Container) (archive.Archive, error) {
 	}
 	return utils.NewReadCloserWrapper(archive, func() error {
 		err := archive.Close()
-		runtime.driver.Put(container.ID)
+		daemon.driver.Put(container.ID)
 		return err
 	}), nil
 }
 
-func (runtime *Runtime) Run(c *Container, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
-	return runtime.execDriver.Run(c.command, pipes, startCallback)
+func (daemon *Daemon) Run(c *Container, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
+	return daemon.execDriver.Run(c.command, pipes, startCallback)
 }
 
-func (runtime *Runtime) Kill(c *Container, sig int) error {
-	return runtime.execDriver.Kill(c.command, sig)
+func (daemon *Daemon) Kill(c *Container, sig int) error {
+	return daemon.execDriver.Kill(c.command, sig)
 }
 
 // Nuke kills all containers then removes all content
 // from the content root, including images, volumes and
 // container filesystems.
-// Again: this will remove your entire docker runtime!
-func (runtime *Runtime) Nuke() error {
+// Again: this will remove your entire docker daemon!
+func (daemon *Daemon) Nuke() error {
 	var wg sync.WaitGroup
-	for _, container := range runtime.List() {
+	for _, container := range daemon.List() {
 		wg.Add(1)
 		go func(c *Container) {
 			c.Kill()
@@ -931,63 +932,63 @@ func (runtime *Runtime) Nuke() error {
 		}(container)
 	}
 	wg.Wait()
-	runtime.Close()
+	daemon.Close()
 
-	return os.RemoveAll(runtime.config.Root)
+	return os.RemoveAll(daemon.config.Root)
 }
 
 // FIXME: this is a convenience function for integration tests
-// which need direct access to runtime.graph.
+// which need direct access to daemon.graph.
 // Once the tests switch to using engine and jobs, this method
 // can go away.
-func (runtime *Runtime) Graph() *graph.Graph {
-	return runtime.graph
+func (daemon *Daemon) Graph() *graph.Graph {
+	return daemon.graph
 }
 
-func (runtime *Runtime) Repositories() *graph.TagStore {
-	return runtime.repositories
+func (daemon *Daemon) Repositories() *graph.TagStore {
+	return daemon.repositories
 }
 
-func (runtime *Runtime) Config() *daemonconfig.Config {
-	return runtime.config
+func (daemon *Daemon) Config() *daemonconfig.Config {
+	return daemon.config
 }
 
-func (runtime *Runtime) SystemConfig() *sysinfo.SysInfo {
-	return runtime.sysInfo
+func (daemon *Daemon) SystemConfig() *sysinfo.SysInfo {
+	return daemon.sysInfo
 }
 
-func (runtime *Runtime) SystemInitPath() string {
-	return runtime.sysInitPath
+func (daemon *Daemon) SystemInitPath() string {
+	return daemon.sysInitPath
 }
 
-func (runtime *Runtime) GraphDriver() graphdriver.Driver {
-	return runtime.driver
+func (daemon *Daemon) GraphDriver() graphdriver.Driver {
+	return daemon.driver
 }
 
-func (runtime *Runtime) ExecutionDriver() execdriver.Driver {
-	return runtime.execDriver
+func (daemon *Daemon) ExecutionDriver() execdriver.Driver {
+	return daemon.execDriver
 }
 
-func (runtime *Runtime) Volumes() *graph.Graph {
-	return runtime.volumes
+func (daemon *Daemon) Volumes() *graph.Graph {
+	return daemon.volumes
 }
 
-func (runtime *Runtime) ContainerGraph() *graphdb.Database {
-	return runtime.containerGraph
+func (daemon *Daemon) ContainerGraph() *graphdb.Database {
+	return daemon.containerGraph
 }
 
-func (runtime *Runtime) SetServer(server Server) {
-	runtime.srv = server
+func (daemon *Daemon) SetServer(server Server) {
+	daemon.srv = server
 }
 
-func (runtime *Runtime) checkLocaldns() error {
-	resolvConf, err := utils.GetResolvConf()
+func (daemon *Daemon) checkLocaldns() error {
+	resolvConf, err := resolvconf.Get()
 	if err != nil {
 		return err
 	}
-	if len(runtime.config.Dns) == 0 && utils.CheckLocalDns(resolvConf) {
+	if len(daemon.config.Dns) == 0 && utils.CheckLocalDns(resolvConf) {
 		log.Printf("Local (127.0.0.1) DNS resolver found in resolv.conf and containers can't use it. Using default external servers : %v\n", DefaultDns)
-		runtime.config.Dns = DefaultDns
+		daemon.config.Dns = DefaultDns
 	}
 	return nil
 }

+ 3 - 3
runtime/runtime_aufs.go → daemon/daemon_aufs.go

@@ -1,11 +1,11 @@
 // +build !exclude_graphdriver_aufs
 
-package runtime
+package daemon
 
 import (
+	"github.com/dotcloud/docker/daemon/graphdriver"
+	"github.com/dotcloud/docker/daemon/graphdriver/aufs"
 	"github.com/dotcloud/docker/graph"
-	"github.com/dotcloud/docker/runtime/graphdriver"
-	"github.com/dotcloud/docker/runtime/graphdriver/aufs"
 	"github.com/dotcloud/docker/utils"
 )
 

+ 7 - 0
daemon/daemon_btrfs.go

@@ -0,0 +1,7 @@
+// +build !exclude_graphdriver_btrfs
+
+package daemon
+
+import (
+	_ "github.com/dotcloud/docker/daemon/graphdriver/btrfs"
+)

+ 7 - 0
daemon/daemon_devicemapper.go

@@ -0,0 +1,7 @@
+// +build !exclude_graphdriver_devicemapper
+
+package daemon
+
+import (
+	_ "github.com/dotcloud/docker/daemon/graphdriver/devmapper"
+)

+ 2 - 2
runtime/runtime_no_aufs.go → daemon/daemon_no_aufs.go

@@ -1,9 +1,9 @@
 // +build exclude_graphdriver_aufs
 
-package runtime
+package daemon
 
 import (
-	"github.com/dotcloud/docker/runtime/graphdriver"
+	"github.com/dotcloud/docker/daemon/graphdriver"
 )
 
 func migrateIfAufs(driver graphdriver.Driver, root string) error {

+ 0 - 0
runtime/execdriver/MAINTAINERS → daemon/execdriver/MAINTAINERS


+ 4 - 2
runtime/execdriver/driver.go → daemon/execdriver/driver.go

@@ -89,8 +89,10 @@ type Driver interface {
 
 // Network settings of the container
 type Network struct {
-	Interface *NetworkInterface `json:"interface"` // if interface is nil then networking is disabled
-	Mtu       int               `json:"mtu"`
+	Interface      *NetworkInterface `json:"interface"` // if interface is nil then networking is disabled
+	Mtu            int               `json:"mtu"`
+	ContainerID    string            `json:"container_id"` // id of the container to join network.
+	HostNetworking bool              `json:"host_networking"`
 }
 
 type NetworkInterface struct {

+ 3 - 3
runtime/execdriver/execdrivers/execdrivers.go → daemon/execdriver/execdrivers/execdrivers.go

@@ -2,10 +2,10 @@ package execdrivers
 
 import (
 	"fmt"
+	"github.com/dotcloud/docker/daemon/execdriver"
+	"github.com/dotcloud/docker/daemon/execdriver/lxc"
+	"github.com/dotcloud/docker/daemon/execdriver/native"
 	"github.com/dotcloud/docker/pkg/sysinfo"
-	"github.com/dotcloud/docker/runtime/execdriver"
-	"github.com/dotcloud/docker/runtime/execdriver/lxc"
-	"github.com/dotcloud/docker/runtime/execdriver/native"
 	"path"
 )
 

+ 24 - 9
runtime/execdriver/lxc/driver.go → daemon/execdriver/lxc/driver.go

@@ -1,11 +1,8 @@
 package lxc
 
 import (
+	"encoding/json"
 	"fmt"
-	"github.com/dotcloud/docker/pkg/cgroups"
-	"github.com/dotcloud/docker/pkg/label"
-	"github.com/dotcloud/docker/runtime/execdriver"
-	"github.com/dotcloud/docker/utils"
 	"io/ioutil"
 	"log"
 	"os"
@@ -16,6 +13,12 @@ import (
 	"strings"
 	"syscall"
 	"time"
+
+	"github.com/dotcloud/docker/daemon/execdriver"
+	"github.com/dotcloud/docker/pkg/cgroups"
+	"github.com/dotcloud/docker/pkg/label"
+	"github.com/dotcloud/docker/pkg/system"
+	"github.com/dotcloud/docker/utils"
 )
 
 const DriverName = "lxc"
@@ -25,23 +28,21 @@ func init() {
 		if err := setupEnv(args); err != nil {
 			return err
 		}
-
 		if err := setupHostname(args); err != nil {
 			return err
 		}
-
 		if err := setupNetworking(args); err != nil {
 			return err
 		}
-
 		if err := setupCapabilities(args); err != nil {
 			return err
 		}
-
 		if err := setupWorkingDirectory(args); err != nil {
 			return err
 		}
-
+		if err := system.CloseFdsFrom(3); err != nil {
+			return err
+		}
 		if err := changeUser(args); err != nil {
 			return err
 		}
@@ -85,6 +86,9 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
 	if err := execdriver.SetTerminal(c, pipes); err != nil {
 		return -1, err
 	}
+	if err := d.generateEnvConfig(c); err != nil {
+		return -1, err
+	}
 	configPath, err := d.generateLXCConfig(c)
 	if err != nil {
 		return -1, err
@@ -416,3 +420,14 @@ func (d *driver) generateLXCConfig(c *execdriver.Command) (string, error) {
 	}
 	return root, nil
 }
+
+func (d *driver) generateEnvConfig(c *execdriver.Command) error {
+	data, err := json.Marshal(c.Env)
+	if err != nil {
+		return err
+	}
+	p := path.Join(d.root, "containers", c.ID, "config.env")
+	c.Mounts = append(c.Mounts, execdriver.Mount{p, "/.dockerenv", false, true})
+
+	return ioutil.WriteFile(p, data, 0600)
+}

+ 0 - 0
runtime/execdriver/lxc/info.go → daemon/execdriver/lxc/info.go


+ 0 - 0
runtime/execdriver/lxc/info_test.go → daemon/execdriver/lxc/info_test.go


+ 6 - 4
runtime/execdriver/lxc/init.go → daemon/execdriver/lxc/init.go

@@ -3,15 +3,16 @@ package lxc
 import (
 	"encoding/json"
 	"fmt"
-	"github.com/dotcloud/docker/pkg/netlink"
-	"github.com/dotcloud/docker/pkg/user"
-	"github.com/dotcloud/docker/runtime/execdriver"
-	"github.com/syndtr/gocapability/capability"
 	"io/ioutil"
 	"net"
 	"os"
 	"strings"
 	"syscall"
+
+	"github.com/dotcloud/docker/daemon/execdriver"
+	"github.com/dotcloud/docker/pkg/netlink"
+	"github.com/dotcloud/docker/pkg/user"
+	"github.com/syndtr/gocapability/capability"
 )
 
 // Clear environment pollution introduced by lxc-start
@@ -149,6 +150,7 @@ func setupCapabilities(args *execdriver.InitArgs) error {
 		capability.CAP_MAC_OVERRIDE,
 		capability.CAP_MAC_ADMIN,
 		capability.CAP_NET_ADMIN,
+		capability.CAP_SYSLOG,
 	}
 
 	c, err := capability.NewPid(os.Getpid())

+ 0 - 0
runtime/execdriver/lxc/lxc_init_linux.go → daemon/execdriver/lxc/lxc_init_linux.go


+ 0 - 0
runtime/execdriver/lxc/lxc_init_unsupported.go → daemon/execdriver/lxc/lxc_init_unsupported.go


+ 11 - 10
runtime/execdriver/lxc/lxc_template.go → daemon/execdriver/lxc/lxc_template.go

@@ -1,10 +1,11 @@
 package lxc
 
 import (
-	"github.com/dotcloud/docker/pkg/label"
-	"github.com/dotcloud/docker/runtime/execdriver"
 	"strings"
 	"text/template"
+
+	"github.com/dotcloud/docker/daemon/execdriver"
+	"github.com/dotcloud/docker/pkg/label"
 )
 
 const LxcTemplate = `
@@ -13,12 +14,13 @@ const LxcTemplate = `
 lxc.network.type = veth
 lxc.network.link = {{.Network.Interface.Bridge}}
 lxc.network.name = eth0
-{{else}}
+lxc.network.mtu = {{.Network.Mtu}}
+{{else if not .Network.HostNetworking}}
 # network is disabled (-n=false)
 lxc.network.type = empty
 lxc.network.flags = up
-{{end}}
 lxc.network.mtu = {{.Network.Mtu}}
+{{end}}
 
 # root filesystem
 {{$ROOTFS := .Rootfs}}
@@ -82,12 +84,11 @@ lxc.pivotdir = lxc_putold
 
 # NOTICE: These mounts must be applied within the namespace
 
-#  WARNING: procfs is a known attack vector and should probably be disabled
-#           if your userspace allows it. eg. see http://blog.zx2c4.com/749
+# WARNING: mounting procfs and/or sysfs read-write is a known attack vector.
+# See e.g. http://blog.zx2c4.com/749 and http://bit.ly/T9CkqJ
+# We mount them read-write here, but later, dockerinit will call the Restrict() function to remount them read-only.
+# We cannot mount them directly read-only, because that would prevent loading AppArmor profiles.
 lxc.mount.entry = proc {{escapeFstabSpaces $ROOTFS}}/proc proc nosuid,nodev,noexec 0 0
-
-# WARNING: sysfs is a known attack vector and should probably be disabled
-# if your userspace allows it. eg. see http://bit.ly/T9CkqJ
 lxc.mount.entry = sysfs {{escapeFstabSpaces $ROOTFS}}/sys sysfs nosuid,nodev,noexec 0 0
 
 {{if .Tty}}
@@ -109,7 +110,7 @@ lxc.mount.entry = {{$value.Source}} {{escapeFstabSpaces $ROOTFS}}/{{escapeFstabS
 {{if .AppArmor}}
 lxc.aa_profile = unconfined
 {{else}}
-#lxc.aa_profile = unconfined
+# Let AppArmor normal confinement take place (i.e., not unconfined)
 {{end}}
 {{end}}
 

+ 1 - 1
runtime/execdriver/lxc/lxc_template_unit_test.go → daemon/execdriver/lxc/lxc_template_unit_test.go

@@ -3,7 +3,7 @@ package lxc
 import (
 	"bufio"
 	"fmt"
-	"github.com/dotcloud/docker/runtime/execdriver"
+	"github.com/dotcloud/docker/daemon/execdriver"
 	"io/ioutil"
 	"math/rand"
 	"os"

+ 36 - 26
runtime/execdriver/native/configuration/parse.go → daemon/execdriver/native/configuration/parse.go

@@ -2,12 +2,13 @@ package configuration
 
 import (
 	"fmt"
-	"github.com/dotcloud/docker/pkg/libcontainer"
-	"github.com/dotcloud/docker/utils"
 	"os/exec"
 	"path/filepath"
 	"strconv"
 	"strings"
+
+	"github.com/dotcloud/docker/pkg/libcontainer"
+	"github.com/dotcloud/docker/utils"
 )
 
 type Action func(*libcontainer.Container, interface{}, string) error
@@ -21,10 +22,13 @@ var actions = map[string]Action{
 
 	"net.join": joinNetNamespace, // join another containers net namespace
 
-	"cgroups.cpu_shares":  cpuShares,  // set the cpu shares
-	"cgroups.memory":      memory,     // set the memory limit
-	"cgroups.memory_swap": memorySwap, // set the memory swap limit
-	"cgroups.cpuset.cpus": cpusetCpus, // set the cpus used
+	"cgroups.cpu_shares":         cpuShares,         // set the cpu shares
+	"cgroups.memory":             memory,            // set the memory limit
+	"cgroups.memory_reservation": memoryReservation, // set the memory reservation
+	"cgroups.memory_swap":        memorySwap,        // set the memory swap limit
+	"cgroups.cpuset.cpus":        cpusetCpus,        // set the cpus used
+
+	"systemd.slice": systemdSlice, // set parent Slice used for systemd unit
 
 	"apparmor_profile": apparmorProfile, // set the apparmor profile to apply
 
@@ -40,6 +44,15 @@ func cpusetCpus(container *libcontainer.Container, context interface{}, value st
 	return nil
 }
 
+func systemdSlice(container *libcontainer.Container, context interface{}, value string) error {
+	if container.Cgroups == nil {
+		return fmt.Errorf("cannot set slice when cgroups are disabled")
+	}
+	container.Cgroups.Slice = value
+
+	return nil
+}
+
 func apparmorProfile(container *libcontainer.Container, context interface{}, value string) error {
 	container.Context["apparmor_profile"] = value
 	return nil
@@ -70,6 +83,19 @@ func memory(container *libcontainer.Container, context interface{}, value string
 	return nil
 }
 
+func memoryReservation(container *libcontainer.Container, context interface{}, value string) error {
+	if container.Cgroups == nil {
+		return fmt.Errorf("cannot set cgroups when they are disabled")
+	}
+
+	v, err := utils.RAMInBytes(value)
+	if err != nil {
+		return err
+	}
+	container.Cgroups.MemoryReservation = v
+	return nil
+}
+
 func memorySwap(container *libcontainer.Container, context interface{}, value string) error {
 	if container.Cgroups == nil {
 		return fmt.Errorf("cannot set cgroups when they are disabled")
@@ -83,38 +109,22 @@ func memorySwap(container *libcontainer.Container, context interface{}, value st
 }
 
 func addCap(container *libcontainer.Container, context interface{}, value string) error {
-	c := container.CapabilitiesMask.Get(value)
-	if c == nil {
-		return fmt.Errorf("%s is not a valid capability", value)
-	}
-	c.Enabled = true
+	container.CapabilitiesMask[value] = true
 	return nil
 }
 
 func dropCap(container *libcontainer.Container, context interface{}, value string) error {
-	c := container.CapabilitiesMask.Get(value)
-	if c == nil {
-		return fmt.Errorf("%s is not a valid capability", value)
-	}
-	c.Enabled = false
+	container.CapabilitiesMask[value] = false
 	return nil
 }
 
 func addNamespace(container *libcontainer.Container, context interface{}, value string) error {
-	ns := container.Namespaces.Get(value)
-	if ns == nil {
-		return fmt.Errorf("%s is not a valid namespace", value[1:])
-	}
-	ns.Enabled = true
+	container.Namespaces[value] = true
 	return nil
 }
 
 func dropNamespace(container *libcontainer.Container, context interface{}, value string) error {
-	ns := container.Namespaces.Get(value)
-	if ns == nil {
-		return fmt.Errorf("%s is not a valid namespace", value[1:])
-	}
-	ns.Enabled = false
+	container.Namespaces[value] = false
 	return nil
 }
 

+ 27 - 10
runtime/execdriver/native/configuration/parse_test.go → daemon/execdriver/native/configuration/parse_test.go

@@ -1,8 +1,9 @@
 package configuration
 
 import (
-	"github.com/dotcloud/docker/runtime/execdriver/native/template"
 	"testing"
+
+	"github.com/dotcloud/docker/daemon/execdriver/native/template"
 )
 
 func TestSetReadonlyRootFs(t *testing.T) {
@@ -38,10 +39,10 @@ func TestConfigurationsDoNotConflict(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	if !container1.CapabilitiesMask.Get("NET_ADMIN").Enabled {
+	if !container1.CapabilitiesMask["NET_ADMIN"] {
 		t.Fatal("container one should have NET_ADMIN enabled")
 	}
-	if container2.CapabilitiesMask.Get("NET_ADMIN").Enabled {
+	if container2.CapabilitiesMask["NET_ADMIN"] {
 		t.Fatal("container two should not have NET_ADMIN enabled")
 	}
 }
@@ -93,7 +94,7 @@ func TestCpuShares(t *testing.T) {
 	}
 }
 
-func TestCgroupMemory(t *testing.T) {
+func TestMemory(t *testing.T) {
 	var (
 		container = template.New()
 		opts      = []string{
@@ -109,6 +110,22 @@ func TestCgroupMemory(t *testing.T) {
 	}
 }
 
+func TestMemoryReservation(t *testing.T) {
+	var (
+		container = template.New()
+		opts      = []string{
+			"cgroups.memory_reservation=500m",
+		}
+	)
+	if err := ParseConfiguration(container, nil, opts); err != nil {
+		t.Fatal(err)
+	}
+
+	if expected := int64(500 * 1024 * 1024); container.Cgroups.MemoryReservation != expected {
+		t.Fatalf("expected memory reservation %d got %d", expected, container.Cgroups.MemoryReservation)
+	}
+}
+
 func TestAddCap(t *testing.T) {
 	var (
 		container = template.New()
@@ -121,10 +138,10 @@ func TestAddCap(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	if !container.CapabilitiesMask.Get("MKNOD").Enabled {
+	if !container.CapabilitiesMask["MKNOD"] {
 		t.Fatal("container should have MKNOD enabled")
 	}
-	if !container.CapabilitiesMask.Get("SYS_ADMIN").Enabled {
+	if !container.CapabilitiesMask["SYS_ADMIN"] {
 		t.Fatal("container should have SYS_ADMIN enabled")
 	}
 }
@@ -137,14 +154,14 @@ func TestDropCap(t *testing.T) {
 		}
 	)
 	// enabled all caps like in privileged mode
-	for _, c := range container.CapabilitiesMask {
-		c.Enabled = true
+	for key := range container.CapabilitiesMask {
+		container.CapabilitiesMask[key] = true
 	}
 	if err := ParseConfiguration(container, nil, opts); err != nil {
 		t.Fatal(err)
 	}
 
-	if container.CapabilitiesMask.Get("MKNOD").Enabled {
+	if container.CapabilitiesMask["MKNOD"] {
 		t.Fatal("container should not have MKNOD enabled")
 	}
 }
@@ -160,7 +177,7 @@ func TestDropNamespace(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	if container.Namespaces.Get("NEWNET").Enabled {
+	if container.Namespaces["NEWNET"] {
 		t.Fatal("container should not have NEWNET enabled")
 	}
 }

+ 44 - 17
runtime/execdriver/native/create.go → daemon/execdriver/native/create.go

@@ -3,12 +3,13 @@ package native
 import (
 	"fmt"
 	"os"
+	"path/filepath"
 
-	"github.com/dotcloud/docker/pkg/label"
+	"github.com/dotcloud/docker/daemon/execdriver"
+	"github.com/dotcloud/docker/daemon/execdriver/native/configuration"
+	"github.com/dotcloud/docker/daemon/execdriver/native/template"
+	"github.com/dotcloud/docker/pkg/apparmor"
 	"github.com/dotcloud/docker/pkg/libcontainer"
-	"github.com/dotcloud/docker/runtime/execdriver"
-	"github.com/dotcloud/docker/runtime/execdriver/native/configuration"
-	"github.com/dotcloud/docker/runtime/execdriver/native/template"
 )
 
 // createContainer populates and configures the container type with the
@@ -24,6 +25,7 @@ func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Container
 	container.Cgroups.Name = c.ID
 	// check to see if we are running in ramdisk to disable pivot root
 	container.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != ""
+	container.Context["restrictions"] = "true"
 
 	if err := d.createNetwork(container, c); err != nil {
 		return nil, err
@@ -32,6 +34,8 @@ func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Container
 		if err := d.setPrivileged(container); err != nil {
 			return nil, err
 		}
+	} else {
+		container.Mounts = append(container.Mounts, libcontainer.Mount{Type: "devtmpfs"})
 	}
 	if err := d.setupCgroups(container, c); err != nil {
 		return nil, err
@@ -49,6 +53,10 @@ func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Container
 }
 
 func (d *driver) createNetwork(container *libcontainer.Container, c *execdriver.Command) error {
+	if c.Network.HostNetworking {
+		container.Namespaces["NEWNET"] = false
+		return nil
+	}
 	container.Networks = []*libcontainer.Network{
 		{
 			Mtu:     c.Network.Mtu,
@@ -72,15 +80,34 @@ func (d *driver) createNetwork(container *libcontainer.Container, c *execdriver.
 		}
 		container.Networks = append(container.Networks, &vethNetwork)
 	}
+
+	if c.Network.ContainerID != "" {
+		cmd := d.activeContainers[c.Network.ContainerID]
+		if cmd == nil || cmd.Process == nil {
+			return fmt.Errorf("%s is not a valid running container to join", c.Network.ContainerID)
+		}
+		nspath := filepath.Join("/proc", fmt.Sprint(cmd.Process.Pid), "ns", "net")
+		container.Networks = append(container.Networks, &libcontainer.Network{
+			Type: "netns",
+			Context: libcontainer.Context{
+				"nspath": nspath,
+			},
+		})
+	}
 	return nil
 }
 
 func (d *driver) setPrivileged(container *libcontainer.Container) error {
-	for _, c := range container.CapabilitiesMask {
-		c.Enabled = true
+	for key := range container.CapabilitiesMask {
+		container.CapabilitiesMask[key] = true
 	}
 	container.Cgroups.DeviceAccess = true
-	container.Context["apparmor_profile"] = "unconfined"
+
+	delete(container.Context, "restrictions")
+
+	if apparmor.IsEnabled() {
+		container.Context["apparmor_profile"] = "unconfined"
+	}
 	return nil
 }
 
@@ -88,6 +115,7 @@ func (d *driver) setupCgroups(container *libcontainer.Container, c *execdriver.C
 	if c.Resources != nil {
 		container.Cgroups.CpuShares = c.Resources.CpuShares
 		container.Cgroups.Memory = c.Resources.Memory
+		container.Cgroups.MemoryReservation = c.Resources.Memory
 		container.Cgroups.MemorySwap = c.Resources.MemorySwap
 	}
 	return nil
@@ -95,20 +123,19 @@ func (d *driver) setupCgroups(container *libcontainer.Container, c *execdriver.C
 
 func (d *driver) setupMounts(container *libcontainer.Container, c *execdriver.Command) error {
 	for _, m := range c.Mounts {
-		container.Mounts = append(container.Mounts, libcontainer.Mount{m.Source, m.Destination, m.Writable, m.Private})
+		container.Mounts = append(container.Mounts, libcontainer.Mount{
+			Type:        "bind",
+			Source:      m.Source,
+			Destination: m.Destination,
+			Writable:    m.Writable,
+			Private:     m.Private,
+		})
 	}
 	return nil
 }
 
 func (d *driver) setupLabels(container *libcontainer.Container, c *execdriver.Command) error {
-	labels := c.Config["label"]
-	if len(labels) > 0 {
-		process, mount, err := label.GenLabels(labels[0])
-		if err != nil {
-			return err
-		}
-		container.Context["mount_label"] = mount
-		container.Context["process_label"] = process
-	}
+	container.Context["process_label"] = c.Config["process_label"][0]
+	container.Context["mount_label"] = c.Config["mount_label"][0]
 	return nil
 }

+ 56 - 94
runtime/execdriver/native/driver.go → daemon/execdriver/native/driver.go

@@ -3,35 +3,31 @@ package native
 import (
 	"encoding/json"
 	"fmt"
-	"github.com/dotcloud/docker/pkg/cgroups"
-	"github.com/dotcloud/docker/pkg/libcontainer"
-	"github.com/dotcloud/docker/pkg/libcontainer/apparmor"
-	"github.com/dotcloud/docker/pkg/libcontainer/nsinit"
-	"github.com/dotcloud/docker/pkg/system"
-	"github.com/dotcloud/docker/runtime/execdriver"
-	"io"
 	"io/ioutil"
-	"log"
 	"os"
 	"os/exec"
 	"path/filepath"
 	"strconv"
 	"strings"
 	"syscall"
+
+	"github.com/dotcloud/docker/daemon/execdriver"
+	"github.com/dotcloud/docker/pkg/apparmor"
+	"github.com/dotcloud/docker/pkg/cgroups"
+	"github.com/dotcloud/docker/pkg/libcontainer"
+	"github.com/dotcloud/docker/pkg/libcontainer/nsinit"
+	"github.com/dotcloud/docker/pkg/system"
 )
 
 const (
 	DriverName                = "native"
-	Version                   = "0.1"
+	Version                   = "0.2"
 	BackupApparmorProfilePath = "apparmor/docker.back" // relative to docker root
 )
 
 func init() {
 	execdriver.RegisterInitFunc(DriverName, func(args *execdriver.InitArgs) error {
-		var (
-			container *libcontainer.Container
-			ns        = nsinit.NewNsInit(&nsinit.DefaultCommandFactory{}, &nsinit.DefaultStateWriter{args.Root}, createLogger(""))
-		)
+		var container *libcontainer.Container
 		f, err := os.Open(filepath.Join(args.Root, "container.json"))
 		if err != nil {
 			return err
@@ -42,7 +38,7 @@ func init() {
 		}
 		f.Close()
 
-		cwd, err := os.Getwd()
+		rootfs, err := os.Getwd()
 		if err != nil {
 			return err
 		}
@@ -50,7 +46,7 @@ func init() {
 		if err != nil {
 			return err
 		}
-		if err := ns.Init(container, cwd, args.Console, syncPipe, args.Args); err != nil {
+		if err := nsinit.Init(container, rootfs, args.Console, syncPipe, args.Args); err != nil {
 			return err
 		}
 		return nil
@@ -87,35 +83,49 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
 	d.activeContainers[c.ID] = &c.Cmd
 
 	var (
-		term        nsinit.Terminal
-		factory     = &dockerCommandFactory{c: c, driver: d}
-		stateWriter = &dockerStateWriter{
-			callback: startCallback,
-			c:        c,
-			dsw:      &nsinit.DefaultStateWriter{filepath.Join(d.root, c.ID)},
-		}
-		ns   = nsinit.NewNsInit(factory, stateWriter, createLogger(os.Getenv("DEBUG")))
-		args = append([]string{c.Entrypoint}, c.Arguments...)
+		dataPath = filepath.Join(d.root, c.ID)
+		args     = append([]string{c.Entrypoint}, c.Arguments...)
 	)
 	if err := d.createContainerRoot(c.ID); err != nil {
 		return -1, err
 	}
 	defer d.removeContainerRoot(c.ID)
 
-	if c.Tty {
-		term = &dockerTtyTerm{
-			pipes: pipes,
-		}
-	} else {
-		term = &dockerStdTerm{
-			pipes: pipes,
-		}
-	}
-	c.Terminal = term
 	if err := d.writeContainerFile(container, c.ID); err != nil {
 		return -1, err
 	}
-	return ns.Exec(container, term, args)
+
+	term := getTerminal(c, pipes)
+
+	return nsinit.Exec(container, term, c.Rootfs, dataPath, args, func(container *libcontainer.Container, console, rootfs, dataPath, init string, child *os.File, args []string) *exec.Cmd {
+		// we need to join the rootfs because nsinit will setup the rootfs and chroot
+		initPath := filepath.Join(c.Rootfs, c.InitPath)
+
+		c.Path = d.initPath
+		c.Args = append([]string{
+			initPath,
+			"-driver", DriverName,
+			"-console", console,
+			"-pipe", "3",
+			"-root", filepath.Join(d.root, c.ID),
+			"--",
+		}, args...)
+
+		// set this to nil so that when we set the clone flags anything else is reset
+		c.SysProcAttr = nil
+		system.SetCloneFlags(&c.Cmd, uintptr(nsinit.GetNamespaceFlags(container.Namespaces)))
+		c.ExtraFiles = []*os.File{child}
+
+		c.Env = container.Env
+		c.Dir = c.Rootfs
+
+		return &c.Cmd
+	}, func() {
+		if startCallback != nil {
+			c.ContainerPid = c.Process.Pid
+			startCallback(c)
+		}
+	})
 }
 
 func (d *driver) Kill(p *execdriver.Command, sig int) error {
@@ -228,65 +238,17 @@ func getEnv(key string, env []string) string {
 	return ""
 }
 
-type dockerCommandFactory struct {
-	c      *execdriver.Command
-	driver *driver
-}
-
-// createCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces
-// defined on the container's configuration and use the current binary as the init with the
-// args provided
-func (d *dockerCommandFactory) Create(container *libcontainer.Container, console string, syncFile *os.File, args []string) *exec.Cmd {
-	// we need to join the rootfs because nsinit will setup the rootfs and chroot
-	initPath := filepath.Join(d.c.Rootfs, d.c.InitPath)
-
-	d.c.Path = d.driver.initPath
-	d.c.Args = append([]string{
-		initPath,
-		"-driver", DriverName,
-		"-console", console,
-		"-pipe", "3",
-		"-root", filepath.Join(d.driver.root, d.c.ID),
-		"--",
-	}, args...)
-
-	// set this to nil so that when we set the clone flags anything else is reset
-	d.c.SysProcAttr = nil
-	system.SetCloneFlags(&d.c.Cmd, uintptr(nsinit.GetNamespaceFlags(container.Namespaces)))
-	d.c.ExtraFiles = []*os.File{syncFile}
-
-	d.c.Env = container.Env
-	d.c.Dir = d.c.Rootfs
-
-	return &d.c.Cmd
-}
-
-type dockerStateWriter struct {
-	dsw      nsinit.StateWriter
-	c        *execdriver.Command
-	callback execdriver.StartCallback
-}
-
-func (d *dockerStateWriter) WritePid(pid int, started string) error {
-	d.c.ContainerPid = pid
-	err := d.dsw.WritePid(pid, started)
-	if d.callback != nil {
-		d.callback(d.c)
-	}
-	return err
-}
-
-func (d *dockerStateWriter) DeletePid() error {
-	return d.dsw.DeletePid()
-}
-
-func createLogger(debug string) *log.Logger {
-	var w io.Writer
-	// if we are in debug mode set the logger to stderr
-	if debug != "" {
-		w = os.Stderr
+func getTerminal(c *execdriver.Command, pipes *execdriver.Pipes) nsinit.Terminal {
+	var term nsinit.Terminal
+	if c.Tty {
+		term = &dockerTtyTerm{
+			pipes: pipes,
+		}
 	} else {
-		w = ioutil.Discard
+		term = &dockerStdTerm{
+			pipes: pipes,
+		}
 	}
-	return log.New(w, "[libcontainer] ", log.LstdFlags)
+	c.Terminal = term
+	return term
 }

+ 0 - 0
runtime/execdriver/native/info.go → daemon/execdriver/native/info.go


+ 47 - 0
daemon/execdriver/native/template/default_template.go

@@ -0,0 +1,47 @@
+package template
+
+import (
+	"github.com/dotcloud/docker/pkg/apparmor"
+	"github.com/dotcloud/docker/pkg/cgroups"
+	"github.com/dotcloud/docker/pkg/libcontainer"
+)
+
+// New returns the docker default configuration for libcontainer
+func New() *libcontainer.Container {
+	container := &libcontainer.Container{
+		CapabilitiesMask: map[string]bool{
+			"SETPCAP":        false,
+			"SYS_MODULE":     false,
+			"SYS_RAWIO":      false,
+			"SYS_PACCT":      false,
+			"SYS_ADMIN":      false,
+			"SYS_NICE":       false,
+			"SYS_RESOURCE":   false,
+			"SYS_TIME":       false,
+			"SYS_TTY_CONFIG": false,
+			"AUDIT_WRITE":    false,
+			"AUDIT_CONTROL":  false,
+			"MAC_OVERRIDE":   false,
+			"MAC_ADMIN":      false,
+			"NET_ADMIN":      false,
+			"MKNOD":          true,
+			"SYSLOG":         false,
+		},
+		Namespaces: map[string]bool{
+			"NEWNS":  true,
+			"NEWUTS": true,
+			"NEWIPC": true,
+			"NEWPID": true,
+			"NEWNET": true,
+		},
+		Cgroups: &cgroups.Cgroup{
+			Parent:       "docker",
+			DeviceAccess: false,
+		},
+		Context: libcontainer.Context{},
+	}
+	if apparmor.IsEnabled() {
+		container.Context["apparmor_profile"] = "docker-default"
+	}
+	return container
+}

+ 1 - 1
runtime/execdriver/native/term.go → daemon/execdriver/native/term.go

@@ -5,7 +5,7 @@
 package native
 
 import (
-	"github.com/dotcloud/docker/runtime/execdriver"
+	"github.com/dotcloud/docker/daemon/execdriver"
 	"io"
 	"os"
 	"os/exec"

+ 0 - 0
runtime/execdriver/pipes.go → daemon/execdriver/pipes.go


+ 0 - 0
runtime/execdriver/termconsole.go → daemon/execdriver/termconsole.go


Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików