Compare commits
335 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 786b29d4db | |||
| 05cc946f62 | |||
| 0e9ef654d2 | |||
| 635ef94a6d | |||
| 937d37fa1a | |||
| 08c55cd94b | |||
| 10965f373c | |||
| c4e6b44df8 | |||
| cc712e6de4 | |||
| e698770d40 | |||
| ac6a9ce95f | |||
| b03b8a23d2 | |||
| 34815f3fa6 | |||
| 7e8cceb05a | |||
| 72d9ba5ac9 | |||
| fcc44248ef | |||
| c090014053 | |||
| 6906fb0693 | |||
| 50fe5319c4 | |||
| 53b80bdc9c | |||
| 44a8cf337b | |||
| 0baf609845 | |||
| e45e9e8fbc | |||
| 62fa0ac765 | |||
| 1b6403b9f1 | |||
| f0c8b90524 | |||
| 60ed011bed | |||
| f99e0cea8a | |||
| 984be835db | |||
| 9fc1c4efb9 | |||
| 012bf4129d | |||
| 0bd5953a88 | |||
| 197f2e0693 | |||
| 73e41874b6 | |||
| 64552d0b49 | |||
| 84b21b55b9 | |||
| 7ffbd7eaee | |||
| 469534c855 | |||
| 85d6e7c4ec | |||
| a1f16a3738 | |||
| 2ef2967570 | |||
| ceda1e75a4 | |||
| 2519689e99 | |||
| 009ba67dd0 | |||
| 4743f3b3aa | |||
| 759cdd8ed6 | |||
| ff770d33cd | |||
| 1d3f7cc012 | |||
| 5291de79ae | |||
| 821f9450fc | |||
| 6a04940f86 | |||
| cf13497ca8 | |||
| 2b15a888cd | |||
| 455ad3afe2 | |||
| b5086a7494 | |||
| 80157b35ac | |||
| 4ebcd0d544 | |||
| 3e4284bd7c | |||
| eb4798a10e | |||
| 6c90a239ed | |||
| 8e81f3711f | |||
| d10ed90080 | |||
| 7223584e10 | |||
| c4ba3a8352 | |||
| 33588c23c3 | |||
| 6a5cbd0dd4 | |||
| 495640005a | |||
| 5c408158a6 | |||
| ede1c3f0c2 | |||
| 09295a1453 | |||
| 1f6eca7b99 | |||
| 8f211fde46 | |||
| 5c70b1eadd | |||
| b3adf94d81 | |||
| 8e7ea1a8fd | |||
| c11128520c | |||
| 25fc200dcf | |||
| d17f27a13f | |||
| f2f2c492e1 | |||
| 18af7fdbba | |||
| 339f0a128a | |||
| 5a0fa9545a | |||
| 930f691919 | |||
| bf371ab2a5 | |||
| d283999b1c | |||
| 2786c4d0e2 | |||
| 2939617c8b | |||
| f5e3c68c93 | |||
| c96b03797a | |||
| 0f06c54f40 | |||
| 32fcacdedb | |||
| 140e36a77e | |||
| 4945a51f73 | |||
| c881349e5e | |||
| ecdf1297a3 | |||
| db3daa7bdd | |||
| c0fc839e2b | |||
| 2e29eadb5c | |||
| ecda5c0a6d | |||
| 4872f86d00 | |||
| 6ca78fff63 | |||
| e9c51c3edc | |||
| b38c720f19 | |||
| 3bed793ba1 | |||
| ab7e7a7338 | |||
| 4fefcde5a6 | |||
| 63e3b7433f | |||
| 736c216d58 | |||
| 85f0e01833 | |||
| eb3ed436a4 | |||
| d77d7a0056 | |||
| a0aad0d4de | |||
| baf9ea5ce4 | |||
| a6fe70c696 | |||
| eee959a9b9 | |||
| d000ba05fd | |||
| d8eff999e0 | |||
| fb124bcad0 | |||
| 9827107dcf | |||
| e57d649057 | |||
| d6ff6e2c6f | |||
| cc2944c7af | |||
| 9cee8c4ed0 | |||
| 7c8fca2ddb | |||
| 376188dcd3 | |||
| dc610864aa | |||
| 97cd073598 | |||
| d5ebb60bdd | |||
| 83c5131acd | |||
| b6a9dc399b | |||
| 614a9690e7 | |||
| 545b440a80 | |||
| 3162024e28 | |||
| 769acfec29 | |||
| 47496519da | |||
| fdd21bf032 | |||
| d928dad8c8 | |||
| 82366ce059 | |||
| 6410c3c066 | |||
| 9231dc9cc0 | |||
| 6a3f37386b | |||
| d9a0c05208 | |||
| 24cb9df189 | |||
| c51cd3298c | |||
| 10affa8018 | |||
| ce27fa2716 | |||
| 8d83409e85 | |||
| 3a73b6a2bf | |||
| f99269882f | |||
| 568a9703ac | |||
| faaeb5162d | |||
| b5613baac2 | |||
| c956efcd52 | |||
| 5455864187 | |||
| ceb72fab34 | |||
| c6ea062a26 | |||
| 0e045ab50c | |||
| eeb05fc081 | |||
| e1381ae328 | |||
| 45ad064150 | |||
| 72e14a1566 | |||
| 7d7bec86c9 | |||
| a39d49d676 | |||
| 5bf15a013b | |||
| 9461967eec | |||
| 3be7d11cee | |||
| d9910b8fd8 | |||
| f115c32f6b | |||
| 57939badc3 | |||
| 51ee02d478 | |||
| c92860748c | |||
| f582f9717f | |||
| ebcb36a8d2 | |||
| e6e8f2d717 | |||
| 317a510261 | |||
| 5d3a080178 | |||
| 542c84c2d2 | |||
| f1df74d09d | |||
| 4ddbc7a62f | |||
| f72b2c02b8 | |||
| af9dab70f8 | |||
| 10425e83f2 | |||
| 9c528dca85 | |||
| cb2c25ad2d | |||
| 962dec81ec | |||
| 1eae925a3d | |||
| 3ce2cc8ee7 | |||
| 054acc4bee | |||
| 63cb03a55b | |||
| 49b6f23696 | |||
| 299ae6a2e6 | |||
| 97b521bf10 | |||
| 7f5937d46c | |||
| b6166b9496 | |||
| b596d025f5 | |||
| ca32446950 | |||
| 5328d6d620 | |||
| d0023242ab | |||
| 3ff002aa1a | |||
| ea9b357be2 | |||
| bf1829459f | |||
| 4f744ca781 | |||
| 7dab04383b | |||
| 8a003c8134 | |||
| 208178c799 | |||
| 03b36f3451 | |||
| 7758553239 | |||
| 10fb5ce6d0 | |||
| 0959aec1a9 | |||
| 773f74eb71 | |||
| 7070d9255a | |||
| 2cb4b7f65c | |||
| 2d80652d8a | |||
| 81b4691406 | |||
| 4bae33ef9f | |||
| a8a31eff10 | |||
| 68a8fd5c4e | |||
| 8387c5ab65 | |||
| 69498943c3 | |||
| 1aeb78c2ae | |||
| 331d37f35d | |||
| edf3bf7f33 | |||
| 9ee8dca246 | |||
| aa98bb6c13 | |||
| 2aba3c69f9 | |||
| 71a44c769e | |||
| d8381fad2b | |||
| be379580d0 | |||
| 7ea8513479 | |||
| 3b2fe01c78 | |||
| e8afc22b1f | |||
| 4e407e6b77 | |||
| 23f1c2ea9e | |||
| 788047cafb | |||
| 0c0e7b1b60 | |||
| 09d41529a0 | |||
| cb288fefee | |||
| f7636796c5 | |||
| cb5af83444 | |||
| 96feaf1920 | |||
| 1f03944950 | |||
| 6060eedf9c | |||
| d217da854a | |||
| d74d6d981b | |||
| 0205ac33d2 | |||
| dbb9d47bdc | |||
| ddd1d081d7 | |||
| d6ac36d929 | |||
| 715b94f664 | |||
| 16baca9277 | |||
| 627f8a6cd5 | |||
| a8a7df203a | |||
| 580cbcefd3 | |||
| d9c5ce6e97 | |||
| 0fe9b95415 | |||
| 41d0e4293e | |||
| 26fe640da1 | |||
| 198ca26969 | |||
| d5365f6fc4 | |||
| 5f7e814ee7 | |||
| a84aca0985 | |||
| 68ec22876a | |||
| 0dcc3559e9 | |||
| d4c731ecd6 | |||
| 2dba4e1386 | |||
| 06a7f471e0 | |||
| 4683d01691 | |||
| 6020a06399 | |||
| cc0bfccdf4 | |||
| 0c18ec62f3 | |||
| a9825c9bd8 | |||
| 908be50c44 | |||
| 2a82dba34d | |||
| 13fd2a908c | |||
| 464891aaf8 | |||
| 9974663ed7 | |||
| 76269e5c9d | |||
| 1121d7c4fd | |||
| 7e197575a2 | |||
| 3dc3059d94 | |||
| 7b6de74c9a | |||
| cad8adacb8 | |||
| 6226deeaf4 | |||
| 3ec19f56cf | |||
| 48c71787ed | |||
| 604731a930 | |||
| e8650e01f8 | |||
| 817d04d992 | |||
| cdff91a01c | |||
| 6f26bd0e16 | |||
| 3c090db4e9 | |||
| b7c3fdfd0d | |||
| aa682a845b | |||
| 218d0dcc9d | |||
| 510d8f8634 | |||
| b65600f6b6 | |||
| 79dcea718c | |||
| 072b09c45d | |||
| c2d9837745 | |||
| fa5dfbb18b | |||
| 6532a075f3 | |||
| 3b4a4bf809 | |||
| 4602909566 | |||
| 588f350b61 | |||
| 6e5ff509b2 | |||
| 61d341c2ca | |||
| b996d379a1 | |||
| b0935ea730 | |||
| 96fe13b49b | |||
| 12ccde442a | |||
| 4262cfe41f | |||
| ddc2e25546 | |||
| 6646cff646 | |||
| ac8fd856c0 | |||
| 48754d673c | |||
| 723684525a | |||
| 32aceadbe6 | |||
| c67d3e159c | |||
| a080e2add7 | |||
| 24d81b0ddb | |||
| 08f2fad40b | |||
| f91fbe39ce | |||
| 018ab080bb | |||
| fe94ecb2c1 | |||
| 7b2e67036f | |||
| e130faea1b | |||
| 38f09de334 | |||
| f9ba68ddfb | |||
| 16913455bd | |||
| 32f189cd08 | |||
| 526ca42282 | |||
| b98b42d843 | |||
| 7bf03dd132 | |||
| 034aa3b2c4 | |||
| 6da1e01e6c |
@@ -30,5 +30,8 @@ docs/_build
|
|||||||
docs/_static
|
docs/_static
|
||||||
docs/_templates
|
docs/_templates
|
||||||
docs/changed-files
|
docs/changed-files
|
||||||
|
# generated by man/man/md2man-all.sh
|
||||||
|
man/man1
|
||||||
|
man/man5
|
||||||
pyenv
|
pyenv
|
||||||
vendor/pkg/
|
vendor/pkg/
|
||||||
|
|||||||
@@ -1,5 +1,63 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 1.7.1 (2015-07-14)
|
||||||
|
|
||||||
|
#### Runtime
|
||||||
|
|
||||||
|
- Fix default user spawning exec process with `docker exec`
|
||||||
|
- Make `--bridge=none` not to configure the network bridge
|
||||||
|
- Publish networking stats properly
|
||||||
|
- Fix implicit devicemapper selection with static binaries
|
||||||
|
- Fix socket connections that hung intermittently
|
||||||
|
- Fix bridge interface creation on CentOS/RHEL 6.6
|
||||||
|
- Fix local dns lookups added to resolv.conf
|
||||||
|
- Fix copy command mounting volumes
|
||||||
|
- Fix read/write privileges in volumes mounted with --volumes-from
|
||||||
|
|
||||||
|
#### Remote API
|
||||||
|
|
||||||
|
- Fix unmarshalling of Command and Entrypoint
|
||||||
|
- Set limit for minimum client version supported
|
||||||
|
- Validate port specification
|
||||||
|
- Return proper errors when attach/reattach fail
|
||||||
|
|
||||||
|
#### Distribution
|
||||||
|
|
||||||
|
- Fix pulling private images
|
||||||
|
- Fix fallback between registry V2 and V1
|
||||||
|
|
||||||
|
## 1.7.0 (2015-06-16)
|
||||||
|
|
||||||
|
#### Runtime
|
||||||
|
+ Experimental feature: support for out-of-process volume plugins
|
||||||
|
* The userland proxy can be disabled in favor of hairpin NAT using the daemon’s `--userland-proxy=false` flag
|
||||||
|
* The `exec` command supports the `-u|--user` flag to specify the new process owner
|
||||||
|
+ Default gateway for containers can be specified daemon-wide using the `--default-gateway` and `--default-gateway-v6` flags
|
||||||
|
+ The CPU CFS (Completely Fair Scheduler) quota can be set in `docker run` using `--cpu-quota`
|
||||||
|
+ Container block IO can be controlled in `docker run` using`--blkio-weight`
|
||||||
|
+ ZFS support
|
||||||
|
+ The `docker logs` command supports a `--since` argument
|
||||||
|
+ UTS namespace can be shared with the host with `docker run --uts=host`
|
||||||
|
|
||||||
|
#### Quality
|
||||||
|
* Networking stack was entirely rewritten as part of the libnetwork effort
|
||||||
|
* Engine internals refactoring
|
||||||
|
* Volumes code was entirely rewritten to support the plugins effort
|
||||||
|
+ Sending SIGUSR1 to a daemon will dump all goroutines stacks without exiting
|
||||||
|
|
||||||
|
#### Build
|
||||||
|
+ Support ${variable:-value} and ${variable:+value} syntax for environment variables
|
||||||
|
+ Support resource management flags `--cgroup-parent`, `--cpu-period`, `--cpu-quota`, `--cpuset-cpus`, `--cpuset-mems`
|
||||||
|
+ git context changes with branches and directories
|
||||||
|
* The .dockerignore file support exclusion rules
|
||||||
|
|
||||||
|
#### Distribution
|
||||||
|
+ Client support for v2 mirroring support for the official registry
|
||||||
|
|
||||||
|
#### Bugfixes
|
||||||
|
* Firewalld is now supported and will automatically be used when available
|
||||||
|
* mounting --device recursively
|
||||||
|
|
||||||
## 1.6.2 (2015-05-13)
|
## 1.6.2 (2015-05-13)
|
||||||
|
|
||||||
#### Runtime
|
#### Runtime
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Want to hack on Docker? Awesome! We have a contributor's guide that explains
|
|||||||
[setting up a Docker development environment and the contribution
|
[setting up a Docker development environment and the contribution
|
||||||
process](https://docs.docker.com/project/who-written-for/).
|
process](https://docs.docker.com/project/who-written-for/).
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
This page contains information about reporting issues as well as some tips and
|
This page contains information about reporting issues as well as some tips and
|
||||||
guidelines useful to experienced open source contributors. Finally, make sure
|
guidelines useful to experienced open source contributors. Finally, make sure
|
||||||
|
|||||||
@@ -22,11 +22,6 @@ DOCKER_ENVS := \
|
|||||||
BIND_DIR := $(if $(BINDDIR),$(BINDDIR),$(if $(DOCKER_HOST),,bundles))
|
BIND_DIR := $(if $(BINDDIR),$(BINDDIR),$(if $(DOCKER_HOST),,bundles))
|
||||||
DOCKER_MOUNT := $(if $(BIND_DIR),-v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/docker/docker/$(BIND_DIR)")
|
DOCKER_MOUNT := $(if $(BIND_DIR),-v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/docker/docker/$(BIND_DIR)")
|
||||||
|
|
||||||
# to allow `make DOCSDIR=docs docs-shell` (to create a bind mount in docs)
|
|
||||||
DOCS_MOUNT := $(if $(DOCSDIR),-v $(CURDIR)/$(DOCSDIR):/$(DOCSDIR))
|
|
||||||
|
|
||||||
# to allow `make DOCSPORT=9000 docs`
|
|
||||||
DOCSPORT := 8000
|
|
||||||
|
|
||||||
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null)
|
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null)
|
||||||
DOCKER_IMAGE := docker-dev$(if $(GIT_BRANCH),:$(GIT_BRANCH))
|
DOCKER_IMAGE := docker-dev$(if $(GIT_BRANCH),:$(GIT_BRANCH))
|
||||||
@@ -50,19 +45,6 @@ binary: build
|
|||||||
cross: build
|
cross: build
|
||||||
$(DOCKER_RUN_DOCKER) hack/make.sh binary cross
|
$(DOCKER_RUN_DOCKER) hack/make.sh binary cross
|
||||||
|
|
||||||
docs: docs-build
|
|
||||||
$(DOCKER_RUN_DOCS) -p $(if $(DOCSPORT),$(DOCSPORT):)8000 "$(DOCKER_DOCS_IMAGE)" mkdocs serve
|
|
||||||
|
|
||||||
docs-shell: docs-build
|
|
||||||
$(DOCKER_RUN_DOCS) -p $(if $(DOCSPORT),$(DOCSPORT):)8000 "$(DOCKER_DOCS_IMAGE)" bash
|
|
||||||
|
|
||||||
docs-release: docs-build
|
|
||||||
$(DOCKER_RUN_DOCS) -e OPTIONS -e BUILD_ROOT -e DISTRIBUTION_ID \
|
|
||||||
-v $(CURDIR)/docs/awsconfig:/docs/awsconfig \
|
|
||||||
"$(DOCKER_DOCS_IMAGE)" ./release.sh
|
|
||||||
|
|
||||||
docs-test: docs-build
|
|
||||||
$(DOCKER_RUN_DOCS) "$(DOCKER_DOCS_IMAGE)" ./test.sh
|
|
||||||
|
|
||||||
test: build
|
test: build
|
||||||
$(DOCKER_RUN_DOCKER) hack/make.sh binary cross test-unit test-integration-cli test-docker-py
|
$(DOCKER_RUN_DOCKER) hack/make.sh binary cross test-unit test-integration-cli test-docker-py
|
||||||
@@ -85,13 +67,5 @@ shell: build
|
|||||||
build: bundles
|
build: bundles
|
||||||
docker build -t "$(DOCKER_IMAGE)" .
|
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
|
|
||||||
echo "$(GITCOMMIT)" > docs/GITCOMMIT
|
|
||||||
docker pull docs/base
|
|
||||||
docker build -t "$(DOCKER_DOCS_IMAGE)" docs
|
|
||||||
|
|
||||||
bundles:
|
bundles:
|
||||||
mkdir bundles
|
mkdir bundles
|
||||||
|
|||||||
@@ -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
|
of large-scale operation and support of hundreds of thousands of
|
||||||
applications and databases.
|
applications and databases.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Security Disclosure
|
## Security Disclosure
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ security@docker.com and not by creating a github issue.
|
|||||||
|
|
||||||
A common method for distributing applications and sandboxing their
|
A common method for distributing applications and sandboxing their
|
||||||
execution is to use virtual machines, or VMs. Typical VM formats are
|
execution is to use virtual machines, or VMs. Typical VM formats are
|
||||||
VMWare's vmdk, Oracle Virtualbox's vdi, and Amazon EC2's ami. In theory
|
VMware's vmdk, Oracle Virtualbox's vdi, and Amazon EC2's ami. In theory
|
||||||
these formats should allow every developer to automatically package
|
these formats should allow every developer to automatically package
|
||||||
their application into a "machine" for easy distribution and deployment.
|
their application into a "machine" for easy distribution and deployment.
|
||||||
In practice, that almost never happens, for a few reasons:
|
In practice, that almost never happens, for a few reasons:
|
||||||
@@ -180,7 +180,7 @@ Contributing to Docker
|
|||||||
======================
|
======================
|
||||||
|
|
||||||
[](https://godoc.org/github.com/docker/docker)
|
[](https://godoc.org/github.com/docker/docker)
|
||||||
[](https://jenkins.dockerproject.com/job/Docker%20Master/)
|
[](https://jenkins.dockerproject.org/job/Docker%20Master/)
|
||||||
|
|
||||||
Want to hack on Docker? Awesome! We have [instructions to help you get
|
Want to hack on Docker? Awesome! We have [instructions to help you get
|
||||||
started contributing code or documentation.](https://docs.docker.com/project/who-written-for/).
|
started contributing code or documentation.](https://docs.docker.com/project/who-written-for/).
|
||||||
@@ -192,12 +192,12 @@ Getting the development builds
|
|||||||
==============================
|
==============================
|
||||||
|
|
||||||
Want to run Docker from a master build? You can download
|
Want to run Docker from a master build? You can download
|
||||||
master builds at [master.dockerproject.com](https://master.dockerproject.com).
|
master builds at [master.dockerproject.org](https://master.dockerproject.org).
|
||||||
They are updated with each commit merged into the master branch.
|
They are updated with each commit merged into the master branch.
|
||||||
|
|
||||||
Don't know how to use that super cool new feature in the master build? Check
|
Don't know how to use that super cool new feature in the master build? Check
|
||||||
out the master docs at
|
out the master docs at
|
||||||
[docs.master.dockerproject.com](http://docs.master.dockerproject.com).
|
[docs.master.dockerproject.org](http://docs.master.dockerproject.org).
|
||||||
|
|
||||||
How the project is run
|
How the project is run
|
||||||
======================
|
======================
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -97,7 +96,7 @@ func (cli *DockerCli) Cmd(args ...string) error {
|
|||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
method, exists := cli.getMethod(args[0])
|
method, exists := cli.getMethod(args[0])
|
||||||
if !exists {
|
if !exists {
|
||||||
return fmt.Errorf("docker: '%s' is not a docker command. See 'docker --help'.", args[0])
|
return fmt.Errorf("docker: '%s' is not a docker command.\nSee 'docker --help'.", args[0])
|
||||||
}
|
}
|
||||||
return method(args[1:]...)
|
return method(args[1:]...)
|
||||||
}
|
}
|
||||||
@@ -117,18 +116,19 @@ func (cli *DockerCli) Subcmd(name, signature, description string, exitOnError bo
|
|||||||
errorHandling = flag.ContinueOnError
|
errorHandling = flag.ContinueOnError
|
||||||
}
|
}
|
||||||
flags := flag.NewFlagSet(name, errorHandling)
|
flags := flag.NewFlagSet(name, errorHandling)
|
||||||
|
if signature != "" {
|
||||||
|
signature = " " + signature
|
||||||
|
}
|
||||||
flags.Usage = func() {
|
flags.Usage = func() {
|
||||||
|
flags.ShortUsage()
|
||||||
|
flags.PrintDefaults()
|
||||||
|
}
|
||||||
|
flags.ShortUsage = func() {
|
||||||
options := ""
|
options := ""
|
||||||
if signature != "" {
|
|
||||||
signature = " " + signature
|
|
||||||
}
|
|
||||||
if flags.FlagCountUndeprecated() > 0 {
|
if flags.FlagCountUndeprecated() > 0 {
|
||||||
options = " [OPTIONS]"
|
options = " [OPTIONS]"
|
||||||
}
|
}
|
||||||
fmt.Fprintf(cli.out, "\nUsage: docker %s%s%s\n\n%s\n\n", name, options, signature, description)
|
fmt.Fprintf(flags.Out(), "\nUsage: docker %s%s%s\n\n%s\n", name, options, signature, description)
|
||||||
flags.SetOutput(cli.out)
|
|
||||||
flags.PrintDefaults()
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
}
|
||||||
return flags
|
return flags
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ func (cli *DockerCli) CmdCreate(args ...string) error {
|
|||||||
config, hostConfig, cmd, err := runconfig.Parse(cmd, args)
|
config, hostConfig, cmd, err := runconfig.Parse(cmd, args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cmd.ReportError(err.Error(), true)
|
cmd.ReportError(err.Error(), true)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
if config.Image == "" {
|
if config.Image == "" {
|
||||||
cmd.Usage()
|
cmd.Usage()
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
req, err := http.NewRequest(method, fmt.Sprintf("/v%s%s", api.APIVERSION, path), params)
|
req, err := http.NewRequest(method, fmt.Sprintf("/v%s%s", api.Version, path), params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/pkg/ioutils"
|
||||||
flag "github.com/docker/docker/pkg/mflag"
|
flag "github.com/docker/docker/pkg/mflag"
|
||||||
"github.com/docker/docker/pkg/units"
|
"github.com/docker/docker/pkg/units"
|
||||||
)
|
)
|
||||||
@@ -15,7 +16,7 @@ import (
|
|||||||
func (cli *DockerCli) CmdInfo(args ...string) error {
|
func (cli *DockerCli) CmdInfo(args ...string) error {
|
||||||
cmd := cli.Subcmd("info", "", "Display system-wide information", true)
|
cmd := cli.Subcmd("info", "", "Display system-wide information", true)
|
||||||
cmd.Require(flag.Exact, 0)
|
cmd.Require(flag.Exact, 0)
|
||||||
cmd.ParseFlags(args, false)
|
cmd.ParseFlags(args, true)
|
||||||
|
|
||||||
rdr, _, err := cli.call("GET", "/info", nil, nil)
|
rdr, _, err := cli.call("GET", "/info", nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -29,20 +30,20 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
|
|||||||
|
|
||||||
fmt.Fprintf(cli.out, "Containers: %d\n", info.Containers)
|
fmt.Fprintf(cli.out, "Containers: %d\n", info.Containers)
|
||||||
fmt.Fprintf(cli.out, "Images: %d\n", info.Images)
|
fmt.Fprintf(cli.out, "Images: %d\n", info.Images)
|
||||||
fmt.Fprintf(cli.out, "Storage Driver: %s\n", info.Driver)
|
ioutils.FprintfIfNotEmpty(cli.out, "Storage Driver: %s\n", info.Driver)
|
||||||
if info.DriverStatus != nil {
|
if info.DriverStatus != nil {
|
||||||
for _, pair := range info.DriverStatus {
|
for _, pair := range info.DriverStatus {
|
||||||
fmt.Fprintf(cli.out, " %s: %s\n", pair[0], pair[1])
|
fmt.Fprintf(cli.out, " %s: %s\n", pair[0], pair[1])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Fprintf(cli.out, "Execution Driver: %s\n", info.ExecutionDriver)
|
ioutils.FprintfIfNotEmpty(cli.out, "Execution Driver: %s\n", info.ExecutionDriver)
|
||||||
fmt.Fprintf(cli.out, "Logging Driver: %s\n", info.LoggingDriver)
|
ioutils.FprintfIfNotEmpty(cli.out, "Logging Driver: %s\n", info.LoggingDriver)
|
||||||
fmt.Fprintf(cli.out, "Kernel Version: %s\n", info.KernelVersion)
|
ioutils.FprintfIfNotEmpty(cli.out, "Kernel Version: %s\n", info.KernelVersion)
|
||||||
fmt.Fprintf(cli.out, "Operating System: %s\n", info.OperatingSystem)
|
ioutils.FprintfIfNotEmpty(cli.out, "Operating System: %s\n", info.OperatingSystem)
|
||||||
fmt.Fprintf(cli.out, "CPUs: %d\n", info.NCPU)
|
fmt.Fprintf(cli.out, "CPUs: %d\n", info.NCPU)
|
||||||
fmt.Fprintf(cli.out, "Total Memory: %s\n", units.BytesSize(float64(info.MemTotal)))
|
fmt.Fprintf(cli.out, "Total Memory: %s\n", units.BytesSize(float64(info.MemTotal)))
|
||||||
fmt.Fprintf(cli.out, "Name: %s\n", info.Name)
|
ioutils.FprintfIfNotEmpty(cli.out, "Name: %s\n", info.Name)
|
||||||
fmt.Fprintf(cli.out, "ID: %s\n", info.ID)
|
ioutils.FprintfIfNotEmpty(cli.out, "ID: %s\n", info.ID)
|
||||||
|
|
||||||
if info.Debug {
|
if info.Debug {
|
||||||
fmt.Fprintf(cli.out, "Debug mode (server): %v\n", info.Debug)
|
fmt.Fprintf(cli.out, "Debug mode (server): %v\n", info.Debug)
|
||||||
@@ -55,15 +56,9 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
|
|||||||
fmt.Fprintf(cli.out, "Docker Root Dir: %s\n", info.DockerRootDir)
|
fmt.Fprintf(cli.out, "Docker Root Dir: %s\n", info.DockerRootDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.HttpProxy != "" {
|
ioutils.FprintfIfNotEmpty(cli.out, "Http Proxy: %s\n", info.HttpProxy)
|
||||||
fmt.Fprintf(cli.out, "Http Proxy: %s\n", info.HttpProxy)
|
ioutils.FprintfIfNotEmpty(cli.out, "Https Proxy: %s\n", info.HttpsProxy)
|
||||||
}
|
ioutils.FprintfIfNotEmpty(cli.out, "No Proxy: %s\n", info.NoProxy)
|
||||||
if info.HttpsProxy != "" {
|
|
||||||
fmt.Fprintf(cli.out, "Https Proxy: %s\n", info.HttpsProxy)
|
|
||||||
}
|
|
||||||
if info.NoProxy != "" {
|
|
||||||
fmt.Fprintf(cli.out, "No Proxy: %s\n", info.NoProxy)
|
|
||||||
}
|
|
||||||
|
|
||||||
if info.IndexServerAddress != "" {
|
if info.IndexServerAddress != "" {
|
||||||
u := cli.configFile.AuthConfigs[info.IndexServerAddress].Username
|
u := cli.configFile.AuthConfigs[info.IndexServerAddress].Username
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ func (cli *DockerCli) CmdLogout(args ...string) error {
|
|||||||
cmd := cli.Subcmd("logout", "[SERVER]", "Log out from a Docker registry, if no server is\nspecified \""+registry.IndexServerAddress()+"\" is the default.", true)
|
cmd := cli.Subcmd("logout", "[SERVER]", "Log out from a Docker registry, if no server is\nspecified \""+registry.IndexServerAddress()+"\" is the default.", true)
|
||||||
cmd.Require(flag.Max, 1)
|
cmd.Require(flag.Max, 1)
|
||||||
|
|
||||||
cmd.ParseFlags(args, false)
|
cmd.ParseFlags(args, true)
|
||||||
serverAddress := registry.IndexServerAddress()
|
serverAddress := registry.IndexServerAddress()
|
||||||
if len(cmd.Args()) > 0 {
|
if len(cmd.Args()) > 0 {
|
||||||
serverAddress = cmd.Arg(0)
|
serverAddress = cmd.Arg(0)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
func (cli *DockerCli) CmdPause(args ...string) error {
|
func (cli *DockerCli) CmdPause(args ...string) error {
|
||||||
cmd := cli.Subcmd("pause", "CONTAINER [CONTAINER...]", "Pause all processes within a container", true)
|
cmd := cli.Subcmd("pause", "CONTAINER [CONTAINER...]", "Pause all processes within a container", true)
|
||||||
cmd.Require(flag.Min, 1)
|
cmd.Require(flag.Min, 1)
|
||||||
cmd.ParseFlags(args, false)
|
cmd.ParseFlags(args, true)
|
||||||
|
|
||||||
var errNames []string
|
var errNames []string
|
||||||
for _, name := range cmd.Args() {
|
for _, name := range cmd.Args() {
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
|
|||||||
// just in case the Parse does not exit
|
// just in case the Parse does not exit
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cmd.ReportError(err.Error(), true)
|
cmd.ReportError(err.Error(), true)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(hostConfig.Dns) > 0 {
|
if len(hostConfig.Dns) > 0 {
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ func (s *containerStats) Collect(cli *DockerCli, streamStats bool) {
|
|||||||
var (
|
var (
|
||||||
previousCPU uint64
|
previousCPU uint64
|
||||||
previousSystem uint64
|
previousSystem uint64
|
||||||
start = true
|
|
||||||
dec = json.NewDecoder(stream)
|
dec = json.NewDecoder(stream)
|
||||||
u = make(chan error, 1)
|
u = make(chan error, 1)
|
||||||
)
|
)
|
||||||
@@ -61,10 +60,9 @@ func (s *containerStats) Collect(cli *DockerCli, streamStats bool) {
|
|||||||
memPercent = float64(v.MemoryStats.Usage) / float64(v.MemoryStats.Limit) * 100.0
|
memPercent = float64(v.MemoryStats.Usage) / float64(v.MemoryStats.Limit) * 100.0
|
||||||
cpuPercent = 0.0
|
cpuPercent = 0.0
|
||||||
)
|
)
|
||||||
if !start {
|
previousCPU = v.PreCpuStats.CpuUsage.TotalUsage
|
||||||
cpuPercent = calculateCPUPercent(previousCPU, previousSystem, v)
|
previousSystem = v.PreCpuStats.SystemUsage
|
||||||
}
|
cpuPercent = calculateCPUPercent(previousCPU, previousSystem, v)
|
||||||
start = false
|
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
s.CPUPercentage = cpuPercent
|
s.CPUPercentage = cpuPercent
|
||||||
s.Memory = float64(v.MemoryStats.Usage)
|
s.Memory = float64(v.MemoryStats.Usage)
|
||||||
@@ -73,8 +71,6 @@ func (s *containerStats) Collect(cli *DockerCli, streamStats bool) {
|
|||||||
s.NetworkRx = float64(v.Network.RxBytes)
|
s.NetworkRx = float64(v.Network.RxBytes)
|
||||||
s.NetworkTx = float64(v.Network.TxBytes)
|
s.NetworkTx = float64(v.Network.TxBytes)
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
previousCPU = v.CpuStats.CpuUsage.TotalUsage
|
|
||||||
previousSystem = v.CpuStats.SystemUsage
|
|
||||||
u <- nil
|
u <- nil
|
||||||
if !streamStats {
|
if !streamStats {
|
||||||
return
|
return
|
||||||
@@ -151,7 +147,7 @@ func (cli *DockerCli) CmdStats(args ...string) error {
|
|||||||
}
|
}
|
||||||
// do a quick pause so that any failed connections for containers that do not exist are able to be
|
// do a quick pause so that any failed connections for containers that do not exist are able to be
|
||||||
// evicted before we display the initial or default values.
|
// evicted before we display the initial or default values.
|
||||||
time.Sleep(500 * time.Millisecond)
|
time.Sleep(1500 * time.Millisecond)
|
||||||
var errs []string
|
var errs []string
|
||||||
for _, c := range cStats {
|
for _, c := range cStats {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
func (cli *DockerCli) CmdUnpause(args ...string) error {
|
func (cli *DockerCli) CmdUnpause(args ...string) error {
|
||||||
cmd := cli.Subcmd("unpause", "CONTAINER [CONTAINER...]", "Unpause all processes within a container", true)
|
cmd := cli.Subcmd("unpause", "CONTAINER [CONTAINER...]", "Unpause all processes within a container", true)
|
||||||
cmd.Require(flag.Min, 1)
|
cmd.Require(flag.Min, 1)
|
||||||
cmd.ParseFlags(args, false)
|
cmd.ParseFlags(args, true)
|
||||||
|
|
||||||
var errNames []string
|
var errNames []string
|
||||||
for _, name := range cmd.Args() {
|
for _, name := range cmd.Args() {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ func (cli *DockerCli) clientRequest(method, path string, in io.Reader, headers m
|
|||||||
if expectedPayload && in == nil {
|
if expectedPayload && in == nil {
|
||||||
in = bytes.NewReader([]byte{})
|
in = bytes.NewReader([]byte{})
|
||||||
}
|
}
|
||||||
req, err := http.NewRequest(method, fmt.Sprintf("/v%s%s", api.APIVERSION, path), in)
|
req, err := http.NewRequest(method, fmt.Sprintf("/v%s%s", api.Version, path), in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", -1, err
|
return nil, "", -1, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/autogen/dockerversion"
|
"github.com/docker/docker/autogen/dockerversion"
|
||||||
flag "github.com/docker/docker/pkg/mflag"
|
flag "github.com/docker/docker/pkg/mflag"
|
||||||
|
"github.com/docker/docker/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdVersion shows Docker version information.
|
// CmdVersion shows Docker version information.
|
||||||
@@ -20,17 +21,20 @@ func (cli *DockerCli) CmdVersion(args ...string) error {
|
|||||||
cmd := cli.Subcmd("version", "", "Show the Docker version information.", true)
|
cmd := cli.Subcmd("version", "", "Show the Docker version information.", true)
|
||||||
cmd.Require(flag.Exact, 0)
|
cmd.Require(flag.Exact, 0)
|
||||||
|
|
||||||
cmd.ParseFlags(args, false)
|
cmd.ParseFlags(args, true)
|
||||||
|
|
||||||
if dockerversion.VERSION != "" {
|
if dockerversion.VERSION != "" {
|
||||||
fmt.Fprintf(cli.out, "Client version: %s\n", dockerversion.VERSION)
|
fmt.Fprintf(cli.out, "Client version: %s\n", dockerversion.VERSION)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(cli.out, "Client API version: %s\n", api.APIVERSION)
|
fmt.Fprintf(cli.out, "Client API version: %s\n", api.Version)
|
||||||
fmt.Fprintf(cli.out, "Go version (client): %s\n", runtime.Version())
|
fmt.Fprintf(cli.out, "Go version (client): %s\n", runtime.Version())
|
||||||
if dockerversion.GITCOMMIT != "" {
|
if dockerversion.GITCOMMIT != "" {
|
||||||
fmt.Fprintf(cli.out, "Git commit (client): %s\n", dockerversion.GITCOMMIT)
|
fmt.Fprintf(cli.out, "Git commit (client): %s\n", dockerversion.GITCOMMIT)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(cli.out, "OS/Arch (client): %s/%s\n", runtime.GOOS, runtime.GOARCH)
|
fmt.Fprintf(cli.out, "OS/Arch (client): %s/%s\n", runtime.GOOS, runtime.GOARCH)
|
||||||
|
if utils.ExperimentalBuild() {
|
||||||
|
fmt.Fprintf(cli.out, "Experimental (client): true\n")
|
||||||
|
}
|
||||||
|
|
||||||
stream, _, err := cli.call("GET", "/version", nil, nil)
|
stream, _, err := cli.call("GET", "/version", nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -50,6 +54,8 @@ func (cli *DockerCli) CmdVersion(args ...string) error {
|
|||||||
fmt.Fprintf(cli.out, "Go version (server): %s\n", v.GoVersion)
|
fmt.Fprintf(cli.out, "Go version (server): %s\n", v.GoVersion)
|
||||||
fmt.Fprintf(cli.out, "Git commit (server): %s\n", v.GitCommit)
|
fmt.Fprintf(cli.out, "Git commit (server): %s\n", v.GitCommit)
|
||||||
fmt.Fprintf(cli.out, "OS/Arch (server): %s/%s\n", v.Os, v.Arch)
|
fmt.Fprintf(cli.out, "OS/Arch (server): %s/%s\n", v.Os, v.Arch)
|
||||||
|
if v.Experimental {
|
||||||
|
fmt.Fprintf(cli.out, "Experimental (server): true\n")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,14 @@ import (
|
|||||||
|
|
||||||
// Common constants for daemon and client.
|
// Common constants for daemon and client.
|
||||||
const (
|
const (
|
||||||
APIVERSION version.Version = "1.19" // Current REST API version
|
// Current REST API version
|
||||||
DefaultDockerfileName string = "Dockerfile" // Default filename with Docker commands, read by docker build
|
Version version.Version = "1.19"
|
||||||
|
|
||||||
|
// Minimun REST API version supported
|
||||||
|
MinVersion version.Version = "1.12"
|
||||||
|
|
||||||
|
// Default filename with Docker commands, read by docker build
|
||||||
|
DefaultDockerfileName string = "Dockerfile"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ByPrivatePort []types.Port
|
type ByPrivatePort []types.Port
|
||||||
|
|||||||
@@ -11,6 +11,15 @@ func boolValue(r *http.Request, k string) bool {
|
|||||||
return !(s == "" || s == "0" || s == "no" || s == "false" || s == "none")
|
return !(s == "" || s == "0" || s == "no" || s == "false" || s == "none")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// boolValueOrDefault returns the default bool passed if the query param is
|
||||||
|
// missing, otherwise it's just a proxy to boolValue above
|
||||||
|
func boolValueOrDefault(r *http.Request, k string, d bool) bool {
|
||||||
|
if _, ok := r.Form[k]; !ok {
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
return boolValue(r, k)
|
||||||
|
}
|
||||||
|
|
||||||
func int64ValueOrZero(r *http.Request, k string) int64 {
|
func int64ValueOrZero(r *http.Request, k string) int64 {
|
||||||
val, err := strconv.ParseInt(r.FormValue(k), 10, 64)
|
val, err := strconv.ParseInt(r.FormValue(k), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -33,6 +33,21 @@ func TestBoolValue(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBoolValueOrDefault(t *testing.T) {
|
||||||
|
r, _ := http.NewRequest("GET", "", nil)
|
||||||
|
if !boolValueOrDefault(r, "queryparam", true) {
|
||||||
|
t.Fatal("Expected to get true default value, got false")
|
||||||
|
}
|
||||||
|
|
||||||
|
v := url.Values{}
|
||||||
|
v.Set("param", "")
|
||||||
|
r, _ = http.NewRequest("GET", "", nil)
|
||||||
|
r.Form = v
|
||||||
|
if boolValueOrDefault(r, "param", true) {
|
||||||
|
t.Fatal("Expected not to get true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestInt64ValueOrZero(t *testing.T) {
|
func TestInt64ValueOrZero(t *testing.T) {
|
||||||
cases := map[string]int64{
|
cases := map[string]int64{
|
||||||
"": 0,
|
"": 0,
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import (
|
|||||||
"github.com/docker/docker/pkg/version"
|
"github.com/docker/docker/pkg/version"
|
||||||
"github.com/docker/docker/runconfig"
|
"github.com/docker/docker/runconfig"
|
||||||
"github.com/docker/docker/utils"
|
"github.com/docker/docker/utils"
|
||||||
"github.com/docker/libnetwork/portallocator"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServerConfig struct {
|
type ServerConfig struct {
|
||||||
@@ -97,15 +96,17 @@ func (s *Server) ServeApi(protoAddrs []string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s.servers = append(s.servers, srv)
|
s.servers = append(s.servers, srv...)
|
||||||
|
|
||||||
go func(proto, addr string) {
|
for _, s := range srv {
|
||||||
logrus.Infof("Listening for HTTP on %s (%s)", proto, addr)
|
logrus.Infof("Listening for HTTP on %s (%s)", protoAddrParts[0], protoAddrParts[1])
|
||||||
if err := srv.Serve(); err != nil && strings.Contains(err.Error(), "use of closed network connection") {
|
go func(s serverCloser) {
|
||||||
err = nil
|
if err := s.Serve(); err != nil && strings.Contains(err.Error(), "use of closed network connection") {
|
||||||
}
|
err = nil
|
||||||
chErrors <- err
|
}
|
||||||
}(protoAddrParts[0], protoAddrParts[1])
|
chErrors <- err
|
||||||
|
}(s)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < len(protoAddrs); i++ {
|
for i := 0; i < len(protoAddrs); i++ {
|
||||||
@@ -246,12 +247,17 @@ func (s *Server) postAuth(version version.Version, w http.ResponseWriter, r *htt
|
|||||||
func (s *Server) getVersion(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
func (s *Server) getVersion(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||||
v := &types.Version{
|
v := &types.Version{
|
||||||
Version: dockerversion.VERSION,
|
Version: dockerversion.VERSION,
|
||||||
ApiVersion: api.APIVERSION,
|
ApiVersion: api.Version,
|
||||||
GitCommit: dockerversion.GITCOMMIT,
|
GitCommit: dockerversion.GITCOMMIT,
|
||||||
GoVersion: runtime.Version(),
|
GoVersion: runtime.Version(),
|
||||||
Os: runtime.GOOS,
|
Os: runtime.GOOS,
|
||||||
Arch: runtime.GOARCH,
|
Arch: runtime.GOARCH,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if version.GreaterThanOrEqualTo("1.19") {
|
||||||
|
v.Experimental = utils.ExperimentalBuild()
|
||||||
|
}
|
||||||
|
|
||||||
if kernelVersion, err := kernel.GetKernelVersion(); err == nil {
|
if kernelVersion, err := kernel.GetKernelVersion(); err == nil {
|
||||||
v.KernelVersion = kernelVersion.String()
|
v.KernelVersion = kernelVersion.String()
|
||||||
}
|
}
|
||||||
@@ -271,14 +277,20 @@ func (s *Server) postContainersKill(version version.Version, w http.ResponseWrit
|
|||||||
name := vars["name"]
|
name := vars["name"]
|
||||||
|
|
||||||
// If we have a signal, look at it. Otherwise, do nothing
|
// If we have a signal, look at it. Otherwise, do nothing
|
||||||
if sigStr := vars["signal"]; sigStr != "" {
|
if sigStr := r.Form.Get("signal"); sigStr != "" {
|
||||||
// Check if we passed the signal as a number:
|
// Check if we passed the signal as a number:
|
||||||
// The largest legal signal is 31, so let's parse on 5 bits
|
// The largest legal signal is 31, so let's parse on 5 bits
|
||||||
sig, err := strconv.ParseUint(sigStr, 10, 5)
|
sigN, err := strconv.ParseUint(sigStr, 10, 5)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// The signal is not a number, treat it as a string (either like
|
// The signal is not a number, treat it as a string (either like
|
||||||
// "KILL" or like "SIGKILL")
|
// "KILL" or like "SIGKILL")
|
||||||
sig = uint64(signal.SignalMap[strings.TrimPrefix(sigStr, "SIG")])
|
syscallSig, ok := signal.SignalMap[strings.TrimPrefix(sigStr, "SIG")]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Invalid signal: %s", sigStr)
|
||||||
|
}
|
||||||
|
sig = uint64(syscallSig)
|
||||||
|
} else {
|
||||||
|
sig = sigN
|
||||||
}
|
}
|
||||||
|
|
||||||
if sig == 0 {
|
if sig == 0 {
|
||||||
@@ -386,6 +398,7 @@ func (s *Server) getEvents(version version.Version, w http.ResponseWriter, r *ht
|
|||||||
}
|
}
|
||||||
until = u
|
until = u
|
||||||
}
|
}
|
||||||
|
|
||||||
timer := time.NewTimer(0)
|
timer := time.NewTimer(0)
|
||||||
timer.Stop()
|
timer.Stop()
|
||||||
if until > 0 {
|
if until > 0 {
|
||||||
@@ -444,6 +457,9 @@ func (s *Server) getEvents(version version.Version, w http.ResponseWriter, r *ht
|
|||||||
}
|
}
|
||||||
|
|
||||||
current, l := es.Subscribe()
|
current, l := es.Subscribe()
|
||||||
|
if since == -1 {
|
||||||
|
current = nil
|
||||||
|
}
|
||||||
defer es.Evict(l)
|
defer es.Evict(l)
|
||||||
for _, ev := range current {
|
for _, ev := range current {
|
||||||
if ev.Time < since {
|
if ev.Time < since {
|
||||||
@@ -453,6 +469,12 @@ func (s *Server) getEvents(version version.Version, w http.ResponseWriter, r *ht
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var closeNotify <-chan bool
|
||||||
|
if closeNotifier, ok := w.(http.CloseNotifier); ok {
|
||||||
|
closeNotify = closeNotifier.CloseNotify()
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case ev := <-l:
|
case ev := <-l:
|
||||||
@@ -465,6 +487,9 @@ func (s *Server) getEvents(version version.Version, w http.ResponseWriter, r *ht
|
|||||||
}
|
}
|
||||||
case <-timer.C:
|
case <-timer.C:
|
||||||
return nil
|
return nil
|
||||||
|
case <-closeNotify:
|
||||||
|
logrus.Debug("Client disconnected, stop sending events")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -550,7 +575,16 @@ func (s *Server) getContainersStats(version version.Version, w http.ResponseWrit
|
|||||||
return fmt.Errorf("Missing parameter")
|
return fmt.Errorf("Missing parameter")
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.daemon.ContainerStats(vars["name"], boolValue(r, "stream"), ioutils.NewWriteFlusher(w))
|
stream := boolValueOrDefault(r, "stream", true)
|
||||||
|
var out io.Writer
|
||||||
|
if !stream {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
out = w
|
||||||
|
} else {
|
||||||
|
out = ioutils.NewWriteFlusher(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.daemon.ContainerStats(vars["name"], stream, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) getContainersLogs(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
func (s *Server) getContainersLogs(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||||
@@ -634,10 +668,6 @@ func (s *Server) postCommit(version version.Version, w http.ResponseWriter, r *h
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if c == nil {
|
|
||||||
c = &runconfig.Config{}
|
|
||||||
}
|
|
||||||
|
|
||||||
containerCommitConfig := &daemon.ContainerCommitConfig{
|
containerCommitConfig := &daemon.ContainerCommitConfig{
|
||||||
Pause: pause,
|
Pause: pause,
|
||||||
Repo: r.Form.Get("repo"),
|
Repo: r.Form.Get("repo"),
|
||||||
@@ -873,6 +903,7 @@ func (s *Server) postContainersCreate(version version.Version, w http.ResponseWr
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
adjustCpuShares(version, hostConfig)
|
||||||
|
|
||||||
containerId, warnings, err := s.daemon.ContainerCreate(name, config, hostConfig)
|
containerId, warnings, err := s.daemon.ContainerCreate(name, config, hostConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1070,6 +1101,11 @@ func (s *Server) postContainersAttach(version version.Version, w http.ResponseWr
|
|||||||
return fmt.Errorf("Missing parameter")
|
return fmt.Errorf("Missing parameter")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cont, err := s.daemon.Get(vars["name"])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
inStream, outStream, err := hijackServer(w)
|
inStream, outStream, err := hijackServer(w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1093,7 +1129,7 @@ func (s *Server) postContainersAttach(version version.Version, w http.ResponseWr
|
|||||||
Multiplex: version.GreaterThanOrEqualTo("1.6"),
|
Multiplex: version.GreaterThanOrEqualTo("1.6"),
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.daemon.ContainerAttachWithLogs(vars["name"], attachWithLogsConfig); err != nil {
|
if err := s.daemon.ContainerAttachWithLogs(cont, attachWithLogsConfig); err != nil {
|
||||||
fmt.Fprintf(outStream, "Error attaching: %s\n", err)
|
fmt.Fprintf(outStream, "Error attaching: %s\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1108,6 +1144,11 @@ func (s *Server) wsContainersAttach(version version.Version, w http.ResponseWrit
|
|||||||
return fmt.Errorf("Missing parameter")
|
return fmt.Errorf("Missing parameter")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cont, err := s.daemon.Get(vars["name"])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
h := websocket.Handler(func(ws *websocket.Conn) {
|
h := websocket.Handler(func(ws *websocket.Conn) {
|
||||||
defer ws.Close()
|
defer ws.Close()
|
||||||
|
|
||||||
@@ -1119,7 +1160,7 @@ func (s *Server) wsContainersAttach(version version.Version, w http.ResponseWrit
|
|||||||
Stream: boolValue(r, "stream"),
|
Stream: boolValue(r, "stream"),
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.daemon.ContainerWsAttachWithLogs(vars["name"], wsAttachWithLogsConfig); err != nil {
|
if err := s.daemon.ContainerWsAttachWithLogs(cont, wsAttachWithLogsConfig); err != nil {
|
||||||
logrus.Errorf("Error attaching websocket: %s", err)
|
logrus.Errorf("Error attaching websocket: %s", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -1133,6 +1174,14 @@ func (s *Server) getContainersByName(version version.Version, w http.ResponseWri
|
|||||||
return fmt.Errorf("Missing parameter")
|
return fmt.Errorf("Missing parameter")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if version.LessThan("1.19") {
|
||||||
|
containerJSONRaw, err := s.daemon.ContainerInspectRaw(vars["name"])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return writeJSON(w, http.StatusOK, containerJSONRaw)
|
||||||
|
}
|
||||||
|
|
||||||
containerJSON, err := s.daemon.ContainerInspect(vars["name"])
|
containerJSON, err := s.daemon.ContainerInspect(vars["name"])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1168,18 +1217,17 @@ func (s *Server) getImagesByName(version version.Version, w http.ResponseWriter,
|
|||||||
|
|
||||||
func (s *Server) postBuild(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
func (s *Server) postBuild(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||||
var (
|
var (
|
||||||
authConfig = &cliconfig.AuthConfig{}
|
authConfigs = map[string]cliconfig.AuthConfig{}
|
||||||
configFileEncoded = r.Header.Get("X-Registry-Config")
|
authConfigsEncoded = r.Header.Get("X-Registry-Config")
|
||||||
configFile = &cliconfig.ConfigFile{}
|
buildConfig = builder.NewBuildConfig()
|
||||||
buildConfig = builder.NewBuildConfig()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if configFileEncoded != "" {
|
if authConfigsEncoded != "" {
|
||||||
configFileJson := base64.NewDecoder(base64.URLEncoding, strings.NewReader(configFileEncoded))
|
authConfigsJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authConfigsEncoded))
|
||||||
if err := json.NewDecoder(configFileJson).Decode(configFile); err != nil {
|
if err := json.NewDecoder(authConfigsJSON).Decode(&authConfigs); err != nil {
|
||||||
// for a pull it is not an error if no auth was given
|
// 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
|
// to increase compatibility with the existing api it is defaulting
|
||||||
configFile = &cliconfig.ConfigFile{}
|
// to be empty.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1206,8 +1254,7 @@ func (s *Server) postBuild(version version.Version, w http.ResponseWriter, r *ht
|
|||||||
buildConfig.SuppressOutput = boolValue(r, "q")
|
buildConfig.SuppressOutput = boolValue(r, "q")
|
||||||
buildConfig.NoCache = boolValue(r, "nocache")
|
buildConfig.NoCache = boolValue(r, "nocache")
|
||||||
buildConfig.ForceRemove = boolValue(r, "forcerm")
|
buildConfig.ForceRemove = boolValue(r, "forcerm")
|
||||||
buildConfig.AuthConfig = authConfig
|
buildConfig.AuthConfigs = authConfigs
|
||||||
buildConfig.ConfigFile = configFile
|
|
||||||
buildConfig.MemorySwap = int64ValueOrZero(r, "memswap")
|
buildConfig.MemorySwap = int64ValueOrZero(r, "memswap")
|
||||||
buildConfig.Memory = int64ValueOrZero(r, "memory")
|
buildConfig.Memory = int64ValueOrZero(r, "memory")
|
||||||
buildConfig.CpuShares = int64ValueOrZero(r, "cpushares")
|
buildConfig.CpuShares = int64ValueOrZero(r, "cpushares")
|
||||||
@@ -1436,14 +1483,18 @@ func makeHttpHandler(logging bool, localMethod string, localRoute string, handle
|
|||||||
}
|
}
|
||||||
version := version.Version(mux.Vars(r)["version"])
|
version := version.Version(mux.Vars(r)["version"])
|
||||||
if version == "" {
|
if version == "" {
|
||||||
version = api.APIVERSION
|
version = api.Version
|
||||||
}
|
}
|
||||||
if corsHeaders != "" {
|
if corsHeaders != "" {
|
||||||
writeCorsHeaders(w, r, corsHeaders)
|
writeCorsHeaders(w, r, corsHeaders)
|
||||||
}
|
}
|
||||||
|
|
||||||
if version.GreaterThan(api.APIVERSION) {
|
if version.GreaterThan(api.Version) {
|
||||||
http.Error(w, fmt.Errorf("client and server don't have same version (client API version: %s, server API version: %s)", version, api.APIVERSION).Error(), http.StatusBadRequest)
|
http.Error(w, fmt.Errorf("client is newer than server (client API version: %s, server API version: %s)", version, api.Version).Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if version.LessThan(api.MinVersion) {
|
||||||
|
http.Error(w, fmt.Errorf("client is too old, minimum supported API version is %s, please upgrade your client to a newer version", api.MinVersion).Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1546,30 +1597,3 @@ func createRouter(s *Server) *mux.Router {
|
|||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func allocateDaemonPort(addr string) error {
|
|
||||||
host, port, err := net.SplitHostPort(addr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
intPort, err := strconv.Atoi(port)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var hostIPs []net.IP
|
|
||||||
if parsedIP := net.ParseIP(host); parsedIP != nil {
|
|
||||||
hostIPs = append(hostIPs, parsedIP)
|
|
||||||
} else if hostIPs, err = net.LookupIP(host); err != nil {
|
|
||||||
return fmt.Errorf("failed to lookup %s address in host specification", host)
|
|
||||||
}
|
|
||||||
|
|
||||||
pa := portallocator.Get()
|
|
||||||
for _, hostIP := range hostIPs {
|
|
||||||
if _, err := pa.RequestPort(hostIP, "tcp", intPort); err != nil {
|
|
||||||
return fmt.Errorf("failed to allocate daemon listening port %d (err: %v)", intPort, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,63 +6,65 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/docker/daemon"
|
"github.com/docker/docker/daemon"
|
||||||
"github.com/docker/docker/pkg/sockets"
|
"github.com/docker/docker/pkg/sockets"
|
||||||
"github.com/docker/docker/pkg/systemd"
|
"github.com/docker/docker/pkg/systemd"
|
||||||
|
"github.com/docker/docker/pkg/version"
|
||||||
|
"github.com/docker/docker/runconfig"
|
||||||
|
"github.com/docker/libnetwork/portallocator"
|
||||||
)
|
)
|
||||||
|
|
||||||
// newServer sets up the required serverCloser and does protocol specific checking.
|
const (
|
||||||
func (s *Server) newServer(proto, addr string) (serverCloser, error) {
|
// See http://git.kernel.org/cgit/linux/kernel/git/tip/tip.git/tree/kernel/sched/sched.h?id=8cd9234c64c584432f6992fe944ca9e46ca8ea76#n269
|
||||||
|
linuxMinCpuShares = 2
|
||||||
|
linuxMaxCpuShares = 262144
|
||||||
|
)
|
||||||
|
|
||||||
|
// newServer sets up the required serverClosers and does protocol specific checking.
|
||||||
|
func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
l net.Listener
|
ls []net.Listener
|
||||||
)
|
)
|
||||||
switch proto {
|
switch proto {
|
||||||
case "fd":
|
case "fd":
|
||||||
ls, err := systemd.ListenFD(addr)
|
ls, err = systemd.ListenFD(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
chErrors := make(chan error, len(ls))
|
|
||||||
// We don't want to start serving on these sockets until the
|
// We don't want to start serving on these sockets until the
|
||||||
// daemon is initialized and installed. Otherwise required handlers
|
// daemon is initialized and installed. Otherwise required handlers
|
||||||
// won't be ready.
|
// won't be ready.
|
||||||
<-s.start
|
<-s.start
|
||||||
// Since ListenFD will return one or more sockets we have
|
|
||||||
// to create a go func to spawn off multiple serves
|
|
||||||
for i := range ls {
|
|
||||||
listener := ls[i]
|
|
||||||
go func() {
|
|
||||||
httpSrv := http.Server{Handler: s.router}
|
|
||||||
chErrors <- httpSrv.Serve(listener)
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
for i := 0; i < len(ls); i++ {
|
|
||||||
if err := <-chErrors; err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
case "tcp":
|
case "tcp":
|
||||||
l, err = s.initTcpSocket(addr)
|
l, err := s.initTcpSocket(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
ls = append(ls, l)
|
||||||
case "unix":
|
case "unix":
|
||||||
if l, err = sockets.NewUnixSocket(addr, s.cfg.SocketGroup, s.start); err != nil {
|
l, err := sockets.NewUnixSocket(addr, s.cfg.SocketGroup, s.start)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
ls = append(ls, l)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("Invalid protocol format: %q", proto)
|
return nil, fmt.Errorf("Invalid protocol format: %q", proto)
|
||||||
}
|
}
|
||||||
return &HttpServer{
|
var res []serverCloser
|
||||||
&http.Server{
|
for _, l := range ls {
|
||||||
Addr: addr,
|
res = append(res, &HttpServer{
|
||||||
Handler: s.router,
|
&http.Server{
|
||||||
},
|
Addr: addr,
|
||||||
l,
|
Handler: s.router,
|
||||||
}, nil
|
},
|
||||||
|
l,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) AcceptConnections(d *daemon.Daemon) {
|
func (s *Server) AcceptConnections(d *daemon.Daemon) {
|
||||||
@@ -76,3 +78,45 @@ func (s *Server) AcceptConnections(d *daemon.Daemon) {
|
|||||||
close(s.start)
|
close(s.start)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func allocateDaemonPort(addr string) error {
|
||||||
|
host, port, err := net.SplitHostPort(addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
intPort, err := strconv.Atoi(port)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var hostIPs []net.IP
|
||||||
|
if parsedIP := net.ParseIP(host); parsedIP != nil {
|
||||||
|
hostIPs = append(hostIPs, parsedIP)
|
||||||
|
} else if hostIPs, err = net.LookupIP(host); err != nil {
|
||||||
|
return fmt.Errorf("failed to lookup %s address in host specification", host)
|
||||||
|
}
|
||||||
|
|
||||||
|
pa := portallocator.Get()
|
||||||
|
for _, hostIP := range hostIPs {
|
||||||
|
if _, err := pa.RequestPort(hostIP, "tcp", intPort); err != nil {
|
||||||
|
return fmt.Errorf("failed to allocate daemon listening port %d (err: %v)", intPort, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func adjustCpuShares(version version.Version, hostConfig *runconfig.HostConfig) {
|
||||||
|
if version.LessThan("1.19") {
|
||||||
|
if hostConfig.CpuShares > 0 {
|
||||||
|
// Handle unsupported CpuShares
|
||||||
|
if hostConfig.CpuShares < linuxMinCpuShares {
|
||||||
|
logrus.Warnf("Changing requested CpuShares of %d to minimum allowed of %d", hostConfig.CpuShares, linuxMinCpuShares)
|
||||||
|
hostConfig.CpuShares = linuxMinCpuShares
|
||||||
|
} else if hostConfig.CpuShares > linuxMaxCpuShares {
|
||||||
|
logrus.Warnf("Changing requested CpuShares of %d to maximum allowed of %d", hostConfig.CpuShares, linuxMaxCpuShares)
|
||||||
|
hostConfig.CpuShares = linuxMaxCpuShares
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
// +build linux
|
||||||
|
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/docker/pkg/version"
|
||||||
|
"github.com/docker/docker/runconfig"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAdjustCpuSharesOldApi(t *testing.T) {
|
||||||
|
apiVersion := version.Version("1.18")
|
||||||
|
hostConfig := &runconfig.HostConfig{
|
||||||
|
CpuShares: linuxMinCpuShares - 1,
|
||||||
|
}
|
||||||
|
adjustCpuShares(apiVersion, hostConfig)
|
||||||
|
if hostConfig.CpuShares != linuxMinCpuShares {
|
||||||
|
t.Errorf("Expected CpuShares to be %d", linuxMinCpuShares)
|
||||||
|
}
|
||||||
|
|
||||||
|
hostConfig.CpuShares = linuxMaxCpuShares + 1
|
||||||
|
adjustCpuShares(apiVersion, hostConfig)
|
||||||
|
if hostConfig.CpuShares != linuxMaxCpuShares {
|
||||||
|
t.Errorf("Expected CpuShares to be %d", linuxMaxCpuShares)
|
||||||
|
}
|
||||||
|
|
||||||
|
hostConfig.CpuShares = 0
|
||||||
|
adjustCpuShares(apiVersion, hostConfig)
|
||||||
|
if hostConfig.CpuShares != 0 {
|
||||||
|
t.Error("Expected CpuShares to be unchanged")
|
||||||
|
}
|
||||||
|
|
||||||
|
hostConfig.CpuShares = 1024
|
||||||
|
adjustCpuShares(apiVersion, hostConfig)
|
||||||
|
if hostConfig.CpuShares != 1024 {
|
||||||
|
t.Error("Expected CpuShares to be unchanged")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAdjustCpuSharesNoAdjustment(t *testing.T) {
|
||||||
|
apiVersion := version.Version("1.19")
|
||||||
|
hostConfig := &runconfig.HostConfig{
|
||||||
|
CpuShares: linuxMinCpuShares - 1,
|
||||||
|
}
|
||||||
|
adjustCpuShares(apiVersion, hostConfig)
|
||||||
|
if hostConfig.CpuShares != linuxMinCpuShares-1 {
|
||||||
|
t.Errorf("Expected CpuShares to be %d", linuxMinCpuShares-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
hostConfig.CpuShares = linuxMaxCpuShares + 1
|
||||||
|
adjustCpuShares(apiVersion, hostConfig)
|
||||||
|
if hostConfig.CpuShares != linuxMaxCpuShares+1 {
|
||||||
|
t.Errorf("Expected CpuShares to be %d", linuxMaxCpuShares+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
hostConfig.CpuShares = 0
|
||||||
|
adjustCpuShares(apiVersion, hostConfig)
|
||||||
|
if hostConfig.CpuShares != 0 {
|
||||||
|
t.Error("Expected CpuShares to be unchanged")
|
||||||
|
}
|
||||||
|
|
||||||
|
hostConfig.CpuShares = 1024
|
||||||
|
adjustCpuShares(apiVersion, hostConfig)
|
||||||
|
if hostConfig.CpuShares != 1024 {
|
||||||
|
t.Error("Expected CpuShares to be unchanged")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// NewServer sets up the required Server and does protocol specific checking.
|
// NewServer sets up the required Server and does protocol specific checking.
|
||||||
func (s *Server) newServer(proto, addr string) (Server, error) {
|
func (s *Server) newServer(proto, addr string) (serverCloser, error) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
l net.Listener
|
l net.Listener
|
||||||
@@ -22,6 +22,7 @@ func (s *Server) newServer(proto, addr string) (Server, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("Invalid protocol format. Windows only supports tcp.")
|
return nil, errors.New("Invalid protocol format. Windows only supports tcp.")
|
||||||
}
|
}
|
||||||
@@ -43,3 +44,10 @@ func (s *Server) AcceptConnections(d *daemon.Daemon) {
|
|||||||
close(s.start)
|
close(s.start)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func allocateDaemonPort(addr string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func adjustCpuShares(version version.Version, hostConfig *runconfig.HostConfig) {
|
||||||
|
}
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ type Network struct {
|
|||||||
type Stats struct {
|
type Stats struct {
|
||||||
Read time.Time `json:"read"`
|
Read time.Time `json:"read"`
|
||||||
Network Network `json:"network,omitempty"`
|
Network Network `json:"network,omitempty"`
|
||||||
|
PreCpuStats CpuStats `json:"precpu_stats,omitempty"`
|
||||||
CpuStats CpuStats `json:"cpu_stats,omitempty"`
|
CpuStats CpuStats `json:"cpu_stats,omitempty"`
|
||||||
MemoryStats MemoryStats `json:"memory_stats,omitempty"`
|
MemoryStats MemoryStats `json:"memory_stats,omitempty"`
|
||||||
BlkioStats BlkioStats `json:"blkio_stats,omitempty"`
|
BlkioStats BlkioStats `json:"blkio_stats,omitempty"`
|
||||||
|
|||||||
@@ -94,23 +94,23 @@ type ImageInspect struct {
|
|||||||
|
|
||||||
// GET "/containers/json"
|
// GET "/containers/json"
|
||||||
type Port struct {
|
type Port struct {
|
||||||
IP string
|
IP string `json:",omitempty"`
|
||||||
PrivatePort int
|
PrivatePort int
|
||||||
PublicPort int
|
PublicPort int `json:",omitempty"`
|
||||||
Type string
|
Type string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Container struct {
|
type Container struct {
|
||||||
ID string `json:"Id"`
|
ID string `json:"Id"`
|
||||||
Names []string `json:",omitempty"`
|
Names []string
|
||||||
Image string `json:",omitempty"`
|
Image string
|
||||||
Command string `json:",omitempty"`
|
Command string
|
||||||
Created int `json:",omitempty"`
|
Created int
|
||||||
Ports []Port `json:",omitempty"`
|
Ports []Port
|
||||||
SizeRw int `json:",omitempty"`
|
SizeRw int `json:",omitempty"`
|
||||||
SizeRootFs int `json:",omitempty"`
|
SizeRootFs int `json:",omitempty"`
|
||||||
Labels map[string]string `json:",omitempty"`
|
Labels map[string]string
|
||||||
Status string `json:",omitempty"`
|
Status string
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST "/containers/"+containerID+"/copy"
|
// POST "/containers/"+containerID+"/copy"
|
||||||
@@ -132,6 +132,7 @@ type Version struct {
|
|||||||
Os string
|
Os string
|
||||||
Arch string
|
Arch string
|
||||||
KernelVersion string `json:",omitempty"`
|
KernelVersion string `json:",omitempty"`
|
||||||
|
Experimental bool `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET "/info"
|
// GET "/info"
|
||||||
@@ -194,12 +195,11 @@ type ContainerState struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GET "/containers/{name:.*}/json"
|
// GET "/containers/{name:.*}/json"
|
||||||
type ContainerJSON struct {
|
type ContainerJSONBase struct {
|
||||||
Id string
|
Id string
|
||||||
Created time.Time
|
Created time.Time
|
||||||
Path string
|
Path string
|
||||||
Args []string
|
Args []string
|
||||||
Config *runconfig.Config
|
|
||||||
State *ContainerState
|
State *ContainerState
|
||||||
Image string
|
Image string
|
||||||
NetworkSettings *network.Settings
|
NetworkSettings *network.Settings
|
||||||
@@ -219,3 +219,24 @@ type ContainerJSON struct {
|
|||||||
ExecIDs []string
|
ExecIDs []string
|
||||||
HostConfig *runconfig.HostConfig
|
HostConfig *runconfig.HostConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ContainerJSON struct {
|
||||||
|
*ContainerJSONBase
|
||||||
|
Config *runconfig.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
// backcompatibility struct along with ContainerConfig
|
||||||
|
type ContainerJSONRaw struct {
|
||||||
|
*ContainerJSONBase
|
||||||
|
Config *ContainerConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
type ContainerConfig struct {
|
||||||
|
*runconfig.Config
|
||||||
|
|
||||||
|
// backward compatibility, they now live in HostConfig
|
||||||
|
Memory int64
|
||||||
|
MemorySwap int64
|
||||||
|
CpuShares int64
|
||||||
|
Cpuset string
|
||||||
|
}
|
||||||
|
|||||||
@@ -98,8 +98,8 @@ type Builder struct {
|
|||||||
// the final configs of the Dockerfile but dont want the layers
|
// the final configs of the Dockerfile but dont want the layers
|
||||||
disableCommit bool
|
disableCommit bool
|
||||||
|
|
||||||
AuthConfig *cliconfig.AuthConfig
|
// Registry server auth configs used to pull images when handling `FROM`.
|
||||||
ConfigFile *cliconfig.ConfigFile
|
AuthConfigs map[string]cliconfig.AuthConfig
|
||||||
|
|
||||||
// Deprecated, original writer used for ImagePull. To be removed.
|
// Deprecated, original writer used for ImagePull. To be removed.
|
||||||
OutOld io.Writer
|
OutOld io.Writer
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/docker/builder/parser"
|
"github.com/docker/docker/builder/parser"
|
||||||
|
"github.com/docker/docker/cliconfig"
|
||||||
"github.com/docker/docker/daemon"
|
"github.com/docker/docker/daemon"
|
||||||
"github.com/docker/docker/graph"
|
"github.com/docker/docker/graph"
|
||||||
imagepkg "github.com/docker/docker/image"
|
imagepkg "github.com/docker/docker/image"
|
||||||
@@ -446,15 +447,19 @@ func (b *Builder) pullImage(name string) (*imagepkg.Image, error) {
|
|||||||
tag = "latest"
|
tag = "latest"
|
||||||
}
|
}
|
||||||
|
|
||||||
pullRegistryAuth := b.AuthConfig
|
pullRegistryAuth := &cliconfig.AuthConfig{}
|
||||||
if len(b.ConfigFile.AuthConfigs) > 0 {
|
if len(b.AuthConfigs) > 0 {
|
||||||
// The request came with a full auth config file, we prefer to use that
|
// The request came with a full auth config file, we prefer to use that
|
||||||
repoInfo, err := b.Daemon.RegistryService.ResolveRepository(remote)
|
repoInfo, err := b.Daemon.RegistryService.ResolveRepository(remote)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
resolvedAuth := registry.ResolveAuthConfig(b.ConfigFile, repoInfo.Index)
|
|
||||||
pullRegistryAuth = &resolvedAuth
|
resolvedConfig := registry.ResolveAuthConfig(
|
||||||
|
&cliconfig.ConfigFile{AuthConfigs: b.AuthConfigs},
|
||||||
|
repoInfo.Index,
|
||||||
|
)
|
||||||
|
pullRegistryAuth = &resolvedConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
imagePullConfig := &graph.ImagePullConfig{
|
imagePullConfig := &graph.ImagePullConfig{
|
||||||
|
|||||||
@@ -53,8 +53,7 @@ type Config struct {
|
|||||||
CpuSetCpus string
|
CpuSetCpus string
|
||||||
CpuSetMems string
|
CpuSetMems string
|
||||||
CgroupParent string
|
CgroupParent string
|
||||||
AuthConfig *cliconfig.AuthConfig
|
AuthConfigs map[string]cliconfig.AuthConfig
|
||||||
ConfigFile *cliconfig.ConfigFile
|
|
||||||
|
|
||||||
Stdout io.Writer
|
Stdout io.Writer
|
||||||
Context io.ReadCloser
|
Context io.ReadCloser
|
||||||
@@ -79,9 +78,8 @@ func (b *Config) WaitCancelled() <-chan struct{} {
|
|||||||
|
|
||||||
func NewBuildConfig() *Config {
|
func NewBuildConfig() *Config {
|
||||||
return &Config{
|
return &Config{
|
||||||
AuthConfig: &cliconfig.AuthConfig{},
|
AuthConfigs: map[string]cliconfig.AuthConfig{},
|
||||||
ConfigFile: &cliconfig.ConfigFile{},
|
cancelled: make(chan struct{}),
|
||||||
cancelled: make(chan struct{}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,8 +158,7 @@ func Build(d *daemon.Daemon, buildConfig *Config) error {
|
|||||||
Pull: buildConfig.Pull,
|
Pull: buildConfig.Pull,
|
||||||
OutOld: buildConfig.Stdout,
|
OutOld: buildConfig.Stdout,
|
||||||
StreamFormatter: sf,
|
StreamFormatter: sf,
|
||||||
AuthConfig: buildConfig.AuthConfig,
|
AuthConfigs: buildConfig.AuthConfigs,
|
||||||
ConfigFile: buildConfig.ConfigFile,
|
|
||||||
dockerfileName: buildConfig.DockerfileName,
|
dockerfileName: buildConfig.DockerfileName,
|
||||||
cpuShares: buildConfig.CpuShares,
|
cpuShares: buildConfig.CpuShares,
|
||||||
cpuPeriod: buildConfig.CpuPeriod,
|
cpuPeriod: buildConfig.CpuPeriod,
|
||||||
@@ -221,6 +218,10 @@ func Commit(d *daemon.Daemon, name string, c *daemon.ContainerCommitConfig) (str
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.Config == nil {
|
||||||
|
c.Config = &runconfig.Config{}
|
||||||
|
}
|
||||||
|
|
||||||
newConfig, err := BuildFromConfig(d, c.Config, c.Changes)
|
newConfig, err := BuildFromConfig(d, c.Config, c.Changes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
FROM centos:7
|
FROM centos:7
|
||||||
|
|
||||||
RUN yum groupinstall -y "Development Tools"
|
RUN yum groupinstall -y "Development Tools"
|
||||||
|
RUN yum -y swap -- remove systemd-container systemd-container-libs -- install systemd systemd-libs
|
||||||
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel sqlite-devel tar
|
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel sqlite-devel tar
|
||||||
|
|
||||||
ENV GO_VERSION 1.4.2
|
ENV GO_VERSION 1.4.2
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#
|
||||||
|
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/rpm/generate.sh"!
|
||||||
|
#
|
||||||
|
|
||||||
|
FROM fedora:22
|
||||||
|
|
||||||
|
RUN yum install -y @development-tools fedora-packager
|
||||||
|
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel sqlite-devel tar
|
||||||
|
|
||||||
|
ENV GO_VERSION 1.4.2
|
||||||
|
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
|
||||||
|
ENV PATH $PATH:/usr/local/go/bin
|
||||||
|
|
||||||
|
ENV AUTO_GOPATH 1
|
||||||
|
ENV DOCKER_BUILDTAGS selinux
|
||||||
@@ -38,6 +38,10 @@ for version in "${versions[@]}"; do
|
|||||||
centos:*)
|
centos:*)
|
||||||
# get "Development Tools" packages dependencies
|
# get "Development Tools" packages dependencies
|
||||||
echo 'RUN yum groupinstall -y "Development Tools"' >> "$version/Dockerfile"
|
echo 'RUN yum groupinstall -y "Development Tools"' >> "$version/Dockerfile"
|
||||||
|
|
||||||
|
if [[ "$version" == "centos-7" ]]; then
|
||||||
|
echo 'RUN yum -y swap -- remove systemd-container systemd-container-libs -- install systemd systemd-libs' >> "$version/Dockerfile"
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo 'RUN yum install -y @development-tools fedora-packager' >> "$version/Dockerfile"
|
echo 'RUN yum install -y @development-tools fedora-packager' >> "$version/Dockerfile"
|
||||||
|
|||||||
@@ -212,11 +212,12 @@ _docker_docker() {
|
|||||||
--selinux-enabled
|
--selinux-enabled
|
||||||
--tls
|
--tls
|
||||||
--tlsverify
|
--tlsverify
|
||||||
|
--userland-proxy=false
|
||||||
--version -v
|
--version -v
|
||||||
"
|
"
|
||||||
|
|
||||||
case "$prev" in
|
case "$prev" in
|
||||||
--graph|-g)
|
--exec-root|--graph|-g)
|
||||||
_filedir -d
|
_filedir -d
|
||||||
return
|
return
|
||||||
;;
|
;;
|
||||||
@@ -267,22 +268,25 @@ _docker_attach() {
|
|||||||
|
|
||||||
_docker_build() {
|
_docker_build() {
|
||||||
case "$prev" in
|
case "$prev" in
|
||||||
--tag|-t)
|
--cgroup-parent|--cpuset-cpus|--cpuset-mems|--cpu-shares|-c|--cpu-period|--cpu-quota|--memory|-m|--memory-swap)
|
||||||
__docker_image_repos_and_tags
|
|
||||||
return
|
return
|
||||||
;;
|
;;
|
||||||
--file|-f)
|
--file|-f)
|
||||||
_filedir
|
_filedir
|
||||||
return
|
return
|
||||||
;;
|
;;
|
||||||
|
--tag|-t)
|
||||||
|
__docker_image_repos_and_tags
|
||||||
|
return
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
case "$cur" in
|
case "$cur" in
|
||||||
-*)
|
-*)
|
||||||
COMPREPLY=( $( compgen -W "--cpu-shares -c --cpuset-cpus --cpu-quota --file -f --force-rm --help --memory -m --memory-swap --no-cache --pull --quiet -q --rm --tag -t" -- "$cur" ) )
|
COMPREPLY=( $( compgen -W "--cgroup-parent --cpuset-cpus --cpuset-mems --cpu-shares -c --cpu-period --cpu-quota --file -f --force-rm --help --memory -m --memory-swap --no-cache --pull --quiet -q --rm --tag -t" -- "$cur" ) )
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
local counter="$(__docker_pos_first_nonflag '--tag|-t')"
|
local counter="$(__docker_pos_first_nonflag '--cgroup-parent|--cpuset-cpus|--cpuset-mems|--cpu-shares|-c|--cpu-period|--cpu-quota|--file|-f|--memory|-m|--memory-swap|--tag|-t')"
|
||||||
if [ $cword -eq $counter ]; then
|
if [ $cword -eq $counter ]; then
|
||||||
_filedir -d
|
_filedir -d
|
||||||
fi
|
fi
|
||||||
@@ -405,6 +409,12 @@ _docker_events() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_docker_exec() {
|
_docker_exec() {
|
||||||
|
case "$prev" in
|
||||||
|
--user|-u)
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
case "$cur" in
|
case "$cur" in
|
||||||
-*)
|
-*)
|
||||||
COMPREPLY=( $( compgen -W "--detach -d --help --interactive -i -t --tty -u --user" -- "$cur" ) )
|
COMPREPLY=( $( compgen -W "--detach -d --help --interactive -i -t --tty -u --user" -- "$cur" ) )
|
||||||
@@ -586,7 +596,7 @@ _docker_logout() {
|
|||||||
|
|
||||||
_docker_logs() {
|
_docker_logs() {
|
||||||
case "$prev" in
|
case "$prev" in
|
||||||
--tail)
|
--since|--tail)
|
||||||
return
|
return
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@@ -771,15 +781,16 @@ _docker_rmi() {
|
|||||||
_docker_run() {
|
_docker_run() {
|
||||||
local options_with_args="
|
local options_with_args="
|
||||||
--add-host
|
--add-host
|
||||||
|
--blkio-weight
|
||||||
--attach -a
|
--attach -a
|
||||||
--cap-add
|
--cap-add
|
||||||
--cap-drop
|
--cap-drop
|
||||||
--cgroup-parent
|
--cgroup-parent
|
||||||
--cidfile
|
--cidfile
|
||||||
--cpuset
|
--cpuset
|
||||||
--cpu-shares -c
|
|
||||||
--cpu-period
|
--cpu-period
|
||||||
--cpu-quota
|
--cpu-quota
|
||||||
|
--cpu-shares -c
|
||||||
--device
|
--device
|
||||||
--dns
|
--dns
|
||||||
--dns-search
|
--dns-search
|
||||||
@@ -805,6 +816,7 @@ _docker_run() {
|
|||||||
--security-opt
|
--security-opt
|
||||||
--user -u
|
--user -u
|
||||||
--ulimit
|
--ulimit
|
||||||
|
--uts
|
||||||
--volumes-from
|
--volumes-from
|
||||||
--volume -v
|
--volume -v
|
||||||
--workdir -w
|
--workdir -w
|
||||||
@@ -1156,6 +1168,8 @@ _docker() {
|
|||||||
--api-cors-header
|
--api-cors-header
|
||||||
--bip
|
--bip
|
||||||
--bridge -b
|
--bridge -b
|
||||||
|
--default-gateway
|
||||||
|
--default-gateway-v6
|
||||||
--default-ulimit
|
--default-ulimit
|
||||||
--dns
|
--dns
|
||||||
--dns-search
|
--dns-search
|
||||||
@@ -1203,6 +1217,9 @@ _docker() {
|
|||||||
;;
|
;;
|
||||||
-*)
|
-*)
|
||||||
;;
|
;;
|
||||||
|
=)
|
||||||
|
(( counter++ ))
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
command="${words[$counter]}"
|
command="${words[$counter]}"
|
||||||
cpos=$counter
|
cpos=$counter
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ DOCKER_LOGFILE=${DOCKER_LOGFILE:-/var/log/${SVCNAME}.log}
|
|||||||
DOCKER_PIDFILE=${DOCKER_PIDFILE:-/run/${SVCNAME}.pid}
|
DOCKER_PIDFILE=${DOCKER_PIDFILE:-/run/${SVCNAME}.pid}
|
||||||
DOCKER_BINARY=${DOCKER_BINARY:-/usr/bin/docker}
|
DOCKER_BINARY=${DOCKER_BINARY:-/usr/bin/docker}
|
||||||
DOCKER_OPTS=${DOCKER_OPTS:-}
|
DOCKER_OPTS=${DOCKER_OPTS:-}
|
||||||
UNSHARE_BINARY=${UNSHARE_BINARY:-/usr/bin/unshare}
|
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
checkpath -f -m 0644 -o root:docker "$DOCKER_LOGFILE"
|
checkpath -f -m 0644 -o root:docker "$DOCKER_LOGFILE"
|
||||||
@@ -17,12 +16,11 @@ start() {
|
|||||||
|
|
||||||
ebegin "Starting docker daemon"
|
ebegin "Starting docker daemon"
|
||||||
start-stop-daemon --start --background \
|
start-stop-daemon --start --background \
|
||||||
--exec "$UNSHARE_BINARY" \
|
--exec "$DOCKER_BINARY" \
|
||||||
--pidfile "$DOCKER_PIDFILE" \
|
--pidfile "$DOCKER_PIDFILE" \
|
||||||
--stdout "$DOCKER_LOGFILE" \
|
--stdout "$DOCKER_LOGFILE" \
|
||||||
--stderr "$DOCKER_LOGFILE" \
|
--stderr "$DOCKER_LOGFILE" \
|
||||||
-- --mount \
|
-- -d -p "$DOCKER_PIDFILE" \
|
||||||
-- "$DOCKER_BINARY" -d -p "$DOCKER_PIDFILE" \
|
|
||||||
$DOCKER_OPTS
|
$DOCKER_OPTS
|
||||||
eend $?
|
eend $?
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=Docker Application Container Engine
|
Description=Docker Application Container Engine
|
||||||
Documentation=http://docs.docker.com
|
Documentation=https://docs.docker.com
|
||||||
After=network.target docker.socket
|
After=network.target docker.socket
|
||||||
Requires=docker.socket
|
Requires=docker.socket
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ DOCKER_SSD_PIDFILE=/var/run/$BASE-ssd.pid
|
|||||||
DOCKER_LOGFILE=/var/log/$BASE.log
|
DOCKER_LOGFILE=/var/log/$BASE.log
|
||||||
DOCKER_OPTS=
|
DOCKER_OPTS=
|
||||||
DOCKER_DESC="Docker"
|
DOCKER_DESC="Docker"
|
||||||
UNSHARE=${UNSHARE:-/usr/bin/unshare}
|
|
||||||
|
|
||||||
# Get lsb functions
|
# Get lsb functions
|
||||||
. /lib/lsb/init-functions
|
. /lib/lsb/init-functions
|
||||||
@@ -100,11 +99,11 @@ case "$1" in
|
|||||||
log_begin_msg "Starting $DOCKER_DESC: $BASE"
|
log_begin_msg "Starting $DOCKER_DESC: $BASE"
|
||||||
start-stop-daemon --start --background \
|
start-stop-daemon --start --background \
|
||||||
--no-close \
|
--no-close \
|
||||||
--exec "$UNSHARE" \
|
--exec "$DOCKER" \
|
||||||
--pidfile "$DOCKER_SSD_PIDFILE" \
|
--pidfile "$DOCKER_SSD_PIDFILE" \
|
||||||
--make-pidfile \
|
--make-pidfile \
|
||||||
-- --mount \
|
-- \
|
||||||
-- "$DOCKER" -d -p "$DOCKER_PIDFILE" \
|
-d -p "$DOCKER_PIDFILE" \
|
||||||
$DOCKER_OPTS \
|
$DOCKER_OPTS \
|
||||||
>> "$DOCKER_LOGFILE" 2>&1
|
>> "$DOCKER_LOGFILE" 2>&1
|
||||||
log_end_msg $?
|
log_end_msg $?
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ script
|
|||||||
if [ -f /etc/default/$UPSTART_JOB ]; then
|
if [ -f /etc/default/$UPSTART_JOB ]; then
|
||||||
. /etc/default/$UPSTART_JOB
|
. /etc/default/$UPSTART_JOB
|
||||||
fi
|
fi
|
||||||
exec unshare -m -- "$DOCKER" -d $DOCKER_OPTS
|
exec "$DOCKER" -d $DOCKER_OPTS
|
||||||
end script
|
end script
|
||||||
|
|
||||||
# Don't emit "started" event until docker.sock is ready.
|
# Don't emit "started" event until docker.sock is ready.
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ sudo mkdir -m 755 dev
|
|||||||
# effectively: febootstrap-minimize --keep-zoneinfo --keep-rpmdb --keep-services "$target"
|
# effectively: febootstrap-minimize --keep-zoneinfo --keep-rpmdb --keep-services "$target"
|
||||||
# locales
|
# locales
|
||||||
sudo rm -rf usr/{{lib,share}/locale,{lib,lib64}/gconv,bin/localedef,sbin/build-locale-archive}
|
sudo rm -rf usr/{{lib,share}/locale,{lib,lib64}/gconv,bin/localedef,sbin/build-locale-archive}
|
||||||
# docs
|
# docs and man pages
|
||||||
sudo rm -rf usr/share/{man,doc,info,gnome/help}
|
sudo rm -rf usr/share/{man,doc,info,gnome/help}
|
||||||
# cracklib
|
# cracklib
|
||||||
sudo rm -rf usr/share/cracklib
|
sudo rm -rf usr/share/cracklib
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ shift
|
|||||||
# effectively: febootstrap-minimize --keep-zoneinfo --keep-rpmdb --keep-services "$target"
|
# effectively: febootstrap-minimize --keep-zoneinfo --keep-rpmdb --keep-services "$target"
|
||||||
# locales
|
# locales
|
||||||
rm -rf usr/{{lib,share}/locale,{lib,lib64}/gconv,bin/localedef,sbin/build-locale-archive}
|
rm -rf usr/{{lib,share}/locale,{lib,lib64}/gconv,bin/localedef,sbin/build-locale-archive}
|
||||||
# docs
|
# docs and man pages
|
||||||
rm -rf usr/share/{man,doc,info,gnome/help}
|
rm -rf usr/share/{man,doc,info,gnome/help}
|
||||||
# cracklib
|
# cracklib
|
||||||
rm -rf usr/share/cracklib
|
rm -rf usr/share/cracklib
|
||||||
|
|||||||
@@ -14,12 +14,7 @@ type ContainerAttachWithLogsConfig struct {
|
|||||||
Multiplex bool
|
Multiplex bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) ContainerAttachWithLogs(name string, c *ContainerAttachWithLogsConfig) error {
|
func (daemon *Daemon) ContainerAttachWithLogs(container *Container, c *ContainerAttachWithLogsConfig) error {
|
||||||
container, err := daemon.Get(name)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var errStream io.Writer
|
var errStream io.Writer
|
||||||
|
|
||||||
if !container.Config.Tty && c.Multiplex {
|
if !container.Config.Tty && c.Multiplex {
|
||||||
@@ -51,11 +46,6 @@ type ContainerWsAttachWithLogsConfig struct {
|
|||||||
Logs, Stream bool
|
Logs, Stream bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) ContainerWsAttachWithLogs(name string, c *ContainerWsAttachWithLogsConfig) error {
|
func (daemon *Daemon) ContainerWsAttachWithLogs(container *Container, c *ContainerWsAttachWithLogsConfig) error {
|
||||||
container, err := daemon.Get(name)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return container.AttachWithLogs(c.InStream, c.OutStream, c.ErrStream, c.Logs, c.Stream)
|
return container.AttachWithLogs(c.InStream, c.OutStream, c.ErrStream, c.Logs, c.Stream)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
|
||||||
|
|
||||||
"github.com/docker/docker/opts"
|
"github.com/docker/docker/opts"
|
||||||
flag "github.com/docker/docker/pkg/mflag"
|
flag "github.com/docker/docker/pkg/mflag"
|
||||||
"github.com/docker/docker/runconfig"
|
"github.com/docker/docker/runconfig"
|
||||||
@@ -16,77 +14,46 @@ const (
|
|||||||
// CommonConfig defines the configuration of a docker daemon which are
|
// CommonConfig defines the configuration of a docker daemon which are
|
||||||
// common across platforms.
|
// common across platforms.
|
||||||
type CommonConfig struct {
|
type CommonConfig struct {
|
||||||
AutoRestart bool
|
AutoRestart bool
|
||||||
// Bridge holds bridge network specific configuration.
|
Context map[string][]string
|
||||||
Bridge bridgeConfig
|
CorsHeaders string
|
||||||
Context map[string][]string
|
DisableBridge bool
|
||||||
CorsHeaders string
|
Dns []string
|
||||||
DisableNetwork bool
|
DnsSearch []string
|
||||||
Dns []string
|
EnableCors bool
|
||||||
DnsSearch []string
|
ExecDriver string
|
||||||
EnableCors bool
|
ExecOptions []string
|
||||||
ExecDriver string
|
ExecRoot string
|
||||||
ExecRoot string
|
GraphDriver string
|
||||||
GraphDriver string
|
GraphOptions []string
|
||||||
Labels []string
|
Labels []string
|
||||||
LogConfig runconfig.LogConfig
|
LogConfig runconfig.LogConfig
|
||||||
Mtu int
|
Mtu int
|
||||||
Pidfile string
|
Pidfile string
|
||||||
Root string
|
Root string
|
||||||
TrustKeyPath string
|
TrustKeyPath string
|
||||||
}
|
|
||||||
|
|
||||||
// bridgeConfig stores all the bridge driver specific
|
|
||||||
// configuration.
|
|
||||||
type bridgeConfig struct {
|
|
||||||
EnableIPv6 bool
|
|
||||||
EnableIPTables bool
|
|
||||||
EnableIPForward bool
|
|
||||||
EnableIPMasq bool
|
|
||||||
EnableUserlandProxy bool
|
|
||||||
DefaultIP net.IP
|
|
||||||
Iface string
|
|
||||||
IP string
|
|
||||||
FixedCIDR string
|
|
||||||
FixedCIDRv6 string
|
|
||||||
DefaultGatewayIPv4 string
|
|
||||||
DefaultGatewayIPv6 string
|
|
||||||
InterContainerCommunication bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// InstallCommonFlags adds command-line options to the top-level flag parser for
|
// InstallCommonFlags adds command-line options to the top-level flag parser for
|
||||||
// the current process.
|
// the current process.
|
||||||
// Subsequent calls to `flag.Parse` will populate config with values parsed
|
// Subsequent calls to `flag.Parse` will populate config with values parsed
|
||||||
// from the command-line.
|
// from the command-line.
|
||||||
|
|
||||||
func (config *Config) InstallCommonFlags() {
|
func (config *Config) InstallCommonFlags() {
|
||||||
|
opts.ListVar(&config.GraphOptions, []string{"-storage-opt"}, "Set storage driver options")
|
||||||
|
opts.ListVar(&config.ExecOptions, []string{"-exec-opt"}, "Set exec driver options")
|
||||||
flag.StringVar(&config.Pidfile, []string{"p", "-pidfile"}, defaultPidFile, "Path to use for daemon PID file")
|
flag.StringVar(&config.Pidfile, []string{"p", "-pidfile"}, defaultPidFile, "Path to use for daemon PID file")
|
||||||
flag.StringVar(&config.Root, []string{"g", "-graph"}, defaultGraph, "Root of the Docker runtime")
|
flag.StringVar(&config.Root, []string{"g", "-graph"}, defaultGraph, "Root of the Docker runtime")
|
||||||
flag.StringVar(&config.ExecRoot, []string{"-exec-root"}, "/var/run/docker", "Root of the Docker execdriver")
|
flag.StringVar(&config.ExecRoot, []string{"-exec-root"}, "/var/run/docker", "Root of the Docker execdriver")
|
||||||
flag.BoolVar(&config.AutoRestart, []string{"#r", "#-restart"}, true, "--restart on the daemon has been deprecated in favor of --restart policies on docker run")
|
flag.BoolVar(&config.AutoRestart, []string{"#r", "#-restart"}, true, "--restart on the daemon has been deprecated in favor of --restart policies on docker run")
|
||||||
flag.BoolVar(&config.Bridge.EnableIPTables, []string{"#iptables", "-iptables"}, true, "Enable addition of iptables rules")
|
|
||||||
flag.BoolVar(&config.Bridge.EnableIPForward, []string{"#ip-forward", "-ip-forward"}, true, "Enable net.ipv4.ip_forward")
|
|
||||||
flag.BoolVar(&config.Bridge.EnableIPMasq, []string{"-ip-masq"}, true, "Enable IP masquerading")
|
|
||||||
flag.BoolVar(&config.Bridge.EnableIPv6, []string{"-ipv6"}, false, "Enable IPv6 networking")
|
|
||||||
flag.StringVar(&config.Bridge.IP, []string{"#bip", "-bip"}, "", "Specify network bridge IP")
|
|
||||||
flag.StringVar(&config.Bridge.Iface, []string{"b", "-bridge"}, "", "Attach containers to a network bridge")
|
|
||||||
flag.StringVar(&config.Bridge.FixedCIDR, []string{"-fixed-cidr"}, "", "IPv4 subnet for fixed IPs")
|
|
||||||
flag.StringVar(&config.Bridge.FixedCIDRv6, []string{"-fixed-cidr-v6"}, "", "IPv6 subnet for fixed IPs")
|
|
||||||
flag.StringVar(&config.Bridge.DefaultGatewayIPv4, []string{"-default-gateway"}, "", "Container default gateway IPv4 address")
|
|
||||||
flag.StringVar(&config.Bridge.DefaultGatewayIPv6, []string{"-default-gateway-v6"}, "", "Container default gateway IPv6 address")
|
|
||||||
flag.BoolVar(&config.Bridge.InterContainerCommunication, []string{"#icc", "-icc"}, true, "Enable inter-container communication")
|
|
||||||
flag.StringVar(&config.GraphDriver, []string{"s", "-storage-driver"}, "", "Storage driver to use")
|
flag.StringVar(&config.GraphDriver, []string{"s", "-storage-driver"}, "", "Storage driver to use")
|
||||||
flag.StringVar(&config.ExecDriver, []string{"e", "-exec-driver"}, defaultExec, "Exec driver to use")
|
flag.StringVar(&config.ExecDriver, []string{"e", "-exec-driver"}, defaultExec, "Exec driver to use")
|
||||||
flag.IntVar(&config.Mtu, []string{"#mtu", "-mtu"}, 0, "Set the containers network MTU")
|
flag.IntVar(&config.Mtu, []string{"#mtu", "-mtu"}, 0, "Set the containers network MTU")
|
||||||
flag.BoolVar(&config.EnableCors, []string{"#api-enable-cors", "#-api-enable-cors"}, false, "Enable CORS headers in the remote API, this is deprecated by --api-cors-header")
|
flag.BoolVar(&config.EnableCors, []string{"#api-enable-cors", "#-api-enable-cors"}, false, "Enable CORS headers in the remote API, this is deprecated by --api-cors-header")
|
||||||
flag.StringVar(&config.CorsHeaders, []string{"-api-cors-header"}, "", "Set CORS headers in the remote API")
|
flag.StringVar(&config.CorsHeaders, []string{"-api-cors-header"}, "", "Set CORS headers in the remote API")
|
||||||
opts.IPVar(&config.Bridge.DefaultIP, []string{"#ip", "-ip"}, "0.0.0.0", "Default IP when binding container ports")
|
|
||||||
// FIXME: why the inconsistency between "hosts" and "sockets"?
|
// FIXME: why the inconsistency between "hosts" and "sockets"?
|
||||||
opts.IPListVar(&config.Dns, []string{"#dns", "-dns"}, "DNS server to use")
|
opts.IPListVar(&config.Dns, []string{"#dns", "-dns"}, "DNS server to use")
|
||||||
opts.DnsSearchListVar(&config.DnsSearch, []string{"-dns-search"}, "DNS search domains to use")
|
opts.DnsSearchListVar(&config.DnsSearch, []string{"-dns-search"}, "DNS search domains to use")
|
||||||
opts.LabelListVar(&config.Labels, []string{"-label"}, "Set key=value labels to the daemon")
|
opts.LabelListVar(&config.Labels, []string{"-label"}, "Set key=value labels to the daemon")
|
||||||
flag.StringVar(&config.LogConfig.Type, []string{"-log-driver"}, "json-file", "Default driver for container logs")
|
flag.StringVar(&config.LogConfig.Type, []string{"-log-driver"}, "json-file", "Default driver for container logs")
|
||||||
opts.LogOptsVar(config.LogConfig.Config, []string{"-log-opt"}, "Set log driver options")
|
opts.LogOptsVar(config.LogConfig.Config, []string{"-log-opt"}, "Set log driver options")
|
||||||
flag.BoolVar(&config.Bridge.EnableUserlandProxy, []string{"-userland-proxy"}, true, "Use userland proxy for loopback traffic")
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
"github.com/docker/docker/opts"
|
"github.com/docker/docker/opts"
|
||||||
flag "github.com/docker/docker/pkg/mflag"
|
flag "github.com/docker/docker/pkg/mflag"
|
||||||
"github.com/docker/docker/pkg/ulimit"
|
"github.com/docker/docker/pkg/ulimit"
|
||||||
@@ -19,13 +21,32 @@ type Config struct {
|
|||||||
CommonConfig
|
CommonConfig
|
||||||
|
|
||||||
// Fields below here are platform specific.
|
// Fields below here are platform specific.
|
||||||
|
|
||||||
|
// Bridge holds bridge network specific configuration.
|
||||||
|
Bridge bridgeConfig
|
||||||
EnableSelinuxSupport bool
|
EnableSelinuxSupport bool
|
||||||
ExecOptions []string
|
|
||||||
GraphOptions []string
|
|
||||||
SocketGroup string
|
SocketGroup string
|
||||||
Ulimits map[string]*ulimit.Ulimit
|
Ulimits map[string]*ulimit.Ulimit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bridgeConfig stores all the bridge driver specific
|
||||||
|
// configuration.
|
||||||
|
type bridgeConfig struct {
|
||||||
|
EnableIPv6 bool
|
||||||
|
EnableIPTables bool
|
||||||
|
EnableIPForward bool
|
||||||
|
EnableIPMasq bool
|
||||||
|
EnableUserlandProxy bool
|
||||||
|
DefaultIP net.IP
|
||||||
|
Iface string
|
||||||
|
IP string
|
||||||
|
FixedCIDR string
|
||||||
|
FixedCIDRv6 string
|
||||||
|
DefaultGatewayIPv4 net.IP
|
||||||
|
DefaultGatewayIPv6 net.IP
|
||||||
|
InterContainerCommunication bool
|
||||||
|
}
|
||||||
|
|
||||||
// InstallFlags adds command-line options to the top-level flag parser for
|
// InstallFlags adds command-line options to the top-level flag parser for
|
||||||
// the current process.
|
// the current process.
|
||||||
// Subsequent calls to `flag.Parse` will populate config with values parsed
|
// Subsequent calls to `flag.Parse` will populate config with values parsed
|
||||||
@@ -35,10 +56,21 @@ func (config *Config) InstallFlags() {
|
|||||||
config.InstallCommonFlags()
|
config.InstallCommonFlags()
|
||||||
|
|
||||||
// Then platform-specific install flags
|
// Then platform-specific install flags
|
||||||
opts.ListVar(&config.GraphOptions, []string{"-storage-opt"}, "Set storage driver options")
|
|
||||||
opts.ListVar(&config.ExecOptions, []string{"-exec-opt"}, "Set exec driver options")
|
|
||||||
flag.BoolVar(&config.EnableSelinuxSupport, []string{"-selinux-enabled"}, false, "Enable selinux support")
|
flag.BoolVar(&config.EnableSelinuxSupport, []string{"-selinux-enabled"}, false, "Enable selinux support")
|
||||||
flag.StringVar(&config.SocketGroup, []string{"G", "-group"}, "docker", "Group for the unix socket")
|
flag.StringVar(&config.SocketGroup, []string{"G", "-group"}, "docker", "Group for the unix socket")
|
||||||
config.Ulimits = make(map[string]*ulimit.Ulimit)
|
config.Ulimits = make(map[string]*ulimit.Ulimit)
|
||||||
opts.UlimitMapVar(config.Ulimits, []string{"-default-ulimit"}, "Set default ulimits for containers")
|
opts.UlimitMapVar(config.Ulimits, []string{"-default-ulimit"}, "Set default ulimits for containers")
|
||||||
|
flag.BoolVar(&config.Bridge.EnableIPTables, []string{"#iptables", "-iptables"}, true, "Enable addition of iptables rules")
|
||||||
|
flag.BoolVar(&config.Bridge.EnableIPForward, []string{"#ip-forward", "-ip-forward"}, true, "Enable net.ipv4.ip_forward")
|
||||||
|
flag.BoolVar(&config.Bridge.EnableIPMasq, []string{"-ip-masq"}, true, "Enable IP masquerading")
|
||||||
|
flag.BoolVar(&config.Bridge.EnableIPv6, []string{"-ipv6"}, false, "Enable IPv6 networking")
|
||||||
|
flag.StringVar(&config.Bridge.IP, []string{"#bip", "-bip"}, "", "Specify network bridge IP")
|
||||||
|
flag.StringVar(&config.Bridge.Iface, []string{"b", "-bridge"}, "", "Attach containers to a network bridge")
|
||||||
|
flag.StringVar(&config.Bridge.FixedCIDR, []string{"-fixed-cidr"}, "", "IPv4 subnet for fixed IPs")
|
||||||
|
flag.StringVar(&config.Bridge.FixedCIDRv6, []string{"-fixed-cidr-v6"}, "", "IPv6 subnet for fixed IPs")
|
||||||
|
opts.IPVar(&config.Bridge.DefaultGatewayIPv4, []string{"-default-gateway"}, "", "Container default gateway IPv4 address")
|
||||||
|
opts.IPVar(&config.Bridge.DefaultGatewayIPv6, []string{"-default-gateway-v6"}, "", "Container default gateway IPv6 address")
|
||||||
|
flag.BoolVar(&config.Bridge.InterContainerCommunication, []string{"#icc", "-icc"}, true, "Enable inter-container communication")
|
||||||
|
opts.IPVar(&config.Bridge.DefaultIP, []string{"#ip", "-ip"}, "0.0.0.0", "Default IP when binding container ports")
|
||||||
|
flag.BoolVar(&config.Bridge.EnableUserlandProxy, []string{"-userland-proxy"}, true, "Use userland proxy for loopback traffic")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import (
|
|||||||
"github.com/docker/docker/nat"
|
"github.com/docker/docker/nat"
|
||||||
"github.com/docker/docker/pkg/archive"
|
"github.com/docker/docker/pkg/archive"
|
||||||
"github.com/docker/docker/pkg/broadcastwriter"
|
"github.com/docker/docker/pkg/broadcastwriter"
|
||||||
|
"github.com/docker/docker/pkg/fileutils"
|
||||||
"github.com/docker/docker/pkg/ioutils"
|
"github.com/docker/docker/pkg/ioutils"
|
||||||
"github.com/docker/docker/pkg/jsonlog"
|
"github.com/docker/docker/pkg/jsonlog"
|
||||||
"github.com/docker/docker/pkg/mount"
|
"github.com/docker/docker/pkg/mount"
|
||||||
@@ -73,7 +74,10 @@ type CommonContainer struct {
|
|||||||
MountLabel, ProcessLabel string
|
MountLabel, ProcessLabel string
|
||||||
RestartCount int
|
RestartCount int
|
||||||
UpdateDns bool
|
UpdateDns bool
|
||||||
MountPoints map[string]*mountPoint
|
|
||||||
|
MountPoints map[string]*mountPoint
|
||||||
|
Volumes map[string]string // Deprecated since 1.7, kept for backwards compatibility
|
||||||
|
VolumesRW map[string]bool // Deprecated since 1.7, kept for backwards compatibility
|
||||||
|
|
||||||
hostConfig *runconfig.HostConfig
|
hostConfig *runconfig.HostConfig
|
||||||
command *execdriver.Command
|
command *execdriver.Command
|
||||||
@@ -596,11 +600,20 @@ func (container *Container) Copy(resource string) (io.ReadCloser, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, m := range mounts {
|
for _, m := range mounts {
|
||||||
dest, err := container.GetResourcePath(m.Destination)
|
var dest string
|
||||||
|
dest, err = container.GetResourcePath(m.Destination)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := mount.Mount(m.Source, dest, "bind", "rbind,ro"); err != nil {
|
var stat os.FileInfo
|
||||||
|
stat, err = os.Stat(m.Source)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = fileutils.CreateIfNotExists(dest, stat.IsDir()); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = mount.Mount(m.Source, dest, "bind", "rbind,ro"); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1054,6 +1067,15 @@ func (container *Container) networkMounts() []execdriver.Mount {
|
|||||||
return mounts
|
return mounts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (container *Container) addBindMountPoint(name, source, destination string, rw bool) {
|
||||||
|
container.MountPoints[destination] = &mountPoint{
|
||||||
|
Name: name,
|
||||||
|
Source: source,
|
||||||
|
Destination: destination,
|
||||||
|
RW: rw,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (container *Container) addLocalMountPoint(name, destination string, rw bool) {
|
func (container *Container) addLocalMountPoint(name, destination string, rw bool) {
|
||||||
container.MountPoints[destination] = &mountPoint{
|
container.MountPoints[destination] = &mountPoint{
|
||||||
Name: name,
|
Name: name,
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ func getDevicesFromPath(deviceMapping runconfig.DeviceMapping) (devs []*configs.
|
|||||||
|
|
||||||
func populateCommand(c *Container, env []string) error {
|
func populateCommand(c *Container, env []string) error {
|
||||||
var en *execdriver.Network
|
var en *execdriver.Network
|
||||||
if !c.daemon.config.DisableNetwork {
|
if !c.Config.NetworkDisabled {
|
||||||
en = &execdriver.Network{
|
en = &execdriver.Network{
|
||||||
NamespacePath: c.NetworkSettings.SandboxKey,
|
NamespacePath: c.NetworkSettings.SandboxKey,
|
||||||
}
|
}
|
||||||
@@ -227,9 +227,10 @@ func populateCommand(c *Container, env []string) error {
|
|||||||
|
|
||||||
userSpecifiedDevices = append(userSpecifiedDevices, devs...)
|
userSpecifiedDevices = append(userSpecifiedDevices, devs...)
|
||||||
}
|
}
|
||||||
allowedDevices := append(configs.DefaultAllowedDevices, userSpecifiedDevices...)
|
|
||||||
|
|
||||||
autoCreatedDevices := append(configs.DefaultAutoCreatedDevices, userSpecifiedDevices...)
|
allowedDevices := mergeDevices(configs.DefaultAllowedDevices, userSpecifiedDevices)
|
||||||
|
|
||||||
|
autoCreatedDevices := mergeDevices(configs.DefaultAutoCreatedDevices, userSpecifiedDevices)
|
||||||
|
|
||||||
// TODO: this can be removed after lxc-conf is fully deprecated
|
// TODO: this can be removed after lxc-conf is fully deprecated
|
||||||
lxcConfig, err := mergeLxcConfIntoOptions(c.hostConfig)
|
lxcConfig, err := mergeLxcConfIntoOptions(c.hostConfig)
|
||||||
@@ -309,6 +310,25 @@ func populateCommand(c *Container, env []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mergeDevices(defaultDevices, userDevices []*configs.Device) []*configs.Device {
|
||||||
|
if len(userDevices) == 0 {
|
||||||
|
return defaultDevices
|
||||||
|
}
|
||||||
|
|
||||||
|
paths := map[string]*configs.Device{}
|
||||||
|
for _, d := range userDevices {
|
||||||
|
paths[d.Path] = d
|
||||||
|
}
|
||||||
|
|
||||||
|
var devs []*configs.Device
|
||||||
|
for _, d := range defaultDevices {
|
||||||
|
if _, defined := paths[d.Path]; !defined {
|
||||||
|
devs = append(devs, d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return append(devs, userDevices...)
|
||||||
|
}
|
||||||
|
|
||||||
// GetSize, return real size, virtual size
|
// GetSize, return real size, virtual size
|
||||||
func (container *Container) GetSize() (int64, int64) {
|
func (container *Container) GetSize() (int64, int64) {
|
||||||
var (
|
var (
|
||||||
@@ -449,7 +469,7 @@ func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, err
|
|||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c != nil && !container.daemon.config.DisableNetwork && container.hostConfig.NetworkMode.IsPrivate() {
|
if c != nil && !container.daemon.config.DisableBridge && container.hostConfig.NetworkMode.IsPrivate() {
|
||||||
logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", c.ID, ref.Name, container.NetworkSettings.IPAddress)
|
logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", c.ID, ref.Name, container.NetworkSettings.IPAddress)
|
||||||
joinOptions = append(joinOptions, libnetwork.JoinOptionParentUpdate(c.NetworkSettings.EndpointID, ref.Name, container.NetworkSettings.IPAddress))
|
joinOptions = append(joinOptions, libnetwork.JoinOptionParentUpdate(c.NetworkSettings.EndpointID, ref.Name, container.NetworkSettings.IPAddress))
|
||||||
if c.NetworkSettings.EndpointID != "" {
|
if c.NetworkSettings.EndpointID != "" {
|
||||||
@@ -493,13 +513,23 @@ func (container *Container) buildPortMapInfo(n libnetwork.Network, ep libnetwork
|
|||||||
networkSettings.MacAddress = mac.(net.HardwareAddr).String()
|
networkSettings.MacAddress = mac.(net.HardwareAddr).String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
networkSettings.Ports = nat.PortMap{}
|
||||||
|
|
||||||
|
if expData, ok := driverInfo[netlabel.ExposedPorts]; ok {
|
||||||
|
if exposedPorts, ok := expData.([]types.TransportPort); ok {
|
||||||
|
for _, tp := range exposedPorts {
|
||||||
|
natPort := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port)))
|
||||||
|
networkSettings.Ports[natPort] = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mapData, ok := driverInfo[netlabel.PortMap]
|
mapData, ok := driverInfo[netlabel.PortMap]
|
||||||
if !ok {
|
if !ok {
|
||||||
return networkSettings, nil
|
return networkSettings, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if portMapping, ok := mapData.([]types.PortBinding); ok {
|
if portMapping, ok := mapData.([]types.PortBinding); ok {
|
||||||
networkSettings.Ports = nat.PortMap{}
|
|
||||||
for _, pp := range portMapping {
|
for _, pp := range portMapping {
|
||||||
natPort := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
|
natPort := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
|
||||||
natBndg := nat.PortBinding{HostIp: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))}
|
natBndg := nat.PortBinding{HostIp: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))}
|
||||||
@@ -723,6 +753,11 @@ func (container *Container) AllocateNetwork() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if mode.IsBridge() && container.daemon.config.DisableBridge {
|
||||||
|
container.Config.NetworkDisabled = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
n, err := container.daemon.netController.NetworkByName(string(mode))
|
n, err := container.daemon.netController.NetworkByName(string(mode))
|
||||||
@@ -787,10 +822,6 @@ func (container *Container) initializeNetworking() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if container.daemon.config.DisableNetwork {
|
|
||||||
container.Config.NetworkDisabled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if container.hostConfig.NetworkMode.IsHost() {
|
if container.hostConfig.NetworkMode.IsHost() {
|
||||||
container.Config.Hostname, err = os.Hostname()
|
container.Config.Hostname, err = os.Hostname()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -909,7 +940,13 @@ func (container *Container) getNetworkedContainer() (*Container, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) ReleaseNetwork() {
|
func (container *Container) ReleaseNetwork() {
|
||||||
if container.hostConfig.NetworkMode.IsContainer() || container.daemon.config.DisableNetwork {
|
if container.hostConfig.NetworkMode.IsContainer() || container.Config.NetworkDisabled {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the container is not attached to any network do not try
|
||||||
|
// to release network and generate spurious error messages.
|
||||||
|
if container.NetworkSettings.NetworkID == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (daemon *Daemon) ContainerCreate(name string, config *runconfig.Config, hostConfig *runconfig.HostConfig) (string, []string, error) {
|
func (daemon *Daemon) ContainerCreate(name string, config *runconfig.Config, hostConfig *runconfig.HostConfig) (string, []string, error) {
|
||||||
|
if config == nil {
|
||||||
|
return "", nil, fmt.Errorf("Config cannot be empty in order to create a container")
|
||||||
|
}
|
||||||
|
|
||||||
warnings, err := daemon.verifyHostConfig(hostConfig)
|
warnings, err := daemon.verifyHostConfig(hostConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", warnings, err
|
return "", warnings, err
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@@ -31,6 +32,7 @@ import (
|
|||||||
"github.com/docker/docker/daemon/network"
|
"github.com/docker/docker/daemon/network"
|
||||||
"github.com/docker/docker/graph"
|
"github.com/docker/docker/graph"
|
||||||
"github.com/docker/docker/image"
|
"github.com/docker/docker/image"
|
||||||
|
"github.com/docker/docker/nat"
|
||||||
"github.com/docker/docker/pkg/archive"
|
"github.com/docker/docker/pkg/archive"
|
||||||
"github.com/docker/docker/pkg/broadcastwriter"
|
"github.com/docker/docker/pkg/broadcastwriter"
|
||||||
"github.com/docker/docker/pkg/fileutils"
|
"github.com/docker/docker/pkg/fileutils"
|
||||||
@@ -48,10 +50,9 @@ import (
|
|||||||
"github.com/docker/docker/utils"
|
"github.com/docker/docker/utils"
|
||||||
volumedrivers "github.com/docker/docker/volume/drivers"
|
volumedrivers "github.com/docker/docker/volume/drivers"
|
||||||
"github.com/docker/docker/volume/local"
|
"github.com/docker/docker/volume/local"
|
||||||
|
"github.com/docker/libcontainer/netlink"
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultVolumesPathName = "volumes"
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
validContainerNameChars = `[a-zA-Z0-9][a-zA-Z0-9_.-]`
|
validContainerNameChars = `[a-zA-Z0-9][a-zA-Z0-9_.-]`
|
||||||
validContainerNamePattern = regexp.MustCompile(`^/?` + validContainerNameChars + `+$`)
|
validContainerNamePattern = regexp.MustCompile(`^/?` + validContainerNameChars + `+$`)
|
||||||
@@ -158,12 +159,7 @@ func (daemon *Daemon) containerRoot(id string) string {
|
|||||||
// This is typically done at startup.
|
// This is typically done at startup.
|
||||||
func (daemon *Daemon) load(id string) (*Container, error) {
|
func (daemon *Daemon) load(id string) (*Container, error) {
|
||||||
container := &Container{
|
container := &Container{
|
||||||
CommonContainer: CommonContainer{
|
CommonContainer: daemon.newBaseContainer(id),
|
||||||
State: NewState(),
|
|
||||||
root: daemon.containerRoot(id),
|
|
||||||
MountPoints: make(map[string]*mountPoint),
|
|
||||||
execCommands: newExecStore(),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := container.FromDisk(); err != nil {
|
if err := container.FromDisk(); err != nil {
|
||||||
@@ -213,7 +209,7 @@ func (daemon *Daemon) register(container *Container, updateSuffixarray bool) err
|
|||||||
// we'll waste time if we update it for every container
|
// we'll waste time if we update it for every container
|
||||||
daemon.idIndex.Add(container.ID)
|
daemon.idIndex.Add(container.ID)
|
||||||
|
|
||||||
if err := daemon.verifyOldVolumesInfo(container); err != nil {
|
if err := daemon.verifyVolumesInfo(container); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -526,25 +522,21 @@ func (daemon *Daemon) newContainer(name string, config *runconfig.Config, imgID
|
|||||||
daemon.generateHostname(id, config)
|
daemon.generateHostname(id, config)
|
||||||
entrypoint, args := daemon.getEntrypointAndArgs(config.Entrypoint, config.Cmd)
|
entrypoint, args := daemon.getEntrypointAndArgs(config.Entrypoint, config.Cmd)
|
||||||
|
|
||||||
|
base := daemon.newBaseContainer(id)
|
||||||
|
base.Created = time.Now().UTC()
|
||||||
|
base.Path = entrypoint
|
||||||
|
base.Args = args //FIXME: de-duplicate from config
|
||||||
|
base.Config = config
|
||||||
|
base.hostConfig = &runconfig.HostConfig{}
|
||||||
|
base.ImageID = imgID
|
||||||
|
base.NetworkSettings = &network.Settings{}
|
||||||
|
base.Name = name
|
||||||
|
base.Driver = daemon.driver.String()
|
||||||
|
base.ExecDriver = daemon.execDriver.Name()
|
||||||
|
|
||||||
container := &Container{
|
container := &Container{
|
||||||
CommonContainer: CommonContainer{
|
CommonContainer: base,
|
||||||
ID: id, // FIXME: we should generate the ID here instead of receiving it as an argument
|
|
||||||
Created: time.Now().UTC(),
|
|
||||||
Path: entrypoint,
|
|
||||||
Args: args, //FIXME: de-duplicate from config
|
|
||||||
Config: config,
|
|
||||||
hostConfig: &runconfig.HostConfig{},
|
|
||||||
ImageID: imgID,
|
|
||||||
NetworkSettings: &network.Settings{},
|
|
||||||
Name: name,
|
|
||||||
Driver: daemon.driver.String(),
|
|
||||||
ExecDriver: daemon.execDriver.Name(),
|
|
||||||
State: NewState(),
|
|
||||||
execCommands: newExecStore(),
|
|
||||||
MountPoints: map[string]*mountPoint{},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
container.root = daemon.containerRoot(container.ID)
|
|
||||||
|
|
||||||
return container, err
|
return container, err
|
||||||
}
|
}
|
||||||
@@ -683,13 +675,15 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
|
|||||||
if config.Bridge.Iface != "" && config.Bridge.IP != "" {
|
if config.Bridge.Iface != "" && config.Bridge.IP != "" {
|
||||||
return nil, fmt.Errorf("You specified -b & --bip, mutually exclusive options. Please specify only one.")
|
return nil, fmt.Errorf("You specified -b & --bip, mutually exclusive options. Please specify only one.")
|
||||||
}
|
}
|
||||||
|
setDefaultMtu(config)
|
||||||
|
|
||||||
if !config.Bridge.EnableIPTables && !config.Bridge.InterContainerCommunication {
|
if !config.Bridge.EnableIPTables && !config.Bridge.InterContainerCommunication {
|
||||||
return nil, fmt.Errorf("You specified --iptables=false with --icc=false. ICC uses iptables to function. Please set --icc or --iptables to true.")
|
return nil, fmt.Errorf("You specified --iptables=false with --icc=false. ICC uses iptables to function. Please set --icc or --iptables to true.")
|
||||||
}
|
}
|
||||||
if !config.Bridge.EnableIPTables && config.Bridge.EnableIPMasq {
|
if !config.Bridge.EnableIPTables && config.Bridge.EnableIPMasq {
|
||||||
config.Bridge.EnableIPMasq = false
|
config.Bridge.EnableIPMasq = false
|
||||||
}
|
}
|
||||||
config.DisableNetwork = config.Bridge.Iface == disableNetworkBridge
|
config.DisableBridge = config.Bridge.Iface == disableNetworkBridge
|
||||||
|
|
||||||
// Check that the system is supported and we have sufficient privileges
|
// Check that the system is supported and we have sufficient privileges
|
||||||
if runtime.GOOS != "linux" {
|
if runtime.GOOS != "linux" {
|
||||||
@@ -792,7 +786,7 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
volumesDriver, err := local.New(filepath.Join(config.Root, defaultVolumesPathName))
|
volumesDriver, err := local.New(config.Root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -826,11 +820,9 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
|
|||||||
return nil, fmt.Errorf("Couldn't create Tag store: %s", err)
|
return nil, fmt.Errorf("Couldn't create Tag store: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !config.DisableNetwork {
|
d.netController, err = initNetworkController(config)
|
||||||
d.netController, err = initNetworkController(config)
|
if err != nil {
|
||||||
if err != nil {
|
return nil, fmt.Errorf("Error initializing network controller: %v", err)
|
||||||
return nil, fmt.Errorf("Error initializing network controller: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
graphdbPath := path.Join(config.Root, "linkgraph.db")
|
graphdbPath := path.Join(config.Root, "linkgraph.db")
|
||||||
@@ -918,12 +910,22 @@ func initNetworkController(config *Config) (libnetwork.NetworkController, error)
|
|||||||
return nil, fmt.Errorf("Error creating default \"host\" network: %v", err)
|
return nil, fmt.Errorf("Error creating default \"host\" network: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize default driver "bridge"
|
if !config.DisableBridge {
|
||||||
|
// Initialize default driver "bridge"
|
||||||
|
if err := initBridgeDriver(controller, config); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return controller, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error {
|
||||||
option := options.Generic{
|
option := options.Generic{
|
||||||
"EnableIPForwarding": config.Bridge.EnableIPForward}
|
"EnableIPForwarding": config.Bridge.EnableIPForward}
|
||||||
|
|
||||||
if err := controller.ConfigureNetworkDriver("bridge", options.Generic{netlabel.GenericData: option}); err != nil {
|
if err := controller.ConfigureNetworkDriver("bridge", options.Generic{netlabel.GenericData: option}); err != nil {
|
||||||
return nil, fmt.Errorf("Error initializing bridge driver: %v", err)
|
return fmt.Errorf("Error initializing bridge driver: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
netOption := options.Generic{
|
netOption := options.Generic{
|
||||||
@@ -938,7 +940,7 @@ func initNetworkController(config *Config) (libnetwork.NetworkController, error)
|
|||||||
if config.Bridge.IP != "" {
|
if config.Bridge.IP != "" {
|
||||||
ip, bipNet, err := net.ParseCIDR(config.Bridge.IP)
|
ip, bipNet, err := net.ParseCIDR(config.Bridge.IP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
bipNet.IP = ip
|
bipNet.IP = ip
|
||||||
@@ -948,7 +950,7 @@ func initNetworkController(config *Config) (libnetwork.NetworkController, error)
|
|||||||
if config.Bridge.FixedCIDR != "" {
|
if config.Bridge.FixedCIDR != "" {
|
||||||
_, fCIDR, err := net.ParseCIDR(config.Bridge.FixedCIDR)
|
_, fCIDR, err := net.ParseCIDR(config.Bridge.FixedCIDR)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
netOption["FixedCIDR"] = fCIDR
|
netOption["FixedCIDR"] = fCIDR
|
||||||
@@ -957,41 +959,38 @@ func initNetworkController(config *Config) (libnetwork.NetworkController, error)
|
|||||||
if config.Bridge.FixedCIDRv6 != "" {
|
if config.Bridge.FixedCIDRv6 != "" {
|
||||||
_, fCIDRv6, err := net.ParseCIDR(config.Bridge.FixedCIDRv6)
|
_, fCIDRv6, err := net.ParseCIDR(config.Bridge.FixedCIDRv6)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
netOption["FixedCIDRv6"] = fCIDRv6
|
netOption["FixedCIDRv6"] = fCIDRv6
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.Bridge.DefaultGatewayIPv4 != nil {
|
||||||
|
netOption["DefaultGatewayIPv4"] = config.Bridge.DefaultGatewayIPv4
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Bridge.DefaultGatewayIPv6 != nil {
|
||||||
|
netOption["DefaultGatewayIPv6"] = config.Bridge.DefaultGatewayIPv6
|
||||||
|
}
|
||||||
|
|
||||||
// --ip processing
|
// --ip processing
|
||||||
if config.Bridge.DefaultIP != nil {
|
if config.Bridge.DefaultIP != nil {
|
||||||
netOption["DefaultBindingIP"] = config.Bridge.DefaultIP
|
netOption["DefaultBindingIP"] = config.Bridge.DefaultIP
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize default network on "bridge" with the same name
|
// Initialize default network on "bridge" with the same name
|
||||||
_, err = controller.NewNetwork("bridge", "bridge",
|
_, err := controller.NewNetwork("bridge", "bridge",
|
||||||
libnetwork.NetworkOptionGeneric(options.Generic{
|
libnetwork.NetworkOptionGeneric(options.Generic{
|
||||||
netlabel.GenericData: netOption,
|
netlabel.GenericData: netOption,
|
||||||
netlabel.EnableIPv6: config.Bridge.EnableIPv6,
|
netlabel.EnableIPv6: config.Bridge.EnableIPv6,
|
||||||
}))
|
}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Error creating default \"bridge\" network: %v", err)
|
return fmt.Errorf("Error creating default \"bridge\" network: %v", err)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
return controller, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) Shutdown() error {
|
func (daemon *Daemon) Shutdown() error {
|
||||||
if daemon.containerGraph != nil {
|
|
||||||
if err := daemon.containerGraph.Close(); err != nil {
|
|
||||||
logrus.Errorf("Error during container graph.Close(): %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if daemon.driver != nil {
|
|
||||||
if err := daemon.driver.Cleanup(); err != nil {
|
|
||||||
logrus.Errorf("Error during graph storage driver.Cleanup(): %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if daemon.containers != nil {
|
if daemon.containers != nil {
|
||||||
group := sync.WaitGroup{}
|
group := sync.WaitGroup{}
|
||||||
logrus.Debug("starting clean shutdown of all containers...")
|
logrus.Debug("starting clean shutdown of all containers...")
|
||||||
@@ -1003,8 +1002,9 @@ func (daemon *Daemon) Shutdown() error {
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer group.Done()
|
defer group.Done()
|
||||||
if err := c.KillSig(15); err != nil {
|
// If container failed to exit in 10 seconds of SIGTERM, then using the force
|
||||||
logrus.Debugf("kill 15 error for %s - %s", c.ID, err)
|
if err := c.Stop(10); err != nil {
|
||||||
|
logrus.Errorf("Stop container %s with error: %v", c.ID, err)
|
||||||
}
|
}
|
||||||
c.WaitStop(-1 * time.Second)
|
c.WaitStop(-1 * time.Second)
|
||||||
logrus.Debugf("container stopped %s", c.ID)
|
logrus.Debugf("container stopped %s", c.ID)
|
||||||
@@ -1012,6 +1012,23 @@ func (daemon *Daemon) Shutdown() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
group.Wait()
|
group.Wait()
|
||||||
|
|
||||||
|
// trigger libnetwork GC only if it's initialized
|
||||||
|
if daemon.netController != nil {
|
||||||
|
daemon.netController.GC()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if daemon.containerGraph != nil {
|
||||||
|
if err := daemon.containerGraph.Close(); err != nil {
|
||||||
|
logrus.Errorf("Error during container graph.Close(): %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if daemon.driver != nil {
|
||||||
|
if err := daemon.driver.Cleanup(); err != nil {
|
||||||
|
logrus.Errorf("Error during graph storage driver.Cleanup(): %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -1181,6 +1198,13 @@ func (daemon *Daemon) verifyHostConfig(hostConfig *runconfig.HostConfig) ([]stri
|
|||||||
return warnings, nil
|
return warnings, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for port := range hostConfig.PortBindings {
|
||||||
|
_, portStr := nat.SplitProtoPort(string(port))
|
||||||
|
if _, err := nat.ParsePort(portStr); err != nil {
|
||||||
|
return warnings, fmt.Errorf("Invalid port specification: %s", portStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if hostConfig.LxcConf.Len() > 0 && !strings.Contains(daemon.ExecutionDriver().Name(), "lxc") {
|
if hostConfig.LxcConf.Len() > 0 && !strings.Contains(daemon.ExecutionDriver().Name(), "lxc") {
|
||||||
return warnings, fmt.Errorf("Cannot use --lxc-conf with execdriver: %s", daemon.ExecutionDriver().Name())
|
return warnings, fmt.Errorf("Cannot use --lxc-conf with execdriver: %s", daemon.ExecutionDriver().Name())
|
||||||
}
|
}
|
||||||
@@ -1245,3 +1269,42 @@ func (daemon *Daemon) setHostConfig(container *Container, hostConfig *runconfig.
|
|||||||
container.toDisk()
|
container.toDisk()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (daemon *Daemon) newBaseContainer(id string) CommonContainer {
|
||||||
|
return CommonContainer{
|
||||||
|
ID: id,
|
||||||
|
State: NewState(),
|
||||||
|
MountPoints: make(map[string]*mountPoint),
|
||||||
|
Volumes: make(map[string]string),
|
||||||
|
VolumesRW: make(map[string]bool),
|
||||||
|
execCommands: newExecStore(),
|
||||||
|
root: daemon.containerRoot(id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setDefaultMtu(config *Config) {
|
||||||
|
// do nothing if the config does not have the default 0 value.
|
||||||
|
if config.Mtu != 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
config.Mtu = defaultNetworkMtu
|
||||||
|
if routeMtu, err := getDefaultRouteMtu(); err == nil {
|
||||||
|
config.Mtu = routeMtu
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var errNoDefaultRoute = errors.New("no default route was found")
|
||||||
|
|
||||||
|
// getDefaultRouteMtu returns the MTU for the default route's interface.
|
||||||
|
func getDefaultRouteMtu() (int, error) {
|
||||||
|
routes, err := netlink.NetworkGetRoutes()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
for _, r := range routes {
|
||||||
|
if r.Default {
|
||||||
|
return r.Iface.MTU, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, errNoDefaultRoute
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import (
|
|||||||
"github.com/docker/docker/pkg/stringid"
|
"github.com/docker/docker/pkg/stringid"
|
||||||
"github.com/docker/docker/pkg/truncindex"
|
"github.com/docker/docker/pkg/truncindex"
|
||||||
"github.com/docker/docker/volume"
|
"github.com/docker/docker/volume"
|
||||||
|
"github.com/docker/docker/volume/drivers"
|
||||||
|
"github.com/docker/docker/volume/local"
|
||||||
)
|
)
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -129,12 +131,25 @@ func TestLoadWithVolume(t *testing.T) {
|
|||||||
|
|
||||||
containerId := "d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e"
|
containerId := "d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e"
|
||||||
containerPath := filepath.Join(tmp, containerId)
|
containerPath := filepath.Join(tmp, containerId)
|
||||||
if err = os.MkdirAll(containerPath, 0755); err != nil {
|
if err := os.MkdirAll(containerPath, 0755); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
hostVolumeId := stringid.GenerateRandomID()
|
hostVolumeId := stringid.GenerateRandomID()
|
||||||
volumePath := filepath.Join(tmp, "vfs", "dir", hostVolumeId)
|
vfsPath := filepath.Join(tmp, "vfs", "dir", hostVolumeId)
|
||||||
|
volumePath := filepath.Join(tmp, "volumes", hostVolumeId)
|
||||||
|
|
||||||
|
if err := os.MkdirAll(vfsPath, 0755); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := os.MkdirAll(volumePath, 0755); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
content := filepath.Join(vfsPath, "helo")
|
||||||
|
if err := ioutil.WriteFile(content, []byte("HELO"), 0644); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
config := `{"State":{"Running":true,"Paused":false,"Restarting":false,"OOMKilled":false,"Dead":false,"Pid":2464,"ExitCode":0,
|
config := `{"State":{"Running":true,"Paused":false,"Restarting":false,"OOMKilled":false,"Dead":false,"Pid":2464,"ExitCode":0,
|
||||||
"Error":"","StartedAt":"2015-05-26T16:48:53.869308965Z","FinishedAt":"0001-01-01T00:00:00Z"},
|
"Error":"","StartedAt":"2015-05-26T16:48:53.869308965Z","FinishedAt":"0001-01-01T00:00:00Z"},
|
||||||
@@ -152,7 +167,7 @@ func TestLoadWithVolume(t *testing.T) {
|
|||||||
"Name":"/ubuntu","Driver":"aufs","ExecDriver":"native-0.2","MountLabel":"","ProcessLabel":"","AppArmorProfile":"","RestartCount":0,
|
"Name":"/ubuntu","Driver":"aufs","ExecDriver":"native-0.2","MountLabel":"","ProcessLabel":"","AppArmorProfile":"","RestartCount":0,
|
||||||
"UpdateDns":false,"Volumes":{"/vol1":"%s"},"VolumesRW":{"/vol1":true},"AppliedVolumesFrom":null}`
|
"UpdateDns":false,"Volumes":{"/vol1":"%s"},"VolumesRW":{"/vol1":true},"AppliedVolumesFrom":null}`
|
||||||
|
|
||||||
cfg := fmt.Sprintf(config, volumePath)
|
cfg := fmt.Sprintf(config, vfsPath)
|
||||||
if err = ioutil.WriteFile(filepath.Join(containerPath, "config.json"), []byte(cfg), 0644); err != nil {
|
if err = ioutil.WriteFile(filepath.Join(containerPath, "config.json"), []byte(cfg), 0644); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -165,21 +180,18 @@ func TestLoadWithVolume(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = os.MkdirAll(volumePath, 0755); err != nil {
|
daemon, err := initDaemonForVolumesTest(tmp)
|
||||||
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
defer volumedrivers.Unregister(volume.DefaultDriverName)
|
||||||
daemon := &Daemon{
|
|
||||||
repository: tmp,
|
|
||||||
root: tmp,
|
|
||||||
}
|
|
||||||
|
|
||||||
c, err := daemon.load(containerId)
|
c, err := daemon.load(containerId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = daemon.verifyOldVolumesInfo(c)
|
err = daemon.verifyVolumesInfo(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -204,4 +216,301 @@ func TestLoadWithVolume(t *testing.T) {
|
|||||||
if m.Driver != volume.DefaultDriverName {
|
if m.Driver != volume.DefaultDriverName {
|
||||||
t.Fatalf("Expected mount driver local, was %s\n", m.Driver)
|
t.Fatalf("Expected mount driver local, was %s\n", m.Driver)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newVolumeContent := filepath.Join(volumePath, local.VolumeDataPathName, "helo")
|
||||||
|
b, err := ioutil.ReadFile(newVolumeContent)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if string(b) != "HELO" {
|
||||||
|
t.Fatalf("Expected HELO, was %s\n", string(b))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoadWithBindMount(t *testing.T) {
|
||||||
|
tmp, err := ioutil.TempDir("", "docker-daemon-test-")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmp)
|
||||||
|
|
||||||
|
containerId := "d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e"
|
||||||
|
containerPath := filepath.Join(tmp, containerId)
|
||||||
|
if err = os.MkdirAll(containerPath, 0755); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
config := `{"State":{"Running":true,"Paused":false,"Restarting":false,"OOMKilled":false,"Dead":false,"Pid":2464,"ExitCode":0,
|
||||||
|
"Error":"","StartedAt":"2015-05-26T16:48:53.869308965Z","FinishedAt":"0001-01-01T00:00:00Z"},
|
||||||
|
"ID":"d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e","Created":"2015-05-26T16:48:53.7987917Z","Path":"top",
|
||||||
|
"Args":[],"Config":{"Hostname":"d59df5276e7b","Domainname":"","User":"","Memory":0,"MemorySwap":0,"CpuShares":0,"Cpuset":"",
|
||||||
|
"AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"PortSpecs":null,"ExposedPorts":null,"Tty":true,"OpenStdin":true,
|
||||||
|
"StdinOnce":false,"Env":null,"Cmd":["top"],"Image":"ubuntu:latest","Volumes":null,"WorkingDir":"","Entrypoint":null,
|
||||||
|
"NetworkDisabled":false,"MacAddress":"","OnBuild":null,"Labels":{}},"Image":"07f8e8c5e66084bef8f848877857537ffe1c47edd01a93af27e7161672ad0e95",
|
||||||
|
"NetworkSettings":{"IPAddress":"172.17.0.1","IPPrefixLen":16,"MacAddress":"02:42:ac:11:00:01","LinkLocalIPv6Address":"fe80::42:acff:fe11:1",
|
||||||
|
"LinkLocalIPv6PrefixLen":64,"GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"Gateway":"172.17.42.1","IPv6Gateway":"","Bridge":"docker0","PortMapping":null,"Ports":{}},
|
||||||
|
"ResolvConfPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/resolv.conf",
|
||||||
|
"HostnamePath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/hostname",
|
||||||
|
"HostsPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/hosts",
|
||||||
|
"LogPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e-json.log",
|
||||||
|
"Name":"/ubuntu","Driver":"aufs","ExecDriver":"native-0.2","MountLabel":"","ProcessLabel":"","AppArmorProfile":"","RestartCount":0,
|
||||||
|
"UpdateDns":false,"Volumes":{"/vol1": "/vol1"},"VolumesRW":{"/vol1":true},"AppliedVolumesFrom":null}`
|
||||||
|
|
||||||
|
if err = ioutil.WriteFile(filepath.Join(containerPath, "config.json"), []byte(config), 0644); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hostConfig := `{"Binds":["/vol1:/vol1"],"ContainerIDFile":"","LxcConf":[],"Memory":0,"MemorySwap":0,"CpuShares":0,"CpusetCpus":"",
|
||||||
|
"Privileged":false,"PortBindings":{},"Links":null,"PublishAllPorts":false,"Dns":null,"DnsSearch":null,"ExtraHosts":null,"VolumesFrom":null,
|
||||||
|
"Devices":[],"NetworkMode":"bridge","IpcMode":"","PidMode":"","CapAdd":null,"CapDrop":null,"RestartPolicy":{"Name":"no","MaximumRetryCount":0},
|
||||||
|
"SecurityOpt":null,"ReadonlyRootfs":false,"Ulimits":null,"LogConfig":{"Type":"","Config":null},"CgroupParent":""}`
|
||||||
|
if err = ioutil.WriteFile(filepath.Join(containerPath, "hostconfig.json"), []byte(hostConfig), 0644); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
daemon, err := initDaemonForVolumesTest(tmp)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer volumedrivers.Unregister(volume.DefaultDriverName)
|
||||||
|
|
||||||
|
c, err := daemon.load(containerId)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = daemon.verifyVolumesInfo(c)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.MountPoints) != 1 {
|
||||||
|
t.Fatalf("Expected 1 volume mounted, was 0\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
m := c.MountPoints["/vol1"]
|
||||||
|
if m.Name != "" {
|
||||||
|
t.Fatalf("Expected empty mount name, was %s\n", m.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Source != "/vol1" {
|
||||||
|
t.Fatalf("Expected mount source /vol1, was %s\n", m.Source)
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Destination != "/vol1" {
|
||||||
|
t.Fatalf("Expected mount destination /vol1, was %s\n", m.Destination)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !m.RW {
|
||||||
|
t.Fatalf("Expected mount point to be RW but it was not\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoadWithVolume17RC(t *testing.T) {
|
||||||
|
tmp, err := ioutil.TempDir("", "docker-daemon-test-")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmp)
|
||||||
|
|
||||||
|
containerId := "d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e"
|
||||||
|
containerPath := filepath.Join(tmp, containerId)
|
||||||
|
if err := os.MkdirAll(containerPath, 0755); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hostVolumeId := "6a3c03fc4a4e588561a543cc3bdd50089e27bd11bbb0e551e19bf735e2514101"
|
||||||
|
volumePath := filepath.Join(tmp, "volumes", hostVolumeId)
|
||||||
|
|
||||||
|
if err := os.MkdirAll(volumePath, 0755); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
content := filepath.Join(volumePath, "helo")
|
||||||
|
if err := ioutil.WriteFile(content, []byte("HELO"), 0644); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
config := `{"State":{"Running":true,"Paused":false,"Restarting":false,"OOMKilled":false,"Dead":false,"Pid":2464,"ExitCode":0,
|
||||||
|
"Error":"","StartedAt":"2015-05-26T16:48:53.869308965Z","FinishedAt":"0001-01-01T00:00:00Z"},
|
||||||
|
"ID":"d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e","Created":"2015-05-26T16:48:53.7987917Z","Path":"top",
|
||||||
|
"Args":[],"Config":{"Hostname":"d59df5276e7b","Domainname":"","User":"","Memory":0,"MemorySwap":0,"CpuShares":0,"Cpuset":"",
|
||||||
|
"AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"PortSpecs":null,"ExposedPorts":null,"Tty":true,"OpenStdin":true,
|
||||||
|
"StdinOnce":false,"Env":null,"Cmd":["top"],"Image":"ubuntu:latest","Volumes":null,"WorkingDir":"","Entrypoint":null,
|
||||||
|
"NetworkDisabled":false,"MacAddress":"","OnBuild":null,"Labels":{}},"Image":"07f8e8c5e66084bef8f848877857537ffe1c47edd01a93af27e7161672ad0e95",
|
||||||
|
"NetworkSettings":{"IPAddress":"172.17.0.1","IPPrefixLen":16,"MacAddress":"02:42:ac:11:00:01","LinkLocalIPv6Address":"fe80::42:acff:fe11:1",
|
||||||
|
"LinkLocalIPv6PrefixLen":64,"GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"Gateway":"172.17.42.1","IPv6Gateway":"","Bridge":"docker0","PortMapping":null,"Ports":{}},
|
||||||
|
"ResolvConfPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/resolv.conf",
|
||||||
|
"HostnamePath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/hostname",
|
||||||
|
"HostsPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/hosts",
|
||||||
|
"LogPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e-json.log",
|
||||||
|
"Name":"/ubuntu","Driver":"aufs","ExecDriver":"native-0.2","MountLabel":"","ProcessLabel":"","AppArmorProfile":"","RestartCount":0,
|
||||||
|
"UpdateDns":false,"MountPoints":{"/vol1":{"Name":"6a3c03fc4a4e588561a543cc3bdd50089e27bd11bbb0e551e19bf735e2514101","Destination":"/vol1","Driver":"local","RW":true,"Source":"","Relabel":""}},"AppliedVolumesFrom":null}`
|
||||||
|
|
||||||
|
if err = ioutil.WriteFile(filepath.Join(containerPath, "config.json"), []byte(config), 0644); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hostConfig := `{"Binds":[],"ContainerIDFile":"","LxcConf":[],"Memory":0,"MemorySwap":0,"CpuShares":0,"CpusetCpus":"",
|
||||||
|
"Privileged":false,"PortBindings":{},"Links":null,"PublishAllPorts":false,"Dns":null,"DnsSearch":null,"ExtraHosts":null,"VolumesFrom":null,
|
||||||
|
"Devices":[],"NetworkMode":"bridge","IpcMode":"","PidMode":"","CapAdd":null,"CapDrop":null,"RestartPolicy":{"Name":"no","MaximumRetryCount":0},
|
||||||
|
"SecurityOpt":null,"ReadonlyRootfs":false,"Ulimits":null,"LogConfig":{"Type":"","Config":null},"CgroupParent":""}`
|
||||||
|
if err = ioutil.WriteFile(filepath.Join(containerPath, "hostconfig.json"), []byte(hostConfig), 0644); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
daemon, err := initDaemonForVolumesTest(tmp)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer volumedrivers.Unregister(volume.DefaultDriverName)
|
||||||
|
|
||||||
|
c, err := daemon.load(containerId)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = daemon.verifyVolumesInfo(c)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.MountPoints) != 1 {
|
||||||
|
t.Fatalf("Expected 1 volume mounted, was 0\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
m := c.MountPoints["/vol1"]
|
||||||
|
if m.Name != hostVolumeId {
|
||||||
|
t.Fatalf("Expected mount name to be %s, was %s\n", hostVolumeId, m.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Destination != "/vol1" {
|
||||||
|
t.Fatalf("Expected mount destination /vol1, was %s\n", m.Destination)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !m.RW {
|
||||||
|
t.Fatalf("Expected mount point to be RW but it was not\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Driver != volume.DefaultDriverName {
|
||||||
|
t.Fatalf("Expected mount driver local, was %s\n", m.Driver)
|
||||||
|
}
|
||||||
|
|
||||||
|
newVolumeContent := filepath.Join(volumePath, local.VolumeDataPathName, "helo")
|
||||||
|
b, err := ioutil.ReadFile(newVolumeContent)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if string(b) != "HELO" {
|
||||||
|
t.Fatalf("Expected HELO, was %s\n", string(b))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemoveLocalVolumesFollowingSymlinks(t *testing.T) {
|
||||||
|
tmp, err := ioutil.TempDir("", "docker-daemon-test-")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmp)
|
||||||
|
|
||||||
|
containerId := "d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e"
|
||||||
|
containerPath := filepath.Join(tmp, containerId)
|
||||||
|
if err := os.MkdirAll(containerPath, 0755); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hostVolumeId := stringid.GenerateRandomID()
|
||||||
|
vfsPath := filepath.Join(tmp, "vfs", "dir", hostVolumeId)
|
||||||
|
volumePath := filepath.Join(tmp, "volumes", hostVolumeId)
|
||||||
|
|
||||||
|
if err := os.MkdirAll(vfsPath, 0755); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := os.MkdirAll(volumePath, 0755); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
content := filepath.Join(vfsPath, "helo")
|
||||||
|
if err := ioutil.WriteFile(content, []byte("HELO"), 0644); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
config := `{"State":{"Running":true,"Paused":false,"Restarting":false,"OOMKilled":false,"Dead":false,"Pid":2464,"ExitCode":0,
|
||||||
|
"Error":"","StartedAt":"2015-05-26T16:48:53.869308965Z","FinishedAt":"0001-01-01T00:00:00Z"},
|
||||||
|
"ID":"d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e","Created":"2015-05-26T16:48:53.7987917Z","Path":"top",
|
||||||
|
"Args":[],"Config":{"Hostname":"d59df5276e7b","Domainname":"","User":"","Memory":0,"MemorySwap":0,"CpuShares":0,"Cpuset":"",
|
||||||
|
"AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"PortSpecs":null,"ExposedPorts":null,"Tty":true,"OpenStdin":true,
|
||||||
|
"StdinOnce":false,"Env":null,"Cmd":["top"],"Image":"ubuntu:latest","Volumes":null,"WorkingDir":"","Entrypoint":null,
|
||||||
|
"NetworkDisabled":false,"MacAddress":"","OnBuild":null,"Labels":{}},"Image":"07f8e8c5e66084bef8f848877857537ffe1c47edd01a93af27e7161672ad0e95",
|
||||||
|
"NetworkSettings":{"IPAddress":"172.17.0.1","IPPrefixLen":16,"MacAddress":"02:42:ac:11:00:01","LinkLocalIPv6Address":"fe80::42:acff:fe11:1",
|
||||||
|
"LinkLocalIPv6PrefixLen":64,"GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"Gateway":"172.17.42.1","IPv6Gateway":"","Bridge":"docker0","PortMapping":null,"Ports":{}},
|
||||||
|
"ResolvConfPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/resolv.conf",
|
||||||
|
"HostnamePath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/hostname",
|
||||||
|
"HostsPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/hosts",
|
||||||
|
"LogPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e-json.log",
|
||||||
|
"Name":"/ubuntu","Driver":"aufs","ExecDriver":"native-0.2","MountLabel":"","ProcessLabel":"","AppArmorProfile":"","RestartCount":0,
|
||||||
|
"UpdateDns":false,"Volumes":{"/vol1":"%s"},"VolumesRW":{"/vol1":true},"AppliedVolumesFrom":null}`
|
||||||
|
|
||||||
|
cfg := fmt.Sprintf(config, vfsPath)
|
||||||
|
if err = ioutil.WriteFile(filepath.Join(containerPath, "config.json"), []byte(cfg), 0644); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hostConfig := `{"Binds":[],"ContainerIDFile":"","LxcConf":[],"Memory":0,"MemorySwap":0,"CpuShares":0,"CpusetCpus":"",
|
||||||
|
"Privileged":false,"PortBindings":{},"Links":null,"PublishAllPorts":false,"Dns":null,"DnsSearch":null,"ExtraHosts":null,"VolumesFrom":null,
|
||||||
|
"Devices":[],"NetworkMode":"bridge","IpcMode":"","PidMode":"","CapAdd":null,"CapDrop":null,"RestartPolicy":{"Name":"no","MaximumRetryCount":0},
|
||||||
|
"SecurityOpt":null,"ReadonlyRootfs":false,"Ulimits":null,"LogConfig":{"Type":"","Config":null},"CgroupParent":""}`
|
||||||
|
if err = ioutil.WriteFile(filepath.Join(containerPath, "hostconfig.json"), []byte(hostConfig), 0644); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
daemon, err := initDaemonForVolumesTest(tmp)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer volumedrivers.Unregister(volume.DefaultDriverName)
|
||||||
|
|
||||||
|
c, err := daemon.load(containerId)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = daemon.verifyVolumesInfo(c)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.MountPoints) != 1 {
|
||||||
|
t.Fatalf("Expected 1 volume mounted, was 0\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
m := c.MountPoints["/vol1"]
|
||||||
|
v, err := createVolume(m.Name, m.Driver)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := removeVolume(v); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fi, err := os.Stat(vfsPath)
|
||||||
|
if err == nil || !os.IsNotExist(err) {
|
||||||
|
t.Fatalf("Expected vfs path to not exist: %v - %v\n", fi, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func initDaemonForVolumesTest(tmp string) (*Daemon, error) {
|
||||||
|
daemon := &Daemon{
|
||||||
|
repository: tmp,
|
||||||
|
root: tmp,
|
||||||
|
}
|
||||||
|
|
||||||
|
volumesDriver, err := local.New(tmp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
volumedrivers.Register(volumesDriver, volumesDriver.Name())
|
||||||
|
|
||||||
|
return daemon, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,7 +109,6 @@ func (d *Daemon) getActiveContainer(name string) (*Container, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *Daemon) ContainerExecCreate(config *runconfig.ExecConfig) (string, error) {
|
func (d *Daemon) ContainerExecCreate(config *runconfig.ExecConfig) (string, error) {
|
||||||
|
|
||||||
// Not all drivers support Exec (LXC for example)
|
// Not all drivers support Exec (LXC for example)
|
||||||
if err := checkExecSupport(d.execDriver.Name()); err != nil {
|
if err := checkExecSupport(d.execDriver.Name()); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -123,11 +122,16 @@ func (d *Daemon) ContainerExecCreate(config *runconfig.ExecConfig) (string, erro
|
|||||||
cmd := runconfig.NewCommand(config.Cmd...)
|
cmd := runconfig.NewCommand(config.Cmd...)
|
||||||
entrypoint, args := d.getEntrypointAndArgs(runconfig.NewEntrypoint(), cmd)
|
entrypoint, args := d.getEntrypointAndArgs(runconfig.NewEntrypoint(), cmd)
|
||||||
|
|
||||||
|
user := config.User
|
||||||
|
if len(user) == 0 {
|
||||||
|
user = container.Config.User
|
||||||
|
}
|
||||||
|
|
||||||
processConfig := execdriver.ProcessConfig{
|
processConfig := execdriver.ProcessConfig{
|
||||||
Tty: config.Tty,
|
Tty: config.Tty,
|
||||||
Entrypoint: entrypoint,
|
Entrypoint: entrypoint,
|
||||||
Arguments: args,
|
Arguments: args,
|
||||||
User: config.User,
|
User: user,
|
||||||
}
|
}
|
||||||
|
|
||||||
execConfig := &execConfig{
|
execConfig := &execConfig{
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ func InitContainer(c *Command) *configs.Config {
|
|||||||
container.Devices = c.AutoCreatedDevices
|
container.Devices = c.AutoCreatedDevices
|
||||||
container.Rootfs = c.Rootfs
|
container.Rootfs = c.Rootfs
|
||||||
container.Readonlyfs = c.ReadonlyRootfs
|
container.Readonlyfs = c.ReadonlyRootfs
|
||||||
|
container.Privatefs = true
|
||||||
|
|
||||||
// check to see if we are running in ramdisk to disable pivot root
|
// check to see if we are running in ramdisk to disable pivot root
|
||||||
container.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != ""
|
container.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != ""
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
|
|||||||
dataPath = d.containerDir(c.ID)
|
dataPath = d.containerDir(c.ID)
|
||||||
)
|
)
|
||||||
|
|
||||||
if c.Network.NamespacePath == "" && c.Network.ContainerID == "" {
|
if c.Network == nil || (c.Network.NamespacePath == "" && c.Network.ContainerID == "") {
|
||||||
return execdriver.ExitStatus{ExitCode: -1}, fmt.Errorf("empty namespace path for non-container network")
|
return execdriver.ExitStatus{ExitCode: -1}, fmt.Errorf("empty namespace path for non-container network")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,8 +104,8 @@ type DeviceSet struct {
|
|||||||
thinpBlockSize uint32
|
thinpBlockSize uint32
|
||||||
thinPoolDevice string
|
thinPoolDevice string
|
||||||
Transaction `json:"-"`
|
Transaction `json:"-"`
|
||||||
overrideUdevSyncCheck bool
|
|
||||||
deferredRemove bool // use deferred removal
|
deferredRemove bool // use deferred removal
|
||||||
|
overrideUdevSyncCheck bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type DiskUsage struct {
|
type DiskUsage struct {
|
||||||
@@ -1033,10 +1033,7 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
|
|||||||
|
|
||||||
// https://github.com/docker/docker/issues/4036
|
// https://github.com/docker/docker/issues/4036
|
||||||
if supported := devicemapper.UdevSetSyncSupport(true); !supported {
|
if supported := devicemapper.UdevSetSyncSupport(true); !supported {
|
||||||
logrus.Errorf("Udev sync is not supported. This will lead to unexpected behavior, data loss and errors. For more information, see https://docs.docker.com/reference/commandline/cli/#daemon-storage-driver-option")
|
logrus.Warn("Udev sync is not supported. This will lead to unexpected behavior, data loss and errors. For more information, see https://docs.docker.com/reference/commandline/cli/#daemon-storage-driver-option")
|
||||||
if !devices.overrideUdevSyncCheck {
|
|
||||||
return graphdriver.ErrNotSupported
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.MkdirAll(devices.metadataDir(), 0700); err != nil && !os.IsExist(err) {
|
if err := os.MkdirAll(devices.metadataDir(), 0700); err != nil && !os.IsExist(err) {
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ func scanPriorDrivers(root string) []string {
|
|||||||
priorDrivers := []string{}
|
priorDrivers := []string{}
|
||||||
for driver := range drivers {
|
for driver := range drivers {
|
||||||
p := filepath.Join(root, driver)
|
p := filepath.Join(root, driver)
|
||||||
if _, err := os.Stat(p); err == nil {
|
if _, err := os.Stat(p); err == nil && driver != "vfs" {
|
||||||
priorDrivers = append(priorDrivers, driver)
|
priorDrivers = append(priorDrivers, driver)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import (
|
|||||||
"github.com/docker/docker/daemon/graphdriver"
|
"github.com/docker/docker/daemon/graphdriver"
|
||||||
"github.com/docker/docker/pkg/mount"
|
"github.com/docker/docker/pkg/mount"
|
||||||
"github.com/docker/docker/pkg/parsers"
|
"github.com/docker/docker/pkg/parsers"
|
||||||
|
"github.com/docker/libcontainer/label"
|
||||||
zfs "github.com/mistifyio/go-zfs"
|
zfs "github.com/mistifyio/go-zfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -281,14 +282,15 @@ func (d *Driver) Remove(id string) error {
|
|||||||
func (d *Driver) Get(id, mountLabel string) (string, error) {
|
func (d *Driver) Get(id, mountLabel string) (string, error) {
|
||||||
mountpoint := d.MountPath(id)
|
mountpoint := d.MountPath(id)
|
||||||
filesystem := d.ZfsPath(id)
|
filesystem := d.ZfsPath(id)
|
||||||
log.Debugf(`[zfs] mount("%s", "%s", "%s")`, filesystem, mountpoint, mountLabel)
|
options := label.FormatMountLabel("", mountLabel)
|
||||||
|
log.Debugf(`[zfs] mount("%s", "%s", "%s")`, filesystem, mountpoint, options)
|
||||||
|
|
||||||
// Create the target directories if they don't exist
|
// Create the target directories if they don't exist
|
||||||
if err := os.MkdirAll(mountpoint, 0755); err != nil && !os.IsExist(err) {
|
if err := os.MkdirAll(mountpoint, 0755); err != nil && !os.IsExist(err) {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
err := mount.Mount(filesystem, mountpoint, "zfs", mountLabel)
|
err := mount.Mount(filesystem, mountpoint, "zfs", options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("error creating zfs mount of %s to %s: %v", filesystem, mountpoint, err)
|
return "", fmt.Errorf("error creating zfs mount of %s to %s: %v", filesystem, mountpoint, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,8 @@ func (daemon *Daemon) imgDeleteHelper(name string, list *[]types.ImageDelete, fi
|
|||||||
repos := daemon.Repositories().ByID()[img.ID]
|
repos := daemon.Repositories().ByID()[img.ID]
|
||||||
|
|
||||||
//If delete by id, see if the id belong only to one repository
|
//If delete by id, see if the id belong only to one repository
|
||||||
if repoName == "" {
|
deleteByID := repoName == ""
|
||||||
|
if deleteByID {
|
||||||
for _, repoAndTag := range repos {
|
for _, repoAndTag := range repos {
|
||||||
parsedRepo, parsedTag := parsers.ParseRepositoryTag(repoAndTag)
|
parsedRepo, parsedTag := parsers.ParseRepositoryTag(repoAndTag)
|
||||||
if repoName == "" || repoName == parsedRepo {
|
if repoName == "" || repoName == parsedRepo {
|
||||||
@@ -91,7 +92,7 @@ func (daemon *Daemon) imgDeleteHelper(name string, list *[]types.ImageDelete, fi
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(repos) <= 1 {
|
if len(repos) <= 1 || (len(repoAndTags) <= 1 && deleteByID) {
|
||||||
if err := daemon.canDeleteImage(img.ID, force); err != nil {
|
if err := daemon.canDeleteImage(img.ID, force); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,40 @@ func (daemon *Daemon) ContainerInspect(name string) (*types.ContainerJSON, error
|
|||||||
container.Lock()
|
container.Lock()
|
||||||
defer container.Unlock()
|
defer container.Unlock()
|
||||||
|
|
||||||
|
base, err := daemon.getInspectData(container)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.ContainerJSON{base, container.Config}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (daemon *Daemon) ContainerInspectRaw(name string) (*types.ContainerJSONRaw, error) {
|
||||||
|
container, err := daemon.Get(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
container.Lock()
|
||||||
|
defer container.Unlock()
|
||||||
|
|
||||||
|
base, err := daemon.getInspectData(container)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
config := &types.ContainerConfig{
|
||||||
|
container.Config,
|
||||||
|
container.hostConfig.Memory,
|
||||||
|
container.hostConfig.MemorySwap,
|
||||||
|
container.hostConfig.CpuShares,
|
||||||
|
container.hostConfig.CpusetCpus,
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.ContainerJSONRaw{base, config}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (daemon *Daemon) getInspectData(container *Container) (*types.ContainerJSONBase, error) {
|
||||||
// make a copy to play with
|
// make a copy to play with
|
||||||
hostConfig := *container.hostConfig
|
hostConfig := *container.hostConfig
|
||||||
|
|
||||||
@@ -60,12 +94,11 @@ func (daemon *Daemon) ContainerInspect(name string) (*types.ContainerJSON, error
|
|||||||
volumesRW[m.Destination] = m.RW
|
volumesRW[m.Destination] = m.RW
|
||||||
}
|
}
|
||||||
|
|
||||||
contJSON := &types.ContainerJSON{
|
contJSONBase := &types.ContainerJSONBase{
|
||||||
Id: container.ID,
|
Id: container.ID,
|
||||||
Created: container.Created,
|
Created: container.Created,
|
||||||
Path: container.Path,
|
Path: container.Path,
|
||||||
Args: container.Args,
|
Args: container.Args,
|
||||||
Config: container.Config,
|
|
||||||
State: containerState,
|
State: containerState,
|
||||||
Image: container.ImageID,
|
Image: container.ImageID,
|
||||||
NetworkSettings: container.NetworkSettings,
|
NetworkSettings: container.NetworkSettings,
|
||||||
@@ -86,7 +119,7 @@ func (daemon *Daemon) ContainerInspect(name string) (*types.ContainerJSON, error
|
|||||||
HostConfig: &hostConfig,
|
HostConfig: &hostConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
return contJSON, nil
|
return contJSONBase, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) ContainerExecInspect(id string) (*execConfig, error) {
|
func (daemon *Daemon) ContainerExecInspect(id string) (*execConfig, error) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package logger
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -40,14 +41,27 @@ func (c *Copier) Run() {
|
|||||||
|
|
||||||
func (c *Copier) copySrc(name string, src io.Reader) {
|
func (c *Copier) copySrc(name string, src io.Reader) {
|
||||||
defer c.copyJobs.Done()
|
defer c.copyJobs.Done()
|
||||||
scanner := bufio.NewScanner(src)
|
reader := bufio.NewReader(src)
|
||||||
for scanner.Scan() {
|
|
||||||
if err := c.dst.Log(&Message{ContainerID: c.cid, Line: scanner.Bytes(), Source: name, Timestamp: time.Now().UTC()}); err != nil {
|
for {
|
||||||
logrus.Errorf("Failed to log msg %q for logger %s: %s", scanner.Bytes(), c.dst.Name(), err)
|
line, err := reader.ReadBytes('\n')
|
||||||
|
line = bytes.TrimSuffix(line, []byte{'\n'})
|
||||||
|
|
||||||
|
// ReadBytes can return full or partial output even when it failed.
|
||||||
|
// e.g. it can return a full entry and EOF.
|
||||||
|
if err == nil || len(line) > 0 {
|
||||||
|
if logErr := c.dst.Log(&Message{ContainerID: c.cid, Line: line, Source: name, Timestamp: time.Now().UTC()}); logErr != nil {
|
||||||
|
logrus.Errorf("Failed to log msg %q for logger %s: %s", line, c.dst.Name(), logErr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if err := scanner.Err(); err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("Error scanning log stream: %s", err)
|
if err != io.EOF {
|
||||||
|
logrus.Errorf("Error scanning log stream: %s", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,14 +3,17 @@
|
|||||||
package syslog
|
package syslog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"log/syslog"
|
"log/syslog"
|
||||||
|
"net"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/docker/daemon/logger"
|
"github.com/docker/docker/daemon/logger"
|
||||||
|
"github.com/docker/docker/pkg/urlutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
const name = "syslog"
|
const name = "syslog"
|
||||||
@@ -27,7 +30,18 @@ func init() {
|
|||||||
|
|
||||||
func New(ctx logger.Context) (logger.Logger, error) {
|
func New(ctx logger.Context) (logger.Logger, error) {
|
||||||
tag := ctx.ContainerID[:12]
|
tag := ctx.ContainerID[:12]
|
||||||
log, err := syslog.New(syslog.LOG_DAEMON, fmt.Sprintf("%s/%s", path.Base(os.Args[0]), tag))
|
|
||||||
|
proto, address, err := parseAddress(ctx.Config["syslog-address"])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log, err := syslog.Dial(
|
||||||
|
proto,
|
||||||
|
address,
|
||||||
|
syslog.LOG_DAEMON,
|
||||||
|
path.Base(os.Args[0])+"/"+tag,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -55,3 +69,33 @@ func (s *Syslog) Name() string {
|
|||||||
func (s *Syslog) GetReader() (io.Reader, error) {
|
func (s *Syslog) GetReader() (io.Reader, error) {
|
||||||
return nil, logger.ReadLogsNotSupported
|
return nil, logger.ReadLogsNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseAddress(address string) (string, string, error) {
|
||||||
|
if urlutil.IsTransportURL(address) {
|
||||||
|
url, err := url.Parse(address)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// unix socket validation
|
||||||
|
if url.Scheme == "unix" {
|
||||||
|
if _, err := os.Stat(url.Path); err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
return url.Scheme, url.Path, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// here we process tcp|udp
|
||||||
|
host := url.Host
|
||||||
|
if _, _, err := net.SplitHostPort(host); err != nil {
|
||||||
|
if !strings.Contains(err.Error(), "missing port in address") {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
host = host + ":514"
|
||||||
|
}
|
||||||
|
|
||||||
|
return url.Scheme, host, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", "", nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/docker/docker/daemon/execdriver"
|
"github.com/docker/docker/daemon/execdriver"
|
||||||
"github.com/docker/libcontainer"
|
"github.com/docker/libcontainer"
|
||||||
"github.com/docker/libcontainer/cgroups"
|
"github.com/docker/libcontainer/cgroups"
|
||||||
|
"github.com/docker/libnetwork/sandbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (daemon *Daemon) ContainerStats(name string, stream bool, out io.Writer) error {
|
func (daemon *Daemon) ContainerStats(name string, stream bool, out io.Writer) error {
|
||||||
@@ -15,21 +16,43 @@ func (daemon *Daemon) ContainerStats(name string, stream bool, out io.Writer) er
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
enc := json.NewEncoder(out)
|
|
||||||
for v := range updates {
|
var preCpuStats types.CpuStats
|
||||||
|
getStat := func(v interface{}) *types.Stats {
|
||||||
update := v.(*execdriver.ResourceStats)
|
update := v.(*execdriver.ResourceStats)
|
||||||
|
// Retrieve the nw statistics from libnetwork and inject them in the Stats
|
||||||
|
if nwStats, err := daemon.getNetworkStats(name); err == nil {
|
||||||
|
update.Stats.Interfaces = nwStats
|
||||||
|
}
|
||||||
ss := convertToAPITypes(update.Stats)
|
ss := convertToAPITypes(update.Stats)
|
||||||
|
ss.PreCpuStats = preCpuStats
|
||||||
ss.MemoryStats.Limit = uint64(update.MemoryLimit)
|
ss.MemoryStats.Limit = uint64(update.MemoryLimit)
|
||||||
ss.Read = update.Read
|
ss.Read = update.Read
|
||||||
ss.CpuStats.SystemUsage = update.SystemUsage
|
ss.CpuStats.SystemUsage = update.SystemUsage
|
||||||
if err := enc.Encode(ss); err != nil {
|
preCpuStats = ss.CpuStats
|
||||||
|
return ss
|
||||||
|
}
|
||||||
|
|
||||||
|
enc := json.NewEncoder(out)
|
||||||
|
|
||||||
|
if !stream {
|
||||||
|
// prime the cpu stats so they aren't 0 in the final output
|
||||||
|
s := getStat(<-updates)
|
||||||
|
|
||||||
|
// now pull stats again with the cpu stats primed
|
||||||
|
s = getStat(<-updates)
|
||||||
|
err := enc.Encode(s)
|
||||||
|
daemon.UnsubscribeToContainerStats(name, updates)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for v := range updates {
|
||||||
|
s := getStat(v)
|
||||||
|
if err := enc.Encode(s); err != nil {
|
||||||
// TODO: handle the specific broken pipe
|
// TODO: handle the specific broken pipe
|
||||||
daemon.UnsubscribeToContainerStats(name, updates)
|
daemon.UnsubscribeToContainerStats(name, updates)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !stream {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -100,3 +123,46 @@ func copyBlkioEntry(entries []cgroups.BlkioStatEntry) []types.BlkioStatEntry {
|
|||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (daemon *Daemon) getNetworkStats(name string) ([]*libcontainer.NetworkInterface, error) {
|
||||||
|
var list []*libcontainer.NetworkInterface
|
||||||
|
|
||||||
|
c, err := daemon.Get(name)
|
||||||
|
if err != nil {
|
||||||
|
return list, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nw, err := daemon.netController.NetworkByID(c.NetworkSettings.NetworkID)
|
||||||
|
if err != nil {
|
||||||
|
return list, err
|
||||||
|
}
|
||||||
|
ep, err := nw.EndpointByID(c.NetworkSettings.EndpointID)
|
||||||
|
if err != nil {
|
||||||
|
return list, err
|
||||||
|
}
|
||||||
|
|
||||||
|
stats, err := ep.Statistics()
|
||||||
|
if err != nil {
|
||||||
|
return list, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert libnetwork nw stats into libcontainer nw stats
|
||||||
|
for ifName, ifStats := range stats {
|
||||||
|
list = append(list, convertLnNetworkStats(ifName, ifStats))
|
||||||
|
}
|
||||||
|
|
||||||
|
return list, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertLnNetworkStats(name string, stats *sandbox.InterfaceStatistics) *libcontainer.NetworkInterface {
|
||||||
|
n := &libcontainer.NetworkInterface{Name: name}
|
||||||
|
n.RxBytes = stats.RxBytes
|
||||||
|
n.RxPackets = stats.RxPackets
|
||||||
|
n.RxErrors = stats.RxErrors
|
||||||
|
n.RxDropped = stats.RxDropped
|
||||||
|
n.TxBytes = stats.TxBytes
|
||||||
|
n.TxPackets = stats.TxPackets
|
||||||
|
n.TxErrors = stats.TxErrors
|
||||||
|
n.TxDropped = stats.TxDropped
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/docker/pkg/chrootarchive"
|
"github.com/docker/docker/pkg/chrootarchive"
|
||||||
"github.com/docker/docker/runconfig"
|
"github.com/docker/docker/runconfig"
|
||||||
"github.com/docker/docker/volume"
|
"github.com/docker/docker/volume"
|
||||||
|
"github.com/docker/docker/volume/local"
|
||||||
"github.com/docker/libcontainer/label"
|
"github.com/docker/libcontainer/label"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -52,6 +53,13 @@ func (m *mountPoint) Path() string {
|
|||||||
return m.Source
|
return m.Source
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BackwardsCompatible decides whether this mount point can be
|
||||||
|
// used in old versions of Docker or not.
|
||||||
|
// Only bind mounts and local volumes can be used in old versions of Docker.
|
||||||
|
func (m *mountPoint) BackwardsCompatible() bool {
|
||||||
|
return len(m.Source) > 0 || m.Driver == volume.DefaultDriverName
|
||||||
|
}
|
||||||
|
|
||||||
func parseBindMount(spec string, mountLabel string, config *runconfig.Config) (*mountPoint, error) {
|
func parseBindMount(spec string, mountLabel string, config *runconfig.Config) (*mountPoint, error) {
|
||||||
bind := &mountPoint{
|
bind := &mountPoint{
|
||||||
RW: true,
|
RW: true,
|
||||||
@@ -74,7 +82,7 @@ func parseBindMount(spec string, mountLabel string, config *runconfig.Config) (*
|
|||||||
return nil, fmt.Errorf("Invalid volume specification: %s", spec)
|
return nil, fmt.Errorf("Invalid volume specification: %s", spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
name, source, err := parseVolumeSource(arr[0], config)
|
name, source, err := parseVolumeSource(arr[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -183,11 +191,16 @@ func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runc
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, m := range c.MountPoints {
|
for _, m := range c.MountPoints {
|
||||||
cp := m
|
cp := &mountPoint{
|
||||||
cp.RW = m.RW && mode != "ro"
|
Name: m.Name,
|
||||||
|
Source: m.Source,
|
||||||
|
RW: m.RW && mode != "ro",
|
||||||
|
Driver: m.Driver,
|
||||||
|
Destination: m.Destination,
|
||||||
|
}
|
||||||
|
|
||||||
if len(m.Source) == 0 {
|
if len(cp.Source) == 0 {
|
||||||
v, err := createVolume(m.Name, m.Driver)
|
v, err := createVolume(cp.Name, cp.Driver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -231,53 +244,99 @@ func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runc
|
|||||||
mountPoints[bind.Destination] = bind
|
mountPoints[bind.Destination] = bind
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep backwards compatible structures
|
||||||
|
bcVolumes := map[string]string{}
|
||||||
|
bcVolumesRW := map[string]bool{}
|
||||||
|
for _, m := range mountPoints {
|
||||||
|
if m.BackwardsCompatible() {
|
||||||
|
bcVolumes[m.Destination] = m.Path()
|
||||||
|
bcVolumesRW[m.Destination] = m.RW
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
container.Lock()
|
container.Lock()
|
||||||
container.MountPoints = mountPoints
|
container.MountPoints = mountPoints
|
||||||
|
container.Volumes = bcVolumes
|
||||||
|
container.VolumesRW = bcVolumesRW
|
||||||
container.Unlock()
|
container.Unlock()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// verifyOldVolumesInfo ports volumes configured for the containers pre docker 1.7.
|
// verifyVolumesInfo ports volumes configured for the containers pre docker 1.7.
|
||||||
// It reads the container configuration and creates valid mount points for the old volumes.
|
// It reads the container configuration and creates valid mount points for the old volumes.
|
||||||
func (daemon *Daemon) verifyOldVolumesInfo(container *Container) error {
|
func (daemon *Daemon) verifyVolumesInfo(container *Container) error {
|
||||||
jsonPath, err := container.jsonPath()
|
// Inspect old structures only when we're upgrading from old versions
|
||||||
if err != nil {
|
// to versions >= 1.7 and the MountPoints has not been populated with volumes data.
|
||||||
return err
|
if len(container.MountPoints) == 0 && len(container.Volumes) > 0 {
|
||||||
}
|
for destination, hostPath := range container.Volumes {
|
||||||
f, err := os.Open(jsonPath)
|
vfsPath := filepath.Join(daemon.root, "vfs", "dir")
|
||||||
if err != nil {
|
rw := container.VolumesRW != nil && container.VolumesRW[destination]
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return nil
|
if strings.HasPrefix(hostPath, vfsPath) {
|
||||||
|
id := filepath.Base(hostPath)
|
||||||
|
if err := migrateVolume(id, hostPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
container.addLocalMountPoint(id, destination, rw)
|
||||||
|
} else { // Bind mount
|
||||||
|
id, source, err := parseVolumeSource(hostPath)
|
||||||
|
// We should not find an error here coming
|
||||||
|
// from the old configuration, but who knows.
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
container.addBindMountPoint(id, source, destination, rw)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return err
|
} else if len(container.MountPoints) > 0 {
|
||||||
}
|
// Volumes created with a Docker version >= 1.7. We verify integrity in case of data created
|
||||||
|
// with Docker 1.7 RC versions that put the information in
|
||||||
type oldContVolCfg struct {
|
// DOCKER_ROOT/volumes/VOLUME_ID rather than DOCKER_ROOT/volumes/VOLUME_ID/_container_data.
|
||||||
Volumes map[string]string
|
l, err := getVolumeDriver(volume.DefaultDriverName)
|
||||||
VolumesRW map[string]bool
|
if err != nil {
|
||||||
}
|
return err
|
||||||
|
|
||||||
vols := oldContVolCfg{
|
|
||||||
Volumes: make(map[string]string),
|
|
||||||
VolumesRW: make(map[string]bool),
|
|
||||||
}
|
|
||||||
if err := json.NewDecoder(f).Decode(&vols); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for destination, hostPath := range vols.Volumes {
|
|
||||||
vfsPath := filepath.Join(daemon.root, "vfs", "dir")
|
|
||||||
|
|
||||||
if strings.HasPrefix(hostPath, vfsPath) {
|
|
||||||
id := filepath.Base(hostPath)
|
|
||||||
|
|
||||||
rw := vols.VolumesRW != nil && vols.VolumesRW[destination]
|
|
||||||
container.addLocalMountPoint(id, destination, rw)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, m := range container.MountPoints {
|
||||||
|
if m.Driver != volume.DefaultDriverName {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dataPath := l.(*local.Root).DataPath(m.Name)
|
||||||
|
volumePath := filepath.Dir(dataPath)
|
||||||
|
|
||||||
|
d, err := ioutil.ReadDir(volumePath)
|
||||||
|
if err != nil {
|
||||||
|
// If the volume directory doesn't exist yet it will be recreated,
|
||||||
|
// so we only return the error when there is a different issue.
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Do not check when the volume directory does not exist.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if validVolumeLayout(d) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.Mkdir(dataPath, 0755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move data inside the data directory
|
||||||
|
for _, f := range d {
|
||||||
|
oldp := filepath.Join(volumePath, f.Name())
|
||||||
|
newp := filepath.Join(dataPath, f.Name())
|
||||||
|
if err := os.Rename(oldp, newp); err != nil {
|
||||||
|
logrus.Errorf("Unable to move %s to %s\n", oldp, newp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return container.ToDisk()
|
||||||
}
|
}
|
||||||
|
|
||||||
return container.ToDisk()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createVolume(name, driverName string) (volume.Volume, error) {
|
func createVolume(name, driverName string) (volume.Volume, error) {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ package daemon
|
|||||||
import (
|
import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/docker/docker/runconfig"
|
|
||||||
"github.com/docker/docker/volume"
|
"github.com/docker/docker/volume"
|
||||||
"github.com/docker/docker/volume/drivers"
|
"github.com/docker/docker/volume/drivers"
|
||||||
)
|
)
|
||||||
@@ -17,7 +16,7 @@ func getVolumeDriver(name string) (volume.Driver, error) {
|
|||||||
return volumedrivers.Lookup(name)
|
return volumedrivers.Lookup(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseVolumeSource(spec string, config *runconfig.Config) (string, string, error) {
|
func parseVolumeSource(spec string) (string, string, error) {
|
||||||
if !filepath.IsAbs(spec) {
|
if !filepath.IsAbs(spec) {
|
||||||
return spec, "", nil
|
return spec, "", nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/docker/daemon/execdriver"
|
"github.com/docker/docker/daemon/execdriver"
|
||||||
"github.com/docker/docker/pkg/system"
|
"github.com/docker/docker/pkg/system"
|
||||||
|
"github.com/docker/docker/volume"
|
||||||
|
"github.com/docker/docker/volume/local"
|
||||||
)
|
)
|
||||||
|
|
||||||
// copyOwnership copies the permissions and uid:gid of the source file
|
// copyOwnership copies the permissions and uid:gid of the source file
|
||||||
@@ -68,3 +70,50 @@ func (m mounts) Swap(i, j int) {
|
|||||||
func (m mounts) parts(i int) int {
|
func (m mounts) parts(i int) int {
|
||||||
return len(strings.Split(filepath.Clean(m[i].Destination), string(os.PathSeparator)))
|
return len(strings.Split(filepath.Clean(m[i].Destination), string(os.PathSeparator)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// migrateVolume links the contents of a volume created pre Docker 1.7
|
||||||
|
// into the location expected by the local driver.
|
||||||
|
// It creates a symlink from DOCKER_ROOT/vfs/dir/VOLUME_ID to DOCKER_ROOT/volumes/VOLUME_ID/_container_data.
|
||||||
|
// It preserves the volume json configuration generated pre Docker 1.7 to be able to
|
||||||
|
// downgrade from Docker 1.7 to Docker 1.6 without losing volume compatibility.
|
||||||
|
func migrateVolume(id, vfs string) error {
|
||||||
|
l, err := getVolumeDriver(volume.DefaultDriverName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
newDataPath := l.(*local.Root).DataPath(id)
|
||||||
|
fi, err := os.Stat(newDataPath)
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if fi != nil && fi.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return os.Symlink(vfs, newDataPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// validVolumeLayout checks whether the volume directory layout
|
||||||
|
// is valid to work with Docker post 1.7 or not.
|
||||||
|
func validVolumeLayout(files []os.FileInfo) bool {
|
||||||
|
if len(files) == 1 && files[0].Name() == local.VolumeDataPathName && files[0].IsDir() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(files) != 2 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range files {
|
||||||
|
if f.Name() == "config.json" ||
|
||||||
|
(f.Name() == local.VolumeDataPathName && f.Mode()&os.ModeSymlink == os.ModeSymlink) {
|
||||||
|
// Old volume configuration, we ignore it
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/docker/docker/runconfig"
|
|
||||||
"github.com/docker/docker/volume"
|
"github.com/docker/docker/volume"
|
||||||
"github.com/docker/docker/volume/drivers"
|
"github.com/docker/docker/volume/drivers"
|
||||||
)
|
)
|
||||||
@@ -15,7 +14,7 @@ func getVolumeDriver(_ string) (volume.Driver, error) {
|
|||||||
return volumedrivers.Lookup(volume.DefaultDriverName)
|
return volumedrivers.Lookup(volume.DefaultDriverName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseVolumeSource(spec string, _ *runconfig.Config) (string, string, error) {
|
func parseVolumeSource(spec string) (string, string, error) {
|
||||||
if !filepath.IsAbs(spec) {
|
if !filepath.IsAbs(spec) {
|
||||||
return "", "", fmt.Errorf("cannot bind mount volume: %s volume paths must be absolute.", spec)
|
return "", "", fmt.Errorf("cannot bind mount volume: %s volume paths must be absolute.", spec)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,11 @@
|
|||||||
|
|
||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
import "github.com/docker/docker/daemon/execdriver"
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/docker/docker/daemon/execdriver"
|
||||||
|
)
|
||||||
|
|
||||||
// Not supported on Windows
|
// Not supported on Windows
|
||||||
func copyOwnership(source, destination string) error {
|
func copyOwnership(source, destination string) error {
|
||||||
@@ -12,3 +16,11 @@ func copyOwnership(source, destination string) error {
|
|||||||
func (container *Container) setupMounts() ([]execdriver.Mount, error) {
|
func (container *Container) setupMounts() ([]execdriver.Mount, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func migrateVolume(id, vfs string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validVolumeLayout(files []os.FileInfo) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import (
|
|||||||
flag "github.com/docker/docker/pkg/mflag"
|
flag "github.com/docker/docker/pkg/mflag"
|
||||||
"github.com/docker/docker/pkg/reexec"
|
"github.com/docker/docker/pkg/reexec"
|
||||||
"github.com/docker/docker/pkg/term"
|
"github.com/docker/docker/pkg/term"
|
||||||
|
"github.com/docker/docker/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -161,5 +162,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func showVersion() {
|
func showVersion() {
|
||||||
fmt.Printf("Docker version %s, build %s\n", dockerversion.VERSION, dockerversion.GITCOMMIT)
|
if utils.ExperimentalBuild() {
|
||||||
|
fmt.Printf("Docker version %s, build %s, experimental\n", dockerversion.VERSION, dockerversion.GITCOMMIT)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Docker version %s, build %s\n", dockerversion.VERSION, dockerversion.GITCOMMIT)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,2 @@
|
|||||||
# generated by man/man/md2man-all.sh
|
|
||||||
man1/
|
|
||||||
man5/
|
|
||||||
# avoid commiting the awsconfig file used for releases
|
# avoid commiting the awsconfig file used for releases
|
||||||
awsconfig
|
awsconfig
|
||||||
|
|||||||
@@ -1,163 +1,13 @@
|
|||||||
#
|
FROM docs/base:hugo
|
||||||
# See the top level Makefile in https://github.com/docker/docker for usage.
|
MAINTAINER Mary Anthony <mary@docker.com> (@moxiegirl)
|
||||||
#
|
|
||||||
FROM docs/base:latest
|
|
||||||
MAINTAINER Sven Dowideit <SvenDowideit@docker.com> (@SvenDowideit)
|
|
||||||
|
|
||||||
# This section ensures we pull the correct version of each
|
# To get the git info for this repo
|
||||||
# sub project
|
|
||||||
ENV COMPOSE_BRANCH release
|
|
||||||
ENV SWARM_BRANCH v0.2.0
|
|
||||||
ENV MACHINE_BRANCH docs
|
|
||||||
ENV DISTRIB_BRANCH docs
|
|
||||||
ENV KITEMATIC_BRANCH master
|
|
||||||
|
|
||||||
|
|
||||||
# TODO: need the full repo source to get the git version info
|
|
||||||
COPY . /src
|
COPY . /src
|
||||||
|
|
||||||
# Reset the /docs dir so we can replace the theme meta with the new repo's git info
|
COPY . /docs/content/
|
||||||
# RUN git reset --hard
|
|
||||||
|
|
||||||
# Then copy the desired docs into the /docs/sources/ dir
|
WORKDIR /docs/content
|
||||||
COPY ./sources/ /docs/sources
|
|
||||||
|
|
||||||
COPY ./VERSION VERSION
|
RUN /docs/content/touch-up.sh
|
||||||
|
|
||||||
# adding the image spec will require Docker 1.5 and `docker build -f docs/Dockerfile .`
|
WORKDIR /docs
|
||||||
#COPY ./image/spec/v1.md /docs/sources/reference/image-spec-v1.md
|
|
||||||
|
|
||||||
# TODO: don't do this - look at merging the yml file in build.sh
|
|
||||||
COPY ./mkdocs.yml ./s3_website.json ./release.sh ./
|
|
||||||
|
|
||||||
#######################
|
|
||||||
# Docker Distribution
|
|
||||||
########################
|
|
||||||
|
|
||||||
#ADD https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/mkdocs.yml /docs/mkdocs-distribution.yml
|
|
||||||
|
|
||||||
ADD https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/images/notifications.png \
|
|
||||||
https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/images/registry.png \
|
|
||||||
/docs/sources/registry/images/
|
|
||||||
|
|
||||||
ADD https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/index.md \
|
|
||||||
https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/deploying.md \
|
|
||||||
https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/configuration.md \
|
|
||||||
https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/storagedrivers.md \
|
|
||||||
https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/notifications.md \
|
|
||||||
/docs/sources/registry/
|
|
||||||
|
|
||||||
ADD https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/spec/api.md \
|
|
||||||
https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/spec/json.md \
|
|
||||||
/docs/sources/registry/spec/
|
|
||||||
|
|
||||||
ADD https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/storage-drivers/s3.md \
|
|
||||||
https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/storage-drivers/azure.md \
|
|
||||||
https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/storage-drivers/filesystem.md \
|
|
||||||
https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/storage-drivers/inmemory.md \
|
|
||||||
/docs/sources/registry/storage-drivers/
|
|
||||||
|
|
||||||
ADD https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/spec/auth/token.md /docs/sources/registry/spec/auth/token.md
|
|
||||||
|
|
||||||
RUN sed -i.old '1s;^;no_version_dropdown: true;' \
|
|
||||||
/docs/sources/registry/*.md \
|
|
||||||
/docs/sources/registry/spec/*.md \
|
|
||||||
/docs/sources/registry/spec/auth/*.md \
|
|
||||||
/docs/sources/registry/storage-drivers/*.md
|
|
||||||
|
|
||||||
RUN sed -i.old -e '/^<!--GITHUB/g' -e '/^IGNORES-->/g'\
|
|
||||||
/docs/sources/registry/*.md \
|
|
||||||
/docs/sources/registry/spec/*.md \
|
|
||||||
/docs/sources/registry/spec/auth/*.md \
|
|
||||||
/docs/sources/registry/storage-drivers/*.md
|
|
||||||
|
|
||||||
#######################
|
|
||||||
# Docker Swarm
|
|
||||||
#######################
|
|
||||||
|
|
||||||
#ADD https://raw.githubusercontent.com/docker/swarm/${SWARM_BRANCH}/docs/mkdocs.yml /docs/mkdocs-swarm.yml
|
|
||||||
ADD https://raw.githubusercontent.com/docker/swarm/${SWARM_BRANCH}/docs/index.md /docs/sources/swarm/index.md
|
|
||||||
|
|
||||||
ADD https://raw.githubusercontent.com/docker/swarm/${SWARM_BRANCH}/discovery/README.md /docs/sources/swarm/discovery.md
|
|
||||||
|
|
||||||
ADD https://raw.githubusercontent.com/docker/swarm/${SWARM_BRANCH}/api/README.md /docs/sources/swarm/API.md
|
|
||||||
|
|
||||||
ADD https://raw.githubusercontent.com/docker/swarm/${SWARM_BRANCH}/scheduler/filter/README.md /docs/sources/swarm/scheduler/filter.md
|
|
||||||
|
|
||||||
ADD https://raw.githubusercontent.com/docker/swarm/${SWARM_BRANCH}/scheduler/strategy/README.md /docs/sources/swarm/scheduler/strategy.md
|
|
||||||
|
|
||||||
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/swarm/*.md /docs/sources/swarm/scheduler/*.md
|
|
||||||
|
|
||||||
#######################
|
|
||||||
# Docker Machine
|
|
||||||
#######################
|
|
||||||
#ADD https://raw.githubusercontent.com/docker/machine/${MACHINE_BRANCH}/docs/mkdocs.yml /docs/mkdocs-machine.yml
|
|
||||||
|
|
||||||
ADD https://raw.githubusercontent.com/docker/machine/${MACHINE_BRANCH}/docs/index.md /docs/sources/machine/index.md
|
|
||||||
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/machine/index.md
|
|
||||||
|
|
||||||
#######################
|
|
||||||
# Docker Compose
|
|
||||||
#######################
|
|
||||||
|
|
||||||
#ADD https://raw.githubusercontent.com/docker/compose/${COMPOSE_BRANCH}/docs/mkdocs.yml /docs/mkdocs-compose.yml
|
|
||||||
|
|
||||||
ADD https://raw.githubusercontent.com/docker/compose/${COMPOSE_BRANCH}/docs/index.md \
|
|
||||||
https://raw.githubusercontent.com/docker/compose/${COMPOSE_BRANCH}/docs/install.md \
|
|
||||||
https://raw.githubusercontent.com/docker/compose/${COMPOSE_BRANCH}/docs/cli.md \
|
|
||||||
https://raw.githubusercontent.com/docker/compose/${COMPOSE_BRANCH}/docs/yml.md \
|
|
||||||
https://raw.githubusercontent.com/docker/compose/${COMPOSE_BRANCH}/docs/env.md \
|
|
||||||
https://raw.githubusercontent.com/docker/compose/${COMPOSE_BRANCH}/docs/completion.md \
|
|
||||||
https://raw.githubusercontent.com/docker/compose/${COMPOSE_BRANCH}/docs/django.md \
|
|
||||||
https://raw.githubusercontent.com/docker/compose/${COMPOSE_BRANCH}/docs/rails.md \
|
|
||||||
https://raw.githubusercontent.com/docker/compose/${COMPOSE_BRANCH}/docs/wordpress.md \
|
|
||||||
https://raw.githubusercontent.com/docker/compose/${COMPOSE_BRANCH}/docs/extends.md \
|
|
||||||
https://raw.githubusercontent.com/docker/compose/${COMPOSE_BRANCH}/docs/production.md \
|
|
||||||
/docs/sources/compose/
|
|
||||||
|
|
||||||
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/compose/*.md
|
|
||||||
|
|
||||||
#######################
|
|
||||||
# Kitematic
|
|
||||||
#######################
|
|
||||||
ADD https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/faq.md \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/index.md \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/known-issues.md \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/minecraft-server.md \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/nginx-web-server.md \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/rethinkdb-dev-database.md \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/userguide.md \
|
|
||||||
/docs/sources/kitematic/
|
|
||||||
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/kitematic/*.md
|
|
||||||
ADD https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/browse-images.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/change-folder.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/cli-access-button.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/cli-redis-container.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/cli-terminal.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/containers.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/installing.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/minecraft-add-server.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/minecraft-create.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/minecraft-data-volume.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/minecraft-login.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/minecraft-map.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/minecraft-port.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/minecraft-restart.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/minecraft-server-address.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/nginx-2048-files.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/nginx-2048.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/nginx-create.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/nginx-data-folder.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/nginx-data-volume.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/nginx-hello-world.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/nginx-preview.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/nginx-serving-2048.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/rethink-container.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/rethink-create.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/rethink-ports.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/rethinkdb-preview.png \
|
|
||||||
https://raw.githubusercontent.com/kitematic/kitematic/${KITEMATIC_BRANCH}/docs/assets/volumes-dir.png \
|
|
||||||
/docs/sources/kitematic/assets/
|
|
||||||
|
|
||||||
# Then build everything together, ready for mkdocs
|
|
||||||
RUN /docs/build.sh
|
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
.PHONY: all binary build cross default docs docs-build docs-shell shell test test-unit test-integration test-integration-cli test-docker-py validate
|
||||||
|
|
||||||
|
# env vars passed through directly to Docker's build scripts
|
||||||
|
# to allow things like `make DOCKER_CLIENTONLY=1 binary` easily
|
||||||
|
# `docs/sources/contributing/devenvironment.md ` and `project/PACKAGERS.md` have some limited documentation of some of these
|
||||||
|
DOCKER_ENVS := \
|
||||||
|
-e BUILDFLAGS \
|
||||||
|
-e DOCKER_CLIENTONLY \
|
||||||
|
-e DOCKER_EXECDRIVER \
|
||||||
|
-e DOCKER_GRAPHDRIVER \
|
||||||
|
-e TESTDIRS \
|
||||||
|
-e TESTFLAGS \
|
||||||
|
-e TIMEOUT
|
||||||
|
# note: we _cannot_ add "-e DOCKER_BUILDTAGS" here because even if it's unset in the shell, that would shadow the "ENV DOCKER_BUILDTAGS" set in our Dockerfile, which is very important for our official builds
|
||||||
|
|
||||||
|
# to allow `make DOCSDIR=docs docs-shell` (to create a bind mount in docs)
|
||||||
|
DOCS_MOUNT := $(if $(DOCSDIR),-v $(CURDIR)/$(DOCSDIR):/$(DOCSDIR))
|
||||||
|
|
||||||
|
# to allow `make DOCSPORT=9000 docs`
|
||||||
|
DOCSPORT := 8000
|
||||||
|
|
||||||
|
# Get the IP ADDRESS
|
||||||
|
DOCKER_IP=$(shell python -c "import urlparse ; print urlparse.urlparse('$(DOCKER_HOST)').hostname or ''")
|
||||||
|
HUGO_BASE_URL=$(shell test -z "$(DOCKER_IP)" && echo localhost || echo "$(DOCKER_IP)")
|
||||||
|
HUGO_BIND_IP=0.0.0.0
|
||||||
|
|
||||||
|
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null)
|
||||||
|
DOCKER_IMAGE := docker$(if $(GIT_BRANCH),:$(GIT_BRANCH))
|
||||||
|
DOCKER_DOCS_IMAGE := docs-base$(if $(GIT_BRANCH),:$(GIT_BRANCH))
|
||||||
|
|
||||||
|
|
||||||
|
DOCKER_RUN_DOCS := docker run --rm -it $(DOCS_MOUNT) -e AWS_S3_BUCKET -e NOCACHE
|
||||||
|
|
||||||
|
# for some docs workarounds (see below in "docs-build" target)
|
||||||
|
GITCOMMIT := $(shell git rev-parse --short HEAD 2>/dev/null)
|
||||||
|
|
||||||
|
default: docs
|
||||||
|
|
||||||
|
docs: docs-build
|
||||||
|
$(DOCKER_RUN_DOCS) -p $(if $(DOCSPORT),$(DOCSPORT):)8000 -e DOCKERHOST "$(DOCKER_DOCS_IMAGE)" hugo server --port=$(DOCSPORT) --baseUrl=$(HUGO_BASE_URL) --bind=$(HUGO_BIND_IP)
|
||||||
|
|
||||||
|
docs-draft: docs-build
|
||||||
|
$(DOCKER_RUN_DOCS) -p $(if $(DOCSPORT),$(DOCSPORT):)8000 -e DOCKERHOST "$(DOCKER_DOCS_IMAGE)" hugo server --buildDrafts="true" --port=$(DOCSPORT) --baseUrl=$(HUGO_BASE_URL) --bind=$(HUGO_BIND_IP)
|
||||||
|
|
||||||
|
|
||||||
|
docs-shell: docs-build
|
||||||
|
$(DOCKER_RUN_DOCS) -p $(if $(DOCSPORT),$(DOCSPORT):)8000 "$(DOCKER_DOCS_IMAGE)" bash
|
||||||
|
|
||||||
|
|
||||||
|
docs-build:
|
||||||
|
# ( git remote | grep -v upstream ) || git diff --name-status upstream/release..upstream/docs ./ > ./changed-files
|
||||||
|
# echo "$(GIT_BRANCH)" > GIT_BRANCH
|
||||||
|
# echo "$(AWS_S3_BUCKET)" > AWS_S3_BUCKET
|
||||||
|
# echo "$(GITCOMMIT)" > GITCOMMIT
|
||||||
|
docker build -t "$(DOCKER_DOCS_IMAGE)" .
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
|
<!--[metadata]>
|
||||||
|
+++
|
||||||
|
draft = true
|
||||||
|
+++
|
||||||
|
<![end-metadata]-->
|
||||||
|
|
||||||
# Docker Documentation
|
# Docker Documentation
|
||||||
|
|
||||||
The source for Docker documentation is in this directory under `sources/`. Our
|
The source for Docker documentation is in this directory. Our
|
||||||
documentation uses extended Markdown, as implemented by
|
documentation uses extended Markdown, as implemented by
|
||||||
[MkDocs](http://mkdocs.org). The current release of the Docker documentation
|
[MkDocs](http://mkdocs.org). The current release of the Docker documentation
|
||||||
resides on [https://docs.docker.com](https://docs.docker.com).
|
resides on [https://docs.docker.com](https://docs.docker.com).
|
||||||
@@ -12,7 +18,7 @@ Docker has two primary branches for documentation:
|
|||||||
| Branch | Description | URL (published via commit-hook) |
|
| Branch | Description | URL (published via commit-hook) |
|
||||||
|----------|--------------------------------|------------------------------------------------------------------------------|
|
|----------|--------------------------------|------------------------------------------------------------------------------|
|
||||||
| `docs` | Official release documentation | [https://docs.docker.com](https://docs.docker.com) |
|
| `docs` | Official release documentation | [https://docs.docker.com](https://docs.docker.com) |
|
||||||
| `master` | Merged but unreleased development work | [http://docs.master.dockerproject.com](http://docs.master.dockerproject.com) |
|
| `master` | Merged but unreleased development work | [http://docs.master.dockerproject.org](http://docs.master.dockerproject.org) |
|
||||||
|
|
||||||
Additions and updates to upcoming releases are made in a feature branch off of
|
Additions and updates to upcoming releases are made in a feature branch off of
|
||||||
the `master` branch. The Docker maintainers also support a `docs` branch that
|
the `master` branch. The Docker maintainers also support a `docs` branch that
|
||||||
@@ -22,7 +28,7 @@ After a release, documentation updates are continually merged into `master` as
|
|||||||
they occur. This work includes new documentation for forthcoming features, bug
|
they occur. This work includes new documentation for forthcoming features, bug
|
||||||
fixes, and other updates. Docker's CI system automatically builds and updates
|
fixes, and other updates. Docker's CI system automatically builds and updates
|
||||||
the `master` documentation after each merge and posts it to
|
the `master` documentation after each merge and posts it to
|
||||||
[http://docs.master.dockerproject.com](http://docs.master.dockerproject.com).
|
[http://docs.master.dockerproject.org](http://docs.master.dockerproject.org).
|
||||||
|
|
||||||
Periodically, the Docker maintainers update `docs.docker.com` between official
|
Periodically, the Docker maintainers update `docs.docker.com` between official
|
||||||
releases of Docker. They do this by cherry-picking commits from `master`,
|
releases of Docker. They do this by cherry-picking commits from `master`,
|
||||||
@@ -54,7 +60,7 @@ own.
|
|||||||
release. It also allows docs maintainers to easily cherry-pick your changes
|
release. It also allows docs maintainers to easily cherry-pick your changes
|
||||||
into the `docs` release branch.
|
into the `docs` release branch.
|
||||||
|
|
||||||
4. Modify existing or add new `.md` files to the `docs/sources` directory.
|
4. Modify existing or add new `.md` files to the `docs` directory.
|
||||||
|
|
||||||
If you add a new document (`.md`) file, you must also add it to the
|
If you add a new document (`.md`) file, you must also add it to the
|
||||||
appropriate section of the `docs/mkdocs.yml` file in this repository.
|
appropriate section of the `docs/mkdocs.yml` file in this repository.
|
||||||
@@ -107,7 +113,7 @@ links that are referenced in the documentation—there should be none.
|
|||||||
## Style guide
|
## Style guide
|
||||||
|
|
||||||
If you have questions about how to write for Docker's documentation, please see
|
If you have questions about how to write for Docker's documentation, please see
|
||||||
the [style guide](sources/project/doc-style.md). The style guide provides
|
the [style guide](project/doc-style.md). The style guide provides
|
||||||
guidance about grammar, syntax, formatting, styling, language, or tone. If
|
guidance about grammar, syntax, formatting, styling, language, or tone. If
|
||||||
something isn't clear in the guide, please submit an issue to let us know or
|
something isn't clear in the guide, please submit an issue to let us know or
|
||||||
submit a pull request to help us improve it.
|
submit a pull request to help us improve it.
|
||||||
@@ -280,24 +286,11 @@ aws cloudfront create-invalidation --profile docs.docker.com --distribution-id
|
|||||||
aws cloudfront create-invalidation --profile docs.docker.com --distribution-id $DISTRIBUTION_ID --invalidation-batch '{"Paths":{"Quantity":1, "Items":["/v1.1/reference/api/docker_io_oauth_api/"]},"CallerReference":"6Mar2015sventest1"}'
|
aws cloudfront create-invalidation --profile docs.docker.com --distribution-id $DISTRIBUTION_ID --invalidation-batch '{"Paths":{"Quantity":1, "Items":["/v1.1/reference/api/docker_io_oauth_api/"]},"CallerReference":"6Mar2015sventest1"}'
|
||||||
```
|
```
|
||||||
|
|
||||||
### Generate the man pages for Mac OSX
|
### Generate the man pages
|
||||||
|
|
||||||
When using Docker on Mac OSX the man pages will be missing by default. You can manually generate them by following these steps:
|
For information on generating man pages (short for manual page), see [the man
|
||||||
|
page directory](https://github.com/docker/docker/tree/master/docker) in this
|
||||||
|
project.
|
||||||
|
|
||||||
1. Checkout the docker source. You must clone into your `/Users` directory because Boot2Docker can only share this path
|
|
||||||
with the docker containers.
|
|
||||||
|
|
||||||
$ git clone https://github.com/docker/docker.git
|
|
||||||
|
|
||||||
2. Build the docker image.
|
|
||||||
|
|
||||||
$ cd docker/docs/man
|
|
||||||
$ docker build -t docker/md2man .
|
|
||||||
|
|
||||||
3. Build the man pages.
|
|
||||||
|
|
||||||
$ docker run -v /Users/<path-to-git-dir>/docker/docs/man:/docs:rw -w /docs -i docker/md2man /docs/md2man-all.sh
|
|
||||||
|
|
||||||
4. Copy the generated man pages to `/usr/share/man`
|
|
||||||
|
|
||||||
$ cp -R man* /usr/share/man/
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 183 KiB After Width: | Height: | Size: 183 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 175 KiB After Width: | Height: | Size: 175 KiB |
@@ -1,6 +1,13 @@
|
|||||||
page_title: Link via an ambassador container
|
<!--[metadata]>
|
||||||
page_description: Using the Ambassador pattern to abstract (network) services
|
+++
|
||||||
page_keywords: Examples, Usage, links, docker, documentation, examples, names, name, container naming
|
title = "Link via an ambassador container"
|
||||||
|
description = "Using the Ambassador pattern to abstract (network) services"
|
||||||
|
keywords = ["Examples, Usage, links, docker, documentation, examples, names, name, container naming"]
|
||||||
|
[menu.main]
|
||||||
|
parent = "smn_administrate"
|
||||||
|
weight = 6
|
||||||
|
+++
|
||||||
|
<![end-metadata]-->
|
||||||
|
|
||||||
# Link via an ambassador container
|
# Link via an ambassador container
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 9.4 KiB |
@@ -1,6 +1,12 @@
|
|||||||
page_title: Resizing a Boot2Docker volume
|
<!--[metadata]>
|
||||||
page_description: Resizing a Boot2Docker volume in VirtualBox with GParted
|
+++
|
||||||
page_keywords: boot2docker, volume, virtualbox
|
title = "Resizing a Boot2Docker volume "
|
||||||
|
description = "Resizing a Boot2Docker volume in VirtualBox with GParted"
|
||||||
|
keywords = ["boot2docker, volume, virtualbox"]
|
||||||
|
[menu.main]
|
||||||
|
parent = "smn_win_osx"
|
||||||
|
+++
|
||||||
|
<![end-metadata]-->
|
||||||
|
|
||||||
# Getting “no space left on device” errors with Boot2Docker?
|
# Getting “no space left on device” errors with Boot2Docker?
|
||||||
|
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
page_title: Create a base image
|
<!--[metadata]>
|
||||||
page_description: How to create base images
|
+++
|
||||||
page_keywords: Examples, Usage, base image, docker, documentation, examples
|
title = "Create a base image"
|
||||||
|
description = "How to create base images"
|
||||||
|
keywords = ["Examples, Usage, base image, docker, documentation, examples"]
|
||||||
|
[menu.main]
|
||||||
|
parent = "smn_images"
|
||||||
|
+++
|
||||||
|
<![end-metadata]-->
|
||||||
|
|
||||||
# Create a base image
|
# Create a base image
|
||||||
|
|
||||||
@@ -1,8 +1,14 @@
|
|||||||
page_title: First steps with Docker
|
<!--[metadata]>
|
||||||
page_description: Common usage and commands
|
+++
|
||||||
page_keywords: Examples, Usage, basic commands, docker, documentation, examples
|
title = "Get started with containers"
|
||||||
|
description = "Common usage and commands"
|
||||||
|
keywords = ["Examples, Usage, basic commands, docker, documentation, examples"]
|
||||||
|
[menu.main]
|
||||||
|
parent = "smn_containers"
|
||||||
|
+++
|
||||||
|
<![end-metadata]-->
|
||||||
|
|
||||||
# First steps with Docker
|
# "Get started with containers
|
||||||
|
|
||||||
This guide assumes you have a working installation of Docker. To check
|
This guide assumes you have a working installation of Docker. To check
|
||||||
your Docker install, run the following command:
|
your Docker install, run the following command:
|
||||||
@@ -41,7 +47,9 @@ image cache.
|
|||||||
> characters of the full image ID - which can be found using
|
> characters of the full image ID - which can be found using
|
||||||
> `docker inspect` or `docker images --no-trunc=true`
|
> `docker inspect` or `docker images --no-trunc=true`
|
||||||
|
|
||||||
{{ include "no-remote-sudo.md" }}
|
> **Note:** if you are using a remote Docker daemon, such as Boot2Docker,
|
||||||
|
> then _do not_ type the `sudo` before the `docker` commands shown in the
|
||||||
|
> documentation's examples.
|
||||||
|
|
||||||
## Running an interactive shell
|
## Running an interactive shell
|
||||||
|
|
||||||
@@ -1,6 +1,13 @@
|
|||||||
page_title: Using certificates for repository client verification
|
<!--[metadata]>
|
||||||
page_description: How to set up and use certificates with a registry to verify access
|
+++
|
||||||
page_keywords: Usage, registry, repository, client, root, certificate, docker, apache, ssl, tls, documentation, examples, articles, tutorials
|
title = "Using certificates for repository client verification"
|
||||||
|
description = "How to set up and use certificates with a registry to verify access"
|
||||||
|
keywords = ["Usage, registry, repository, client, root, certificate, docker, apache, ssl, tls, documentation, examples, articles, tutorials"]
|
||||||
|
[menu.main]
|
||||||
|
parent = "mn_docker_hub"
|
||||||
|
weight = 7
|
||||||
|
+++
|
||||||
|
<![end-metadata]-->
|
||||||
|
|
||||||
# Using certificates for repository client verification
|
# Using certificates for repository client verification
|
||||||
|
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
page_title: Process management with CFEngine
|
<!--[metadata]>
|
||||||
page_description: Managing containerized processes with CFEngine
|
+++
|
||||||
page_keywords: cfengine, process, management, usage, docker, documentation
|
title = "Process management with CFEngine"
|
||||||
|
description = "Managing containerized processes with CFEngine"
|
||||||
|
keywords = ["cfengine, process, management, usage, docker, documentation"]
|
||||||
|
[menu.main]
|
||||||
|
parent = "smn_third_party"
|
||||||
|
+++
|
||||||
|
<![end-metadata]-->
|
||||||
|
|
||||||
# Process management with CFEngine
|
# Process management with CFEngine
|
||||||
|
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
page_title: Using Chef
|
<!--[metadata]>
|
||||||
page_description: Installation and using Docker via Chef
|
+++
|
||||||
page_keywords: chef, installation, usage, docker, documentation
|
title = "Using Chef"
|
||||||
|
description = "Installation and using Docker via Chef"
|
||||||
|
keywords = ["chef, installation, usage, docker, documentation"]
|
||||||
|
[menu.main]
|
||||||
|
parent = "smn_third_party"
|
||||||
|
+++
|
||||||
|
<![end-metadata]-->
|
||||||
|
|
||||||
# Using Chef
|
# Using Chef
|
||||||
|
|
||||||
@@ -1,6 +1,13 @@
|
|||||||
page_title: Configuring and running Docker
|
<!--[metadata]>
|
||||||
page_description: Configuring and running the Docker daemon on various distributions
|
+++
|
||||||
page_keywords: docker, daemon, configuration, running, process managers
|
title = "Configuring and running Docker"
|
||||||
|
description = "Configuring and running the Docker daemon on various distributions"
|
||||||
|
keywords = ["docker, daemon, configuration, running, process managers"]
|
||||||
|
[menu.main]
|
||||||
|
parent = "smn_administrate"
|
||||||
|
weight = 3
|
||||||
|
+++
|
||||||
|
<![end-metadata]-->
|
||||||
|
|
||||||
# Configuring and running Docker on various distributions
|
# Configuring and running Docker on various distributions
|
||||||
|
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
page_title: Best practices for writing Dockerfiles
|
<!--[metadata]>
|
||||||
page_description: Hints, tips and guidelines for writing clean, reliable Dockerfiles
|
+++
|
||||||
page_keywords: Examples, Usage, base image, docker, documentation, dockerfile, best practices, hub, official repo
|
title = "Best practices for writing Dockerfiles"
|
||||||
|
description = "Hints, tips and guidelines for writing clean, reliable Dockerfiles"
|
||||||
|
keywords = ["Examples, Usage, base image, docker, documentation, dockerfile, best practices, hub, official repo"]
|
||||||
|
[menu.main]
|
||||||
|
parent = "smn_images"
|
||||||
|
+++
|
||||||
|
<![end-metadata]-->
|
||||||
|
|
||||||
# Best practices for writing Dockerfiles
|
# Best practices for writing Dockerfiles
|
||||||
|
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
page_title: PowerShell DSC Usage
|
<!--[metadata]>
|
||||||
page_description: Using DSC to configure a new Docker host
|
+++
|
||||||
page_keywords: powershell, dsc, installation, usage, docker, documentation
|
title = "PowerShell DSC Usage"
|
||||||
|
description = "Using DSC to configure a new Docker host"
|
||||||
|
keywords = ["powershell, dsc, installation, usage, docker, documentation"]
|
||||||
|
[menu.main]
|
||||||
|
parent = "smn_win_osx"
|
||||||
|
+++
|
||||||
|
<![end-metadata]-->
|
||||||
|
|
||||||
# Using PowerShell DSC
|
# Using PowerShell DSC
|
||||||
|
|
||||||
@@ -1,6 +1,13 @@
|
|||||||
page_title: Automatically start containers
|
<!--[metadata]>
|
||||||
page_description: How to generate scripts for upstart, systemd, etc.
|
+++
|
||||||
page_keywords: systemd, upstart, supervisor, docker, documentation, host integration
|
title = "Automatically start containers"
|
||||||
|
description = "How to generate scripts for upstart, systemd, etc."
|
||||||
|
keywords = ["systemd, upstart, supervisor, docker, documentation, host integration"]
|
||||||
|
[menu.main]
|
||||||
|
parent = "smn_containers"
|
||||||
|
weight = 99
|
||||||
|
+++
|
||||||
|
<![end-metadata]-->
|
||||||
|
|
||||||
# Automatically start containers
|
# Automatically start containers
|
||||||
|
|
||||||
@@ -1,8 +1,15 @@
|
|||||||
page_title: Protecting the Docker daemon socket with HTTPS
|
<!--[metadata]>
|
||||||
page_description: How to setup and run Docker with HTTPS
|
+++
|
||||||
page_keywords: docker, docs, article, example, https, daemon, tls, ca, certificate
|
title = "Protect the Docker daemon socket"
|
||||||
|
description = "How to setup and run Docker with HTTPS"
|
||||||
|
keywords = ["docker, docs, article, example, https, daemon, tls, ca, certificate"]
|
||||||
|
[menu.main]
|
||||||
|
parent = "smn_administrate"
|
||||||
|
weight = 5
|
||||||
|
+++
|
||||||
|
<![end-metadata]-->
|
||||||
|
|
||||||
# Protecting the Docker daemon socket with HTTPS
|
# Protect the Docker daemon socket
|
||||||
|
|
||||||
By default, Docker runs via a non-networked Unix socket. It can also
|
By default, Docker runs via a non-networked Unix socket. It can also
|
||||||
optionally communicate using a HTTP socket.
|
optionally communicate using a HTTP socket.
|
||||||