Compare commits

..

131 Commits

Author SHA1 Message Date
James Hunt b58a22a7e1 Allow "docker info" to recognise Clear Linux.
As per os-release spec, /usr/lib/os-release file should be tried if
/etc/os-release is missing.

http://www.freedesktop.org/software/systemd/man/os-release.html

Signed-off-by: James Hunt <james.o.hunt@intel.com>
Signed-off-by: Dimitri John Ledkov <dimitri.j.ledkov@intel.com>
2015-10-20 12:00:31 +01:00
Phil Estes 8eba018b61 Merge pull request #17155 from janten/meitner
Correct Lise Meitner's name, add Euler and Noether
2015-10-19 08:26:55 -04:00
Phil Estes 1f9557ac66 Merge pull request #17166 from echo33/docker_cli_diff_test
use of checkers on docker_cli_diff_test.go
2015-10-19 08:25:32 -04:00
Phil Estes 1c783567c0 Merge pull request #17167 from liaoqingwei/16756-docker_cli_inspect_experimental_test.go
Use of checkers on docker_cli_inspect_experimental_test.go
2015-10-19 08:21:17 -04:00
liaoqingwei f3b2b8700f Use of checkers on docker_cli_inspect_experimental_test.go.
Signed-off-by: liaoqingwei <liaoqingwei@huawei.com>
2015-10-19 19:44:04 +08:00
weiyan 7be79767c1 use of checkers on docker_cli_diff_test.go
Signed-off-by: weiyan <weiyan3@huawei.com>
2015-10-19 19:07:59 +08:00
Antonio Murdaca eaa1fc41c6 Merge pull request #16897 from sunyuan3/docker_cli_rm_test
use of checkers on docker_cli_rm_test.go
2015-10-19 09:14:23 +02:00
Vincent Demeester cfdb954303 Merge pull request #17162 from echo33/docker_cli_exec_unix_test
use of checkers on docker_cli_exec_unix_test.go
2015-10-19 08:54:42 +02:00
weiyan d65ac42ca8 use of checkers on docker_cli_exec_unix_test.go
Signed-off-by: weiyan <weiyan3@huawei.com>
2015-10-19 15:14:59 +08:00
Yuan Sun 0780ddc498 use of checkers on docker_cli_rm_test.go
Signed-off-by: Yuan Sun <sunyuan3@huawei.com>
2015-10-19 10:42:56 +08:00
Jan-Gerd Tenberge ab31d9500e Fix spelling error, add Noether and Euler
Signed-off-by: Jan-Gerd Tenberge <janten@gmail.com>
2015-10-19 01:14:39 +02:00
moxiegirl bab701c143 Merge pull request #17157 from ripcurld00d/fedora_doc
Update fedora doc
2015-10-18 14:41:07 -07:00
ripcurld00d 6a64865991 Update fedora doc
`service` is deprecated from Fedora v21.
It's important to enable and start the `docker` daemon using `systemctl`.

Signed-off-by: Boaz Shuster <ripcurld.github@gmail.com>
2015-10-18 23:00:23 +03:00
Vincent Demeester bece5b82a8 Merge pull request #17008 from liaoqingwei/dev1
Update testcases: use of checkers on docker_cli_nat_test.go
2015-10-18 18:11:02 +02:00
liaoqingwei 26ae6d6b36 Use of checkers on docker_cli_nat_test.go.
Signed-off-by: liaoqingwei <liaoqingwei@huawei.com>
2015-10-18 20:02:55 +08:00
moxiegirl ef49d127e3 Merge pull request #17141 from thaJeztah/fix-17140-storage-driver-formatting
docs: fix storage driver options list
2015-10-17 19:33:40 -07:00
Sebastiaan van Stijn 8f36ded5b1 docs: fix storage driver options list
This fixes the indentation of the storage driver
options list.

Also wraps/reformats some examples to prevent
horizontal scrollbars on the rendered HTML

Fixes #17140

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2015-10-17 19:17:07 -07:00
Vincent Batts 2726434f72 Merge pull request #16960 from pydima/9283_consider_hard_links_in_image_size
Consider hardlinks in image size.
2015-10-17 14:22:33 -04:00
Sebastiaan van Stijn cffd50752c Merge pull request #17056 from vdemeester/16756-integration-cli-checkers-api-build
Vendoring new go-check checkers and use checker for docker_api_build_test.go
2015-10-17 08:50:51 -07:00
Vincent Demeester 253f975fdb Use checker assert for docker_api_build_test.go
Signed-off-by: Vincent Demeester <vincent@sbr.pm>
2015-10-17 14:28:13 +02:00
Vincent Demeester 9685b4767f Vendoring shakers library and update go-check
The shakers library defines a bunch of go-check checkers to ease
writing tests.

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
2015-10-17 14:28:08 +02:00
Brian Goff 9b1fb0d45b Merge pull request #16871 from ZJU-SEL/fix_version_test
update docker_cli_version_test.go
2015-10-17 08:02:18 -04:00
Dmitry Vorobev 4102537cfd Fixes #9283. Consider hardlinks in image size.
Based on #8984. This patch fixes behavior when image size calculation
didn't consider hardlinks.

Signed-off-by: Dmitry Vorobev <dimahabr@gmail.com>
2015-10-17 12:24:05 +02:00
Antonio Murdaca ab1f03397e Merge pull request #17119 from vdemeester/17117-deprecate-c-cli-opts
Deprecate -c cli short variant flag in docker cli build & create
2015-10-17 10:22:46 +02:00
Sebastiaan van Stijn e3fabf3ea1 Merge pull request #16831 from jfrazelle/release-updates
Release updates
2015-10-16 16:57:10 -07:00
David Calavera c3f42b29a8 Merge pull request #17113 from mountkin/validate-filter
make sure the value of the dangling filter is correct
2015-10-16 16:32:11 -07:00
Tibor Vass 365a0db0f0 Merge pull request #17046 from mavenugo/dopts
driver-opts for network create
2015-10-16 15:23:59 -07:00
David Calavera ec7c368ff0 Merge pull request #16901 from WeiZhang555/rmi-inte
Update integration test `integration-cli/docker_cli_rmi_test.go` with Assert
2015-10-16 15:23:00 -07:00
Vincent Demeester d8b4471a59 Merge pull request #16977 from mountkin/refactor-test
refactor integration test to use checkers
2015-10-17 00:22:03 +02:00
Antonio Murdaca 4fc97e40c9 Merge pull request #16950 from cpuguy83/support_ipv6_in_host_parser
Allow API to bind to ipv6 addresses
2015-10-17 00:20:49 +02:00
David Calavera 8c1fa7f320 Merge pull request #16994 from Microsoft/10662-copied
Windows: Fix annoying bad log
2015-10-16 15:14:08 -07:00
David Calavera 475be776b8 Merge pull request #17051 from thaJeztah/fix-volume-readonly-doc
remove incorrect "readonly" example
2015-10-16 15:11:48 -07:00
Vincent Demeester d1064bd441 Deprecate -c cli short variant flag in docker cli
- build
- create

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
2015-10-17 00:05:34 +02:00
David Calavera 258357857b Merge pull request #17065 from ZJaffee/api-exec-resize-test
cleaned up integration-cli/docker_api_exec_resize_test.go
2015-10-16 14:59:06 -07:00
David Calavera 3668be932e Merge pull request #16574 from Djelibeybi/rpm-changelog
Generate a full RPM changelog from the existing CHANGELOG.md file
2015-10-16 14:55:39 -07:00
Madhu Venugopal 6f3eb994b5 Pass network driver option in docker network command
Signed-off-by: Madhu Venugopal <madhu@docker.com>
2015-10-16 14:33:54 -07:00
Madhu Venugopal cf1b5fe601 Vendoring libnetwork to Replace the label variable to DriverOpts
Signed-off-by: Madhu Venugopal <madhu@docker.com>
2015-10-16 14:30:57 -07:00
Tibor Vass e23d834a01 Merge pull request #17106 from albers/completion-import
Add missing options to bash completion for `docker import`
2015-10-16 14:28:14 -07:00
Tibor Vass b1bab9e1e7 Merge pull request #17107 from albers/completion-build
Add missing options to bash completion for `docker build`
2015-10-16 14:27:51 -07:00
Vincent Demeester c56b02b284 Merge pull request #17081 from ZJaffee/api_network_test
Cleaned up integration-cli/docker_api_network_test.go
2015-10-16 23:14:17 +02:00
Vincent Demeester 8b90aefd14 Merge pull request #17121 from sdurrheimer/zsh-completion-fix-double-dash-option-arguments
Zsh : all --<option>= flag values may be given in the next argument
2015-10-16 23:13:25 +02:00
Brian Goff 84be89a273 Merge pull request #16969 from zhangjianfnst/16756-improve-integration-cli
Use c.Assert in integration-cli/docker_cli_logs_test.go
2015-10-16 16:55:44 -04:00
Steve Durrheimer b34aa69e8f Zsh completion : all --<option>= flag values may be given in the next argument
Signed-off-by: Steve Durrheimer <s.durrheimer@gmail.com>
2015-10-16 21:18:27 +02:00
Sebastiaan van Stijn ccf5b60c6f Merge pull request #17098 from sdurrheimer/zsh-completion-import-message
Add zsh completion for 'docker import -m --message'
2015-10-16 11:36:46 -07:00
Tibor Vass b054a88af1 Merge pull request #17093 from endophage/update_notary_gotuf
updating notary and gotuf with latest bugfixes
2015-10-16 11:19:21 -07:00
Zachary Jaffee 7b6bca5af1 cleaned up integration-cli/docker_api_exec_resize_test.go
Signed-off-by: Zachary Jaffee <zij@case.edu>
2015-10-16 13:22:40 -04:00
Sebastiaan van Stijn e2870bda43 Merge pull request #17085 from dnephin/add_digest_to_api_docs
Correct API docs for /images/create
2015-10-16 10:10:41 -07:00
Vincent Demeester 2afdab4454 Merge pull request #17100 from WeiZhang555/port-inte
update docker_cli_port_test.go with Assert
2015-10-16 19:06:14 +02:00
David Lawrence 7ce9f02751 updating notary and gotuf with latest bugfixes
Signed-off-by: David Lawrence <david.lawrence@docker.com>
2015-10-16 09:33:26 -07:00
David Calavera 841205ec01 Merge pull request #17062 from coolljt0725/fix_cancel
Fix cancel build doesn't remove the intermediate container
2015-10-16 09:06:09 -07:00
Brian Goff 08a43b8b3b Merge pull request #17101 from sdurrheimer/zsh-completion-deprecate-run-dash-c-option
Deprecate 'docker run -c' option in zsh completion
2015-10-16 11:40:02 -04:00
Brian Goff 30b945fac9 Merge pull request #17099 from sdurrheimer/zsh-completion-restart-unless-stopped
Add zsh completion for 'unless-stopped' restart policy
2015-10-16 11:37:27 -04:00
Vincent Demeester 71982d8e57 Merge pull request #17105 from liaoqingwei/dev3
Use of checkers on docker_cli_pause_test.go.
2015-10-16 17:36:56 +02:00
David Calavera 579cf43f0f Merge pull request #17102 from sdurrheimer/zsh-completion-build-build-arg
Add zsh completion for 'docker build --build-arg'
2015-10-16 08:34:12 -07:00
David Calavera f9026e2b7b Merge pull request #17078 from kevinkucharczyk/api_version_test
Clean up integration-cli/docker_api_version_test.go
2015-10-16 08:26:53 -07:00
Zhang Wei 1ae4eeb813 update docker_cli_port_test.go with Assert
Part of #16756

Use c.Assert instead of condition judgement

Signed-off-by: Zhang Wei <zhangwei555@huawei.com>
2015-10-16 22:58:51 +08:00
Shijiang Wei 98c1a412b4 make sure the value of the dangling filter is correct
Signed-off-by: Shijiang Wei <mountkin@gmail.com>
2015-10-16 22:09:32 +08:00
Brian Goff 835fbee9a2 Merge pull request #17053 from liaoqingwei/dev2
use of checkers on docker_cli_network_unix_test.go
2015-10-16 09:36:59 -04:00
Brian Goff 60b5b0d380 Merge pull request #17112 from moxiegirl/fix-16961-tic
Removing extra tic
2015-10-16 09:10:12 -04:00
Mary Anthony ee30af5ffb bad d
Signed-off-by: Mary Anthony <mary@docker.com>
2015-10-16 06:09:03 -07:00
Mary Anthony e44876bf1f Removing extra tic
Signed-off-by: Mary Anthony <mary@docker.com>
2015-10-16 06:07:52 -07:00
liaoqingwei 851a533a82 Use of checkers on docker_cli_pause_test.go.
Signed-off-by: liaoqingwei <liaoqingwei@huawei.com>
2015-10-16 21:07:02 +08:00
Harald Albers b0315375f8 Add missing options to bash completion for docker import
Signed-off-by: Harald Albers <github@albersweb.de>
2015-10-16 12:42:12 +02:00
Harald Albers 3a713d91ce bash completion: minor refactoring for consistency
Signed-off-by: Harald Albers <github@albersweb.de>
2015-10-16 12:41:09 +02:00
Harald Albers 28c66b0491 Add missing options to bash completion for docker build
Signed-off-by: Harald Albers <github@albersweb.de>
2015-10-16 12:40:55 +02:00
Antonio Murdaca dee57e4c3e Merge pull request #17087 from LK4D4/speedup_ps
Speedup container list
2015-10-16 12:35:28 +02:00
Lei Jitang 9392de9dfe Fix cancel build doesn't remove the intermediate container
Signed-off-by: Lei Jitang <leijitang@huawei.com>
2015-10-16 05:18:10 -04:00
liaoqingwei 9e3db08363 Use of checkers on docker_cli_network_unix_test.go.
Signed-off-by: liaoqingwei <liaoqingwei@huawei.com>
2015-10-16 16:56:40 +08:00
Steve Durrheimer 96a09ea77c Add zsh completion for 'docker import -m --message'
Signed-off-by: Steve Durrheimer <s.durrheimer@gmail.com>
2015-10-16 10:14:42 +02:00
Steve Durrheimer 89e0990224 Add zsh completion for 'docker build --build-arg'
Signed-off-by: Steve Durrheimer <s.durrheimer@gmail.com>
2015-10-16 08:48:12 +02:00
Steve Durrheimer c37c9df18a Deprecate 'docker run -c' option in zsh completion
Signed-off-by: Steve Durrheimer <s.durrheimer@gmail.com>
2015-10-16 08:37:16 +02:00
Steve Durrheimer cb2bd8bcec Add zsh completion for 'unless-stopped' restart policy
Signed-off-by: Steve Durrheimer <s.durrheimer@gmail.com>
2015-10-16 08:30:56 +02:00
Kevin P. Kucharczyk 6f1b5946b1 Clean up integration-cli/docker_api_version_test.go
Signed-off-by: Kevin P. Kucharczyk <kevinkucharczyk@gmail.com>
2015-10-16 07:03:39 +02:00
Alexander Morozov f256d8ad2d Speedup container list
Remove all unneeded disk operations (reload TagStore, umarshal image)
for checking if image still points to same ID. Now slowest part is
queries to sqlite which hopefuly will be removed soon.

Signed-off-by: Alexander Morozov <lk4d4@docker.com>
2015-10-15 20:41:35 -07:00
Vincent Batts d35a1f2868 Merge pull request #16932 from c0b/fix-race-16924
Fix race #16924 [panic: runtime error: slice bounds out of range] docker daemon crash of racing
2015-10-15 18:05:05 -05:00
Vincent Demeester 1052ff674c Merge pull request #17073 from ZJaffee/api_events_test
Cleaned up integration-cli/docker_api_events_test.go
2015-10-16 00:22:29 +02:00
Vincent Demeester 58b36ba242 Merge pull request #17080 from ZJaffee/api_logs_test
Cleaned up integration-cli/docker_api_logs_test.go
2015-10-16 00:21:30 +02:00
David Calavera e1804098b9 Merge pull request #16997 from Microsoft/10662-kill-parttwo
Windows: [TP4] docker kill handling part two
2015-10-15 14:42:19 -07:00
Jess Frazelle ebfed4d474 Merge pull request #17082 from sdurrheimer/zsh-completion-remove-network-ls-old-options
Remove 'docker network ls -n -l --latest' options from in zsh completion
2015-10-15 13:48:39 -07:00
Jess Frazelle ff4026fa5b Merge pull request #17084 from sdurrheimer/zsh-completion-network-ipam
Add zsh completion for '--ipam-driver --subnet --ip-range --gateway -…
2015-10-15 13:48:19 -07:00
Daniel Nephin 2ec4404ba0 Correct API docs for /images/create
Signed-off-by: Daniel Nephin <dnephin@docker.com>
2015-10-15 16:00:05 -04:00
Steve Durrheimer a00c0d795d Add zsh completion for '--ipam-driver --subnet --ip-range --gateway --aux-address' for 'docker network create'
Signed-off-by: Steve Durrheimer <s.durrheimer@gmail.com>
2015-10-15 21:40:50 +02:00
Steve Durrheimer 080a906aac Remove '-n -l --latest' options from 'docker network ls' in zsh completion
Signed-off-by: Steve Durrheimer <s.durrheimer@gmail.com>
2015-10-15 21:12:31 +02:00
David Calavera f255155f6b Merge pull request #17057 from mavenugo/nls
Added `network` to docker --help and help cleanup
2015-10-15 11:00:43 -07:00
Zachary Jaffee 7345050e4d Cleaned up integration-cli/docker_api_network_test.go
Signed-off-by: Zachary Jaffee <zij@case.edu>
2015-10-15 13:37:54 -04:00
Zachary Jaffee 7aab43e8d4 Cleaned up integration-cli/docker_api_logs_test.go
Signed-off-by: Zachary Jaffee <zij@case.edu>
2015-10-15 13:33:31 -04:00
Tianon Gravi add0d25029 Merge pull request #17054 from hqhq/hq_use_go1.4.3
Bump Go to 1.4.3 for builder
2015-10-15 10:13:23 -07:00
Zachary Jaffee 176d8c5a14 Cleaned up integration-cli/docker_api_events_test.go
Signed-off-by: Zachary Jaffee <zij@case.edu>
2015-10-15 12:40:36 -04:00
Arnaud Porterie 9216b08536 Merge pull request #16998 from vieux/engine_version
only display 'Engine Version' when it's not empty
2015-10-15 08:43:32 -07:00
Vincent Demeester 0f00c36d65 Merge pull request #17004 from echo33/docker_cli_restart_test
use of checkers on docker_cli_restart_test.go
2015-10-15 13:31:05 +02:00
Doug Davis 32ead68e9f Merge pull request #16966 from MHBauer/image-refactor
refactor use of container struct from daemon
2015-10-15 07:30:08 -04:00
Madhu Venugopal 46f7ab3585 Added network to docker --help and help cleanup
Fixes https://github.com/docker/docker/issues/16909

Signed-off-by: Madhu Venugopal <madhu@docker.com>
2015-10-15 03:10:39 -07:00
weiyan 196af472a6 use of checkers on docker_cli_restart_test.go
Signed-off-by: weiyan <weiyan3@huawei.com>
2015-10-15 16:35:03 +08:00
Vincent Demeester e4dadeed88 Merge pull request #17011 from sunyuan3/TestRunWithBlkioInvalidWeight
update TestRunWithBlkioInvalidWeight
2015-10-15 08:34:52 +02:00
Qiang Huang 42d643af55 Bump Go to 1.4.3 for builder
We already bumped this for Dockerfile, should keep build environment
consistent with that.

Signed-off-by: Qiang Huang <h.huangqiang@huawei.com>
2015-10-15 14:02:18 +08:00
Jian Zhang 946e8cde53 Use c.Assert in integration-cli/docker_cli_logs_test.go
Signed-off-by: Jian Zhang <zhangjian.fnst@cn.fujitsu.com>
2015-10-15 10:53:19 +08:00
Sebastiaan van Stijn 244d9c3370 remove incorrect "readonly" example
The :ro option can only be used for named and bind-mounted
volumes, not on "regular" (unnamed) volumes as explained in
https://github.com/docker/docker/pull/16013#issuecomment-146647216

The example in the documentation actually resulted in a
bind-mounted volume, mounted at "ro" inside the container.

This removes the incorrect example from the documentation.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2015-10-14 17:56:38 -07:00
Victor Vieux 17b0017cd0 use Server Version
Signed-off-by: Victor Vieux <vieux@docker.com>
2015-10-14 17:46:59 -07:00
moxiegirl 919c3c1ec8 Merge pull request #17024 from sallyom/man-run-clarify
add clarity to -p option
2015-10-14 14:12:25 -07:00
Brian Goff 84488e228a Merge pull request #17030 from calavera/remove_var_check
Remove defensive check of mux vars handling.
2015-10-14 16:36:50 -04:00
Jess Frazelle b22f89cb77 Merge pull request #16221 from flavio/get-docker-update-suse-installation
Update SUSE/openSUSE installation script
2015-10-14 13:02:45 -07:00
Sally O'Malley 37c6c53b56 add clarity to -p option
Signed-off-by: Sally O'Malley <somalley@redhat.com>
2015-10-14 15:18:04 -04:00
Flavio Castelli 400ac8a66c Update SUSE/openSUSE installation script
Fix installation on SUSE Linux Enterprise machine, the updated Docker RPMs have
been moved to a different location.

Update both openSUSE and SUSE Linux Enterprise scripts to allow the
installation of experimental builds.

Signed-off-by: Flavio Castelli <fcastelli@suse.com>
2015-10-14 20:55:28 +02:00
Sebastiaan van Stijn 2b4128e904 Merge pull request #16617 from zhangjianfnst/15869-improve-commandline-doc
Improve the way we deliver Examples in command line.
2015-10-14 11:05:27 -07:00
Brian Goff adb37a1b39 Merge pull request #17025 from albers/completion-inspect-size
[Fix #15796] Add bash completion for `docker inspect --size`
2015-10-14 13:48:43 -04:00
David Calavera 389ce0aae6 Remove defensive check of mux vars handling.
We should not check if the mux framework internals work as expected in every handler.
The missing parameter error doesn't make sense from the user point of view.

This change initializes a proper vars context if the mux fails to do so and delegates
specific parameter error checks to the handlers.

Signed-off-by: David Calavera <david.calavera@gmail.com>
2015-10-14 10:31:09 -07:00
Vincent Demeester aaa8cae345 Merge pull request #16968 from MHBauer/network-refactor
refactor use of container struct from daemon
2015-10-14 17:48:08 +02:00
Harald Albers 29714ee836 Add bash completion for docker inspect --size
Signed-off-by: Harald Albers <github@albersweb.de>
2015-10-14 17:34:56 +02:00
Brian Goff d60883eb10 Merge pull request #17006 from echo33/docker_cli_v2_only
use of checkers on docker_cli_v2_only.go
2015-10-14 10:27:37 -04:00
Victor Vieux ddf04ad113 only display 'Engine Version' when it's not empty
Signed-off-by: Victor Vieux <vieux@docker.com>
2015-10-14 06:45:11 -07:00
weiyan 899ca94ce8 use of checkers on docker_cli_v2_only.go
Signed-off-by: weiyan <weiyan3@huawei.com>
2015-10-14 20:10:34 +08:00
Yuan Sun d550fbb80e update TestRunWithBlkioInvalidWeight
Signed-off-by: Yuan Sun <sunyuan3@huawei.com>
2015-10-14 16:20:52 +08:00
Jian Zhang cc653b5d61 Improve the way we deliver Examples in command line. (Add descriptive titles)
Signed-off-by: Jian Zhang <zhangjian.fnst@cn.fujitsu.com>
2015-10-14 11:04:51 +08:00
Tibor Vass 7a19164c17 Merge pull request #16995 from jfrazelle/lxc-i-loathe-you
Fix lxc
2015-10-13 19:00:24 -07:00
Jess Frazelle 22a0b0a4f9 Merge pull request #16999 from tiborvass/bump_apiversion_to_v1.22
Bump API Version to v1.22
2015-10-13 18:59:09 -07:00
Tibor Vass 22a0ea5550 Bump API Version to v1.22
Signed-off-by: Tibor Vass <tibor@docker.com>
2015-10-13 17:27:33 -07:00
Morgan Bauer a0398fbd19 refactor use of container struct from daemon
- do existence check instead of get container
 - new connect method on daemon.
 - cli network disconnect integration test

Signed-off-by: Morgan Bauer <mbauer@us.ibm.com>
2015-10-13 16:34:28 -07:00
John Howard bc503ca8ab Windows: [TP4] docker kill handling
Signed-off-by: John Howard <jhoward@microsoft.com>
2015-10-13 16:04:49 -07:00
Derek Ch b48f4bf523 fix a race crash when building with "ADD some-broken.tar.xz ..."
The race is between pools.Put which calls buf.Reset and exec.Cmd
doing io.Copy from the buffer; it caused a runtime crash, as
described in #16924:

``` docker-daemon cat the-tarball.xz | xz -d -c -q | docker-untar /path/to/... (aufs ) ```

When docker-untar side fails (like try to set xattr on aufs, or a broken
tar), invokeUnpack will be responsible to exhaust all input, otherwise
`xz` will be write pending for ever.

this change add a receive only channel to cmdStream, and will close it
to notify it's now safe to close the input stream;

in CmdStream the change to use Stdin / Stdout / Stderr keeps the
code simple, os/exec.Cmd will spawn goroutines and call io.Copy automatically.

the CmdStream is actually called in the same file only, change it
lowercase to mark as private.

[...]
INFO[0000] Docker daemon                                 commit=0a8c2e3 execdriver=native-0.2 graphdriver=aufs version=1.8.2

DEBU[0006] Calling POST /build
INFO[0006] POST /v1.20/build?cgroupparent=&cpuperiod=0&cpuquota=0&cpusetcpus=&cpusetmems=&cpushares=0&dockerfile=Dockerfile&memory=0&memswap=0&rm=1&t=gentoo-x32&ulimits=null
DEBU[0008] [BUILDER] Cache miss
DEBU[0009] Couldn't untar /home/lib-docker-v1.8.2-tmp/tmp/docker-build316710953/stage3-x32-20151004.tar.xz to /home/lib-docker-v1.8.2-tmp/aufs/mnt/d909abb87150463939c13e8a349b889a72d9b14f0cfcab42a8711979be285537: Untar re-exec error: exit status 1: output: operation not supported
DEBU[0009] CopyFileWithTar(/home/lib-docker-v1.8.2-tmp/tmp/docker-build316710953/stage3-x32-20151004.tar.xz, /home/lib-docker-v1.8.2-tmp/aufs/mnt/d909abb87150463939c13e8a349b889a72d9b14f0cfcab42a8711979be285537/)
panic: runtime error: slice bounds out of range

goroutine 42 [running]:
bufio.(*Reader).fill(0xc208187800)
    /usr/local/go/src/bufio/bufio.go:86 +0x2db
bufio.(*Reader).WriteTo(0xc208187800, 0x7ff39602d150, 0xc2083f11a0, 0x508000, 0x0, 0x0)
    /usr/local/go/src/bufio/bufio.go:449 +0x27e
io.Copy(0x7ff39602d150, 0xc2083f11a0, 0x7ff3960261f8, 0xc208187800, 0x0, 0x0, 0x0)
    /usr/local/go/src/io/io.go:354 +0xb2
github.com/docker/docker/pkg/archive.func·006()
    /go/src/github.com/docker/docker/pkg/archive/archive.go:817 +0x71
created by github.com/docker/docker/pkg/archive.CmdStream
    /go/src/github.com/docker/docker/pkg/archive/archive.go:819 +0x1ec

goroutine 1 [chan receive]:
main.(*DaemonCli).CmdDaemon(0xc20809da30, 0xc20800a020, 0xd, 0xd, 0x0, 0x0)
    /go/src/github.com/docker/docker/docker/daemon.go:289 +0x1781
reflect.callMethod(0xc208140090, 0xc20828fce0)
    /usr/local/go/src/reflect/value.go:605 +0x179
reflect.methodValueCall(0xc20800a020, 0xd, 0xd, 0x1, 0xc208140090, 0x0, 0x0, 0xc208140090, 0x0, 0x45343f, ...)
    /usr/local/go/src/reflect/asm_amd64.s:29 +0x36
github.com/docker/docker/cli.(*Cli).Run(0xc208129fb0, 0xc20800a010, 0xe, 0xe, 0x0, 0x0)
    /go/src/github.com/docker/docker/cli/cli.go:89 +0x38e
main.main()
    /go/src/github.com/docker/docker/docker/docker.go:69 +0x428

goroutine 5 [syscall]:
os/signal.loop()
    /usr/local/go/src/os/signal/signal_unix.go:21 +0x1f
created by os/signal.init·1
    /usr/local/go/src/os/signal/signal_unix.go:27 +0x35

Signed-off-by: Derek Ch <denc716@gmail.com>
2015-10-13 15:58:06 -07:00
Jessica Frazelle 28ad7c588f update tests
Signed-off-by: Jessica Frazelle <acidburn@docker.com>
2015-10-13 15:52:14 -07:00
John Howard 69949df242 Windows: Fix annoying bad log
Signed-off-by: John Howard <jhoward@microsoft.com>
2015-10-13 15:03:20 -07:00
Antonio Murdaca cfcddefacd daemon: execdriver: lxc: fix cgroup paths
When running LXC dind (outer docker is started with native driver)
cgroup paths point to `/docker/CID` inside `/proc/self/mountinfo` but
these paths aren't mounted (root is wrong). This fix just discard the
cgroup dir from mountinfo and set it to root `/`.
This patch fixes/skip OOM LXC tests that were failing.
Fix #16520

Signed-off-by: Antonio Murdaca <runcom@linux.com>
Signed-off-by: Antonio Murdaca <amurdaca@redhat.com>
2015-10-13 14:46:59 -07:00
Antonio Murdaca 06f0d03ced daemon: execdriver: lxc: fix set memory swap
On LXC memory swap was only set to memory_limit*2 even if a value for
memory swap was provided. This patch fix this behavior to be the same
as the native driver and set correct memory swap in the template.
Also add a test specifically for LXC but w/o adding a new test
requirement.

Signed-off-by: Antonio Murdaca <runcom@linux.com>
2015-10-13 14:46:59 -07:00
Shijiang Wei a1d4b7dd0d refactor integration test to use checkers
Signed-off-by: Shijiang Wei <mountkin@gmail.com>
2015-10-13 20:21:38 +08:00
Morgan Bauer 844fb29619 refactor use of container struct from daemon
- use Exists instead of Get
 - push Get inside of daemonbuilder

Signed-off-by: Morgan Bauer <mbauer@us.ibm.com>
2015-10-12 16:20:55 -07:00
Brian Goff a82e3bc704 Allow API to bind to ipv6 addresses
Use `net.SplitHostPort` which supports ipv6 rather than relying on
splitting on `:`

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2015-10-12 13:55:27 -04:00
Mageee d4d0718ebf update docker_cli_version_test.go
fix spelling mistake again

Signed-off-by: Mageee <fangpuyi@foxmail.com>
2015-10-12 15:13:31 +08:00
Zhang Wei c6b02ad73b Update integration test with Assert
Part of #16756

Update integration-cli/docker_cli_rmi_test.go:
Use Assert instead of condition judgement in test.

Signed-off-by: Zhang Wei <zhangwei555@huawei.com>
2015-10-11 10:56:02 +08:00
Jessica Frazelle 96559aaef2 add clean apt db to release script
Signed-off-by: Jessica Frazelle <acidburn@docker.com>
2015-10-08 09:21:20 -07:00
Jessica Frazelle 0aee0b1f9e add script to generate index listing for the repo if say hosted on s3
Signed-off-by: Jessica Frazelle <acidburn@docker.com>
2015-10-08 09:21:16 -07:00
Avi Miller 1374ebcde0 Generate a full RPM changelog from the existing CHANGELOG.md file
Signed-off-by: Avi Miller <avi.miller@oracle.com>
2015-09-25 17:25:00 +10:00
431 changed files with 11285 additions and 12619 deletions
-148
View File
@@ -1,153 +1,5 @@
# Changelog
Items starting with `DEPRECATE` are important deprecation notices. For more
information on the list of deprecated flags and APIs please have a look at
https://docs.docker.com/misc/deprecated/ where target removal dates can also
be found.
## 1.9.1
## Runtime
- Do not prevent daemon from booting if images could not be restored (#17695)
- Force IPC mount to unmount on daemon shutdown/init (#17539)
- Turn IPC unmount errors into warnings (#17554)
- Fix `docker stats` performance regression (#17638)
- Clarify cryptic error message upon `docker logs` if `--log-driver=none` (#17767)
- Fix seldom panics (#17639, #17634, #17703)
- Fix opq whiteouts problems for files with dot prefix (#17819)
- devicemapper: try defaulting to xfs instead of ext4 for performance reasons (#17903, #17918)
- devicemapper: fix displayed fs in docker info (#17974)
- selinux: only relabel if user requested so with the `z` option (#17450, #17834)
- Do not make network calls when normalizing names (#18014)
## Client
- Fix `docker login` on windows (#17738)
- Fix bug with `docker inspect` output when not connected to daemon (#17715)
- Fix `docker inspect -f {{.HostConfig.Dns}} somecontainer` (#17680)
## Builder
- Fix regression with symlink behavior in ADD/COPY (#17710)
## Networking
- Allow passing a network ID as an argument for `--net` (#17558)
- Fix connect to host and prevent disconnect from host for `host` network (#17476)
- Fix `--fixed-cidr` issue when gateway ip falls in ip-range and ip-range is
not the first block in the network (#17853)
- Restore deterministic `IPv6` generation from `MAC` address on default `bridge` network (#17890)
- Allow port-mapping only for endpoints created on docker run (#17858)
- Fixed an endpoint delete issue with a possible stale sbox (#18102)
## Distribution
- Correct parent chain in v2 push when v1Compatibility files on the disk are inconsistent (#18047)
## 1.9.0 (2015-11-03)
## Runtime
+ `docker stats` now returns block IO metrics (#15005)
+ `docker stats` now details network stats per interface (#15786)
+ Add `ancestor=<image>` filter to `docker ps --filter` flag to filter
containers based on their ancestor images (#14570)
+ Add `label=<somelabel>` filter to `docker ps --filter` to filter containers
based on label (#16530)
+ Add `--kernel-memory` flag to `docker run` (#14006)
+ Add `--message` flag to `docker import` allowing to specify an optional
message (#15711)
+ Add `--privileged` flag to `docker exec` (#14113)
+ Add `--stop-signal` flag to `docker run` allowing to replace the container
process stopping signal (#15307)
+ Add a new `unless-stopped` restart policy (#15348)
+ Inspecting an image now returns tags (#13185)
+ Add container size information to `docker inspect` (#15796)
+ Add `RepoTags` and `RepoDigests` field to `/images/{name:.*}/json` (#17275)
- Remove the deprecated `/container/ps` endpoint from the API (#15972)
- Send and document correct HTTP codes for `/exec/<name>/start` (#16250)
- Share shm and mqueue between containers sharing IPC namespace (#15862)
- Event stream now shows OOM status when `--oom-kill-disable` is set (#16235)
- Ensure special network files (/etc/hosts etc.) are read-only if bind-mounted
with `ro` option (#14965)
- Improve `rmi` performance (#16890)
- Do not update /etc/hosts for the default bridge network, except for links (#17325)
- Fix conflict with duplicate container names (#17389)
- Fix an issue with incorrect template execution in `docker inspect` (#17284)
- DEPRECATE `-c` short flag variant for `--cpu-shares` in docker run (#16271)
## Client
+ Allow `docker import` to import from local files (#11907)
## Builder
+ Add a `STOPSIGNAL` Dockerfile instruction allowing to set a different
stop-signal for the container process (#15307)
+ Add an `ARG` Dockerfile instruction and a `--build-arg` flag to `docker build`
that allows to add build-time environment variables (#15182)
- Improve cache miss performance (#16890)
## Storage
- devicemapper: Implement deferred deletion capability (#16381)
## Networking
+ `docker network` exits experimental and is part of standard release (#16645)
+ New network top-level concept, with associated subcommands and API (#16645)
WARNING: the API is different from the experimental API
+ Support for multiple isolated/micro-segmented networks (#16645)
+ Built-in multihost networking using VXLAN based overlay driver (#14071)
+ Support for third-party network plugins (#13424)
+ Ability to dynamically connect containers to multiple networks (#16645)
+ Support for user-defined IP address management via pluggable IPAM drivers (#16910)
+ Add daemon flags `--cluster-store` and `--cluster-advertise` for built-in nodes discovery (#16229)
+ Add `--cluster-store-opt` for setting up TLS settings (#16644)
+ Add `--dns-opt` to the daemon (#16031)
- DEPRECATE following container `NetworkSettings` fields in API v1.21: `EndpointID`, `Gateway`,
`GlobalIPv6Address`, `GlobalIPv6PrefixLen`, `IPAddress`, `IPPrefixLen`, `IPv6Gateway` and `MacAddress`.
Those are now specific to the `bridge` network. Use `NetworkSettings.Networks` to inspect
the networking settings of a container per network.
## Volumes
+ New top-level `volume` subcommand and API (#14242)
- Move API volume driver settings to host-specific config (#15798)
- Print an error message if volume name is not unique (#16009)
- Ensure volumes created from Dockerfiles always use the local volume driver
(#15507)
- DEPRECATE auto-creating missing host paths for bind mounts (#16349)
## Logging
+ Add `awslogs` logging driver for Amazon CloudWatch (#15495)
+ Add generic `tag` log option to allow customizing container/image
information passed to driver (e.g. show container names) (#15384)
- Implement the `docker logs` endpoint for the journald driver (#13707)
- DEPRECATE driver-specific log tags (e.g. `syslog-tag`, etc.) (#15384)
## Distribution
+ `docker search` now works with partial names (#16509)
- Push optimization: avoid buffering to file (#15493)
- The daemon will display progress for images that were already being pulled
by another client (#15489)
- Only permissions required for the current action being performed are requested (#)
+ Renaming trust keys (and respective environment variables) from `offline` to
`root` and `tagging` to `repository` (#16894)
- DEPRECATE trust key environment variables
`DOCKER_CONTENT_TRUST_OFFLINE_PASSPHRASE` and
`DOCKER_CONTENT_TRUST_TAGGING_PASSPHRASE` (#16894)
## Security
+ Add SELinux profiles to the rpm package (#15832)
- Fix various issues with AppArmor profiles provided in the deb package
(#14609)
- Add AppArmor policy that prevents writing to /proc (#15571)
## 1.8.3 (2015-10-12)
### Distribution
+2 -10
View File
@@ -58,16 +58,9 @@ RUN apt-get update && apt-get install -y \
ruby1.9.1-dev \
s3cmd=1.1.0* \
ubuntu-zfs \
xfsprogs \
libzfs-dev \
--no-install-recommends
# clr
RUN echo deb http://download.opensuse.org/repositories/home:/clearlinux:/preview/xUbuntu_15.04/ / > /etc/apt/sources.list.d/clear-containers-docker.list
RUN apt-get --allow-unauthenticated update && apt-get install -y --force-yes \
kvmtool\
linux-container
# Get lvm2 source for compiling statically
RUN git clone -b v2_02_103 https://git.fedorahosted.org/git/lvm2.git /usr/local/lvm2
# see https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags
@@ -157,11 +150,10 @@ RUN set -x \
&& rm -rf "$GOPATH"
# Get the "docker-py" source so we can run their integration tests
ENV DOCKER_PY_COMMIT 47ab89ec2bd3bddf1221b856ffbaff333edeabb4
ENV DOCKER_PY_COMMIT 139850f3f3b17357bab5ba3edfb745fb14043764
RUN git clone https://github.com/docker/docker-py.git /docker-py \
&& cd /docker-py \
&& git checkout -q $DOCKER_PY_COMMIT \
&& pip install -r test-requirements.txt
&& git checkout -q $DOCKER_PY_COMMIT
# Setup s3cmd config
RUN { \
-1
View File
@@ -23,7 +23,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
e2fsprogs \
iptables \
procps \
xfsprogs \
xz-utils \
\
aufs-tools \
+1 -1
View File
@@ -1 +1 @@
1.9.1-clear-containers
1.9.0-dev
+1 -6
View File
@@ -112,13 +112,8 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientFlags *cli.ClientF
return errors.New("Please specify only one -H")
}
defaultHost := opts.DefaultTCPHost
if clientFlags.Common.TLSOptions != nil {
defaultHost = opts.DefaultTLSHost
}
var e error
if hosts[0], e = opts.ParseHost(defaultHost, hosts[0]); e != nil {
if hosts[0], e = opts.ParseHost(hosts[0]); e != nil {
return e
}
-3
View File
@@ -107,8 +107,5 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
fmt.Fprintf(cli.out, "Cluster store: %s\n", info.ClusterStore)
}
if info.ClusterAdvertise != "" {
fmt.Fprintf(cli.out, "Cluster advertise: %s\n", info.ClusterAdvertise)
}
return nil
}
+27 -66
View File
@@ -59,21 +59,17 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
}
for _, name := range cmd.Args() {
if *inspectType == "" || *inspectType == "container" {
obj, _, err = readBody(cli.call("GET", "/containers/"+name+"/json?"+v.Encode(), nil, nil))
if err != nil {
if err == errConnectionFailed {
return err
}
if *inspectType == "container" {
if strings.Contains(err.Error(), "No such") {
fmt.Fprintf(cli.err, "Error: No such container: %s\n", name)
} else {
fmt.Fprintf(cli.err, "%s", err)
}
status = 1
continue
if err != nil && *inspectType == "container" {
if strings.Contains(err.Error(), "No such") {
fmt.Fprintf(cli.err, "Error: No such container: %s\n", name)
} else {
fmt.Fprintf(cli.err, "%s", err)
}
status = 1
continue
}
}
@@ -81,9 +77,6 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
obj, _, err = readBody(cli.call("GET", "/images/"+name+"/json", nil, nil))
isImage = true
if err != nil {
if err == errConnectionFailed {
return err
}
if strings.Contains(err.Error(), "No such") {
if *inspectType == "" {
fmt.Fprintf(cli.err, "Error: No such image or container: %s\n", name)
@@ -96,6 +89,7 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
status = 1
continue
}
}
if tmpl == nil {
@@ -107,45 +101,42 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
} else {
rdr := bytes.NewReader(obj)
dec := json.NewDecoder(rdr)
buf := bytes.NewBufferString("")
if isImage {
inspPtr := types.ImageInspect{}
if err := dec.Decode(&inspPtr); err != nil {
fmt.Fprintf(cli.err, "Unable to read inspect data: %v\n", err)
fmt.Fprintf(cli.err, "%s\n", err)
status = 1
break
continue
}
if err := tmpl.Execute(buf, inspPtr); err != nil {
if err := tmpl.Execute(cli.out, inspPtr); err != nil {
rdr.Seek(0, 0)
var ok bool
if buf, ok = cli.decodeRawInspect(tmpl, dec); !ok {
fmt.Fprintf(cli.err, "Template parsing error: %v\n", err)
status = 1
break
var raw interface{}
if err := dec.Decode(&raw); err != nil {
return err
}
if err = tmpl.Execute(cli.out, raw); err != nil {
return err
}
}
} else {
inspPtr := types.ContainerJSON{}
if err := dec.Decode(&inspPtr); err != nil {
fmt.Fprintf(cli.err, "Unable to read inspect data: %v\n", err)
fmt.Fprintf(cli.err, "%s\n", err)
status = 1
break
continue
}
if err := tmpl.Execute(buf, inspPtr); err != nil {
if err := tmpl.Execute(cli.out, inspPtr); err != nil {
rdr.Seek(0, 0)
var ok bool
if buf, ok = cli.decodeRawInspect(tmpl, dec); !ok {
fmt.Fprintf(cli.err, "Template parsing error: %v\n", err)
status = 1
break
var raw interface{}
if err := dec.Decode(&raw); err != nil {
return err
}
if err = tmpl.Execute(cli.out, raw); err != nil {
return err
}
}
}
cli.out.Write(buf.Bytes())
cli.out.Write([]byte{'\n'})
}
indented.WriteString(",")
@@ -171,33 +162,3 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
}
return nil
}
// decodeRawInspect executes the inspect template with a raw interface.
// This allows docker cli to parse inspect structs injected with Swarm fields.
// Unfortunately, go 1.4 doesn't fail executing invalid templates when the input is an interface.
// It doesn't allow to modify this behavior either, sending <no value> messages to the output.
// We assume that the template is invalid when there is a <no value>, if the template was valid
// we'd get <nil> or "" values. In that case we fail with the original error raised executing the
// template with the typed input.
//
// TODO: Go 1.5 allows to customize the error behavior, we can probably get rid of this as soon as
// we build Docker with that version:
// https://golang.org/pkg/text/template/#Template.Option
func (cli *DockerCli) decodeRawInspect(tmpl *template.Template, dec *json.Decoder) (*bytes.Buffer, bool) {
var raw interface{}
buf := bytes.NewBufferString("")
if rawErr := dec.Decode(&raw); rawErr != nil {
fmt.Fprintf(cli.err, "Unable to read inspect data: %v\n", rawErr)
return buf, false
}
if rawErr := tmpl.Execute(buf, raw); rawErr != nil {
return buf, false
}
if strings.Contains(buf.String(), "<no value>") {
return buf, false
}
return buf, true
}
-6
View File
@@ -6,7 +6,6 @@ import (
"fmt"
"io"
"os"
"runtime"
"strings"
"github.com/docker/docker/api/types"
@@ -34,11 +33,6 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
cmd.ParseFlags(args, true)
// On Windows, force the use of the regular OS stdin stream. Fixes #14336/#14210
if runtime.GOOS == "windows" {
cli.in = os.Stdin
}
serverAddress := registry.IndexServer
if len(cmd.Args()) > 0 {
serverAddress = cmd.Arg(0)
-10
View File
@@ -2,7 +2,6 @@ package client
import (
"encoding/json"
"fmt"
"net/url"
"time"
@@ -12,11 +11,6 @@ import (
"github.com/docker/docker/pkg/timeutils"
)
var validDrivers = map[string]bool{
"json-file": true,
"journald": true,
}
// CmdLogs fetches the logs of a given container.
//
// docker logs [OPTIONS] CONTAINER
@@ -42,10 +36,6 @@ func (cli *DockerCli) CmdLogs(args ...string) error {
return err
}
if !validDrivers[c.HostConfig.LogConfig.Type] {
return fmt.Errorf("\"logs\" command is supported only for \"json-file\" and \"journald\" logging drivers (got: %s)", c.HostConfig.LogConfig.Type)
}
v := url.Values{}
v.Set("stdout", "1")
v.Set("stderr", "1")
+14 -38
View File
@@ -54,13 +54,6 @@ func (cli *DockerCli) CmdNetworkCreate(args ...string) error {
return err
}
// Set the default driver to "" if the user didn't set the value.
// That way we can know whether it was user input or not.
driver := *flDriver
if !cmd.IsSet("-driver") && !cmd.IsSet("d") {
driver = ""
}
ipamCfg, err := consolidateIpam(flIpamSubnet.GetAll(), flIpamIPRange.GetAll(), flIpamGateway.GetAll(), flIpamAux.GetAll())
if err != nil {
return err
@@ -69,7 +62,7 @@ func (cli *DockerCli) CmdNetworkCreate(args ...string) error {
// Construct network create request body
nc := types.NetworkCreate{
Name: cmd.Arg(0),
Driver: driver,
Driver: *flDriver,
IPAM: network.IPAM{Driver: *flIpamDriver, Config: ipamCfg},
Options: flOpts.GetAll(),
CheckDuplicate: true,
@@ -191,48 +184,31 @@ func (cli *DockerCli) CmdNetworkLs(args ...string) error {
// CmdNetworkInspect inspects the network object for more details
//
// Usage: docker network inspect [OPTIONS] <NETWORK> [NETWORK...]
// Usage: docker network inspect <NETWORK>
// CmdNetworkInspect handles Network inspect UI
func (cli *DockerCli) CmdNetworkInspect(args ...string) error {
cmd := Cli.Subcmd("network inspect", []string{"NETWORK [NETWORK...]"}, "Displays detailed information on a network", false)
cmd.Require(flag.Min, 1)
cmd := Cli.Subcmd("network inspect", []string{"NETWORK"}, "Displays detailed information on a network", false)
cmd.Require(flag.Exact, 1)
err := cmd.ParseFlags(args, true)
if err != nil {
return err
}
status := 0
var networks []*types.NetworkResource
for _, name := range cmd.Args() {
obj, _, err := readBody(cli.call("GET", "/networks/"+name, nil, nil))
if err != nil {
if strings.Contains(err.Error(), "not found") {
fmt.Fprintf(cli.err, "Error: No such network: %s\n", name)
} else {
fmt.Fprintf(cli.err, "%s", err)
}
status = 1
continue
}
networkResource := types.NetworkResource{}
if err := json.NewDecoder(bytes.NewReader(obj)).Decode(&networkResource); err != nil {
return err
}
networks = append(networks, &networkResource)
}
b, err := json.MarshalIndent(networks, "", " ")
obj, _, err := readBody(cli.call("GET", "/networks/"+cmd.Arg(0), nil, nil))
if err != nil {
return err
}
if _, err := io.Copy(cli.out, bytes.NewReader(b)); err != nil {
networkResource := &types.NetworkResource{}
if err := json.NewDecoder(bytes.NewReader(obj)).Decode(networkResource); err != nil {
return err
}
io.WriteString(cli.out, "\n")
if status != 0 {
return Cli.StatusError{StatusCode: status}
indented := new(bytes.Buffer)
if err := json.Indent(indented, obj, "", " "); err != nil {
return err
}
if _, err := io.Copy(cli.out, indented); err != nil {
return err
}
return nil
}
+7 -9
View File
@@ -198,17 +198,15 @@ func (cli *DockerCli) getPassphraseRetriever() passphrase.Retriever {
// Backwards compatibility with old env names. We should remove this in 1.10
if env["root"] == "" {
if passphrase := os.Getenv("DOCKER_CONTENT_TRUST_OFFLINE_PASSPHRASE"); passphrase != "" {
env["root"] = passphrase
fmt.Fprintf(cli.err, "[DEPRECATED] The environment variable DOCKER_CONTENT_TRUST_OFFLINE_PASSPHRASE has been deprecated and will be removed in v1.10. Please use DOCKER_CONTENT_TRUST_ROOT_PASSPHRASE\n")
}
env["root"] = os.Getenv("DOCKER_CONTENT_TRUST_OFFLINE_PASSPHRASE")
fmt.Fprintf(cli.err, "[DEPRECATED] The environment variable DOCKER_CONTENT_TRUST_OFFLINE_PASSPHRASE has been deprecated and will be removed in v1.10. Please use DOCKER_CONTENT_TRUST_ROOT_PASSPHRASE\n")
}
if env["snapshot"] == "" || env["targets"] == "" {
if passphrase := os.Getenv("DOCKER_CONTENT_TRUST_TAGGING_PASSPHRASE"); passphrase != "" {
env["snapshot"] = passphrase
env["targets"] = passphrase
fmt.Fprintf(cli.err, "[DEPRECATED] The environment variable DOCKER_CONTENT_TRUST_TAGGING_PASSPHRASE has been deprecated and will be removed in v1.10. Please use DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE\n")
}
env["snapshot"] = os.Getenv("DOCKER_CONTENT_TRUST_TAGGING_PASSPHRASE")
env["targets"] = os.Getenv("DOCKER_CONTENT_TRUST_TAGGING_PASSPHRASE")
fmt.Fprintf(cli.err, "[DEPRECATED] The environment variable DOCKER_CONTENT_TRUST_TAGGING_PASSPHRASE has been deprecated and will be removed in v1.10. Please use DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE\n")
}
return func(keyName string, alias string, createNew bool, numAttempts int) (string, bool, error) {
+1 -1
View File
@@ -195,7 +195,7 @@ func (cli *DockerCli) CmdVolumeCreate(args ...string) error {
volReq.Name = *flName
}
resp, err := cli.call("POST", "/volumes/create", volReq, nil)
resp, err := cli.call("POST", "/volumes", volReq, nil)
if err != nil {
return err
}
+1 -1
View File
@@ -18,7 +18,7 @@ import (
// Common constants for daemon and client.
const (
// Version of Current REST API
Version version.Version = "1.21"
Version version.Version = "1.22"
// MinVersion represents Minimun REST API version supported
MinVersion version.Version = "1.12"
-3
View File
@@ -55,9 +55,6 @@ type ArchiveOptions struct {
// ArchiveFormValues parses form values and turns them into ArchiveOptions.
// It fails if the archive name and path are not in the request.
func ArchiveFormValues(r *http.Request, vars map[string]string) (ArchiveOptions, error) {
if vars == nil {
return ArchiveOptions{}, fmt.Errorf("Missing parameter")
}
if err := ParseForm(r); err != nil {
return ArchiveOptions{}, err
}
+4 -67
View File
@@ -56,9 +56,6 @@ func (s *router) getContainersStats(ctx context.Context, w http.ResponseWriter,
if err := httputils.ParseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
stream := httputils.BoolValueOrDefault(r, "stream", true)
var out io.Writer
@@ -66,9 +63,7 @@ func (s *router) getContainersStats(ctx context.Context, w http.ResponseWriter,
w.Header().Set("Content-Type", "application/json")
out = w
} else {
wf := ioutils.NewWriteFlusher(w)
out = wf
defer wf.Close()
out = ioutils.NewWriteFlusher(w)
}
var closeNotifier <-chan bool
@@ -90,9 +85,6 @@ func (s *router) getContainersLogs(ctx context.Context, w http.ResponseWriter, r
if err := httputils.ParseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
// Args are validated before the stream starts because when it starts we're
// sending HTTP 200 by writing an empty chunk of data to tell the client that
@@ -124,16 +116,11 @@ func (s *router) getContainersLogs(ctx context.Context, w http.ResponseWriter, r
return derr.ErrorCodeNoSuchContainer.WithArgs(containerName)
}
outStream := ioutils.NewWriteFlusher(w)
// write an empty chunk of data (this is to ensure that the
// HTTP Response is sent immediately, even if the container has
// not yet produced any data)
w.WriteHeader(http.StatusOK)
if flusher, ok := w.(http.Flusher); ok {
flusher.Flush()
}
output := ioutils.NewWriteFlusher(w)
defer output.Close()
outStream.Write(nil)
logsConfig := &daemon.ContainerLogsConfig{
Follow: httputils.BoolValue(r, "follow"),
@@ -142,7 +129,7 @@ func (s *router) getContainersLogs(ctx context.Context, w http.ResponseWriter, r
Tail: r.Form.Get("tail"),
UseStdout: stdout,
UseStderr: stderr,
OutStream: output,
OutStream: outStream,
Stop: closeNotifier,
}
@@ -157,18 +144,10 @@ func (s *router) getContainersLogs(ctx context.Context, w http.ResponseWriter, r
}
func (s *router) getContainersExport(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
return s.daemon.ContainerExport(vars["name"], w)
}
func (s *router) postContainersStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
// If contentLength is -1, we can assumed chunked encoding
// or more technically that the length is unknown
// https://golang.org/src/pkg/net/http/request.go#L139
@@ -200,9 +179,6 @@ func (s *router) postContainersStop(ctx context.Context, w http.ResponseWriter,
if err := httputils.ParseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
seconds, _ := strconv.Atoi(r.Form.Get("t"))
@@ -215,9 +191,6 @@ func (s *router) postContainersStop(ctx context.Context, w http.ResponseWriter,
}
func (s *router) postContainersKill(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := httputils.ParseForm(r); err != nil {
return err
}
@@ -254,9 +227,6 @@ func (s *router) postContainersRestart(ctx context.Context, w http.ResponseWrite
if err := httputils.ParseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
timeout, _ := strconv.Atoi(r.Form.Get("t"))
@@ -270,9 +240,6 @@ func (s *router) postContainersRestart(ctx context.Context, w http.ResponseWrite
}
func (s *router) postContainersPause(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := httputils.ParseForm(r); err != nil {
return err
}
@@ -287,9 +254,6 @@ func (s *router) postContainersPause(ctx context.Context, w http.ResponseWriter,
}
func (s *router) postContainersUnpause(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := httputils.ParseForm(r); err != nil {
return err
}
@@ -304,10 +268,6 @@ func (s *router) postContainersUnpause(ctx context.Context, w http.ResponseWrite
}
func (s *router) postContainersWait(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
status, err := s.daemon.ContainerWait(vars["name"], -1*time.Second)
if err != nil {
return err
@@ -319,10 +279,6 @@ func (s *router) postContainersWait(ctx context.Context, w http.ResponseWriter,
}
func (s *router) getContainersChanges(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
changes, err := s.daemon.ContainerChanges(vars["name"])
if err != nil {
return err
@@ -332,10 +288,6 @@ func (s *router) getContainersChanges(ctx context.Context, w http.ResponseWriter
}
func (s *router) getContainersTop(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := httputils.ParseForm(r); err != nil {
return err
}
@@ -352,9 +304,6 @@ func (s *router) postContainerRename(ctx context.Context, w http.ResponseWriter,
if err := httputils.ParseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
name := vars["name"]
newName := r.Form.Get("name")
@@ -394,9 +343,6 @@ func (s *router) deleteContainers(ctx context.Context, w http.ResponseWriter, r
if err := httputils.ParseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
name := vars["name"]
config := &daemon.ContainerRmConfig{
@@ -422,9 +368,6 @@ func (s *router) postContainersResize(ctx context.Context, w http.ResponseWriter
if err := httputils.ParseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
height, err := strconv.Atoi(r.Form.Get("h"))
if err != nil {
@@ -442,9 +385,6 @@ func (s *router) postContainersAttach(ctx context.Context, w http.ResponseWriter
if err := httputils.ParseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
containerName := vars["name"]
if !s.daemon.Exists(containerName) {
@@ -484,9 +424,6 @@ func (s *router) wsContainersAttach(ctx context.Context, w http.ResponseWriter,
if err := httputils.ParseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
containerName := vars["name"]
if !s.daemon.Exists(containerName) {
-4
View File
@@ -16,10 +16,6 @@ import (
// postContainersCopy is deprecated in favor of getContainersArchive.
func (s *router) postContainersCopy(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := httputils.CheckForJSON(r); err != nil {
return err
}
-8
View File
@@ -16,10 +16,6 @@ import (
)
func (s *router) getExecByID(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter 'id'")
}
eConfig, err := s.daemon.ContainerExecInspect(vars["id"])
if err != nil {
return err
@@ -118,10 +114,6 @@ func (s *router) postContainerExecResize(ctx context.Context, w http.ResponseWri
if err := httputils.ParseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
height, err := strconv.Atoi(r.Form.Get("h"))
if err != nil {
return err
+4 -30
View File
@@ -16,6 +16,7 @@ import (
"github.com/docker/docker/builder/dockerfile"
"github.com/docker/docker/cliconfig"
"github.com/docker/docker/daemon/daemonbuilder"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/graph"
"github.com/docker/docker/graph/tags"
"github.com/docker/docker/pkg/archive"
@@ -63,12 +64,11 @@ func (s *router) postCommit(ctx context.Context, w http.ResponseWriter, r *http.
Config: c,
}
container, err := s.daemon.Get(cname)
if err != nil {
return err
if !s.daemon.Exists(cname) {
return derr.ErrorCodeNoSuchContainer.WithArgs(cname)
}
imgID, err := dockerfile.Commit(container, s.daemon, commitCfg)
imgID, err := dockerfile.Commit(cname, s.daemon, commitCfg)
if err != nil {
return err
}
@@ -105,7 +105,6 @@ func (s *router) postImagesCreate(ctx context.Context, w http.ResponseWriter, r
err error
output = ioutils.NewWriteFlusher(w)
)
defer output.Close()
w.Header().Set("Content-Type", "application/json")
@@ -157,10 +156,6 @@ func (s *router) postImagesCreate(ctx context.Context, w http.ResponseWriter, r
}
func (s *router) postImagesPush(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
metaHeaders := map[string][]string{}
for k, v := range r.Header {
if strings.HasPrefix(k, "X-Meta-") {
@@ -189,7 +184,6 @@ func (s *router) postImagesPush(ctx context.Context, w http.ResponseWriter, r *h
name := vars["name"]
output := ioutils.NewWriteFlusher(w)
defer output.Close()
imagePushConfig := &graph.ImagePushConfig{
MetaHeaders: metaHeaders,
AuthConfig: authConfig,
@@ -210,9 +204,6 @@ func (s *router) postImagesPush(ctx context.Context, w http.ResponseWriter, r *h
}
func (s *router) getImagesGet(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := httputils.ParseForm(r); err != nil {
return err
}
@@ -220,7 +211,6 @@ func (s *router) getImagesGet(ctx context.Context, w http.ResponseWriter, r *htt
w.Header().Set("Content-Type", "application/x-tar")
output := ioutils.NewWriteFlusher(w)
defer output.Close()
var names []string
if name, ok := vars["name"]; ok {
names = []string{name}
@@ -246,9 +236,6 @@ func (s *router) deleteImages(ctx context.Context, w http.ResponseWriter, r *htt
if err := httputils.ParseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
name := vars["name"]
@@ -268,10 +255,6 @@ func (s *router) deleteImages(ctx context.Context, w http.ResponseWriter, r *htt
}
func (s *router) getImagesByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
imageInspect, err := s.daemon.LookupImage(vars["name"])
if err != nil {
return err
@@ -300,7 +283,6 @@ func (s *router) postBuild(ctx context.Context, w http.ResponseWriter, r *http.R
version := httputils.VersionFromContext(ctx)
output := ioutils.NewWriteFlusher(w)
defer output.Close()
sf := streamformatter.NewJSONStreamFormatter()
errf := func(err error) error {
// Do not write the error in the http output if it's still empty.
@@ -460,10 +442,6 @@ func (s *router) getImagesJSON(ctx context.Context, w http.ResponseWriter, r *ht
}
func (s *router) getImagesHistory(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
name := vars["name"]
history, err := s.daemon.ImageHistory(name)
if err != nil {
@@ -477,10 +455,6 @@ func (s *router) postImagesTag(ctx context.Context, w http.ResponseWriter, r *ht
if err := httputils.ParseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
repo := r.Form.Get("repo")
tag := r.Form.Get("tag")
name := vars["name"]
+11 -13
View File
@@ -52,6 +52,16 @@ func (s *router) getInfo(ctx context.Context, w http.ResponseWriter, r *http.Req
return httputils.WriteJSON(w, http.StatusOK, info)
}
func buildOutputEncoder(w http.ResponseWriter) *json.Encoder {
w.Header().Set("Content-Type", "application/json")
outStream := ioutils.NewWriteFlusher(w)
// Write an empty chunk of data.
// This is to ensure that the HTTP status code is sent immediately,
// so that it will not block the receiver.
outStream.Write(nil)
return json.NewEncoder(outStream)
}
func (s *router) getEvents(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := httputils.ParseForm(r); err != nil {
return err
@@ -77,19 +87,7 @@ func (s *router) getEvents(ctx context.Context, w http.ResponseWriter, r *http.R
return err
}
w.Header().Set("Content-Type", "application/json")
// This is to ensure that the HTTP status code is sent immediately,
// so that it will not block the receiver.
w.WriteHeader(http.StatusOK)
if flusher, ok := w.(http.Flusher); ok {
flusher.Flush()
}
output := ioutils.NewWriteFlusher(w)
defer output.Close()
enc := json.NewEncoder(output)
enc := buildOutputEncoder(w)
d := s.daemon
es := d.EventsService
current, l := es.Subscribe()
-4
View File
@@ -1,7 +1,6 @@
package local
import (
"fmt"
"net/http"
"github.com/docker/docker/api/server/httputils"
@@ -11,9 +10,6 @@ import (
// getContainersByName inspects containers configuration and serializes it as json.
func (s *router) getContainersByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
displaySize := httputils.BoolValue(r, "size")
if vars == nil {
return fmt.Errorf("Missing parameter")
}
var json interface{}
var err error
+1 -1
View File
@@ -141,7 +141,7 @@ func (r *router) initRoutes() {
NewPostRoute("/exec/{name:.*}/start", r.postContainerExecStart),
NewPostRoute("/exec/{name:.*}/resize", r.postContainerExecResize),
NewPostRoute("/containers/{name:.*}/rename", r.postContainerRename),
NewPostRoute("/volumes/create", r.postVolumesCreate),
NewPostRoute("/volumes", r.postVolumesCreate),
// PUT
NewPutRoute("/containers/{name:.*}/archive", r.putContainersArchive),
// DELETE
+6 -22
View File
@@ -1,14 +1,9 @@
package network
import (
"net/http"
"github.com/docker/docker/api/server/httputils"
"github.com/docker/docker/api/server/router"
"github.com/docker/docker/api/server/router/local"
"github.com/docker/docker/daemon"
"github.com/docker/docker/errors"
"golang.org/x/net/context"
)
// networkRouter is a router to talk with the network controller
@@ -34,24 +29,13 @@ func (r *networkRouter) Routes() []router.Route {
func (r *networkRouter) initRoutes() {
r.routes = []router.Route{
// GET
local.NewGetRoute("/networks", r.controllerEnabledMiddleware(r.getNetworksList)),
local.NewGetRoute("/networks/{id:.*}", r.controllerEnabledMiddleware(r.getNetwork)),
local.NewGetRoute("/networks", r.getNetworksList),
local.NewGetRoute("/networks/{id:.*}", r.getNetwork),
// POST
local.NewPostRoute("/networks/create", r.controllerEnabledMiddleware(r.postNetworkCreate)),
local.NewPostRoute("/networks/{id:.*}/connect", r.controllerEnabledMiddleware(r.postNetworkConnect)),
local.NewPostRoute("/networks/{id:.*}/disconnect", r.controllerEnabledMiddleware(r.postNetworkDisconnect)),
local.NewPostRoute("/networks/create", r.postNetworkCreate),
local.NewPostRoute("/networks/{id:.*}/connect", r.postNetworkConnect),
local.NewPostRoute("/networks/{id:.*}/disconnect", r.postNetworkDisconnect),
// DELETE
local.NewDeleteRoute("/networks/{id:.*}", r.controllerEnabledMiddleware(r.deleteNetwork)),
local.NewDeleteRoute("/networks/{id:.*}", r.deleteNetwork),
}
}
func (r *networkRouter) controllerEnabledMiddleware(handler httputils.APIFunc) httputils.APIFunc {
if r.daemon.NetworkControllerEnabled() {
return handler
}
return networkControllerDisabled
}
func networkControllerDisabled(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
return errors.ErrorNetworkControllerNotEnabled.WithArgs()
}
+4 -32
View File
@@ -13,7 +13,6 @@ import (
"github.com/docker/docker/daemon"
"github.com/docker/docker/daemon/network"
"github.com/docker/docker/pkg/parsers/filters"
"github.com/docker/docker/runconfig"
"github.com/docker/libnetwork"
)
@@ -86,11 +85,6 @@ func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWr
return err
}
if runconfig.IsPreDefinedNetwork(create.Name) {
return httputils.WriteJSON(w, http.StatusForbidden,
fmt.Sprintf("%s is a pre-defined network and cannot be created", create.Name))
}
nw, err := n.daemon.GetNetwork(create.Name, daemon.NetworkByName)
if _, ok := err.(libnetwork.ErrNoSuchNetwork); err != nil && !ok {
return err
@@ -132,11 +126,7 @@ func (n *networkRouter) postNetworkConnect(ctx context.Context, w http.ResponseW
return err
}
container, err := n.daemon.Get(connect.Container)
if err != nil {
return fmt.Errorf("invalid container %s : %v", container, err)
}
return container.ConnectToNetwork(nw.Name())
return n.daemon.ConnectContainerToNetwork(connect.Container, nw.Name())
}
func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
@@ -158,11 +148,7 @@ func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.Respon
return err
}
container, err := n.daemon.Get(disconnect.Container)
if err != nil {
return fmt.Errorf("invalid container %s : %v", container, err)
}
return container.DisconnectFromNetwork(nw)
return n.daemon.DisconnectContainerFromNetwork(disconnect.Container, nw)
}
func (n *networkRouter) deleteNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
@@ -175,11 +161,6 @@ func (n *networkRouter) deleteNetwork(ctx context.Context, w http.ResponseWriter
return err
}
if runconfig.IsPreDefinedNetwork(nw.Name()) {
return httputils.WriteJSON(w, http.StatusForbidden,
fmt.Sprintf("%s is a pre-defined network and cannot be removed", nw.Name()))
}
return nw.Delete()
}
@@ -199,11 +180,7 @@ func buildNetworkResource(nw libnetwork.Network) *types.NetworkResource {
epl := nw.Endpoints()
for _, e := range epl {
ei := e.Info()
if ei == nil {
continue
}
sb := ei.Sandbox()
sb := e.Info().Sandbox()
if sb == nil {
continue
}
@@ -245,12 +222,7 @@ func buildEndpointResource(e libnetwork.Endpoint) types.EndpointResource {
}
er.EndpointID = e.ID()
ei := e.Info()
if ei == nil {
return er
}
if iface := ei.Iface(); iface != nil {
if iface := e.Info().Iface(); iface != nil {
if mac := iface.MacAddress(); mac != nil {
er.MacAddress = mac.String()
}
+6 -2
View File
@@ -153,7 +153,12 @@ func (s *Server) makeHTTPHandler(handler httputils.APIFunc) http.HandlerFunc {
ctx := context.Background()
handlerFunc := s.handleWithGlobalMiddlewares(handler)
if err := handlerFunc(ctx, w, r, mux.Vars(r)); err != nil {
vars := mux.Vars(r)
if vars == nil {
vars = make(map[string]string)
}
if err := handlerFunc(ctx, w, r, vars); err != nil {
logrus.Errorf("Handler for %s %s returned error: %s", r.Method, r.URL.Path, utils.GetErrorMessage(err))
httputils.WriteError(w, err)
}
@@ -165,7 +170,6 @@ func (s *Server) makeHTTPHandler(handler httputils.APIFunc) http.HandlerFunc {
func (s *Server) InitRouters(d *daemon.Daemon) {
s.addRouter(local.NewRouter(d))
s.addRouter(network.NewRouter(d))
for _, srv := range s.servers {
srv.srv.Handler = s.CreateMux()
}
+25 -62
View File
@@ -5,7 +5,6 @@ import (
"time"
"github.com/docker/docker/daemon/network"
"github.com/docker/docker/pkg/nat"
"github.com/docker/docker/pkg/version"
"github.com/docker/docker/registry"
"github.com/docker/docker/runconfig"
@@ -97,8 +96,7 @@ type GraphDriverData struct {
// GET "/images/{name:.*}/json"
type ImageInspect struct {
ID string `json:"Id"`
RepoTags []string
RepoDigests []string
Tags []string
Parent string
Comment string
Created string
@@ -220,7 +218,6 @@ type Info struct {
ExperimentalBuild bool
ServerVersion string
ClusterStore string
ClusterAdvertise string
}
// ExecStartCheck is a temp struct used by execStart
@@ -257,6 +254,7 @@ type ContainerJSONBase struct {
Args []string
State *ContainerState
Image string
NetworkSettings *network.Settings
ResolvConfPath string
HostnamePath string
HostsPath string
@@ -278,43 +276,8 @@ type ContainerJSONBase struct {
// ContainerJSON is newly used struct along with MountPoint
type ContainerJSON struct {
*ContainerJSONBase
Mounts []MountPoint
Config *runconfig.Config
NetworkSettings *NetworkSettings
}
// NetworkSettings exposes the network settings in the api
type NetworkSettings struct {
NetworkSettingsBase
DefaultNetworkSettings
Networks map[string]*network.EndpointSettings
}
// NetworkSettingsBase holds basic information about networks
type NetworkSettingsBase struct {
Bridge string
SandboxID string
HairpinMode bool
LinkLocalIPv6Address string
LinkLocalIPv6PrefixLen int
Ports nat.PortMap
SandboxKey string
SecondaryIPAddresses []network.Address
SecondaryIPv6Addresses []network.Address
}
// DefaultNetworkSettings holds network information
// during the 2 release deprecation period.
// It will be removed in Docker 1.11.
type DefaultNetworkSettings struct {
EndpointID string
Gateway string
GlobalIPv6Address string
GlobalIPv6PrefixLen int
IPAddress string
IPPrefixLen int
IPv6Gateway string
MacAddress string
Mounts []MountPoint
Config *runconfig.Config
}
// MountPoint represents a mount point configuration inside the container.
@@ -341,7 +304,7 @@ type VolumesListResponse struct {
}
// VolumeCreateRequest contains the response for the remote API:
// POST "/volumes/create"
// POST "/volumes"
type VolumeCreateRequest struct {
Name string // Name is the requested name of the volume
Driver string // Driver is the name of the driver that should be used to create the volume
@@ -350,44 +313,44 @@ type VolumeCreateRequest struct {
// NetworkResource is the body of the "get network" http response message
type NetworkResource struct {
Name string
ID string `json:"Id"`
Scope string
Driver string
IPAM network.IPAM
Containers map[string]EndpointResource
Options map[string]string
Name string `json:"name"`
ID string `json:"id"`
Scope string `json:"scope"`
Driver string `json:"driver"`
IPAM network.IPAM `json:"ipam"`
Containers map[string]EndpointResource `json:"containers"`
Options map[string]string `json:"options"`
}
//EndpointResource contains network resources allocated and usd for a container in a network
type EndpointResource struct {
EndpointID string
MacAddress string
IPv4Address string
IPv6Address string
EndpointID string `json:"endpoint"`
MacAddress string `json:"mac_address"`
IPv4Address string `json:"ipv4_address"`
IPv6Address string `json:"ipv6_address"`
}
// NetworkCreate is the expected body of the "create network" http request message
type NetworkCreate struct {
Name string
CheckDuplicate bool
Driver string
IPAM network.IPAM
Options map[string]string
Name string `json:"name"`
CheckDuplicate bool `json:"check_duplicate"`
Driver string `json:"driver"`
IPAM network.IPAM `json:"ipam"`
Options map[string]string `json:"options"`
}
// NetworkCreateResponse is the response message sent by the server for network create call
type NetworkCreateResponse struct {
ID string `json:"Id"`
Warning string
ID string `json:"id"`
Warning string `json:"warning"`
}
// NetworkConnect represents the data to be used to connect a container to the network
type NetworkConnect struct {
Container string
Container string `json:"container"`
}
// NetworkDisconnect represents the data to be used to disconnect a container from the network
type NetworkDisconnect struct {
Container string
Container string `json:"container"`
}
+3 -10
View File
@@ -3,8 +3,6 @@ package v1p19
import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/versions/v1p20"
"github.com/docker/docker/pkg/nat"
"github.com/docker/docker/runconfig"
)
@@ -12,20 +10,15 @@ import (
// Note this is not used by the Windows daemon.
type ContainerJSON struct {
*types.ContainerJSONBase
Volumes map[string]string
VolumesRW map[string]bool
Config *ContainerConfig
NetworkSettings *v1p20.NetworkSettings
Volumes map[string]string
VolumesRW map[string]bool
Config *ContainerConfig
}
// ContainerConfig is a backcompatibility struct for APIs prior to 1.20.
type ContainerConfig struct {
*runconfig.Config
MacAddress string
NetworkDisabled bool
ExposedPorts map[nat.Port]struct{}
// backward compatibility, they now live in HostConfig
VolumeDriver string
Memory int64
+2 -14
View File
@@ -3,26 +3,20 @@ package v1p20
import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/nat"
"github.com/docker/docker/runconfig"
)
// ContainerJSON is a backcompatibility struct for the API 1.20
type ContainerJSON struct {
*types.ContainerJSONBase
Mounts []types.MountPoint
Config *ContainerConfig
NetworkSettings *NetworkSettings
Mounts []types.MountPoint
Config *ContainerConfig
}
// ContainerConfig is a backcompatibility struct used in ContainerJSON for the API 1.20
type ContainerConfig struct {
*runconfig.Config
MacAddress string
NetworkDisabled bool
ExposedPorts map[nat.Port]struct{}
// backward compatibility, they now live in HostConfig
VolumeDriver string
}
@@ -32,9 +26,3 @@ type StatsJSON struct {
types.Stats
Network types.NetworkStats `json:"network,omitempty"`
}
// NetworkSettings is a backward compatible struct for APIs prior to 1.21
type NetworkSettings struct {
types.NetworkSettingsBase
types.DefaultNetworkSettings
}
+1 -12
View File
@@ -33,8 +33,7 @@ type Context interface {
Close() error
// Stat returns an entry corresponding to path if any.
// It is recommended to return an error if path was not found.
// If path is a symlink it also returns the path to the target file.
Stat(path string) (string, FileInfo, error)
Stat(path string) (FileInfo, error)
// Open opens path from the context and returns a readable stream of it.
Open(path string) (io.ReadCloser, error)
// Walk walks the tree of the context with the function passed to it.
@@ -65,8 +64,6 @@ type PathFileInfo struct {
os.FileInfo
// FilePath holds the absolute path to the file.
FilePath string
// Name holds the basename for the file.
FileName string
}
// Path returns the absolute path to the file.
@@ -74,14 +71,6 @@ func (fi PathFileInfo) Path() string {
return fi.FilePath
}
// Name returns the basename of the file.
func (fi PathFileInfo) Name() string {
if fi.FileName != "" {
return fi.FileName
}
return fi.FileInfo.Name()
}
// Hashed defines an extra method intended for implementations of os.FileInfo.
type Hashed interface {
// Hash returns the hash of a file.
+6 -1
View File
@@ -256,7 +256,12 @@ func BuildFromConfig(config *runconfig.Config, changes []string) (*runconfig.Con
// Commit will create a new image from a container's changes
// TODO: remove daemon, make Commit a method on *Builder ?
func Commit(container *daemon.Container, d *daemon.Daemon, c *CommitConfig) (string, error) {
func Commit(containerName string, d *daemon.Daemon, c *CommitConfig) (string, error) {
container, err := d.Get(containerName)
if err != nil {
return "", err
}
// It is not possible to commit a running container on Windows
if runtime.GOOS == "windows" && container.IsRunning() {
return "", fmt.Errorf("Windows does not support commit of a running container")
+21 -14
View File
@@ -366,7 +366,7 @@ func (b *Builder) calcCopyInfo(cmdName, origPath string, allowLocalDecompression
// Must be a dir or a file
statPath, fi, err := b.context.Stat(origPath)
fi, err := b.context.Stat(origPath)
if err != nil {
return nil, err
}
@@ -383,9 +383,11 @@ func (b *Builder) calcCopyInfo(cmdName, origPath string, allowLocalDecompression
hfi.SetHash("file:" + hfi.Hash())
return copyInfos, nil
}
// Must be a dir
var subfiles []string
err = b.context.Walk(statPath, func(path string, info builder.FileInfo, err error) error {
b.context.Walk(origPath, func(path string, info builder.FileInfo, err error) error {
if err != nil {
return err
}
@@ -393,9 +395,6 @@ func (b *Builder) calcCopyInfo(cmdName, origPath string, allowLocalDecompression
subfiles = append(subfiles, info.(builder.Hashed).Hash())
return nil
})
if err != nil {
return nil, err
}
sort.Strings(subfiles)
hasher := sha256.New()
@@ -558,8 +557,9 @@ func (b *Builder) run(c *daemon.Container) error {
go func() {
select {
case <-b.cancelled:
logrus.Debugln("Build cancelled, killing container:", c.ID)
logrus.Debugln("Build cancelled, killing and removing container:", c.ID)
c.Kill()
b.removeContainer(c.ID)
case <-finished:
}
}()
@@ -583,14 +583,21 @@ func (b *Builder) run(c *daemon.Container) error {
return nil
}
func (b *Builder) removeContainer(c string) error {
rmConfig := &daemon.ContainerRmConfig{
ForceRemove: true,
RemoveVolume: true,
}
if err := b.docker.Remove(c, rmConfig); err != nil {
fmt.Fprintf(b.Stdout, "Error removing intermediate container %s: %v\n", stringid.TruncateID(c), err)
return err
}
return nil
}
func (b *Builder) clearTmp() {
for c := range b.tmpContainers {
rmConfig := &daemon.ContainerRmConfig{
ForceRemove: true,
RemoveVolume: true,
}
if err := b.docker.Remove(c, rmConfig); err != nil {
fmt.Fprintf(b.Stdout, "Error removing intermediate container %s: %v\n", stringid.TruncateID(c), err)
if err := b.removeContainer(c); err != nil {
return
}
delete(b.tmpContainers, c)
@@ -605,9 +612,9 @@ func (b *Builder) readDockerfile() error {
// back to 'Dockerfile' and use that in the error message.
if b.DockerfileName == "" {
b.DockerfileName = api.DefaultDockerfileName
if _, _, err := b.context.Stat(b.DockerfileName); os.IsNotExist(err) {
if _, err := b.context.Stat(b.DockerfileName); os.IsNotExist(err) {
lowercase := strings.ToLower(b.DockerfileName)
if _, _, err := b.context.Stat(lowercase); err == nil {
if _, err := b.context.Stat(lowercase); err == nil {
b.DockerfileName = lowercase
}
}
+35 -28
View File
@@ -5,6 +5,7 @@ import (
"io"
"os"
"path/filepath"
"strings"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/chrootarchive"
@@ -42,32 +43,26 @@ func (c *tarSumContext) Open(path string) (io.ReadCloser, error) {
return r, nil
}
func (c *tarSumContext) Stat(path string) (string, FileInfo, error) {
func (c *tarSumContext) Stat(path string) (fi FileInfo, err error) {
cleanpath, fullpath, err := c.normalize(path)
if err != nil {
return "", nil, err
return nil, err
}
st, err := os.Lstat(fullpath)
if err != nil {
return "", nil, convertPathError(err, cleanpath)
return nil, convertPathError(err, cleanpath)
}
rel, err := filepath.Rel(c.root, fullpath)
if err != nil {
return "", nil, convertPathError(err, cleanpath)
}
// We set sum to path by default for the case where GetFile returns nil.
// The usual case is if relative path is empty.
fi = PathFileInfo{st, fullpath}
// we set sum to path by default for the case where GetFile returns nil.
// The usual case is if cleanpath is empty.
sum := path
// Use the checksum of the followed path(not the possible symlink) because
// this is the file that is actually copied.
if tsInfo := c.sums.GetFile(rel); tsInfo != nil {
if tsInfo := c.sums.GetFile(cleanpath); tsInfo != nil {
sum = tsInfo.Sum()
}
fi := &HashedFileInfo{PathFileInfo{st, fullpath, filepath.Base(cleanpath)}, sum}
return rel, fi, nil
fi = &HashedFileInfo{fi, sum}
return fi, nil
}
// MakeTarSumContext returns a build Context from a tar stream.
@@ -119,7 +114,7 @@ func (c *tarSumContext) normalize(path string) (cleanpath, fullpath string, err
if err != nil {
return "", "", fmt.Errorf("Forbidden path outside the build context: %s (%s)", path, fullpath)
}
_, err = os.Lstat(fullpath)
_, err = os.Stat(fullpath)
if err != nil {
return "", "", convertPathError(err, path)
}
@@ -127,26 +122,38 @@ func (c *tarSumContext) normalize(path string) (cleanpath, fullpath string, err
}
func (c *tarSumContext) Walk(root string, walkFn WalkFunc) error {
root = filepath.Join(c.root, filepath.Join(string(filepath.Separator), root))
return filepath.Walk(root, func(fullpath string, info os.FileInfo, err error) error {
rel, err := filepath.Rel(c.root, fullpath)
for _, tsInfo := range c.sums {
path := tsInfo.Name()
path, fullpath, err := c.normalize(path)
if err != nil {
return err
}
if rel == "." {
return nil
// Any file in the context that starts with the given path will be
// picked up and its hashcode used. However, we'll exclude the
// root dir itself. We do this for a coupel of reasons:
// 1 - ADD/COPY will not copy the dir itself, just its children
// so there's no reason to include it in the hash calc
// 2 - the metadata on the dir will change when any child file
// changes. This will lead to a miss in the cache check if that
// child file is in the .dockerignore list.
if rel, err := filepath.Rel(root, path); err != nil {
return err
} else if rel == "." || strings.HasPrefix(rel, ".."+string(os.PathSeparator)) {
continue
}
sum := rel
if tsInfo := c.sums.GetFile(rel); tsInfo != nil {
sum = tsInfo.Sum()
info, err := os.Lstat(fullpath)
if err != nil {
return convertPathError(err, path)
}
fi := &HashedFileInfo{PathFileInfo{FileInfo: info, FilePath: fullpath}, sum}
if err := walkFn(rel, fi, nil); err != nil {
// TODO check context breakout?
fi := &HashedFileInfo{PathFileInfo{info, fullpath}, tsInfo.Sum()}
if err := walkFn(path, fi, nil); err != nil {
return err
}
return nil
})
}
return nil
}
func (c *tarSumContext) Remove(path string) error {
+1 -1
View File
@@ -6,7 +6,7 @@ FROM debian:jessie
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev libsystemd-journal-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.4.2
ENV GO_VERSION 1.4.3
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
@@ -6,7 +6,7 @@ FROM debian:stretch
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev libsystemd-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.4.2
ENV GO_VERSION 1.4.3
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
+1 -1
View File
@@ -6,7 +6,7 @@ FROM debian:wheezy-backports
RUN apt-get update && apt-get install -y bash-completion btrfs-tools/wheezy-backports build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev libsystemd-journal-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.4.2
ENV GO_VERSION 1.4.3
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
@@ -6,7 +6,7 @@ FROM ubuntu:precise
RUN apt-get update && apt-get install -y bash-completion build-essential curl ca-certificates debhelper git libapparmor-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.4.2
ENV GO_VERSION 1.4.3
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
+1 -1
View File
@@ -6,7 +6,7 @@ FROM ubuntu:trusty
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev libsystemd-journal-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.4.2
ENV GO_VERSION 1.4.3
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
+1 -1
View File
@@ -6,7 +6,7 @@ FROM ubuntu:vivid
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev libsystemd-journal-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.4.2
ENV GO_VERSION 1.4.3
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
+1 -1
View File
@@ -6,7 +6,7 @@ FROM ubuntu:wily
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev libsystemd-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.4.2
ENV GO_VERSION 1.4.3
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
+1 -1
View File
@@ -8,7 +8,7 @@ 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 selinux-policy selinux-policy-devel sqlite-devel tar
ENV GO_VERSION 1.4.2
ENV GO_VERSION 1.4.3
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
+1 -1
View File
@@ -7,7 +7,7 @@ FROM fedora:21
RUN yum install -y @development-tools fedora-packager
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel selinux-policy selinux-policy-devel sqlite-devel tar
ENV GO_VERSION 1.4.2
ENV GO_VERSION 1.4.3
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
+1 -1
View File
@@ -7,7 +7,7 @@ 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 selinux-policy selinux-policy-devel sqlite-devel tar
ENV GO_VERSION 1.4.2
ENV GO_VERSION 1.4.3
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
-15
View File
@@ -1,15 +0,0 @@
#
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/rpm/generate.sh"!
#
FROM fedora:23
RUN dnf install -y @development-tools fedora-packager
RUN dnf install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel selinux-policy selinux-policy-devel sqlite-devel tar
ENV GO_VERSION 1.5.1
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
+1 -1
View File
@@ -7,7 +7,7 @@ FROM opensuse:13.2
RUN zypper --non-interactive install ca-certificates* curl gzip rpm-build
RUN zypper --non-interactive install libbtrfs-devel device-mapper-devel glibc-static libselinux-devel selinux-policy selinux-policy-devel sqlite-devel tar
ENV GO_VERSION 1.4.2
ENV GO_VERSION 1.4.3
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
+1 -1
View File
@@ -7,7 +7,7 @@ FROM oraclelinux:6
RUN yum groupinstall -y "Development Tools"
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel selinux-policy selinux-policy-devel sqlite-devel tar
ENV GO_VERSION 1.4.2
ENV GO_VERSION 1.4.3
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
+1 -1
View File
@@ -7,7 +7,7 @@ FROM oraclelinux:7
RUN yum groupinstall -y "Development Tools"
RUN yum install -y --enablerepo=ol7_optional_latest btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel selinux-policy selinux-policy-devel sqlite-devel tar
ENV GO_VERSION 1.4.2
ENV GO_VERSION 1.4.3
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
+22 -56
View File
@@ -42,9 +42,6 @@
# options immediately following their corresponding long form.
# This order should be applied to lists, alternatives and code blocks.
__docker_previous_extglob_setting=$(shopt -p extglob)
shopt -s extglob
__docker_q() {
docker ${host:+-H "$host"} ${config:+--config "$config"} 2>/dev/null "$@"
}
@@ -306,7 +303,6 @@ __docker_capabilities() {
__docker_log_drivers() {
COMPREPLY=( $( compgen -W "
awslogs
fluentd
gelf
journald
@@ -318,21 +314,15 @@ __docker_log_drivers() {
__docker_log_driver_options() {
# see docs/reference/logging/index.md
local awslogs_options="awslogs-region awslogs-group awslogs-stream"
local fluentd_options="env fluentd-address labels tag"
local gelf_options="env gelf-address labels tag"
local journald_options="env labels"
local json_file_options="env labels max-file max-size"
local fluentd_options="fluentd-address tag"
local gelf_options="gelf-address tag"
local json_file_options="max-file max-size"
local syslog_options="syslog-address syslog-facility tag"
local all_options="$fluentd_options $gelf_options $journald_options $json_file_options $syslog_options"
local awslogs_options="awslogs-region awslogs-group awslogs-stream"
case $(__docker_value_of_option --log-driver) in
'')
COMPREPLY=( $( compgen -W "$all_options" -S = -- "$cur" ) )
;;
awslogs)
COMPREPLY=( $( compgen -W "$awslogs_options" -S = -- "$cur" ) )
COMPREPLY=( $( compgen -W "$fluentd_options $gelf_options $json_file_options $syslog_options" -S = -- "$cur" ) )
;;
fluentd)
COMPREPLY=( $( compgen -W "$fluentd_options" -S = -- "$cur" ) )
@@ -340,15 +330,15 @@ __docker_log_driver_options() {
gelf)
COMPREPLY=( $( compgen -W "$gelf_options" -S = -- "$cur" ) )
;;
journald)
COMPREPLY=( $( compgen -W "$journald_options" -S = -- "$cur" ) )
;;
json-file)
COMPREPLY=( $( compgen -W "$json_file_options" -S = -- "$cur" ) )
;;
syslog)
COMPREPLY=( $( compgen -W "$syslog_options" -S = -- "$cur" ) )
;;
awslogs)
COMPREPLY=( $( compgen -W "$awslogs_options" -S = -- "$cur" ) )
;;
*)
return
;;
@@ -571,18 +561,9 @@ _docker_cp() {
return
;;
*)
# combined container and filename completion
_filedir
local files=( ${COMPREPLY[@]} )
__docker_containers_all
COMPREPLY=( $( compgen -W "${COMPREPLY[*]}" -S ':' ) )
local containers=( ${COMPREPLY[@]} )
COMPREPLY=( $( compgen -W "${files[*]} ${containers[*]}" -- "$cur" ) )
if [[ "$COMPREPLY" == *: ]]; then
__docker_nospace
fi
__docker_nospace
return
;;
esac
@@ -590,13 +571,7 @@ _docker_cp() {
(( counter++ ))
if [ $cword -eq $counter ]; then
if [ -e "$prev" ]; then
__docker_containers_all
COMPREPLY=( $( compgen -W "${COMPREPLY[*]}" -S ':' ) )
__docker_nospace
else
_filedir
fi
_filedir -d
return
fi
;;
@@ -692,8 +667,6 @@ _docker_daemon() {
dm.mountopt
dm.override_udev_sync_check
dm.thinpooldev
dm.use_deferred_deletion
dm.use_deferred_removal
"
local zfs_options="zfs.fsname"
@@ -731,7 +704,7 @@ _docker_daemon() {
case "${words[$cword-2]}$prev=" in
# completions for --storage-opt
*dm.@(blkdiscard|override_udev_sync_check|use_deferred_@(removal|deletion))=*)
*dm.blkdiscard=*)
COMPREPLY=( $( compgen -W "false true" -- "${cur#=}" ) )
return
;;
@@ -739,6 +712,10 @@ _docker_daemon() {
COMPREPLY=( $( compgen -W "ext4 xfs" -- "${cur#=}" ) )
return
;;
*dm.override_udev_sync_check=*)
COMPREPLY=( $( compgen -W "false true" -- "${cur#=}" ) )
return
;;
*dm.thinpooldev=*)
_filedir
return
@@ -1077,13 +1054,6 @@ _docker_network_connect() {
_docker_network_create() {
case "$prev" in
--aux-address|--gateway|--ip-range|--opt|-o|--subnet)
return
;;
--ipam-driver)
COMPREPLY=( $( compgen -W "default" -- "$cur" ) )
return
;;
--driver|-d)
# no need to suggest drivers that allow one instance only
# (host, null)
@@ -1094,7 +1064,7 @@ _docker_network_create() {
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--aux-address --driver -d --gateway --help --ip-range --ipam-driver --opt -o --subnet" -- "$cur" ) )
COMPREPLY=( $( compgen -W "--driver -d --help" -- "$cur" ) )
;;
esac
}
@@ -1111,7 +1081,11 @@ _docker_network_inspect() {
COMPREPLY=( $( compgen -W "--help" -- "$cur" ) )
;;
*)
__docker_networks
local counter=$(__docker_pos_first_nonflag)
if [ $cword -eq $counter ]; then
__docker_networks
fi
;;
esac
}
@@ -1370,7 +1344,6 @@ _docker_run() {
--ulimit
--user -u
--uts
--volume-driver
--volumes-from
--volume -v
--workdir -w
@@ -1492,7 +1465,7 @@ _docker_run() {
on-failure:*)
;;
*)
COMPREPLY=( $( compgen -W "always no on-failure on-failure: unless-stopped" -- "$cur") )
COMPREPLY=( $( compgen -W "no on-failure on-failure: always" -- "$cur") )
;;
esac
return
@@ -1515,10 +1488,6 @@ _docker_run() {
esac
return
;;
--volume-driver)
COMPREPLY=( $( compgen -W "local" -- "$cur" ) )
return
;;
--volumes-from)
__docker_containers_all
return
@@ -1872,7 +1841,4 @@ _docker() {
return 0
}
eval "$__docker_previous_extglob_setting"
unset __docker_previous_extglob_setting
complete -F _docker docker
+1 -1
View File
@@ -339,7 +339,7 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l restart -d 'Res
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l rm -d 'Automatically remove the container when it exits (incompatible with -d)'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l security-opt -d 'Security Options'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l sig-proxy -d 'Proxy received signals to the process (non-TTY mode only). SIGCHLD, SIGSTOP, and SIGKILL are not proxied.'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l stop-signal -d 'Signal to kill a container'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l stop-signal 'Signal to kill a container'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s t -l tty -d 'Allocate a pseudo-TTY'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s u -l user -d 'Username or UID'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s v -l volume -d 'Bind mount a volume (e.g., from the host: -v /host:/container, from Docker: -v /container)'
+6 -8
View File
@@ -258,13 +258,12 @@ __docker_network_subcommand() {
"($help)*--ip-range=[Allocate container ip from a sub-range]:IP/mask: " \
"($help)*--gateway=[ipv4 or ipv6 Gateway for the master subnet]:IP: " \
"($help)*--aux-address[Auxiliary ipv4 or ipv6 addresses used by network driver]:key=IP: " \
"($help)*"{-o=,--opt=}"[Set driver specific options]:key=value: " \
"($help -)1:Network Name: " && ret=0
;;
(inspect|rm)
_arguments \
$opts_help \
"($help -)*:network:__docker_networks" && ret=0
"($help -):network:__docker_networks" && ret=0
;;
(ls)
_arguments \
@@ -334,9 +333,9 @@ __docker_volume_subcommand() {
(create)
_arguments \
$opts_help \
"($help -d --driver)"{-d,--driver=}"[Specify volume driver name]:Driver name:(local)" \
"($help -d --driver)"{-d,--driver=}"[Specify volume driver name]:Driver name: " \
"($help)--name=[Specify volume name]" \
"($help)*"{-o,--opt=}"[Set driver specific options]:Driver option: " && ret=0
"($help -o --opt)*"{-o,--opt=}"[Set driver specific options]:Driver option: " && ret=0
;;
(inspect)
_arguments \
@@ -347,7 +346,7 @@ __docker_volume_subcommand() {
(ls)
_arguments \
$opts_help \
"($help)*"{-f,--filter=}"[Provide filter values (i.e. 'dangling=true')]:filter: " \
"($help -f --filter)*"{-f,--filter=}"[Provide filter values (i.e. 'dangling=true')]:filter: " \
"($help -q --quiet)"{-q,--quiet}"[Only display volume names]" && ret=0
;;
(rm)
@@ -444,7 +443,6 @@ __docker_subcommand() {
"($help -t --tty)"{-t,--tty}"[Allocate a pseudo-tty]"
"($help -u --user)"{-u,--user=}"[Username or UID]:user:_users"
"($help)*-v[Bind mount a volume]:volume: "
"($help)--volume-driver=[Optional volume driver for the container]:volume driver:(local)"
"($help)*--volumes-from=[Mount volumes from the specified container]:volume: "
"($help -w --workdir)"{-w,--workdir=}"[Working directory inside the container]:directory:_directories"
)
@@ -475,7 +473,7 @@ __docker_subcommand() {
_arguments \
$opts_help \
"($help -a --author)"{-a,--author=}"[Author]:author: " \
"($help)*"{-c,--change=}"[Apply Dockerfile instruction to the created image]:Dockerfile:_files" \
"($help -c --change)*"{-c,--change=}"[Apply Dockerfile instruction to the created image]:Dockerfile:_files" \
"($help -m --message)"{-m,--message=}"[Commit message]:message: " \
"($help -p --pause)"{-p,--pause}"[Pause container during commit]" \
"($help -):container:__docker_containers" \
@@ -643,7 +641,7 @@ __docker_subcommand() {
(import)
_arguments \
$opts_help \
"($help)*"{-c,--change=}"[Apply Dockerfile instruction to the created image]:Dockerfile:_files" \
"($help -c --change)*"{-c,--change=}"[Apply Dockerfile instruction to the created image]:Dockerfile:_files" \
"($help -m --message)"{-m,--message=}"[Set commit message for imported image]:message: " \
"($help -):URL:(- http:// file://)" \
"($help -): :__docker_repositories_with_tags" && ret=0
+1 -1
View File
@@ -71,7 +71,7 @@ func (config *Config) InstallCommonFlags(cmd *flag.FlagSet, usageFn func(string)
cmd.Var(opts.NewListOptsRef(&config.Labels, opts.ValidateLabel), []string{"-label"}, usageFn("Set key=value labels to the daemon"))
cmd.StringVar(&config.LogConfig.Type, []string{"-log-driver"}, "json-file", usageFn("Default driver for container logs"))
cmd.Var(opts.NewMapOpts(config.LogConfig.Config, nil), []string{"-log-opt"}, usageFn("Set log driver options"))
cmd.StringVar(&config.ClusterAdvertise, []string{"-cluster-advertise"}, "", usageFn("Address or interface name to advertise"))
cmd.StringVar(&config.ClusterAdvertise, []string{"-cluster-advertise"}, "", usageFn("Address of the daemon instance to advertise"))
cmd.StringVar(&config.ClusterStore, []string{"-cluster-store"}, "", usageFn("Set the cluster store"))
cmd.Var(opts.NewMapOpts(config.ClusterOpts, nil), []string{"-cluster-store-opt"}, usageFn("Set cluster store options"))
}
+1 -1
View File
@@ -13,7 +13,7 @@ import (
var (
defaultPidFile = "/var/run/docker.pid"
defaultGraph = "/var/lib/docker"
defaultExec = "clr"
defaultExec = "native"
)
// Config defines the configuration of a docker daemon.
+8 -23
View File
@@ -153,28 +153,7 @@ func (container *Container) readHostConfig() error {
}
defer f.Close()
if err := json.NewDecoder(f).Decode(&container.hostConfig); err != nil {
return err
}
// Make sure the dns fields are never nil.
// New containers don't ever have those fields nil,
// but pre created containers can still have those nil values.
// See https://github.com/docker/docker/pull/17779
// for a more detailed explanation on why we don't want that.
if container.hostConfig.DNS == nil {
container.hostConfig.DNS = make([]string, 0)
}
if container.hostConfig.DNSSearch == nil {
container.hostConfig.DNSSearch = make([]string, 0)
}
if container.hostConfig.DNSOptions == nil {
container.hostConfig.DNSOptions = make([]string, 0)
}
return nil
return json.NewDecoder(f).Decode(&container.hostConfig)
}
func (container *Container) writeHostConfig() error {
@@ -349,12 +328,18 @@ func (streamConfig *streamConfig) StderrPipe() io.ReadCloser {
return ioutils.NewBufReader(reader)
}
func (container *Container) isNetworkAllocated() bool {
return container.NetworkSettings.IPAddress != ""
}
// cleanup releases any network resources allocated to the container along with any rules
// around how containers are linked together. It also unmounts the container's root filesystem.
func (container *Container) cleanup() {
container.releaseNetwork()
container.unmountIpcMounts(detachMounted)
if err := container.unmountIpcMounts(); err != nil {
logrus.Errorf("%s: Failed to umount ipc filesystems: %v", container.ID, err)
}
if err := container.Unmount(); err != nil {
logrus.Errorf("%s: Failed to umount filesystem: %v", container.ID, err)
-70
View File
@@ -1,15 +1,10 @@
package daemon
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/docker/docker/pkg/signal"
"github.com/docker/docker/runconfig"
"github.com/docker/docker/volume"
"github.com/docker/docker/volume/drivers"
)
func TestGetFullName(t *testing.T) {
@@ -69,68 +64,3 @@ func TestContainerStopSignal(t *testing.T) {
t.Fatalf("Expected 9, got %v", s)
}
}
func TestContainerInitDNS(t *testing.T) {
tmp, err := ioutil.TempDir("", "docker-container-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","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","MountLabel":"","ProcessLabel":"","AppArmorProfile":"","RestartCount":0,
"UpdateDns":false,"Volumes":{},"VolumesRW":{},"AppliedVolumesFrom":null}`
if err = ioutil.WriteFile(filepath.Join(containerPath, "config.json"), []byte(config), 0644); err != nil {
t.Fatal(err)
}
hostConfig := `{"Binds":[],"ContainerIDFile":"","Memory":0,"MemorySwap":0,"CpuShares":0,"CpusetCpus":"",
"Privileged":false,"PortBindings":{},"Links":null,"PublishAllPorts":false,"Dns":null,"DnsOptions":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 := initDaemonWithVolumeStore(tmp)
if err != nil {
t.Fatal(err)
}
defer volumedrivers.Unregister(volume.DefaultDriverName)
c, err := daemon.load(containerID)
if err != nil {
t.Fatal(err)
}
if c.hostConfig.DNS == nil {
t.Fatal("Expected container DNS to not be nil")
}
if c.hostConfig.DNSSearch == nil {
t.Fatal("Expected container DNSSearch to not be nil")
}
if c.hostConfig.DNSOptions == nil {
t.Fatal("Expected container DNSOptions to not be nil")
}
}
+110 -179
View File
@@ -89,25 +89,15 @@ func (container *Container) setupLinkedContainers() ([]string, error) {
return nil, err
}
bridgeSettings := container.NetworkSettings.Networks["bridge"]
if bridgeSettings == nil {
return nil, nil
}
if len(children) > 0 {
for linkAlias, child := range children {
if !child.IsRunning() {
return nil, derr.ErrorCodeLinkNotRunning.WithArgs(child.Name, linkAlias)
}
childBridgeSettings := child.NetworkSettings.Networks["bridge"]
if childBridgeSettings == nil {
return nil, fmt.Errorf("container %d not attached to default bridge network", child.ID)
}
link := links.NewLink(
bridgeSettings.IPAddress,
childBridgeSettings.IPAddress,
container.NetworkSettings.IPAddress,
child.NetworkSettings.IPAddress,
linkAlias,
child.Config.Env,
child.Config.ExposedPorts,
@@ -228,12 +218,6 @@ func populateCommand(c *Container, env []string) error {
} else {
ipc.HostIpc = c.hostConfig.IpcMode.IsHost()
if ipc.HostIpc {
if _, err := os.Stat("/dev/shm"); err != nil {
return fmt.Errorf("/dev/shm is not mounted, but must be for --ipc=host")
}
if _, err := os.Stat("/dev/mqueue"); err != nil {
return fmt.Errorf("/dev/mqueue is not mounted, but must be for --ipc=host")
}
c.ShmPath = "/dev/shm"
c.MqueuePath = "/dev/mqueue"
}
@@ -541,9 +525,6 @@ func (container *Container) buildSandboxOptions(n libnetwork.Network) ([]libnetw
}
for linkAlias, child := range children {
if !isLinkable(child) {
return nil, fmt.Errorf("Cannot link to %s, as it does not belong to the default network", child.Name)
}
_, alias := path.Split(linkAlias)
// allow access to the linked container via the alias, real name, and container hostname
aliasList := alias + " " + child.Config.Hostname
@@ -551,14 +532,13 @@ func (container *Container) buildSandboxOptions(n libnetwork.Network) ([]libnetw
if alias != child.Name[1:] {
aliasList = aliasList + " " + child.Name[1:]
}
sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, child.NetworkSettings.Networks["bridge"].IPAddress))
sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, child.NetworkSettings.IPAddress))
cEndpoint, _ := child.getEndpointInNetwork(n)
if cEndpoint != nil && cEndpoint.ID() != "" {
childEndpoints = append(childEndpoints, cEndpoint.ID())
}
}
bridgeSettings := container.NetworkSettings.Networks["bridge"]
refs := container.daemon.containerGraph().RefPaths(container.ID)
for _, ref := range refs {
if ref.ParentID == "0" {
@@ -571,8 +551,8 @@ func (container *Container) buildSandboxOptions(n libnetwork.Network) ([]libnetw
}
if c != nil && !container.daemon.configStore.DisableBridge && container.hostConfig.NetworkMode.IsPrivate() {
logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", c.ID, ref.Name, bridgeSettings.IPAddress)
sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate(c.ID, ref.Name, bridgeSettings.IPAddress))
logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", c.ID, ref.Name, container.NetworkSettings.IPAddress)
sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate(c.ID, ref.Name, container.NetworkSettings.IPAddress))
if ep.ID() != "" {
parentEndpoints = append(parentEndpoints, ep.ID())
}
@@ -591,12 +571,6 @@ func (container *Container) buildSandboxOptions(n libnetwork.Network) ([]libnetw
return sboxOptions, nil
}
func isLinkable(child *Container) bool {
// A container is linkable only if it belongs to the default network
_, ok := child.NetworkSettings.Networks["bridge"]
return ok
}
func (container *Container) getEndpointInNetwork(n libnetwork.Network) (libnetwork.Endpoint, error) {
endpointName := strings.TrimPrefix(container.Name, "/")
return n.EndpointByName(endpointName)
@@ -621,10 +595,12 @@ func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint, networkSett
return networkSettings, nil
}
if networkSettings.Ports == nil {
networkSettings.Ports = nat.PortMap{}
if mac, ok := driverInfo[netlabel.MacAddress]; ok {
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 {
@@ -656,7 +632,7 @@ func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint, networkSett
return networkSettings, nil
}
func (container *Container) buildEndpointInfo(n libnetwork.Network, ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) {
func (container *Container) buildEndpointInfo(ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) {
if ep == nil {
return nil, derr.ErrorCodeEmptyEndpoint
}
@@ -671,50 +647,36 @@ func (container *Container) buildEndpointInfo(n libnetwork.Network, ep libnetwor
return networkSettings, nil
}
if _, ok := networkSettings.Networks[n.Name()]; !ok {
networkSettings.Networks[n.Name()] = new(network.EndpointSettings)
}
networkSettings.Networks[n.Name()].EndpointID = ep.ID()
iface := epInfo.Iface()
if iface == nil {
return networkSettings, nil
}
if iface.MacAddress() != nil {
networkSettings.Networks[n.Name()].MacAddress = iface.MacAddress().String()
}
if iface.Address() != nil {
ones, _ := iface.Address().Mask.Size()
networkSettings.Networks[n.Name()].IPAddress = iface.Address().IP.String()
networkSettings.Networks[n.Name()].IPPrefixLen = ones
networkSettings.IPAddress = iface.Address().IP.String()
networkSettings.IPPrefixLen = ones
}
if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil {
onesv6, _ := iface.AddressIPv6().Mask.Size()
networkSettings.Networks[n.Name()].GlobalIPv6Address = iface.AddressIPv6().IP.String()
networkSettings.Networks[n.Name()].GlobalIPv6PrefixLen = onesv6
networkSettings.GlobalIPv6Address = iface.AddressIPv6().IP.String()
networkSettings.GlobalIPv6PrefixLen = onesv6
}
return networkSettings, nil
}
func (container *Container) updateJoinInfo(n libnetwork.Network, ep libnetwork.Endpoint) error {
if _, err := container.buildPortMapInfo(ep, container.NetworkSettings); err != nil {
return err
}
func (container *Container) updateJoinInfo(ep libnetwork.Endpoint) error {
epInfo := ep.Info()
if epInfo == nil {
// It is not an error to get an empty endpoint info
return nil
}
if epInfo.Gateway() != nil {
container.NetworkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String()
}
container.NetworkSettings.Gateway = epInfo.Gateway().String()
if epInfo.GatewayIPv6().To16() != nil {
container.NetworkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String()
container.NetworkSettings.IPv6Gateway = epInfo.GatewayIPv6().String()
}
return nil
@@ -722,14 +684,11 @@ func (container *Container) updateJoinInfo(n libnetwork.Network, ep libnetwork.E
func (container *Container) updateNetworkSettings(n libnetwork.Network) error {
if container.NetworkSettings == nil {
container.NetworkSettings = &network.Settings{Networks: make(map[string]*network.EndpointSettings)}
container.NetworkSettings = &network.Settings{Networks: []string{}}
}
settings := container.NetworkSettings
if !container.hostConfig.NetworkMode.IsHost() && runconfig.NetworkMode(n.Type()).IsHost() {
return runconfig.ErrConflictHostNetwork
}
for s := range container.NetworkSettings.Networks {
for _, s := range settings.Networks {
sn, err := container.daemon.FindNetwork(s)
if err != nil {
continue
@@ -748,13 +707,18 @@ func (container *Container) updateNetworkSettings(n libnetwork.Network) error {
return runconfig.ErrConflictNoNetwork
}
}
container.NetworkSettings.Networks[n.Name()] = new(network.EndpointSettings)
settings.Networks = append(settings.Networks, n.Name())
return nil
}
func (container *Container) updateEndpointNetworkSettings(n libnetwork.Network, ep libnetwork.Endpoint) error {
networkSettings, err := container.buildEndpointInfo(n, ep, container.NetworkSettings)
networkSettings, err := container.buildPortMapInfo(ep, container.NetworkSettings)
if err != nil {
return err
}
networkSettings, err = container.buildEndpointInfo(ep, networkSettings)
if err != nil {
return err
}
@@ -785,7 +749,7 @@ func (container *Container) updateNetwork() error {
// Find if container is connected to the default bridge network
var n libnetwork.Network
for name := range container.NetworkSettings.Networks {
for _, name := range container.NetworkSettings.Networks {
sn, err := container.daemon.FindNetwork(name)
if err != nil {
continue
@@ -813,7 +777,7 @@ func (container *Container) updateNetwork() error {
return nil
}
func (container *Container) buildCreateEndpointOptions(n libnetwork.Network) ([]libnetwork.EndpointOption, error) {
func (container *Container) buildCreateEndpointOptions() ([]libnetwork.EndpointOption, error) {
var (
portSpecs = make(nat.PortSet)
bindings = make(nat.PortMap)
@@ -822,17 +786,6 @@ func (container *Container) buildCreateEndpointOptions(n libnetwork.Network) ([]
createOptions []libnetwork.EndpointOption
)
if n.Name() == "bridge" || container.NetworkSettings.IsAnonymousEndpoint {
createOptions = append(createOptions, libnetwork.CreateOptionAnonymous())
}
// Other configs are applicable only for the endpoint in the network
// to which container was connected to on docker run.
if n.Name() != container.hostConfig.NetworkMode.NetworkName() &&
!(n.Name() == "bridge" && container.hostConfig.NetworkMode.IsDefault()) {
return createOptions, nil
}
if container.Config.ExposedPorts != nil {
portSpecs = container.Config.ExposedPorts
}
@@ -922,16 +875,11 @@ func createNetwork(controller libnetwork.NetworkController, dnet string, driver
}
func (container *Container) allocateNetwork() error {
controller := container.daemon.netController
// Cleanup any stale sandbox left over due to ungraceful daemon shutdown
if err := controller.SandboxDestroy(container.ID); err != nil {
logrus.Errorf("failed to cleanup up stale network sandbox for container %s", container.ID)
}
settings := container.NetworkSettings.Networks
updateSettings := false
if len(container.NetworkSettings.Networks) == 0 {
if settings == nil {
mode := container.hostConfig.NetworkMode
controller := container.daemon.netController
if container.Config.NetworkDisabled || mode.IsContainer() {
return nil
}
@@ -940,54 +888,32 @@ func (container *Container) allocateNetwork() error {
if mode.IsDefault() {
networkName = controller.Config().Daemon.DefaultNetwork
}
if mode.IsUserDefined() {
n, err := container.daemon.FindNetwork(networkName)
if err != nil {
return err
}
networkName = n.Name()
}
container.NetworkSettings.Networks = make(map[string]*network.EndpointSettings)
container.NetworkSettings.Networks[networkName] = new(network.EndpointSettings)
settings = []string{networkName}
updateSettings = true
}
for n := range container.NetworkSettings.Networks {
for _, n := range settings {
if err := container.connectToNetwork(n, updateSettings); err != nil {
return err
if updateSettings {
return err
}
// dont fail a container restart case if the user removed the network
logrus.Warnf("Could not connect container %s : %v", container.ID, err)
}
}
return container.writeHostConfig()
}
func (container *Container) getNetworkSandbox() libnetwork.Sandbox {
var sb libnetwork.Sandbox
container.daemon.netController.WalkSandboxes(func(s libnetwork.Sandbox) bool {
if s.ContainerID() == container.ID {
sb = s
return true
}
return false
})
return sb
}
// ConnectToNetwork connects a container to a network
// ConnectToNetwork connects a container to a netork
func (container *Container) ConnectToNetwork(idOrName string) error {
if !container.Running {
return derr.ErrorCodeNotRunning.WithArgs(container.ID)
}
if err := container.connectToNetwork(idOrName, true); err != nil {
return err
}
if err := container.toDiskLocking(); err != nil {
return fmt.Errorf("Error saving container to disk: %v", err)
}
return nil
return container.connectToNetwork(idOrName, true)
}
func (container *Container) connectToNetwork(idOrName string, updateSettings bool) (err error) {
func (container *Container) connectToNetwork(idOrName string, updateSettings bool) error {
if container.hostConfig.NetworkMode.IsContainer() {
return runconfig.ErrConflictSharedNetwork
}
@@ -1012,37 +938,35 @@ func (container *Container) connectToNetwork(idOrName string, updateSettings boo
}
ep, err := container.getEndpointInNetwork(n)
if err == nil {
return fmt.Errorf("container already connected to network %s", idOrName)
}
if _, ok := err.(libnetwork.ErrNoSuchEndpoint); !ok {
return err
}
createOptions, err := container.buildCreateEndpointOptions(n)
if err != nil {
return err
}
endpointName := strings.TrimPrefix(container.Name, "/")
ep, err = n.CreateEndpoint(endpointName, createOptions...)
if err != nil {
return err
}
defer func() {
if err != nil {
if e := ep.Delete(); e != nil {
logrus.Warnf("Could not rollback container connection to network %s", idOrName)
}
if _, ok := err.(libnetwork.ErrNoSuchEndpoint); !ok {
return err
}
}()
createOptions, err := container.buildCreateEndpointOptions()
if err != nil {
return err
}
endpointName := strings.TrimPrefix(container.Name, "/")
ep, err = n.CreateEndpoint(endpointName, createOptions...)
if err != nil {
return err
}
}
if err := container.updateEndpointNetworkSettings(n, ep); err != nil {
return err
}
sb := container.getNetworkSandbox()
var sb libnetwork.Sandbox
controller.WalkSandboxes(func(s libnetwork.Sandbox) bool {
if s.ContainerID() == container.ID {
sb = s
return true
}
return false
})
if sb == nil {
options, err := container.buildSandboxOptions(n)
if err != nil {
@@ -1052,15 +976,15 @@ func (container *Container) connectToNetwork(idOrName string, updateSettings boo
if err != nil {
return err
}
container.updateSandboxNetworkSettings(sb)
}
container.updateSandboxNetworkSettings(sb)
if err := ep.Join(sb); err != nil {
return err
}
if err := container.updateJoinInfo(n, ep); err != nil {
if err := container.updateJoinInfo(ep); err != nil {
return derr.ErrorCodeJoinInfo.WithArgs(err)
}
@@ -1187,9 +1111,6 @@ func (container *Container) releaseNetwork() {
sid := container.NetworkSettings.SandboxID
networks := container.NetworkSettings.Networks
for n := range networks {
networks[n] = &network.EndpointSettings{}
}
container.NetworkSettings = &network.Settings{Networks: networks}
@@ -1203,6 +1124,14 @@ func (container *Container) releaseNetwork() {
return
}
for _, ns := range networks {
n, err := container.daemon.FindNetwork(ns)
if err != nil {
continue
}
container.disconnectFromNetwork(n, false)
}
if err := sb.Delete(); err != nil {
logrus.Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err)
}
@@ -1214,32 +1143,17 @@ func (container *Container) DisconnectFromNetwork(n libnetwork.Network) error {
return derr.ErrorCodeNotRunning.WithArgs(container.ID)
}
if container.hostConfig.NetworkMode.IsHost() && runconfig.NetworkMode(n.Type()).IsHost() {
return runconfig.ErrConflictHostNetwork
}
if err := container.disconnectFromNetwork(n); err != nil {
return err
}
if err := container.toDiskLocking(); err != nil {
return fmt.Errorf("Error saving container to disk: %v", err)
}
return nil
return container.disconnectFromNetwork(n, true)
}
func (container *Container) disconnectFromNetwork(n libnetwork.Network) error {
func (container *Container) disconnectFromNetwork(n libnetwork.Network, updateSettings bool) error {
var (
ep libnetwork.Endpoint
sbox libnetwork.Sandbox
)
s := func(current libnetwork.Endpoint) bool {
epInfo := current.Info()
if epInfo == nil {
return false
}
if sb := epInfo.Sandbox(); sb != nil {
if sb := current.Info().Sandbox(); sb != nil {
if sb.ContainerID() == container.ID {
ep = current
sbox = sb
@@ -1262,7 +1176,20 @@ func (container *Container) disconnectFromNetwork(n libnetwork.Network) error {
return fmt.Errorf("endpoint delete failed for container %s on network %s: %v", container.ID, n.Name(), err)
}
delete(container.NetworkSettings.Networks, n.Name())
if updateSettings {
networks := container.NetworkSettings.Networks
for i, s := range networks {
sn, err := container.daemon.FindNetwork(s)
if err != nil {
continue
}
if sn.Name() == n.Name() {
networks = append(networks[:i], networks[i+1:]...)
container.NetworkSettings.Networks = networks
break
}
}
}
return nil
}
@@ -1482,21 +1409,22 @@ func (container *Container) setupIpcDirs() error {
return nil
}
func (container *Container) unmountIpcMounts(unmount func(pth string) error) {
func (container *Container) unmountIpcMounts() error {
if container.hostConfig.IpcMode.IsContainer() || container.hostConfig.IpcMode.IsHost() {
return
return nil
}
var warnings []string
var errors []string
if !container.hasMountFor("/dev/shm") {
shmPath, err := container.shmPath()
if err != nil {
logrus.Error(err)
warnings = append(warnings, err.Error())
} else if shmPath != "" {
if err := unmount(shmPath); err != nil {
warnings = append(warnings, fmt.Sprintf("failed to umount %s: %v", shmPath, err))
errors = append(errors, err.Error())
} else {
if err := detachMounted(shmPath); err != nil {
logrus.Errorf("failed to umount %s: %v", shmPath, err)
errors = append(errors, err.Error())
}
}
@@ -1506,17 +1434,20 @@ func (container *Container) unmountIpcMounts(unmount func(pth string) error) {
mqueuePath, err := container.mqueuePath()
if err != nil {
logrus.Error(err)
warnings = append(warnings, err.Error())
} else if mqueuePath != "" {
if err := unmount(mqueuePath); err != nil {
warnings = append(warnings, fmt.Sprintf("failed to umount %s: %v", mqueuePath, err))
errors = append(errors, err.Error())
} else {
if err := detachMounted(mqueuePath); err != nil {
logrus.Errorf("failed to umount %s: %v", mqueuePath, err)
errors = append(errors, err.Error())
}
}
}
if len(warnings) > 0 {
logrus.Warnf("failed to cleanup ipc mounts:\n%v", strings.Join(warnings, "\n"))
if len(errors) > 0 {
return fmt.Errorf("failed to cleanup ipc mounts:\n%v", strings.Join(errors, "\n"))
}
return nil
}
func (container *Container) ipcMounts() []execdriver.Mount {
+2 -5
View File
@@ -183,14 +183,11 @@ func (container *Container) removeMountPoints(_ bool) error {
return nil
}
func (container *Container) unmountIpcMounts(unmount func(pth string) error) {
}
func detachMounted(path string) error {
func (container *Container) setupIpcDirs() error {
return nil
}
func (container *Container) setupIpcDirs() error {
func (container *Container) unmountIpcMounts() error {
return nil
}
+24 -32
View File
@@ -12,6 +12,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"regexp"
"runtime"
"strings"
"sync"
@@ -38,7 +39,6 @@ import (
"github.com/docker/docker/pkg/graphdb"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/mount"
"github.com/docker/docker/pkg/namesgenerator"
"github.com/docker/docker/pkg/nat"
"github.com/docker/docker/pkg/parsers/filters"
@@ -50,7 +50,6 @@ import (
"github.com/docker/docker/pkg/truncindex"
"github.com/docker/docker/registry"
"github.com/docker/docker/runconfig"
"github.com/docker/docker/utils"
volumedrivers "github.com/docker/docker/volume/drivers"
"github.com/docker/docker/volume/local"
"github.com/docker/docker/volume/store"
@@ -58,8 +57,8 @@ import (
)
var (
validContainerNameChars = utils.RestrictedNameChars
validContainerNamePattern = utils.RestrictedNamePattern
validContainerNameChars = `[a-zA-Z0-9][a-zA-Z0-9_.-]`
validContainerNamePattern = regexp.MustCompile(`^/?` + validContainerNameChars + `+$`)
errSystemNotSupported = errors.New("The Docker daemon is not supported on this platform.")
)
@@ -223,8 +222,9 @@ func (daemon *Daemon) Register(container *Container) error {
}
daemon.execDriver.Terminate(cmd)
container.unmountIpcMounts(mount.Unmount)
if err := container.unmountIpcMounts(); err != nil {
logrus.Errorf("%s: Failed to umount ipc filesystems: %v", container.ID, err)
}
if err := container.Unmount(); err != nil {
logrus.Debugf("unmount error %s", err)
}
@@ -406,12 +406,20 @@ func (daemon *Daemon) reserveName(id, name string) (string, error) {
conflictingContainer, err := daemon.GetByName(name)
if err != nil {
return "", err
}
return "", fmt.Errorf(
"Conflict. The name %q is already in use by container %s. You have to remove (or rename) that container to be able to reuse that name.", strings.TrimPrefix(name, "/"),
stringid.TruncateID(conflictingContainer.ID))
if strings.Contains(err.Error(), "Could not find entity") {
return "", err
}
// Remove name and continue starting the container
if err := daemon.containerGraphDB.Delete(name); err != nil {
return "", err
}
} else {
nameAsKnownByUser := strings.TrimPrefix(name, "/")
return "", fmt.Errorf(
"Conflict. The name %q is already in use by container %s. You have to remove (or rename) that container to be able to reuse that name.", nameAsKnownByUser,
stringid.TruncateID(conflictingContainer.ID))
}
}
return name, nil
}
@@ -468,9 +476,8 @@ func (daemon *Daemon) getEntrypointAndArgs(configEntrypoint *stringutils.StrSlic
func (daemon *Daemon) newContainer(name string, config *runconfig.Config, imgID string) (*Container, error) {
var (
id string
err error
noExplicitName = name == ""
id string
err error
)
id, name, err = daemon.generateIDAndName(name)
if err != nil {
@@ -487,7 +494,7 @@ func (daemon *Daemon) newContainer(name string, config *runconfig.Config, imgID
base.Config = config
base.hostConfig = &runconfig.HostConfig{}
base.ImageID = imgID
base.NetworkSettings = &network.Settings{IsAnonymousEndpoint: noExplicitName}
base.NetworkSettings = &network.Settings{}
base.Name = name
base.Driver = daemon.driver.String()
base.ExecDriver = daemon.execDriver.Name()
@@ -754,17 +761,10 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
// initialized, the daemon is registered and we can store the discovery backend as its read-only
// DiscoveryWatcher version.
if config.ClusterStore != "" && config.ClusterAdvertise != "" {
advertise, err := discovery.ParseAdvertise(config.ClusterStore, config.ClusterAdvertise)
if err != nil {
return nil, fmt.Errorf("discovery advertise parsing failed (%v)", err)
}
config.ClusterAdvertise = advertise
d.discoveryWatcher, err = initDiscovery(config.ClusterStore, config.ClusterAdvertise, config.ClusterOpts)
if err != nil {
var err error
if d.discoveryWatcher, err = initDiscovery(config.ClusterStore, config.ClusterAdvertise, config.ClusterOpts); err != nil {
return nil, fmt.Errorf("discovery initialization failed (%v)", err)
}
} else if config.ClusterAdvertise != "" {
return nil, fmt.Errorf("invalid cluster configuration. --cluster-advertise must be accompanied by --cluster-store configuration")
}
d.netController, err = d.initNetworkController(config)
@@ -1136,14 +1136,6 @@ func (daemon *Daemon) GetRemappedUIDGID() (int, int) {
// created. nil is returned if a child cannot be found. An error is
// returned if the parent image cannot be found.
func (daemon *Daemon) ImageGetCached(imgID string, config *runconfig.Config) (*image.Image, error) {
// for now just exit if imgID has no children.
// maybe parentRefs in graph could be used to store
// the Image obj children for faster lookup below but this can
// be quite memory hungry.
if !daemon.Graph().HasChildren(imgID) {
return nil, nil
}
// Retrieve all images
images := daemon.Graph().Map()
+1 -2
View File
@@ -9,7 +9,6 @@ import (
"strings"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/mount"
)
// cleanupMounts umounts shm/mqueue mounts for old containers
@@ -21,7 +20,7 @@ func (daemon *Daemon) cleanupMounts() error {
}
defer f.Close()
return daemon.cleanupMountsFromReader(f, mount.Unmount)
return daemon.cleanupMountsFromReader(f, detachMounted)
}
func (daemon *Daemon) cleanupMountsFromReader(reader io.Reader, unmount func(target string) error) error {
+5 -30
View File
@@ -182,7 +182,7 @@ func TestLoadWithVolume(t *testing.T) {
t.Fatal(err)
}
daemon, err := initDaemonWithVolumeStore(tmp)
daemon, err := initDaemonForVolumesTest(tmp)
if err != nil {
t.Fatal(err)
}
@@ -270,7 +270,7 @@ func TestLoadWithBindMount(t *testing.T) {
t.Fatal(err)
}
daemon, err := initDaemonWithVolumeStore(tmp)
daemon, err := initDaemonForVolumesTest(tmp)
if err != nil {
t.Fatal(err)
}
@@ -361,7 +361,7 @@ func TestLoadWithVolume17RC(t *testing.T) {
t.Fatal(err)
}
daemon, err := initDaemonWithVolumeStore(tmp)
daemon, err := initDaemonForVolumesTest(tmp)
if err != nil {
t.Fatal(err)
}
@@ -466,7 +466,7 @@ func TestRemoveLocalVolumesFollowingSymlinks(t *testing.T) {
t.Fatal(err)
}
daemon, err := initDaemonWithVolumeStore(tmp)
daemon, err := initDaemonForVolumesTest(tmp)
if err != nil {
t.Fatal(err)
}
@@ -502,7 +502,7 @@ func TestRemoveLocalVolumesFollowingSymlinks(t *testing.T) {
}
}
func initDaemonWithVolumeStore(tmp string) (*Daemon, error) {
func initDaemonForVolumesTest(tmp string) (*Daemon, error) {
daemon := &Daemon{
repository: tmp,
root: tmp,
@@ -549,28 +549,3 @@ func TestParseSecurityOpt(t *testing.T) {
t.Fatal("Expected parseSecurityOpt error, got nil")
}
}
func TestNetworkOptions(t *testing.T) {
daemon := &Daemon{}
dconfigCorrect := &Config{
CommonConfig: CommonConfig{
DefaultNetwork: "netPlugin:mynet:dev",
ClusterStore: "consul://localhost:8500",
ClusterAdvertise: "192.168.0.1:8000",
},
}
if _, err := daemon.networkOptions(dconfigCorrect); err != nil {
t.Fatalf("Expect networkOptions sucess, got error: %v", err)
}
dconfigWrong := &Config{
CommonConfig: CommonConfig{
ClusterStore: "consul://localhost:8500://test://bbb",
},
}
if _, err := daemon.networkOptions(dconfigWrong); err == nil {
t.Fatalf("Expected networkOptions error, got nil")
}
}
+7 -23
View File
@@ -114,6 +114,9 @@ func (daemon *Daemon) adaptContainerSettings(hostConfig *runconfig.HostConfig, a
// By default, MemorySwap is set to twice the size of Memory.
hostConfig.MemorySwap = hostConfig.Memory * 2
}
if hostConfig.MemoryReservation == 0 && hostConfig.Memory > 0 {
hostConfig.MemoryReservation = hostConfig.Memory
}
}
// verifyPlatformContainerSettings performs platform-specific validation of the
@@ -332,14 +335,11 @@ func (daemon *Daemon) networkOptions(dconfig *Config) ([]nwconfig.Option, error)
if strings.TrimSpace(dconfig.ClusterStore) != "" {
kv := strings.Split(dconfig.ClusterStore, "://")
if len(kv) != 2 {
if len(kv) < 2 {
return nil, fmt.Errorf("kv store daemon config must be of the form KV-PROVIDER://KV-URL")
}
options = append(options, nwconfig.OptionKVProvider(kv[0]))
options = append(options, nwconfig.OptionKVProviderURL(kv[1]))
}
if len(dconfig.ClusterOpts) > 0 {
options = append(options, nwconfig.OptionKVOpts(dconfig.ClusterOpts))
options = append(options, nwconfig.OptionKVProviderURL(strings.Join(kv[1:], "://")))
}
if daemon.discoveryWatcher != nil {
@@ -441,8 +441,6 @@ func initBridgeDriver(controller libnetwork.NetworkController, config *Config) e
return err
}
ipamV4Conf.Gateway = ip.String()
} else if bridgeName == bridge.DefaultBridgeName && ipamV4Conf.PreferredPool != "" {
logrus.Infof("Default bridge (%s) is assigned with an IP address %s. Daemon option --bip can be used to set a preferred IP address", bridgeName, ipamV4Conf.PreferredPool)
}
if config.Bridge.FixedCIDR != "" {
@@ -458,25 +456,12 @@ func initBridgeDriver(controller libnetwork.NetworkController, config *Config) e
ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.Bridge.DefaultGatewayIPv4.String()
}
var (
ipamV6Conf *libnetwork.IpamConf
deferIPv6Alloc bool
)
var ipamV6Conf *libnetwork.IpamConf
if config.Bridge.FixedCIDRv6 != "" {
_, fCIDRv6, err := net.ParseCIDR(config.Bridge.FixedCIDRv6)
if err != nil {
return err
}
// In case user has specified the daemon flag --fixed-cidr-v6 and the passed network has
// at least 48 host bits, we need to guarantee the current behavior where the containers'
// IPv6 addresses will be constructed based on the containers' interface MAC address.
// We do so by telling libnetwork to defer the IPv6 address allocation for the endpoints
// on this network until after the driver has created the endpoint and returned the
// constructed address. Libnetwork will then reserve this address with the ipam driver.
ones, _ := fCIDRv6.Mask.Size()
deferIPv6Alloc = ones <= 80
if ipamV6Conf == nil {
ipamV6Conf = &libnetwork.IpamConf{}
}
@@ -501,8 +486,7 @@ func initBridgeDriver(controller libnetwork.NetworkController, config *Config) e
netlabel.GenericData: netOption,
netlabel.EnableIPv6: config.Bridge.EnableIPv6,
}),
libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf),
libnetwork.NetworkOptionDeferIPv6Alloc(deferIPv6Alloc))
libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf))
if err != nil {
return fmt.Errorf("Error creating default \"bridge\" network: %v", err)
}
+2 -2
View File
@@ -177,7 +177,7 @@ func (d Docker) Copy(c *daemon.Container, destPath string, src builder.FileInfo,
// only needed for fixPermissions, but might as well put it before CopyFileWithTar
if destExists && destStat.IsDir() {
destPath = filepath.Join(destPath, src.Name())
destPath = filepath.Join(destPath, filepath.Base(srcPath))
}
if err := system.MkdirAll(filepath.Dir(destPath), 0755); err != nil {
@@ -193,7 +193,7 @@ func (d Docker) Copy(c *daemon.Container, destPath string, src builder.FileInfo,
// GetCachedImage returns a reference to a cached image whose parent equals `parent`
// and runconfig equals `cfg`. A cache miss is expected to return an empty ID and a nil error.
func (d Docker) GetCachedImage(imgID string, cfg *runconfig.Config) (string, error) {
cache, err := d.Daemon.ImageGetCached(imgID, cfg)
cache, err := d.Daemon.ImageGetCached(string(imgID), cfg)
if cache == nil || err != nil {
return "", err
}
+12 -10
View File
@@ -76,20 +76,22 @@ func (daemon *Daemon) rm(container *Container, forceRemove bool) (err error) {
}
}
// Container state RemovalInProgress should be used to avoid races.
if err = container.setRemovalInProgress(); err != nil {
if err == derr.ErrorCodeAlreadyRemoving {
// do not fail when the removal is in progress started by other request.
return nil
}
return derr.ErrorCodeRmState.WithArgs(err)
}
defer container.resetRemovalInProgress()
// stop collection of stats for the container regardless
// if stats are currently getting collected.
daemon.statsCollector.stopCollection(container)
element := daemon.containers.Get(container.ID)
if element == nil {
return derr.ErrorCodeRmNotFound.WithArgs(container.ID)
}
// Container state RemovalInProgress should be used to avoid races.
if err = container.setRemovalInProgress(); err != nil {
return derr.ErrorCodeRmState.WithArgs(err)
}
defer container.resetRemovalInProgress()
if err = container.Stop(3); err != nil {
return err
}
-39
View File
@@ -1,39 +0,0 @@
package daemon
import (
"io/ioutil"
"os"
"testing"
"github.com/docker/docker/runconfig"
)
func TestContainerDoubleDelete(t *testing.T) {
tmp, err := ioutil.TempDir("", "docker-daemon-unix-test-")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmp)
daemon := &Daemon{
repository: tmp,
root: tmp,
}
container := &Container{
CommonContainer: CommonContainer{
State: NewState(),
Config: &runconfig.Config{},
},
}
// Mark the container as having a delete in progress
if err := container.setRemovalInProgress(); err != nil {
t.Fatal(err)
}
// Try to remove the container when it's start is removalInProgress.
// It should ignore the container and not return an error.
if err := daemon.rm(container, true); err != nil {
t.Fatal(err)
}
}
-964
View File
@@ -1,964 +0,0 @@
// +build linux
package clr
import (
"crypto/sha512"
"errors"
"fmt"
"io"
"io/ioutil"
"math"
"net/http"
"net/url"
"os"
"os/exec"
"path"
"path/filepath"
"strconv"
"strings"
"sync"
"syscall"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/daemon/execdriver"
"github.com/docker/docker/pkg/mount"
sysinfo "github.com/docker/docker/pkg/system"
"github.com/docker/docker/pkg/term"
"github.com/docker/libnetwork/netlabel"
"github.com/kr/pty"
"github.com/opencontainers/runc/libcontainer/configs"
)
const (
// Clear Linux for Intel(R) Architecture
driverName = "clr"
envVarPrefix = "CLR_"
// variable that allows clrURL to be modified
clrEnvURL = envVarPrefix + "DOWNLOAD_URL"
// Command used for lkvm control
lkvmName = "lkvm"
// default value for clrURL
defaultClrURL = "https://download.clearlinux.org"
// upstream latest release file (found below clrURL)
latestFile = "latest"
// local "latest" information
clrFile = "latest"
// ASCII file containing a checksums for the downloaded image.
clrChecksumFile = "SHA512SUMS"
// clr kernel (not bzimage)
clrKernel = "/usr/lib/kernel/vmlinux.container"
)
var (
// upstream base URL
clrURL = defaultClrURL
)
type driver struct {
root string // root path for the driver to use
libPath string
initPath string
version string
apparmor bool
sharedRoot bool
activeContainers map[string]*activeContainer
machineMemory int64
containerPid int
sync.Mutex
ipaddr string
gateway string
macaddr string
}
type activeContainer struct {
container *configs.Config
cmd *exec.Cmd
}
type ProgressReader struct {
// The real reader
io.Reader
// Total size of download
total uint64
// Bytes received
bytes uint64
// Rate-limiting counter
lastShown int
rawURL string
}
// Read implements the Reader interface by calling the _real_ reader
// and periodically displaying progress information.
func (r *ProgressReader) Read(p []byte) (n int, err error) {
n, err = r.Reader.Read(p)
if err != nil && err != io.EOF {
// A true error occured
return n, err
}
r.bytes += uint64(n)
if r.total == 0 {
// http header did not provide size
logrus.Debugf("Read %v bytes from %v", r.bytes, r.rawURL)
} else {
percent := (float64(r.bytes) / float64(r.total)) * 100
// rate-limit to only display messages for every 10% downloaded
next := int(percent / 10)
if r.lastShown == -1 || next > r.lastShown {
logrus.Debugf("Read %v of %v bytes from %v (%2.2f%%)", r.bytes, r.total, r.rawURL, percent)
r.lastShown = next
}
}
return n, err
}
func getTapIf(c *execdriver.Command) string {
return fmt.Sprintf("tb-%s", c.ID[:12])
}
// getClrVersion reads the latest image version from the
// locally-downloaded "latest" file.
func getClrVersion(libPath string) string {
txt, err := ioutil.ReadFile(path.Join(libPath, clrFile))
if err != nil {
return ""
}
return strings.Split(string(txt), "\n")[0]
}
func getURL(rawURL, outfile string) error {
_url, err := url.Parse(rawURL)
if err != nil {
return err
}
out, err := os.Create(outfile)
if err != nil {
return err
}
defer out.Close()
transport := &http.Transport{Proxy: http.ProxyFromEnvironment}
client := &http.Client{Transport: transport}
// Determine size of download by consulting the headers
response, err := client.Head(rawURL)
if err != nil {
return err
}
lenStr := response.Header.Get("Content-Length")
dataLen, _ := strconv.Atoi(lenStr)
request, err := http.NewRequest("GET", _url.String(), nil)
if err != nil {
return err
}
response, err = client.Do(request)
defer response.Body.Close()
reader := &ProgressReader{
Reader: response.Body,
total: uint64(dataLen),
lastShown: -1,
rawURL: rawURL,
}
_, err = io.Copy(out, reader)
return err
}
// fetchLatest downloads the "latest" file which contains the version
// number of the latest image.
func fetchLatest(libPath string) error {
file := path.Join(libPath, clrFile)
return getURL(clrURL+"/"+latestFile, file)
}
// NewDriver creates a new clear linux execution driver.
func NewDriver(root, libPath, initPath string, apparmor bool) (*driver, error) {
if err := os.MkdirAll(root, 0700); err != nil {
return nil, err
}
meminfo, err := sysinfo.ReadMemInfo()
if err != nil {
return nil, err
}
version, err := prepareClr(libPath)
if err != nil {
return nil, err
}
return &driver{
apparmor: apparmor,
root: root,
libPath: libPath,
initPath: initPath,
version: version,
sharedRoot: false,
activeContainers: make(map[string]*activeContainer),
// FIXME:
machineMemory: meminfo.MemTotal,
}, nil
}
// fetchImage downloads the latest image and verifies its checksum.
func fetchImage(version, outfile, outpath string) error {
url := fmt.Sprintf("%s/releases/%s/clear/%s", clrURL, version, outfile)
logrus.Debugf("Fetching clr version: %s, %s", version, outpath)
return getURL(url, outpath)
}
// uncompressImage handles decompressing the image specified by path.
func uncompressImage(path string) error {
// decompress the file
cmd := exec.Command("unxz", path)
cmd.Dir = filepath.Dir(path)
if output, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("Unable to extract image %s: %s", path, output)
}
return nil
}
// getChecksumLine reads the file specified and returns the checksum for
// the filename specified.
func getChecksumLine(file string, filename string) string {
data, err := ioutil.ReadFile(file)
if err != nil {
return ""
}
lines := strings.Split(string(data), "\n")
for _, line := range lines {
if strings.HasSuffix(line, filename) {
fields := strings.Fields(line)
if len(fields) == 2 {
return fields[0]
}
}
}
return ""
}
// getChecksum downloads the checksum file for the image version specified,
// storing it under libPath, then extracts the checksum corresponding to
// imageFile and returns it.
func getChecksum(version string, libPath string, imageFile string) (string, error) {
outfile := path.Join(libPath, clrChecksumFile)
checkurl := fmt.Sprintf("%s/releases/%s/clear/%s", clrURL, version, clrChecksumFile)
err := getURL(checkurl, outfile)
if err != nil {
return "", err
}
// Now, extract the checksum from the downloaded file.
return getChecksumLine(outfile, imageFile), nil
}
func verifyChecksum(fullPath, expectedChecksum string) error {
if expectedChecksum == "" {
return errors.New("blank expectedChecksum")
}
if fullPath == "" {
return errors.New("blank path")
}
data, err := ioutil.ReadFile(fullPath)
if err != nil {
return err
}
calculatedChecksum := fmt.Sprintf("%x", sha512.Sum512(data))
if calculatedChecksum != expectedChecksum {
return fmt.Errorf("Checksum mismatch: %v %v", calculatedChecksum, expectedChecksum)
}
logrus.Debugf("Checksum for %v correct: %v", fullPath, expectedChecksum)
return nil
}
// alreadyDownloaded determines if the uncompressed version of the file
// specified by outpath already exists and seems sane.
func alreadyDownloaded(outpath string) bool {
// strip off the (first) extension
base := path.Base(outpath)
extension := filepath.Ext(base)
uncompressed := strings.TrimSuffix(outpath, extension)
st, err := os.Stat(uncompressed)
if err != nil {
return false
}
if st.IsDir() {
return false
}
if st.Size() == 0 {
return false
}
return true
}
// prepareClr handles downloading and checking clr images, returning the
// version of clr that will be used.
func prepareClr(libPath string) (string, error) {
logrus.Debugf("%s preparing environment", driverName)
tmp := os.Getenv(clrEnvURL)
if tmp != "" {
clrURL = tmp
logrus.Debugf("%s using alternate download URL: %s", driverName, clrURL)
}
var version = getClrVersion(libPath)
err := fetchLatest(libPath)
if err != nil {
return "", err
}
nversion := getClrVersion(libPath)
if nversion == "" {
return "", errors.New("unable to determine latest clr version")
}
outfile := fmt.Sprintf("clear-%s-containers.img.xz", nversion)
outpath := path.Join(libPath, outfile)
// If the download originally failed, there may be a partial .xz
// file. However, this will be ignored and a new download triggered
// since we only only check for the uncompressed file (which would
// only exist if the download was successful).
if alreadyDownloaded(outpath) && nversion == version {
logrus.Debugf("Using clr version: %s", nversion)
return nversion, nil
}
// Determine the expected checksum for the file about to be
// downloaded.
checksum, err := getChecksum(nversion, libPath, outfile)
if err != nil {
return "", err
}
if nversion != version && version != "" {
logrus.Debugf("Updating to clr version: %s", nversion)
} else if version == "" {
logrus.Debugf("Installing clr version: %s", nversion)
}
err = fetchImage(nversion, outfile, outpath)
if err != nil {
return "", err
}
if err = verifyChecksum(outpath, checksum); err != nil {
return "", err
}
err = uncompressImage(outpath)
if err != nil {
return "", err
}
return nversion, nil
}
func (d *driver) Name() string {
return fmt.Sprintf("%s-%s", driverName, d.version)
}
func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execdriver.Hooks) (execdriver.ExitStatus, error) {
var (
term execdriver.Terminal
err error
)
container, err := d.createContainer(c)
if err != nil {
return execdriver.ExitStatus{ExitCode: -1}, err
}
memoryMiB := c.HostConfig.Memory
if memoryMiB == 0 {
memoryMiB = 1024
} else {
// docker passes the value as bytes
memoryMiB = memoryMiB / int64(math.Pow(2, 20))
}
workingDirVar := fmt.Sprintf("%s%s=%q", envVarPrefix, "WORKINGDIR", c.WorkingDir)
c.ProcessConfig.Cmd.Env = append(c.ProcessConfig.Cmd.Env, workingDirVar)
userVar := fmt.Sprintf("%s%s=%q", envVarPrefix, "USER", c.ProcessConfig.User)
c.ProcessConfig.Cmd.Env = append(c.ProcessConfig.Cmd.Env, userVar)
if err := d.setupNetwork(c); err != nil {
return execdriver.ExitStatus{ExitCode: -1}, err
}
if c.ProcessConfig.Tty {
term, err = NewTtyConsole(&c.ProcessConfig, pipes)
} else {
term, err = execdriver.NewStdConsole(&c.ProcessConfig, pipes)
}
if err != nil {
return execdriver.ExitStatus{ExitCode: -1}, err
}
c.ProcessConfig.Terminal = term
d.Lock()
d.activeContainers[c.ID] = &activeContainer{
container: container,
cmd: &c.ProcessConfig.Cmd,
}
d.Unlock()
if err := d.generateEnvConfig(c); err != nil {
return execdriver.ExitStatus{ExitCode: -1}, err
}
if err := d.generateDockerInit(c); err != nil {
return execdriver.ExitStatus{ExitCode: -1}, err
}
for _, m := range c.Mounts {
dest := path.Join(c.Rootfs, m.Destination)
if m.Destination == "/etc/hostname" {
continue
}
if !pathExists(m.Source) {
continue
}
opts := "bind"
if m.Private {
opts = opts + ",rprivate"
}
if m.Slave {
opts = opts + ",rslave"
}
// This may look racy, but it isn't since the VM isn't
// running yet.
//
// The check is necessary to handle bind mounting of
// regular files correctly since without it we may be
// attempting to create a directory where there already
// exists a normal file.
if !pathExists(dest) {
if err := os.MkdirAll(dest, 0750); err != nil {
return execdriver.ExitStatus{ExitCode: -1}, err
}
}
if err := mount.Mount(m.Source, dest, "", opts); err != nil {
return execdriver.ExitStatus{ExitCode: -1}, err
}
if !m.Writable {
if err := mount.Mount("", dest, "", "bind,remount,ro"); err != nil {
return execdriver.ExitStatus{ExitCode: -1}, err
}
}
defer mount.Unmount(dest)
}
var args []string
// various things for lkvm
ifname := getTapIf(c)
// FIXME: Should be real hostname from like process/container struct
hostname := c.ID[0:12]
img := fmt.Sprintf("%s/clear-%s-containers.img", d.libPath, d.version)
memory := fmt.Sprintf("%d", memoryMiB)
// FIXME: Locked cores to 6 ?
cores := fmt.Sprintf("%d", 6)
args = append(args, c.ProcessConfig.Entrypoint)
args = append(args, c.ProcessConfig.Arguments...)
rootParams := fmt.Sprintf("root=/dev/plkvm0p1 rootfstype=ext4 rootflags=dax,data=ordered "+
"init=/usr/lib/systemd/systemd systemd.unit=container.target rw tsc=reliable "+
"systemd.show_status=false "+
"no_timer_check rcupdate.rcu_expedited=1 console=hvc0 quiet ip=%s::%s::%s::off",
d.ipaddr, d.gateway, hostname)
params := []string{
lkvmName, "run", "-c", cores, "-m", memory,
"--name", c.ID, "--console", "virtio",
"--kernel", clrKernel,
"--params", rootParams,
"--shmem", fmt.Sprintf("0x200000000:0:file=%s:private", img),
"--network", fmt.Sprintf("mode=tap,script=none,tapif=%s,guest_mac=%s", ifname, d.macaddr),
"--9p", fmt.Sprintf("%s,rootfs", c.Rootfs),
}
logrus.Debugf("%s params %s", driverName, params)
var (
name = params[0]
arg = params[1:]
)
aname, err := exec.LookPath(name)
if err != nil {
aname = name
}
c.ProcessConfig.Path = aname
c.ProcessConfig.Args = append([]string{name}, arg...)
c.ProcessConfig.Env = []string{fmt.Sprintf("HOME=%s", d.root)}
// Start the container. Since it runs synchronously, we don't Wait()
// for it since we need to check the status to determine if it did
// actually start successfully.
if err := c.ProcessConfig.Start(); err != nil {
return execdriver.ExitStatus{ExitCode: -1}, err
}
var (
waitErr error
waitLock = make(chan struct{})
)
go func() {
if err := c.ProcessConfig.Wait(); err != nil {
if _, ok := err.(*exec.ExitError); !ok { // Do not propagate the error if it's simply a status code != 0
waitErr = err
}
}
close(waitLock)
}()
// FIXME: need to create state.json for Stats() to work.
pid := c.ProcessConfig.Process.Pid
c.ContainerPid = pid
d.containerPid = pid
if hooks.Start != nil {
logrus.Debugf("Invoking startCallback")
chOOM := make(chan struct{})
close(chOOM)
hooks.Start(&c.ProcessConfig, pid, chOOM)
}
// FIXME:
oomKill := false
// Wait for the VM to shutdown
<-waitLock
exitCode := getExitCode(c)
cExitStatus, cerr := d.cleanupVM(c)
if cerr != nil {
waitErr = cerr
exitCode = cExitStatus
}
// check oom error
if oomKill {
exitCode = 137
}
return execdriver.ExitStatus{ExitCode: exitCode, OOMKilled: false}, waitErr
}
func pathExists(path string) bool {
if _, err := os.Stat(path); err == nil {
return true
}
return false
}
func pathExecutable(path string) bool {
s, err := os.Stat(path)
if err != nil {
return false
}
mode := s.Mode()
if mode&0111 != 0 {
return true
}
return false
}
func (d *driver) cleanupVM(c *execdriver.Command) (exitStatus int, err error) {
cmd := exec.Command("ip", "tuntap", "del", "dev", getTapIf(c), "mode", "tap")
var output []byte
if output, err = cmd.CombinedOutput(); err != nil {
if exitError, ok := err.(*exec.ExitError); ok {
waitStatus := exitError.Sys().(syscall.WaitStatus)
exitStatus = waitStatus.ExitStatus()
}
logrus.Debugf("teardown failed for vm %s: %s (%s)", c.ID, string(output), err.Error())
}
// doesn't matter if this fails
// lkvm could have removed it, and stale sockets are not fatal
_ = os.Remove(fmt.Sprintf("%s/.lkvm/%s.sock", d.root, c.ID))
return exitStatus, err
}
// createContainer populates and configures the container type with the
// data provided by the execdriver.Command
func (d *driver) createContainer(c *execdriver.Command) (*configs.Config, error) {
return execdriver.InitContainer(c), nil
}
/// Return the exit code of the process
// if the process has not exited -1 will be returned
func getExitCode(c *execdriver.Command) int {
if c.ProcessConfig.ProcessState == nil {
return -1
}
return c.ProcessConfig.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
}
func (d *driver) lkvmCommand(c *execdriver.Command, arg string) ([]byte, error) {
args := append([]string{lkvmName}, arg)
if c != nil {
args = append(args, "--name", c.ID)
}
cmd := exec.Command(lkvmName, args...)
cmd.Env = []string{fmt.Sprintf("HOME=%s", d.root)}
return cmd.Output()
}
// Kill sends a signal to workload
func (d *driver) Kill(c *execdriver.Command, sig int) error {
// Not supported
return nil
}
func (d *driver) Pause(c *execdriver.Command) error {
_, err := d.lkvmCommand(c, "pause")
return err
}
func (d *driver) Unpause(c *execdriver.Command) error {
_, err := d.lkvmCommand(c, "resume")
return err
}
// Terminate forcibly stops a container
func (d *driver) Terminate(c *execdriver.Command) error {
_, err := d.lkvmCommand(c, "stop")
return err
}
func (d *driver) containerDir(containerID string) string {
return path.Join(d.libPath, "containers", containerID)
}
// isDigit returns true if s can be represented as an integer
func isDigit(s string) bool {
if _, err := strconv.Atoi(s); err == nil {
return true
}
return false
}
func (d *driver) getInfo(id string) ([]byte, error) {
output, err := d.lkvmCommand(nil, "list")
if err != nil {
return nil, err
}
for i, line := range strings.Split(string(output), "\n") {
if i < 2 {
continue
}
fields := strings.Fields(strings.TrimSpace(line))
if len(fields) != 3 {
continue
}
if !isDigit(fields[0]) {
continue
}
if fields[1] != id {
continue
}
return []byte(line), nil
}
return []byte(fmt.Sprintf("-1 %s stopped", id)), nil
}
type info struct {
ID string
driver *driver
}
func (i *info) IsRunning() bool {
output, err := i.driver.getInfo(i.ID)
if err != nil {
logrus.Errorf("Error getting info for %s container %s: %s (%s)",
driverName, i.ID, err, output)
return false
}
clrInfo, err := parseClrInfo(i.ID, string(output))
if err != nil {
return false
}
return clrInfo.Running
}
func (d *driver) Info(id string) execdriver.Info {
return &info{
ID: id,
driver: d,
}
}
func (d *driver) GetPidsForContainer(id string) ([]int, error) {
// The VM doesn't expose the worload pid(s), so the only meaningful
// pid is that of the VM
return []int{d.containerPid}, nil
}
// TtyConsole is a type to represent a pseud-oterminal (see pty(7))
type TtyConsole struct {
MasterPty *os.File
SlavePty *os.File
}
// NewTtyConsole returns a new TtyConsole object.
func NewTtyConsole(processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes) (*TtyConsole, error) {
// lxc is special in that we cannot create the master outside of the container without
// opening the slave because we have nothing to provide to the cmd. We have to open both then do
// the crazy setup on command right now instead of passing the console path to lxc and telling it
// to open up that console. we save a couple of openfiles in the native driver because we can do
// this.
ptyMaster, ptySlave, err := pty.Open()
if err != nil {
return nil, err
}
tty := &TtyConsole{
MasterPty: ptyMaster,
SlavePty: ptySlave,
}
if err := tty.AttachPipes(&processConfig.Cmd, pipes); err != nil {
tty.Close()
return nil, err
}
processConfig.Console = tty.SlavePty.Name()
return tty, nil
}
// Master returns the master end of the pty
func (t *TtyConsole) Master() *os.File {
return t.MasterPty
}
// Resize modifies the size of the pty terminal being used.
func (t *TtyConsole) Resize(h, w int) error {
return term.SetWinsize(t.MasterPty.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
}
// AttachPipes associates the specified pipes with the pty master.
func (t *TtyConsole) AttachPipes(command *exec.Cmd, pipes *execdriver.Pipes) error {
command.Stdout = t.SlavePty
command.Stderr = t.SlavePty
go func() {
if wb, ok := pipes.Stdout.(interface {
CloseWriters() error
}); ok {
defer wb.CloseWriters()
}
io.Copy(pipes.Stdout, t.MasterPty)
}()
if pipes.Stdin != nil {
command.Stdin = t.SlavePty
command.SysProcAttr.Setctty = true
go func() {
io.Copy(t.MasterPty, pipes.Stdin)
pipes.Stdin.Close()
}()
}
return nil
}
// Close closes both ends of the pty.
func (t *TtyConsole) Close() error {
t.SlavePty.Close()
return t.MasterPty.Close()
}
func (d *driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, hooks execdriver.Hooks) (int, error) {
return -1, fmt.Errorf("Unsupported: Exec is not supported by the %q driver", driverName)
}
// Clean up after an Exec
func (d *driver) Clean(id string) error {
return nil
}
func (d *driver) generateEnvConfig(c *execdriver.Command) error {
data := []byte(strings.Join(c.ProcessConfig.Env, "\n"))
p := path.Join(d.libPath, "containers", c.ID, "config.env")
c.Mounts = append(c.Mounts, execdriver.Mount{
Source: p,
Destination: "/.dockerenv",
Writable: false,
Private: true,
})
return ioutil.WriteFile(p, data, 0600)
}
func (d *driver) generateDockerInit(c *execdriver.Command) error {
p := fmt.Sprintf("%s/.containerexec", c.Rootfs)
var args []string
if pathExecutable(p) {
return nil
}
args = append(args, c.ProcessConfig.Entrypoint)
args = append(args, c.ProcessConfig.Arguments...)
data := []byte(fmt.Sprintf("#!/bin/sh\n%s\n", strings.Join(args, " ")))
return ioutil.WriteFile(p, data, 0755)
}
func (d *driver) linkExists(name string) bool {
cmd := exec.Command("ip", "link", "show", name)
err := cmd.Run()
return err == nil
}
func (d *driver) setupNetwork(c *execdriver.Command) error {
ifname := getTapIf(c)
var bridgeName string
var bridgeLinkName string
var output []byte
var err error
var ok bool
bridge := c.NetworkSettings.Networks["bridge"]
if bridge == nil {
return fmt.Errorf("no bridge network available")
}
d.ipaddr = bridge.IPAddress
d.macaddr = bridge.MacAddress
d.gateway = bridge.Gateway
// Extract the bridge details from the relevant endpoint.
for _, info := range c.EndpointInfo {
if _, ok = info[netlabel.BridgeEID].(string); !ok {
continue
}
if bridgeName, ok = info[netlabel.BridgeName].(string); !ok {
return fmt.Errorf("unable to determine bridge name")
}
if bridgeLinkName, ok = info[netlabel.BridgeLinkName].(string); !ok {
return fmt.Errorf("unable to determine bridge link name")
}
}
// Strip existing veth if it exists
if bridgeLinkName != "" && d.linkExists(bridgeLinkName) {
cmd := exec.Command("ip", "link", "del", bridgeLinkName)
if output, err = cmd.CombinedOutput(); err != nil {
logrus.Debugf("%s setupNetwork error: %v, %s", driverName, cmd.Args, output)
return err
}
}
cmd := exec.Command("ip", "tuntap", "add", "dev", ifname, "mode", "tap", "vnet_hdr")
if output, err = cmd.CombinedOutput(); err != nil {
logrus.Debugf("%s setupNetwork error: %v, %s", driverName, cmd.Args, output)
return err
}
cmd = exec.Command("ip", "link", "set", "dev", ifname, "master", bridgeName)
if output, err = cmd.CombinedOutput(); err != nil {
logrus.Debugf("%s setupNetwork error: %v, %s", driverName, cmd.Args, output)
return err
}
cmd = exec.Command("ip", "link", "set", "dev", ifname, "up")
if output, err = cmd.CombinedOutput(); err != nil {
logrus.Debugf("%s setupNetwork error: %v, %s", driverName, cmd.Args, output)
return err
}
return err
}
func (d *driver) Stats(id string) (*execdriver.ResourceStats, error) {
if _, ok := d.activeContainers[id]; !ok {
return nil, fmt.Errorf("%s is not a key in active containers", id)
}
// FIXME:
return execdriver.Stats(d.containerDir(id), d.activeContainers[id].container.Cgroups.Memory, d.machineMemory)
}
func (d *driver) SupportsHooks() bool {
return false
}
-51
View File
@@ -1,51 +0,0 @@
// +build linux
package clr
import (
"errors"
"strconv"
"strings"
)
var (
ErrCannotParse = errors.New("cannot parse raw input")
)
type clrInfo struct {
Running bool
Pid int
}
func parseClrInfo(name, raw string) (*clrInfo, error) {
if raw == "" {
return nil, ErrCannotParse
}
var (
err error
info = &clrInfo{}
)
fields := strings.Fields(strings.TrimSpace(raw))
// The format is expected to be:
//
// <pid> <name> <state>
//
if len(fields) != 3 {
return nil, ErrCannotParse
}
info.Pid, err = strconv.Atoi(fields[0])
if err != nil {
return nil, ErrCannotParse
}
if fields[1] != name {
return nil, ErrCannotParse
}
info.Running = fields[2] == "running"
return info, nil
}
-97
View File
@@ -1,97 +0,0 @@
// +build linux
package clr
import (
"encoding/json"
"flag"
"fmt"
"os"
"strings"
"syscall"
)
// Args provided to the init function for a driver
type InitArgs struct {
User string
Gateway string
Ip string
WorkDir string
Privileged bool
Env []string
Args []string
Mtu int
Console string
Pipe int
Root string
CapAdd string
CapDrop string
}
func getArgs() *InitArgs {
var (
// Get cmdline arguments
user = flag.String("u", "", "username or uid")
gateway = flag.String("g", "", "gateway address")
ip = flag.String("i", "", "ip address")
workDir = flag.String("w", "", "workdir")
privileged = flag.Bool("privileged", false, "privileged mode")
mtu = flag.Int("mtu", 1500, "interface mtu")
capAdd = flag.String("cap-add", "", "capabilities to add")
capDrop = flag.String("cap-drop", "", "capabilities to drop")
)
flag.Parse()
return &InitArgs{
User: *user,
Gateway: *gateway,
Ip: *ip,
WorkDir: *workDir,
Privileged: *privileged,
Args: flag.Args(),
Mtu: *mtu,
CapAdd: *capAdd,
CapDrop: *capDrop,
}
}
// Clear environment pollution introduced by lxc-start
func setupEnv(args *InitArgs) error {
// Get env
var env []string
dockerenv, err := os.Open(".dockerenv")
if err != nil {
return fmt.Errorf("Unable to load environment variables: %v", err)
}
defer dockerenv.Close()
if err := json.NewDecoder(dockerenv).Decode(&env); err != nil {
return fmt.Errorf("Unable to decode environment variables: %v", err)
}
// Propagate the plugin-specific container env variable
env = append(env, "container="+os.Getenv("container"))
args.Env = env
os.Clearenv()
for _, kv := range args.Env {
parts := strings.SplitN(kv, "=", 2)
if len(parts) == 1 {
parts = append(parts, "")
}
os.Setenv(parts[0], parts[1])
}
return nil
}
// Setup working directory
func setupWorkingDirectory(args *InitArgs) error {
if args.WorkDir == "" {
return nil
}
if err := syscall.Chdir(args.WorkDir); err != nil {
return fmt.Errorf("Unable to change dir to %v: %v", args.WorkDir, err)
}
return nil
}
-6
View File
@@ -8,9 +8,7 @@ import (
"github.com/docker/docker/pkg/idtools"
// TODO Windows: Factor out ulimit
"github.com/docker/docker/daemon/network"
"github.com/docker/docker/pkg/ulimit"
"github.com/docker/docker/runconfig"
"github.com/opencontainers/runc/libcontainer"
"github.com/opencontainers/runc/libcontainer/configs"
)
@@ -232,8 +230,4 @@ type Command struct {
LayerPaths []string `json:"layer_paths"` // Windows needs to know the layer paths and folder for a command
LayerFolder string `json:"layer_folder"`
Hostname string `json:"hostname"` // Windows sets the hostname in the execdriver
NetworkSettings *network.Settings `json:"network_settings"`
EndpointInfo []map[string]interface{} `json:"endpoint_info"`
HostConfig *runconfig.HostConfig `json:"hostconfig"`
}
@@ -8,7 +8,6 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/docker/daemon/execdriver"
"github.com/docker/docker/daemon/execdriver/clr"
"github.com/docker/docker/daemon/execdriver/lxc"
"github.com/docker/docker/daemon/execdriver/native"
"github.com/docker/docker/pkg/sysinfo"
@@ -16,10 +15,7 @@ import (
// NewDriver returns a new execdriver.Driver from the given name configured with the provided options.
func NewDriver(name string, options []string, root, libPath, initPath string, sysInfo *sysinfo.SysInfo) (execdriver.Driver, error) {
rootPath := path.Join(root, "execdriver", name)
switch name {
case "clr":
return clr.NewDriver(rootPath, libPath, initPath, sysInfo.AppArmor)
case "lxc":
// we want to give the lxc driver the full docker root because it needs
// to access and write config and template files in /var/lib/docker/containers/*
@@ -27,7 +23,7 @@ func NewDriver(name string, options []string, root, libPath, initPath string, sy
logrus.Warn("LXC built-in support is deprecated.")
return lxc.NewDriver(root, libPath, initPath, sysInfo.AppArmor)
case "native":
return native.NewDriver(rootPath, initPath, options)
return native.NewDriver(path.Join(root, "execdriver", "native"), initPath, options)
}
return nil, fmt.Errorf("unknown exec driver %s", name)
}
+8 -4
View File
@@ -18,6 +18,7 @@ func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessCo
term execdriver.Terminal
err error
exitCode int32
errno uint32
)
active := d.activeContainers[c.ID]
@@ -77,12 +78,15 @@ func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessCo
hooks.Start(&c.ProcessConfig, int(pid), chOOM)
}
if exitCode, err = hcsshim.WaitForProcessInComputeSystem(c.ID, pid); err != nil {
logrus.Errorf("Failed to WaitForProcessInComputeSystem %s", err)
if exitCode, errno, err = hcsshim.WaitForProcessInComputeSystem(c.ID, pid, hcsshim.TimeoutInfinite); err != nil {
if errno == hcsshim.Win32PipeHasBeenEnded {
logrus.Debugf("Exiting Run() after WaitForProcessInComputeSystem failed with recognised error 0x%X", errno)
return hcsshim.WaitErrExecFailed, nil
}
logrus.Warnf("WaitForProcessInComputeSystem failed (container may have been killed): 0x%X %s", errno, err)
return -1, err
}
// TODO Windows - Do something with this exit code
logrus.Debugln("Exiting Run() with ExitCode 0", c.ID)
logrus.Debugln("Exiting Run()", c.ID)
return int(exitCode), nil
}
+11 -2
View File
@@ -3,6 +3,7 @@
package windows
import (
"fmt"
"io"
"github.com/Sirupsen/logrus"
@@ -22,7 +23,11 @@ func startStdinCopy(dst io.WriteCloser, src io.Reader) {
go func() {
defer dst.Close()
bytes, err := io.Copy(dst, src)
logrus.Debugf("Copied %d bytes from stdin err=%s", bytes, err)
log := fmt.Sprintf("Copied %d bytes from stdin.", bytes)
if err != nil {
log = log + " err=" + err.Error()
}
logrus.Debugf(log)
}()
}
@@ -35,7 +40,11 @@ func startStdouterrCopy(dst io.Writer, src io.ReadCloser, name string) {
go func() {
defer src.Close()
bytes, err := io.Copy(dst, src)
logrus.Debugf("Copied %d bytes from %s err=%s", bytes, name, err)
log := fmt.Sprintf("Copied %d bytes from %s.", bytes, name)
if err != nil {
log = log + " err=" + err.Error()
}
logrus.Debugf(log)
}()
}
+23 -17
View File
@@ -220,22 +220,19 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execd
}
defer func() {
// Stop the container
if terminateMode {
logrus.Debugf("Terminating container %s", c.ID)
if err := hcsshim.TerminateComputeSystem(c.ID); err != nil {
// IMPORTANT: Don't fail if fails to change state. It could already
// have been stopped through kill().
// Otherwise, the docker daemon will hang in job wait()
logrus.Warnf("Ignoring error from TerminateComputeSystem %s", err)
if forceKill {
logrus.Debugf("Forcibly terminating container %s", c.ID)
if errno, err := hcsshim.TerminateComputeSystem(c.ID, hcsshim.TimeoutInfinite, "exec-run-defer"); err != nil {
logrus.Warnf("Ignoring error from TerminateComputeSystem 0x%X %s", errno, err)
}
} else {
logrus.Debugf("Shutting down container %s", c.ID)
if err := hcsshim.ShutdownComputeSystem(c.ID); err != nil {
// IMPORTANT: Don't fail if fails to change state. It could already
// have been stopped through kill().
// Otherwise, the docker daemon will hang in job wait()
logrus.Warnf("Ignoring error from ShutdownComputeSystem %s", err)
if errno, err := hcsshim.ShutdownComputeSystem(c.ID, hcsshim.TimeoutInfinite, "exec-run-defer"); err != nil {
if errno != hcsshim.Win32SystemShutdownIsInProgress &&
errno != hcsshim.Win32SpecifiedPathInvalid &&
errno != hcsshim.Win32SystemCannotFindThePathSpecified {
logrus.Warnf("Ignoring error from ShutdownComputeSystem 0x%X %s", errno, err)
}
}
}
}()
@@ -303,11 +300,20 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execd
hooks.Start(&c.ProcessConfig, int(pid), chOOM)
}
var exitCode int32
exitCode, err = hcsshim.WaitForProcessInComputeSystem(c.ID, pid)
var (
exitCode int32
errno uint32
)
exitCode, errno, err = hcsshim.WaitForProcessInComputeSystem(c.ID, pid, hcsshim.TimeoutInfinite)
if err != nil {
logrus.Errorf("Failed to WaitForProcessInComputeSystem %s", err)
return execdriver.ExitStatus{ExitCode: -1}, err
if errno != hcsshim.Win32PipeHasBeenEnded {
logrus.Warnf("WaitForProcessInComputeSystem failed (container may have been killed): %s", err)
}
// Do NOT return err here as the container would have
// started, otherwise docker will deadlock. It's perfectly legitimate
// for WaitForProcessInComputeSystem to fail in situations such
// as the container being killed on another thread.
return execdriver.ExitStatus{ExitCode: hcsshim.WaitErrExecFailed}, nil
}
logrus.Debugf("Exiting Run() exitCode %d id=%s", exitCode, c.ID)
+20 -18
View File
@@ -3,6 +3,9 @@
package windows
import (
"fmt"
"syscall"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/daemon/execdriver"
"github.com/microsoft/hcsshim"
@@ -10,37 +13,36 @@ import (
// Terminate implements the exec driver Driver interface.
func (d *Driver) Terminate(p *execdriver.Command) error {
logrus.Debugf("WindowsExec: Terminate() id=%s", p.ID)
return kill(p.ID, p.ContainerPid)
return kill(p.ID, p.ContainerPid, syscall.SIGTERM)
}
// Kill implements the exec driver Driver interface.
func (d *Driver) Kill(p *execdriver.Command, sig int) error {
logrus.Debugf("WindowsExec: Kill() id=%s sig=%d", p.ID, sig)
return kill(p.ID, p.ContainerPid)
return kill(p.ID, p.ContainerPid, syscall.Signal(sig))
}
func kill(id string, pid int) error {
logrus.Debugln("kill() ", id, pid)
func kill(id string, pid int, sig syscall.Signal) error {
logrus.Debugf("WindowsExec: kill() id=%s pid=%d sig=%d", id, pid, sig)
var err error
context := fmt.Sprintf("kill: sig=%d pid=%d", sig, pid)
// Terminate Process
if err = hcsshim.TerminateProcessInComputeSystem(id, uint32(pid)); err != nil {
logrus.Warnf("Failed to terminate pid %d in %s: %q", pid, id, err)
// Ignore errors
err = nil
}
if terminateMode {
if sig == syscall.SIGKILL || forceKill {
// Terminate the compute system
if err = hcsshim.TerminateComputeSystem(id); err != nil {
logrus.Errorf("Failed to terminate %s - %q", id, err)
if errno, err := hcsshim.TerminateComputeSystem(id, hcsshim.TimeoutInfinite, context); err != nil {
logrus.Errorf("Failed to terminate %s - 0x%X %q", id, errno, err)
}
} else {
// Terminate Process
if err = hcsshim.TerminateProcessInComputeSystem(id, uint32(pid)); err != nil {
logrus.Warnf("Failed to terminate pid %d in %s: %q", pid, id, err)
// Ignore errors
err = nil
}
// Shutdown the compute system
if err = hcsshim.ShutdownComputeSystem(id); err != nil {
logrus.Errorf("Failed to shutdown %s - %q", id, err)
if errno, err := hcsshim.ShutdownComputeSystem(id, hcsshim.TimeoutInfinite, context); err != nil {
logrus.Errorf("Failed to shutdown %s - 0x%X %q", id, errno, err)
}
}
return err
+5 -4
View File
@@ -18,7 +18,8 @@ import (
var dummyMode bool
// This allows the daemon to terminate containers rather than shutdown
var terminateMode bool
// This allows the daemon to force kill (HCS terminate) rather than shutdown
var forceKill bool
// Define name and version for windows
var (
@@ -62,11 +63,11 @@ func NewDriver(root, initPath string, options []string) (*Driver, error) {
logrus.Warn("Using dummy mode in Windows exec driver. This is for development use only!")
}
case "terminate":
case "forcekill":
switch val {
case "1":
terminateMode = true
logrus.Warn("Using terminate mode in Windows exec driver. This is for testing purposes only.")
forceKill = true
logrus.Warn("Using force kill mode in Windows exec driver. This is for testing purposes only.")
}
default:
+7 -73
View File
@@ -3,7 +3,6 @@
package devmapper
import (
"bufio"
"encoding/json"
"errors"
"fmt"
@@ -149,8 +148,6 @@ type Status struct {
Metadata DiskUsage
// BaseDeviceSize is base size of container and image
BaseDeviceSize uint64
// BaseDeviceFS is backing filesystem.
BaseDeviceFS string
// SectorSize size of the vector.
SectorSize uint64
// UdevSyncSupported is true if sync is supported.
@@ -535,45 +532,6 @@ func (devices *DeviceSet) activateDeviceIfNeeded(info *devInfo, ignoreDeleted bo
return devicemapper.ActivateDevice(devices.getPoolDevName(), info.Name(), info.DeviceID, info.Size)
}
// Return true only if kernel supports xfs and mkfs.xfs is available
func xfsSupported() bool {
// Make sure mkfs.xfs is available
if _, err := exec.LookPath("mkfs.xfs"); err != nil {
return false
}
// Check if kernel supports xfs filesystem or not.
exec.Command("modprobe", "xfs").Run()
f, err := os.Open("/proc/filesystems")
if err != nil {
logrus.Warnf("Could not check if xfs is supported: %v", err)
return false
}
defer f.Close()
s := bufio.NewScanner(f)
for s.Scan() {
if strings.HasSuffix(s.Text(), "\txfs") {
return true
}
}
if err := s.Err(); err != nil {
logrus.Warnf("Could not check if xfs is supported: %v", err)
}
return false
}
func determineDefaultFS() string {
if xfsSupported() {
return "xfs"
}
logrus.Warn("XFS is not supported in your system. Either the kernel doesnt support it or mkfs.xfs is not in your PATH. Defaulting to ext4 filesystem")
return "ext4"
}
func (devices *DeviceSet) createFilesystem(info *devInfo) error {
devname := info.DevName()
@@ -585,11 +543,6 @@ func (devices *DeviceSet) createFilesystem(info *devInfo) error {
args = append(args, devname)
var err error
if devices.filesystem == "" {
devices.filesystem = determineDefaultFS()
}
switch devices.filesystem {
case "xfs":
err = exec.Command("mkfs.xfs", args...).Run()
@@ -646,7 +599,6 @@ func (devices *DeviceSet) cleanupDeletedDevices() error {
// If there are no deleted devices, there is nothing to do.
if devices.nrDeletedDevices == 0 {
devices.Unlock()
return nil
}
@@ -891,11 +843,7 @@ func (devices *DeviceSet) getBaseDeviceSize() uint64 {
return info.Size
}
func (devices *DeviceSet) getBaseDeviceFS() string {
return devices.filesystem
}
func (devices *DeviceSet) verifyBaseDeviceUUIDFS(baseInfo *devInfo) error {
func (devices *DeviceSet) verifyBaseDeviceUUID(baseInfo *devInfo) error {
devices.Lock()
defer devices.Unlock()
@@ -911,23 +859,9 @@ func (devices *DeviceSet) verifyBaseDeviceUUIDFS(baseInfo *devInfo) error {
}
if devices.BaseDeviceUUID != uuid {
return fmt.Errorf("Current Base Device UUID:%s does not match with stored UUID:%s. Possibly using a different thin pool than last invocation", uuid, devices.BaseDeviceUUID)
return fmt.Errorf("Current Base Device UUID:%s does not match with stored UUID:%s", uuid, devices.BaseDeviceUUID)
}
// If user specified a filesystem using dm.fs option and current
// file system of base image is not same, warn user that dm.fs
// will be ignored.
if devices.filesystem != "" {
fs, err := ProbeFsType(baseInfo.DevName())
if err != nil {
return err
}
if fs != devices.filesystem {
logrus.Warnf("Base device already exists and has filesystem %s on it. User specified filesystem %s will be ignored.", fs, devices.filesystem)
devices.filesystem = fs
}
}
return nil
}
@@ -1028,7 +962,7 @@ func (devices *DeviceSet) checkThinPool() error {
// Base image is initialized properly. Either save UUID for first time (for
// upgrade case or verify UUID.
func (devices *DeviceSet) setupVerifyBaseImageUUIDFS(baseInfo *devInfo) error {
func (devices *DeviceSet) setupVerifyBaseImageUUID(baseInfo *devInfo) error {
// If BaseDeviceUUID is nil (upgrade case), save it and return success.
if devices.BaseDeviceUUID == "" {
if err := devices.saveBaseDeviceUUID(baseInfo); err != nil {
@@ -1037,8 +971,8 @@ func (devices *DeviceSet) setupVerifyBaseImageUUIDFS(baseInfo *devInfo) error {
return nil
}
if err := devices.verifyBaseDeviceUUIDFS(baseInfo); err != nil {
return fmt.Errorf("Base Device UUID and Filesystem verification failed.%v", err)
if err := devices.verifyBaseDeviceUUID(baseInfo); err != nil {
return fmt.Errorf("Base Device UUID verification failed. Possibly using a different thin pool than last invocation:%v", err)
}
return nil
@@ -1053,7 +987,7 @@ func (devices *DeviceSet) setupBaseImage() error {
if oldInfo != nil {
if oldInfo.Initialized && !oldInfo.Deleted {
if err := devices.setupVerifyBaseImageUUIDFS(oldInfo); err != nil {
if err := devices.setupVerifyBaseImageUUID(oldInfo); err != nil {
return err
}
@@ -2275,7 +2209,6 @@ func (devices *DeviceSet) Status() *Status {
status.DeferredDeleteEnabled = devices.deferredDelete
status.DeferredDeletedDeviceCount = devices.nrDeletedDevices
status.BaseDeviceSize = devices.getBaseDeviceSize()
status.BaseDeviceFS = devices.getBaseDeviceFS()
totalSizeInSectors, _, dataUsed, dataTotal, metadataUsed, metadataTotal, err := devices.poolStatus()
if err == nil {
@@ -2336,6 +2269,7 @@ func NewDeviceSet(root string, doInit bool, options []string, uidMaps, gidMaps [
metaDataLoopbackSize: defaultMetaDataLoopbackSize,
baseFsSize: defaultBaseFsSize,
overrideUdevSyncCheck: defaultUdevSyncOverride,
filesystem: "ext4",
doBlkDiscard: true,
thinpBlockSize: defaultThinpBlockSize,
deviceIDMap: make([]byte, deviceIDMapSz),
@@ -5,7 +5,6 @@ package devmapper
import (
"fmt"
"testing"
"time"
"github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/daemon/graphdriver/graphtest"
@@ -80,31 +79,3 @@ func testChangeLoopBackSize(t *testing.T, delta, expectDataSize, expectMetaDataS
t.Fatal(err)
}
}
// Make sure devices.Lock() has been release upon return from cleanupDeletedDevices() function
func TestDevmapperLockReleasedDeviceDeletion(t *testing.T) {
driver := graphtest.GetDriver(t, "devicemapper").(*graphtest.Driver).Driver.(*graphdriver.NaiveDiffDriver).ProtoDriver.(*Driver)
defer graphtest.PutDriver(t)
// Call cleanupDeletedDevices() and after the call take and release
// DeviceSet Lock. If lock has not been released, this will hang.
driver.DeviceSet.cleanupDeletedDevices()
doneChan := make(chan bool)
go func() {
driver.DeviceSet.Lock()
defer driver.DeviceSet.Unlock()
doneChan <- true
}()
select {
case <-time.After(time.Second * 5):
// Timer expired. That means lock was not released upon
// function return and we are deadlocked. Release lock
// here so that cleanup could succeed and fail the test.
driver.DeviceSet.Unlock()
t.Fatalf("Could not acquire devices lock after call to cleanupDeletedDevices()")
case <-doneChan:
}
}
+1 -1
View File
@@ -80,7 +80,7 @@ func (d *Driver) Status() [][2]string {
{"Pool Name", s.PoolName},
{"Pool Blocksize", fmt.Sprintf("%s", units.HumanSize(float64(s.SectorSize)))},
{"Base Device Size", fmt.Sprintf("%s", units.HumanSize(float64(s.BaseDeviceSize)))},
{"Backing Filesystem", s.BaseDeviceFS},
{"Backing Filesystem", backingFs},
{"Data file", s.DataFile},
{"Metadata file", s.MetadataFile},
{"Data Space Used", fmt.Sprintf("%s", units.HumanSize(float64(s.Data.Used)))},
+2 -7
View File
@@ -84,11 +84,6 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
daemon.EventsService.Log("untag", img.ID, "")
records = append(records, untaggedRecord)
// If has remaining references then untag finishes the remove
if daemon.repositories.HasReferences(img) {
return records, nil
}
removedRepositoryRef = true
} else {
// If an ID reference was given AND there is exactly one
@@ -284,7 +279,7 @@ func (daemon *Daemon) checkImageDeleteHardConflict(img *image.Image) *imageDelet
}
// Check if the image has any descendent images.
if daemon.Graph().HasChildren(img.ID) {
if daemon.Graph().HasChildren(img) {
return &imageDeleteConflict{
hard: true,
imgID: img.ID,
@@ -342,5 +337,5 @@ func (daemon *Daemon) checkImageDeleteSoftConflict(img *image.Image) *imageDelet
// that there are no repository references to the given image and it has no
// child images.
func (daemon *Daemon) imageIsDangling(img *image.Image) bool {
return !(daemon.repositories.HasReferences(img) || daemon.Graph().HasChildren(img.ID))
return !(daemon.repositories.HasReferences(img) || daemon.Graph().HasChildren(img))
}
-1
View File
@@ -92,7 +92,6 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
ExperimentalBuild: utils.ExperimentalBuild(),
ServerVersion: dockerversion.VERSION,
ClusterStore: daemon.config().ClusterStore,
ClusterAdvertise: daemon.config().ClusterAdvertise,
}
// TODO Windows. Refactor this more once sysinfo is refactored into
+18 -74
View File
@@ -6,7 +6,6 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/versions/v1p20"
"github.com/docker/docker/daemon/network"
)
// ContainerInspect returns low-level information about a
@@ -27,23 +26,8 @@ func (daemon *Daemon) ContainerInspect(name string, size bool) (*types.Container
}
mountPoints := addMountPoints(container)
networkSettings := &types.NetworkSettings{
NetworkSettingsBase: types.NetworkSettingsBase{
Bridge: container.NetworkSettings.Bridge,
SandboxID: container.NetworkSettings.SandboxID,
HairpinMode: container.NetworkSettings.HairpinMode,
LinkLocalIPv6Address: container.NetworkSettings.LinkLocalIPv6Address,
LinkLocalIPv6PrefixLen: container.NetworkSettings.LinkLocalIPv6PrefixLen,
Ports: container.NetworkSettings.Ports,
SandboxKey: container.NetworkSettings.SandboxKey,
SecondaryIPAddresses: container.NetworkSettings.SecondaryIPAddresses,
SecondaryIPv6Addresses: container.NetworkSettings.SecondaryIPv6Addresses,
},
DefaultNetworkSettings: daemon.getDefaultNetworkSettings(container.NetworkSettings.Networks),
Networks: container.NetworkSettings.Networks,
}
return &types.ContainerJSON{base, mountPoints, container.Config, networkSettings}, nil
return &types.ContainerJSON{base, mountPoints, container.Config}, nil
}
// ContainerInspect120 serializes the master version of a container into a json type.
@@ -64,14 +48,10 @@ func (daemon *Daemon) ContainerInspect120(name string) (*v1p20.ContainerJSON, er
mountPoints := addMountPoints(container)
config := &v1p20.ContainerConfig{
container.Config,
container.Config.MacAddress,
container.Config.NetworkDisabled,
container.Config.ExposedPorts,
container.hostConfig.VolumeDriver,
}
networkSettings := daemon.getBackwardsCompatibleNetworkSettings(container.NetworkSettings)
return &v1p20.ContainerJSON{base, mountPoints, config, networkSettings}, nil
return &v1p20.ContainerJSON{base, mountPoints, config}, nil
}
func (daemon *Daemon) getInspectData(container *Container, size bool) (*types.ContainerJSONBase, error) {
@@ -108,21 +88,22 @@ func (daemon *Daemon) getInspectData(container *Container, size bool) (*types.Co
}
contJSONBase := &types.ContainerJSONBase{
ID: container.ID,
Created: container.Created.Format(time.RFC3339Nano),
Path: container.Path,
Args: container.Args,
State: containerState,
Image: container.ImageID,
LogPath: container.LogPath,
Name: container.Name,
RestartCount: container.RestartCount,
Driver: container.Driver,
ExecDriver: container.ExecDriver,
MountLabel: container.MountLabel,
ProcessLabel: container.ProcessLabel,
ExecIDs: container.getExecIDs(),
HostConfig: &hostConfig,
ID: container.ID,
Created: container.Created.Format(time.RFC3339Nano),
Path: container.Path,
Args: container.Args,
State: containerState,
Image: container.ImageID,
NetworkSettings: container.NetworkSettings,
LogPath: container.LogPath,
Name: container.Name,
RestartCount: container.RestartCount,
Driver: container.Driver,
ExecDriver: container.ExecDriver,
MountLabel: container.MountLabel,
ProcessLabel: container.ProcessLabel,
ExecIDs: container.getExecIDs(),
HostConfig: &hostConfig,
}
var (
@@ -167,40 +148,3 @@ func (daemon *Daemon) VolumeInspect(name string) (*types.Volume, error) {
}
return volumeToAPIType(v), nil
}
func (daemon *Daemon) getBackwardsCompatibleNetworkSettings(settings *network.Settings) *v1p20.NetworkSettings {
result := &v1p20.NetworkSettings{
NetworkSettingsBase: types.NetworkSettingsBase{
Bridge: settings.Bridge,
SandboxID: settings.SandboxID,
HairpinMode: settings.HairpinMode,
LinkLocalIPv6Address: settings.LinkLocalIPv6Address,
LinkLocalIPv6PrefixLen: settings.LinkLocalIPv6PrefixLen,
Ports: settings.Ports,
SandboxKey: settings.SandboxKey,
SecondaryIPAddresses: settings.SecondaryIPAddresses,
SecondaryIPv6Addresses: settings.SecondaryIPv6Addresses,
},
DefaultNetworkSettings: daemon.getDefaultNetworkSettings(settings.Networks),
}
return result
}
// getDefaultNetworkSettings creates the deprecated structure that holds the information
// about the bridge network for a container.
func (daemon *Daemon) getDefaultNetworkSettings(networks map[string]*network.EndpointSettings) types.DefaultNetworkSettings {
var settings types.DefaultNetworkSettings
if defaultNetwork, ok := networks["bridge"]; ok {
settings.EndpointID = defaultNetwork.EndpointID
settings.Gateway = defaultNetwork.Gateway
settings.GlobalIPv6Address = defaultNetwork.GlobalIPv6Address
settings.GlobalIPv6PrefixLen = defaultNetwork.GlobalIPv6PrefixLen
settings.IPAddress = defaultNetwork.IPAddress
settings.IPPrefixLen = defaultNetwork.IPPrefixLen
settings.IPv6Gateway = defaultNetwork.IPv6Gateway
settings.MacAddress = defaultNetwork.MacAddress
}
return settings
}
+1 -5
View File
@@ -41,18 +41,14 @@ func (daemon *Daemon) ContainerInspectPre120(name string) (*v1p19.ContainerJSON,
config := &v1p19.ContainerConfig{
container.Config,
container.Config.MacAddress,
container.Config.NetworkDisabled,
container.Config.ExposedPorts,
container.hostConfig.VolumeDriver,
container.hostConfig.Memory,
container.hostConfig.MemorySwap,
container.hostConfig.CPUShares,
container.hostConfig.CpusetCpus,
}
networkSettings := daemon.getBackwardsCompatibleNetworkSettings(container.NetworkSettings)
return &v1p19.ContainerJSON{base, volumes, volumesRW, config, networkSettings}, nil
return &v1p19.ContainerJSON{base, volumes, volumesRW, config}, nil
}
func addMountPoints(container *Container) []types.MountPoint {
+11 -1
View File
@@ -1,6 +1,12 @@
package daemon
import "syscall"
import (
"fmt"
"runtime"
"syscall"
"github.com/docker/docker/pkg/signal"
)
// ContainerKill send signal to the container
// If no signal is given (sig 0), then Kill with SIGKILL and wait
@@ -12,6 +18,10 @@ func (daemon *Daemon) ContainerKill(name string, sig uint64) error {
return err
}
if sig != 0 && !signal.ValidSignalForPlatform(syscall.Signal(sig)) {
return fmt.Errorf("The %s daemon does not support signal %d", runtime.GOOS, sig)
}
// If no signal is passed, or SIGKILL, perform regular Kill (SIGKILL + wait())
if sig == 0 || syscall.Signal(sig) == syscall.SIGKILL {
if err := container.Kill(); err != nil {
-26
View File
@@ -142,32 +142,6 @@ func (m *containerMonitor) Start() error {
m.lastStartTime = time.Now()
// Make the network settings available to the execution
// driver to allow for integration with libnetwork networking.
m.container.command.NetworkSettings = m.container.NetworkSettings
// Allow the execution driver to query memory limits
m.container.command.HostConfig = m.container.hostConfig
// Make the network endpoint details available to the execution
// driver, to allow it to determine the bridge name.
for name, _ := range m.container.NetworkSettings.Networks {
n, _err := m.container.daemon.netController.NetworkByName(name)
if _err == nil {
var eps []map[string]interface{}
for _, ep := range n.Endpoints() {
info, err := ep.DriverInfo()
if err != nil {
continue
}
eps = append(eps, info)
}
m.container.command.EndpointInfo = eps
}
}
if exitStatus, err = m.container.daemon.run(m.container, pipes, m.callback); err != nil {
// if we receive an internal error from the initial start of a container then lets
// return it instead of entering the restart loop
+24 -7
View File
@@ -17,12 +17,6 @@ const (
NetworkByName
)
// NetworkControllerEnabled checks if the networking stack is enabled.
// This feature depends on OS primitives and it's dissabled in systems like Windows.
func (daemon *Daemon) NetworkControllerEnabled() bool {
return daemon.netController != nil
}
// FindNetwork function finds a network for a given string that can represent network name or id
func (daemon *Daemon) FindNetwork(idName string) (libnetwork.Network, error) {
// Find by Name
@@ -99,7 +93,9 @@ func (daemon *Daemon) CreateNetwork(name, driver string, ipam network.IPAM, opti
return nil, err
}
nwOptions = append(nwOptions, libnetwork.NetworkOptionIpam(ipam.Driver, "", v4Conf, v6Conf))
if len(ipam.Config) > 0 {
nwOptions = append(nwOptions, libnetwork.NetworkOptionIpam(ipam.Driver, "", v4Conf, v6Conf))
}
nwOptions = append(nwOptions, libnetwork.NetworkOptionDriverOpts(options))
return c.NewNetwork(driver, name, nwOptions...)
}
@@ -125,3 +121,24 @@ func getIpamConfig(data []network.IPAMConfig) ([]*libnetwork.IpamConf, []*libnet
}
return ipamV4Cfg, ipamV6Cfg, nil
}
// ConnectContainerToNetwork connects the given container to the given
// network. If either cannot be found, an err is returned. If the
// network cannot be set up, an err is returned.
func (daemon *Daemon) ConnectContainerToNetwork(containerName, networkName string) error {
container, err := daemon.Get(containerName)
if err != nil {
return err
}
return container.ConnectToNetwork(networkName)
}
// DisconnectContainerFromNetwork disconnects the given container from
// the given network. If either cannot be found, an err is returned.
func (daemon *Daemon) DisconnectContainerFromNetwork(containerName string, network libnetwork.Network) error {
container, err := daemon.Get(containerName)
if err != nil {
return err
}
return container.DisconnectFromNetwork(network)
}
+15 -20
View File
@@ -10,42 +10,37 @@ type Address struct {
// IPAM represents IP Address Management
type IPAM struct {
Driver string
Config []IPAMConfig
Driver string `json:"driver"`
Config []IPAMConfig `json:"config"`
}
// IPAMConfig represents IPAM configurations
type IPAMConfig struct {
Subnet string `json:",omitempty"`
IPRange string `json:",omitempty"`
Gateway string `json:",omitempty"`
AuxAddress map[string]string `json:"AuxiliaryAddresses,omitempty"`
Subnet string `json:"subnet,omitempty"`
IPRange string `json:"ip_range,omitempty"`
Gateway string `json:"gateway,omitempty"`
AuxAddress map[string]string `json:"auxiliary_address,omitempty"`
}
// Settings stores configuration details about the daemon network config
// TODO Windows. Many of these fields can be factored out.,
type Settings struct {
Bridge string
EndpointID string
SandboxID string
Gateway string
GlobalIPv6Address string
GlobalIPv6PrefixLen int
HairpinMode bool
IPAddress string
IPPrefixLen int
IPv6Gateway string
LinkLocalIPv6Address string
LinkLocalIPv6PrefixLen int
Networks map[string]*EndpointSettings
MacAddress string
Networks []string
Ports nat.PortMap
SandboxKey string
SecondaryIPAddresses []Address
SecondaryIPv6Addresses []Address
IsAnonymousEndpoint bool
}
// EndpointSettings stores the network endpoint details
type EndpointSettings struct {
EndpointID string
Gateway string
IPAddress string
IPPrefixLen int
IPv6Gateway string
GlobalIPv6Address string
GlobalIPv6PrefixLen int
MacAddress string
}
+10 -45
View File
@@ -1,28 +1,18 @@
package daemon
import (
"github.com/Sirupsen/logrus"
derr "github.com/docker/docker/errors"
"github.com/docker/libnetwork"
"strings"
)
// ContainerRename changes the name of a container, using the oldName
// to find the container. An error is returned if newName is already
// reserved.
func (daemon *Daemon) ContainerRename(oldName, newName string) error {
var (
err error
sid string
sb libnetwork.Sandbox
container *Container
)
if oldName == "" || newName == "" {
return derr.ErrorCodeEmptyRename
}
container, err = daemon.Get(oldName)
container, err := daemon.Get(oldName)
if err != nil {
return err
}
@@ -37,44 +27,19 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) error {
container.Name = newName
defer func() {
if err != nil {
container.Name = oldName
daemon.reserveName(container.ID, oldName)
daemon.containerGraphDB.Delete(newName)
}
}()
undo := func() {
container.Name = oldName
daemon.reserveName(container.ID, oldName)
daemon.containerGraphDB.Delete(newName)
}
if err = daemon.containerGraphDB.Delete(oldName); err != nil {
if err := daemon.containerGraphDB.Delete(oldName); err != nil {
undo()
return derr.ErrorCodeRenameDelete.WithArgs(oldName, err)
}
if err = container.toDisk(); err != nil {
return err
}
if !container.Running {
container.logEvent("rename")
return nil
}
defer func() {
if err != nil {
container.Name = oldName
if e := container.toDisk(); e != nil {
logrus.Errorf("%s: Failed in writing to Disk on rename failure: %v", container.ID, e)
}
}
}()
sid = container.NetworkSettings.SandboxID
sb, err = daemon.netController.SandboxByID(sid)
if err != nil {
return err
}
err = sb.Rename(strings.TrimPrefix(container.Name, "/"))
if err != nil {
if err := container.toDisk(); err != nil {
undo()
return err
}
+58 -7
View File
@@ -8,6 +8,8 @@ import (
"github.com/docker/docker/api/types/versions/v1p20"
"github.com/docker/docker/daemon/execdriver"
"github.com/docker/docker/pkg/version"
lntypes "github.com/docker/libnetwork/types"
"github.com/opencontainers/runc/libcontainer"
)
// ContainerStatsConfig holds information for configuring the runtime
@@ -48,6 +50,10 @@ func (daemon *Daemon) ContainerStats(prefixOrName string, config *ContainerStats
var preCPUStats types.CPUStats
getStatJSON := func(v interface{}) *types.StatsJSON {
update := v.(*execdriver.ResourceStats)
// Retrieve the nw statistics from libnetwork and inject them in the Stats
if nwStats, err := daemon.getNetworkStats(container); err == nil {
update.Stats.Interfaces = nwStats
}
ss := convertStatsToAPITypes(update.Stats)
ss.PreCPUStats = preCPUStats
ss.MemoryStats.Limit = uint64(update.MemoryLimit)
@@ -69,8 +75,7 @@ func (daemon *Daemon) ContainerStats(prefixOrName string, config *ContainerStats
return nil
}
var statsJSON interface{}
statsJSONPost120 := getStatJSON(v)
statsJSON := getStatJSON(v)
if config.Version.LessThan("1.21") {
var (
rxBytes uint64
@@ -82,7 +87,7 @@ func (daemon *Daemon) ContainerStats(prefixOrName string, config *ContainerStats
txErrors uint64
txDropped uint64
)
for _, v := range statsJSONPost120.Networks {
for _, v := range statsJSON.Networks {
rxBytes += v.RxBytes
rxPackets += v.RxPackets
rxErrors += v.RxErrors
@@ -92,8 +97,8 @@ func (daemon *Daemon) ContainerStats(prefixOrName string, config *ContainerStats
txErrors += v.TxErrors
txDropped += v.TxDropped
}
statsJSON = &v1p20.StatsJSON{
Stats: statsJSONPost120.Stats,
statsJSONPre121 := &v1p20.StatsJSON{
Stats: statsJSON.Stats,
Network: types.NetworkStats{
RxBytes: rxBytes,
RxPackets: rxPackets,
@@ -105,8 +110,20 @@ func (daemon *Daemon) ContainerStats(prefixOrName string, config *ContainerStats
TxDropped: txDropped,
},
}
} else {
statsJSON = statsJSONPost120
if !config.Stream && noStreamFirstFrame {
// prime the cpu stats so they aren't 0 in the final output
noStreamFirstFrame = false
continue
}
if err := enc.Encode(statsJSONPre121); err != nil {
return err
}
if !config.Stream {
return nil
}
}
if !config.Stream && noStreamFirstFrame {
@@ -127,3 +144,37 @@ func (daemon *Daemon) ContainerStats(prefixOrName string, config *ContainerStats
}
}
}
func (daemon *Daemon) getNetworkStats(c *Container) ([]*libcontainer.NetworkInterface, error) {
var list []*libcontainer.NetworkInterface
sb, err := daemon.netController.SandboxByID(c.NetworkSettings.SandboxID)
if err != nil {
return list, err
}
stats, err := sb.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 *lntypes.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
}
-41
View File
@@ -14,8 +14,6 @@ import (
"github.com/docker/docker/daemon/execdriver"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/pkg/pubsub"
lntypes "github.com/docker/libnetwork/types"
"github.com/opencontainers/runc/libcontainer"
"github.com/opencontainers/runc/libcontainer/system"
)
@@ -120,11 +118,6 @@ func (s *statsCollector) run() {
continue
}
stats.SystemUsage = systemUsage
// Retrieve the nw statistics from libnetwork and inject them in the Stats
if nwStats, err := s.getNetworkStats(pair.container); err == nil {
stats.Interfaces = nwStats
}
pair.publisher.Publish(stats)
}
}
@@ -177,37 +170,3 @@ func (s *statsCollector) getSystemCPUUsage() (uint64, error) {
}
return 0, derr.ErrorCodeBadStatFormat
}
func (s *statsCollector) getNetworkStats(c *Container) ([]*libcontainer.NetworkInterface, error) {
var list []*libcontainer.NetworkInterface
sb, err := c.daemon.netController.SandboxByID(c.NetworkSettings.SandboxID)
if err != nil {
return list, err
}
stats, err := sb.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 *lntypes.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
}
+3 -4
View File
@@ -365,10 +365,9 @@ func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runc
}
}
if label.RelabelNeeded(bind.Mode) {
if err := label.Relabel(bind.Source, container.MountLabel, label.IsShared(bind.Mode)); err != nil {
return err
}
shared := label.IsShared(bind.Mode)
if err := label.Relabel(bind.Source, container.MountLabel, shared); err != nil {
return err
}
binds[bind.Destination] = true
mountPoints[bind.Destination] = bind
+1 -3
View File
@@ -210,7 +210,6 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
}
serverConfig = setPlatformServerConfig(serverConfig, cli.Config)
defaultHost := opts.DefaultHost
if commonFlags.TLSOptions != nil {
if !commonFlags.TLSOptions.InsecureSkipVerify {
// server requires and verifies client's certificate
@@ -221,7 +220,6 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
logrus.Fatal(err)
}
serverConfig.TLSConfig = tlsConfig
defaultHost = opts.DefaultTLSHost
}
if len(commonFlags.Hosts) == 0 {
@@ -229,7 +227,7 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
}
for i := 0; i < len(commonFlags.Hosts); i++ {
var err error
if commonFlags.Hosts[i], err = opts.ParseHost(defaultHost, commonFlags.Hosts[i]); err != nil {
if commonFlags.Hosts[i], err = opts.ParseHost(commonFlags.Hosts[i]); err != nil {
logrus.Fatalf("error parsing -H %s : %v", commonFlags.Hosts[i], err)
}
}

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

+25 -28
View File
@@ -81,43 +81,42 @@ On the Docker host (192.168.1.52) that Redis will run on:
^D
# add redis ambassador
$ docker run -t -i --link redis:redis --name redis_ambassador -p 6379:6379 alpine:3.2 sh
$ docker run -t -i --link redis:redis --name redis_ambassador -p 6379:6379 busybox sh
In the `redis_ambassador` container, you can see the linked Redis
containers `env`:
/ # env
$ env
REDIS_PORT=tcp://172.17.0.136:6379
REDIS_PORT_6379_TCP_ADDR=172.17.0.136
REDIS_NAME=/redis_ambassador/redis
HOSTNAME=19d7adf4705e
SHLVL=1
HOME=/root
REDIS_PORT_6379_TCP_PORT=6379
HOME=/
REDIS_PORT_6379_TCP_PROTO=tcp
container=lxc
REDIS_PORT_6379_TCP=tcp://172.17.0.136:6379
TERM=xterm
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
/ # exit
This environment is used by the ambassador `socat` script to expose Redis
to the world (via the `-p 6379:6379` port mapping):
$ docker rm redis_ambassador
$ CMD="apk update && apk add socat && sh"
$ docker run -t -i --link redis:redis --name redis_ambassador -p 6379:6379 alpine:3.2 sh -c "$CMD"
[...]
/ # socat -t 100000000 TCP4-LISTEN:6379,fork,reuseaddr TCP4:172.17.0.136:6379
$ sudo ./contrib/mkimage-unittest.sh
$ docker run -t -i --link redis:redis --name redis_ambassador -p 6379:6379 docker-ut sh
$ socat TCP4-LISTEN:6379,fork,reuseaddr TCP4:172.17.0.136:6379
Now ping the Redis server via the ambassador:
Now go to a different server:
$ CMD="apk update && apk add socat && sh"
$ docker run -t -i --expose 6379 --name redis_ambassador alpine:3.2 sh -c "$CMD"
[...]
/ # socat -t 100000000 TCP4-LISTEN:6379,fork,reuseaddr TCP4:192.168.1.52:6379
$ sudo ./contrib/mkimage-unittest.sh
$ docker run -t -i --expose 6379 --name redis_ambassador docker-ut sh
$ socat TCP4-LISTEN:6379,fork,reuseaddr TCP4:192.168.1.52:6379
And get the `redis-cli` image so we can talk over the ambassador bridge.
@@ -128,8 +127,8 @@ And get the `redis-cli` image so we can talk over the ambassador bridge.
## The svendowideit/ambassador Dockerfile
The `svendowideit/ambassador` image is based on the `alpine:3.2` image with
`socat` installed. When you start the container, it uses a small `sed`
The `svendowideit/ambassador` image is a small `busybox` image with
`socat` built in. When you start the container, it uses a small `sed`
script to parse out the (possibly multiple) link environment variables
to set up the port forwarding. On the remote host, you need to set the
variable using the `-e` command line option.
@@ -140,21 +139,19 @@ Will forward the local `1234` port to the remote IP and port, in this
case `192.168.1.52:6379`.
#
# do
# docker build -t svendowideit/ambassador .
#
# first you need to build the docker-ut image
# using ./contrib/mkimage-unittest.sh
# then
# docker build -t SvenDowideit/ambassador .
# docker tag SvenDowideit/ambassador ambassador
# then to run it (on the host that has the real backend on it)
# docker run -t -i -link redis:redis -name redis_ambassador -p 6379:6379 svendowideit/ambassador
# docker run -t -i --link redis:redis --name redis_ambassador -p 6379:6379 ambassador
# on the remote host, you can set up another ambassador
# docker run -t -i -name redis_ambassador -expose 6379 -e REDIS_PORT_6379_TCP=tcp://192.168.1.52:6379 svendowideit/ambassador sh
# you can read more about this process at https://docs.docker.com/articles/ambassador_pattern_linking/
# docker run -t -i --name redis_ambassador --expose 6379 sh
# use alpine because its a minimal image with a package manager.
# prettymuch all that is needed is a container that has a functioning env and socat (or equivalent)
FROM alpine:3.2
MAINTAINER SvenDowideit@home.org.au
FROM docker-ut
MAINTAINER SvenDowideit@home.org.au
RUN apk update && \
apk add socat && \
rm -r /var/cache/
CMD env | grep _TCP= | sed 's/.*_PORT_\([0-9]*\)_TCP=tcp:\/\/\(.*\):\(.*\)/socat -t 100000000 TCP4-LISTEN:\1,fork,reuseaddr TCP4:\2:\3 \& wait/' | sh
CMD env | grep _TCP= | sed 's/.*_PORT_\([0-9]*\)_TCP=tcp:\/\/\(.*\):\(.*\)/socat TCP4-LISTEN:\1,fork,reuseaddr TCP4:\2:\3 \&/' | sh && top
@@ -1,16 +1,17 @@
<!--[metadata]>
+++
title = "Quickstart containers"
title = "Get started with containers"
description = "Common usage and commands"
keywords = ["Examples, Usage, basic commands, docker, documentation, examples"]
[menu.main]
parent = "mn_fun_docker"
parent = "smn_containers"
+++
<![end-metadata]-->
# Quickstart containers
# Get started with containers
This quickstart assumes you have a working installation of Docker. To verify Docker is installed, use the following command:
This guide assumes you have a working installation of Docker. To verify Docker
is installed, use the following command:
# Check that you have a working install
$ docker info
@@ -53,7 +54,7 @@ image cache.
To run an interactive shell in the Ubuntu image:
$ docker run -i -t ubuntu /bin/bash
The `-i` flag starts an interactive container. The `-t` flag creates a
pseudo-TTY that attaches `stdin` and `stdout`.
@@ -182,7 +183,7 @@ re-used.
When you commit your container, Docker only stores the diff (difference) between
the source image and the current state of the container's image. To list images
you already have, use the `docker images` command.
you already have, use the `docker images` command.
# Commit your container to a new named image
$ docker commit <container> <some_name>
@@ -192,8 +193,7 @@ you already have, use the `docker images` command.
You now have an image state from which you can create new instances.
## Where to go next
* Work your way through the [Docker User Guide](../userguide/index.md)
* Read more about [*Share Images via Repositories*](../userguide/dockerrepos.md)
* Review [*Command Line*](../reference/commandline/cli.md)
Read more about [*Share Images via
Repositories*](../userguide/dockerrepos.md) or
continue to the complete [*Command
Line*](../reference/commandline/cli.md)
+1 -1
View File
@@ -59,7 +59,7 @@ in a database image.
In almost all cases, you should only run a single process in a single
container. Decoupling applications into multiple containers makes it much
easier to scale horizontally and reuse containers. If that service depends on
another service, make use of [container linking](../userguide/networking/default_network/dockerlinks.md).
another service, make use of [container linking](../userguide/dockerlinks.md).
### Minimize the number of layers

Some files were not shown because too many files have changed in this diff Show More