Compare commits

..

515 Commits

Author SHA1 Message Date
Tianon Gravi 3c20a8cdc7 Clean out remaining cruft from 'tianon-separate-dockerinit' 2013-10-18 18:19:54 -06:00
Guillaume J. Charmes d5b3299673 Merge branch 'tianon-separate-dockerinit' into dm
Conflicts:
	runtime_test.go
2013-10-18 16:40:15 -07:00
Guillaume J. Charmes 27140018c5 Merge branch 'links' into dm
Conflicts:
	Dockerfile
	docker-init/docker-init.go
	hack/make.sh
	hack/make/binary
	hack/make/test
	runtime.go
	runtime_test.go
	utils.go
2013-10-18 15:40:50 -07:00
Victor Vieux fbf85e2e0a fix merge issue and gofmt 2013-10-18 14:15:24 -07:00
Victor Vieux d596a8a72c no more name encoding 2013-10-18 14:05:53 -07:00
Victor Vieux bf25342e11 replace == by HasPrefix for names and improve error message 2013-10-18 14:05:53 -07:00
Victor Vieux 4f51ad7d0e refactor notrunc in commands.go to add names support 2013-10-18 14:05:53 -07:00
Victor Vieux 2e181c5635 fix typo in docs 2013-10-18 14:05:53 -07:00
Michael Crosby 1db7cb2f01 Updated fixes post rebase from master
Removed test cases that are no longer
applicable with links and the port changes.
Remove test case where a test was hitting an
external ip.
2013-10-18 14:05:53 -07:00
Alexander Larsson e6e6d89cc1 Move SysInit to a submodule
This allows docker-init to not import the main docker
module, which means it won't e.g. pick up any sqlite
dependencies.
2013-10-18 14:05:53 -07:00
Alexander Larsson 1484434196 Move ListOps to utils submodule
This will be needed for later use in docker-init without a docker
dependency
2013-10-18 14:05:53 -07:00
Alexander Larsson 34c7fb0c43 Add a network test
This just tries pinging first 127.0.0.1 and then 8.8.8.8.

We can't ping via a dns name, because libresolv.so is missing
from the test image, so dns resolving doesn't work.
2013-10-18 14:05:53 -07:00
Alexander Larsson 9268e5e42f network: Stop shelling out to /sbin/ip
We have our own netlink version of all the required calls now, so
we can just skip the /sbin/ip dependency.
2013-10-18 14:05:53 -07:00
Alexander Larsson 04f8ffa140 Use netlink directly instead of /bin/ip in Sysinit
The sysinit code only uses /bin/ip to set a default gateway. This
is pretty easy to do via netlink directly, so we can avoid
the ip dependency.
2013-10-18 14:05:53 -07:00
Alexander Larsson 7e3e662ba5 Add netlink submodule
This contains various operations that can replace the use of
shelling out to "ip".
2013-10-18 14:05:52 -07:00
Michael Crosby 2b17d79e5b Add flag for inter-container communication 2013-10-18 14:05:52 -07:00
Solomon Hykes 0fae30e8c3 Typos and FIXMEs 2013-10-18 14:05:52 -07:00
Solomon Hykes 7fff719cf3 gograph: fix a bug which caused the unicity of (parent, name) to not be enforced 2013-10-18 14:05:52 -07:00
Michael Crosby 6f8d479324 Remove docker ls from docs and cli usage 2013-10-18 14:05:52 -07:00
Michael Crosby 4c27690cdd Add links for container relationships and introspection 2013-10-18 14:04:41 -07:00
Guillaume J. Charmes bc92933384 Merge branch 'separate-dockerinit' of https://github.com/tianon/docker into tianon-separate-dockerinit 2013-10-18 12:45:28 -07:00
Guillaume J. Charmes e9ee860c91 Merge branch 'master' into dm
Conflicts:
	Dockerfile
	buildfile.go
	container.go
	hack/make/test
	runtime_test.go
	utils/utils.go
2013-10-18 12:38:29 -07:00
Guillaume J. Charmes c2175ae736 Switch back some Errorf to Debugf. 2013-10-18 12:29:16 -07:00
Andy Rothfusz ad7c6bc950 Merge pull request #2281 from metalivedev/cleanupformat
Clean up build warnings. Remove redundant files.
2013-10-18 11:39:46 -07:00
Victor Vieux 2e4ee72201 Merge pull request #2282 from shykes/fix-tests
Tests: Cleanup the test suite
2013-10-18 11:31:13 -07:00
Tianon Gravi 34365ececa Rename all cases of "docker-init" to "dockerinit" for consistency 2013-10-18 10:32:19 -06:00
Alexander Larsson 7591a69108 Add a separate docker-init binary
This may be used for the .dockerinit case if the main binary is not
statically linked.

Conflicts:
	docker-init/docker-init.go
2013-10-18 10:23:45 -06:00
Alexander Larsson 764ce78c1d Move SysInit to a submodule
This allows docker-init to not import the main docker
module, which means it won't e.g. pick up any sqlite
dependencies.
2013-10-18 10:22:28 -06:00
Alexander Larsson 2812baf395 devmapper: Fix prefix name to work with udev
Udev escapes "," used in device names to 0\x2c which breaks libdevmapper.
Instead use : to escape minor and minor which works.
2013-10-18 11:39:47 +02:00
Alexander Larsson 572b1fd9be devmapper: Fix major/minor extraction
The way devices are mapped is a bit more complex than before.
This implements the method from new_decode_dev in:
https://github.com/mirrors/linux-2.6/blob/master/include/linux/kdev_t.h

Which is what is needed on kernels > 2.6
2013-10-18 11:38:21 +02:00
Solomon Hykes 4756ad248a devmapper: use major,minor of underlying device in devmapper device name, for readability. 2013-10-18 08:30:53 +00:00
Solomon Hykes dfb77274ce devmapper: clearer make the 'unknown base hash' error message more understandable 2013-10-18 08:22:42 +00:00
Solomon Hykes b629810fe0 hack: encode the name of the current test in temporary directories, for easier tracking
Conflicts:
	utils_test.go
2013-10-18 07:29:07 +00:00
Solomon Hykes 07d9e4353b Increase readbility of unit tests by using mkRuntime everywhere 2013-10-18 07:20:39 +00:00
Solomon Hykes 73545199a8 Merge remote-tracking branch 'alexlarsson/dm-status' into dm
Conflicts:
	devmapper/deviceset.go
2013-10-18 07:17:13 +00:00
Solomon Hykes 0ad35c6746 devmapper: cleanup error reporting 2013-10-18 07:09:13 +00:00
Solomon Hykes 5e363072f5 Merge branch 'dm' of ssh://github.com/dotcloud/docker into dm 2013-10-18 06:51:50 +00:00
Solomon Hykes cad913c57b devmapper: the tests are fast enough that we no longer need a workaround to avoid timeouts 2013-10-18 06:48:20 +00:00
Solomon Hykes 5f58a1fbe4 hack: encode the name of the current test in temporary directories, for easier tracking 2013-10-18 06:47:08 +00:00
Solomon Hykes 07e09d57af Increase readbility of unit tests by using mkRuntime everywhere 2013-10-18 06:44:30 +00:00
Tianon Gravi 89a2c8e2cd Merge pull request #2283 from tmc/master
Make mkimage-arch.sh a little more clear
2013-10-17 23:05:01 -07:00
Solomon Hykes 9f85a967bb Merge pull request #2269 from alexlarsson/dm-blocksize
devmapper: Use a smaller blocksize for the thin-pool
2013-10-17 22:50:33 -07:00
Travis Cline f34a62ea19 Use heredoc to make expect script more clear 2013-10-18 00:35:12 -05:00
Solomon Hykes 85a36b3b53 devmapper: rename deviceset_devmapper.go to deviceset.go 2013-10-18 05:19:22 +00:00
Solomon Hykes d3505d836a Merge remote-tracking branch 'alexlarsson/dm-readonly-images' into dm
Conflicts:
	devmapper/deviceset_devmapper.go
2013-10-18 03:40:46 +00:00
Solomon Hykes c47e93fcbe Merge remote-tracking branch 'alexlarsson/fix-tar-leak' into dm-correct 2013-10-18 03:32:47 +00:00
Solomon Hykes 5cd7de5de8 hack: fail tests if there are leftover temp files before or after 2013-10-18 03:31:21 +00:00
Solomon Hykes 5c175357aa Hack: fix tests which didn't cleanup properly 2013-10-18 02:13:36 +00:00
Solomon Hykes 240d5b3fa1 Hack: don't run integration tests in /var/lib/docker/unit-tests; add missing cleanups in a few tests 2013-10-18 02:13:36 +00:00
Solomon Hykes d034aafac7 devicemapper: Add fixme 2013-10-18 00:58:20 +00:00
Andy Rothfusz 689bcd1dc3 Clean up build warnings. Remove redundant files. 2013-10-17 17:57:01 -07:00
Solomon Hykes 4bd6021806 devmapper: Rename DeviceSetDM to DeviceSet 2013-10-18 00:07:56 +00:00
Solomon Hykes ed03dbfe82 Don't add /.docker-id to the container filesystem 2013-10-18 00:07:46 +00:00
Solomon Hykes 330062ef72 Remove race condition caused by double-destroy in 2 tests 2013-10-17 23:59:59 +00:00
Jérôme Petazzoni 95ccb78aa7 Merge pull request #2253 from jpetazzo/infrastructure-docs
Try a different presentation of infrastructure documentation.
2013-10-17 16:17:32 -07:00
Guillaume J. Charmes 31b883b076 Add error checking and error messages 2013-10-17 15:04:14 -07:00
Jérôme Petazzoni d401e9d3ac Add Stackbrew. 2013-10-17 14:11:10 -07:00
Guillaume J. Charmes bdb3b2a88c Merge pull request #2262 from alexlarsson/dm-dind-use-root-dir
devicemapper: Use device/inode of the root dir, not the image
2013-10-17 11:54:40 -07:00
Victor Vieux 47cc6c8081 Update CHANGELOG.md 2013-10-17 11:26:17 -07:00
Alexander Larsson a14496ce89 Devmapper: Mount images readonly when calculating changes
There is no need to have this be writable, and there is a chance
that e.g. atime updates will cause writes to the image which is
bad for disk use wrt sharing between all containers.
2013-10-17 16:14:53 +02:00
Alexander Larsson 8abcc8e713 devmapper: Use a smaller blocksize for the thin-pool
As per the thin provisioning docs for creating the pool:

   $data_block_size gives the smallest unit of disk space that can be
   allocated at a time expressed in units of 512-byte sectors.
   $data_block_size must be between 128 (64KB) and 2097152 (1GB) and a
   multiple of 128 (64KB). $data_block_size cannot be changed after the
   thin-pool is created. People primarily interested in thin provisioning
   may want to use a value such as 1024 (512KB). People doing lots of
   snapshotting may want a smaller value such as 128 (64KB).

The switch from 512 (which we used before) to 128 (recommended above
for lots of snapshoting) means a simple container creation (based on the
mattdm/fedora:f19 image) adds 1 MB of diskspace rather than 3.6.
This seems more in tune with how docker is typically used.
2013-10-17 15:33:00 +02:00
Alexander Larsson d733cdcebb Show devicemapper status in "docker info"
This shows the current global diskspace use in "docker info"
2013-10-17 15:32:07 +02:00
Alexander Larsson 0aee096fd7 TarFilter: Fix leak of tmpfiles
We were leaking the temporary directory that we create in TarFilter,
because the "tmpDir, err := ioutil.TempDir()" call overrides the
tmpDir in the outer scope with a new locally scoped variable.
This means tmpDir is always "" when the cleanup function is called.

Also, we did not call the atExit() function if CmdStream had an
error early on.

On errors in CmdStream(),
2013-10-17 14:46:58 +02:00
Alexander Larsson e6a73e65a2 devicemapper: Use device/inode of the root dir, not the image
This way the devicemapper prefix stays stable even if we're not
using loopback mounted devices.
2013-10-17 09:53:09 +02:00
Solomon Hykes ad2fbd9e87 devmapper: error reporting workaround in waitRemove() 2013-10-17 01:49:51 +00:00
Solomon Hykes e5d7472a0d devmapper: small fixes in error reporting 2013-10-17 01:49:27 +00:00
Solomon Hykes 7d3c7e2b29 devmapper: debug messages 2013-10-17 01:47:03 +00:00
Solomon Hykes f1d07e2dbe devmapper: prefix device names with the dev_id+inode of the data image 2013-10-17 01:46:28 +00:00
Solomon Hykes ad968ef3ef devmapper: add useful comments 2013-10-17 01:42:05 +00:00
Michael Crosby 414795856a Merge branch 'release' 2013-10-16 18:20:04 -07:00
Michael Crosby 2f74b1c84b Merge pull request #2255 from dotcloud/bump_0.6.4
Bump to 0.6.4
2013-10-16 17:59:45 -07:00
Michael Crosby e8da76605f Bump version to 0.6.4 2013-10-16 17:50:08 -07:00
Michael Crosby f16e60665b Merge branch 'master' into bump_0.6.4 2013-10-16 17:48:17 -07:00
Michael Crosby 3ba9893786 Merge pull request #2242 from jpetazzo/remove-spurious-errors-and-errclosedpipe
Fix error/debug messages in Container.Attach and recover from ErrClosedPipe
2013-10-16 17:27:23 -07:00
Jérôme Petazzoni 7b1c6ccabd Try a different presentation of infrastructure documentation. 2013-10-16 17:11:21 -07:00
Solomon Hykes c688e9b5a6 devmapper: debug messages 2013-10-16 23:27:33 +00:00
Solomon Hykes f3e6d34df2 hack: cleanup devicemapper at the last test 2013-10-16 23:27:00 +00:00
Solomon Hykes ea04f3de72 devmapper: wait for devices to be effectively removed before returning a successful remove 2013-10-16 23:26:37 +00:00
Solomon Hykes 153248b60f devicemapper: remove unused code 2013-10-16 23:23:35 +00:00
Guillaume J. Charmes 6ee2964a4f Merge pull request #2256 from dotcloud/discard_errno_0_errors
- Runtime: discard errno = 0 errors
2013-10-16 16:22:03 -07:00
Solomon Hykes 1711de4b09 devmapper: wait for devices to be effectively unmounted before removing them 2013-10-16 23:06:07 +00:00
Victor Vieux 49c62879b8 discard errno = 0 errors 2013-10-16 23:05:50 +00:00
Michael Crosby 34745ee0f4 Merge pull request #2246 from dotcloud/clean_when_start_fail
Add cleanup when container.Start fails
2013-10-16 15:06:08 -07:00
Victor Vieux d21bd5b964 Merge pull request #2251 from dotcloud/skip_autoremove_test
skip auto-remove test for now
2013-10-16 14:59:08 -07:00
Michael Crosby 82220ea2ad Merge pull request #2249 from jpetazzo/cleanup-errclosing-in-proxy
Catch errClosing error when TCP and UDP proxies are terminated.
2013-10-16 14:51:43 -07:00
Victor Vieux 655b16c712 skip auto-remove test for now 2013-10-16 21:47:20 +00:00
Michael Crosby eb2d0d4bf5 Merge pull request #2250 from dotcloud/revert-07-doc-changes
Revert "Fix #2115 Clean AUFS references. Also fixes some links to client...
2013-10-16 14:44:53 -07:00
Jérôme Petazzoni cc851dbb3f Catch errClosing error when TCP and UDP proxies are terminated. 2013-10-16 14:43:20 -07:00
Victor Vieux e40fd1e3e1 fix panic 2013-10-16 21:39:03 +00:00
Michael Crosby dab84f7e8b Revert "Fix #2115 Clean AUFS references. Also fixes some links to client libraries and mongo example."
This reverts commit f4c17a202b.
2013-10-16 14:38:24 -07:00
Daniel Mizyrycki 7df8ec2093 Merge pull request #2195 from mzdaniel/report
Add aggregated docker-ci email report
2013-10-16 14:29:24 -07:00
Solomon Hykes 11d695a297 Add debug messages while testing devicemapper 2013-10-16 20:45:59 +00:00
Solomon Hykes acf58362cb Hack: fix tests which didn't cleanup properly 2013-10-16 20:44:15 +00:00
Guillaume J. Charmes 3a246ac3d1 Change default values for devicemapper as variable instead of env 2013-10-16 20:42:50 +00:00
Daniel Mizyrycki a2ffa637ce testing infrastructure, PR #2195: Add aggregated docker-ci email report 2013-10-16 13:30:15 -07:00
Guillaume J. Charmes ed6ca109bf Refactor container.Start() 2013-10-16 13:12:56 -07:00
Solomon Hykes 1da335f784 Hack: don't run integration tests in /var/lib/docker/unit-tests; add missing cleanups in a few tests 2013-10-16 20:10:20 +00:00
Victor Vieux 6e48b73955 Merge pull request #2247 from dotcloud/improve_tests_error_messages
Tests: Remove a few errors
2013-10-16 12:50:15 -07:00
Victor Vieux 664acd2971 Add clean if start fail 2013-10-16 19:48:24 +00:00
Victor Vieux 3acfc60028 change an errorf to a debugf 2013-10-16 19:45:10 +00:00
Victor Vieux 0e64a4d7e7 remove false alarm error 2013-10-16 19:38:12 +00:00
Victor Vieux 104a86936a api.go:108 Error parsing media type: error: mime: no media type
fix
2013-10-16 19:32:03 +00:00
Victor Vieux df697b4318 use httpError in a separate test 2013-10-16 19:23:47 +00:00
Tianon Gravi 27fc01271e Merge pull request #2219 from tianon/completion
Reorganize contributed completion scripts to add zsh completion
2013-10-16 11:40:56 -07:00
Tianon Gravi 97ab118fbb Merge pull request #2220 from tianon/vim
Add vim syntax highlighting for Dockerfiles from @honza
2013-10-16 11:40:42 -07:00
Jérôme Petazzoni fc659b68e4 Fix error/debug messages in Container.Attach and recover from ErrClosedPipe conditions. 2013-10-16 11:35:45 -07:00
Guillaume J. Charmes 99f6b43f4f Merge pull request #2243 from jpetazzo/comments-stdcopy
Add better comments to utils/stdcopy.go.
2013-10-16 11:17:15 -07:00
Victor Vieux 2b92aa71f9 Merge pull request #2244 from dotcloud/add_cleanup_leftover_container_tests
Tests: add cleanup to remove leftover containers
2013-10-16 11:09:48 -07:00
Victor Vieux f854529ae8 add cleanupin tests to remove leftover containers 2013-10-16 18:06:37 +00:00
Jérôme Petazzoni e32debcf5f Add better comments to utils/stdcopy.go. 2013-10-16 10:58:53 -07:00
Andy Rothfusz 0e08e1d695 Merge pull request #2236 from SvenDowideit/2209-comments-doc
#2209 - add the example @tianon gave to elaborate on the Comment docume...
2013-10-16 10:51:15 -07:00
Andy Rothfusz 65b62307c3 Merge pull request #2231 from metalivedev/1919-docreleaseinfo
Fix #1919 document how to edit and release docs.
2013-10-16 10:45:01 -07:00
Andy Rothfusz 03e5d94b12 Merge pull request #2090 from kencochrane/master
added initial draft of the Docker infrastructure doc
2013-10-16 10:44:22 -07:00
Tianon Gravi 0ca533ca35 Merge pull request #2233 from tmc/master
Add mkimage-arch.sh
2013-10-15 19:27:45 -07:00
Travis Cline d94a027da6 Add mkimage-arch.sh 2013-10-16 02:26:15 +00:00
Sven Dowideit 7250f94874 #2209 - add the example @tianon gave to elaborate on the Comment documentation 2013-10-16 11:12:47 +10:00
Michael Crosby 4196c704f0 Merge pull request #1943 from dotcloud/1940-prevent_crash_parseNat_build-fix
Abort build if mergeConfig returns an error and fix duplicate error message
2013-10-15 17:40:48 -07:00
Victor Vieux adb48ef319 Merge pull request #2235 from dotcloud/update_dockerfile
Update Dockerfile test comment
2013-10-15 17:32:48 -07:00
Victor Vieux ee7d9b0bde Update Dockerfile test comment 2013-10-16 00:31:34 +00:00
Victor Vieux 2f4526d5c4 Merge pull request #2221 from flavio/fix_broken_tests
Fixed broken tests
2013-10-15 17:26:19 -07:00
Victor Vieux 261285c2c2 Merge pull request #2232 from shykes/error-should-be-debug
Remove error messages which are not actually errors
2013-10-15 17:12:51 -07:00
Solomon Hykes cd61fb2e6f WIP: debugging dm-base-hash + dm-refactor-init 2013-10-15 23:56:04 +00:00
Solomon Hykes fdba1aeed8 Merge branch 'dm-refactor-init' into dm
Conflicts:
	runtime_test.go
2013-10-15 23:27:28 +00:00
Solomon Hykes cbc49d7d76 Remove error messages which are not actually errors 2013-10-15 23:12:27 +00:00
Solomon Hykes c9f3e54c31 Merge branch 'dm-base-hash' into dm 2013-10-15 23:09:26 +00:00
Solomon Hykes 3997b8a923 hack: don't set DEBUG when running tests 2013-10-15 23:07:26 +00:00
Solomon Hykes ec885d9180 hack: only run certain tests with TESTFLAGS='-run TestName' make.sh 2013-10-15 23:06:41 +00:00
Solomon Hykes 4dc90405e3 Merge pull request #2230 from shykes/hack-select-test
hack: only run certain tests with TESTFLAGS='-run TestName' make.sh
2013-10-15 15:58:54 -07:00
Solomon Hykes b7abe9dab5 hack: only run certain tests with TESTFLAGS='-run TestName' make.sh 2013-10-15 22:57:40 +00:00
Andy Rothfusz cd455ca6fa Fix #1919 document how to edit and release docs. 2013-10-15 15:52:21 -07:00
Solomon Hykes 54b0cd7cd1 Merge branch 'dm-missing-mapper' into dm 2013-10-15 22:51:20 +00:00
Solomon Hykes 66db2ac9d8 Merge branch 'dm-fix-test-2' into dm 2013-10-15 22:42:49 +00:00
Alexander Larsson 5ebaca7e55 devmapper: create device nodes 'on create' instead of 'on resume' 2013-10-15 21:27:47 +00:00
Solomon Hykes 432ff7e3c3 Merge pull request #2227 from dotcloud/dm-rename-loopback
Rename loopback dir to devicemapper
2013-10-15 12:23:43 -07:00
Michael Crosby 80bd64245f Add filesystemtype for containers
If no type is specified then assume aufs.
2013-10-15 11:49:13 -07:00
Michael Crosby 4431e9edb7 Rename loopback dir to devicemapper 2013-10-15 11:30:06 -07:00
Flavio Castelli ca56b35e53 Fixed broken tests
Some tests failed because the `auplink` binary was not found inside of the
"docker" container.
2013-10-15 11:44:56 +02:00
Tianon Gravi ace059e409 Add vim syntax highlighting for Dockerfiles from @honza
See https://github.com/honza/dockerfile.vim
See also https://twitter.com/_honza/status/390046317579620352
2013-10-15 03:35:13 -06:00
Tianon Gravi 9da2b3590e Add zsh completion from @felixr with permission
See https://github.com/felixr/docker-zsh-completion for the original.
See also https://github.com/dotcloud/docker/issues/2202#issuecomment-26313287

Fixes #2202
2013-10-15 03:04:06 -06:00
Tianon Gravi e99ab1df97 Move contrib/docker.bash to contrib/completion/bash/docker for better organization 2013-10-15 03:02:31 -06:00
Solomon Hykes fde157425c Merge pull request #2218 from tianon/ksid
Remove @KSid from contrib maintainers for now
2013-10-15 00:13:58 -07:00
Tianon Gravi a0e5657cb6 Remove @KSid from contrib maintainers for now
His availability has been very limited, so I'll take over completely for the short term until he can find more time to help out.
2013-10-15 00:58:34 -06:00
Solomon Hykes 7093411a8d Initialize devicemapper in NewRuntimeFromDIrectory 2013-10-15 03:53:48 +00:00
Guillaume J. Charmes 5778ed7db2 Make sure the base device is well created before running the tests 2013-10-14 18:36:18 -07:00
Michael Crosby 3455c1a098 Use incrementing prefix on pool and loopback to allow dind 2013-10-14 17:48:43 -07:00
Michael Crosby 5dd12ba20a Ignore cleanup with /dev/mapper does not exist 2013-10-14 14:23:58 -07:00
Daniel Mizyrycki f4a98b4598 Merge pull request #2211 from mzdaniel/2190-docker-ci
Prevent docker-ci to test closing PRs
2013-10-14 14:12:23 -07:00
Daniel Mizyrycki 53a07d5475 Prevent docker-ci to test closing PRs 2013-10-14 14:00:06 -07:00
Solomon Hykes 5892c8e469 Merge pull request #2199 from alexlarsson/dm-docs
Add some docs for newly exported functions
2013-10-14 13:33:21 -07:00
Solomon Hykes 20e3e8c07d Merge pull request #2200 from alexlarsson/dm-remove-unused
Runtime: Remove unused funtion hasFilesystemSupport()
2013-10-14 13:24:53 -07:00
Solomon Hykes 79c0c4470f Merge pull request #2182 from dotcloud/cleanup-dm-unittests
Clean up better from previous unit-test runs
2013-10-14 12:29:59 -07:00
Solomon Hykes 4dedd9a9aa Merge pull request #2183 from dotcloud/migrate-aufs
Migrate aufs to new device mapper backend
2013-10-14 12:28:28 -07:00
Solomon Hykes 063ebbab68 Merge pull request #2184 from dotcloud/dm-rmi
Do not allow image to be deleted when containers are dependent
2013-10-14 12:27:19 -07:00
Guillaume J. Charmes ea92dc2e8c Add error return to cleanup, use os.OpenFile instead of syscall.Open, Make sure the pools are removed after all other devices 2013-10-14 12:26:46 -07:00
Andy Rothfusz 93b258413f Merge pull request #2160 from iffy/patch-1
Minor updates to postgresql_service.rst
2013-10-14 11:59:57 -07:00
Andy Rothfusz c0bfb75e5f Merge pull request #2142 from SvenDowideit/patch-1
tell the new developer how they can replace the real docker binary with ...
2013-10-14 11:55:42 -07:00
Michael Crosby 7f429e0ceb Do not allow image to be deleted when containers are dependent 2013-10-14 09:47:01 -07:00
Alexander Larsson bb42801cdc Runtime: Remove unused funtion hasFilesystemSupport()
This used to be used to be used to detect AUFS support, but is not
used anymore.
2013-10-14 10:54:50 +02:00
Alexander Larsson 8e4b3a3390 Add some docs for newly exported functions 2013-10-14 10:53:12 +02:00
Solomon Hykes 48070274ee Change the base filesystem size in unit tests 2013-10-12 15:06:53 -07:00
Michael Crosby c3f1bb3287 Allow loopback and base fs sizes set by env var 2013-10-11 20:37:11 -07:00
Daniel Mizyrycki 620bc5b9e1 Merge pull request #1823 from dotcloud/1766-nightly-release
testing, issue #1766: Add nightly release to docker-ci
2013-10-11 17:38:06 -07:00
Michael Crosby 562e4f1e23 Verbose migration add warning for running container
Conflicts:
	hack/make.sh
	runtime.go
	runtime_test.go
2013-10-11 17:11:18 -07:00
Michael Crosby a263e07678 Migrate AUFS containers to devmapper
Conflicts:
	hack/make.sh
	runtime.go
2013-10-11 16:54:08 -07:00
Alexander Larsson e7986da531 Clean up better from previous unit-test runs
This makes sure we unmount existing mounts (as well as removing the
devmapper devices), and it fails with proper logs rather than just
panic()ing.
2013-10-11 16:42:11 -07:00
Alexander Larsson b440ec0136 device-mapper: Move all devicemapper spew to log through utils.Debugf(). 2013-10-11 16:31:06 -07:00
Alexander Larsson c77697a45c devmapper: Move all "raw" libdevmapper wrappers to devmapper.go
This separates out the DeviceSet logic a bit better from the raw
device mapper operations.

devicemapper: Serialize addess to the devicemapper deviceset

This code is not safe to run in multiple threads at the same time,
and neither is libdevmapper.

DeviceMapper: Move deactivate into UnmountDevice

This way the deactivate is atomic wrt othe device mapper operations
and will not fail with EBUSY if someone else starts a devicemapper
operation inbetween unmount and deactivate.

devmapper: Fix loopback mounting regression

Some changes were added to attach_loop_device which added
a perror() in a place that caused it to override errno so that
a later errno != EBUSY failed. This fixes that and cleans up
the error reporting a bit.

devmapper: Build on old kernels without LOOP_CTL_GET_FREE define
2013-10-11 16:30:02 -07:00
Daniel Mizyrycki 6d6097cddf Merge pull request #1813 from doubleyou/patch-1
Improve network performance for VirtualBox
2013-10-11 16:23:19 -07:00
Daniel Mizyrycki 42277d0329 Merge pull request #2178 from tianon/vagrant-docker-group
Add vagrant user to the docker group
2013-10-11 15:10:50 -07:00
Tianon Gravi d62df6b2b5 Add vagrant user to the docker group 2013-10-11 11:00:04 -06:00
Michael Crosby 97779ff7cf Merge pull request #2118 from karlgrz/936-enhance-logging
Add utils.Errorf for error logging
2013-10-11 08:51:37 -07:00
Michael Crosby 9afa48a92f Merge pull request #2169 from dotcloud/remove-deprecated-packaging
Remove deprecated packaging directory
2013-10-11 08:44:34 -07:00
Karl Grzeszczak ad723bbfe7 Initial steps to fix Issue #936
Use utils.Errorf instead of utils.Debugf
2013-10-11 08:04:40 -05:00
Solomon Hykes f15cd71bb8 Merge pull request #2037 from tianon/install-script-revamp
Revamp install.sh to be usable by more people, and to use official install methods whenever possible (apt repo, portage tree, etc.)
2013-10-10 23:56:13 -07:00
Tianon Gravi 94bf5b0011 Revamp install.sh to be usable by more people, and to use official install methods whenever possible (apt repo, portage tree, etc.), thus making it an official script and moving it to hack/ 2013-10-11 00:53:15 -06:00
Daniel Mizyrycki d542318d63 testing infrastructure, issue #1766: Dockerize deployment of docker-ci 2013-10-10 18:29:10 -07:00
Daniel Mizyrycki 6e3068700f testing infrastructure, issue #1766: Temporarily install docker with proper apparmor handling 2013-10-10 18:29:10 -07:00
Daniel Mizyrycki fac190959f testing, issue #1766: Upgrade tooling for Docker nightly release 2013-10-10 18:29:10 -07:00
Daniel Mizyrycki 1dcdc3deb7 testing, issue #1766: Add nightly release to docker-ci 2013-10-10 18:29:10 -07:00
Solomon Hykes ee256ce6bf Merge pull request #2038 from tianon/mkimage-debian-fixes
Fix contrib/mkimage-debian.sh apt caching prevention
2013-10-10 17:59:17 -07:00
Solomon Hykes 5fe699f813 Merge pull request #2166 from pnasrat/document-approval
Clarify LGTM process to contributors.
2013-10-10 17:55:32 -07:00
Solomon Hykes 7561e2570c Merge pull request #2159 from nathankleyn/fix-references-to-param-names
Small fixes to parameter names in docs for ADD command.
2013-10-10 17:53:57 -07:00
Guillaume J. Charmes 640ca68e4f Merge pull request #2128 from titanous/update-authors
Update AUTHORS
2013-10-10 16:40:33 -07:00
Guillaume J. Charmes f9b9dfc82d Merge pull request #2164 from pnasrat/add-finished-time
* Runtime: Record termination time in state.
2013-10-10 16:29:07 -07:00
Guillaume J. Charmes c978f0fa5c Merge pull request #2165 from jrydberg/master
- Registry: Use correct auth config when logging in.
2013-10-10 16:28:46 -07:00
Sven Dowideit d91bf33df3 tell the new developer how they can replace the real docker binary with the one they've been hacking on (#2142) 2013-10-11 08:47:32 +10:00
Paul Nasrat 310a174260 Clarify LGTM process to contributors. 2013-10-10 18:32:33 -04:00
Solomon Hykes 1804fcba93 Merged master into device-mapper branch 2013-10-10 12:50:30 -07:00
Paul Nasrat 2eb404ab14 Record termination time in state.
Supercedes pull #1946
2013-10-10 14:47:25 -04:00
Ken Cochrane 60e426938e Merge pull request #2155 from jdubois/patch-1
- Documentation: Corrected error in the package name
2013-10-10 11:19:22 -07:00
Matt Haggard 9041d6a47b Minor updates to postgresql_service.rst
I've added the steps that were missing/wrong for me when I went through this just now.
2013-10-10 10:23:24 -06:00
Nathan Kleyn 8abd328f53 Small fixes to parameter names in docs for ADD command. 2013-10-10 12:14:18 +01:00
Solomon Hykes ae780fb5ea Remove deprecated packaging directory (distro-specific packaging is now managed downstream by their respective package maintainers) 2013-10-10 03:54:10 -07:00
Julien Dubois 152037f011 Corrected error in the package name 2013-10-10 10:10:33 +02:00
Andy Rothfusz 0367032bd1 Merge pull request #2144 from shamrin/patch-5
document what `vagrant up` is actually doing
2013-10-09 17:42:37 -07:00
Andy Rothfusz edca9f7e9c Merge pull request #2139 from metalivedev/2115-AUFScleanup
Fix #2115 Clean AUFS references.
2013-10-09 17:35:05 -07:00
Guillaume J. Charmes e19cc1e843 Merge pull request #2125 from dotcloud/2099_rm-v_fix
- Runtime: fix `docker rm` with volumes
2013-10-09 16:01:51 -07:00
Guillaume J. Charmes feabce3bcc Merge pull request #2119 from SvenDowideit/2117-hardcoded-tmp-dir
use empty string so TempDir uses the OS's temp dir automatically (Closes...
2013-10-09 16:00:40 -07:00
Michael Crosby ded74b0bb3 Merge pull request #2133 from dotcloud/improve_tests
Make sure to close the network allocators
2013-10-09 15:45:16 -07:00
Guillaume J. Charmes ffee5faae8 Merge pull request #2145 from dotcloud/remove-panic-test
* Runtime: replace panic by log.Fatal in tests
2013-10-09 15:37:08 -07:00
Andy Rothfusz c1bb33ea4d Merge pull request #2114 from metalivedev/2113-searchbump
Fix #2113 improve doc search results
2013-10-09 12:24:33 -07:00
Andy Rothfusz 6545e53803 Clean up javascript comment. 2013-10-09 12:22:14 -07:00
Victor Vieux d30806590c Merge pull request #2127 from titanous/close-body
Fix some error cases where a HTTP body might not be closed
2013-10-09 06:52:03 -07:00
Victor Vieux 823174de4d replace panic by log.Fatal in tests 2013-10-09 13:47:49 +00:00
Tianon Gravi d5f9160441 Merge pull request #1956 from tianon/bash-completion
Add proper bash completion for "docker push"
2013-10-09 05:47:55 -07:00
Alexey Shamrin 37df1d92d8 document what vagrant up is actually doing
* don't mention outdated PPA that Vagrantfile doesn't use
* point to official Ubuntu installation instructions that Vagrant appears to be following; should be future proof
2013-10-09 15:05:09 +04:00
Jonathan Rudenberg dabac81824 Update AUTHORS 2013-10-08 23:51:38 -04:00
Guillaume J. Charmes bb62c281f5 Merge pull request #2130 from tianon/swap-contrib-maintainers
Swap contrib MAINTAINERS
2013-10-08 17:57:52 -07:00
Andy Rothfusz 3565bf8d00 Merge pull request #2134 from tianon/contributing
Add devenvironment link to CONTRIBUTING.md
2013-10-08 17:36:56 -07:00
Andy Rothfusz f4c17a202b Fix #2115 Clean AUFS references. Also fixes some links to client libraries and mongo example. 2013-10-08 17:33:19 -07:00
Tianon Gravi 9a4b0b9823 Add devenvironment link to CONTRIBUTING.md 2013-10-08 16:48:19 -06:00
Guillaume J. Charmes 9107565d06 Make sure to close the network allocators 2013-10-08 15:42:02 -07:00
Tianon Gravi 4fda3314d8 Swap contrib MAINTAINERS 2013-10-08 15:15:58 -06:00
Jonathan Rudenberg e906485b07 Fix some error cases where a HTTP body might not be closed
Refs #2126
2013-10-08 15:35:00 -04:00
Victor Vieux 1daf242c8b fix rm -v 2013-10-08 16:35:47 +00:00
Johan Rydberg 967010ae8c Use correct auth config when logging in. 2013-10-08 06:46:29 +02:00
Sven Dowideit d03022b9ca use empty string so TempDir uses the OS's temp dir automatically (Closes #2117) 2013-10-08 13:24:20 +10:00
Andy Rothfusz 6d67ac2a1b Insert popularity and boost docs results. 2013-10-07 17:51:07 -07:00
Solomon Hykes 2d425af1b1 Merge pull request #2103 from tianon/clean-out-fixme
Clean out a few outdated FIXME items
2013-10-07 15:19:01 -07:00
Andy Rothfusz ed19693f50 Merge pull request #2106 from mastahyeti/api_1.5_docs_whitespace
Cleanup whitespace in API 1.5 docs
2013-10-07 13:23:55 -07:00
Tianon Gravi ee27444098 Fix contrib/mkimage-debian.sh apt caching prevention 2013-10-07 13:41:10 -06:00
Andy Rothfusz 194c1dbbd8 Merge pull request #2109 from shamrin/patch-4
[docs] use angle brackets in MAINTAINER example email
2013-10-07 12:18:44 -07:00
Alexey Shamrin a9eac7eab4 [docs] use angle brackets in MAINTAINER example email 2013-10-07 20:29:54 +04:00
Ben Toews 7c28683f08 Cleanup whitespace in API 1.5 docs
remove whitespace on blank lines
2013-10-06 19:52:18 -06:00
Daniel Mizyrycki c18e849451 Merge pull request #2061 from dotcloud/1948-test-detach
testing, issue #1948: Increase TestRunDetach timeout
2013-10-06 13:26:44 -07:00
Tianon Gravi a665517151 Clean out a few outdated FIXME items 2013-10-06 13:55:26 -06:00
Ken Cochrane 0d3c899528 added initial draft of the Docker infrastructure doc 2013-10-04 15:12:40 -04:00
Andy Rothfusz 863eebe7bd Merge pull request #2084 from makeusabrew/patch-1
Fix help text for -v option
2013-10-04 09:29:56 -07:00
Victor Vieux f6913592a1 Merge pull request #2087 from alexlarsson/device-mapper-test
Device mapper test branch update
2013-10-04 07:54:43 -07:00
Alexander Larsson aaf1f73bcc Tests: Initialize devicemapper early to avoid it happening in a test
This can take a while and may cause some tests to timeout
2013-10-04 15:47:43 +02:00
Alexander Larsson 9b65c7cf49 hack: Don't just run the "TestRunHostname" test 2013-10-04 15:38:47 +02:00
Alexander Larsson f7e374fb3a Remove overly spewy Debugf 2013-10-04 15:36:30 +02:00
Nick Payne 3c5350ba92 Fix help text for -v option 2013-10-04 10:26:57 +01:00
Tianon Gravi c52c95f97f Merge pull request #1876 from asbjornenge/master
Added Dockerfile.tmLanguage to contrib
2013-10-03 23:52:37 -07:00
Asbjørn Enge 85a5139665 Added Dockerfile.tmLanguage to contrib 2013-10-04 08:45:15 +02:00
Guillaume J. Charmes f29c500d8d Small fixes 2013-10-03 18:05:07 -07:00
Guillaume J. Charmes b843998718 Small fixes 2013-10-03 18:04:14 -07:00
Michael Crosby ad4b09cdb8 Merge pull request #1832 from dotcloud/26-default_r_flag
Autorestart containers by default
2013-10-03 15:59:58 -07:00
Victor Vieux e594c788e4 keep -r, but default true 2013-10-03 22:42:35 +00:00
Victor Vieux f84dc1e908 add missing error check 2013-10-03 22:33:00 +00:00
Michael Crosby 826aaa0e9b Merge pull request #1990 from modcloth-labs/more-tests-for-auth-registry-resolution
Adding more tests around `auth.ResolveAuthConfig`
2013-10-03 14:45:02 -07:00
Alexander Larsson 1a1be5a87c Make sure we mark the libdevmapper /dev/mapper/control fd CLOEXEC
We do a hack to mark it such, because otherwise lxc-start will not
work.
2013-10-03 21:00:16 +02:00
Alexander Larsson 7b58e15b08 Be better at cleaning up leftover from earlier test runs
When running the test inside a docker container we sometimes are left with
leftover device nodes for device mapper devices that no longer exist.
We were panic:ing in this case, but with this change we just remove such
nodes.
2013-10-03 19:54:14 +02:00
Victor Vieux 1328be7c29 Add test 2013-10-03 15:21:14 +00:00
Guillaume J. Charmes 8b2f4aab23 Random improvments 2013-10-02 20:18:15 -07:00
Tianon Gravi 06d0843a61 Update Dockerfile and hack to support compiling device-mapper code statically (using go1.2rc1) 2013-10-03 10:32:47 -06:00
Victor Vieux deb05a36e8 rebase 2013-10-03 15:49:28 +00:00
Victor Vieux 55189307d0 disable: don't create device nodes manually if udev is not availabile as we don't have it in dind 2013-10-03 15:47:38 +00:00
Andy Rothfusz ff4f32d58f Fix #2017 Merge branch '2017-api-details' 2013-10-02 18:20:44 -07:00
Andy Rothfusz 462ac1efcf Merge branch 'hint-api-details' of git://github.com/cdunklau/docker into 2017-api-details
Conflicts:
	docs/sources/api/docker_remote_api.rst
2013-10-02 18:18:46 -07:00
Solomon Hykes 1332f400f7 Merge pull request #2015 from dsissitka/1927
Configured FPM to make /etc/init/docker.conf a config file.
2013-10-02 18:18:16 -07:00
Solomon Hykes a292c04ddb Merge pull request #2069 from philips/add-xz-to-runtime-dependencies
fix(hack/PACKAGERS): add xz utils as a runtime dep
2013-10-02 17:37:56 -07:00
Andy Rothfusz 37c4513cf9 Merge pull request #2060 from mastahyeti/patch-1
Add `apt-get install curl` to Ubuntu docs
2013-10-02 16:46:00 -07:00
Andy Rothfusz b584c21ca4 Merge pull request #2063 from dhrp/doc-template-fix
Doc template fix
2013-10-02 16:31:47 -07:00
Andy Rothfusz c92507341d Merge pull request #2073 from tianon/gentoo-no-more-1422-hack
Remove Gentoo install notes about #1422 workaround
2013-10-02 16:24:11 -07:00
Andy Rothfusz 9f0feaa2e1 Merge pull request #2065 from kyleconroy/fix_ping_endpoint
Fix Ping endpoint documentation
2013-10-02 16:22:49 -07:00
Ben Toews 0f830aa431 Update ubuntu docs to use wget instead of curl
Ubuntu doesn't come with curl.

wget instead of curl

nicer wget syntax

remove /dev/null
2013-10-02 16:27:34 -06:00
Tianon Gravi 5f05cb4817 Remove Gentoo install notes about #1422 workaround 2013-10-02 16:06:22 -06:00
Michael Crosby 4778039dd2 Merge pull request #2066 from tianon/vendor-bump-kr-pty
Bump vendor kr/pty to commit 3b1f6487b (syscall.O_NOCTTY)
2013-10-02 14:44:07 -07:00
Guillaume J. Charmes b180770b1d Merge pull request #2014 from alexlarsson/allow_set_file_cap
* Runtime: lxc: Allow set_file_cap capability in container
2013-10-02 14:38:50 -07:00
Brandon Philips 4f5c2cbccc fix(hack/PACKAGERS): add xz utils as a runtime dep 2013-10-02 12:06:19 -07:00
Andy Rothfusz c3acd9bece Merge pull request #2047 from Thermionix/patch-1
Update archlinux.rst
2013-10-02 10:57:48 -07:00
Tianon Gravi cb21a40490 Bump vendor kr/pty to commit 3b1f6487b (syscall.O_NOCTTY) 2013-10-01 19:48:50 -06:00
Thatcher Peskens 5025b4d094 Cleanup 2013-10-01 16:32:56 -07:00
Thatcher Peskens 509e25cf04 Add/modified the canonical link to work with all /index/ links. Added style for "danger' 2013-10-01 16:26:14 -07:00
Daniel Mizyrycki 135c1fce90 testing, issue #1948: Increase TestAttachDetach and TestRunDetach timeout 2013-10-01 15:59:52 -07:00
Kyle Conroy d517fd3d77 Fix Ping endpoint documentation 2013-10-01 15:49:32 -07:00
Michael Crosby b4e1b8d2e2 Merge pull request #2058 from marcusramberg/patch-1
Fix ironic typo in changelog
2013-10-01 09:58:32 -07:00
Marcus Ramberg 45bd52d472 Fix ironic typo in changelog 2013-10-01 18:16:10 +02:00
Andy Rothfusz 534a991cff fix logo path 2013-09-30 16:54:04 -07:00
Alexander Larsson 55e1782d66 Image: Fix time setting for old kernels
This is a better fix for futimes() on kernels not supporting O_PATH.
The previous fix broke when copying a device, as it tried to open it
and got and error.
2013-09-30 17:35:02 -06:00
Victor Vieux 152302e379 go fmt and aufs support removed 2013-09-30 17:35:02 -06:00
Victor Vieux 72a08a5458 Revert "add a -mount-method flag"
This reverts commit e52d756f40c9ccf8b37ca496cb72be057c909ed7.
2013-09-30 17:35:02 -06:00
Victor Vieux aeb89ffbba add a -mount-method flag 2013-09-30 17:35:02 -06:00
Alexander Larsson 0484b2c325 RootIsShared: Fix root detection
Column 4 is the mount position, column 3 will not always be
"/" for the root. On one of my system its "/root".
2013-09-30 17:35:02 -06:00
Alexander Larsson be6fef0254 Tests: Clean up any old devmapper leftovers before starting tests 2013-09-30 17:35:02 -06:00
Alexander Larsson 071cc18b58 Image.Changes: Deactivate image device after unmounting it
There is no need to keep the image device around if we were the
onces creating the device.
2013-09-30 17:35:02 -06:00
Alexander Larsson 6ec5585501 Add DeviceSet.HasActivatedDevice()
This lets you see if a device has been activated
2013-09-30 17:35:02 -06:00
Alexander Larsson 6f57e8025a image: Unmount before removing device in error paths
The device remove fails unless we unmount first
2013-09-30 17:35:02 -06:00
Alexander Larsson b0a9147fd5 runtime test: Ensure all containers are unmounted at nuke()
Otherwise we may leave around e.g. devmapper mounts
2013-09-30 17:35:02 -06:00
Alexander Larsson a7e876e357 ShellQuoteArguments: Fix quoting
This accidentally used two quotes to start/end each quoted string.
2013-09-30 17:35:01 -06:00
Alexander Larsson ecdbdfdaea Image: unmount device before removing it on failures
If we don't do this the remove will fail due to EBUSY
2013-09-30 17:35:01 -06:00
Alexander Larsson 2c71710b74 image: Handle systems that don't support O_PATH when updating timestamp
Older kernel can't handle O_PATH in open() so this will
fail on dirs and symlinks. For dirs wa can fallback to
the normal Utimes, but for symlinks there is not much to do
but ignore their timestamps.
2013-09-30 17:35:01 -06:00
Alexander Larsson bbc72c85f7 devmapper: Fix loopback mount code
Typo in the loop-control code made it always fall back to the
old method of opening loopback devices.
2013-09-30 17:35:01 -06:00
Alexander Larsson 1a082ed245 applyLayer() use btrfs reflinks if availible
We use the new file copy helper which uses btrfs reflinks if availible.
2013-09-30 17:35:01 -06:00
Alexander Larsson 86421e8b5e Add CopyFile that can use btrfs reflinks if availible 2013-09-30 17:35:01 -06:00
Alexander Larsson 91c69fd353 Remove accidental commit that enabled MountMethodFilesystem 2013-09-30 17:35:01 -06:00
Alexander Larsson 43a7d3d0e9 Add trivial copy-based CoW backend
This creates a container by copying the corresponding files
from the layers into the containers. This is not gonna be very useful
on a developer setup, as there is no copy-on-write or general diskspace
sharing. It also makes container instantiation slower.

However, it may be useful in deployment where we don't always have a lot
of containers running (long-running daemons) and where we don't
do a lot of docker commits.
2013-09-30 17:35:01 -06:00
Alexander Larsson 60f552cac3 Add Changes.ChangesLayers()
This calculates the difference between a set of layers and a
directory tree.
2013-09-30 17:35:01 -06:00
Alexander Larsson ad402763e1 Changes: Better metadata comparison
Change the comparison to better handle files that are copied during
container creation but not actually changed:

* Inode - this will change during a copy
* ctime - this will change during a copy (as we can't set it back)
* blocksize - this will change for sparse files during copy
* size for directories - this can change anytime but doesn't
  necessarily reflect an actual contents change
* Compare mtimes at microsecond precision (as this is what utimes has)
2013-09-30 17:35:01 -06:00
Alexander Larsson 5d2ace3424 Image.applyLayer: Be better at creating identical files
There are some changes here that make the file metadata better match
the layer files:

* Set the mode of the file after the chown, as otherwise the per-group/uid
  specific flags and e.g. sticky bit is lost
* Use lchown instead of chown
* Delay mtime updates to after all other changes so that later file
  creation doesn't change the mtime for the parent directory
* Use Futimes in combination with O_PATH|O_NOFOLLOW to set mtime on symlinks
2013-09-30 17:35:01 -06:00
Alexander Larsson 727e7fccca Change how ChangesDirs() works
Rather than scan the files in the old directory twice to detect the
deletions we now scan both directories twice and then do all the
diffing on the in-memory structure.

This is more efficient, but it also lets us diff more complex things
later that are not exact on-disk trees.
2013-09-30 17:35:01 -06:00
Alexander Larsson 7d566b4f76 RootIsShared() - Fix array out of bounds error
This happened for me on the last (empty) line, but better safe than sorry
so we make the check general.
2013-09-30 17:35:01 -06:00
Alexander Larsson fdbc2695fe devmapper: Move init layer to top rather than bottom
The init layer needs to be topmost to make sure certain files
are always there (for instance, the ubuntu:12.10 image wrongly
has /dev/shm being a symlink to /run/shm, and we need to override
that). However, previously the devmapper code implemented the
init layer by putting it in the base devmapper device, which meant
layers above it could override these files (so that ubuntu:12.10
broke).

So, instead we put the base layer in *each* images devmapper device.
This is "safe" because we still have the pristine layer data
in the layer directory. Also, it means we diff the container
against the image with the init layer applied, so it won't show
up in diffs/commits.
2013-09-30 17:35:01 -06:00
Alexander Larsson 429587779a lxc: Work around lxc-start need for private mounts
lxc-start requires / to be mounted private, otherwise the changes
it does inside the container (both mounts and unmounts) will propagate
out to the host.

We work around this by starting up lxc-start in its own namespace where
we set / to rprivate.

Unfortunately go can't really execute any code between clone and exec,
so we can't do this in a nice way. Instead we have a horrible hack that
use the unshare command, the shell and the mount command...
2013-09-30 17:35:01 -06:00
Alexander Larsson 145024c6cc Utils: Add ShellQuoteArguments 2013-09-30 17:35:01 -06:00
Alexander Larsson c138801073 Container: Inject into the mount, not the rwPath
For device-mapper setups we can't just push the file into the rwPath.
2013-09-30 17:35:01 -06:00
Alexander Larsson 0722786600 api_test: Fix PostContainersCreate
We can't look for the created file in the rwpath, because that
doesn't exist in the device-mapper world, instead look in the
RootfsPath.
2013-09-30 17:35:01 -06:00
Alexander Larsson 5f8e24f842 Runtime: Only remove device on destroy if it exists 2013-09-30 17:35:01 -06:00
Alexander Larsson 0d7ab8db03 graph test: Unmount image via image.Unmount()
This helps us track the unmount
2013-09-30 17:35:01 -06:00
Alexander Larsson ed741f7b27 deviceset: Cleanup device sets on test end
We unmount all mounts and deactivate all device mapper devices to
make sure we're left with no leftovers after the test.
2013-09-30 17:35:01 -06:00
Alexander Larsson 9e64ebb295 DeviceSet: Add UnmountDevice()
Right now this does nothing but add a new layer, but it means
that all DeviceMounts are paired with DeviceUnmounts so that we
can track (and cleanup) active mounts.
2013-09-30 17:35:01 -06:00
Alexander Larsson d951911b23 Always start tests from a clean set of loopback images
This way we don't get any issues with leftovers
2013-09-30 17:35:01 -06:00
Alexander Larsson 7fb60caa5d tests: Store the loopback images for test outside unit-tests
This directory is copied to each test prefix which is really
slow with the large loopback mounts.
2013-09-30 17:35:01 -06:00
Alexander Larsson 76a2ab6e34 Allow specifying the docker client path in _DOCKER_INIT_PATH
I currently need this to get the tests running, otherwise it will
mount the docker.test binary inside the containers, which doesn't
work due to the libdevmapper.so dependency.
2013-09-30 17:35:00 -06:00
Alexander Larsson 6094257b28 Limit the amount of prints during normal runs
This removes some Debugf() calls and chages some direct prints to
Debugf(). This means we don't get a bunch of spew when running the
tests.
2013-09-30 17:35:00 -06:00
Alexander Larsson 52294192b2 Reuse a single DeviceSetDM for all the tests
We wrap the "real" DeviceSet for each test so that we get only
a single device-mapper pool and loopback mounts, but still
separate out the IDs in the tests. This makes the test run
much faster.
2013-09-30 17:35:00 -06:00
Alexander Larsson 381ce94ef4 Add DeviceSetWrapper
This wraps an existing DeviceSet and just adds a prefix to all ids in
it. This will be useful for reusing a single DeviceSet for all the tests
(but with separate ids)
2013-09-30 17:35:00 -06:00
Alexander Larsson 99393cf3cf Delete corresponding Devices when deleting Images
If an image is deleted and there is a corresponding device
for that image we also delete the image.
2013-09-30 17:35:00 -06:00
Alexander Larsson 30890c7763 Runtime: Delete corresponding devices when deleting container 2013-09-30 17:35:00 -06:00
Alexander Larsson b0626f403b Implement container.ExportRW() on device-mapper 2013-09-30 17:34:59 -06:00
Alexander Larsson fda6ff9c27 Make TarFilter more useful
There are a few changes:
* Callers can specify if they want recursive behaviour or not
* All file listings to tar are sent on stdin, to handle long lists better
* We can pass in a list of filenames which will be created as empty
  files in the tarball

This is exactly what we want for the creation of layer tarballs given
a container fs, a set of files to add and a set of whiteout files to create.
2013-09-30 17:34:59 -06:00
Alexander Larsson b86f67126c Archive: Fix up tar commandline arguments in TarFilter()
There is no need to duplicate the compression flags for
every element in the filter.
2013-09-30 17:34:59 -06:00
Alexander Larsson 1c5dc26a7c Implement docker diff for device-mapper
To do diffing we just compare file metadata, so this relies
on things like size and mtime/ctime to catch any changes.
Its *possible* to trick this by updating a file without
changing the size and setting back the mtime/ctime, but
that seems pretty unlikely to happen in reality, and lets
us avoid comparing the actual file data.
2013-09-30 17:34:59 -06:00
Alexander Larsson 8e7cbbff50 devmapper: Base the device-mapper names on the root dir name
This means the default is "docker-*", but for tests we get separate
prefixes for each test.
2013-09-30 17:34:59 -06:00
Alexander Larsson 074f38d493 Image: Always create a .docker-id file in the devices we create
Without this there is really no way to map back from the device-mapper
devices to the actual docker image/container ids in case the json file
somehow got lost
2013-09-30 17:34:59 -06:00
Alexander Larsson a9ec1dbc9b Image: Deactivate image device when unmounting container
There is no need to keep all the device-mapper devices active, we
can just activate them on demand if needed.
2013-09-30 17:34:59 -06:00
Alexander Larsson d2ba3e2005 Image: Initial support for device-mapper mounts
This supports creating images from layers and mounting them
for running a container.

Not supported yet are:
* Creating diffs between images/containers
* Creating layers for new images from a device-mapper container
2013-09-30 17:34:59 -06:00
Alexander Larsson 8f7361279c Runtime: Add MountMethod to allow AUFS and device-mapper to coexist 2013-09-30 17:34:59 -06:00
Alexander Larsson ca2f7f955e Runtime: Add DeviceSet singleton
This adds a DeviceSet singleton to the Runtime object which will be used for
any DeviceMapper dependent code.
2013-09-30 17:34:59 -06:00
Alexander Larsson 1d36b8c7b7 Server: Pass in device-mapper DeviceSet to server
This makes docker (but not docker-init) link to libdevmapper and will
allow it to use the DeviceSet
2013-09-30 17:34:59 -06:00
Alexander Larsson e6216793d9 Add DeviceSet interface
This interface matches the device-mapper implementation (DeviceSetDM)
but is free from any dependencies. This allows core docker code
to refer to a DeviceSet without having an explicit dependency on
the devmapper package.

This is important, because the devmapper package has external
dependencies which are not wanted in the docker client app, as it
needs to run with minimal dependencies in the docker image.
2013-09-30 17:34:58 -06:00
Alexander Larsson e368c8bb01 Image: Add runtime and container id args to Mount()
We will later need the runtime to get access to the VolumeSet
singleton, and the container id to have a name for the volume
for the container
2013-09-30 17:34:58 -06:00
Alexander Larsson 167601e858 Runtime: Automatically use docker-init if it exists
In some builds the main docker binary is not statically linked,
and as such not usable in as the .dockerinit binary, for those
cases we look for a separately shipped docker-init binary and
use that instead.
2013-09-30 17:34:58 -06:00
Alexander Larsson b8dc7b5f1a Add a separate docker-init binary
This may be used for the .dockerinit case if the main binary is not
statically linked.
2013-09-30 17:34:58 -06:00
Alexander Larsson 7fb3bfed03 devmapper: Add simple tool to test the DeviceSet commands 2013-09-30 17:34:58 -06:00
Alexander Larsson 374a5e9913 devmapper: Add DeviceSet device-mapper helper
This is a module that uses the device-mapper create CoW snapshots
You instantiate a DeviceSetDM object on a specified root (/var/lib/docker),
and it will create a subdirectory there called "loopback". It will
contain two sparse files which are loopback mounted into
a thin-pool device-mapper device called "docker-pool".

We then create a base snapshot in the pool with an empty filesystem
which can be used as a base for docker snapshots. It also keeps track
of the mapping between docker image ids and the snapshots in the pool.

Typical use of is something like (without error checking):

devices = NewDeviceSetDM("/var/lib/docker")
devices.AddDevice(imageId, "") // "" is the base image id
devices.MountDevice(imageId, "/mnt/image")
 ... extract base image to /mnt/image
devices.AddDevice(containerId, imageId)
devices.MountDevice(containerId, "/mnt/container")
... start container at /mnt/container
2013-09-30 17:34:58 -06:00
Alexander Larsson 459bac7127 Add libdevmapper wrapper 2013-09-30 17:34:58 -06:00
Solomon Hykes 23015fa14d Merge pull request #1994 from metalivedev/1993-legalcontext
Fix #1993: add explanation for export restrictions
2013-09-30 16:33:46 -07:00
Thermionix fb46d911c2 Update archlinux.rst 2013-10-01 09:33:12 +10:00
Tianon Gravi 85b776995c Merge pull request #2051 from tianon/hack-dockerfile-refactor
Add cleanup/refactor portion of #2010 for hack and Dockerfile updates
2013-09-30 16:29:32 -07:00
Thatcher fa44555fb4 Merge pull request #2035 from dhrp/style-revamp
Changes to a new style for the docs. Includes version switcher.
2013-09-30 15:51:43 -07:00
Andy Rothfusz 3e7c50e8a1 Merge pull request #2033 from metalivedev/1969-cherrypick-fixcommitformat
Fix #1969 formatting, add information about multiline json
2013-09-30 14:55:11 -07:00
Tianon Gravi ccefe47897 Add cleanup/refactor portion of #2010 for hack and Dockerfile updates 2013-09-30 13:57:30 -06:00
Tianon Gravi ff85031980 Merge pull request #2039 from tianon/mkimage-centos
Add contrib/mkimage-centos.sh back (from #1621), and associated documentation link
2013-09-30 10:51:06 -07:00
Guillaume J. Charmes 017ecefd66 Merge pull request #2046 from dotcloud/2030-dockercfg_panic_err-fix
- Runtime: fix panic with wrong dockercfg file
2013-09-30 10:02:12 -07:00
Thermionix 88f710f0e7 Update archlinux.rst
The /etc/sysctl.conf file is deprecated
https://www.archlinux.org/news/deprecation-of-etcsysctlconf/
2013-09-30 22:44:09 +10:00
Victor Vieux 6496059154 fix panic with wrong dockercfg file 2013-09-30 11:07:32 +00:00
Victor Vieux bcce3cbdd1 Merge pull request #1995 from dotcloud/fix_attach_2
Fix the attach behavior with -i
2013-09-30 03:29:19 -07:00
Victor Vieux bbf644ed62 Merge pull request #2025 from dotcloud/2020_add_dockercfg_doc
add .dockercfg doc
2013-09-30 03:21:46 -07:00
Tianon Gravi d89ce09a76 Add contrib/mkimage-centos.sh back (from #1621), and associated documentation link 2013-09-28 07:54:34 -06:00
Thatcher Peskens e3e041b6bf Changes to a new style for the docs. Includes version switcher.
* added link to edit on GitHub
* Changed image source on homepage
* Made some changes to the structure, added the ability to have l3 navigation. Added warning, note and other styles.
* Fixed an image link, removed the .. :content: links because they were quicky and didn't look good, added pagelinks to current page of other versions.
* Moved the remote client api's to their own doc
2013-09-27 19:54:52 -07:00
Andy Rothfusz 0a35b1fb36 Added more context. 2013-09-27 19:07:12 -07:00
Andy Rothfusz 3894add8a9 Merge pull request #2034 from metalivedev/1969-cherrypick-fixcommitformat
Fix #1969 formatting, add information about multiline json
2013-09-27 18:19:55 -07:00
Andy Rothfusz 74d54b9b2e Fix #1969 formatting, add information about multiline json 2013-09-27 18:16:00 -07:00
Michael Crosby 31fd11860b Merge pull request #2032 from dotcloud/move-rm-to-client
Move run -rm to the cli only
2013-09-27 17:19:01 -07:00
Daniel Mizyrycki b081a740b3 Merge pull request #2006 from jo-m/master
Enable SSH Agent forwarding in Vagrant VM
2013-09-27 12:07:44 -07:00
Michael Crosby db869ecce5 Merge pull request #1589 from unclejack/479-add_rm_support_to_docker_run
Add -rm to docker run for removing a container on exit
2013-09-27 11:45:32 -07:00
Guillaume J. Charmes 537149829a Fix the attach behavior with -i 2013-09-27 11:10:55 -07:00
Andy Rothfusz ba10e28927 Merge pull request #2009 from kyleconroy/master
Improve registry and index REST API documentation
2013-09-27 10:56:21 -07:00
Victor Vieux f4855a7cf0 add .dockercfg doc 2013-09-27 18:19:17 +02:00
unclejack 22e7e107ad automatically remove container via -rm
add AutoRemove to HostConfig
add -rm flag to docker run
add TestRunAutoRemove to test -rm
docs: add -rm to commandline/command/run
add hostConfig to container monitor
make monitor destroy the container via -rm

This adds support for automatically removing a container after it
exits. The removal of the container is handled on the server side.
2013-09-27 17:43:12 +03:00
Colin Dunklau edd90d46c7 Clearly point at detailed docs 2013-09-27 08:32:55 -05:00
Victor Vieux 514886c73d Merge pull request #2023 from alexlarsson/old_kernel
Image: Fix time setting for old kernels
2013-09-27 05:25:13 -07:00
Guillaume J. Charmes f435970695 Merge pull request #1842 from dotcloud/split_stdout_stderr
* Runtime: Split stdout stderr
2013-09-26 18:05:24 -07:00
Guillaume J. Charmes cb18a6e1b9 Update docs + fix endian issue 2013-09-26 17:36:21 -07:00
Alexander Larsson 75e958bf48 Image: Fix time setting for old kernels
This is a better fix for futimes() on kernels not supporting O_PATH.
The previous fix broke when copying a device, as it tried to open it
and got and error.
2013-09-26 23:59:37 +02:00
Kyle Conroy ce05083d4b Fix copypasta errors 2013-09-26 14:57:02 -07:00
Michael Crosby 723de87681 Move run -rm to the cli only 2013-09-26 14:52:37 -07:00
David Sissitka c22e377a6d Used tabs for alignment when I should've used spaces. Fixed. 2013-09-26 13:56:59 -07:00
Colin Dunklau 3f0d0075f8 Hint for Remote API doc details in header links 2013-09-26 15:30:26 -05:00
David Sissitka f8c9f11f06 Configured FPM to make /etc/init/docker.conf a config file. 2013-09-26 12:52:43 -07:00
Alexander Larsson 80319add55 lxc: Allow set_file_cap capability in container
This means you're able to set the bits for capabilities on files
inside the container. This is needed for e.g. many fedora packages
as they use finegrained capabilities rather than setuid binaries.

This is safe as we're not adding capabilities really, since the
container is already allowed to create setuid binaries. Setuid
binaries are strictly more powerful that any capabilities (as root implies
all capabilities).

This doesn't mean the container can *gain* capabilities that it
doesn't already have though. The actual set of caps are strictly
decreasing.
2013-09-26 21:41:45 +02:00
Victor Vieux ebfa24acb0 go fmt and aufs support removed 2013-09-26 15:40:13 +00:00
Victor Vieux 5e1d540209 Revert "add a -mount-method flag"
This reverts commit e52d756f40c9ccf8b37ca496cb72be057c909ed7.
2013-09-26 15:14:03 +00:00
Victor Vieux c1e25d7273 add a -mount-method flag 2013-09-26 15:10:01 +00:00
Alexander Larsson d263aa6ca9 RootIsShared: Fix root detection
Column 4 is the mount position, column 3 will not always be
"/" for the root. On one of my system its "/root".
2013-09-26 15:09:33 +00:00
Alexander Larsson 03320f0d1c Tests: Clean up any old devmapper leftovers before starting tests 2013-09-26 15:09:33 +00:00
Alexander Larsson 6c7ae06435 Image.Changes: Deactivate image device after unmounting it
There is no need to keep the image device around if we were the
onces creating the device.
2013-09-26 15:09:33 +00:00
Alexander Larsson 395bce4c41 Add DeviceSet.HasActivatedDevice()
This lets you see if a device has been activated
2013-09-26 15:09:33 +00:00
Alexander Larsson 41399ac005 image: Unmount before removing device in error paths
The device remove fails unless we unmount first
2013-09-26 15:09:33 +00:00
Alexander Larsson 67788723c9 runtime test: Ensure all containers are unmounted at nuke()
Otherwise we may leave around e.g. devmapper mounts
2013-09-26 15:09:33 +00:00
Alexander Larsson f99f39abaa ShellQuoteArguments: Fix quoting
This accidentally used two quotes to start/end each quoted string.
2013-09-26 15:09:33 +00:00
Alexander Larsson 009d0f9d81 Image: unmount device before removing it on failures
If we don't do this the remove will fail due to EBUSY
2013-09-26 15:09:32 +00:00
Alexander Larsson ed65815613 image: Handle systems that don't support O_PATH when updating timestamp
Older kernel can't handle O_PATH in open() so this will
fail on dirs and symlinks. For dirs wa can fallback to
the normal Utimes, but for symlinks there is not much to do
but ignore their timestamps.
2013-09-26 15:09:32 +00:00
Alexander Larsson cc28829429 devmapper: Fix loopback mount code
Typo in the loop-control code made it always fall back to the
old method of opening loopback devices.
2013-09-26 15:09:32 +00:00
Alexander Larsson 062a2b32e9 applyLayer() use btrfs reflinks if availible
We use the new file copy helper which uses btrfs reflinks if availible.
2013-09-26 15:09:32 +00:00
Alexander Larsson cda8754013 Add CopyFile that can use btrfs reflinks if availible 2013-09-26 15:09:32 +00:00
Alexander Larsson 5415804c9d Remove accidental commit that enabled MountMethodFilesystem 2013-09-26 15:09:32 +00:00
Alexander Larsson adae684987 Add trivial copy-based CoW backend
This creates a container by copying the corresponding files
from the layers into the containers. This is not gonna be very useful
on a developer setup, as there is no copy-on-write or general diskspace
sharing. It also makes container instantiation slower.

However, it may be useful in deployment where we don't always have a lot
of containers running (long-running daemons) and where we don't
do a lot of docker commits.
2013-09-26 15:09:32 +00:00
Alexander Larsson ad0a6a03e3 Add Changes.ChangesLayers()
This calculates the difference between a set of layers and a
directory tree.
2013-09-26 15:09:32 +00:00
Alexander Larsson 36603e68e3 Changes: Better metadata comparison
Change the comparison to better handle files that are copied during
container creation but not actually changed:

* Inode - this will change during a copy
* ctime - this will change during a copy (as we can't set it back)
* blocksize - this will change for sparse files during copy
* size for directories - this can change anytime but doesn't
  necessarily reflect an actual contents change
* Compare mtimes at microsecond precision (as this is what utimes has)
2013-09-26 15:09:32 +00:00
Alexander Larsson 99c7d129f4 Image.applyLayer: Be better at creating identical files
There are some changes here that make the file metadata better match
the layer files:

* Set the mode of the file after the chown, as otherwise the per-group/uid
  specific flags and e.g. sticky bit is lost
* Use lchown instead of chown
* Delay mtime updates to after all other changes so that later file
  creation doesn't change the mtime for the parent directory
* Use Futimes in combination with O_PATH|O_NOFOLLOW to set mtime on symlinks
2013-09-26 15:09:32 +00:00
Alexander Larsson 02b5f1369c Change how ChangesDirs() works
Rather than scan the files in the old directory twice to detect the
deletions we now scan both directories twice and then do all the
diffing on the in-memory structure.

This is more efficient, but it also lets us diff more complex things
later that are not exact on-disk trees.
2013-09-26 15:09:32 +00:00
Alexander Larsson d478a4bb54 RootIsShared() - Fix array out of bounds error
This happened for me on the last (empty) line, but better safe than sorry
so we make the check general.
2013-09-26 15:09:32 +00:00
Alexander Larsson c199ed228b devmapper: Move init layer to top rather than bottom
The init layer needs to be topmost to make sure certain files
are always there (for instance, the ubuntu:12.10 image wrongly
has /dev/shm being a symlink to /run/shm, and we need to override
that). However, previously the devmapper code implemented the
init layer by putting it in the base devmapper device, which meant
layers above it could override these files (so that ubuntu:12.10
broke).

So, instead we put the base layer in *each* images devmapper device.
This is "safe" because we still have the pristine layer data
in the layer directory. Also, it means we diff the container
against the image with the init layer applied, so it won't show
up in diffs/commits.
2013-09-26 15:09:32 +00:00
Alexander Larsson e40f5c7cb9 lxc: Work around lxc-start need for private mounts
lxc-start requires / to be mounted private, otherwise the changes
it does inside the container (both mounts and unmounts) will propagate
out to the host.

We work around this by starting up lxc-start in its own namespace where
we set / to rprivate.

Unfortunately go can't really execute any code between clone and exec,
so we can't do this in a nice way. Instead we have a horrible hack that
use the unshare command, the shell and the mount command...
2013-09-26 15:09:32 +00:00
Alexander Larsson d80be57c15 Utils: Add ShellQuoteArguments 2013-09-26 15:09:32 +00:00
Alexander Larsson 20bac716b5 Container: Inject into the mount, not the rwPath
For device-mapper setups we can't just push the file into the rwPath.
2013-09-26 15:09:32 +00:00
Alexander Larsson 2566e2604c api_test: Fix PostContainersCreate
We can't look for the created file in the rwpath, because that
doesn't exist in the device-mapper world, instead look in the
RootfsPath.
2013-09-26 15:09:32 +00:00
Alexander Larsson e1c418cac3 Runtime: Only remove device on destroy if it exists 2013-09-26 15:09:32 +00:00
Alexander Larsson 3343b3f8f8 graph test: Unmount image via image.Unmount()
This helps us track the unmount
2013-09-26 15:09:32 +00:00
Alexander Larsson c6e8813c97 deviceset: Cleanup device sets on test end
We unmount all mounts and deactivate all device mapper devices to
make sure we're left with no leftovers after the test.
2013-09-26 15:09:32 +00:00
Alexander Larsson 251a7ed437 DeviceSet: Add UnmountDevice()
Right now this does nothing but add a new layer, but it means
that all DeviceMounts are paired with DeviceUnmounts so that we
can track (and cleanup) active mounts.
2013-09-26 15:09:31 +00:00
Alexander Larsson 261b0b01df Always start tests from a clean set of loopback images
This way we don't get any issues with leftovers
2013-09-26 15:09:31 +00:00
Alexander Larsson a7fd1fce5d tests: Store the loopback images for test outside unit-tests
This directory is copied to each test prefix which is really
slow with the large loopback mounts.
2013-09-26 15:09:31 +00:00
Alexander Larsson 6938a36c69 Allow specifying the docker client path in _DOCKER_INIT_PATH
I currently need this to get the tests running, otherwise it will
mount the docker.test binary inside the containers, which doesn't
work due to the libdevmapper.so dependency.
2013-09-26 15:09:31 +00:00
Alexander Larsson bc7fa7b957 Limit the amount of prints during normal runs
This removes some Debugf() calls and chages some direct prints to
Debugf(). This means we don't get a bunch of spew when running the
tests.
2013-09-26 15:09:31 +00:00
Alexander Larsson d47c18c5fb Reuse a single DeviceSetDM for all the tests
We wrap the "real" DeviceSet for each test so that we get only
a single device-mapper pool and loopback mounts, but still
separate out the IDs in the tests. This makes the test run
much faster.
2013-09-26 15:09:31 +00:00
Alexander Larsson 0e686fa2f4 Add DeviceSetWrapper
This wraps an existing DeviceSet and just adds a prefix to all ids in
it. This will be useful for reusing a single DeviceSet for all the tests
(but with separate ids)
2013-09-26 15:09:31 +00:00
Alexander Larsson 3f3f5f0bba Delete corresponding Devices when deleting Images
If an image is deleted and there is a corresponding device
for that image we also delete the image.
2013-09-26 15:09:31 +00:00
Alexander Larsson 19ba0b851b Runtime: Delete corresponding devices when deleting container 2013-09-26 15:08:55 +00:00
Alexander Larsson 94fa3c7bb5 Implement container.ExportRW() on device-mapper 2013-09-26 15:08:55 +00:00
Alexander Larsson 223280f319 Make TarFilter more useful
There are a few changes:
* Callers can specify if they want recursive behaviour or not
* All file listings to tar are sent on stdin, to handle long lists better
* We can pass in a list of filenames which will be created as empty
  files in the tarball

This is exactly what we want for the creation of layer tarballs given
a container fs, a set of files to add and a set of whiteout files to create.
2013-09-26 15:08:55 +00:00
Alexander Larsson 8f23945f7f Archive: Fix up tar commandline arguments in TarFilter()
There is no need to duplicate the compression flags for
every element in the filter.
2013-09-26 15:08:55 +00:00
Alexander Larsson 8e8ef7cb5b Implement docker diff for device-mapper
To do diffing we just compare file metadata, so this relies
on things like size and mtime/ctime to catch any changes.
Its *possible* to trick this by updating a file without
changing the size and setting back the mtime/ctime, but
that seems pretty unlikely to happen in reality, and lets
us avoid comparing the actual file data.
2013-09-26 15:08:55 +00:00
Alexander Larsson 8f343ea65a devmapper: Base the device-mapper names on the root dir name
This means the default is "docker-*", but for tests we get separate
prefixes for each test.
2013-09-26 15:08:55 +00:00
Alexander Larsson b125f2334c Image: Always create a .docker-id file in the devices we create
Without this there is really no way to map back from the device-mapper
devices to the actual docker image/container ids in case the json file
somehow got lost
2013-09-26 15:08:55 +00:00
Alexander Larsson a89a51128e Image: Deactivate image device when unmounting container
There is no need to keep all the device-mapper devices active, we
can just activate them on demand if needed.
2013-09-26 15:08:54 +00:00
Alexander Larsson fcd41fe51a Image: Initial support for device-mapper mounts
This supports creating images from layers and mounting them
for running a container.

Not supported yet are:
* Creating diffs between images/containers
* Creating layers for new images from a device-mapper container
2013-09-26 15:08:54 +00:00
Alexander Larsson 53851474c0 Runtime: Add MountMethod to allow AUFS and device-mapper to coexist 2013-09-26 15:08:54 +00:00
Alexander Larsson f317a6b6fe Runtime: Add DeviceSet singleton
This adds a DeviceSet singleton to the Runtime object which will be used for
any DeviceMapper dependent code.
2013-09-26 15:08:54 +00:00
Alexander Larsson 87e248f524 Server: Pass in device-mapper DeviceSet to server
This makes docker (but not docker-init) link to libdevmapper and will
allow it to use the DeviceSet
2013-09-26 15:08:54 +00:00
Alexander Larsson ac194fc696 Add DeviceSet interface
This interface matches the device-mapper implementation (DeviceSetDM)
but is free from any dependencies. This allows core docker code
to refer to a DeviceSet without having an explicit dependency on
the devmapper package.

This is important, because the devmapper package has external
dependencies which are not wanted in the docker client app, as it
needs to run with minimal dependencies in the docker image.
2013-09-26 15:08:54 +00:00
Alexander Larsson 8637ba710e Image: Add runtime and container id args to Mount()
We will later need the runtime to get access to the VolumeSet
singleton, and the container id to have a name for the volume
for the container
2013-09-26 15:08:54 +00:00
Alexander Larsson 0f5ccf934e Runtime: Automatically use docker-init if it exists
In some builds the main docker binary is not statically linked,
and as such not usable in as the .dockerinit binary, for those
cases we look for a separately shipped docker-init binary and
use that instead.
2013-09-26 15:08:54 +00:00
Alexander Larsson 250bc3f615 Add a separate docker-init binary
This may be used for the .dockerinit case if the main binary is not
statically linked.
2013-09-26 15:08:54 +00:00
Alexander Larsson 2b1dc8a8a3 devmapper: Add simple tool to test the DeviceSet commands 2013-09-26 15:08:54 +00:00
Alexander Larsson 0b12702c0c devmapper: Add DeviceSet device-mapper helper
This is a module that uses the device-mapper create CoW snapshots
You instantiate a DeviceSetDM object on a specified root (/var/lib/docker),
and it will create a subdirectory there called "loopback". It will
contain two sparse files which are loopback mounted into
a thin-pool device-mapper device called "docker-pool".

We then create a base snapshot in the pool with an empty filesystem
which can be used as a base for docker snapshots. It also keeps track
of the mapping between docker image ids and the snapshots in the pool.

Typical use of is something like (without error checking):

devices = NewDeviceSetDM("/var/lib/docker")
devices.AddDevice(imageId, "") // "" is the base image id
devices.MountDevice(imageId, "/mnt/image")
 ... extract base image to /mnt/image
devices.AddDevice(containerId, imageId)
devices.MountDevice(containerId, "/mnt/container")
... start container at /mnt/container
2013-09-26 15:08:54 +00:00
Alexander Larsson 739af0a17f Add libdevmapper wrapper 2013-09-26 15:08:54 +00:00
Kyle Conroy 818ec10da3 Fix Authorization headers 2013-09-26 01:19:49 -07:00
Kyle Conroy 34e28ccc88 Remove smart quotes. Add the X-Docker-Token header
Also fix the /layer endpoint, which had incorrect information
2013-09-26 01:15:36 -07:00
Kyle Conroy 792403f2dc Add the X-Docker-Registry header and /v1/_ping endpoint 2013-09-26 00:16:15 -07:00
Jonathan Mueller 8f5c33dc1f Enable SSH Agent forwarding in Vagrant VM, so one is able to clone repos from private git repos etc. 2013-09-25 22:57:04 +02:00
Andy Rothfusz 06c1f000e8 Merge pull request #2000 from tianon/deprecated-docker-latest-tgz
Replace deprecated upgrading reference to docker-latest.tgz, which hasn't been updated since 0.5.3
2013-09-25 13:47:48 -07:00
Andy Rothfusz 00b3acb8ab Merge pull request #2001 from tianon/gentoo-tree
Update Gentoo installation documentation now that we're in the portage tree proper
2013-09-25 13:45:51 -07:00
Victor Vieux 420ba9c85a Merge pull request #2004 from kencochrane/master
fix the error message so it is the same as the regex issue #1999
2013-09-25 09:46:15 -07:00
Ken Cochrane 0f829bf5cf fix the error message so it is the same as the regex issue #1999 2013-09-25 11:33:09 -04:00
Victor Vieux 1363de0934 Merge pull request #1989 from alexlarsson/setsid
Container: Always create a new session for the container
2013-09-25 07:40:51 -07:00
Tianon Gravi d06116d2e8 Update Gentoo installation documentation now that we're in the portage tree proper
We're officially a first-class Gentoo citizen now, which is very exciting.  Many thanks to @gregkh for helping us get here.

I started just adapting sections of language in this document, and realized several bits needed to just be rewritten entirely to be more clear.
2013-09-24 23:26:36 -06:00
Tianon Gravi 595210a370 Replace deprecated upgrading reference to docker-latest.tgz, which hasn't been updated since 0.5.3 2013-09-24 21:25:45 -06:00
Michael Crosby c9b916b293 Update VERSION to 0.6.3-dev 2013-09-24 19:54:13 -07:00
Michael Crosby 1e6370fd4b Merge branch 'release' 2013-09-24 19:54:06 -07:00
Solomon Hykes a59a66528b Merge pull request #1968 from tianon/hack-build-instructions
* Hack: Add several of the small make.sh fixes from #1920, and make the output more consistent and contributor-friendly
2013-09-24 17:38:39 -07:00
Andy Rothfusz b048e9dffc Merge pull request #1983 from blissdev/patch-1
various command fixes in postgres example
2013-09-24 14:03:48 -07:00
blissdev c000e6a7fc revert removal of slash betwixt user/repo 2013-09-24 15:51:21 -05:00
Tianon Gravi aa3de0b849 Add several of the small make.sh fixes from #1920, and make the output more consistent and contributor-friendly, since release instructions already exist in release.sh 2013-09-24 14:36:20 -06:00
Michael Crosby 648d759517 Merge pull request #1972 from dotcloud/bump_0.6.3
Bump to version v0.6.3
2013-09-24 11:20:27 -07:00
Andy Rothfusz 5c190fa926 Fix #1993: add explanation for export restrictions 2013-09-24 11:04:08 -07:00
Solomon Hykes 03fe5632d0 Merge pull request #1970 from dotcloud/cleanup-hack
Cleanup and reorganize docs and tooling for contributors and maintainers
2013-09-24 10:38:21 -07:00
Dan Buch edde4f55e0 Adding more tests around auth.ResolveAuthConfig
mostly because I've been failing at getting docker `0.6.2` working with
docker-registry `0.6.0` with regard to login and push.  I suspect there
may be some mismatched expectations between `auth.ResolveAuthConfig` and
`registry.ResolveRepositoryName`, but I haven't done enough research or
experimentation to think it's anything more than user error.  More tests
are good, no?
2013-09-24 12:36:50 -04:00
Victor Vieux 7447867edd Merge pull request #1982 from modcloth-labs/spelling-fix-for-the-word-protocol
Minor spelling correction of protocoll -> protocol
2013-09-24 07:40:21 -07:00
Alexander Larsson c1c74cb0b1 Container: Always create a new session for the container
We never want the container to be in the same process group as the
daemon, as then the container will receive signals sent to the
process group of the container.
2013-09-24 14:57:29 +02:00
blissdev 17b7194d91 use su instead of sudo 2013-09-24 02:25:16 -05:00
Jordan Arentsen 15ad2915b9 various command fixes
Indicating the repository and tag should be separated by a space and not a '/'. Also fixed a quote typo.
2013-09-24 02:12:24 -05:00
Tianon Gravi d6887b769c Merge pull request #1883 from tianon/mkimage-debian
Several small tweaks/fixes for contrib/mkimage-debian.sh
2013-09-23 22:44:16 -07:00
Tianon Gravi 10362870db Add a few tweaks and fixes to contrib/mkimage-debian.sh
Add simple workaround for #1755 to contrib/mkimage-debian.sh

Add simple echo patch in contrib/mkimage-debian.sh to prevent init scripts from running during apt-get installs/updates

Add `apt-get clean` to mkimage-debian.sh for slightly smaller images

Add more small apt tweaks to mkimage-debian.sh thanks to @jpetazzo and @spahl
2013-09-23 22:39:57 -06:00
Dan Buch a7db125480 Minor spelling correction of protocoll -> protocol 2013-09-23 23:14:42 -04:00
Solomon Hykes f6c64827c8 Hack: correct typo in release checklist 2013-09-23 18:43:08 -07:00
Andy Rothfusz 30b759ffa9 Merge pull request #1973 from metalivedev/1969-formatfix
Fix #1969 formatting, add information about multiline json
2013-09-23 13:17:55 -07:00
Michael Crosby 35ca35ffb6 Merge pull request #1975 from tianon/patch-1
Add @tianon to hack/MAINTAINERS
2013-09-23 12:21:36 -07:00
Tianon Gravi a4067b1b44 Add @tianon to hack/MAINTAINERS 2013-09-23 12:39:14 -06:00
Michael Crosby b0a49a30c7 Bump to version v0.6.3 2013-09-23 11:29:11 -07:00
Andy Rothfusz 6097644e4b Fix #1969 formatting, add information about multiline json 2013-09-23 11:29:08 -07:00
Solomon Hykes fa3837abf1 Hack: update README 2013-09-23 11:26:05 -07:00
Solomon Hykes baff72bc82 Update maintainer's manual: every change should be done in a pull request. 2013-09-23 11:26:05 -07:00
Solomon Hykes 99377de7d2 Hack: update release checklist and reference it in REAMDE 2013-09-23 11:26:04 -07:00
Solomon Hykes 0ef5bcb17d hack/MAINTAINERS.md: a maintainer's manual. 2013-09-23 11:26:04 -07:00
Solomon Hykes fd1c43f0e0 Hack: remove deprecated files 2013-09-23 11:26:03 -07:00
Michael Crosby dc06496dc8 Merge pull request #1967 from dotcloud/vendor-update-tar
Update tar dependency to newest version
2013-09-23 10:44:42 -07:00
Michael Crosby cfbe76e559 Update tar dependency to newest version 2013-09-23 09:59:04 -07:00
Victor Vieux 2fafe1efce Merge pull request #1948 from dotcloud/fix_attach
Fix attach issue
2013-09-23 02:15:51 -07:00
Daniel Mizyrycki 8240e37b87 Merge pull request #1820 from dotcloud/1647-api-group
packaging, issue #1647: Add docker groupname on the package release
2013-09-22 14:21:26 -07:00
Michael Crosby 23cf3c7a33 Merge pull request #1934 from dotcloud/host-permissions
Only copy files and change permissions with non bindmount
2013-09-22 09:40:52 -07:00
Tianon Gravi e37bb50628 Add proper bash completion for "docker push" 2013-09-20 21:22:51 -06:00
Andy Rothfusz 2819cfb3f3 Merge pull request #1954 from metalivedev/1901-cherrypick-builddocker
1901 1929 1932 cherrypick to release and docs
2013-09-20 18:13:11 -07:00
Andy Rothfusz a479f7659d Merge pull request #1929 from tianon/gentoo-docs
Simplified Gentoo install instructions now that our overlay is in the official layman repositories.xml list
2013-09-20 18:06:27 -07:00
Andy Rothfusz b02a591f57 Merge pull request #1932 from jcassee/patch-1
Download Ubuntu 13.04 repository key over HTTPS
2013-09-20 18:02:40 -07:00
Andy Rothfusz c654075654 Merge pull request #1901 from jalateras/update-contributring-docs
Fix #1664
2013-09-20 17:55:15 -07:00
Andy Rothfusz 5a3dcbb3f6 Merge pull request #1952 from metalivedev/1909-cherrypick
Fix minor typo
2013-09-20 16:56:07 -07:00
Nick Stinemates cce6f00c0c Fix minor typo
Changed  to
2013-09-20 16:31:57 -07:00
Michael Crosby 4db64111bd Merge pull request #1949 from dotcloud/1895-registry-regex
Modify repository name regex to match index
2013-09-20 14:03:50 -07:00
Guillaume J. Charmes e97364ecd7 Improve detach unit tests 2013-09-20 13:36:19 -07:00
Guillaume J. Charmes 2bd089dadb Fix attach issue 2013-09-20 11:31:00 -07:00
Victor Vieux 5bd0437eed abord build if mergeConfig returns an error and fix duplicate error message 2013-09-20 12:46:24 +00:00
Victor Vieux a81393787f Merge pull request #1889 from dsissitka/fixhttpimport
Fixed HTTP imports.
2013-09-20 03:06:04 -07:00
Michael Crosby b45e280ee8 Only copy files and change permissions with non bindmount 2013-09-19 20:35:05 -07:00
Michael Crosby 5867f9e761 Modify repository name regex to match index 2013-09-19 20:25:00 -07:00
Andy Rothfusz 6132f378e0 Merge pull request #1901 from jalateras/update-contributring-docs
Fix #1664
2013-09-19 18:00:23 -07:00
Jim Alateras 3cf4b2c7c1 Updated the section about extracting the binary 2013-09-20 10:00:30 +10:00
Jim Alateras d70cbbf1fc Updated the section about extracting the binary 2013-09-20 09:58:12 +10:00
Jim Alateras b7e7104e92 Updated the section about extracting the binary 2013-09-20 09:49:20 +10:00
Andy Rothfusz 7e60a6b1ea Merge pull request #1932 from jcassee/patch-1
Download Ubuntu 13.04 repository key over HTTPS
2013-09-19 13:41:51 -07:00
Andy Rothfusz 45979a7ef7 Merge pull request #1929 from tianon/gentoo-docs
Simplified Gentoo install instructions now that our overlay is in the official layman repositories.xml list
2013-09-19 13:41:29 -07:00
Joost Cassee 5c9213258a Download Ubuntu 13.04 repository key over HTTPS 2013-09-19 21:14:39 +02:00
Guillaume J. Charmes 68074fce68 Merge pull request #1886 from dotcloud/multi-volumes-from
* Runtime: Allow multiple volumes-from
2013-09-19 12:01:12 -07:00
Andy Rothfusz c42056b969 Merge pull request #1914 from tianon/base-repository-is-deprecated
Removing the deprecated `base` repository from more docs
2013-09-19 11:04:11 -07:00
Tianon Gravi 341addeccd Simplify install instructions now that our overlay is in the official repositories.xml list, and add note about hacky #1422 workaround 2013-09-19 11:49:43 -06:00
Tianon Gravi 47904290a5 Remove many remaining docs references to the deprecated base repository and several other minor doc cleanups 2013-09-19 10:27:08 -06:00
Solomon Hykes a18c26392f Docs: remove reference to deprecated 'base' image 2013-09-19 10:25:30 -06:00
Andy Rothfusz 77ad95d372 Merge pull request #1913 from metalivedev/1654-registryexamples
Fix #1654 Improve the introduction to repositories flow.
2013-09-18 17:53:13 -07:00
Guillaume J. Charmes fee61895f2 Update VERSION 2013-09-18 12:06:29 -07:00
Guillaume J. Charmes f6a78f89ba Merge remote-tracking branch 'origin/release' 2013-09-18 12:06:10 -07:00
Daniel Mizyrycki 081543c49a Merge pull request #1908 from dotcloud/bump_v0.6.2
Bump v0.6.2
2013-09-18 11:21:51 -07:00
Jim Alateras 4054f31471 Updated the dev environment document 2013-09-18 14:18:05 +10:00
Jim Alateras 76a07371c5 Further updates to the dev environment document 2013-09-18 14:18:05 +10:00
Jim Alateras 5d364fda3c Further updates to the dev environment document 2013-09-18 14:18:05 +10:00
Jim Alateras 28311f61be Update the devenvironment document 2013-09-18 14:18:05 +10:00
Jim Alateras 70b731735c Updated the dev environment document 2013-09-18 12:41:12 +10:00
Andy Rothfusz 67453d6b48 Fix #1654 Improve the introduction to repositories flow. 2013-09-17 19:01:11 -07:00
Andy Rothfusz c14450ae5c Merge pull request #1909 from dotcloud/fix-typo-docs
Fix minor typo
2013-09-17 18:25:59 -07:00
Nick Stinemates 593566438d Fix minor typo
Changed  to
2013-09-17 18:49:47 +00:00
Solomon Hykes 85f3ec88a6 Merge pull request #1893 from dotcloud/add-tianon-maintainer
Add Tianon to contrib/ maintainers
2013-09-17 11:00:48 -07:00
Jim Alateras 5797e7e34e Further updates to the dev environment document 2013-09-17 21:05:55 +10:00
Jim Alateras 089a60c2cf Further updates to the dev environment document 2013-09-17 21:02:57 +10:00
Jim Alateras a99a8386fd Update the devenvironment document 2013-09-17 19:29:13 +10:00
Daniel Mizyrycki dfd0deefbb packaging, issue #1647: Add docker groupname on the package release 2013-09-16 23:00:54 -07:00
Nick Stinemates 9946981c61 Add Tianon to contrib/ maintainers
He's awesome and always contributing to this area.
2013-09-16 04:50:53 +00:00
David Sissitka c6b4076125 Fixed HTTP imports. 2013-09-15 18:40:29 -07:00
Michael Crosby b79bd4e864 Allow multiple volumes-from 2013-09-14 20:09:15 +00:00
Guillaume J. Charmes 082d142024 Add documentation 2013-09-11 15:41:44 -07:00
Guillaume J. Charmes e854b7b2e6 Make StdCopy works with huge amount of data 2013-09-11 14:49:33 -07:00
Guillaume J. Charmes 289350e633 Add stderr unit test 2013-09-11 14:48:22 -07:00
Guillaume J. Charmes 8ae5348a51 Split stdout stderr for non-tty commands 2013-09-11 14:48:22 -07:00
Dmitry Demeshchuk e5239b9859 Improve network performance for VirtualBox
Without those lines, VitrualBox machines are being very slow with all network operations (tested only in OS X Lion, but they are supposed to work everywhere). See https://github.com/mitchellh/vagrant/issues/1807
2013-09-05 21:05:23 -07:00
261 changed files with 15930 additions and 11666 deletions
+12
View File
@@ -26,3 +26,15 @@ Roberto Hashioka <roberto_hashioka@hotmail.com>
Konstantin Pelykh <kpelykh@zettaset.com>
David Sissitka <me@dsissitka.com>
Nolan Darilek <nolan@thewordnerd.info>
<mastahyeti@gmail.com> <mastahyeti@users.noreply.github.com>
Benoit Chesneau <bchesneau@gmail.com>
Jordan Arentsen <blissdev@gmail.com>
Daniel Garcia <daniel@danielgarcia.info>
Miguel Angel Fernández <elmendalerenda@gmail.com>
Bhiraj Butala <abhiraj.butala@gmail.com>
Faiz Khan <faizkhan00@gmail.com>
Victor Lyuboslavsky <victor@victoreda.com>
Jean-Baptiste Barth <jeanbaptiste.barth@gmail.com>
Matthew Mueller <mattmuelle@gmail.com>
<mosoni@ebay.com> <mohitsoni1989@gmail.com>
Shih-Yuan Lee <fourdollars@gmail.com>
+67 -1
View File
@@ -5,64 +5,98 @@
#
Al Tobey <al@ooyala.com>
Alex Gaynor <alex.gaynor@gmail.com>
Alexander Larsson <alexl@redhat.com>
Alexey Shamrin <shamrin@gmail.com>
Andrea Luzzardi <aluzzardi@gmail.com>
Andreas Savvides <andreas@editd.com>
Andreas Tiefenthaler <at@an-ti.eu>
Andrew Macgregor <andrew.macgregor@agworld.com.au>
Andrew Munsell <andrew@wizardapps.net>
Andrews Medina <andrewsmedina@gmail.com>
Andy Rothfusz <github@metaliveblog.com>
Andy Smith <github@anarkystic.com>
Anthony Bishopric <git@anthonybishopric.com>
Antony Messerli <amesserl@rackspace.com>
Asbjørn Enge <asbjorn@hanafjedle.net>
Barry Allard <barry.allard@gmail.com>
Ben Toews <mastahyeti@gmail.com>
Benoit Chesneau <bchesneau@gmail.com>
Bhiraj Butala <abhiraj.butala@gmail.com>
Bouke Haarsma <bouke@webatoom.nl>
Brandon Liu <bdon@bdon.org>
Brandon Philips <brandon@ifup.co>
Brian McCallister <brianm@skife.org>
Brian Olsen <brian@maven-group.org>
Brian Shumate <brian@couchbase.com>
Briehan Lombaard <briehan.lombaard@gmail.com>
Bruno Bigras <bigras.bruno@gmail.com>
Caleb Spare <cespare@gmail.com>
Calen Pennington <cale@edx.org>
Charles Hooper <charles.hooper@dotcloud.com>
Christopher Currie <codemonkey+github@gmail.com>
Colin Dunklau <colin.dunklau@gmail.com>
Colin Rice <colin@daedrum.net>
Dan Buch <d.buch@modcloth.com>
Daniel Garcia <daniel@danielgarcia.info>
Daniel Gasienica <daniel@gasienica.ch>
Daniel Mizyrycki <daniel.mizyrycki@dotcloud.com>
Daniel Nordberg <dnordberg@gmail.com>
Daniel Robinson <gottagetmac@gmail.com>
Daniel Von Fange <daniel@leancoder.com>
Daniel YC Lin <dlin.tw@gmail.com>
David Calavera <david.calavera@gmail.com>
David Sissitka <me@dsissitka.com>
Deni Bertovic <deni@kset.org>
Dominik Honnef <dominik@honnef.co>
Don Spaulding <donspauldingii@gmail.com>
Dr Nic Williams <drnicwilliams@gmail.com>
Dražen Lučanin <kermit666@gmail.com>
Elias Probst <mail@eliasprobst.eu>
Emily Rose <emily@contactvibe.com>
Eric Hanchrow <ehanchrow@ine.com>
Eric Myhre <hash@exultant.us>
Erno Hopearuoho <erno.hopearuoho@gmail.com>
Evan Phoenix <evan@fallingsnow.net>
Evan Wies <evan@neomantra.net>
ezbercih <cem.ezberci@gmail.com>
Fabrizio Regini <freegenie@gmail.com>
Faiz Khan <faizkhan00@gmail.com>
Fareed Dudhia <fareeddudhia@googlemail.com>
Flavio Castelli <fcastelli@suse.com>
Francisco Souza <f@souza.cc>
Frederick F. Kautz IV <fkautz@alumni.cmu.edu>
Gabriel Monroy <gabriel@opdemand.com>
Gareth Rushgrove <gareth@morethanseven.net>
Greg Thornton <xdissent@me.com>
Guillaume J. Charmes <guillaume.charmes@dotcloud.com>
Guruprasad <lgp171188@gmail.com>
Harley Laue <losinggeneration@gmail.com>
Hector Castro <hectcastro@gmail.com>
Hunter Blanks <hunter@twilio.com>
Isao Jonas <isao.jonas@gmail.com>
James Carr <james.r.carr@gmail.com>
Jason McVetta <jason.mcvetta@gmail.com>
Jean-Baptiste Barth <jeanbaptiste.barth@gmail.com>
Jeff Lindsay <progrium@gmail.com>
Jeremy Grosser <jeremy@synack.me>
Jim Alateras <jima@comware.com.au>
Jimmy Cuadra <jimmy@jimmycuadra.com>
Joe Van Dyk <joe@tanga.com>
Joffrey F <joffrey@dotcloud.com>
Johan Euphrosine <proppy@google.com>
John Costa <john.costa@gmail.com>
Jon Wedaman <jweede@gmail.com>
Jonas Pfenniger <jonas@pfenniger.name>
Jonathan Mueller <j.mueller@apoveda.ch>
Jonathan Rudenberg <jonathan@titanous.com>
Joost Cassee <joost@cassee.net>
Jordan Arentsen <blissdev@gmail.com>
Joseph Anthony Pasquale Holsten <joseph@josephholsten.com>
Julien Barbier <write0@gmail.com>
Jérôme Petazzoni <jerome.petazzoni@dotcloud.com>
Karan Lyons <karan@karanlyons.com>
Karl Grzeszczak <karl@karlgrz.com>
Kawsar Saiyeed <kawsar.saiyeed@projiris.com>
Keli Hu <dev@keli.hu>
Ken Cochrane <kencochrane@gmail.com>
Kevin Clark <kevin.clark@gmail.com>
@@ -71,28 +105,45 @@ kim0 <email.ahmedkamal@googlemail.com>
Kimbro Staken <kstaken@kstaken.com>
Kiran Gangadharan <kiran.daredevil@gmail.com>
Konstantin Pelykh <kpelykh@zettaset.com>
Kyle Conroy <kyle.j.conroy@gmail.com>
Laurie Voss <github@seldo.com>
Louis Opter <kalessin@kalessin.fr>
Manuel Meurer <manuel@krautcomputing.com>
Marco Hennings <marco.hennings@freiheit.com>
Marcus Farkas <toothlessgear@finitebox.com>
Marcus Ramberg <marcus@nordaaker.com>
Mark McGranaghan <mmcgrana@gmail.com>
Martin Redmond <mrtodo@gmail.com>
Marko Mikulicic <mmikulicic@gmail.com>
Markus Fix <lispmeister@gmail.com>
Martin Redmond <martin@tinychat.com>
Matt Apperson <me@mattapperson.com>
Matt Bachmann <bachmann.matt@gmail.com>
Matthew Mueller <mattmuelle@gmail.com>
Maxim Treskin <zerthurd@gmail.com>
meejah <meejah@meejah.ca>
Michael Crosby <crosby.michael@gmail.com>
Michael Gorsuch <gorsuch@github.com>
Miguel Angel Fernández <elmendalerenda@gmail.com>
Mike Gaffney <mike@uberu.com>
Mikhail Sobolev <mss@mawhrin.net>
Mohit Soni <mosoni@ebay.com>
Morten Siebuhr <sbhr@sbhr.dk>
Nan Monnand Deng <monnand@gmail.com>
Nate Jones <nate@endot.org>
Nelson Chen <crazysim@gmail.com>
Niall O'Higgins <niallo@unworkable.org>
Nick Payne <nick@kurai.co.uk>
Nick Stenning <nick.stenning@digital.cabinet-office.gov.uk>
Nick Stinemates <nick@stinemates.org>
Nolan Darilek <nolan@thewordnerd.info>
odk- <github@odkurzacz.org>
Pascal Borreli <pascal@borreli.com>
Paul Bowsher <pbowsher@globalpersonals.co.uk>
Paul Hammond <paul@paulhammond.org>
Phil Spitler <pspitler@gmail.com>
Piotr Bogdan <ppbogdan@gmail.com>
pysqz <randomq@126.com>
Ramon van Alteren <ramon@vanalteren.nl>
Renato Riccieri Santos Zannon <renato.riccieri@gmail.com>
Rhys Hiltner <rhys@twitch.tv>
Robert Obryk <robryk@gmail.com>
@@ -100,14 +151,21 @@ Roberto Hashioka <roberto_hashioka@hotmail.com>
Ryan Fowler <rwfowler@gmail.com>
Sam Alba <sam.alba@gmail.com>
Sam J Sharpe <sam.sharpe@digital.cabinet-office.gov.uk>
Sean P. Kane <skane@newrelic.com>
Shawn Siefkas <shawn.siefkas@meredith.com>
Shih-Yuan Lee <fourdollars@gmail.com>
Silas Sewell <silas@sewell.org>
Solomon Hykes <solomon@dotcloud.com>
Song Gao <song@gao.io>
Sridatta Thatipamala <sthatipamala@gmail.com>
Sridhar Ratnakumar <sridharr@activestate.com>
Steeve Morin <steeve.morin@gmail.com>
Stefan Praszalowicz <stefan@greplin.com>
Thatcher Peskens <thatcher@dotcloud.com>
Thermionix <bond711@gmail.com>
Thijs Terlouw <thijsterlouw@gmail.com>
Thomas Bikeev <thomas.bikeev@mac.com>
Thomas Frössman <thomasf@jossystem.se>
Thomas Hansen <thomas.hansen@gmail.com>
Tianon Gravi <admwiggin@gmail.com>
Tim Terhorst <mynamewastaken+git@gmail.com>
@@ -115,8 +173,16 @@ Tobias Bieniek <Tobias.Bieniek@gmx.de>
Tobias Schmidt <ts@soundcloud.com>
Tobias Schwab <tobias.schwab@dynport.de>
Tom Hulihan <hulihan.tom159@gmail.com>
Tommaso Visconti <tommaso.visconti@gmail.com>
Tyler Brock <tyler.brock@gmail.com>
unclejack <unclejacksons@gmail.com>
Victor Coisne <victor.coisne@dotcloud.com>
Victor Lyuboslavsky <victor@victoreda.com>
Victor Vieux <victor.vieux@dotcloud.com>
Vincent Bernat <bernat@luffy.cx>
Vivek Agarwal <me@vivek.im>
Vladimir Kirillov <proger@wilab.org.ua>
Walter Stanish <walter@pratyeka.org>
Wes Morgan <cap10morgan@gmail.com>
Will Dietz <w@wdtz.org>
Zaiste! <oh@zaiste.net>
+92 -1
View File
@@ -1,5 +1,96 @@
# Changelog
## 0.6.4 (2013-10-16)
- Runtime: Add cleanup of container when Start() fails
- Testing: Catch errClosing error when TCP and UDP proxies are terminated
- Testing: Add aggregated docker-ci email report
- Testing: Remove a few errors in tests
* Contrib: Reorganize contributed completion scripts to add zsh completion
* Contrib: Add vim syntax highlighting for Dockerfiles from @honza
* Runtime: Add better comments to utils/stdcopy.go
- Testing: add cleanup to remove leftover containers
* Documentation: Document how to edit and release docs
* Documentation: Add initial draft of the Docker infrastructure doc
* Contrib: Add mkimage-arch.sh
- Builder: Abort build if mergeConfig returns an error and fix duplicate error message
- Runtime: Remove error messages which are not actually errors
* Testing: Only run certain tests with TESTFLAGS='-run TestName' make.sh
* Testing: Prevent docker-ci to test closing PRs
- Documentation: Minor updates to postgresql_service.rst
* Testing: Add nightly release to docker-ci
* Hack: Improve network performance for VirtualBox
* Hack: Add vagrant user to the docker group
* Runtime: Add utils.Errorf for error logging
- Packaging: Remove deprecated packaging directory
* Hack: Revamp install.sh to be usable by more people, and to use official install methods whenever possible (apt repo, portage tree, etc.)
- Hack: Fix contrib/mkimage-debian.sh apt caching prevention
* Documentation: Clarify LGTM process to contributors
- Documentation: Small fixes to parameter names in docs for ADD command
* Runtime: Record termination time in state.
- Registry: Use correct auth config when logging in.
- Documentation: Corrected error in the package name
* Documentation: Document what `vagrant up` is actually doing
- Runtime: Fix `docker rm` with volumes
- Runtime: Use empty string so TempDir uses the OS's temp dir automatically
- Runtime: Make sure to close the network allocators
* Testing: Replace panic by log.Fatal in tests
+ Documentation: improve doc search results
- Runtime: Fix some error cases where a HTTP body might not be closed
* Hack: Add proper bash completion for "docker push"
* Documentation: Add devenvironment link to CONTRIBUTING.md
* Documentation: Cleanup whitespace in API 1.5 docs
* Documentation: use angle brackets in MAINTAINER example email
- Testing: Increase TestRunDetach timeout
* Documentation: Fix help text for -v option
+ Hack: Added Dockerfile.tmLanguage to contrib
+ Runtime: Autorestart containers by default
* Testing: Adding more tests around auth.ResolveAuthConfig
* Hack: Configured FPM to make /etc/init/docker.conf a config file
* Hack: Add xz utils as a runtime dep
* Documentation: Add `apt-get install curl` to Ubuntu docs
* Documentation: Remove Gentoo install notes about #1422 workaround
* Documentation: Fix Ping endpoint documentation
* Runtime: Bump vendor kr/pty to commit 3b1f6487b (syscall.O_NOCTTY)
* Runtime: lxc: Allow set_file_cap capability in container
* Documentation: Update archlinux.rst
- Documentation: Fix ironic typo in changelog
* Documentation: Add explanation for export restrictions
* Hack: Add cleanup/refactor portion of #2010 for hack and Dockerfile updates
+ Documentation: Changes to a new style for the docs. Includes version switcher.
* Documentation: Formatting, add information about multiline json
+ Hack: Add contrib/mkimage-centos.sh back (from #1621), and associated documentation link
- Runtime: Fix panic with wrong dockercfg file
- Runtime: Fix the attach behavior with -i
* Documentation: Add .dockercfg doc
- Runtime: Move run -rm to the cli only
* Hack: Enable SSH Agent forwarding in Vagrant VM
+ Runtime: Add -rm to docker run for removing a container on exit
* Documentation: Improve registry and index REST API documentation
* Runtime: Split stdout stderr
- Documentation: Replace deprecated upgrading reference to docker-latest.tgz, which hasn't been updated since 0.5.3
* Documentation: Update Gentoo installation documentation now that we're in the portage tree proper
- Registry: Fix the error message so it is the same as the regex
* Runtime: Always create a new session for the container
* Hack: Add several of the small make.sh fixes from #1920, and make the output more consistent and contributor-friendly
* Documentation: Various command fixes in postgres example
* Documentation: Cleanup and reorganize docs and tooling for contributors and maintainers
- Documentation: Minor spelling correction of protocoll -> protocol
* Hack: Several small tweaks/fixes for contrib/mkimage-debian.sh
+ Hack: Add @tianon to hack/MAINTAINERS
## 0.6.3 (2013-09-23)
* Packaging: Update tar vendor dependency
- Client: Fix detach issue
- Runtime: Only copy and change permissions on non-bindmount volumes
- Registry: Update regular expression to match index
* Runtime: Allow multiple volumes-from
* Packaging: Download apt key over HTTPS
* Documentation: Update section on extracting the docker binary after build
* Documentation: Update development environment docs for new build process
* Documentation: Remove 'base' image from documentation
* Packaging: Add 'docker' group on install for ubuntu package
- Runtime: Fix HTTP imports from STDIN
## 0.6.2 (2013-09-17)
+ Hack: Vendor all dependencies
+ Builder: Add -rm option in order to remove intermediate containers
@@ -13,7 +104,7 @@
* Registry: Implement login with private registry
* Remote API: Bump to v1.5
* Packaging: Break down hack/make.sh into small scripts, one per 'bundle': test, binary, ubuntu etc.
* Documentation: General improvments
* Documentation: General improvements
- Runtime: UID and GID are now also applied to volumes
- Runtime: `docker start` set error code upon error
- Runtime: `docker run` set the same error code as the process started
+16 -58
View File
@@ -3,6 +3,10 @@
Want to hack on Docker? Awesome! Here are instructions to get you started. They are probably not perfect, please let us know if anything feels
wrong or incomplete.
## Build Environment
For instructions on setting up your development environment, please see our dedicated [dev environment setup docs](http://docs.docker.io/en/latest/contributing/devenvironment/).
## Contribution guidelines
### Pull requests are always welcome
@@ -55,8 +59,10 @@ Submit unit tests for your changes. Go has a great test framework built in; use
it! Take a look at existing tests for inspiration. Run the full test suite on
your branch before submitting a pull request.
Make sure you include relevant updates or additions to documentation when
creating or modifying features.
Update the documentation when creating or modifying features. Test
your documentation changes for clarity, concision, and correctness, as
well as a clean docmuent build. See ``docs/README.md`` for more
information on building the docs and how docs get released.
Write clean code. Universally formatted code promotes ease of writing, reading,
and maintenance. Always run `go fmt` before committing your changes. Most
@@ -89,53 +95,17 @@ name and email address match your git configuration. The AUTHORS file is
regenerated occasionally from the git commit history, so a mismatch may result
in your changes being overwritten.
### Approval
## Decision process
Docker maintainers use LGTM (looks good to me) in comments on the code review
to indicate acceptance.
### How are decisions made?
A change requires LGTMs from an absolute majority of the maintainers of each
component affected. For example, if a change affects docs/ and registry/, it
needs an absolute majority from the maintainers of docs/ AND, separately, an
absolute majority of the maintainers of registry
Short answer: with pull requests to the docker repository.
Docker is an open-source project with an open design philosophy. This means that the repository is the source of truth for EVERY aspect of the project,
including its philosophy, design, roadmap and APIs. *If it's part of the project, it's in the repo. It's in the repo, it's part of the project.*
As a result, all decisions can be expressed as changes to the repository. An implementation change is a change to the source code. An API change is a change to
the API specification. A philosophy change is a change to the philosophy manifesto. And so on.
All decisions affecting docker, big and small, follow the same 3 steps:
* Step 1: Open a pull request. Anyone can do this.
* Step 2: Discuss the pull request. Anyone can do this.
* Step 3: Accept or refuse a pull request. The relevant maintainer does this (see below "Who decides what?")
### Who decides what?
So all decisions are pull requests, and the relevant maintainer makes the decision by accepting or refusing the pull request.
But how do we identify the relevant maintainer for a given pull request?
Docker follows the timeless, highly efficient and totally unfair system known as [Benevolent dictator for life](http://en.wikipedia.org/wiki/Benevolent_Dictator_for_Life),
with yours truly, Solomon Hykes, in the role of BDFL.
This means that all decisions are made by default by me. Since making every decision myself would be highly unscalable, in practice decisions are spread across multiple maintainers.
The relevant maintainer for a pull request is assigned in 3 steps:
* Step 1: Determine the subdirectory affected by the pull request. This might be src/registry, docs/source/api, or any other part of the repo.
* Step 2: Find the MAINTAINERS file which affects this directory. If the directory itself does not have a MAINTAINERS file, work your way up the the repo hierarchy until you find one.
* Step 3: The first maintainer listed is the primary maintainer. The pull request is assigned to him. He may assign it to other listed maintainers, at his discretion.
### I'm a maintainer, should I make pull requests too?
Primary maintainers are not required to create pull requests when changing their own subdirectory, but secondary maintainers are.
### Who assigns maintainers?
Solomon.
For more details see [MAINTAINERS.md](hack/MAINTAINERS.md)
### How can I become a maintainer?
@@ -146,15 +116,3 @@ Solomon.
Don't forget: being a maintainer is a time investment. Make sure you will have time to make yourself available.
You don't have to be a maintainer to make a difference on the project!
### What are a maintainer's responsibility?
It is every maintainer's responsibility to:
* 1) Expose a clear roadmap for improving their component.
* 2) Deliver prompt feedback and decisions on pull requests.
* 3) Be available to anyone with questions, bug reports, criticism etc. on their component. This includes irc, github requests and the mailing list.
* 4) Make sure their component respects the philosophy, design and roadmap of the project.
### How is this process changed?
Just like everything else: by making a pull request :)
+55 -32
View File
@@ -12,47 +12,70 @@
#
#
# # Run the test suite:
# docker run -privileged -lxc-conf=lxc.aa_profile=unconfined docker go test -v
# docker run -privileged -lxc-conf=lxc.aa_profile=unconfined docker hack/make.sh test
#
# # Publish a release:
# docker run -privileged -lxc-conf=lxc.aa_profile=unconfined \
# -e AWS_S3_BUCKET=baz \
# -e AWS_ACCESS_KEY=foo \
# -e AWS_SECRET_KEY=bar \
# -e GPG_PASSPHRASE=gloubiboulga \
# -lxc-conf=lxc.aa_profile=unconfined -privileged docker hack/release.sh
#
# -e AWS_S3_BUCKET=baz \
# -e AWS_ACCESS_KEY=foo \
# -e AWS_SECRET_KEY=bar \
# -e GPG_PASSPHRASE=gloubiboulga \
# docker hack/release.sh
#
docker-version 0.6.1
from ubuntu:12.04
maintainer Solomon Hykes <solomon@dotcloud.com>
from ubuntu:12.10
maintainer Solomon Hykes <solomon@dotcloud.com>
# Build dependencies
run echo 'deb http://archive.ubuntu.com/ubuntu precise main universe' > /etc/apt/sources.list
run apt-get update
run apt-get install -y -q curl
run apt-get install -y -q git
run apt-get install -y -q mercurial
# Install Go
run curl -s https://go.googlecode.com/files/go1.1.2.linux-amd64.tar.gz | tar -v -C /usr/local -xz
env PATH /usr/local/go/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin
env GOPATH /go:/go/src/github.com/dotcloud/docker/vendor
env CGO_ENABLED 0
run cd /tmp && echo 'package main' > t.go && go test -a -i -v
run apt-get update
run apt-get install -y -q curl
run apt-get install -y -q git
run apt-get install -y -q mercurial
run apt-get install -y -q build-essential
run apt-get install -y -q libsqlite3-dev
# Install Go from source (for eventual cross-compiling)
run curl -s https://go.googlecode.com/files/go1.2rc1.src.tar.gz | tar -v -C / -xz && mv /go /goroot
run cd /goroot/src && ./make.bash
env GOROOT /goroot
env PATH $PATH:/goroot/bin
env GOPATH /go:/go/src/github.com/dotcloud/docker/vendor
# Create Go cache with tag netgo (for static compilation of Go while preserving CGO support)
run go install -ldflags '-w -linkmode external -extldflags "-static -Wl,--unresolved-symbols=ignore-in-shared-libs"' -tags netgo -a std
# Get lvm2 source for compiling statically
run git clone git://git.fedorahosted.org/git/lvm2.git /lvm2
run cd /lvm2 && git checkout v2_02_102
# can't use git clone -b because it's not supported by git versions before 1.7.10
run cd /lvm2 && ./configure --enable-static_link && make && make install_device-mapper
# see https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags
# Ubuntu stuff
run apt-get install -y -q ruby1.9.3 rubygems libffi-dev
run gem install fpm
run apt-get install -y -q reprepro dpkg-sig
run apt-get install -y -q ruby1.9.3 rubygems libffi-dev
run gem install --no-rdoc --no-ri fpm
run apt-get install -y -q reprepro dpkg-sig
# Install s3cmd 1.0.1 (earlier versions don't support env variables in the config)
run apt-get install -y -q python-pip
run pip install s3cmd
run pip install python-magic
run /bin/echo -e '[default]\naccess_key=$AWS_ACCESS_KEY\nsecret_key=$AWS_SECRET_KEY\n' > /.s3cfg
run apt-get install -y -q python-pip
run pip install s3cmd
run pip install python-magic
run /bin/echo -e '[default]\naccess_key=$AWS_ACCESS_KEY\nsecret_key=$AWS_SECRET_KEY\n' > /.s3cfg
# Runtime dependencies
run apt-get install -y -q iptables
run apt-get install -y -q lxc
volume /var/lib/docker
workdir /go/src/github.com/dotcloud/docker
run apt-get install -y -q iptables
run dpkg-divert --local --rename --add /sbin/initctl && \
ln -s /bin/true /sbin/initctl && \
apt-get install -y -q lxc
volume /var/lib/docker
workdir /go/src/github.com/dotcloud/docker
# Wrap all commands in the "docker-in-docker" script to allow nested containers
entrypoint ["hack/dind"]
# Upload docker source
add . /go/src/github.com/dotcloud/docker
add . /go/src/github.com/dotcloud/docker
+3 -10
View File
@@ -15,23 +15,16 @@ to put them - so we put them here :)
* Run linter on codebase
* Unify build commands and regular commands
* Move source code into src/ subdir for clarity
* Clean up the Makefile, it's a mess
* docker build: on non-existent local path for ADD, don't show full absolute path on the host
* mount into /dockerinit rather than /sbin/init
* docker tag foo REPO:TAG
* use size header for progress bar in pull
* Clean up context upload in build!!!
* Parallel pull
* Ensure /proc/sys/net/ipv4/ip_forward is 1
* Force DNS to public!
* Always generate a resolv.conf per container, to avoid changing resolv.conf under thne container's feet
* Save metadata with import/export
* Save metadata with import/export (#1974)
* Upgrade dockerd without stopping containers
* bring back git revision info, looks like it was lost
* Simple command to remove all untagged images
* Simple command to remove all untagged images (`docker rmi $(docker images | awk '/^<none>/ { print $3 }')`)
* Simple command to clean up containers for disk space
* Caching after an ADD
* entry point config
* bring back git revision info, looks like it was lost
* Caching after an ADD (#880)
* Clean up the ProgressReader api, it's a PITA to use
* Use netlink instead of iproute2/iptables (#925)
+37 -5
View File
@@ -1,11 +1,43 @@
Docker
Copyright 2012-2013 dotCloud, inc.
This product includes software developed at dotCloud, inc. (http://www.dotcloud.com).
This product includes software developed at dotCloud,
inc. (http://www.dotcloud.com).
This product contains software (https://github.com/kr/pty) developed by Keith Rarick, licensed under the MIT License.
This product contains software (https://github.com/kr/pty) developed
by Keith Rarick, licensed under the MIT License.
Transfers of Docker shall be in accordance with applicable export controls of any country and all other applicable
legal requirements. Docker shall not be distributed or downloaded to or in Cuba, Iran, North Korea, Sudan or Syria
and shall not be distributed or downloaded to any person on the Denied Persons List administered by the U.S.
The following is courtesy of our legal counsel:
Transfers of Docker shall be in accordance with applicable export
controls of any country and all other applicable legal requirements.
Docker shall not be distributed or downloaded to or in Cuba, Iran,
North Korea, Sudan or Syria and shall not be distributed or downloaded
to any person on the Denied Persons List administered by the U.S.
Department of Commerce.
What does that mean?
Here is a further explanation from our legal counsel:
Like all software products that utilize cryptography, the export and
use of Docker is subject to the U.S. Commerce Department's Export
Administration Regulations (EAR) because it uses or contains
cryptography (see
http://www.bis.doc.gov/index.php/policy-guidance/encryption). Certain
free and open source software projects have a lightweight set of
requirements, which can generally be met by providing email notice to
the appropriate U.S. government agencies that their source code is
available on a publicly available repository and making the
appropriate statements in the README.
The restrictions of the EAR apply to certain denied locations
(currently Iran, Sudan, Syria, North Korea, or Cuba) and those
individuals on the Denied Persons List, which is available here:
http://www.bis.doc.gov/index.php/policy-guidance/lists-of-parties-of-concern/denied-persons-list.
If you are incorporating Docker into a new open source project, the
EAR restrictions apply to your incorporation of Docker into your
project in the same manner as other cryptography-enabled projects,
such as OpenSSL, almost all Linux distributions, etc.
For more information, see http://www.apache.org/dev/crypto.html and/or
seek legal counsel.
+4 -1
View File
@@ -18,7 +18,7 @@ Platform-as-a-Service. It benefits directly from the experience
accumulated over several years of large-scale operation and support of
hundreds of thousands of applications and databases.
![Docker L](docs/sources/static_files/dockerlogo-h.png "Docker")
![Docker L](docs/theme/docker/static/img/dockerlogo-h.png "Docker")
## Better than VMs
@@ -190,6 +190,9 @@ wrong or incomplete.
### Legal
*Brought to you courtesy of our legal counsel. For more context,
please see the Notice document.*
Transfers of Docker shall be in accordance with applicable export
controls of any country and all other applicable legal requirements.
Docker shall not be distributed or downloaded to or in Cuba, Iran,
+1 -1
View File
@@ -1 +1 @@
0.6.2
0.6.4-dev
Vendored
+6
View File
@@ -13,6 +13,8 @@ Vagrant::Config.run do |config|
config.vm.box = BOX_NAME
config.vm.box_url = BOX_URI
config.ssh.forward_agent = true
# Provision docker and new kernel if deployment was not done.
# It is assumed Vagrant can successfully launch the provider instance.
if Dir.glob("#{File.dirname(__FILE__)}/.vagrant/machines/default/*/id").empty?
@@ -37,6 +39,8 @@ Vagrant::Config.run do |config|
"echo 'Installation of VBox Guest Additions is proceeding in the background.'; " \
"echo '\"vagrant reload\" can be used in about 2 minutes to activate the new guest additions.'; "
end
# Add vagrant user to the docker group
pkg_cmd << "usermod -a -G docker vagrant; "
# Activate new kernel
pkg_cmd << "shutdown -r +1; "
config.vm.provision :shell, :inline => pkg_cmd
@@ -76,6 +80,8 @@ Vagrant::VERSION >= "1.1.0" and Vagrant.configure("2") do |config|
config.vm.provider :virtualbox do |vb|
config.vm.box = BOX_NAME
config.vm.box_url = BOX_URI
vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
vb.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
end
end
+125 -30
View File
@@ -6,6 +6,7 @@ import (
"encoding/json"
"fmt"
"github.com/dotcloud/docker/auth"
"github.com/dotcloud/docker/gograph"
"github.com/dotcloud/docker/utils"
"github.com/gorilla/mux"
"io"
@@ -21,10 +22,12 @@ import (
"strings"
)
const APIVERSION = 1.5
const DEFAULTHTTPHOST = "127.0.0.1"
const DEFAULTHTTPPORT = 4243
const DEFAULTUNIXSOCKET = "/var/run/docker.sock"
const (
APIVERSION = 1.6
DEFAULTHTTPHOST = "127.0.0.1"
DEFAULTHTTPPORT = 4243
DEFAULTUNIXSOCKET = "/var/run/docker.sock"
)
type HttpApiFunc func(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error
@@ -68,8 +71,11 @@ func httpError(w http.ResponseWriter, err error) {
} else if strings.Contains(err.Error(), "hasn't been activated") {
statusCode = http.StatusForbidden
}
utils.Debugf("[error %d] %s", statusCode, err)
http.Error(w, err.Error(), statusCode)
if err != nil {
utils.Errorf("HTTP Error: statusCode=%d %s", statusCode, err.Error())
http.Error(w, err.Error(), statusCode)
}
}
func writeJSON(w http.ResponseWriter, code int, v interface{}) error {
@@ -100,7 +106,7 @@ func getBoolParam(value string) (bool, error) {
func matchesContentType(contentType, expectedType string) bool {
mimetype, _, err := mime.ParseMediaType(contentType)
if err != nil {
utils.Debugf("Error parsing media type: %s error: %s", contentType, err.Error())
utils.Errorf("Error parsing media type: %s error: %s", contentType, err.Error())
}
return err == nil && mimetype == expectedType
}
@@ -145,7 +151,7 @@ func getContainersExport(srv *Server, version float64, w http.ResponseWriter, r
name := vars["name"]
if err := srv.ContainerExport(name, w); err != nil {
utils.Debugf("%s", err)
utils.Errorf("%s", err)
return err
}
return nil
@@ -190,7 +196,7 @@ func getEvents(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
_, err = wf.Write(b)
if err != nil {
// On error, evict the listener
utils.Debugf("%s", err)
utils.Errorf("%s", err)
srv.Lock()
delete(srv.listeners, r.RemoteAddr)
srv.Unlock()
@@ -344,8 +350,8 @@ func postCommit(srv *Server, version float64, w http.ResponseWriter, r *http.Req
return err
}
config := &Config{}
if err := json.NewDecoder(r.Body).Decode(config); err != nil {
utils.Debugf("%s", err)
if err := json.NewDecoder(r.Body).Decode(config); err != nil && err != io.EOF {
utils.Errorf("%s", err)
}
repo := r.Form.Get("repo")
tag := r.Form.Get("tag")
@@ -510,16 +516,19 @@ func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r
return err
}
if !config.NetworkDisabled && len(config.Dns) == 0 && len(srv.runtime.Dns) == 0 && utils.CheckLocalDns(resolvConf) {
if !config.NetworkDisabled && len(config.Dns) == 0 && len(srv.runtime.config.Dns) == 0 && utils.CheckLocalDns(resolvConf) {
out.Warnings = append(out.Warnings, fmt.Sprintf("Docker detected local DNS server on resolv.conf. Using default external servers: %v", defaultDns))
config.Dns = defaultDns
}
id, err := srv.ContainerCreate(config)
id, warnings, err := srv.ContainerCreate(config)
if err != nil {
return err
}
out.ID = id
for _, warning := range warnings {
out.Warnings = append(out.Warnings, warning)
}
if config.Memory > 0 && !srv.runtime.capabilities.MemoryLimit {
log.Println("WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.")
@@ -565,12 +574,17 @@ func deleteContainers(srv *Server, version float64, w http.ResponseWriter, r *ht
return fmt.Errorf("Missing parameter")
}
name := vars["name"]
removeVolume, err := getBoolParam(r.Form.Get("v"))
if err != nil {
return err
}
removeLink, err := getBoolParam(r.Form.Get("link"))
if err != nil {
return err
}
if err := srv.ContainerDestroy(name, removeVolume); err != nil {
if err := srv.ContainerDestroy(name, removeVolume, removeLink); err != nil {
return err
}
w.WriteHeader(http.StatusNoContent)
@@ -618,6 +632,7 @@ func postContainersStart(srv *Server, version float64, w http.ResponseWriter, r
}
name := vars["name"]
if err := srv.ContainerStart(name, hostConfig); err != nil {
utils.Debugf("error ContainerStart: %s", err)
return err
}
w.WriteHeader(http.StatusNoContent)
@@ -650,6 +665,7 @@ func postContainersWait(srv *Server, version float64, w http.ResponseWriter, r *
return fmt.Errorf("Missing parameter")
}
name := vars["name"]
status, err := srv.ContainerWait(name)
if err != nil {
return err
@@ -710,32 +726,43 @@ func postContainersAttach(srv *Server, version float64, w http.ResponseWriter, r
}
name := vars["name"]
if _, err := srv.ContainerInspect(name); err != nil {
c, err := srv.ContainerInspect(name)
if err != nil {
return err
}
in, out, err := hijackServer(w)
inStream, outStream, err := hijackServer(w)
if err != nil {
return err
}
defer func() {
if tcpc, ok := in.(*net.TCPConn); ok {
if tcpc, ok := inStream.(*net.TCPConn); ok {
tcpc.CloseWrite()
} else {
in.Close()
inStream.Close()
}
}()
defer func() {
if tcpc, ok := out.(*net.TCPConn); ok {
if tcpc, ok := outStream.(*net.TCPConn); ok {
tcpc.CloseWrite()
} else if closer, ok := out.(io.Closer); ok {
} else if closer, ok := outStream.(io.Closer); ok {
closer.Close()
}
}()
fmt.Fprintf(out, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
if err := srv.ContainerAttach(name, logs, stream, stdin, stdout, stderr, in, out); err != nil {
fmt.Fprintf(out, "Error: %s\n", err)
var errStream io.Writer
fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
if !c.Config.Tty && version >= 1.6 {
errStream = utils.NewStdWriter(outStream, utils.Stderr)
outStream = utils.NewStdWriter(outStream, utils.Stdout)
} else {
errStream = outStream
}
if err := srv.ContainerAttach(name, logs, stream, stdin, stdout, stderr, inStream, outStream, errStream); err != nil {
fmt.Fprintf(outStream, "Error: %s\n", err)
}
return nil
}
@@ -778,8 +805,8 @@ func wsContainersAttach(srv *Server, version float64, w http.ResponseWriter, r *
h := websocket.Handler(func(ws *websocket.Conn) {
defer ws.Close()
if err := srv.ContainerAttach(name, logs, stream, stdin, stdout, stderr, ws, ws); err != nil {
utils.Debugf("Error: %s", err)
if err := srv.ContainerAttach(name, logs, stream, stdin, stdout, stderr, ws, ws, ws); err != nil {
utils.Errorf("Error: %s", err)
}
})
h.ServeHTTP(w, r)
@@ -892,8 +919,7 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
b := NewBuildFile(srv, utils.NewWriteFlusher(w), !suppressOutput, !noCache, rm)
id, err := b.Build(context)
if err != nil {
fmt.Fprintf(w, "Error build: %s\n", err)
return err
return fmt.Errorf("Error build: %s", err)
}
if repoName != "" {
srv.runtime.repositories.Set(repoName, tag, id, false)
@@ -925,7 +951,7 @@ func postContainersCopy(srv *Server, version float64, w http.ResponseWriter, r *
}
if err := srv.ContainerCopy(name, copyData.Resource, w); err != nil {
utils.Debugf("%s", err.Error())
utils.Errorf("%s", err.Error())
return err
}
return nil
@@ -960,7 +986,7 @@ func makeHttpHandler(srv *Server, logging bool, localMethod string, localRoute s
if err != nil {
version = APIVERSION
}
if srv.enableCors {
if srv.runtime.config.EnableCors {
writeCorsHeaders(w, r)
}
@@ -970,12 +996,79 @@ func makeHttpHandler(srv *Server, logging bool, localMethod string, localRoute s
}
if err := handlerFunc(srv, version, w, r, mux.Vars(r)); err != nil {
utils.Debugf("Error: %s", err)
utils.Errorf("Error: %s", err)
httpError(w, err)
}
}
}
func getContainersLinks(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
runtime := srv.runtime
all, err := getBoolParam(r.Form.Get("all"))
if err != nil {
return err
}
out := []APILink{}
err = runtime.containerGraph.Walk("/", func(p string, e *gograph.Entity) error {
if container := runtime.Get(e.ID()); container != nil {
if !all && strings.Contains(p, container.ID) {
return nil
}
out = append(out, APILink{
Path: p,
ContainerID: container.ID,
Image: runtime.repositories.ImageName(container.Image),
})
}
return nil
}, -1)
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, out)
}
func postContainerLink(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
values := make(map[string]string)
if matchesContentType(r.Header.Get("Content-Type"), "application/json") && r.Body != nil {
defer r.Body.Close()
dec := json.NewDecoder(r.Body)
if err := dec.Decode(&values); err != nil {
return err
}
} else {
return fmt.Errorf("Invalid json body")
}
currentName := values["currentName"]
newName := values["newName"]
if currentName == "" {
return fmt.Errorf("currentName cannot be empty")
}
if newName == "" {
return fmt.Errorf("newName cannot be empty")
}
if err := srv.runtime.RenameLink(currentName, newName); err != nil {
if strings.HasSuffix(err.Error(), "name are not unique") {
return fmt.Errorf("Conflict, %s already exists", newName)
}
return err
}
return nil
}
func createRouter(srv *Server, logging bool) (*mux.Router, error) {
r := mux.NewRouter()
@@ -996,6 +1089,7 @@ func createRouter(srv *Server, logging bool) (*mux.Router, error) {
"/containers/{name:.*}/json": getContainersByName,
"/containers/{name:.*}/top": getContainersTop,
"/containers/{name:.*}/attach/ws": wsContainersAttach,
"/containers/links": getContainersLinks,
},
"POST": {
"/auth": postAuth,
@@ -1014,6 +1108,7 @@ func createRouter(srv *Server, logging bool) (*mux.Router, error) {
"/containers/{name:.*}/resize": postContainersResize,
"/containers/{name:.*}/attach": postContainersAttach,
"/containers/{name:.*}/copy": postContainersCopy,
"/containers/link": postContainerLink,
},
"DELETE": {
"/containers/{name:.*}": deleteContainers,
+32 -29
View File
@@ -1,7 +1,5 @@
package docker
import "encoding/json"
type APIHistory struct {
ID string `json:"Id"`
Tags []string `json:",omitempty"`
@@ -19,18 +17,23 @@ type APIImages struct {
}
type APIInfo struct {
Debug bool
Containers int
Images int
NFd int `json:",omitempty"`
NGoroutines int `json:",omitempty"`
MemoryLimit bool `json:",omitempty"`
SwapLimit bool `json:",omitempty"`
IPv4Forwarding bool `json:",omitempty"`
LXCVersion string `json:",omitempty"`
NEventsListener int `json:",omitempty"`
KernelVersion string `json:",omitempty"`
IndexServerAddress string `json:",omitempty"`
Debug bool
Containers int
Images int
NFd int `json:",omitempty"`
NGoroutines int `json:",omitempty"`
MemoryLimit bool `json:",omitempty"`
SwapLimit bool `json:",omitempty"`
IPv4Forwarding bool `json:",omitempty"`
LXCVersion string `json:",omitempty"`
NEventsListener int `json:",omitempty"`
KernelVersion string `json:",omitempty"`
IndexServerAddress string `json:",omitempty"`
DevmapperPool string `json:",omitempty"`
DevmapperDataUsed uint64 `json:",omitempty"`
DevmapperDataTotal uint64 `json:",omitempty"`
DevmapperMetadataUsed uint64 `json:",omitempty"`
DevmapperMetadataTotal uint64 `json:",omitempty"`
}
type APITop struct {
@@ -52,17 +55,18 @@ type APIContainers struct {
Ports []APIPort
SizeRw int64
SizeRootFs int64
Names []string
}
func (self *APIContainers) ToLegacy() APIContainersOld {
return APIContainersOld{
ID: self.ID,
Image: self.Image,
Command: self.Command,
Created: self.Created,
Status: self.Status,
Ports: displayablePorts(self.Ports),
SizeRw: self.SizeRw,
ID: self.ID,
Image: self.Image,
Command: self.Command,
Created: self.Created,
Status: self.Status,
Ports: displayablePorts(self.Ports),
SizeRw: self.SizeRw,
SizeRootFs: self.SizeRootFs,
}
}
@@ -96,14 +100,7 @@ type APIPort struct {
PrivatePort int64
PublicPort int64
Type string
}
func (port *APIPort) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]interface{}{
"PrivatePort": port.PrivatePort,
"PublicPort": port.PublicPort,
"Type": port.Type,
})
IP string
}
type APIVersion struct {
@@ -129,3 +126,9 @@ type APICopy struct {
Resource string
HostPath string
}
type APILink struct {
Path string
ContainerID string
Image string
}
+153 -28
View File
@@ -5,6 +5,7 @@ import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"github.com/dotcloud/docker/utils"
"io"
"net"
@@ -12,6 +13,7 @@ import (
"net/http/httptest"
"os"
"path"
"strings"
"testing"
"time"
)
@@ -40,6 +42,25 @@ func TestGetBoolParam(t *testing.T) {
}
}
func TesthttpError(t *testing.T) {
r := httptest.NewRecorder()
httpError(r, fmt.Errorf("No such method"))
if r.Code != http.StatusNotFound {
t.Fatalf("Expected %d, got %d", http.StatusNotFound, r.Code)
}
httpError(r, fmt.Errorf("This accound hasn't been activated"))
if r.Code != http.StatusForbidden {
t.Fatalf("Expected %d, got %d", http.StatusForbidden, r.Code)
}
httpError(r, fmt.Errorf("Some error"))
if r.Code != http.StatusInternalServerError {
t.Fatalf("Expected %d, got %d", http.StatusInternalServerError, r.Code)
}
}
func TestGetVersion(t *testing.T) {
var err error
runtime := mkRuntime(t)
@@ -91,6 +112,7 @@ func TestGetInfo(t *testing.T) {
func TestGetEvents(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{
runtime: runtime,
events: make([]utils.JSONMessage, 0, 64),
@@ -243,7 +265,11 @@ func TestGetImagesJSON(t *testing.T) {
t.Fatalf("Error expected, received none")
}
httpError(r4, err)
if !strings.HasPrefix(err.Error(), "Bad parameter") {
t.Fatalf("Error should starts with \"Bad parameter\"")
}
http.Error(r4, err.Error(), http.StatusBadRequest)
if r4.Code != http.StatusBadRequest {
t.Fatalf("%d Bad Request expected, received %d\n", http.StatusBadRequest, r4.Code)
}
@@ -321,7 +347,7 @@ func TestGetContainersJSON(t *testing.T) {
srv := &Server{runtime: runtime}
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"echo", "test"},
})
@@ -336,9 +362,11 @@ func TestGetContainersJSON(t *testing.T) {
}
r := httptest.NewRecorder()
if err := getContainersJSON(srv, APIVERSION, r, req, nil); err != nil {
t.Fatal(err)
}
setTimeout(t, "getContainerJSON timed out", 5*time.Second, func() {
if err := getContainersJSON(srv, APIVERSION, r, req, nil); err != nil {
t.Fatal(err)
}
})
containers := []APIContainers{}
if err := json.Unmarshal(r.Body.Bytes(), &containers); err != nil {
t.Fatal(err)
@@ -358,7 +386,7 @@ func TestGetContainersExport(t *testing.T) {
srv := &Server{runtime: runtime}
// Create a container and remove a file
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"touch", "/test"},
@@ -374,7 +402,7 @@ func TestGetContainersExport(t *testing.T) {
}
r := httptest.NewRecorder()
if err = getContainersExport(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil {
if err := getContainersExport(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil {
t.Fatal(err)
}
@@ -408,7 +436,7 @@ func TestGetContainersChanges(t *testing.T) {
srv := &Server{runtime: runtime}
// Create a container and remove a file
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/rm", "/etc/passwd"},
@@ -446,15 +474,12 @@ func TestGetContainersChanges(t *testing.T) {
func TestGetContainersTop(t *testing.T) {
t.Skip("Fixme. Skipping test for now. Reported error when testing using dind: 'api_test.go:527: Expected 2 processes, found 0.'")
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/sh", "-c", "cat"},
@@ -536,7 +561,7 @@ func TestGetContainersByName(t *testing.T) {
srv := &Server{runtime: runtime}
// Create a container and remove a file
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"echo", "test"},
@@ -566,9 +591,8 @@ func TestPostCommit(t *testing.T) {
srv := &Server{runtime: runtime}
// Create a container and remove a file
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"touch", "/test"},
@@ -647,13 +671,21 @@ func TestPostContainersCreate(t *testing.T) {
t.Fatal(err)
}
if _, err := os.Stat(path.Join(container.rwPath(), "test")); err != nil {
if err := container.EnsureMounted(); err != nil {
t.Fatalf("Unable to mount container: %s", err)
}
if _, err := os.Stat(path.Join(container.RootfsPath(), "test")); err != nil {
if os.IsNotExist(err) {
utils.Debugf("Err: %s", err)
t.Fatalf("The test file has not been created")
}
t.Fatal(err)
}
if err := container.Unmount(); err != nil {
t.Fatalf("Unable to unmount container: %s", err)
}
}
func TestPostContainersKill(t *testing.T) {
@@ -662,7 +694,7 @@ func TestPostContainersKill(t *testing.T) {
srv := &Server{runtime: runtime}
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/cat"},
@@ -704,7 +736,7 @@ func TestPostContainersRestart(t *testing.T) {
srv := &Server{runtime: runtime}
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/cat"},
@@ -758,7 +790,7 @@ func TestPostContainersStart(t *testing.T) {
srv := &Server{runtime: runtime}
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/cat"},
@@ -777,6 +809,8 @@ func TestPostContainersStart(t *testing.T) {
t.Fatal(err)
}
req.Header.Set("Content-Type", "application/json")
r := httptest.NewRecorder()
if err := postContainersStart(srv, APIVERSION, r, req, map[string]string{"name": container.ID}); err != nil {
t.Fatal(err)
@@ -808,7 +842,7 @@ func TestPostContainersStop(t *testing.T) {
srv := &Server{runtime: runtime}
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/cat"},
@@ -855,7 +889,7 @@ func TestPostContainersWait(t *testing.T) {
srv := &Server{runtime: runtime}
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/sleep", "1"},
@@ -897,7 +931,7 @@ func TestPostContainersAttach(t *testing.T) {
srv := &Server{runtime: runtime}
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/cat"},
@@ -952,7 +986,96 @@ func TestPostContainersAttach(t *testing.T) {
})
setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
if err := assertPipe("hello\n", string([]byte{1, 0, 0, 0, 0, 0, 0, 6})+"hello", stdout, stdinPipe, 15); err != nil {
t.Fatal(err)
}
})
// Close pipes (client disconnects)
if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
t.Fatal(err)
}
// Wait for attach to finish, the client disconnected, therefore, Attach finished his job
setTimeout(t, "Waiting for CmdAttach timed out", 10*time.Second, func() {
<-c1
})
// We closed stdin, expect /bin/cat to still be running
// Wait a little bit to make sure container.monitor() did his thing
err = container.WaitTimeout(500 * time.Millisecond)
if err == nil || !container.State.Running {
t.Fatalf("/bin/cat is not running after closing stdin")
}
// Try to avoid the timeout in destroy. Best effort, don't check error
cStdin, _ := container.StdinPipe()
cStdin.Close()
container.Wait()
}
func TestPostContainersAttachStderr(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/sh", "-c", "/bin/cat >&2"},
OpenStdin: true,
},
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container)
// Start the process
hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
t.Fatal(err)
}
stdin, stdinPipe := io.Pipe()
stdout, stdoutPipe := io.Pipe()
// Try to avoid the timeout in destroy. Best effort, don't check error
defer func() {
closeWrap(stdin, stdinPipe, stdout, stdoutPipe)
container.Kill()
}()
// Attach to it
c1 := make(chan struct{})
go func() {
defer close(c1)
r := &hijackTester{
ResponseRecorder: httptest.NewRecorder(),
in: stdin,
out: stdoutPipe,
}
req, err := http.NewRequest("POST", "/containers/"+container.ID+"/attach?stream=1&stdin=1&stdout=1&stderr=1", bytes.NewReader([]byte{}))
if err != nil {
t.Fatal(err)
}
if err := postContainersAttach(srv, APIVERSION, r, req, map[string]string{"name": container.ID}); err != nil {
t.Fatal(err)
}
}()
// Acknowledge hijack
setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() {
stdout.Read([]byte{})
stdout.Read(make([]byte, 4096))
})
setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
if err := assertPipe("hello\n", string([]byte{2, 0, 0, 0, 0, 0, 0, 6})+"hello", stdout, stdinPipe, 15); err != nil {
t.Fatal(err)
}
})
@@ -989,7 +1112,7 @@ func TestDeleteContainers(t *testing.T) {
srv := &Server{runtime: runtime}
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"touch", "/test"},
})
@@ -1027,7 +1150,8 @@ func TestOptionsRoute(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime, enableCors: true}
runtime.config.EnableCors = true
srv := &Server{runtime: runtime}
r := httptest.NewRecorder()
router, err := createRouter(srv, false)
@@ -1050,7 +1174,8 @@ func TestGetEnabledCors(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime, enableCors: true}
runtime.config.EnableCors = true
srv := &Server{runtime: runtime}
r := httptest.NewRecorder()
@@ -1177,7 +1302,7 @@ func TestPostContainersCopy(t *testing.T) {
srv := &Server{runtime: runtime}
// Create a container and remove a file
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"touch", "/test.txt"},
+85 -8
View File
@@ -80,20 +80,74 @@ func (compression *Compression) Extension() string {
// Tar creates an archive from the directory at `path`, and returns it as a
// stream of bytes.
func Tar(path string, compression Compression) (io.Reader, error) {
return TarFilter(path, compression, nil)
return TarFilter(path, compression, nil, true, nil)
}
func escapeName(name string) string {
escaped := make([]byte, 0)
for i, c := range []byte(name) {
if i == 0 && c == '/' {
continue
}
// all printable chars except "-" which is 0x2d
if (0x20 <= c && c <= 0x7E) && c != 0x2d {
escaped = append(escaped, c)
} else {
escaped = append(escaped, fmt.Sprintf("\\%03o", c)...)
}
}
return string(escaped)
}
// Tar creates an archive from the directory at `path`, only including files whose relative
// paths are included in `filter`. If `filter` is nil, then all files are included.
func TarFilter(path string, compression Compression, filter []string) (io.Reader, error) {
args := []string{"tar", "--numeric-owner", "-f", "-", "-C", path}
func TarFilter(path string, compression Compression, filter []string, recursive bool, createFiles []string) (io.Reader, error) {
args := []string{"tar", "--numeric-owner", "-f", "-", "-C", path, "-T", "-"}
if filter == nil {
filter = []string{"."}
}
for _, f := range filter {
args = append(args, "-c"+compression.Flag(), f)
args = append(args, "-c"+compression.Flag())
if !recursive {
args = append(args, "--no-recursion")
}
return CmdStream(exec.Command(args[0], args[1:]...))
files := ""
for _, f := range filter {
files = files + escapeName(f) + "\n"
}
tmpDir := ""
if createFiles != nil {
var err error // Can't use := here or we override the outer tmpDir
tmpDir, err = ioutil.TempDir("", "docker-tar")
if err != nil {
return nil, err
}
files = files + "-C" + tmpDir + "\n"
for _, f := range createFiles {
path := filepath.Join(tmpDir, f)
err := os.MkdirAll(filepath.Dir(path), 0600)
if err != nil {
return nil, err
}
if file, err := os.OpenFile(path, os.O_CREATE, 0600); err != nil {
return nil, err
} else {
file.Close()
}
files = files + escapeName(f) + "\n"
}
}
return CmdStream(exec.Command(args[0], args[1:]...), &files, func() {
if tmpDir != "" {
_ = os.RemoveAll(tmpDir)
}
})
}
// Untar reads a stream of bytes from `archive`, parses it as a tar archive,
@@ -140,7 +194,7 @@ func Untar(archive io.Reader, path string) error {
// TarUntar aborts and returns the error.
func TarUntar(src string, filter []string, dst string) error {
utils.Debugf("TarUntar(%s %s %s)", src, filter, dst)
archive, err := TarFilter(src, Uncompressed, filter)
archive, err := TarFilter(src, Uncompressed, filter, true, nil)
if err != nil {
return err
}
@@ -227,13 +281,33 @@ func CopyFileWithTar(src, dst string) error {
// CmdStream executes a command, and returns its stdout as a stream.
// If the command fails to run or doesn't complete successfully, an error
// will be returned, including anything written on stderr.
func CmdStream(cmd *exec.Cmd) (io.Reader, error) {
func CmdStream(cmd *exec.Cmd, input *string, atEnd func()) (io.Reader, error) {
if input != nil {
stdin, err := cmd.StdinPipe()
if err != nil {
if atEnd != nil {
atEnd()
}
return nil, err
}
// Write stdin if any
go func() {
_, _ = stdin.Write([]byte(*input))
stdin.Close()
}()
}
stdout, err := cmd.StdoutPipe()
if err != nil {
if atEnd != nil {
atEnd()
}
return nil, err
}
stderr, err := cmd.StderrPipe()
if err != nil {
if atEnd != nil {
atEnd()
}
return nil, err
}
pipeR, pipeW := io.Pipe()
@@ -258,6 +332,9 @@ func CmdStream(cmd *exec.Cmd) (io.Reader, error) {
} else {
pipeW.Close()
}
if atEnd != nil {
atEnd()
}
}()
// Run the command and return the pipe
if err := cmd.Start(); err != nil {
+3 -3
View File
@@ -14,7 +14,7 @@ import (
func TestCmdStreamLargeStderr(t *testing.T) {
cmd := exec.Command("/bin/sh", "-c", "dd if=/dev/zero bs=1k count=1000 of=/dev/stderr; echo hello")
out, err := CmdStream(cmd)
out, err := CmdStream(cmd, nil, nil)
if err != nil {
t.Fatalf("Failed to start command: %s", err)
}
@@ -35,7 +35,7 @@ func TestCmdStreamLargeStderr(t *testing.T) {
func TestCmdStreamBad(t *testing.T) {
badCmd := exec.Command("/bin/sh", "-c", "echo hello; echo >&2 error couldn\\'t reverse the phase pulser; exit 1")
out, err := CmdStream(badCmd)
out, err := CmdStream(badCmd, nil, nil)
if err != nil {
t.Fatalf("Failed to start command: %s", err)
}
@@ -50,7 +50,7 @@ func TestCmdStreamBad(t *testing.T) {
func TestCmdStreamGood(t *testing.T) {
cmd := exec.Command("/bin/sh", "-c", "echo hello; exit 0")
out, err := CmdStream(cmd)
out, err := CmdStream(cmd, nil, nil)
if err != nil {
t.Fatal(err)
}
+9 -3
View File
@@ -91,11 +91,17 @@ func LoadConfig(rootPath string) (*ConfigFile, error) {
}
authConfig := AuthConfig{}
origAuth := strings.Split(arr[0], " = ")
if len(origAuth) != 2 {
return &configFile, fmt.Errorf("Invalid Auth config file")
}
authConfig.Username, authConfig.Password, err = decodeAuth(origAuth[1])
if err != nil {
return &configFile, err
}
origEmail := strings.Split(arr[1], " = ")
if len(origEmail) != 2 {
return &configFile, fmt.Errorf("Invalid Auth config file")
}
authConfig.Email = origEmail[1]
authConfig.ServerAddress = IndexServerAddress()
configFile.Configs[IndexServerAddress()] = authConfig
@@ -239,7 +245,7 @@ func (config *ConfigFile) ResolveAuthConfig(registry string) AuthConfig {
// as there is only one auth entry which is fully qualified we need to start
// parsing and matching
swapProtocoll := func(url string) string {
swapProtocol := func(url string) string {
if strings.HasPrefix(url, "http:") {
return strings.Replace(url, "http:", "https:", 1)
}
@@ -253,9 +259,9 @@ func (config *ConfigFile) ResolveAuthConfig(registry string) AuthConfig {
if c, found := config.Configs[url]; found {
return c
}
registrySwappedProtocoll := swapProtocoll(url)
registrySwappedProtocol := swapProtocol(url)
// now try to match with the different protocol
if c, found := config.Configs[registrySwappedProtocoll]; found {
if c, found := config.Configs[registrySwappedProtocol]; found {
return c
}
return AuthConfig{}
+87 -8
View File
@@ -75,22 +75,34 @@ func TestCreateAccount(t *testing.T) {
}
}
func TestSameAuthDataPostSave(t *testing.T) {
root, err := ioutil.TempDir("", "docker-test")
func setupTempConfigFile() (*ConfigFile, error) {
root, err := ioutil.TempDir("", "docker-test-auth")
if err != nil {
t.Fatal(err)
return nil, err
}
configFile := &ConfigFile{
rootPath: root,
Configs: make(map[string]AuthConfig, 1),
Configs: make(map[string]AuthConfig),
}
configFile.Configs["testIndex"] = AuthConfig{
Username: "docker-user",
Password: "docker-pass",
Email: "docker@docker.io",
for _, registry := range []string{"testIndex", IndexServerAddress()} {
configFile.Configs[registry] = AuthConfig{
Username: "docker-user",
Password: "docker-pass",
Email: "docker@docker.io",
}
}
return configFile, nil
}
func TestSameAuthDataPostSave(t *testing.T) {
configFile, err := setupTempConfigFile()
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(configFile.rootPath)
err = SaveConfig(configFile)
if err != nil {
t.Fatal(err)
@@ -110,3 +122,70 @@ func TestSameAuthDataPostSave(t *testing.T) {
t.Fail()
}
}
func TestResolveAuthConfigIndexServer(t *testing.T) {
configFile, err := setupTempConfigFile()
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(configFile.rootPath)
for _, registry := range []string{"", IndexServerAddress()} {
resolved := configFile.ResolveAuthConfig(registry)
if resolved != configFile.Configs[IndexServerAddress()] {
t.Fail()
}
}
}
func TestResolveAuthConfigFullURL(t *testing.T) {
configFile, err := setupTempConfigFile()
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(configFile.rootPath)
registryAuth := AuthConfig{
Username: "foo-user",
Password: "foo-pass",
Email: "foo@example.com",
}
localAuth := AuthConfig{
Username: "bar-user",
Password: "bar-pass",
Email: "bar@example.com",
}
configFile.Configs["https://registry.example.com/v1/"] = registryAuth
configFile.Configs["http://localhost:8000/v1/"] = localAuth
validRegistries := map[string][]string{
"https://registry.example.com/v1/": {
"https://registry.example.com/v1/",
"http://registry.example.com/v1/",
"registry.example.com",
"registry.example.com/v1/",
},
"http://localhost:8000/v1/": {
"https://localhost:8000/v1/",
"http://localhost:8000/v1/",
"localhost:8000",
"localhost:8000/v1/",
},
}
for configKey, registries := range validRegistries {
for _, registry := range registries {
var (
configured AuthConfig
ok bool
)
resolved := configFile.ResolveAuthConfig(registry)
if configured, ok = configFile.Configs[configKey]; !ok {
t.Fail()
}
if resolved.Email != configured.Email {
t.Errorf("%s -> %q != %q\n", registry, resolved.Email, configured.Email)
}
}
}
}
+10 -6
View File
@@ -176,6 +176,8 @@ func (b *buildFile) CmdEnv(args string) error {
func (b *buildFile) CmdCmd(args string) error {
var cmd []string
if err := json.Unmarshal([]byte(args), &cmd); err != nil {
// If the unmarshal fails, it is not an error, we just use the
// args as a string.
utils.Debugf("Error unmarshalling: %s, setting cmd to /bin/sh -c", err)
cmd = []string{"/bin/sh", "-c", args}
}
@@ -187,6 +189,9 @@ func (b *buildFile) CmdCmd(args string) error {
}
func (b *buildFile) CmdExpose(args string) error {
if strings.Contains(args, ":") {
return fmt.Errorf("EXPOSE cannot be used to bind to a host ip or port")
}
ports := strings.Split(args, " ")
b.config.PortSpecs = append(ports, b.config.PortSpecs...)
return b.commit("", b.config.Cmd, fmt.Sprintf("EXPOSE %v", ports))
@@ -296,7 +301,7 @@ func (b *buildFile) addContext(container *Container, orig, dest string) error {
}
// First try to unpack the source as an archive
} else if err := UntarPath(origPath, destPath); err != nil {
utils.Debugf("Couldn't untar %s to %s: %s", origPath, destPath, err)
utils.Debugf("[tar] Not a directory nor a tar archive. Copying as a file. Untar error from %s to %s: %s", origPath, destPath, err)
// If that fails, just copy it as a regular file
if err := os.MkdirAll(path.Dir(destPath), 0755); err != nil {
return err
@@ -332,7 +337,7 @@ func (b *buildFile) CmdAdd(args string) error {
b.config.Image = b.image
// Create the container and start it
container, err := b.runtime.Create(b.config)
container, _, err := b.runtime.Create(b.config)
if err != nil {
return err
}
@@ -367,7 +372,7 @@ func (b *buildFile) run() (string, error) {
b.config.Image = b.image
// Create the container and start it
c, err := b.runtime.Create(b.config)
c, _, err := b.runtime.Create(b.config)
if err != nil {
return "", err
}
@@ -423,7 +428,7 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
}
}
container, err := b.runtime.Create(b.config)
container, _, err := b.runtime.Create(b.config)
if err != nil {
return err
}
@@ -458,9 +463,8 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
var lineContinuation = regexp.MustCompile(`\s*\\\s*\n`)
func (b *buildFile) Build(context io.Reader) (string, error) {
// FIXME: @creack any reason for using /tmp instead of ""?
// FIXME: @creack "name" is a terrible variable name
name, err := ioutil.TempDir("/tmp", "docker-build")
name, err := ioutil.TempDir("", "docker-build")
if err != nil {
return "", err
}
+6 -24
View File
@@ -229,10 +229,7 @@ func TestBuild(t *testing.T) {
func buildImage(context testContextTemplate, t *testing.T, srv *Server, useCache bool) *Image {
if srv == nil {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv = &Server{
@@ -370,10 +367,7 @@ func TestBuildEntrypoint(t *testing.T) {
// testing #1405 - config.Cmd does not get cleaned up if
// utilizing cache
func TestBuildEntrypointRunCleanup(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{
@@ -402,10 +396,7 @@ func TestBuildEntrypointRunCleanup(t *testing.T) {
}
func TestBuildImageWithCache(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{
@@ -433,10 +424,7 @@ func TestBuildImageWithCache(t *testing.T) {
}
func TestBuildImageWithoutCache(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{
@@ -464,10 +452,7 @@ func TestBuildImageWithoutCache(t *testing.T) {
}
func TestForbiddenContextPath(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{
@@ -513,10 +498,7 @@ func TestForbiddenContextPath(t *testing.T) {
}
func TestBuildADDFileNotFound(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{
+259 -49
View File
@@ -5,6 +5,7 @@ import (
"os"
"path/filepath"
"strings"
"syscall"
)
type ChangeType int
@@ -33,74 +34,283 @@ func (change *Change) String() string {
return fmt.Sprintf("%s %s", kind, change.Path)
}
func Changes(layers []string, rw string) ([]Change, error) {
type FileInfo struct {
parent *FileInfo
name string
stat syscall.Stat_t
children map[string]*FileInfo
}
func (root *FileInfo) LookUp(path string) *FileInfo {
parent := root
if path == "/" {
return root
}
pathElements := strings.Split(path, "/")
for _, elem := range pathElements {
if elem != "" {
child := parent.children[elem]
if child == nil {
return nil
}
parent = child
}
}
return parent
}
func (info *FileInfo) path() string {
if info.parent == nil {
return "/"
}
return filepath.Join(info.parent.path(), info.name)
}
func (info *FileInfo) unlink() {
if info.parent != nil {
delete(info.parent.children, info.name)
}
}
func (info *FileInfo) Remove(path string) bool {
child := info.LookUp(path)
if child != nil {
child.unlink()
return true
}
return false
}
func (info *FileInfo) isDir() bool {
return info.parent == nil || info.stat.Mode&syscall.S_IFDIR == syscall.S_IFDIR
}
func (info *FileInfo) addChanges(oldInfo *FileInfo, changes *[]Change) {
if oldInfo == nil {
// add
change := Change{
Path: info.path(),
Kind: ChangeAdd,
}
*changes = append(*changes, change)
}
// We make a copy so we can modify it to detect additions
// also, we only recurse on the old dir if the new info is a directory
// otherwise any previous delete/change is considered recursive
oldChildren := make(map[string]*FileInfo)
if oldInfo != nil && info.isDir() {
for k, v := range oldInfo.children {
oldChildren[k] = v
}
}
for name, newChild := range info.children {
oldChild, _ := oldChildren[name]
if oldChild != nil {
// change?
oldStat := &oldChild.stat
newStat := &newChild.stat
// Note: We can't compare inode or ctime or blocksize here, because these change
// when copying a file into a container. However, that is not generally a problem
// because any content change will change mtime, and any status change should
// be visible when actually comparing the stat fields. The only time this
// breaks down is if some code intentionally hides a change by setting
// back mtime
oldMtime := syscall.NsecToTimeval(oldStat.Mtim.Nano())
newMtime := syscall.NsecToTimeval(oldStat.Mtim.Nano())
if oldStat.Mode != newStat.Mode ||
oldStat.Uid != newStat.Uid ||
oldStat.Gid != newStat.Gid ||
oldStat.Rdev != newStat.Rdev ||
// Don't look at size for dirs, its not a good measure of change
(oldStat.Size != newStat.Size && oldStat.Mode&syscall.S_IFDIR != syscall.S_IFDIR) ||
oldMtime.Sec != newMtime.Sec ||
oldMtime.Usec != newMtime.Usec {
change := Change{
Path: newChild.path(),
Kind: ChangeModify,
}
*changes = append(*changes, change)
}
// Remove from copy so we can detect deletions
delete(oldChildren, name)
}
newChild.addChanges(oldChild, changes)
}
for _, oldChild := range oldChildren {
// delete
change := Change{
Path: oldChild.path(),
Kind: ChangeDelete,
}
*changes = append(*changes, change)
}
}
func (info *FileInfo) Changes(oldInfo *FileInfo) []Change {
var changes []Change
err := filepath.Walk(rw, func(path string, f os.FileInfo, err error) error {
info.addChanges(oldInfo, &changes)
return changes
}
func newRootFileInfo() *FileInfo {
root := &FileInfo{
name: "/",
children: make(map[string]*FileInfo),
}
return root
}
func applyLayer(root *FileInfo, layer string) error {
err := filepath.Walk(layer, func(layerPath string, f os.FileInfo, err error) error {
if err != nil {
return err
}
// Skip root
if layerPath == layer {
return nil
}
// rebase path
relPath, err := filepath.Rel(layer, layerPath)
if err != nil {
return err
}
relPath = filepath.Join("/", relPath)
// Skip AUFS metadata
if matched, err := filepath.Match("/.wh..wh.*", relPath); err != nil || matched {
if err != nil || !f.IsDir() {
return err
}
return filepath.SkipDir
}
var layerStat syscall.Stat_t
err = syscall.Lstat(layerPath, &layerStat)
if err != nil {
return err
}
file := filepath.Base(relPath)
// If there is a whiteout, then the file was removed
if strings.HasPrefix(file, ".wh.") {
originalFile := file[len(".wh."):]
deletePath := filepath.Join(filepath.Dir(relPath), originalFile)
root.Remove(deletePath)
} else {
// Added or changed file
existing := root.LookUp(relPath)
if existing != nil {
// Changed file
existing.stat = layerStat
if !existing.isDir() {
// Changed from dir to non-dir, delete all previous files
existing.children = make(map[string]*FileInfo)
}
} else {
// Added file
parent := root.LookUp(filepath.Dir(relPath))
if parent == nil {
return fmt.Errorf("collectFileInfo: Unexpectedly no parent for %s", relPath)
}
info := &FileInfo{
name: filepath.Base(relPath),
children: make(map[string]*FileInfo),
parent: parent,
stat: layerStat,
}
parent.children[info.name] = info
}
}
return nil
})
return err
}
func collectFileInfo(sourceDir string) (*FileInfo, error) {
root := newRootFileInfo()
err := filepath.Walk(sourceDir, func(path string, f os.FileInfo, err error) error {
if err != nil {
return err
}
// Rebase path
path, err = filepath.Rel(rw, path)
relPath, err := filepath.Rel(sourceDir, path)
if err != nil {
return err
}
path = filepath.Join("/", path)
relPath = filepath.Join("/", relPath)
// Skip root
if path == "/" {
if relPath == "/" {
return nil
}
// Skip AUFS metadata
if matched, err := filepath.Match("/.wh..wh.*", path); err != nil || matched {
parent := root.LookUp(filepath.Dir(relPath))
if parent == nil {
return fmt.Errorf("collectFileInfo: Unexpectedly no parent for %s", relPath)
}
info := &FileInfo{
name: filepath.Base(relPath),
children: make(map[string]*FileInfo),
parent: parent,
}
if err := syscall.Lstat(path, &info.stat); err != nil {
return err
}
change := Change{
Path: path,
}
parent.children[info.name] = info
// Find out what kind of modification happened
file := filepath.Base(path)
// If there is a whiteout, then the file was removed
if strings.HasPrefix(file, ".wh.") {
originalFile := file[len(".wh."):]
change.Path = filepath.Join(filepath.Dir(path), originalFile)
change.Kind = ChangeDelete
} else {
// Otherwise, the file was added
change.Kind = ChangeAdd
// ...Unless it already existed in a top layer, in which case, it's a modification
for _, layer := range layers {
stat, err := os.Stat(filepath.Join(layer, path))
if err != nil && !os.IsNotExist(err) {
return err
}
if err == nil {
// The file existed in the top layer, so that's a modification
// However, if it's a directory, maybe it wasn't actually modified.
// If you modify /foo/bar/baz, then /foo will be part of the changed files only because it's the parent of bar
if stat.IsDir() && f.IsDir() {
if f.Size() == stat.Size() && f.Mode() == stat.Mode() && f.ModTime() == stat.ModTime() {
// Both directories are the same, don't record the change
return nil
}
}
change.Kind = ChangeModify
break
}
}
}
// Record change
changes = append(changes, change)
return nil
})
if err != nil && !os.IsNotExist(err) {
if err != nil {
return nil, err
}
return changes, nil
return root, nil
}
// Compare a directory with an array of layer directories it was based on and
// generate an array of Change objects describing the changes
func ChangesLayers(newDir string, layers []string) ([]Change, error) {
newRoot, err := collectFileInfo(newDir)
if err != nil {
return nil, err
}
oldRoot := newRootFileInfo()
for i := len(layers) - 1; i >= 0; i-- {
layer := layers[i]
if err = applyLayer(oldRoot, layer); err != nil {
return nil, err
}
}
return newRoot.Changes(oldRoot), nil
}
// Compare two directories and generate an array of Change objects describing the changes
func ChangesDirs(newDir, oldDir string) ([]Change, error) {
oldRoot, err := collectFileInfo(oldDir)
if err != nil {
return nil, err
}
newRoot, err := collectFileInfo(newDir)
if err != nil {
return nil, err
}
return newRoot.Changes(oldRoot), nil
}
+185 -69
View File
@@ -6,6 +6,7 @@ import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
"flag"
"fmt"
"github.com/dotcloud/docker/auth"
@@ -22,6 +23,7 @@ import (
"os/signal"
"path/filepath"
"reflect"
"regexp"
"runtime"
"sort"
"strconv"
@@ -36,6 +38,10 @@ var (
VERSION string
)
var (
ErrConnectionRefused = errors.New("Can't connect to docker daemon. Is 'docker -d' running on this host?")
)
func (cli *DockerCli) getMethod(name string) (reflect.Method, bool) {
methodName := "Cmd" + strings.ToUpper(name[:1]) + strings.ToLower(name[1:])
return reflect.TypeOf(cli).MethodByName(methodName)
@@ -298,7 +304,7 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
}
cli.LoadConfigFile()
authconfig, ok := cli.configFile.Configs[auth.IndexServerAddress()]
authconfig, ok := cli.configFile.Configs[serverAddress]
if !ok {
authconfig = auth.AuthConfig{}
}
@@ -413,7 +419,7 @@ func (cli *DockerCli) CmdVersion(args ...string) error {
var out APIVersion
err = json.Unmarshal(body, &out)
if err != nil {
utils.Debugf("Error unmarshal: body: %s, err: %s\n", body, err)
utils.Errorf("Error unmarshal: body: %s, err: %s\n", body, err)
return err
}
if out.Version != "" {
@@ -460,6 +466,11 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
fmt.Fprintf(cli.out, "Containers: %d\n", out.Containers)
fmt.Fprintf(cli.out, "Images: %d\n", out.Images)
if out.DevmapperDataTotal != 0 {
fmt.Fprintf(cli.out, "Devmapper disk use: Data: %.1f/%.1f Metadata: %.1f/%.1f\n",
float64(out.DevmapperDataUsed)/(1024*1024), float64(out.DevmapperDataTotal)/(1024*1024),
float64(out.DevmapperMetadataUsed)/(1024*1024), float64(out.DevmapperMetadataTotal)/(1024*1024))
}
if out.Debug || os.Getenv("DEBUG") != "" {
fmt.Fprintf(cli.out, "Debug mode (server): %v\n", out.Debug)
fmt.Fprintf(cli.out, "Debug mode (client): %v\n", os.Getenv("DEBUG") != "")
@@ -468,6 +479,7 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
fmt.Fprintf(cli.out, "LXC Version: %s\n", out.LXCVersion)
fmt.Fprintf(cli.out, "EventsListeners: %d\n", out.NEventsListener)
fmt.Fprintf(cli.out, "Kernel Version: %s\n", out.KernelVersion)
fmt.Fprintf(cli.out, "Devmapper pool: %s\n", out.DevmapperPool)
}
if len(out.IndexServerAddress) != 0 {
@@ -735,6 +747,8 @@ func (cli *DockerCli) CmdHistory(args ...string) error {
func (cli *DockerCli) CmdRm(args ...string) error {
cmd := Subcmd("rm", "[OPTIONS] CONTAINER [CONTAINER...]", "Remove one or more containers")
v := cmd.Bool("v", false, "Remove the volumes associated to the container")
link := cmd.Bool("link", false, "Remove the specified link and not the underlying container")
if err := cmd.Parse(args); err != nil {
return nil
}
@@ -746,6 +760,9 @@ func (cli *DockerCli) CmdRm(args ...string) error {
if *v {
val.Set("v", "1")
}
if *link {
val.Set("link", "1")
}
for _, name := range cmd.Args() {
_, _, err := cli.call("DELETE", "/containers/"+name+"?"+val.Encode(), nil)
if err != nil {
@@ -795,11 +812,13 @@ func (cli *DockerCli) CmdImport(args ...string) error {
v.Set("tag", tag)
v.Set("fromSrc", src)
err := cli.stream("POST", "/images/create?"+v.Encode(), cli.in, cli.out, nil)
if err != nil {
return err
var in io.Reader
if src == "-" {
in = cli.in
}
return nil
return cli.stream("POST", "/images/create?"+v.Encode(), in, cli.out, nil)
}
func (cli *DockerCli) CmdPush(args ...string) error {
@@ -978,25 +997,19 @@ func (cli *DockerCli) CmdImages(args ...string) error {
out.Tag = "<none>"
}
if !*noTrunc {
out.ID = utils.TruncateID(out.ID)
}
if !*quiet {
fmt.Fprintf(w, "%s\t%s\t", out.Repository, out.Tag)
if *noTrunc {
fmt.Fprintf(w, "%s\t", out.ID)
} else {
fmt.Fprintf(w, "%s\t", utils.TruncateID(out.ID))
}
fmt.Fprintf(w, "%s ago\t", utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))))
fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t", out.Repository, out.Tag, out.ID, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))))
if out.VirtualSize > 0 {
fmt.Fprintf(w, "%s (virtual %s)\n", utils.HumanSize(out.Size), utils.HumanSize(out.VirtualSize))
} else {
fmt.Fprintf(w, "%s\n", utils.HumanSize(out.Size))
}
} else {
if *noTrunc {
fmt.Fprintln(w, out.ID)
} else {
fmt.Fprintln(w, utils.TruncateID(out.ID))
}
fmt.Fprintln(w, out.ID)
}
}
@@ -1010,10 +1023,10 @@ func (cli *DockerCli) CmdImages(args ...string) error {
func displayablePorts(ports []APIPort) string {
result := []string{}
for _, port := range ports {
if port.Type == "tcp" {
result = append(result, fmt.Sprintf("%d->%d", port.PublicPort, port.PrivatePort))
if port.IP == "" {
result = append(result, fmt.Sprintf("%d/%s", port.PublicPort, port.Type))
} else {
result = append(result, fmt.Sprintf("%d->%d/%s", port.PublicPort, port.PrivatePort, port.Type))
result = append(result, fmt.Sprintf("%s:%d->%d/%s", port.IP, port.PublicPort, port.PrivatePort, port.Type))
}
}
sort.Strings(result)
@@ -1066,7 +1079,7 @@ func (cli *DockerCli) CmdPs(args ...string) error {
}
w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
if !*quiet {
fmt.Fprint(w, "ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS")
fmt.Fprint(w, "ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS\tNAMES")
if *size {
fmt.Fprintln(w, "\tSIZE")
} else {
@@ -1075,12 +1088,17 @@ func (cli *DockerCli) CmdPs(args ...string) error {
}
for _, out := range outs {
if !*noTrunc {
out.ID = utils.TruncateID(out.ID)
}
if !*quiet {
if *noTrunc {
fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t", out.ID, out.Image, out.Command, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Status, displayablePorts(out.Ports))
} else {
fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t", utils.TruncateID(out.ID), out.Image, utils.Trunc(out.Command, 20), utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Status, displayablePorts(out.Ports))
if !*noTrunc {
out.Command = utils.Trunc(out.Command, 20)
for i := 0; i < len(out.Names); i++ {
out.Names[i] = utils.Trunc(out.Names[i], 10)
}
}
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s ago\t%s\t%s\t", out.ID, out.Image, out.Command, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Status, displayablePorts(out.Ports), strings.Join(out.Names, ","))
if *size {
if out.SizeRootFs > 0 {
fmt.Fprintf(w, "%s (virtual %s)\n", utils.HumanSize(out.SizeRw), utils.HumanSize(out.SizeRootFs))
@@ -1091,11 +1109,7 @@ func (cli *DockerCli) CmdPs(args ...string) error {
fmt.Fprint(w, "\n")
}
} else {
if *noTrunc {
fmt.Fprintln(w, out.ID)
} else {
fmt.Fprintln(w, utils.TruncateID(out.ID))
}
fmt.Fprintln(w, out.ID)
}
}
@@ -1105,6 +1119,64 @@ func (cli *DockerCli) CmdPs(args ...string) error {
return nil
}
func (cli *DockerCli) CmdLs(args ...string) error {
cmd := Subcmd("ls", "", "List links for containers")
flAll := cmd.Bool("a", false, "Show all links")
if err := cmd.Parse(args); err != nil {
return nil
}
v := url.Values{}
if *flAll {
v.Set("all", "1")
}
body, _, err := cli.call("GET", "/containers/links?"+v.Encode(), nil)
if err != nil {
return err
}
var links []APILink
if err := json.Unmarshal(body, &links); err != nil {
return err
}
w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
fmt.Fprintf(w, "NAME\tID\tIMAGE")
fmt.Fprintf(w, "\n")
sortLinks(links, func(i, j APILink) bool {
return len(i.Path) < len(j.Path)
})
for _, link := range links {
fmt.Fprintf(w, "%s\t%s\t%s", link.Path, utils.TruncateID(link.ContainerID), link.Image)
fmt.Fprintf(w, "\n")
}
w.Flush()
return nil
}
func (cli *DockerCli) CmdLink(args ...string) error {
cmd := Subcmd("link", "CURRENT_NAME NEW_NAME", "Link the container with a new name")
if err := cmd.Parse(args); err != nil {
return nil
}
if cmd.NArg() != 2 {
cmd.Usage()
return nil
}
body := map[string]string{
"currentName": cmd.Arg(0),
"newName": cmd.Arg(1),
}
_, _, err := cli.call("POST", "/containers/link", body)
if err != nil {
return err
}
return nil
}
func (cli *DockerCli) CmdCommit(args ...string) error {
cmd := Subcmd("commit", "[OPTIONS] CONTAINER [REPOSITORY [TAG]]", "Create a new image from a container's changes")
flComment := cmd.String("m", "", "Commit message")
@@ -1222,8 +1294,9 @@ func (cli *DockerCli) CmdLogs(args ...string) error {
cmd.Usage()
return nil
}
name := cmd.Arg(0)
if err := cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?logs=1&stdout=1&stderr=1", false, nil, cli.out); err != nil {
if err := cli.hijack("POST", "/containers/"+name+"/attach?logs=1&stdout=1&stderr=1", false, nil, cli.out, cli.err); err != nil {
return err
}
return nil
@@ -1238,8 +1311,8 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
cmd.Usage()
return nil
}
body, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil)
name := cmd.Arg(0)
body, _, err := cli.call("GET", "/containers/"+name+"/json", nil)
if err != nil {
return err
}
@@ -1256,7 +1329,7 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
if container.Config.Tty {
if err := cli.monitorTtySize(cmd.Arg(0)); err != nil {
return err
utils.Debugf("Error monitoring tty size: %s", err)
}
}
@@ -1266,7 +1339,7 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
v.Set("stdout", "1")
v.Set("stderr", "1")
if err := cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), container.Config.Tty, cli.in, cli.out); err != nil {
if err := cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), container.Config.Tty, cli.in, cli.out, cli.err); err != nil {
return err
}
return nil
@@ -1319,18 +1392,6 @@ func (cli *DockerCli) CmdSearch(args ...string) error {
// Ports type - Used to parse multiple -p flags
type ports []int
// ListOpts type
type ListOpts []string
func (opts *ListOpts) String() string {
return fmt.Sprint(*opts)
}
func (opts *ListOpts) Set(value string) error {
*opts = append(*opts, value)
return nil
}
// AttachOpts stores arguments to 'docker run -a', eg. which streams to attach to
type AttachOpts map[string]bool
@@ -1426,6 +1487,9 @@ func (cli *DockerCli) CmdRun(args ...string) error {
return nil
}
flRm := cmd.Lookup("rm")
autoRemove, _ := strconv.ParseBool(flRm.Value.String())
var containerIDFile *os.File
if len(hostConfig.ContainerIDFile) > 0 {
if _, err := ioutil.ReadFile(hostConfig.ContainerIDFile); err == nil {
@@ -1523,14 +1587,18 @@ func (cli *DockerCli) CmdRun(args ...string) error {
if config.AttachStdin || config.AttachStdout || config.AttachStderr {
if config.Tty {
if err := cli.monitorTtySize(runResult.ID); err != nil {
utils.Debugf("Error monitoring TTY size: %s\n", err)
// When running the test suite, there is no terminal, just pipes.
// Discard the error then.
if os.Getenv("TEST") != "1" {
utils.Errorf("Error monitoring TTY size: %s\n", err)
}
}
}
v := url.Values{}
v.Set("logs", "1")
v.Set("stream", "1")
var out io.Writer
var out, stderr io.Writer
if config.AttachStdin {
v.Set("stdin", "1")
@@ -1541,7 +1609,11 @@ func (cli *DockerCli) CmdRun(args ...string) error {
}
if config.AttachStderr {
v.Set("stderr", "1")
out = cli.out
if config.Tty {
stderr = cli.out
} else {
stderr = cli.err
}
}
signals := make(chan os.Signal, 1)
@@ -1555,7 +1627,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
}
}()
if err := cli.hijack("POST", "/containers/"+runResult.ID+"/attach?"+v.Encode(), config.Tty, cli.in, out); err != nil {
if err := cli.hijack("POST", "/containers/"+runResult.ID+"/attach?"+v.Encode(), config.Tty, cli.in, out, stderr); err != nil {
utils.Debugf("Error hijack: %s", err)
return err
}
@@ -1565,12 +1637,18 @@ func (cli *DockerCli) CmdRun(args ...string) error {
// Detached mode
<-wait
} else {
status, err := waitForExit(cli, runResult.ID)
status, err := getExitCode(cli, runResult.ID)
if err != nil {
return err
}
if autoRemove {
_, _, err = cli.call("DELETE", "/containers/"+runResult.ID, nil)
if err != nil {
return err
}
}
if status != 0 {
return &utils.StatusError{status}
return &utils.StatusError{Status: status}
}
}
@@ -1622,6 +1700,10 @@ func (cli *DockerCli) call(method, path string, data interface{}) ([]byte, int,
params = bytes.NewBuffer(buf)
}
// fixme: refactor client to support redirect
re := regexp.MustCompile("/+")
path = re.ReplaceAllString(path, "/")
req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", APIVERSION, path), params)
if err != nil {
return nil, -1, err
@@ -1636,7 +1718,7 @@ func (cli *DockerCli) call(method, path string, data interface{}) ([]byte, int,
dial, err := net.Dial(cli.proto, cli.addr)
if err != nil {
if strings.Contains(err.Error(), "connection refused") {
return nil, -1, fmt.Errorf("Can't connect to docker daemon. Is 'docker -d' running on this host?")
return nil, -1, ErrConnectionRefused
}
return nil, -1, err
}
@@ -1645,7 +1727,7 @@ func (cli *DockerCli) call(method, path string, data interface{}) ([]byte, int,
defer clientconn.Close()
if err != nil {
if strings.Contains(err.Error(), "connection refused") {
return nil, -1, fmt.Errorf("Can't connect to docker daemon. Is 'docker -d' running on this host?")
return nil, -1, ErrConnectionRefused
}
return nil, -1, err
}
@@ -1667,6 +1749,11 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer, h
if (method == "POST" || method == "PUT") && in == nil {
in = bytes.NewReader([]byte{})
}
// fixme: refactor client to support redirect
re := regexp.MustCompile("/+")
path = re.ReplaceAllString(path, "/")
req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", APIVERSION, path), in)
if err != nil {
return err
@@ -1722,7 +1809,10 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer, h
return nil
}
func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.ReadCloser, out io.Writer) error {
func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.ReadCloser, stdout, stderr io.Writer) error {
// fixme: refactor client to support redirect
re := regexp.MustCompile("/+")
path = re.ReplaceAllString(path, "/")
req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", APIVERSION, path), nil)
if err != nil {
@@ -1748,10 +1838,16 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
rwc, br := clientconn.Hijack()
defer rwc.Close()
var receiveStdout (chan error)
if out != nil {
receiveStdout = utils.Go(func() error {
_, err := io.Copy(out, br)
var receiveStdout chan error
if stdout != nil {
receiveStdout = utils.Go(func() (err error) {
// When TTY is ON, use regular copy
if setRawTerminal {
_, err = io.Copy(stdout, br)
} else {
_, err = utils.StdCopy(stdout, stderr, br)
}
utils.Debugf("[hijack] End of stdout")
return err
})
@@ -1772,27 +1868,27 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
}
if tcpc, ok := rwc.(*net.TCPConn); ok {
if err := tcpc.CloseWrite(); err != nil {
utils.Debugf("Couldn't send EOF: %s\n", err)
utils.Errorf("Couldn't send EOF: %s\n", err)
}
} else if unixc, ok := rwc.(*net.UnixConn); ok {
if err := unixc.CloseWrite(); err != nil {
utils.Debugf("Couldn't send EOF: %s\n", err)
utils.Errorf("Couldn't send EOF: %s\n", err)
}
}
// Discard errors due to pipe interruption
return nil
})
if out != nil {
if stdout != nil {
if err := <-receiveStdout; err != nil {
utils.Debugf("Error receiveStdout: %s", err)
utils.Errorf("Error receiveStdout: %s", err)
return err
}
}
if !cli.isTerminal {
if err := <-sendStdin; err != nil {
utils.Debugf("Error sendStdin: %s", err)
utils.Errorf("Error sendStdin: %s", err)
return err
}
}
@@ -1806,7 +1902,7 @@ func (cli *DockerCli) getTtySize() (int, int) {
}
ws, err := term.GetWinsize(cli.terminalFd)
if err != nil {
utils.Debugf("Error getting size: %s", err)
utils.Errorf("Error getting size: %s", err)
if ws == nil {
return 0, 0
}
@@ -1823,7 +1919,7 @@ func (cli *DockerCli) resizeTty(id string) {
v.Set("h", strconv.Itoa(height))
v.Set("w", strconv.Itoa(width))
if _, _, err := cli.call("POST", "/containers/"+id+"/resize?"+v.Encode(), nil); err != nil {
utils.Debugf("Error resize: %s", err)
utils.Errorf("Error resize: %s", err)
}
}
@@ -1864,7 +1960,11 @@ func (cli *DockerCli) LoadConfigFile() (err error) {
func waitForExit(cli *DockerCli, containerId string) (int, error) {
body, _, err := cli.call("POST", "/containers/"+containerId+"/wait", nil)
if err != nil {
return -1, err
// If we can't connect, then the daemon probably died.
if err != ErrConnectionRefused {
return -1, err
}
return -1, nil
}
var out APIWait
@@ -1874,6 +1974,22 @@ func waitForExit(cli *DockerCli, containerId string) (int, error) {
return out.StatusCode, nil
}
func getExitCode(cli *DockerCli, containerId string) (int, error) {
body, _, err := cli.call("GET", "/containers/"+containerId+"/json", nil)
if err != nil {
// If we can't connect, then the daemon probably died.
if err != ErrConnectionRefused {
return -1, err
}
return -1, nil
}
c := &Container{}
if err := json.Unmarshal(body, c); err != nil {
return -1, err
}
return c.State.ExitCode, nil
}
func NewDockerCli(in io.ReadCloser, out, err io.Writer, proto, addr string) *DockerCli {
var (
isTerminal = false
+142
View File
@@ -369,6 +369,110 @@ func TestRunAttachStdin(t *testing.T) {
}
}
// TestRunDetach checks attaching and detaching with the escape sequence.
func TestRunDetach(t *testing.T) {
stdin, stdinPipe := io.Pipe()
stdout, stdoutPipe := io.Pipe()
cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
defer cleanup(globalRuntime)
ch := make(chan struct{})
go func() {
defer close(ch)
cli.CmdRun("-i", "-t", unitTestImageID, "cat")
}()
setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
t.Fatal(err)
}
})
container := globalRuntime.List()[0]
setTimeout(t, "Escape sequence timeout", 5*time.Second, func() {
stdinPipe.Write([]byte{'', ''})
if err := stdinPipe.Close(); err != nil {
t.Fatal(err)
}
})
// wait for CmdRun to return
setTimeout(t, "Waiting for CmdRun timed out", 15*time.Second, func() {
<-ch
})
time.Sleep(500 * time.Millisecond)
if !container.State.Running {
t.Fatal("The detached container should be still running")
}
setTimeout(t, "Waiting for container to die timed out", 20*time.Second, func() {
container.Kill()
container.Wait()
})
}
// TestAttachDetach checks that attach in tty mode can be detached
func TestAttachDetach(t *testing.T) {
stdin, stdinPipe := io.Pipe()
stdout, stdoutPipe := io.Pipe()
cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
defer cleanup(globalRuntime)
go stdout.Read(make([]byte, 1024))
setTimeout(t, "Starting container timed out", 2*time.Second, func() {
if err := cli.CmdRun("-i", "-t", "-d", unitTestImageID, "cat"); err != nil {
t.Fatal(err)
}
})
container := globalRuntime.List()[0]
stdin, stdinPipe = io.Pipe()
stdout, stdoutPipe = io.Pipe()
cli = NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
ch := make(chan struct{})
go func() {
defer close(ch)
if err := cli.CmdAttach(container.ShortID()); err != nil {
t.Fatal(err)
}
}()
setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
t.Fatal(err)
}
})
setTimeout(t, "Escape sequence timeout", 5*time.Second, func() {
stdinPipe.Write([]byte{'', ''})
if err := stdinPipe.Close(); err != nil {
t.Fatal(err)
}
})
// wait for CmdRun to return
setTimeout(t, "Waiting for CmdAttach timed out", 15*time.Second, func() {
<-ch
})
time.Sleep(500 * time.Millisecond)
if !container.State.Running {
t.Fatal("The detached container should be still running")
}
setTimeout(t, "Waiting for container to die timedout", 5*time.Second, func() {
container.Kill()
container.Wait()
})
}
// Expected behaviour, the process stays alive when the client disconnects
func TestAttachDisconnect(t *testing.T) {
stdin, stdinPipe := io.Pipe()
@@ -438,3 +542,41 @@ func TestAttachDisconnect(t *testing.T) {
cStdin.Close()
container.Wait()
}
// Expected behaviour: container gets deleted automatically after exit
func TestRunAutoRemove(t *testing.T) {
t.Skip("Fixme. Skipping test for now, race condition")
stdout, stdoutPipe := io.Pipe()
cli := NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
defer cleanup(globalRuntime)
c := make(chan struct{})
go func() {
defer close(c)
if err := cli.CmdRun("-rm", unitTestImageID, "hostname"); err != nil {
t.Fatal(err)
}
}()
var temporaryContainerID string
setTimeout(t, "Reading command output time out", 2*time.Second, func() {
cmdOutput, err := bufio.NewReader(stdout).ReadString('\n')
if err != nil {
t.Fatal(err)
}
temporaryContainerID = cmdOutput
if err := closeWrap(stdout, stdoutPipe); err != nil {
t.Fatal(err)
}
})
setTimeout(t, "CmdRun timed out", 5*time.Second, func() {
<-c
})
time.Sleep(500 * time.Millisecond)
if len(globalRuntime.List()) > 0 {
t.Fatalf("failed to remove container automatically: container %s still exists", temporaryContainerID)
}
}
+18
View File
@@ -0,0 +1,18 @@
package docker
import (
"net"
)
type DaemonConfig struct {
Pidfile string
GraphPath string
ProtoAddresses []string
AutoRestart bool
EnableCors bool
Dns []string
EnableIptables bool
BridgeIface string
DefaultIp net.IP
InterContainerCommunication bool
}
+400 -170
View File
@@ -16,7 +16,6 @@ import (
"os/exec"
"path"
"path/filepath"
"strconv"
"strings"
"syscall"
"time"
@@ -43,6 +42,7 @@ type Container struct {
ResolvConfPath string
HostnamePath string
HostsPath string
FilesystemType string
cmd *exec.Cmd
stdout *utils.WriteBroadcaster
@@ -58,6 +58,8 @@ type Container struct {
// Store rw/ro in a separate structure to preserve reverse-compatibility on-disk.
// Easier than migrating older container configs :)
VolumesRW map[string]bool
activeLinks map[string]*Link
}
type Config struct {
@@ -70,7 +72,8 @@ type Config struct {
AttachStdin bool
AttachStdout bool
AttachStderr bool
PortSpecs []string
PortSpecs []string // Deprecated - Can be in the format of 8080/tcp
ExposedPorts map[Port]struct{}
Tty bool // Attach standard streams to a tty, including stdin if it is not closed.
OpenStdin bool // Open stdin
StdinOnce bool // If true, close stdin after the 1 attached client disconnects.
@@ -90,6 +93,8 @@ type HostConfig struct {
Binds []string
ContainerIDFile string
LxcConf []KeyValuePair
PortBindings map[Port][]PortBinding
Links []string
}
type BindMap struct {
@@ -107,6 +112,34 @@ type KeyValuePair struct {
Value string
}
type PortBinding struct {
HostIp string
HostPort string
}
// 80/tcp
type Port string
func (p Port) Proto() string {
return strings.Split(string(p), "/")[1]
}
func (p Port) Port() string {
return strings.Split(string(p), "/")[0]
}
func (p Port) Int() int {
i, err := parsePort(p.Port())
if err != nil {
panic(err)
}
return i
}
func NewPort(proto, port string) Port {
return Port(fmt.Sprintf("%s/%s", port, proto))
}
func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig, *flag.FlagSet, error) {
cmd := Subcmd("run", "[OPTIONS] IMAGE [COMMAND] [ARG...]", "Run a command in a new container")
if os.Getenv("TEST") != "" {
@@ -126,6 +159,7 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
flContainerIDFile := cmd.String("cidfile", "", "Write the container ID to the file")
flNetwork := cmd.Bool("n", true, "Enable networking for this container")
flPrivileged := cmd.Bool("privileged", false, "Give extended privileges to this container")
flAutoRemove := cmd.Bool("rm", false, "Automatically remove the container when it exits (incompatible with -d)")
if capabilities != nil && *flMemory > 0 && !capabilities.MemoryLimit {
//fmt.Fprintf(stdout, "WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.\n")
@@ -134,24 +168,32 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
flCpuShares := cmd.Int64("c", 0, "CPU shares (relative weight)")
var flPorts ListOpts
cmd.Var(&flPorts, "p", "Expose a container's port to the host (use 'docker port' to see the actual mapping)")
var flPublish utils.ListOpts
cmd.Var(&flPublish, "p", "Publish a container's port to the host (use 'docker port' to see the actual mapping)")
var flEnv ListOpts
var flExpose utils.ListOpts
cmd.Var(&flExpose, "expose", "Expose a port from the container without publishing it to your host")
var flEnv utils.ListOpts
cmd.Var(&flEnv, "e", "Set environment variables")
var flDns ListOpts
var flDns utils.ListOpts
cmd.Var(&flDns, "dns", "Set custom dns servers")
flVolumes := NewPathOpts()
cmd.Var(flVolumes, "v", "Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)")
flVolumesFrom := cmd.String("volumes-from", "", "Mount volumes from the specified container")
var flVolumesFrom utils.ListOpts
cmd.Var(&flVolumesFrom, "volumes-from", "Mount volumes from the specified container")
flEntrypoint := cmd.String("entrypoint", "", "Overwrite the default entrypoint of the image")
var flLxcOpts ListOpts
var flLxcOpts utils.ListOpts
cmd.Var(&flLxcOpts, "lxc-conf", "Add custom lxc options -lxc-conf=\"lxc.cgroup.cpuset.cpus = 0,1\"")
var flLinks utils.ListOpts
cmd.Var(&flLinks, "link", "Add link to another container (containerid:alias)")
if err := cmd.Parse(args); err != nil {
return nil, nil, cmd, err
}
@@ -172,6 +214,10 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
}
}
if *flDetach && *flAutoRemove {
return nil, nil, cmd, fmt.Errorf("Conflicting options: -rm and -d")
}
var binds []string
// add any bind targets to the list of container volumes
@@ -213,10 +259,28 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
hostname = parts[0]
domainname = parts[1]
}
ports, portBindings, err := parsePortSpecs(flPublish)
if err != nil {
return nil, nil, cmd, err
}
// Merge in exposed ports to the map of published ports
for _, e := range flExpose {
if strings.Contains(e, ":") {
return nil, nil, cmd, fmt.Errorf("Invalid port format for -expose: %s", e)
}
p := NewPort(splitProtoPort(e))
if _, exists := ports[p]; !exists {
ports[p] = struct{}{}
}
}
config := &Config{
Hostname: hostname,
Hostname: *flHostname,
Domainname: domainname,
PortSpecs: flPorts,
PortSpecs: nil, // Deprecated
ExposedPorts: ports,
User: *flUser,
Tty: *flTty,
NetworkDisabled: !*flNetwork,
@@ -231,15 +295,18 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
Dns: flDns,
Image: image,
Volumes: flVolumes,
VolumesFrom: *flVolumesFrom,
VolumesFrom: strings.Join(flVolumesFrom, ","),
Entrypoint: entrypoint,
Privileged: *flPrivileged,
WorkingDir: *flWorkingDir,
}
hostConfig := &HostConfig{
Binds: binds,
ContainerIDFile: *flContainerIDFile,
LxcConf: lxcConf,
PortBindings: portBindings,
Links: flLinks,
}
if capabilities != nil && *flMemory > 0 && !capabilities.SwapLimit {
@@ -254,48 +321,55 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
return config, hostConfig, cmd, nil
}
type PortMapping map[string]string
type PortMapping map[string]string // Deprecated
type NetworkSettings struct {
IPAddress string
IPPrefixLen int
Gateway string
Bridge string
PortMapping map[string]PortMapping
PortMapping map[string]PortMapping // Deprecated
Ports map[Port][]PortBinding
}
// returns a more easy to process description of the port mapping defined in the settings
func (settings *NetworkSettings) PortMappingAPI() []APIPort {
var mapping []APIPort
for private, public := range settings.PortMapping["Tcp"] {
pubint, _ := strconv.ParseInt(public, 0, 0)
privint, _ := strconv.ParseInt(private, 0, 0)
mapping = append(mapping, APIPort{
PrivatePort: privint,
PublicPort: pubint,
Type: "tcp",
})
}
for private, public := range settings.PortMapping["Udp"] {
pubint, _ := strconv.ParseInt(public, 0, 0)
privint, _ := strconv.ParseInt(private, 0, 0)
mapping = append(mapping, APIPort{
PrivatePort: privint,
PublicPort: pubint,
Type: "udp",
})
for port, bindings := range settings.Ports {
p, _ := parsePort(port.Port())
if len(bindings) == 0 {
mapping = append(mapping, APIPort{
PublicPort: int64(p),
Type: port.Proto(),
})
continue
}
for _, binding := range bindings {
p, _ := parsePort(port.Port())
h, _ := parsePort(binding.HostPort)
mapping = append(mapping, APIPort{
PrivatePort: int64(p),
PublicPort: int64(h),
Type: port.Proto(),
IP: binding.HostIp,
})
}
}
return mapping
}
// Inject the io.Reader at the given path. Note: do not close the reader
func (container *Container) Inject(file io.Reader, pth string) error {
// Make sure the directory exists
if err := os.MkdirAll(path.Join(container.rwPath(), path.Dir(pth)), 0755); err != nil {
if err := container.EnsureMounted(); err != nil {
return err
}
// Make sure the directory exists
if err := os.MkdirAll(path.Join(container.RootfsPath(), path.Dir(pth)), 0755); err != nil {
return err
}
// FIXME: Handle permissions/already existing dest
dest, err := os.Create(path.Join(container.rwPath(), pth))
dest, err := os.Create(path.Join(container.RootfsPath(), pth))
if err != nil {
return err
}
@@ -383,20 +457,20 @@ func (container *Container) startPty() error {
// Copy the PTYs to our broadcasters
go func() {
defer container.stdout.CloseWriters()
utils.Debugf("[startPty] Begin of stdout pipe")
utils.Debugf("startPty: begin of stdout pipe")
io.Copy(container.stdout, ptyMaster)
utils.Debugf("[startPty] End of stdout pipe")
utils.Debugf("startPty: end of stdout pipe")
}()
// stdin
if container.Config.OpenStdin {
container.cmd.Stdin = ptySlave
container.cmd.SysProcAttr = &syscall.SysProcAttr{Setctty: true, Setsid: true}
container.cmd.SysProcAttr.Setctty = true
go func() {
defer container.stdin.Close()
utils.Debugf("[startPty] Begin of stdin pipe")
utils.Debugf("startPty: begin of stdin pipe")
io.Copy(ptyMaster, container.stdin)
utils.Debugf("[startPty] End of stdin pipe")
utils.Debugf("startPty: end of stdin pipe")
}()
}
if err := container.cmd.Start(); err != nil {
@@ -416,9 +490,9 @@ func (container *Container) start() error {
}
go func() {
defer stdin.Close()
utils.Debugf("Begin of stdin pipe [start]")
utils.Debugf("start: begin of stdin pipe")
io.Copy(stdin, container.stdin)
utils.Debugf("End of stdin pipe [start]")
utils.Debugf("start: end of stdin pipe")
}()
}
return container.cmd.Start()
@@ -435,8 +509,8 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
errors <- err
} else {
go func() {
utils.Debugf("[start] attach stdin\n")
defer utils.Debugf("[end] attach stdin\n")
utils.Debugf("attach: stdin: begin")
defer utils.Debugf("attach: stdin: end")
// No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
if container.Config.StdinOnce && !container.Config.Tty {
defer cStdin.Close()
@@ -454,7 +528,7 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
_, err = io.Copy(cStdin, stdin)
}
if err != nil {
utils.Debugf("[error] attach stdin: %s\n", err)
utils.Errorf("attach: stdin: %s", err)
}
// Discard error, expecting pipe error
errors <- nil
@@ -468,20 +542,21 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
} else {
cStdout = p
go func() {
utils.Debugf("[start] attach stdout\n")
defer utils.Debugf("[end] attach stdout\n")
utils.Debugf("attach: stdout: begin")
defer utils.Debugf("attach: stdout: end")
// If we are in StdinOnce mode, then close stdin
if container.Config.StdinOnce {
if stdin != nil {
defer stdin.Close()
}
if stdinCloser != nil {
defer stdinCloser.Close()
}
if container.Config.StdinOnce && stdin != nil {
defer stdin.Close()
}
if stdinCloser != nil {
defer stdinCloser.Close()
}
_, err := io.Copy(stdout, cStdout)
if err == io.ErrClosedPipe {
err = nil
}
if err != nil {
utils.Debugf("[error] attach stdout: %s\n", err)
utils.Errorf("attach: stdout: %s", err)
}
errors <- err
}()
@@ -491,9 +566,8 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
if stdinCloser != nil {
defer stdinCloser.Close()
}
if cStdout, err := container.StdoutPipe(); err != nil {
utils.Debugf("Error stdout pipe")
utils.Errorf("attach: stdout pipe: %s", err)
} else {
io.Copy(&utils.NopWriter{}, cStdout)
}
@@ -506,20 +580,21 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
} else {
cStderr = p
go func() {
utils.Debugf("[start] attach stderr\n")
defer utils.Debugf("[end] attach stderr\n")
utils.Debugf("attach: stderr: begin")
defer utils.Debugf("attach: stderr: end")
// If we are in StdinOnce mode, then close stdin
if container.Config.StdinOnce {
if stdin != nil {
defer stdin.Close()
}
if stdinCloser != nil {
defer stdinCloser.Close()
}
if container.Config.StdinOnce && stdin != nil {
defer stdin.Close()
}
if stdinCloser != nil {
defer stdinCloser.Close()
}
_, err := io.Copy(stderr, cStderr)
if err == io.ErrClosedPipe {
err = nil
}
if err != nil {
utils.Debugf("[error] attach stderr: %s\n", err)
utils.Errorf("attach: stderr: %s", err)
}
errors <- err
}()
@@ -531,7 +606,7 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
}
if cStderr, err := container.StderrPipe(); err != nil {
utils.Debugf("Error stdout pipe")
utils.Errorf("attach: stdout pipe: %s", err)
} else {
io.Copy(&utils.NopWriter{}, cStderr)
}
@@ -545,24 +620,29 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
if cStderr != nil {
defer cStderr.Close()
}
// FIXME: how do clean up the stdin goroutine without the unwanted side effect
// FIXME: how to clean up the stdin goroutine without the unwanted side effect
// of closing the passed stdin? Add an intermediary io.Pipe?
for i := 0; i < nJobs; i += 1 {
utils.Debugf("Waiting for job %d/%d\n", i+1, nJobs)
utils.Debugf("attach: waiting for job %d/%d", i+1, nJobs)
if err := <-errors; err != nil {
utils.Debugf("Job %d returned error %s. Aborting all jobs\n", i+1, err)
utils.Errorf("attach: job %d returned error %s, aborting all jobs", i+1, err)
return err
}
utils.Debugf("Job %d completed successfully\n", i+1)
utils.Debugf("attach: job %d completed successfully", i+1)
}
utils.Debugf("All jobs completed successfully\n")
utils.Debugf("attach: all jobs completed successfully")
return nil
})
}
func (container *Container) Start(hostConfig *HostConfig) error {
func (container *Container) Start(hostConfig *HostConfig) (err error) {
container.State.Lock()
defer container.State.Unlock()
defer func() {
if err != nil {
container.cleanup()
}
}()
if hostConfig == nil { // in docker start of docker restart we want to reuse previous HostConfigFile
hostConfig, _ = container.ReadHostConfig()
@@ -577,7 +657,7 @@ func (container *Container) Start(hostConfig *HostConfig) error {
if container.runtime.networkManager.disabled {
container.Config.NetworkDisabled = true
} else {
if err := container.allocateNetwork(); err != nil {
if err := container.allocateNetwork(hostConfig); err != nil {
return err
}
}
@@ -639,21 +719,25 @@ func (container *Container) Start(hostConfig *HostConfig) error {
// Apply volumes from another container if requested
if container.Config.VolumesFrom != "" {
c := container.runtime.Get(container.Config.VolumesFrom)
if c == nil {
return fmt.Errorf("Container %s not found. Impossible to mount its volumes", container.ID)
}
for volPath, id := range c.Volumes {
if _, exists := container.Volumes[volPath]; exists {
continue
volumes := strings.Split(container.Config.VolumesFrom, ",")
for _, v := range volumes {
c := container.runtime.Get(v)
if c == nil {
return fmt.Errorf("Container %s not found. Impossible to mount its volumes", container.ID)
}
if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil {
return err
}
container.Volumes[volPath] = id
if isRW, exists := c.VolumesRW[volPath]; exists {
container.VolumesRW[volPath] = isRW
for volPath, id := range c.Volumes {
if _, exists := container.Volumes[volPath]; exists {
continue
}
if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil {
return err
}
container.Volumes[volPath] = id
if isRW, exists := c.VolumesRW[volPath]; exists {
container.VolumesRW[volPath] = isRW
}
}
}
}
@@ -665,9 +749,11 @@ func (container *Container) Start(hostConfig *HostConfig) error {
continue
}
var srcPath string
var isBindMount bool
srcRW := false
// If an external bind is defined for this volume, use that as a source
if bindMap, exists := binds[volPath]; exists {
isBindMount = true
srcPath = bindMap.SrcPath
if strings.ToLower(bindMap.Mode) == "rw" {
srcRW = true
@@ -691,7 +777,9 @@ func (container *Container) Start(hostConfig *HostConfig) error {
if err := os.MkdirAll(rootVolPath, 0755); err != nil {
return nil
}
if srcRW {
// Do not copy or change permissions if we are mounting from the host
if srcRW && !isBindMount {
volList, err := ioutil.ReadDir(rootVolPath)
if err != nil {
return err
@@ -702,22 +790,26 @@ func (container *Container) Start(hostConfig *HostConfig) error {
return err
}
if len(srcList) == 0 {
// If the source volume is empty copy files from the root into the volume
if err := CopyWithTar(rootVolPath, srcPath); err != nil {
return err
}
}
}
var stat syscall.Stat_t
if err := syscall.Stat(rootVolPath, &stat); err != nil {
return err
}
var srcStat syscall.Stat_t
if err := syscall.Stat(srcPath, &srcStat); err != nil {
return err
}
if stat.Uid != srcStat.Uid || stat.Gid != srcStat.Gid {
if err := os.Chown(srcPath, int(stat.Uid), int(stat.Gid)); err != nil {
return err
var stat syscall.Stat_t
if err := syscall.Stat(rootVolPath, &stat); err != nil {
return err
}
var srcStat syscall.Stat_t
if err := syscall.Stat(srcPath, &srcStat); err != nil {
return err
}
// Change the source volume's ownership if it differs from the root
// files that where just copied
if stat.Uid != srcStat.Uid || stat.Gid != srcStat.Gid {
if err := os.Chown(srcPath, int(stat.Uid), int(stat.Gid)); err != nil {
return err
}
}
}
}
}
@@ -728,6 +820,7 @@ func (container *Container) Start(hostConfig *HostConfig) error {
}
params := []string{
"lxc-start",
"-n", container.ID,
"-f", container.lxcConfigPath(),
"--",
@@ -755,6 +848,46 @@ func (container *Container) Start(hostConfig *HostConfig) error {
"-e", "container=lxc",
"-e", "HOSTNAME="+container.Config.Hostname,
)
// Init any links between the parent and children
runtime := container.runtime
children, err := runtime.Children(fmt.Sprintf("/%s", container.ID))
if err != nil {
return err
}
if len(children) > 0 {
container.activeLinks = make(map[string]*Link, len(children))
// If we encounter an error make sure that we rollback any network
// config and ip table changes
rollback := func() {
for _, link := range container.activeLinks {
link.Disable()
}
container.activeLinks = nil
}
for p, child := range children {
link, err := NewLink(container, child, p, runtime.networkManager.bridgeIface)
if err != nil {
rollback()
return err
}
container.activeLinks[link.Alias()] = link
if err := link.Enable(); err != nil {
rollback()
return err
}
for _, envVar := range link.ToEnv() {
params = append(params, "-e", envVar)
}
}
}
if container.Config.WorkingDir != "" {
workingDir := path.Clean(container.Config.WorkingDir)
utils.Debugf("[working dir] working dir is %s", workingDir)
@@ -776,7 +909,21 @@ func (container *Container) Start(hostConfig *HostConfig) error {
params = append(params, "--", container.Path)
params = append(params, container.Args...)
container.cmd = exec.Command("lxc-start", params...)
if RootIsShared() {
// lxc-start really needs / to be private, or all kinds of stuff break
// What we really want is to clone into a new namespace and then
// mount / MS_REC|MS_PRIVATE, but since we can't really clone or fork
// without exec in go we have to do this horrible shell hack...
shellString :=
"mount --make-rprivate /; exec " +
utils.ShellQuoteArguments(params)
params = []string{
"unshare", "-m", "--", "/bin/sh", "-c", shellString,
}
}
container.cmd = exec.Command(params[0], params[1:]...)
// Setup logging of stdout and stderr to disk
if err := container.runtime.LogToDisk(container.stdout, container.logPath("json"), "stdout"); err != nil {
@@ -786,7 +933,8 @@ func (container *Container) Start(hostConfig *HostConfig) error {
return err
}
var err error
container.cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
if container.Config.Tty {
err = container.startPty()
} else {
@@ -804,7 +952,7 @@ func (container *Container) Start(hostConfig *HostConfig) error {
container.ToDisk()
container.SaveHostConfig(hostConfig)
go container.monitor()
go container.monitor(hostConfig)
return nil
}
@@ -832,9 +980,14 @@ func (container *Container) Output() (output []byte, err error) {
return output, err
}
// StdinPipe() returns a pipe connected to the standard input of the container's
// active process.
//
// Container.StdinPipe returns a WriteCloser which can be used to feed data
// to the standard input of the container's active process.
// Container.StdoutPipe and Container.StderrPipe each return a ReadCloser
// which can be used to retrieve the standard output (and error) generated
// by the container's active process. The output (and error) are actually
// copied and delivered to all StdoutPipe and StderrPipe consumers, using
// a kind of "broadcaster".
func (container *Container) StdinPipe() (io.WriteCloser, error) {
return container.stdinPipe, nil
}
@@ -851,7 +1004,7 @@ func (container *Container) StderrPipe() (io.ReadCloser, error) {
return utils.NewBufReader(reader), nil
}
func (container *Container) allocateNetwork() error {
func (container *Container) allocateNetwork(hostConfig *HostConfig) error {
if container.Config.NetworkDisabled {
return nil
}
@@ -878,41 +1031,64 @@ func (container *Container) allocateNetwork() error {
}
}
var portSpecs []string
if !container.State.Ghost {
portSpecs = container.Config.PortSpecs
} else {
for backend, frontend := range container.NetworkSettings.PortMapping["Tcp"] {
portSpecs = append(portSpecs, fmt.Sprintf("%s:%s/tcp", frontend, backend))
if container.Config.PortSpecs != nil {
utils.Debugf("Migrating port mappings for container: %s", strings.Join(container.Config.PortSpecs, ", "))
if err := migratePortMappings(container.Config); err != nil {
return err
}
for backend, frontend := range container.NetworkSettings.PortMapping["Udp"] {
portSpecs = append(portSpecs, fmt.Sprintf("%s:%s/udp", frontend, backend))
container.Config.PortSpecs = nil
}
portSpecs := make(map[Port]struct{})
bindings := make(map[Port][]PortBinding)
if !container.State.Ghost {
if container.Config.ExposedPorts != nil {
portSpecs = container.Config.ExposedPorts
}
if hostConfig.PortBindings != nil {
bindings = hostConfig.PortBindings
}
} else {
if container.NetworkSettings.Ports != nil {
for port, binding := range container.NetworkSettings.Ports {
portSpecs[port] = struct{}{}
bindings[port] = binding
}
}
}
container.NetworkSettings.PortMapping = make(map[string]PortMapping)
container.NetworkSettings.PortMapping["Tcp"] = make(PortMapping)
container.NetworkSettings.PortMapping["Udp"] = make(PortMapping)
for _, spec := range portSpecs {
nat, err := iface.AllocatePort(spec)
if err != nil {
iface.Release()
return err
container.NetworkSettings.PortMapping = nil
for port := range portSpecs {
binding := bindings[port]
for i := 0; i < len(binding); i++ {
b := binding[i]
nat, err := iface.AllocatePort(port, b)
if err != nil {
iface.Release()
return err
}
utils.Debugf("Allocate port: %s:%s->%s", nat.Binding.HostIp, port, nat.Binding.HostPort)
binding[i] = nat.Binding
}
proto := strings.Title(nat.Proto)
backend, frontend := strconv.Itoa(nat.Backend), strconv.Itoa(nat.Frontend)
container.NetworkSettings.PortMapping[proto][backend] = frontend
bindings[port] = binding
}
container.SaveHostConfig(hostConfig)
container.NetworkSettings.Ports = bindings
container.network = iface
container.NetworkSettings.Bridge = container.runtime.networkManager.bridgeIface
container.NetworkSettings.IPAddress = iface.IPNet.IP.String()
container.NetworkSettings.IPPrefixLen, _ = iface.IPNet.Mask.Size()
container.NetworkSettings.Gateway = iface.Gateway.String()
return nil
}
func (container *Container) releaseNetwork() {
if container.Config.NetworkDisabled {
if container.Config.NetworkDisabled || container.network == nil {
return
}
container.network.Release()
@@ -920,7 +1096,7 @@ func (container *Container) releaseNetwork() {
container.NetworkSettings = &NetworkSettings{}
}
// FIXME: replace this with a control socket within docker-init
// FIXME: replace this with a control socket within dockerinit
func (container *Container) waitLxc() error {
for {
output, err := exec.Command("lxc-info", "-n", container.ID).CombinedOutput()
@@ -934,62 +1110,47 @@ func (container *Container) waitLxc() error {
}
}
func (container *Container) monitor() {
func (container *Container) monitor(hostConfig *HostConfig) {
// Wait for the program to exit
utils.Debugf("Waiting for process")
// If the command does not exists, try to wait via lxc
// If the command does not exist, try to wait via lxc
// (This probably happens only for ghost containers, i.e. containers that were running when Docker started)
if container.cmd == nil {
utils.Debugf("monitor: waiting for container %s using waitLxc", container.ID)
if err := container.waitLxc(); err != nil {
utils.Debugf("%s: Process: %s", container.ID, err)
// Discard the error as any signals or non 0 returns will generate an error
utils.Debugf("monitor: while waiting for container %s, waitLxc had a problem: %s", container.ShortID(), err)
}
} else {
utils.Debugf("monitor: waiting for container %s using cmd.Wait", container.ID)
if err := container.cmd.Wait(); err != nil {
// Discard the error as any signals or non 0 returns will generate an error
utils.Debugf("%s: Process: %s", container.ID, err)
// Since non-zero exit status and signal terminations will cause err to be non-nil,
// we have to actually discard it. Still, log it anyway, just in case.
utils.Debugf("monitor: cmd.Wait reported exit status %s for container %s", err, container.ID)
}
}
utils.Debugf("Process finished")
if container.runtime != nil && container.runtime.srv != nil {
container.runtime.srv.LogEvent("die", container.ShortID(), container.runtime.repositories.ImageName(container.Image))
}
utils.Debugf("monitor: container %s finished", container.ID)
exitCode := -1
if container.cmd != nil {
exitCode = container.cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
}
// Report status back
container.State.setStopped(exitCode)
if container.runtime != nil && container.runtime.srv != nil {
container.runtime.srv.LogEvent("die", container.ShortID(), container.runtime.repositories.ImageName(container.Image))
}
// Cleanup
container.releaseNetwork()
if container.Config.OpenStdin {
if err := container.stdin.Close(); err != nil {
utils.Debugf("%s: Error close stdin: %s", container.ID, err)
}
}
if err := container.stdout.CloseWriters(); err != nil {
utils.Debugf("%s: Error close stdout: %s", container.ID, err)
}
if err := container.stderr.CloseWriters(); err != nil {
utils.Debugf("%s: Error close stderr: %s", container.ID, err)
}
if container.ptyMaster != nil {
if err := container.ptyMaster.Close(); err != nil {
utils.Debugf("%s: Error closing Pty master: %s", container.ID, err)
}
}
if err := container.Unmount(); err != nil {
log.Printf("%v: Failed to umount filesystem: %v", container.ID, err)
}
container.cleanup()
// Re-create a brand new stdin pipe once the container exited
if container.Config.OpenStdin {
container.stdin, container.stdinPipe = io.Pipe()
}
// Report status back
container.State.setStopped(exitCode)
// Release the lock
close(container.waitLock)
@@ -1004,6 +1165,39 @@ func (container *Container) monitor() {
}
}
func (container *Container) cleanup() {
container.releaseNetwork()
// Disable all active links
if container.activeLinks != nil {
for _, link := range container.activeLinks {
link.Disable()
}
}
if container.Config.OpenStdin {
if err := container.stdin.Close(); err != nil {
utils.Errorf("%s: Error close stdin: %s", container.ID, err)
}
}
if err := container.stdout.CloseWriters(); err != nil {
utils.Errorf("%s: Error close stdout: %s", container.ID, err)
}
if err := container.stderr.CloseWriters(); err != nil {
utils.Errorf("%s: Error close stderr: %s", container.ID, err)
}
if container.ptyMaster != nil {
if err := container.ptyMaster.Close(); err != nil {
utils.Errorf("%s: Error closing Pty master: %s", container.ID, err)
}
}
if err := container.Unmount(); err != nil {
log.Printf("%v: Failed to umount filesystem: %v", container.ID, err)
}
}
func (container *Container) kill() error {
if !container.State.Running {
return nil
@@ -1092,7 +1286,15 @@ func (container *Container) Resize(h, w int) error {
}
func (container *Container) ExportRw() (Archive, error) {
return Tar(container.rwPath(), Uncompressed)
if err := container.EnsureMounted(); err != nil {
return nil, err
}
image, err := container.GetImage()
if err != nil {
return nil, err
}
return image.ExportChanges(container.runtime, container.RootfsPath(), container.rwPath(), container.ID)
}
func (container *Container) RwChecksum() (string, error) {
@@ -1134,20 +1336,33 @@ func (container *Container) EnsureMounted() error {
return container.Mount()
}
func (container *Container) EnsureUnmounted() error {
if mounted, err := container.Mounted(); err != nil {
return err
} else if !mounted {
return nil
}
return container.Unmount()
}
func (container *Container) Mount() error {
image, err := container.GetImage()
if err != nil {
return err
}
return image.Mount(container.RootfsPath(), container.rwPath())
return image.Mount(container.runtime, container.RootfsPath(), container.rwPath(), container.ID)
}
func (container *Container) Changes() ([]Change, error) {
if err := container.EnsureMounted(); err != nil {
return nil, err
}
image, err := container.GetImage()
if err != nil {
return nil, err
}
return image.Changes(container.rwPath())
return image.Changes(container.runtime, container.RootfsPath(), container.rwPath(), container.ID)
}
func (container *Container) GetImage() (*Image, error) {
@@ -1158,11 +1373,20 @@ func (container *Container) GetImage() (*Image, error) {
}
func (container *Container) Mounted() (bool, error) {
return Mounted(container.RootfsPath())
image, err := container.GetImage()
if err != nil {
return false, err
}
return image.Mounted(container.runtime, container.RootfsPath(), container.rwPath())
}
func (container *Container) Unmount() error {
return Unmount(container.RootfsPath())
image, err := container.GetImage()
if err != nil {
return err
}
err = image.Unmount(container.runtime, container.RootfsPath(), container.ID)
return err
}
// ShortID returns a shorthand version of the container's id for convenience.
@@ -1250,5 +1474,11 @@ func (container *Container) Copy(resource string) (Archive, error) {
filter = []string{path.Base(basePath)}
basePath = path.Dir(basePath)
}
return TarFilter(basePath, Uncompressed, filter)
return TarFilter(basePath, Uncompressed, filter, true, nil)
}
// Returns true if the container exposes a certain port
func (container *Container) Exposes(p Port) bool {
_, exists := container.Config.ExposedPorts[p]
return exists
}
+134 -62
View File
@@ -18,7 +18,7 @@ import (
func TestIDFormat(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container1, err := runtime.Create(
container1, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/sh", "-c", "echo hello world"},
@@ -388,7 +388,7 @@ func TestRun(t *testing.T) {
func TestOutput(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"echo", "-n", "foobar"},
@@ -407,11 +407,32 @@ func TestOutput(t *testing.T) {
}
}
func TestContainerNetwork(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"ping", "-c", "1", "127.0.0.1"},
},
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container)
if err := container.Run(); err != nil {
t.Fatal(err)
}
if container.State.ExitCode != 0 {
t.Errorf("Unexpected ping 127.0.0.1 exit code %d (expected 0)", container.State.ExitCode)
}
}
func TestKillDifferentUser(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"cat"},
OpenStdin: true,
@@ -471,7 +492,7 @@ func TestCreateVolume(t *testing.T) {
if err != nil {
t.Fatal(err)
}
c, err := runtime.Create(config)
c, _, err := runtime.Create(config)
if err != nil {
t.Fatal(err)
}
@@ -486,7 +507,7 @@ func TestCreateVolume(t *testing.T) {
func TestKill(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"sleep", "2"},
},
@@ -530,7 +551,7 @@ func TestExitCode(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
trueContainer, err := runtime.Create(&Config{
trueContainer, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/true", ""},
})
@@ -545,7 +566,7 @@ func TestExitCode(t *testing.T) {
t.Errorf("Unexpected exit code %d (expected 0)", trueContainer.State.ExitCode)
}
falseContainer, err := runtime.Create(&Config{
falseContainer, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/false", ""},
})
@@ -564,7 +585,7 @@ func TestExitCode(t *testing.T) {
func TestRestart(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"echo", "-n", "foobar"},
},
@@ -594,7 +615,7 @@ func TestRestart(t *testing.T) {
func TestRestartStdin(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"cat"},
@@ -672,7 +693,7 @@ func TestUser(t *testing.T) {
defer nuke(runtime)
// Default user must be root
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"id"},
},
@@ -690,7 +711,7 @@ func TestUser(t *testing.T) {
}
// Set a username
container, err = runtime.Create(&Config{
container, _, err = runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"id"},
@@ -710,7 +731,7 @@ func TestUser(t *testing.T) {
}
// Set a UID
container, err = runtime.Create(&Config{
container, _, err = runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"id"},
@@ -730,7 +751,7 @@ func TestUser(t *testing.T) {
}
// Set a different user by uid
container, err = runtime.Create(&Config{
container, _, err = runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"id"},
@@ -752,7 +773,7 @@ func TestUser(t *testing.T) {
}
// Set a different user by username
container, err = runtime.Create(&Config{
container, _, err = runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"id"},
@@ -772,7 +793,7 @@ func TestUser(t *testing.T) {
}
// Test an wrong username
container, err = runtime.Create(&Config{
container, _, err = runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"id"},
@@ -793,7 +814,7 @@ func TestMultipleContainers(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container1, err := runtime.Create(&Config{
container1, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"sleep", "2"},
},
@@ -803,7 +824,7 @@ func TestMultipleContainers(t *testing.T) {
}
defer runtime.Destroy(container1)
container2, err := runtime.Create(&Config{
container2, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"sleep", "2"},
},
@@ -847,7 +868,7 @@ func TestMultipleContainers(t *testing.T) {
func TestStdin(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"cat"},
@@ -892,7 +913,7 @@ func TestStdin(t *testing.T) {
func TestTty(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"cat"},
@@ -937,7 +958,7 @@ func TestTty(t *testing.T) {
func TestEnv(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"env"},
},
@@ -986,7 +1007,7 @@ func TestEnv(t *testing.T) {
func TestEntrypoint(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Entrypoint: []string{"/bin/echo"},
@@ -1009,7 +1030,7 @@ func TestEntrypoint(t *testing.T) {
func TestEntrypointNoCmd(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Entrypoint: []string{"/bin/echo", "foobar"},
@@ -1060,7 +1081,7 @@ func TestLXCConfig(t *testing.T) {
cpuMin := 100
cpuMax := 10000
cpu := cpuMin + rand.Intn(cpuMax-cpuMin)
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/true"},
@@ -1072,7 +1093,6 @@ func TestLXCConfig(t *testing.T) {
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container)
container.generateLXCConfig(nil)
grepFile(t, container.lxcConfigPath(), "lxc.utsname = foobar")
grepFile(t, container.lxcConfigPath(),
@@ -1084,7 +1104,7 @@ func TestLXCConfig(t *testing.T) {
func TestCustomLxcConfig(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/true"},
@@ -1115,7 +1135,7 @@ func BenchmarkRunSequencial(b *testing.B) {
runtime := mkRuntime(b)
defer nuke(runtime)
for i := 0; i < b.N; i++ {
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"echo", "-n", "foo"},
},
@@ -1147,7 +1167,7 @@ func BenchmarkRunParallel(b *testing.B) {
complete := make(chan error)
tasks = append(tasks, complete)
go func(i int, complete chan error) {
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"echo", "-n", "foo"},
},
@@ -1189,7 +1209,7 @@ func BenchmarkRunParallel(b *testing.B) {
}
func tempDir(t *testing.T) string {
tmpDir, err := ioutil.TempDir("", "docker-test")
tmpDir, err := ioutil.TempDir("", "docker-test-container")
if err != nil {
t.Fatal(err)
}
@@ -1202,7 +1222,7 @@ func TestCopyVolumeUidGid(t *testing.T) {
defer nuke(r)
// Add directory not owned by root
container1, _, _ := mkContainer(r, []string{"_", "/bin/sh", "-c", "mkdir -p /hello && chown daemon.daemon /hello"}, t)
container1, _, _ := mkContainer(r, []string{"_", "/bin/sh", "-c", "mkdir -p /hello && touch /hello/test.txt && chown daemon.daemon /hello"}, t)
defer r.Destroy(container1)
if container1.State.Running {
@@ -1227,18 +1247,10 @@ func TestCopyVolumeUidGid(t *testing.T) {
// Test that the uid and gid is copied from the image to the volume
tmpDir1 := tempDir(t)
defer os.RemoveAll(tmpDir1)
stdout1, _ := runContainer(r, []string{"-v", fmt.Sprintf("%s:/hello", tmpDir1), img.ID, "stat", "-c", "%U %G", "/hello"}, t)
stdout1, _ := runContainer(r, []string{"-v", "/hello", img.ID, "stat", "-c", "%U %G", "/hello"}, t)
if !strings.Contains(stdout1, "daemon daemon") {
t.Fatal("Container failed to transfer uid and gid to volume")
}
// Test that the uid and gid is not copied from the image when the volume is read only
tmpDir2 := tempDir(t)
defer os.RemoveAll(tmpDir1)
stdout2, _ := runContainer(r, []string{"-v", fmt.Sprintf("%s:/hello:ro", tmpDir2), img.ID, "stat", "-c", "%U %G", "/hello"}, t)
if strings.Contains(stdout2, "daemon daemon") {
t.Fatal("Container transfered uid and gid to volume")
}
}
// Test for #1582
@@ -1272,27 +1284,10 @@ func TestCopyVolumeContent(t *testing.T) {
// Test that the content is copied from the image to the volume
tmpDir1 := tempDir(t)
defer os.RemoveAll(tmpDir1)
stdout1, _ := runContainer(r, []string{"-v", fmt.Sprintf("%s:/hello", tmpDir1), img.ID, "find", "/hello"}, t)
stdout1, _ := runContainer(r, []string{"-v", "/hello", img.ID, "find", "/hello"}, t)
if !(strings.Contains(stdout1, "/hello/local/world") && strings.Contains(stdout1, "/hello/local")) {
t.Fatal("Container failed to transfer content to volume")
}
// Test that the content is not copied when the volume is readonly
tmpDir2 := tempDir(t)
defer os.RemoveAll(tmpDir2)
stdout2, _ := runContainer(r, []string{"-v", fmt.Sprintf("%s:/hello:ro", tmpDir2), img.ID, "find", "/hello"}, t)
if strings.Contains(stdout2, "/hello/local/world") || strings.Contains(stdout2, "/hello/local") {
t.Fatal("Container transfered content to readonly volume")
}
// Test that the content is not copied when the volume is non-empty
tmpDir3 := tempDir(t)
defer os.RemoveAll(tmpDir3)
writeFile(path.Join(tmpDir3, "touch-me"), "", t)
stdout3, _ := runContainer(r, []string{"-v", fmt.Sprintf("%s:/hello:rw", tmpDir3), img.ID, "find", "/hello"}, t)
if strings.Contains(stdout3, "/hello/local/world") || strings.Contains(stdout3, "/hello/local") || !strings.Contains(stdout3, "/hello/touch-me") {
t.Fatal("Container transfered content to non-empty volume")
}
}
func TestBindMounts(t *testing.T) {
@@ -1322,7 +1317,7 @@ func TestBindMounts(t *testing.T) {
func TestVolumesFromReadonlyMount(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/echo", "-n", "foobar"},
@@ -1341,7 +1336,7 @@ func TestVolumesFromReadonlyMount(t *testing.T) {
t.Fail()
}
container2, err := runtime.Create(
container2, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/echo", "-n", "foobar"},
@@ -1377,7 +1372,7 @@ func TestRestartWithVolumes(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"echo", "-n", "foobar"},
Volumes: map[string]struct{}{"/test": {}},
@@ -1420,7 +1415,7 @@ func TestVolumesFromWithVolumes(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"sh", "-c", "echo -n bar > /test/foo"},
Volumes: map[string]struct{}{"/test": {}},
@@ -1447,7 +1442,7 @@ func TestVolumesFromWithVolumes(t *testing.T) {
t.Fail()
}
container2, err := runtime.Create(
container2, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"cat", "/test/foo"},
@@ -1488,7 +1483,7 @@ func TestOnlyLoopbackExistsWhenUsingDisableNetworkOption(t *testing.T) {
if err != nil {
t.Fatal(err)
}
c, err := runtime.Create(config)
c, _, err := runtime.Create(config)
if err != nil {
t.Fatal(err)
}
@@ -1549,3 +1544,80 @@ func TestPrivilegedCannotMount(t *testing.T) {
t.Fatal("Could mount into secure container")
}
}
func TestMultipleVolumesFrom(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"sh", "-c", "echo -n bar > /test/foo"},
Volumes: map[string]struct{}{"/test": {}},
},
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container)
for key := range container.Config.Volumes {
if key != "/test" {
t.Fail()
}
}
_, err = container.Output()
if err != nil {
t.Fatal(err)
}
expected := container.Volumes["/test"]
if expected == "" {
t.Fail()
}
container2, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"sh", "-c", "echo -n bar > /other/foo"},
Volumes: map[string]struct{}{"/other": {}},
},
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container2)
for key := range container2.Config.Volumes {
if key != "/other" {
t.FailNow()
}
}
if _, err := container2.Output(); err != nil {
t.Fatal(err)
}
container3, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/echo", "-n", "foobar"},
VolumesFrom: strings.Join([]string{container.ID, container2.ID}, ","),
})
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container3)
if _, err := container3.Output(); err != nil {
t.Fatal(err)
}
t.Log(container3.Volumes)
if container3.Volumes["/test"] != container.Volumes["/test"] {
t.Fail()
}
if container3.Volumes["/other"] != container2.Volumes["/other"] {
t.Fail()
}
}
@@ -0,0 +1,23 @@
# [PackageDev] target_format: plist, ext: tmLanguage
---
name: Dockerfile
scopeName: source.dockerfile
uuid: a39d8795-59d2-49af-aa00-fe74ee29576e
patterns:
# Keywords
- name: keyword.control.dockerfile
match: ^\s*(FROM|MAINTAINER|RUN|CMD|EXPOSE|ENV|ADD)\s
- name: keyword.operator.dockerfile
match: ^\s*(ENTRYPOINT|VOLUME|USER|WORKDIR)\s
# String
- name: string.quoted.double.dockerfile
begin: "\""
end: "\""
patterns:
- name: constant.character.escaped.dockerfile
match: \\.
# Comment
- name: comment.block.dockerfile
match: ^\s*#.*$
...
@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>name</key>
<string>Dockerfile</string>
<key>patterns</key>
<array>
<dict>
<key>match</key>
<string>^\s*(FROM|MAINTAINER|RUN|CMD|EXPOSE|ENV|ADD)\s</string>
<key>name</key>
<string>keyword.control.dockerfile</string>
</dict>
<dict>
<key>match</key>
<string>^\s*(ENTRYPOINT|VOLUME|USER|WORKDIR)\s</string>
<key>name</key>
<string>keyword.operator.dockerfile</string>
</dict>
<dict>
<key>begin</key>
<string>"</string>
<key>end</key>
<string>"</string>
<key>name</key>
<string>string.quoted.double.dockerfile</string>
<key>patterns</key>
<array>
<dict>
<key>match</key>
<string>\\.</string>
<key>name</key>
<string>constant.character.escaped.dockerfile</string>
</dict>
</array>
</dict>
<dict>
<key>match</key>
<string>^\s*#.*$</string>
<key>name</key>
<string>comment.block.dockerfile</string>
</dict>
</array>
<key>scopeName</key>
<string>source.dockerfile</string>
<key>uuid</key>
<string>a39d8795-59d2-49af-aa00-fe74ee29576e</string>
</dict>
</plist>
@@ -0,0 +1 @@
Asbjorn Enge <asbjorn@hanafjedle.net> (@asbjornenge)
+9
View File
@@ -0,0 +1,9 @@
# Dockerfile.tmLanguage
Pretty basic Dockerfile.tmLanguage for Sublime Text syntax highlighting.
PR's with syntax updates, suggestions etc. are all very much appreciated!
I'll get to making this installable via Package Control soon!
enjoy.
+1 -1
View File
@@ -1 +1 @@
Kawsar Saiyeed <kawsar.saiyeed@projiris.com>
Tianon Gravi <admwiggin@gmail.com> (@tianon)
+1 -1
View File
@@ -341,7 +341,7 @@ _docker_pull()
_docker_push()
{
return
__docker_image_repos
}
_docker_restart()
+242
View File
@@ -0,0 +1,242 @@
#compdef docker
#
# zsh completion for docker (http://docker.io)
#
# version: 0.2.2
# author: Felix Riedel
# license: BSD License
# github: https://github.com/felixr/docker-zsh-completion
#
__parse_docker_list() {
sed -e '/^ID/d' -e 's/[ ]\{2,\}/|/g' -e 's/ \([hdwm]\)\(inutes\|ays\|ours\|eeks\)/\1/' | awk ' BEGIN {FS="|"} { printf("%s:%7s, %s\n", $1, $4, $2)}'
}
__docker_stoppedcontainers() {
local expl
declare -a stoppedcontainers
stoppedcontainers=(${(f)"$(docker ps -a | grep --color=never 'Exit' | __parse_docker_list )"})
_describe -t containers-stopped "Stopped Containers" stoppedcontainers
}
__docker_runningcontainers() {
local expl
declare -a containers
containers=(${(f)"$(docker ps | __parse_docker_list)"})
_describe -t containers-active "Running Containers" containers
}
__docker_containers () {
__docker_stoppedcontainers
__docker_runningcontainers
}
__docker_images () {
local expl
declare -a images
images=(${(f)"$(docker images | awk '(NR > 1){printf("%s\\:%s\n", $1,$2)}')"})
images=($images ${(f)"$(docker images | awk '(NR > 1){printf("%s:%-15s in %s\n", $3,$2,$1)}')"})
_describe -t docker-images "Images" images
}
__docker_tags() {
local expl
declare -a tags
tags=(${(f)"$(docker images | awk '(NR>1){print $2}'| sort | uniq)"})
_describe -t docker-tags "tags" tags
}
__docker_search() {
# declare -a dockersearch
local cache_policy
zstyle -s ":completion:${curcontext}:" cache-policy cache_policy
if [[ -z "$cache_policy" ]]; then
zstyle ":completion:${curcontext}:" cache-policy __docker_caching_policy
fi
local searchterm cachename
searchterm="${words[$CURRENT]%/}"
cachename=_docker-search-$searchterm
local expl
local -a result
if ( [[ ${(P)+cachename} -eq 0 ]] || _cache_invalid ${cachename#_} ) \
&& ! _retrieve_cache ${cachename#_}; then
_message "Searching for ${searchterm}..."
result=(${(f)"$(docker search ${searchterm} | awk '(NR>2){print $1}')"})
_store_cache ${cachename#_} result
fi
_wanted dockersearch expl 'Available images' compadd -a result
}
__docker_caching_policy()
{
# oldp=( "$1"(Nmh+24) ) # 24 hour
oldp=( "$1"(Nmh+1) ) # 24 hour
(( $#oldp ))
}
__docker_repositories () {
local expl
declare -a repos
repos=(${(f)"$(docker images | sed -e '1d' -e 's/[ ].*//' | sort | uniq)"})
_describe -t docker-repos "Repositories" repos
}
__docker_commands () {
# local -a _docker_subcommands
local cache_policy
zstyle -s ":completion:${curcontext}:" cache-policy cache_policy
if [[ -z "$cache_policy" ]]; then
zstyle ":completion:${curcontext}:" cache-policy __docker_caching_policy
fi
if ( [[ ${+_docker_subcommands} -eq 0 ]] || _cache_invalid docker_subcommands) \
&& ! _retrieve_cache docker_subcommands;
then
_docker_subcommands=(${${(f)"$(_call_program commands
docker 2>&1 | sed -e '1,6d' -e '/^[ ]*$/d' -e 's/[ ]*\([^ ]\+\)\s*\([^ ].*\)/\1:\2/' )"}})
_docker_subcommands=($_docker_subcommands 'help:Show help for a command')
_store_cache docker_subcommands _docker_subcommands
fi
_describe -t docker-commands "docker command" _docker_subcommands
}
__docker_subcommand () {
local -a _command_args
case "$words[1]" in
(attach|wait)
_arguments ':containers:__docker_runningcontainers'
;;
(build)
_arguments \
'-t=-:repository:__docker_repositories' \
':path or URL:_directories'
;;
(commit)
_arguments \
':container:__docker_containers' \
':repository:__docker_repositories' \
':tag: '
;;
(diff|export|logs)
_arguments '*:containers:__docker_containers'
;;
(history)
_arguments '*:images:__docker_images'
;;
(images)
_arguments \
'-a[Show all images]' \
':repository:__docker_repositories'
;;
(inspect)
_arguments '*:containers:__docker_containers'
;;
(history)
_arguments ':images:__docker_images'
;;
(insert)
_arguments '1:containers:__docker_containers' \
'2:URL:(http:// file://)' \
'3:file:_files'
;;
(kill)
_arguments '*:containers:__docker_runningcontainers'
;;
(port)
_arguments '1:containers:__docker_runningcontainers'
;;
(start)
_arguments '*:containers:__docker_stoppedcontainers'
;;
(rm)
_arguments '-v[Remove the volumes associated to the container]' \
'*:containers:__docker_stoppedcontainers'
;;
(rmi)
_arguments '-v[Remove the volumes associated to the container]' \
'*:images:__docker_images'
;;
(top)
_arguments '1:containers:__docker_runningcontainers'
;;
(restart|stop)
_arguments '-t=-[Number of seconds to try to stop for before killing the container]:seconds to before killing:(1 5 10 30 60)' \
'*:containers:__docker_runningcontainers'
;;
(top)
_arguments ':containers:__docker_runningcontainers'
;;
(ps)
_arguments '-a[Show all containers. Only running containers are shown by default]' \
'-h[Show help]' \
'-beforeId=-[Show only container created before Id, include non-running one]:containers:__docker_containers' \
'-n=-[Show n last created containers, include non-running one]:n:(1 5 10 25 50)'
;;
(tag)
_arguments \
'-f[force]'\
':image:__docker_images'\
':repository:__docker_repositories' \
':tag:__docker_tags'
;;
(run)
_arguments \
'-a=-[Attach to stdin, stdout or stderr]:toggle:(true false)' \
'-c=-[CPU shares (relative weight)]:CPU shares: ' \
'-d[Detached mode: leave the container running in the background]' \
'*-dns=[Set custom dns servers]:dns server: ' \
'*-e=[Set environment variables]:environment variable: ' \
'-entrypoint=-[Overwrite the default entrypoint of the image]:entry point: ' \
'-h=-[Container host name]:hostname:_hosts' \
'-i[Keep stdin open even if not attached]' \
'-m=-[Memory limit (in bytes)]:limit: ' \
'*-p=-[Expose a container''s port to the host]:port:_ports' \
'-t=-[Allocate a pseudo-tty]:toggle:(true false)' \
'-u=-[Username or UID]:user:_users' \
'*-v=-[Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)]:volume: '\
'-volumes-from=-[Mount volumes from the specified container]:volume: ' \
'(-):images:__docker_images' \
'(-):command: _command_names -e' \
'*::arguments: _normal'
;;
(pull|search)
_arguments ':name:__docker_search'
;;
(help)
_arguments ':subcommand:__docker_commands'
;;
(*)
_message 'Unknown sub command'
esac
}
_docker () {
local curcontext="$curcontext" state line
typeset -A opt_args
_arguments -C \
'-H=-[tcp://host:port to bind/connect to]:socket: ' \
'(-): :->command' \
'(-)*:: :->option-or-argument'
if (( CURRENT == 1 )); then
fi
case $state in
(command)
__docker_commands
;;
(option-or-argument)
curcontext=${curcontext%:*:*}:docker-$words[1]:
__docker_subcommand
;;
esac
}
_docker "$@"
+1 -1
View File
@@ -77,7 +77,7 @@ func crashTest() error {
stop = false
for i := 0; i < 100 && !stop; {
func() error {
cmd := exec.Command(DOCKERPATH, "run", "base", "echo", fmt.Sprintf("%d", totalTestCount))
cmd := exec.Command(DOCKERPATH, "run", "ubuntu", "echo", fmt.Sprintf("%d", totalTestCount))
i++
totalTestCount++
outPipe, err := cmd.StdoutPipe()
-61
View File
@@ -1,61 +0,0 @@
#!/bin/sh
# This script is meant for quick & easy install via 'curl URL-OF-SCRIPT | sh'
# Original version by Jeff Lindsay <progrium@gmail.com>
# Revamped by Jerome Petazzoni <jerome@dotcloud.com>
#
# This script canonical location is https://get.docker.io/; to update it, run:
# s3cmd put -m text/x-shellscript -P install.sh s3://get.docker.io/index
echo "Ensuring basic dependencies are installed..."
apt-get -qq update
apt-get -qq install lxc wget
echo "Looking in /proc/filesystems to see if we have AUFS support..."
if grep -q aufs /proc/filesystems
then
echo "Found."
else
echo "Ahem, it looks like the current kernel does not support AUFS."
echo "Let's see if we can load the AUFS module with modprobe..."
if modprobe aufs
then
echo "Module loaded."
else
echo "Ahem, things didn't turn out as expected."
KPKG=linux-image-extra-$(uname -r)
echo "Trying to install $KPKG..."
if apt-get -qq install $KPKG
then
echo "Installed."
else
echo "Oops, we couldn't install the -extra kernel."
echo "Are you sure you are running a supported version of Ubuntu?"
echo "Proceeding anyway, but Docker will probably NOT WORK!"
fi
fi
fi
echo "Downloading docker binary to /usr/local/bin..."
curl -s https://get.docker.io/builds/$(uname -s)/$(uname -m)/docker-latest \
> /usr/local/bin/docker
chmod +x /usr/local/bin/docker
if [ -f /etc/init/dockerd.conf ]
then
echo "Upstart script already exists."
else
echo "Creating /etc/init/dockerd.conf..."
cat >/etc/init/dockerd.conf <<EOF
description "Docker daemon"
start on filesystem and started lxc-net
stop on runlevel [!2345]
respawn
exec /usr/local/bin/docker -d
EOF
fi
echo "Starting dockerd..."
start dockerd > /dev/null
echo "Done."
echo
+67
View File
@@ -0,0 +1,67 @@
#!/bin/bash
# Generate a minimal filesystem for archlinux and load it into the local
# docker as "archlinux"
# requires root
set -e
PACSTRAP=$(which pacstrap)
[ "$PACSTRAP" ] || {
echo "Could not find pacstrap. Run pacman -S arch-install-scripts"
exit 1
}
EXPECT=$(which expect)
[ "$EXPECT" ] || {
echo "Could not find expect. Run pacman -S expect"
exit 1
}
ROOTFS=~/rootfs-arch-$$-$RANDOM
mkdir $ROOTFS
#packages to ignore for space savings
PKGIGNORE=linux,jfsutils,lvm2,cryptsetup,groff,man-db,man-pages,mdadm,pciutils,pcmciautils,reiserfsprogs,s-nail,xfsprogs
expect <<EOF
set timeout 60
set send_slow {1 1}
spawn pacstrap -c -d -G -i $ROOTFS base haveged --ignore $PKGIGNORE
expect {
"Install anyway?" { send n\r; exp_continue }
"(default=all)" { send \r; exp_continue }
"Proceed with installation?" { send "\r"; exp_continue }
"skip the above package" {send "y\r"; exp_continue }
"checking" { exp_continue }
"loading" { exp_continue }
"installing" { exp_continue }
}
EOF
arch-chroot $ROOTFS /bin/sh -c "haveged -w 1024; pacman-key --init; pkill haveged; pacman -Rs --noconfirm haveged; pacman-key --populate archlinux"
arch-chroot $ROOTFS /bin/sh -c "ln -s /usr/share/zoneinfo/UTC /etc/localtime"
cat > $ROOTFS/etc/locale.gen <<DELIM
en_US.UTF-8 UTF-8
en_US ISO-8859-1
DELIM
arch-chroot $ROOTFS locale-gen
arch-chroot $ROOTFS /bin/sh -c 'echo "Server = http://mirrors.kernel.org/archlinux/\$repo/os/\$arch" > /etc/pacman.d/mirrorlist'
# udev doesn't work in containers, rebuild /dev
DEV=${ROOTFS}/dev
mv ${DEV} ${DEV}.old
mkdir -p ${DEV}
mknod -m 666 ${DEV}/null c 1 3
mknod -m 666 ${DEV}/zero c 1 5
mknod -m 666 ${DEV}/random c 1 8
mknod -m 666 ${DEV}/urandom c 1 9
mkdir -m 755 ${DEV}/pts
mkdir -m 1777 ${DEV}/shm
mknod -m 666 ${DEV}/tty c 5 0
mknod -m 600 ${DEV}/console c 5 1
mknod -m 666 ${DEV}/tty0 c 4 0
mknod -m 666 ${DEV}/full c 1 7
mknod -m 600 ${DEV}/initctl p
mknod -m 666 ${DEV}/ptmx c 5 2
tar -C $ROOTFS -c . | docker import - archlinux
docker run -i -t archlinux echo Success.
rm -rf $ROOTFS
+15
View File
@@ -0,0 +1,15 @@
#!/bin/bash
# Create a CentOS base image for Docker
# From unclejack https://github.com/dotcloud/docker/issues/290
set -e
MIRROR_URL="http://centos.netnitco.net/6.4/os/x86_64/"
MIRROR_URL_UPDATES="http://centos.netnitco.net/6.4/updates/x86_64/"
yum install -y febootstrap xz
febootstrap -i bash -i coreutils -i tar -i bzip2 -i gzip -i vim-minimal -i wget -i patch -i diffutils -i iproute -i yum centos centos64 $MIRROR_URL -u $MIRROR_URL_UPDATES
touch centos64/etc/resolv.conf
touch centos64/sbin/init
tar --numeric-owner -Jcpf centos-64.tar.xz -C centos64 .
+37 -9
View File
@@ -10,12 +10,18 @@ variant='minbase'
include='iproute,iputils-ping'
repo="$1"
suite="${2:-$stableSuite}"
suite="$2"
mirror="${3:-}" # stick to the default debootstrap mirror if one is not provided
if [ ! "$repo" ]; then
echo >&2 "usage: $0 repo [suite [mirror]]"
if [ ! "$repo" ] || [ ! "$suite" ]; then
echo >&2 "usage: $0 repo suite [mirror]"
echo >&2
echo >&2 " ie: $0 tianon/debian squeeze"
echo >&2 " $0 tianon/debian squeeze http://ftp.uk.debian.org/debian/"
echo >&2
echo >&2 " ie: $0 tianon/ubuntu precise"
echo >&2 " $0 tianon/ubuntu precise http://mirrors.melbourne.co.uk/ubuntu/"
echo >&2
exit 1
fi
@@ -32,22 +38,44 @@ sudo debootstrap --verbose --variant="$variant" --include="$include" "$suite" "$
cd "$target"
# create the image
img=$(sudo tar -c . | docker import -)
# prevent init scripts from running during install/update
# policy-rc.d (for most scripts)
echo $'#!/bin/sh\nexit 101' | sudo tee usr/sbin/policy-rc.d > /dev/null
sudo chmod +x usr/sbin/policy-rc.d
# initctl (for some pesky upstart scripts)
sudo chroot . dpkg-divert --local --rename --add /sbin/initctl
sudo ln -sf /bin/true sbin/initctl
# see https://github.com/dotcloud/docker/issues/446#issuecomment-16953173
# tag suite
docker tag $img $repo $suite
# shrink the image, since apt makes us fat (wheezy: ~157.5MB vs ~120MB)
sudo chroot . apt-get clean
# while we're at it, apt is unnecessarily slow inside containers
# this forces dpkg not to call sync() after package extraction and speeds up install
# the benefit is huge on spinning disks, and the penalty is nonexistent on SSD or decent server virtualization
echo 'force-unsafe-io' | sudo tee etc/dpkg/dpkg.cfg.d/02apt-speedup > /dev/null
# we want to effectively run "apt-get clean" after every install to keep images small
echo 'DPkg::Post-Invoke {"/bin/rm -f /var/cache/apt/archives/*.deb || true";};' | sudo tee etc/apt/apt.conf.d/no-cache > /dev/null
# helpful undo lines for each the above tweaks (for lack of a better home to keep track of them):
# rm /usr/sbin/policy-rc.d
# rm /sbin/initctl; dpkg-divert --rename --remove /sbin/initctl
# rm /etc/dpkg/dpkg.cfg.d/02apt-speedup
# rm /etc/apt/apt.conf.d/no-cache
# create the image (and tag $repo:$suite)
sudo tar -c . | docker import - $repo $suite
# test the image
docker run -i -t $repo:$suite echo success
if [ "$suite" = "$stableSuite" -o "$suite" = 'stable' ]; then
# tag latest
docker tag $img $repo latest
docker tag $repo:$suite $repo latest
# tag the specific debian release version
ver=$(docker run $repo:$suite cat /etc/debian_version)
docker tag $img $repo $ver
docker tag $repo:$suite $repo $ver
fi
# cleanup
+22
View File
@@ -0,0 +1,22 @@
Copyright (c) 2013 Honza Pokorny
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+23
View File
@@ -0,0 +1,23 @@
dockerfile.vim
==============
Syntax highlighting for Dockerfiles
Installation
------------
Via pathogen, the usual way...
Features
--------
The syntax highlighting includes:
* The directives (e.g. `FROM`)
* Strings
* Comments
License
-------
BSD, short and sweet
+18
View File
@@ -0,0 +1,18 @@
*dockerfile.txt* Syntax highlighting for Dockerfiles
Author: Honza Pokorny <http://honza.ca>
License: BSD
INSTALLATION *installation*
Drop it on your Pathogen path and you're all set.
FEATURES *features*
The syntax highlighting includes:
* The directives (e.g. FROM)
* Strings
* Comments
vim:tw=78:et:ft=help:norl:
@@ -0,0 +1 @@
au BufNewFile,BufRead Dockerfile set filetype=dockerfile
+22
View File
@@ -0,0 +1,22 @@
" dockerfile.vim - Syntax highlighting for Dockerfiles
" Maintainer: Honza Pokorny <http://honza.ca>
" Version: 0.5
if exists("b:current_syntax")
finish
endif
let b:current_syntax = "dockerfile"
syntax case ignore
syntax match dockerfileKeyword /\v^\s*(FROM|MAINTAINER|RUN|CMD|EXPOSE|ENV|ADD)\s/
syntax match dockerfileKeyword /\v^\s*(ENTRYPOINT|VOLUME|USER|WORKDIR)\s/
highlight link dockerfileKeyword Keyword
syntax region dockerfileString start=/\v"/ skip=/\v\\./ end=/\v"/
highlight link dockerfileString String
syntax match dockerfileComment "\v^\s*#.*$"
highlight link dockerfileComment Comment
+850
View File
@@ -0,0 +1,850 @@
package devmapper
import (
"encoding/json"
"fmt"
"github.com/dotcloud/docker/utils"
"io"
"io/ioutil"
"os"
"os/exec"
"path"
"path/filepath"
"strconv"
"sync"
"syscall"
"time"
)
var (
DefaultDataLoopbackSize int64 = 100 * 1024 * 1024 * 1024
DefaultMetaDataLoopbackSize int64 = 2 * 1024 * 1024 * 1024
DefaultBaseFsSize uint64 = 10 * 1024 * 1024 * 1024
)
type DevInfo struct {
Hash string `json:"-"`
DeviceId int `json:"device_id"`
Size uint64 `json:"size"`
TransactionId uint64 `json:"transaction_id"`
Initialized bool `json:"initialized"`
devices *DeviceSet `json:"-"`
}
type MetaData struct {
Devices map[string]*DevInfo `json:devices`
}
type DeviceSet struct {
MetaData
sync.Mutex
initialized bool
root string
devicePrefix string
TransactionId uint64
NewTransactionId uint64
nextFreeDevice int
activeMounts map[string]int
}
type DiskUsage struct {
Used uint64
Total uint64
}
type Status struct {
PoolName string
DataLoopback string
MetadataLoopback string
Data DiskUsage
Metadata DiskUsage
}
func getDevName(name string) string {
return "/dev/mapper/" + name
}
func (info *DevInfo) Name() string {
hash := info.Hash
if hash == "" {
hash = "base"
}
return fmt.Sprintf("%s-%s", info.devices.devicePrefix, hash)
}
func (info *DevInfo) DevName() string {
return getDevName(info.Name())
}
func (devices *DeviceSet) loopbackDir() string {
return path.Join(devices.root, "devicemapper")
}
func (devices *DeviceSet) jsonFile() string {
return path.Join(devices.loopbackDir(), "json")
}
func (devices *DeviceSet) getPoolName() string {
return devices.devicePrefix + "-pool"
}
func (devices *DeviceSet) getPoolDevName() string {
return getDevName(devices.getPoolName())
}
func (devices *DeviceSet) hasImage(name string) bool {
dirname := devices.loopbackDir()
filename := path.Join(dirname, name)
_, err := os.Stat(filename)
return err == nil
}
// ensureImage creates a sparse file of <size> bytes at the path
// <root>/devicemapper/<name>.
// If the file already exists, it does nothing.
// Either way it returns the full path.
func (devices *DeviceSet) ensureImage(name string, size int64) (string, error) {
dirname := devices.loopbackDir()
filename := path.Join(dirname, name)
if err := os.MkdirAll(dirname, 0700); err != nil && !os.IsExist(err) {
return "", err
}
if _, err := os.Stat(filename); err != nil {
if !os.IsNotExist(err) {
return "", err
}
utils.Debugf("Creating loopback file %s for device-manage use", filename)
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0600)
if err != nil {
return "", err
}
if err = file.Truncate(size); err != nil {
return "", err
}
}
return filename, nil
}
func (devices *DeviceSet) allocateDeviceId() int {
// TODO: Add smarter reuse of deleted devices
id := devices.nextFreeDevice
devices.nextFreeDevice = devices.nextFreeDevice + 1
return id
}
func (devices *DeviceSet) allocateTransactionId() uint64 {
devices.NewTransactionId = devices.NewTransactionId + 1
return devices.NewTransactionId
}
func (devices *DeviceSet) saveMetadata() error {
jsonData, err := json.Marshal(devices.MetaData)
if err != nil {
return fmt.Errorf("Error encoding metaadata to json: %s", err)
}
tmpFile, err := ioutil.TempFile(filepath.Dir(devices.jsonFile()), ".json")
if err != nil {
return fmt.Errorf("Error creating metadata file: %s", err)
}
n, err := tmpFile.Write(jsonData)
if err != nil {
return fmt.Errorf("Error writing metadata to %s: %s", tmpFile.Name(), err)
}
if n < len(jsonData) {
return io.ErrShortWrite
}
if err := tmpFile.Sync(); err != nil {
return fmt.Errorf("Error syncing metadata file %s: %s", tmpFile.Name(), err)
}
if err := tmpFile.Close(); err != nil {
return fmt.Errorf("Error closing metadata file %s: %s", tmpFile.Name(), err)
}
if err := os.Rename(tmpFile.Name(), devices.jsonFile()); err != nil {
return fmt.Errorf("Error committing metadata file", err)
}
if devices.NewTransactionId != devices.TransactionId {
if err = setTransactionId(devices.getPoolDevName(), devices.TransactionId, devices.NewTransactionId); err != nil {
return fmt.Errorf("Error setting devmapper transition ID: %s", err)
}
devices.TransactionId = devices.NewTransactionId
}
return nil
}
func (devices *DeviceSet) registerDevice(id int, hash string, size uint64) (*DevInfo, error) {
utils.Debugf("registerDevice(%v, %v)", id, hash)
info := &DevInfo{
Hash: hash,
DeviceId: id,
Size: size,
TransactionId: devices.allocateTransactionId(),
Initialized: false,
devices: devices,
}
devices.Devices[hash] = info
if err := devices.saveMetadata(); err != nil {
// Try to remove unused device
delete(devices.Devices, hash)
return nil, err
}
return info, nil
}
func (devices *DeviceSet) activateDeviceIfNeeded(hash string) error {
utils.Debugf("activateDeviceIfNeeded(%v)", hash)
info := devices.Devices[hash]
if info == nil {
return fmt.Errorf("Unknown device %s", hash)
}
if devinfo, _ := getInfo(info.Name()); devinfo != nil && devinfo.Exists != 0 {
return nil
}
return activateDevice(devices.getPoolDevName(), info.Name(), info.DeviceId, info.Size)
}
func (devices *DeviceSet) createFilesystem(info *DevInfo) error {
devname := info.DevName()
err := exec.Command("mkfs.ext4", "-E", "discard,lazy_itable_init=0,lazy_journal_init=0", devname).Run()
if err != nil {
err = exec.Command("mkfs.ext4", "-E", "discard,lazy_itable_init=0", devname).Run()
}
if err != nil {
utils.Debugf("\n--->Err: %s\n", err)
return err
}
return nil
}
func (devices *DeviceSet) loadMetaData() error {
utils.Debugf("loadMetadata()")
defer utils.Debugf("loadMetadata END")
_, _, _, params, err := getStatus(devices.getPoolName())
if err != nil {
utils.Debugf("\n--->Err: %s\n", err)
return err
}
if _, err := fmt.Sscanf(params, "%d", &devices.TransactionId); err != nil {
utils.Debugf("\n--->Err: %s\n", err)
return err
}
devices.NewTransactionId = devices.TransactionId
jsonData, err := ioutil.ReadFile(devices.jsonFile())
if err != nil && !os.IsNotExist(err) {
utils.Debugf("\n--->Err: %s\n", err)
return err
}
devices.MetaData.Devices = make(map[string]*DevInfo)
if jsonData != nil {
if err := json.Unmarshal(jsonData, &devices.MetaData); err != nil {
utils.Debugf("\n--->Err: %s\n", err)
return err
}
}
for hash, d := range devices.Devices {
d.Hash = hash
d.devices = devices
if d.DeviceId >= devices.nextFreeDevice {
devices.nextFreeDevice = d.DeviceId + 1
}
// If the transaction id is larger than the actual one we lost the device due to some crash
if d.TransactionId > devices.TransactionId {
utils.Debugf("Removing lost device %s with id %d", hash, d.TransactionId)
delete(devices.Devices, hash)
}
}
return nil
}
func (devices *DeviceSet) setupBaseImage() error {
oldInfo := devices.Devices[""]
if oldInfo != nil && oldInfo.Initialized {
return nil
}
if oldInfo != nil && !oldInfo.Initialized {
utils.Debugf("Removing uninitialized base image")
if err := devices.removeDevice(""); err != nil {
utils.Debugf("\n--->Err: %s\n", err)
return err
}
}
utils.Debugf("Initializing base device-manager snapshot")
id := devices.allocateDeviceId()
// Create initial device
if err := createDevice(devices.getPoolDevName(), id); err != nil {
utils.Debugf("\n--->Err: %s\n", err)
return err
}
utils.Debugf("Registering base device (id %v) with FS size %v", id, DefaultBaseFsSize)
info, err := devices.registerDevice(id, "", DefaultBaseFsSize)
if err != nil {
_ = deleteDevice(devices.getPoolDevName(), id)
utils.Debugf("\n--->Err: %s\n", err)
return err
}
utils.Debugf("Creating filesystem on base device-manager snapshot")
if err = devices.activateDeviceIfNeeded(""); err != nil {
utils.Debugf("\n--->Err: %s\n", err)
return err
}
if err := devices.createFilesystem(info); err != nil {
utils.Debugf("\n--->Err: %s\n", err)
return err
}
info.Initialized = true
if err = devices.saveMetadata(); err != nil {
info.Initialized = false
utils.Debugf("\n--->Err: %s\n", err)
return err
}
return nil
}
func setCloseOnExec(name string) {
fileInfos, _ := ioutil.ReadDir("/proc/self/fd")
if fileInfos != nil {
for _, i := range fileInfos {
link, _ := os.Readlink(filepath.Join("/proc/self/fd", i.Name()))
if link == name {
fd, err := strconv.Atoi(i.Name())
if err == nil {
syscall.CloseOnExec(fd)
}
}
}
}
}
func (devices *DeviceSet) log(level int, file string, line int, dmError int, message string) {
if level >= 7 {
return // Ignore _LOG_DEBUG
}
utils.Debugf("libdevmapper(%d): %s:%d (%d) %s", level, file, line, dmError, message)
}
func major(device uint64) uint64 {
return (device >> 8) & 0xfff
}
func minor(device uint64) uint64 {
return (device & 0xff) | ((device >> 12) & 0xfff00)
}
func (devices *DeviceSet) initDevmapper() error {
logInit(devices)
// Make sure the sparse images exist in <root>/devicemapper/data and
// <root>/devicemapper/metadata
createdLoopback := !devices.hasImage("data") || !devices.hasImage("metadata")
data, err := devices.ensureImage("data", DefaultDataLoopbackSize)
if err != nil {
utils.Debugf("Error device ensureImage (data): %s\n", err)
return err
}
metadata, err := devices.ensureImage("metadata", DefaultMetaDataLoopbackSize)
if err != nil {
utils.Debugf("Error device ensureImage (metadata): %s\n", err)
return err
}
// Set the device prefix from the device id and inode of the docker root dir
st, err := os.Stat(devices.root)
if err != nil {
return fmt.Errorf("Error looking up dir %s: %s", devices.root, err)
}
sysSt := st.Sys().(*syscall.Stat_t)
// "reg-" stands for "regular file".
// In the future we might use "dev-" for "device file", etc.
// docker-maj,min[-inode] stands for:
// - Managed by docker
// - The target of this device is at major <maj> and minor <min>
// - If <inode> is defined, use that file inside the device as a loopback image. Otherwise use the device itself.
devices.devicePrefix = fmt.Sprintf("docker-%d:%d-%d", major(sysSt.Dev), minor(sysSt.Dev), sysSt.Ino)
utils.Debugf("Generated prefix: %s", devices.devicePrefix)
// Check for the existence of the device <prefix>-pool
utils.Debugf("Checking for existence of the pool '%s'", devices.getPoolName())
info, err := getInfo(devices.getPoolName())
if info == nil {
utils.Debugf("Error device getInfo: %s", err)
return err
}
// It seems libdevmapper opens this without O_CLOEXEC, and go exec will not close files
// that are not Close-on-exec, and lxc-start will die if it inherits any unexpected files,
// so we add this badhack to make sure it closes itself
setCloseOnExec("/dev/mapper/control")
// If the pool doesn't exist, create it
if info.Exists == 0 {
utils.Debugf("Pool doesn't exist. Creating it.")
dataFile, err := AttachLoopDevice(data)
if err != nil {
utils.Debugf("\n--->Err: %s\n", err)
return err
}
defer dataFile.Close()
metadataFile, err := AttachLoopDevice(metadata)
if err != nil {
utils.Debugf("\n--->Err: %s\n", err)
return err
}
defer metadataFile.Close()
if err := createPool(devices.getPoolName(), dataFile, metadataFile); err != nil {
utils.Debugf("\n--->Err: %s\n", err)
return err
}
}
// If we didn't just create the data or metadata image, we need to
// load the metadata from the existing file.
if !createdLoopback {
if err = devices.loadMetaData(); err != nil {
utils.Debugf("\n--->Err: %s\n", err)
return err
}
}
// Setup the base image
if err := devices.setupBaseImage(); err != nil {
utils.Debugf("Error device setupBaseImage: %s\n", err)
return err
}
return nil
}
func (devices *DeviceSet) AddDevice(hash, baseHash string) error {
devices.Lock()
defer devices.Unlock()
if err := devices.ensureInit(); err != nil {
utils.Debugf("Error init: %s\n", err)
return err
}
if devices.Devices[hash] != nil {
return fmt.Errorf("hash %s already exists", hash)
}
baseInfo := devices.Devices[baseHash]
if baseInfo == nil {
return fmt.Errorf("Error adding device for '%s': can't find device for parent '%s'", hash, baseHash)
}
deviceId := devices.allocateDeviceId()
if err := devices.createSnapDevice(devices.getPoolDevName(), deviceId, baseInfo.Name(), baseInfo.DeviceId); err != nil {
utils.Debugf("Error creating snap device: %s\n", err)
return err
}
if _, err := devices.registerDevice(deviceId, hash, baseInfo.Size); err != nil {
deleteDevice(devices.getPoolDevName(), deviceId)
utils.Debugf("Error registering device: %s\n", err)
return err
}
return nil
}
func (devices *DeviceSet) removeDevice(hash string) error {
info := devices.Devices[hash]
if info == nil {
return fmt.Errorf("hash %s doesn't exists", hash)
}
devinfo, _ := getInfo(info.Name())
if devinfo != nil && devinfo.Exists != 0 {
if err := removeDevice(info.Name()); err != nil {
utils.Debugf("Error removing device: %s\n", err)
return err
}
}
if info.Initialized {
info.Initialized = false
if err := devices.saveMetadata(); err != nil {
utils.Debugf("Error saving meta data: %s\n", err)
return err
}
}
if err := deleteDevice(devices.getPoolDevName(), info.DeviceId); err != nil {
utils.Debugf("Error deleting device: %s\n", err)
return err
}
devices.allocateTransactionId()
delete(devices.Devices, info.Hash)
if err := devices.saveMetadata(); err != nil {
devices.Devices[info.Hash] = info
utils.Debugf("Error saving meta data: %s\n", err)
return err
}
return nil
}
func (devices *DeviceSet) RemoveDevice(hash string) error {
devices.Lock()
defer devices.Unlock()
if err := devices.ensureInit(); err != nil {
utils.Debugf("\n--->Err: %s\n", err)
return err
}
return devices.removeDevice(hash)
}
func (devices *DeviceSet) deactivateDevice(hash string) error {
utils.Debugf("[devmapper] deactivateDevice(%s)", hash)
defer utils.Debugf("[devmapper] deactivateDevice END")
var devname string
// FIXME: shouldn't we just register the pool into devices?
devname, err := devices.byHash(hash)
if err != nil {
return err
}
devinfo, err := getInfo(devname)
if err != nil {
utils.Debugf("\n--->Err: %s\n", err)
return err
}
if devinfo.Exists != 0 {
if err := removeDevice(devname); err != nil {
utils.Debugf("\n--->Err: %s\n", err)
return err
}
if err := devices.waitRemove(hash); err != nil {
return err
}
}
return nil
}
// waitRemove blocks until either:
// a) the device registered at <device_set_prefix>-<hash> is removed,
// or b) the 1 second timeout expires.
func (devices *DeviceSet) waitRemove(hash string) error {
utils.Debugf("[deviceset %s] waitRemove(%s)", devices.devicePrefix, hash)
defer utils.Debugf("[deviceset %s] waitRemove END", devices.devicePrefix, hash)
devname, err := devices.byHash(hash)
if err != nil {
return err
}
i := 0
for ; i < 1000; i += 1 {
devinfo, err := getInfo(devname)
if err != nil {
// If there is an error we assume the device doesn't exist.
// The error might actually be something else, but we can't differentiate.
return nil
}
utils.Debugf("Waiting for removal of %s: exists=%d", devname, devinfo.Exists)
if devinfo.Exists == 0 {
break
}
time.Sleep(1 * time.Millisecond)
}
if i == 1000 {
return fmt.Errorf("Timeout while waiting for device %s to be removed", devname)
}
return nil
}
// waitClose blocks until either:
// a) the device registered at <device_set_prefix>-<hash> is closed,
// or b) the 1 second timeout expires.
func (devices *DeviceSet) waitClose(hash string) error {
devname, err := devices.byHash(hash)
if err != nil {
return err
}
i := 0
for ; i < 1000; i += 1 {
devinfo, err := getInfo(devname)
if err != nil {
return err
}
utils.Debugf("Waiting for unmount of %s: opencount=%d", devname, devinfo.OpenCount)
if devinfo.OpenCount == 0 {
break
}
time.Sleep(1 * time.Millisecond)
}
if i == 1000 {
return fmt.Errorf("Timeout while waiting for device %s to close", devname)
}
return nil
}
// byHash is a hack to allow looking up the deviceset's pool by the hash "pool".
// FIXME: it seems probably cleaner to register the pool in devices.Devices,
// but I am afraid of arcane implications deep in the devicemapper code,
// so this will do.
func (devices *DeviceSet) byHash(hash string) (devname string, err error) {
if hash == "pool" {
return devices.getPoolDevName(), nil
}
info := devices.Devices[hash]
if info == nil {
return "", fmt.Errorf("hash %s doesn't exists", hash)
}
return info.Name(), nil
}
func (devices *DeviceSet) Shutdown() error {
utils.Debugf("[deviceset %s] shutdown()", devices.devicePrefix)
defer utils.Debugf("[deviceset %s] shutdown END", devices.devicePrefix)
devices.Lock()
utils.Debugf("[devmapper] Shutting down DeviceSet: %s", devices.root)
defer devices.Unlock()
if !devices.initialized {
return nil
}
for path, count := range devices.activeMounts {
for i := count; i > 0; i-- {
if err := syscall.Unmount(path, 0); err != nil {
utils.Debugf("Shutdown unmounting %s, error: %s\n", path, err)
}
}
delete(devices.activeMounts, path)
}
for _, d := range devices.Devices {
if err := devices.waitClose(d.Hash); err != nil {
utils.Errorf("Warning: error waiting for device %s to unmount: %s\n", d.Hash, err)
}
if err := devices.deactivateDevice(d.Hash); err != nil {
utils.Debugf("Shutdown deactivate %s , error: %s\n", d.Hash, err)
}
}
pool := devices.getPoolDevName()
if devinfo, err := getInfo(pool); err == nil && devinfo.Exists != 0 {
if err := devices.deactivateDevice("pool"); err != nil {
utils.Debugf("Shutdown deactivate %s , error: %s\n", pool, err)
}
}
return nil
}
func (devices *DeviceSet) MountDevice(hash, path string, readOnly bool) error {
devices.Lock()
defer devices.Unlock()
if err := devices.ensureInit(); err != nil {
return fmt.Errorf("Error initializing devmapper: %s", err)
}
if err := devices.activateDeviceIfNeeded(hash); err != nil {
return fmt.Errorf("Error activating devmapper device for '%s': %s", hash, err)
}
info := devices.Devices[hash]
var flags uintptr = syscall.MS_MGC_VAL
if readOnly {
flags = flags | syscall.MS_RDONLY
}
err := syscall.Mount(info.DevName(), path, "ext4", flags, "discard")
if err != nil && err == syscall.EINVAL {
err = syscall.Mount(info.DevName(), path, "ext4", flags, "")
}
if err != nil {
return fmt.Errorf("Error mounting '%s' on '%s': %s", info.DevName(), path, err)
}
count := devices.activeMounts[path]
devices.activeMounts[path] = count + 1
return nil
}
func (devices *DeviceSet) UnmountDevice(hash, path string, deactivate bool) error {
utils.Debugf("[devmapper] UnmountDevice(hash=%s path=%s)", hash, path)
defer utils.Debugf("[devmapper] UnmountDevice END")
devices.Lock()
defer devices.Unlock()
utils.Debugf("[devmapper] Unmount(%s)", path)
if err := syscall.Unmount(path, 0); err != nil {
utils.Debugf("\n--->Err: %s\n", err)
return err
}
utils.Debugf("[devmapper] Unmount done")
// Wait for the unmount to be effective,
// by watching the value of Info.OpenCount for the device
if err := devices.waitClose(hash); err != nil {
return err
}
if count := devices.activeMounts[path]; count > 1 {
devices.activeMounts[path] = count - 1
} else {
delete(devices.activeMounts, path)
}
if deactivate {
devices.deactivateDevice(hash)
}
return nil
}
func (devices *DeviceSet) HasDevice(hash string) bool {
devices.Lock()
defer devices.Unlock()
if err := devices.ensureInit(); err != nil {
return false
}
return devices.Devices[hash] != nil
}
func (devices *DeviceSet) HasInitializedDevice(hash string) bool {
devices.Lock()
defer devices.Unlock()
if err := devices.ensureInit(); err != nil {
return false
}
info := devices.Devices[hash]
return info != nil && info.Initialized
}
func (devices *DeviceSet) HasActivatedDevice(hash string) bool {
devices.Lock()
defer devices.Unlock()
if err := devices.ensureInit(); err != nil {
return false
}
info := devices.Devices[hash]
if info == nil {
return false
}
devinfo, _ := getInfo(info.Name())
return devinfo != nil && devinfo.Exists != 0
}
func (devices *DeviceSet) SetInitialized(hash string) error {
devices.Lock()
defer devices.Unlock()
if err := devices.ensureInit(); err != nil {
utils.Debugf("\n--->Err: %s\n", err)
return err
}
info := devices.Devices[hash]
if info == nil {
return fmt.Errorf("Unknown device %s", hash)
}
info.Initialized = true
if err := devices.saveMetadata(); err != nil {
info.Initialized = false
utils.Debugf("\n--->Err: %s\n", err)
return err
}
return nil
}
func (devices *DeviceSet) Status() *Status {
devices.Lock()
defer devices.Unlock()
status := &Status{}
if err := devices.ensureInit(); err != nil {
return status
}
status.PoolName = devices.getPoolName()
status.DataLoopback = path.Join(devices.loopbackDir(), "data")
status.MetadataLoopback = path.Join(devices.loopbackDir(), "metadata")
_, totalSizeInSectors, _, params, err := getStatus(devices.getPoolName())
if err == nil {
var transactionId, dataUsed, dataTotal, metadataUsed, metadataTotal uint64
if _, err := fmt.Sscanf(params, "%d %d/%d %d/%d", &transactionId, &metadataUsed, &metadataTotal, &dataUsed, &dataTotal); err == nil {
// Convert from blocks to bytes
blockSizeInSectors := totalSizeInSectors / dataTotal
status.Data.Used = dataUsed * blockSizeInSectors * 512
status.Data.Total = dataTotal * blockSizeInSectors * 512
// metadata blocks are always 4k
status.Metadata.Used = metadataUsed * 4096
status.Metadata.Total = metadataTotal * 4096
}
}
return status
}
func (devices *DeviceSet) ensureInit() error {
if !devices.initialized {
devices.initialized = true
if err := devices.initDevmapper(); err != nil {
utils.Debugf("\n--->Err: %s\n", err)
return err
}
}
return nil
}
func NewDeviceSet(root string) *DeviceSet {
SetDevDir("/dev")
return &DeviceSet{
initialized: false,
root: root,
MetaData: MetaData{Devices: make(map[string]*DevInfo)},
activeMounts: make(map[string]int),
}
}
+709
View File
@@ -0,0 +1,709 @@
package devmapper
/*
#cgo LDFLAGS: -L. -ldevmapper
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libdevmapper.h>
#include <linux/loop.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <errno.h>
#ifndef LOOP_CTL_GET_FREE
#define LOOP_CTL_GET_FREE 0x4C82
#endif
// FIXME: this could easily be rewritten in go
char* attach_loop_device(const char *filename, int *loop_fd_out)
{
struct loop_info64 loopinfo = {0};
struct stat st;
char buf[64];
int i, loop_fd, fd, start_index;
char* loopname;
*loop_fd_out = -1;
start_index = 0;
fd = open("/dev/loop-control", O_RDONLY);
if (fd >= 0) {
start_index = ioctl(fd, LOOP_CTL_GET_FREE);
close(fd);
if (start_index < 0)
start_index = 0;
}
fd = open(filename, O_RDWR);
if (fd < 0) {
perror("open");
return NULL;
}
loop_fd = -1;
for (i = start_index ; loop_fd < 0 ; i++ ) {
if (sprintf(buf, "/dev/loop%d", i) < 0) {
close(fd);
return NULL;
}
if (stat(buf, &st)) {
if (!S_ISBLK(st.st_mode)) {
fprintf(stderr, "[error] Loopback device %s is not a block device.\n", buf);
} else if (errno == ENOENT) {
fprintf(stderr, "[error] There are no more loopback device available.\n");
} else {
fprintf(stderr, "[error] Unkown error trying to stat the loopback device %s (errno: %d).\n", buf, errno);
}
close(fd);
return NULL;
}
loop_fd = open(buf, O_RDWR);
if (loop_fd < 0 && errno == ENOENT) {
fprintf(stderr, "[error] The loopback device %s does not exists.\n", buf);
close(fd);
return NULL;
} else if (loop_fd < 0) {
fprintf(stderr, "[error] Unkown error openning the loopback device %s. (errno: %d)\n", buf, errno);
continue;
}
if (ioctl(loop_fd, LOOP_SET_FD, (void *)(size_t)fd) < 0) {
int errsv = errno;
close(loop_fd);
loop_fd = -1;
if (errsv != EBUSY) {
close(fd);
fprintf(stderr, "cannot set up loopback device %s: %s", buf, strerror(errsv));
return NULL;
}
continue;
}
close(fd);
strncpy((char*)loopinfo.lo_file_name, buf, LO_NAME_SIZE);
loopinfo.lo_offset = 0;
loopinfo.lo_flags = LO_FLAGS_AUTOCLEAR;
if (ioctl(loop_fd, LOOP_SET_STATUS64, &loopinfo) < 0) {
perror("ioctl LOOP_SET_STATUS64");
if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) {
perror("ioctl LOOP_CLR_FD");
}
close(loop_fd);
fprintf (stderr, "cannot set up loopback device info");
return (NULL);
}
loopname = strdup(buf);
if (loopname == NULL) {
close(loop_fd);
return (NULL);
}
*loop_fd_out = loop_fd;
return (loopname);
}
return (NULL);
}
static int64_t get_block_size(int fd)
{
uint64_t size;
if (ioctl(fd, BLKGETSIZE64, &size) == -1)
return -1;
return ((int64_t)size);
}
extern void DevmapperLogCallback(int level, char *file, int line, int dm_errno_or_class, char *str);
static void
log_cb(int level, const char *file, int line,
int dm_errno_or_class, const char *f, ...)
{
char buffer[256];
va_list ap;
va_start(ap, f);
vsnprintf(buffer, 256, f, ap);
va_end(ap);
DevmapperLogCallback(level, (char *)file, line, dm_errno_or_class, buffer);
}
static void
log_with_errno_init ()
{
dm_log_with_errno_init(log_cb);
}
*/
import "C"
import (
"errors"
"fmt"
"github.com/dotcloud/docker/utils"
"os"
"runtime"
"syscall"
"unsafe"
)
type DevmapperLogger interface {
log(level int, file string, line int, dmError int, message string)
}
const (
DeviceCreate TaskType = iota
DeviceReload
DeviceRemove
DeviceRemoveAll
DeviceSuspend
DeviceResume
DeviceInfo
DeviceDeps
DeviceRename
DeviceVersion
DeviceStatus
DeviceTable
DeviceWaitevent
DeviceList
DeviceClear
DeviceMknodes
DeviceListVersions
DeviceTargetMsg
DeviceSetGeometry
)
const (
AddNodeOnResume AddNodeType = iota
AddNodeOnCreate
)
var (
ErrTaskRun = errors.New("dm_task_run failed")
ErrTaskSetName = errors.New("dm_task_set_name failed")
ErrTaskSetMessage = errors.New("dm_task_set_message failed")
ErrTaskSetAddNode = errors.New("dm_task_set_add_node failed")
ErrTaskSetRO = errors.New("dm_task_set_ro failed")
ErrTaskAddTarget = errors.New("dm_task_add_target failed")
ErrGetDriverVersion = errors.New("dm_task_get_driver_version failed")
ErrAttachLoopbackDevice = errors.New("loopback mounting failed")
ErrGetBlockSize = errors.New("Can't get block size")
ErrUdevWait = errors.New("wait on udev cookie failed")
ErrSetDevDir = errors.New("dm_set_dev_dir failed")
ErrGetLibraryVersion = errors.New("dm_get_library_version failed")
ErrCreateRemoveTask = errors.New("Can't create task of type DeviceRemove")
ErrRunRemoveDevice = errors.New("running removeDevice failed")
)
type (
Task struct {
unmanaged *C.struct_dm_task
}
Info struct {
Exists int
Suspended int
LiveTable int
InactiveTable int
OpenCount int32
EventNr uint32
Major uint32
Minor uint32
ReadOnly int
TargetCount int32
}
TaskType int
AddNodeType int
)
func (t *Task) destroy() {
if t != nil {
C.dm_task_destroy(t.unmanaged)
runtime.SetFinalizer(t, nil)
}
}
func TaskCreate(tasktype TaskType) *Task {
c_task := C.dm_task_create(C.int(tasktype))
if c_task == nil {
return nil
}
task := &Task{unmanaged: c_task}
runtime.SetFinalizer(task, (*Task).destroy)
return task
}
func (t *Task) Run() error {
if res := C.dm_task_run(t.unmanaged); res != 1 {
return ErrTaskRun
}
return nil
}
func (t *Task) SetName(name string) error {
c_name := C.CString(name)
defer free(c_name)
if res := C.dm_task_set_name(t.unmanaged, c_name); res != 1 {
return ErrTaskSetName
}
return nil
}
func (t *Task) SetMessage(message string) error {
c_message := C.CString(message)
defer free(c_message)
if res := C.dm_task_set_message(t.unmanaged, c_message); res != 1 {
return ErrTaskSetMessage
}
return nil
}
func (t *Task) SetSector(sector uint64) error {
if res := C.dm_task_set_sector(t.unmanaged, C.uint64_t(sector)); res != 1 {
return ErrTaskSetAddNode
}
return nil
}
func (t *Task) SetCookie(cookie *uint32, flags uint16) error {
c_cookie := C.uint32_t(*cookie)
if res := C.dm_task_set_cookie(t.unmanaged, &c_cookie, C.uint16_t(flags)); res != 1 {
return ErrTaskSetAddNode
}
*cookie = uint32(c_cookie)
return nil
}
func (t *Task) SetAddNode(add_node AddNodeType) error {
if res := C.dm_task_set_add_node(t.unmanaged, C.dm_add_node_t(add_node)); res != 1 {
return ErrTaskSetAddNode
}
return nil
}
func (t *Task) SetRo() error {
if res := C.dm_task_set_ro(t.unmanaged); res != 1 {
return ErrTaskSetRO
}
return nil
}
func (t *Task) AddTarget(start uint64, size uint64, ttype string, params string) error {
c_ttype := C.CString(ttype)
defer free(c_ttype)
c_params := C.CString(params)
defer free(c_params)
if res := C.dm_task_add_target(t.unmanaged, C.uint64_t(start), C.uint64_t(size), c_ttype, c_params); res != 1 {
return ErrTaskAddTarget
}
return nil
}
func (t *Task) GetDriverVersion() (string, error) {
buffer := C.CString(string(make([]byte, 128)))
defer free(buffer)
if res := C.dm_task_get_driver_version(t.unmanaged, buffer, 128); res != 1 {
return "", ErrGetDriverVersion
}
return C.GoString(buffer), nil
}
func (t *Task) GetInfo() (*Info, error) {
c_info := C.struct_dm_info{}
if res := C.dm_task_get_info(t.unmanaged, &c_info); res != 1 {
return nil, ErrGetDriverVersion
}
return &Info{
Exists: int(c_info.exists),
Suspended: int(c_info.suspended),
LiveTable: int(c_info.live_table),
InactiveTable: int(c_info.inactive_table),
OpenCount: int32(c_info.open_count),
EventNr: uint32(c_info.event_nr),
Major: uint32(c_info.major),
Minor: uint32(c_info.minor),
ReadOnly: int(c_info.read_only),
TargetCount: int32(c_info.target_count),
}, nil
}
func (t *Task) GetNextTarget(next uintptr) (uintptr, uint64, uint64, string, string) {
var (
c_start, c_length C.uint64_t
c_target_type, c_params *C.char
)
nextp := C.dm_get_next_target(t.unmanaged, unsafe.Pointer(next), &c_start, &c_length, &c_target_type, &c_params)
return uintptr(nextp), uint64(c_start), uint64(c_length), C.GoString(c_target_type), C.GoString(c_params)
}
func AttachLoopDevice(filename string) (*os.File, error) {
c_filename := C.CString(filename)
defer free(c_filename)
var fd C.int
res := C.attach_loop_device(c_filename, &fd)
if res == nil {
if os.Getenv("DEBUG") != "" {
C.perror(C.CString(fmt.Sprintf("[debug] Error attach_loop_device(%s, %d)", filename, int(fd))))
}
return nil, ErrAttachLoopbackDevice
}
defer free(res)
return os.NewFile(uintptr(fd), C.GoString(res)), nil
}
func getBlockSize(fd uintptr) int {
var size uint64
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, C.BLKGETSIZE64, uintptr(unsafe.Pointer(&size))); err != 0 {
utils.Debugf("Error ioctl: %s", err)
return -1
}
return int(size)
}
func GetBlockDeviceSize(file *os.File) (uint64, error) {
if size := C.get_block_size(C.int(file.Fd())); size == -1 {
return 0, ErrGetBlockSize
} else {
return uint64(size), nil
}
}
func UdevWait(cookie uint32) error {
if res := C.dm_udev_wait(C.uint32_t(cookie)); res != 1 {
utils.Debugf("Failed to wait on udev cookie %d", cookie)
return ErrUdevWait
}
return nil
}
func LogInitVerbose(level int) {
C.dm_log_init_verbose(C.int(level))
}
var dmLogger DevmapperLogger = nil
func logInit(logger DevmapperLogger) {
dmLogger = logger
C.log_with_errno_init()
}
func SetDevDir(dir string) error {
c_dir := C.CString(dir)
defer free(c_dir)
if res := C.dm_set_dev_dir(c_dir); res != 1 {
utils.Debugf("Error dm_set_dev_dir")
return ErrSetDevDir
}
return nil
}
func GetLibraryVersion() (string, error) {
buffer := C.CString(string(make([]byte, 128)))
defer free(buffer)
if res := C.dm_get_library_version(buffer, 128); res != 1 {
return "", ErrGetLibraryVersion
}
return C.GoString(buffer), nil
}
// Useful helper for cleanup
func RemoveDevice(name string) error {
task := TaskCreate(DeviceRemove)
if task == nil {
return ErrCreateRemoveTask
}
if err := task.SetName(name); err != nil {
utils.Debugf("Can't set task name %s", name)
return err
}
if err := task.Run(); err != nil {
return ErrRunRemoveDevice
}
return nil
}
func free(p *C.char) {
C.free(unsafe.Pointer(p))
}
// This is the programmatic example of "dmsetup create"
func createPool(poolName string, dataFile *os.File, metadataFile *os.File) error {
task, err := createTask(DeviceCreate, poolName)
if task == nil {
return err
}
size, err := GetBlockDeviceSize(dataFile)
if err != nil {
return fmt.Errorf("Can't get data size")
}
params := metadataFile.Name() + " " + dataFile.Name() + " 128 32768"
if err := task.AddTarget(0, size/512, "thin-pool", params); err != nil {
return fmt.Errorf("Can't add target")
}
var cookie uint32 = 0
if err := task.SetCookie(&cookie, 0); err != nil {
return fmt.Errorf("Can't set cookie")
}
if err := task.Run(); err != nil {
return fmt.Errorf("Error running DeviceCreate")
}
UdevWait(cookie)
return nil
}
func createTask(t TaskType, name string) (*Task, error) {
task := TaskCreate(t)
if task == nil {
return nil, fmt.Errorf("Can't create task of type %d", int(t))
}
if err := task.SetName(name); err != nil {
return nil, fmt.Errorf("Can't set task name %s", name)
}
return task, nil
}
func getInfo(name string) (*Info, error) {
task, err := createTask(DeviceInfo, name)
if task == nil {
return nil, err
}
if err := task.Run(); err != nil {
return nil, err
}
return task.GetInfo()
}
func getStatus(name string) (uint64, uint64, string, string, error) {
task, err := createTask(DeviceStatus, name)
if task == nil {
utils.Debugf("getStatus: Error createTask: %s", err)
return 0, 0, "", "", err
}
if err := task.Run(); err != nil {
utils.Debugf("getStatus: Error Run: %s", err)
return 0, 0, "", "", err
}
devinfo, err := task.GetInfo()
if err != nil {
utils.Debugf("getStatus: Error GetInfo: %s", err)
return 0, 0, "", "", err
}
if devinfo.Exists == 0 {
utils.Debugf("getStatus: Non existing device %s", name)
return 0, 0, "", "", fmt.Errorf("Non existing device %s", name)
}
_, start, length, target_type, params := task.GetNextTarget(0)
return start, length, target_type, params, nil
}
func setTransactionId(poolName string, oldId uint64, newId uint64) error {
task, err := createTask(DeviceTargetMsg, poolName)
if task == nil {
return err
}
if err := task.SetSector(0); err != nil {
return fmt.Errorf("Can't set sector")
}
if err := task.SetMessage(fmt.Sprintf("set_transaction_id %d %d", oldId, newId)); err != nil {
return fmt.Errorf("Can't set message")
}
if err := task.Run(); err != nil {
return fmt.Errorf("Error running setTransactionId")
}
return nil
}
func suspendDevice(name string) error {
task, err := createTask(DeviceSuspend, name)
if task == nil {
return err
}
if err := task.Run(); err != nil {
return fmt.Errorf("Error running DeviceSuspend")
}
return nil
}
func resumeDevice(name string) error {
task, err := createTask(DeviceResume, name)
if task == nil {
return err
}
var cookie uint32 = 0
if err := task.SetCookie(&cookie, 0); err != nil {
return fmt.Errorf("Can't set cookie")
}
if err := task.Run(); err != nil {
return fmt.Errorf("Error running DeviceSuspend")
}
UdevWait(cookie)
return nil
}
func createDevice(poolName string, deviceId int) error {
utils.Debugf("[devmapper] createDevice(poolName=%v, deviceId=%v)", poolName, deviceId)
task, err := createTask(DeviceTargetMsg, poolName)
if task == nil {
return err
}
if err := task.SetSector(0); err != nil {
return fmt.Errorf("Can't set sector")
}
if err := task.SetMessage(fmt.Sprintf("create_thin %d", deviceId)); err != nil {
return fmt.Errorf("Can't set message")
}
if err := task.Run(); err != nil {
return fmt.Errorf("Error running createDevice")
}
return nil
}
func deleteDevice(poolName string, deviceId int) error {
task, err := createTask(DeviceTargetMsg, poolName)
if task == nil {
return err
}
if err := task.SetSector(0); err != nil {
return fmt.Errorf("Can't set sector")
}
if err := task.SetMessage(fmt.Sprintf("delete %d", deviceId)); err != nil {
return fmt.Errorf("Can't set message")
}
if err := task.Run(); err != nil {
return fmt.Errorf("Error running deleteDevice")
}
return nil
}
func removeDevice(name string) error {
utils.Debugf("[devmapper] removeDevice START")
defer utils.Debugf("[devmapper] removeDevice END")
task, err := createTask(DeviceRemove, name)
if task == nil {
return err
}
if err = task.Run(); err != nil {
return fmt.Errorf("Error running removeDevice")
}
return nil
}
func activateDevice(poolName string, name string, deviceId int, size uint64) error {
task, err := createTask(DeviceCreate, name)
if task == nil {
return err
}
params := fmt.Sprintf("%s %d", poolName, deviceId)
if err := task.AddTarget(0, size/512, "thin", params); err != nil {
return fmt.Errorf("Can't add target")
}
if err := task.SetAddNode(AddNodeOnCreate); err != nil {
return fmt.Errorf("Can't add node")
}
var cookie uint32 = 0
if err := task.SetCookie(&cookie, 0); err != nil {
return fmt.Errorf("Can't set cookie")
}
if err := task.Run(); err != nil {
return fmt.Errorf("Error running DeviceCreate")
}
UdevWait(cookie)
return nil
}
func (devices *DeviceSet) createSnapDevice(poolName string, deviceId int, baseName string, baseDeviceId int) error {
devinfo, _ := getInfo(baseName)
doSuspend := devinfo != nil && devinfo.Exists != 0
if doSuspend {
if err := suspendDevice(baseName); err != nil {
return err
}
}
task, err := createTask(DeviceTargetMsg, poolName)
if task == nil {
if doSuspend {
resumeDevice(baseName)
}
return err
}
if err := task.SetSector(0); err != nil {
if doSuspend {
resumeDevice(baseName)
}
return fmt.Errorf("Can't set sector")
}
if err := task.SetMessage(fmt.Sprintf("create_snap %d %d", deviceId, baseDeviceId)); err != nil {
if doSuspend {
resumeDevice(baseName)
}
return fmt.Errorf("Can't set message")
}
if err := task.Run(); err != nil {
if doSuspend {
resumeDevice(baseName)
}
return fmt.Errorf("Error running DeviceCreate")
}
if doSuspend {
if err := resumeDevice(baseName); err != nil {
return err
}
}
return nil
}
+13
View File
@@ -0,0 +1,13 @@
package devmapper
import "C"
// Due to the way cgo works this has to be in a separate file, as devmapper.go has
// definitions in the cgo block, which is incompatible with using "//export"
//export DevmapperLogCallback
func DevmapperLogCallback(level C.int, file *C.char, line C.int, dm_errno_or_class C.int, message *C.char) {
if dmLogger != nil {
dmLogger.log(int(level), C.GoString(file), int(line), int(dm_errno_or_class), C.GoString(message))
}
}
@@ -0,0 +1,62 @@
package main
import (
"fmt"
"github.com/dotcloud/docker/devmapper"
"os"
)
func usage() {
fmt.Printf("Usage: %s [snap new-id base-id] | [remove id] | [mount id mountpoint]\n", os.Args[0])
os.Exit(1)
}
func main() {
devices := devmapper.NewDeviceSet("/var/lib/docker")
if len(os.Args) < 2 {
usage()
}
cmd := os.Args[1]
if cmd == "snap" {
if len(os.Args) < 4 {
usage()
}
err := devices.AddDevice(os.Args[2], os.Args[3])
if err != nil {
fmt.Println("Can't create snap device: ", err)
os.Exit(1)
}
} else if cmd == "remove" {
if len(os.Args) < 3 {
usage()
}
err := devices.RemoveDevice(os.Args[2])
if err != nil {
fmt.Println("Can't remove device: ", err)
os.Exit(1)
}
} else if cmd == "mount" {
if len(os.Args) < 4 {
usage()
}
err := devices.MountDevice(os.Args[2], os.Args[3])
if err != nil {
fmt.Println("Can't create snap device: ", err)
os.Exit(1)
}
} else {
fmt.Printf("Unknown command %s\n", cmd)
if len(os.Args) < 4 {
usage()
}
os.Exit(1)
}
return
}
+41 -20
View File
@@ -4,9 +4,11 @@ import (
"flag"
"fmt"
"github.com/dotcloud/docker"
"github.com/dotcloud/docker/sysinit"
"github.com/dotcloud/docker/utils"
"io/ioutil"
"log"
"net"
"os"
"os/signal"
"strconv"
@@ -22,22 +24,27 @@ var (
func main() {
if selfPath := utils.SelfPath(); selfPath == "/sbin/init" || selfPath == "/.dockerinit" {
// Running in init mode
docker.SysInit()
sysinit.SysInit()
return
}
// FIXME: Switch d and D ? (to be more sshd like)
flVersion := flag.Bool("v", false, "Print version information and quit")
flDaemon := flag.Bool("d", false, "Daemon mode")
flDebug := flag.Bool("D", false, "Debug mode")
flAutoRestart := flag.Bool("r", false, "Restart previously running containers")
flAutoRestart := flag.Bool("r", true, "Restart previously running containers")
bridgeName := flag.String("b", "", "Attach containers to a pre-existing network bridge. Use 'none' to disable container networking")
pidfile := flag.String("p", "/var/run/docker.pid", "File containing process PID")
flGraphPath := flag.String("g", "/var/lib/docker", "Path to graph storage base dir.")
flEnableCors := flag.Bool("api-enable-cors", false, "Enable CORS requests in the remote api.")
flDns := flag.String("dns", "", "Set custom dns servers")
flHosts := docker.ListOpts{fmt.Sprintf("unix://%s", docker.DEFAULTUNIXSOCKET)}
flHosts := utils.ListOpts{fmt.Sprintf("unix://%s", docker.DEFAULTUNIXSOCKET)}
flag.Var(&flHosts, "H", "tcp://host:port to bind/connect to or unix://path/to/socket to use")
flEnableIptables := flag.Bool("iptables", true, "Disable iptables within docker")
flDefaultIp := flag.String("ip", "0.0.0.0", "Default ip address to use when binding a containers ports")
flInterContainerComm := flag.Bool("enable-container-comm", false, "Enable inter-container communication")
flag.Parse()
if *flVersion {
showVersion()
return
@@ -49,10 +56,9 @@ func main() {
flHosts[i] = utils.ParseHost(docker.DEFAULTHTTPHOST, docker.DEFAULTHTTPPORT, flHost)
}
bridge := docker.DefaultNetworkBridge
if *bridgeName != "" {
docker.NetworkBridgeIface = *bridgeName
} else {
docker.NetworkBridgeIface = docker.DefaultNetworkBridge
bridge = *bridgeName
}
if *flDebug {
os.Setenv("DEBUG", "1")
@@ -64,7 +70,26 @@ func main() {
flag.Usage()
return
}
if err := daemon(*pidfile, *flGraphPath, flHosts, *flAutoRestart, *flEnableCors, *flDns); err != nil {
var dns []string
if *flDns != "" {
dns = []string{*flDns}
}
ip := net.ParseIP(*flDefaultIp)
config := &docker.DaemonConfig{
Pidfile: *pidfile,
GraphPath: *flGraphPath,
AutoRestart: *flAutoRestart,
EnableCors: *flEnableCors,
Dns: dns,
EnableIptables: *flEnableIptables,
BridgeIface: bridge,
ProtoAddresses: flHosts,
DefaultIp: ip,
InterContainerCommunication: *flInterContainerComm,
}
if err := daemon(config); err != nil {
log.Fatal(err)
os.Exit(-1)
}
@@ -115,30 +140,26 @@ func removePidFile(pidfile string) {
}
}
func daemon(pidfile string, flGraphPath string, protoAddrs []string, autoRestart, enableCors bool, flDns string) error {
if err := createPidFile(pidfile); err != nil {
func daemon(config *docker.DaemonConfig) error {
if err := createPidFile(config.Pidfile); err != nil {
log.Fatal(err)
}
defer removePidFile(pidfile)
defer removePidFile(config.Pidfile)
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, os.Kill, os.Signal(syscall.SIGTERM))
signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGTERM)
go func() {
sig := <-c
log.Printf("Received signal '%v', exiting\n", sig)
removePidFile(pidfile)
removePidFile(config.Pidfile)
os.Exit(0)
}()
var dns []string
if flDns != "" {
dns = []string{flDns}
}
server, err := docker.NewServer(flGraphPath, autoRestart, enableCors, dns)
server, err := docker.NewServer(config)
if err != nil {
return err
}
chErrors := make(chan error, len(protoAddrs))
for _, protoAddr := range protoAddrs {
chErrors := make(chan error, len(config.ProtoAddresses))
for _, protoAddr := range config.ProtoAddresses {
protoAddrParts := strings.SplitN(protoAddr, "://", 2)
if protoAddrParts[0] == "unix" {
syscall.Unlink(protoAddrParts[1])
@@ -154,7 +175,7 @@ func daemon(pidfile string, flGraphPath string, protoAddrs []string, autoRestart
chErrors <- docker.ListenAndServe(protoAddrParts[0], protoAddrParts[1], server, true)
}()
}
for i := 0; i < len(protoAddrs); i += 1 {
for i := 0; i < len(config.ProtoAddresses); i += 1 {
err := <-chErrors
if err != nil {
return err
+16
View File
@@ -0,0 +1,16 @@
package main
import (
"github.com/dotcloud/docker/sysinit"
)
var (
GITCOMMIT string
VERSION string
)
func main() {
// Running in init mode
sysinit.SysInit()
return
}
+86 -24
View File
@@ -1,38 +1,93 @@
Docker Documentation
====================
Documentation
-------------
This is your definite place to contribute to the docker documentation. After each push to master the documentation
is automatically generated and made available on [docs.docker.io](http://docs.docker.io)
Overview
--------
Each of the .rst files under sources reflects a page on the documentation.
The source for Docker documentation is here under ``sources/`` in the
form of .rst files. These files use
[reStructuredText](http://docutils.sourceforge.net/rst.html)
formatting with [Sphinx](http://sphinx-doc.org/) extensions for
structure, cross-linking and indexing.
Installation
------------
The HTML files are built and hosted on
[readthedocs.org](https://readthedocs.org/projects/docker/), appearing
via proxy on https://docs.docker.io. The HTML files update
automatically after each change to the master or release branch of the
[docker files on GitHub](https://github.com/dotcloud/docker) thanks to
post-commit hooks. The "release" branch maps to the "latest"
documentation and the "master" branch maps to the "master"
documentation.
**Warning**: The "master" documentation may include features not yet
part of any official docker release. "Master" docs should be used only
for understanding bleeding-edge development and "latest" should be
used for the latest official release.
If you need to manually trigger a build of an existing branch, then
you can do that through the [readthedocs
interface](https://readthedocs.org/builds/docker/). If you would like
to add new build targets, including new branches or tags, then you
must contact one of the existing maintainers and get your
readthedocs.org account added to the maintainers list, or just file an
issue on GitHub describing the branch/tag and why it needs to be added
to the docs, and one of the maintainers will add it for you.
Getting Started
---------------
To edit and test the docs, you'll need to install the Sphinx tool and
its dependencies. There are two main ways to install this tool:
Native Installation
...................
* Work in your own fork of the code, we accept pull requests.
* Install sphinx: `pip install sphinx`
* Mac OS X: `[sudo] pip-2.7 install sphinx`)
* Mac OS X: `[sudo] pip-2.7 install sphinx`
* Install sphinx httpdomain contrib package: `pip install sphinxcontrib-httpdomain`
* Mac OS X: `[sudo] pip-2.7 install sphinxcontrib-httpdomain`
* If pip is not available you can probably install it using your favorite package manager as **python-pip**
Alternative Installation: Docker Container
..........................................
If you're running ``docker`` on your development machine then you may
find it easier and cleaner to use the Dockerfile. This installs Sphinx
in a container, adds the local ``docs/`` directory and builds the HTML
docs inside the container, even starting a simple HTTP server on port
8000 so that you can connect and see your changes. Just run ``docker
build .`` and run the resulting image. This is the equivalent to
``make clean server`` since each container starts clean.
Usage
-----
* Change the `.rst` files with your favorite editor to your liking.
* Run `make docs` to clean up old files and generate new ones.
* Your static website can now be found in the `_build` directory.
* To preview what you have generated run `make server` and open http://localhost:8000/ in your favorite browser.
* Follow the contribution guidelines (``../CONTRIBUTING.md``)
* Work in your own fork of the code, we accept pull requests.
* Change the ``.rst`` files with your favorite editor -- try to keep the
lines short and respect RST and Sphinx conventions.
* Run ``make clean docs`` to clean up old files and generate new ones,
or just ``make docs`` to update after small changes.
* Your static website can now be found in the ``_build`` directory.
* To preview what you have generated run ``make server`` and open
http://localhost:8000/ in your favorite browser.
``make clean docs`` must complete without any warnings or errors.
Working using GitHub's file editor
----------------------------------
Alternatively, for small changes and typo's you might want to use GitHub's built in file editor. It allows
you to preview your changes right online. Just be careful not to create many commits.
Alternatively, for small changes and typos you might want to use
GitHub's built in file editor. It allows you to preview your changes
right online (though there can be some differences between GitHub
markdown and Sphinx RST). Just be careful not to create many commits.
Images
------
When you need to add images, try to make them as small as possible (e.g. as gif).
When you need to add images, try to make them as small as possible
(e.g. as gif). Usually images should go in the same directory as the
.rst file which references them, or in a subdirectory if one already
exists.
Notes
-----
@@ -41,7 +96,7 @@ lessc ``lessc main.less`` or watched using watch-lessc ``watch-lessc -i main.les
Guides on using sphinx
----------------------
* To make links to certain pages create a link target like so:
* To make links to certain sections create a link target like so:
```
.. _hello_world:
@@ -52,7 +107,10 @@ Guides on using sphinx
This is.. (etc.)
```
The ``_hello_world:`` will make it possible to link to this position (page and marker) from all other pages.
The ``_hello_world:`` will make it possible to link to this position
(page and section heading) from all other pages. See the [Sphinx
docs](http://sphinx-doc.org/markup/inline.html#role-ref) for more
information and examples.
* Notes, warnings and alarms
@@ -68,13 +126,17 @@ Guides on using sphinx
* Code examples
Start without $, so it's easy to copy and paste.
* Start without $, so it's easy to copy and paste.
* Use "sudo" with docker to ensure that your command is runnable
even if they haven't [used the *docker*
group](http://docs.docker.io/en/latest/use/basics/#why-sudo).
Manpages
--------
* To make the manpages, simply run 'make man'. Please note there is a bug in spinx 1.1.3 which makes this fail.
Upgrade to the latest version of sphinx.
* Then preview the manpage by running `man _build/man/docker.1`, where _build/man/docker.1 is the path to the generated
manfile
* The manpages are also autogenerated by our hosted readthedocs here: http://docs-docker.dotcloud.com/projects/docker/downloads/
* To make the manpages, run ``make man``. Please note there is a bug
in spinx 1.1.3 which makes this fail. Upgrade to the latest version
of Sphinx.
* Then preview the manpage by running ``man _build/man/docker.1``,
where ``_build/man/docker.1`` is the path to the generated manfile
+63 -48
View File
@@ -9,7 +9,6 @@
Docker Remote API
=================
.. contents:: Table of Contents
1. Brief introduction
=====================
@@ -27,16 +26,41 @@ Docker Remote API
2. Versions
===========
The current version of the API is 1.5
The current version of the API is 1.6
Calling /images/<name>/insert is the same as calling
/v1.5/images/<name>/insert
/v1.6/images/<name>/insert
You can still call an old version of the api using
/v1.0/images/<name>/insert
v1.6
****
Full Documentation
------------------
:doc:`docker_remote_api_v1.6`
What's new
----------
.. http:post:: /containers/(id)/attach
**New!** You can now split stderr from stdout. This is done by prefixing
a header to each transmition. See :http:post:`/containers/(id)/attach`.
The WebSocket attach is unchanged.
Note that attach calls on the previous API version didn't change. Stdout and
stderr are merged.
v1.5
****
Full Documentation
------------------
:doc:`docker_remote_api_v1.5`
*****************************
What's new
----------
@@ -57,15 +81,20 @@ What's new
dicts each containing `PublicPort`, `PrivatePort` and `Type` describing a
port mapping.
v1.4
****
Full Documentation
------------------
:doc:`docker_remote_api_v1.4`
*****************************
What's new
----------
.. http:post:: /images/create
**New!** When pull a repo, all images are now downloaded in parallel.
**New!** When pulling a repo, all images are now downloaded in parallel.
.. http:get:: /containers/(id)/top
@@ -75,11 +104,16 @@ What's new
**New!** Image's name added in the events
:doc:`docker_remote_api_v1.3`
*****************************
v1.3
****
docker v0.5.0 51f6c4a_
Full Documentation
------------------
:doc:`docker_remote_api_v1.3`
What's new
----------
@@ -112,11 +146,16 @@ Start containers (/containers/<id>/start):
- You can now pass host-specific configuration (e.g. bind mounts) in
the POST body for start calls
:doc:`docker_remote_api_v1.2`
*****************************
v1.2
****
docker v0.4.2 2e7649b_
Full Documentation
------------------
:doc:`docker_remote_api_v1.2`
What's new
----------
@@ -142,11 +181,16 @@ The client should send it's authConfig as POST on each call of
deleted/untagged.
:doc:`docker_remote_api_v1.1`
*****************************
v1.1
****
docker v0.4.0 a8ae398_
Full Documentation
------------------
:doc:`docker_remote_api_v1.1`
What's new
----------
@@ -166,12 +210,16 @@ What's new
{"error":"Invalid..."}
...
:doc:`docker_remote_api_v1.0`
*****************************
v1.0
****
docker v0.3.4 8d73740_
Full Documentation
------------------
:doc:`docker_remote_api_v1.0`
What's new
----------
@@ -182,36 +230,3 @@ Initial version
.. _8d73740: https://github.com/dotcloud/docker/commit/8d73740343778651c09160cde9661f5f387b36f4
.. _2e7649b: https://github.com/dotcloud/docker/commit/2e7649beda7c820793bd46766cbc2cfeace7b168
.. _51f6c4a: https://github.com/dotcloud/docker/commit/51f6c4a7372450d164c61e0054daf0223ddbd909
==================================
Docker Remote API Client Libraries
==================================
These libraries have not been tested by the Docker Maintainers for
compatibility. Please file issues with the library owners. If you
find more library implementations, please list them in Docker doc bugs
and we will add the libraries here.
+----------------------+----------------+--------------------------------------------+
| Language/Framework | Name | Repository |
+======================+================+============================================+
| Python | docker-py | https://github.com/dotcloud/docker-py |
+----------------------+----------------+--------------------------------------------+
| Ruby | docker-client | https://github.com/geku/docker-client |
+----------------------+----------------+--------------------------------------------+
| Ruby | docker-api | https://github.com/swipely/docker-api |
+----------------------+----------------+--------------------------------------------+
| Javascript (NodeJS) | docker.io | https://github.com/appersonlabs/docker.io |
| | | Install via NPM: `npm install docker.io` |
+----------------------+----------------+--------------------------------------------+
| Javascript | docker-js | https://github.com/dgoujard/docker-js |
+----------------------+----------------+--------------------------------------------+
| Javascript (Angular) | dockerui | https://github.com/crosbymichael/dockerui |
| **WebUI** | | |
+----------------------+----------------+--------------------------------------------+
| Java | docker-java | https://github.com/kpelykh/docker-java |
+----------------------+----------------+--------------------------------------------+
| Erlang | erldocker | https://github.com/proger/erldocker |
+----------------------+----------------+--------------------------------------------+
| Go | go-dockerclient| https://github.com/fsouza/go-dockerclient |
+----------------------+----------------+--------------------------------------------+
+19 -19
View File
@@ -49,28 +49,28 @@ List containers
[
{
"Id": "8dfafdbc3a40",
"Image": "base:latest",
"Image": "ubuntu:latest",
"Command": "echo 1",
"Created": 1367854155,
"Status": "Exit 0"
},
{
"Id": "9cd87474be90",
"Image": "base:latest",
"Image": "ubuntu:latest",
"Command": "echo 222222",
"Created": 1367854155,
"Status": "Exit 0"
},
{
"Id": "3176a2479c92",
"Image": "base:latest",
"Image": "centos:latest",
"Command": "echo 3333333333333333",
"Created": 1367854154,
"Status": "Exit 0"
},
{
"Id": "4cb07b47f9fb",
"Image": "base:latest",
"Image": "fedora:latest",
"Command": "echo 444444444444444444444444444444444",
"Created": 1367854152,
"Status": "Exit 0"
@@ -117,7 +117,7 @@ Create a container
"date"
],
"Dns":null,
"Image":"base",
"Image":"ubuntu",
"Volumes":{},
"VolumesFrom":""
}
@@ -183,7 +183,7 @@ Inspect a container
"date"
],
"Dns": null,
"Image": "base",
"Image": "ubuntu",
"Volumes": {},
"VolumesFrom": ""
},
@@ -490,14 +490,14 @@ List Images
[
{
"Repository":"base",
"Tag":"ubuntu-12.10",
"Repository":"ubuntu",
"Tag":"precise",
"Id":"b750fe79269d",
"Created":1364102658
},
{
"Repository":"base",
"Tag":"ubuntu-quantal",
"Repository":"ubuntu",
"Tag":"12.04",
"Id":"b750fe79269d",
"Created":1364102658
}
@@ -529,9 +529,9 @@ List Images
"d6434d954665" -> "d82cbacda43a"
base -> "e9aa60c60128" [style=invis]
"074be284591f" -> "f71189fff3de"
"b750fe79269d" [label="b750fe79269d\nbase",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"e9aa60c60128" [label="e9aa60c60128\nbase2",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"9a33b36209ed" [label="9a33b36209ed\ntest",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"b750fe79269d" [label="b750fe79269d\nubuntu",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"e9aa60c60128" [label="e9aa60c60128\ncentos",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"9a33b36209ed" [label="9a33b36209ed\nfedora",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
base [style=invisible]
}
@@ -552,7 +552,7 @@ Create an image
.. sourcecode:: http
POST /images/create?fromImage=base HTTP/1.1
POST /images/create?fromImage=ubuntu HTTP/1.1
**Example response**:
@@ -572,8 +572,8 @@ Create an image
:statuscode 500: server error
Insert a file in a image
************************
Insert a file in an image
*************************
.. http:post:: /images/(name)/insert
@@ -608,7 +608,7 @@ Inspect an image
.. sourcecode:: http
GET /images/base/json HTTP/1.1
GET /images/centos/json HTTP/1.1
**Example response**:
@@ -638,7 +638,7 @@ Inspect an image
"Env":null,
"Cmd": ["/bin/bash"]
,"Dns":null,
"Image":"base",
"Image":"centos",
"Volumes":null,
"VolumesFrom":""
}
@@ -660,7 +660,7 @@ Get the history of an image
.. sourcecode:: http
GET /images/base/history HTTP/1.1
GET /images/fedora/history HTTP/1.1
**Example response**:
+19 -19
View File
@@ -49,28 +49,28 @@ List containers
[
{
"Id": "8dfafdbc3a40",
"Image": "base:latest",
"Image": "ubuntu:latest",
"Command": "echo 1",
"Created": 1367854155,
"Status": "Exit 0"
},
{
"Id": "9cd87474be90",
"Image": "base:latest",
"Image": "ubuntu:latest",
"Command": "echo 222222",
"Created": 1367854155,
"Status": "Exit 0"
},
{
"Id": "3176a2479c92",
"Image": "base:latest",
"Image": "centos:latest",
"Command": "echo 3333333333333333",
"Created": 1367854154,
"Status": "Exit 0"
},
{
"Id": "4cb07b47f9fb",
"Image": "base:latest",
"Image": "fedora:latest",
"Command": "echo 444444444444444444444444444444444",
"Created": 1367854152,
"Status": "Exit 0"
@@ -117,7 +117,7 @@ Create a container
"date"
],
"Dns":null,
"Image":"base",
"Image":"ubuntu",
"Volumes":{},
"VolumesFrom":""
}
@@ -183,7 +183,7 @@ Inspect a container
"date"
],
"Dns": null,
"Image": "base",
"Image": "ubuntu",
"Volumes": {},
"VolumesFrom": ""
},
@@ -490,14 +490,14 @@ List Images
[
{
"Repository":"base",
"Tag":"ubuntu-12.10",
"Repository":"ubuntu",
"Tag":"precise",
"Id":"b750fe79269d",
"Created":1364102658
},
{
"Repository":"base",
"Tag":"ubuntu-quantal",
"Repository":"ubuntu",
"Tag":"12.04",
"Id":"b750fe79269d",
"Created":1364102658
}
@@ -529,9 +529,9 @@ List Images
"d6434d954665" -> "d82cbacda43a"
base -> "e9aa60c60128" [style=invis]
"074be284591f" -> "f71189fff3de"
"b750fe79269d" [label="b750fe79269d\nbase",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"e9aa60c60128" [label="e9aa60c60128\nbase2",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"9a33b36209ed" [label="9a33b36209ed\ntest",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"b750fe79269d" [label="b750fe79269d\nubuntu",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"e9aa60c60128" [label="e9aa60c60128\ncentos",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"9a33b36209ed" [label="9a33b36209ed\nfedora",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
base [style=invisible]
}
@@ -552,7 +552,7 @@ Create an image
.. sourcecode:: http
POST /images/create?fromImage=base HTTP/1.1
POST /images/create?fromImage=ubuntu HTTP/1.1
**Example response**:
@@ -575,8 +575,8 @@ Create an image
:statuscode 500: server error
Insert a file in a image
************************
Insert a file in an image
*************************
.. http:post:: /images/(name)/insert
@@ -615,7 +615,7 @@ Inspect an image
.. sourcecode:: http
GET /images/base/json HTTP/1.1
GET /images/centos/json HTTP/1.1
**Example response**:
@@ -645,7 +645,7 @@ Inspect an image
"Env":null,
"Cmd": ["/bin/bash"]
,"Dns":null,
"Image":"base",
"Image":"centos",
"Volumes":null,
"VolumesFrom":""
}
@@ -667,7 +667,7 @@ Get the history of an image
.. sourcecode:: http
GET /images/base/history HTTP/1.1
GET /images/fedora/history HTTP/1.1
**Example response**:
+20 -20
View File
@@ -49,7 +49,7 @@ List containers
[
{
"Id": "8dfafdbc3a40",
"Image": "base:latest",
"Image": "ubuntu:latest",
"Command": "echo 1",
"Created": 1367854155,
"Status": "Exit 0",
@@ -59,7 +59,7 @@ List containers
},
{
"Id": "9cd87474be90",
"Image": "base:latest",
"Image": "ubuntu:latest",
"Command": "echo 222222",
"Created": 1367854155,
"Status": "Exit 0",
@@ -69,7 +69,7 @@ List containers
},
{
"Id": "3176a2479c92",
"Image": "base:latest",
"Image": "centos:latest",
"Command": "echo 3333333333333333",
"Created": 1367854154,
"Status": "Exit 0",
@@ -79,7 +79,7 @@ List containers
},
{
"Id": "4cb07b47f9fb",
"Image": "base:latest",
"Image": "fedora:latest",
"Command": "echo 444444444444444444444444444444444",
"Created": 1367854152,
"Status": "Exit 0",
@@ -129,7 +129,7 @@ Create a container
"date"
],
"Dns":null,
"Image":"base",
"Image":"ubuntu",
"Volumes":{},
"VolumesFrom":""
}
@@ -195,7 +195,7 @@ Inspect a container
"date"
],
"Dns": null,
"Image": "base",
"Image": "ubuntu",
"Volumes": {},
"VolumesFrom": ""
},
@@ -502,16 +502,16 @@ List Images
[
{
"Repository":"base",
"Tag":"ubuntu-12.10",
"Repository":"ubuntu",
"Tag":"precise",
"Id":"b750fe79269d",
"Created":1364102658,
"Size":24653,
"VirtualSize":180116135
},
{
"Repository":"base",
"Tag":"ubuntu-quantal",
"Repository":"ubuntu",
"Tag":"12.04",
"Id":"b750fe79269d",
"Created":1364102658,
"Size":24653,
@@ -545,9 +545,9 @@ List Images
"d6434d954665" -> "d82cbacda43a"
base -> "e9aa60c60128" [style=invis]
"074be284591f" -> "f71189fff3de"
"b750fe79269d" [label="b750fe79269d\nbase",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"e9aa60c60128" [label="e9aa60c60128\nbase2",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"9a33b36209ed" [label="9a33b36209ed\ntest",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"b750fe79269d" [label="b750fe79269d\nubuntu",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"e9aa60c60128" [label="e9aa60c60128\ncentos",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"9a33b36209ed" [label="9a33b36209ed\nfedora",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
base [style=invisible]
}
@@ -568,7 +568,7 @@ Create an image
.. sourcecode:: http
POST /images/create?fromImage=base HTTP/1.1
POST /images/create?fromImage=ubuntu HTTP/1.1
**Example response**:
@@ -591,8 +591,8 @@ Create an image
:statuscode 500: server error
Insert a file in a image
************************
Insert a file in an image
*************************
.. http:post:: /images/(name)/insert
@@ -631,7 +631,7 @@ Inspect an image
.. sourcecode:: http
GET /images/base/json HTTP/1.1
GET /images/centos/json HTTP/1.1
**Example response**:
@@ -661,7 +661,7 @@ Inspect an image
"Env":null,
"Cmd": ["/bin/bash"]
,"Dns":null,
"Image":"base",
"Image":"centos",
"Volumes":null,
"VolumesFrom":""
},
@@ -684,7 +684,7 @@ Get the history of an image
.. sourcecode:: http
GET /images/base/history HTTP/1.1
GET /images/fedora/history HTTP/1.1
**Example response**:
@@ -696,7 +696,7 @@ Get the history of an image
[
{
"Id":"b750fe79269d",
"Tag":["base:latest"],
"Tag":["ubuntu:latest"],
"Created":1364102658,
"CreatedBy":"/bin/bash"
},
+19 -19
View File
@@ -49,7 +49,7 @@ List containers
[
{
"Id": "8dfafdbc3a40",
"Image": "base:latest",
"Image": "ubuntu:latest",
"Command": "echo 1",
"Created": 1367854155,
"Status": "Exit 0",
@@ -59,7 +59,7 @@ List containers
},
{
"Id": "9cd87474be90",
"Image": "base:latest",
"Image": "ubuntu:latest",
"Command": "echo 222222",
"Created": 1367854155,
"Status": "Exit 0",
@@ -69,7 +69,7 @@ List containers
},
{
"Id": "3176a2479c92",
"Image": "base:latest",
"Image": "centos:latest",
"Command": "echo 3333333333333333",
"Created": 1367854154,
"Status": "Exit 0",
@@ -79,7 +79,7 @@ List containers
},
{
"Id": "4cb07b47f9fb",
"Image": "base:latest",
"Image": "fedora:latest",
"Command": "echo 444444444444444444444444444444444",
"Created": 1367854152,
"Status": "Exit 0",
@@ -130,7 +130,7 @@ Create a container
"date"
],
"Dns":null,
"Image":"base",
"Image":"ubuntu",
"Volumes":{},
"VolumesFrom":""
}
@@ -196,7 +196,7 @@ Inspect a container
"date"
],
"Dns": null,
"Image": "base",
"Image": "ubuntu",
"Volumes": {},
"VolumesFrom": ""
},
@@ -550,16 +550,16 @@ List Images
[
{
"Repository":"base",
"Tag":"ubuntu-12.10",
"Repository":"ubuntu",
"Tag":"precise",
"Id":"b750fe79269d",
"Created":1364102658,
"Size":24653,
"VirtualSize":180116135
},
{
"Repository":"base",
"Tag":"ubuntu-quantal",
"Repository":"ubuntu",
"Tag":"12.04",
"Id":"b750fe79269d",
"Created":1364102658,
"Size":24653,
@@ -593,9 +593,9 @@ List Images
"d6434d954665" -> "d82cbacda43a"
base -> "e9aa60c60128" [style=invis]
"074be284591f" -> "f71189fff3de"
"b750fe79269d" [label="b750fe79269d\nbase",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"e9aa60c60128" [label="e9aa60c60128\nbase2",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"9a33b36209ed" [label="9a33b36209ed\ntest",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"b750fe79269d" [label="b750fe79269d\nubuntu",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"e9aa60c60128" [label="e9aa60c60128\ncentos",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"9a33b36209ed" [label="9a33b36209ed\nfedora",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
base [style=invisible]
}
@@ -616,7 +616,7 @@ Create an image
.. sourcecode:: http
POST /images/create?fromImage=base HTTP/1.1
POST /images/create?fromImage=ubuntu HTTP/1.1
**Example response**:
@@ -639,8 +639,8 @@ Create an image
:statuscode 500: server error
Insert a file in a image
************************
Insert a file in an image
*************************
.. http:post:: /images/(name)/insert
@@ -679,7 +679,7 @@ Inspect an image
.. sourcecode:: http
GET /images/base/json HTTP/1.1
GET /images/centos/json HTTP/1.1
**Example response**:
@@ -709,7 +709,7 @@ Inspect an image
"Env":null,
"Cmd": ["/bin/bash"]
,"Dns":null,
"Image":"base",
"Image":"centos",
"Volumes":null,
"VolumesFrom":""
},
@@ -732,7 +732,7 @@ Get the history of an image
.. sourcecode:: http
GET /images/base/history HTTP/1.1
GET /images/fedora/history HTTP/1.1
**Example response**:
+21 -21
View File
@@ -46,7 +46,7 @@ List containers
[
{
"Id": "8dfafdbc3a40",
"Image": "base:latest",
"Image": "ubuntu:latest",
"Command": "echo 1",
"Created": 1367854155,
"Status": "Exit 0",
@@ -56,7 +56,7 @@ List containers
},
{
"Id": "9cd87474be90",
"Image": "base:latest",
"Image": "ubuntu:latest",
"Command": "echo 222222",
"Created": 1367854155,
"Status": "Exit 0",
@@ -66,7 +66,7 @@ List containers
},
{
"Id": "3176a2479c92",
"Image": "base:latest",
"Image": "centos:latest",
"Command": "echo 3333333333333333",
"Created": 1367854154,
"Status": "Exit 0",
@@ -76,7 +76,7 @@ List containers
},
{
"Id": "4cb07b47f9fb",
"Image": "base:latest",
"Image": "fedora:latest",
"Command": "echo 444444444444444444444444444444444",
"Created": 1367854152,
"Status": "Exit 0",
@@ -128,7 +128,7 @@ Create a container
"date"
],
"Dns":null,
"Image":"base",
"Image":"ubuntu",
"Volumes":{},
"VolumesFrom":"",
"WorkingDir":""
@@ -196,7 +196,7 @@ Inspect a container
"date"
],
"Dns": null,
"Image": "base",
"Image": "ubuntu",
"Volumes": {},
"VolumesFrom": "",
"WorkingDir":""
@@ -592,16 +592,16 @@ List Images
[
{
"Repository":"base",
"Tag":"ubuntu-12.10",
"Repository":"ubuntu",
"Tag":"precise",
"Id":"b750fe79269d",
"Created":1364102658,
"Size":24653,
"VirtualSize":180116135
},
{
"Repository":"base",
"Tag":"ubuntu-quantal",
"Repository":"ubuntu",
"Tag":"12.04",
"Id":"b750fe79269d",
"Created":1364102658,
"Size":24653,
@@ -635,9 +635,9 @@ List Images
"d6434d954665" -> "d82cbacda43a"
base -> "e9aa60c60128" [style=invis]
"074be284591f" -> "f71189fff3de"
"b750fe79269d" [label="b750fe79269d\nbase",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"e9aa60c60128" [label="e9aa60c60128\nbase2",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"9a33b36209ed" [label="9a33b36209ed\ntest",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"b750fe79269d" [label="b750fe79269d\nubuntu",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"e9aa60c60128" [label="e9aa60c60128\ncentos",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
"9a33b36209ed" [label="9a33b36209ed\nfedora",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
base [style=invisible]
}
@@ -658,7 +658,7 @@ Create an image
.. sourcecode:: http
POST /images/create?fromImage=base HTTP/1.1
POST /images/create?fromImage=ubuntu HTTP/1.1
**Example response**:
@@ -721,7 +721,7 @@ Inspect an image
.. sourcecode:: http
GET /images/base/json HTTP/1.1
GET /images/centos/json HTTP/1.1
**Example response**:
@@ -751,7 +751,7 @@ Inspect an image
"Env":null,
"Cmd": ["/bin/bash"]
,"Dns":null,
"Image":"base",
"Image":"centos",
"Volumes":null,
"VolumesFrom":"",
"WorkingDir":""
@@ -776,7 +776,7 @@ Get the history of an image
.. sourcecode:: http
GET /images/base/history HTTP/1.1
GET /images/fedora/history HTTP/1.1
**Example response**:
@@ -1126,10 +1126,10 @@ Monitor Docker's events
HTTP/1.1 200 OK
Content-Type: application/json
{"status":"create","id":"dfdf82bd3881","from":"base:latest","time":1374067924}
{"status":"start","id":"dfdf82bd3881","from":"base:latest","time":1374067924}
{"status":"stop","id":"dfdf82bd3881","from":"base:latest","time":1374067966}
{"status":"destroy","id":"dfdf82bd3881","from":"base:latest","time":1374067970}
{"status":"create","id":"dfdf82bd3881","from":"ubuntu:latest","time":1374067924}
{"status":"start","id":"dfdf82bd3881","from":"ubuntu:latest","time":1374067924}
{"status":"stop","id":"dfdf82bd3881","from":"ubuntu:latest","time":1374067966}
{"status":"destroy","id":"dfdf82bd3881","from":"ubuntu:latest","time":1374067970}
:query since: timestamp used for polling
:statuscode 200: no error
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -14,5 +14,5 @@ Your programs and scripts can access Docker's functionality via these interfaces
registry_api
index_api
docker_remote_api
remote_api_client_libraries
+26 -23
View File
@@ -6,8 +6,6 @@
Docker Index API
=================
.. contents:: Table of Contents
1. Brief introduction
=====================
@@ -42,7 +40,7 @@ User Repo
Authorization: Basic akmklmasadalkm==
X-Docker-Token: true
[{id: 9e89cc6f0bc3c38722009fe6857087b486531f9a779a0c17e3ed29dae8f12c4f}]
[{"id": "9e89cc6f0bc3c38722009fe6857087b486531f9a779a0c17e3ed29dae8f12c4f"}]
:parameter namespace: the namespace for the repo
:parameter repo_name: the name for the repo
@@ -54,7 +52,8 @@ User Repo
HTTP/1.1 200
Vary: Accept
Content-Type: application/json
WWW-Authenticate: Token signature=123abc,repository=foo/bar,access=write
WWW-Authenticate: Token signature=123abc,repository="foo/bar",access=write
X-Docker-Token: signature=123abc,repository="foo/bar",access=write
X-Docker-Endpoints: registry-1.docker.io [, registry-2.docker.io]
""
@@ -92,7 +91,8 @@ User Repo
HTTP/1.1 202
Vary: Accept
Content-Type: application/json
WWW-Authenticate: Token signature=123abc,repository=foo/bar,access=delete
WWW-Authenticate: Token signature=123abc,repository="foo/bar",access=delete
X-Docker-Token: signature=123abc,repository="foo/bar",access=delete
X-Docker-Endpoints: registry-1.docker.io [, registry-2.docker.io]
""
@@ -124,7 +124,7 @@ Library Repo
Authorization: Basic akmklmasadalkm==
X-Docker-Token: true
[{id: 9e89cc6f0bc3c38722009fe6857087b486531f9a779a0c17e3ed29dae8f12c4f}]
[{"id": "9e89cc6f0bc3c38722009fe6857087b486531f9a779a0c17e3ed29dae8f12c4f"}]
:parameter repo_name: the library name for the repo
@@ -135,7 +135,8 @@ Library Repo
HTTP/1.1 200
Vary: Accept
Content-Type: application/json
WWW-Authenticate: Token signature=123abc,repository=library/foobar,access=write
WWW-Authenticate: Token signature=123abc,repository="library/foobar",access=write
X-Docker-Token: signature=123abc,repository="foo/bar",access=write
X-Docker-Endpoints: registry-1.docker.io [, registry-2.docker.io]
""
@@ -174,7 +175,8 @@ Library Repo
HTTP/1.1 202
Vary: Accept
Content-Type: application/json
WWW-Authenticate: Token signature=123abc,repository=library/foobar,access=delete
WWW-Authenticate: Token signature=123abc,repository="library/foobar",access=delete
X-Docker-Token: signature=123abc,repository="foo/bar",access=delete
X-Docker-Endpoints: registry-1.docker.io [, registry-2.docker.io]
""
@@ -205,8 +207,8 @@ User Repo Images
Content-Type: application/json
Authorization: Basic akmklmasadalkm==
[{id: 9e89cc6f0bc3c38722009fe6857087b486531f9a779a0c17e3ed29dae8f12c4f,
checksum: b486531f9a779a0c17e3ed29dae8f12c4f9e89cc6f0bc3c38722009fe6857087}]
[{"id": "9e89cc6f0bc3c38722009fe6857087b486531f9a779a0c17e3ed29dae8f12c4f",
"checksum": "b486531f9a779a0c17e3ed29dae8f12c4f9e89cc6f0bc3c38722009fe6857087"}]
:parameter namespace: the namespace for the repo
:parameter repo_name: the name for the repo
@@ -250,10 +252,10 @@ User Repo Images
Vary: Accept
Content-Type: application/json
[{id: 9e89cc6f0bc3c38722009fe6857087b486531f9a779a0c17e3ed29dae8f12c4f,
checksum: b486531f9a779a0c17e3ed29dae8f12c4f9e89cc6f0bc3c38722009fe6857087},
{id: ertwetewtwe38722009fe6857087b486531f9a779a0c1dfddgfgsdgdsgds,
checksum: 34t23f23fc17e3ed29dae8f12c4f9e89cc6f0bsdfgfsdgdsgdsgerwgew}]
[{"id": "9e89cc6f0bc3c38722009fe6857087b486531f9a779a0c17e3ed29dae8f12c4f",
"checksum": "b486531f9a779a0c17e3ed29dae8f12c4f9e89cc6f0bc3c38722009fe6857087"},
{"id": "ertwetewtwe38722009fe6857087b486531f9a779a0c1dfddgfgsdgdsgds",
"checksum": "34t23f23fc17e3ed29dae8f12c4f9e89cc6f0bsdfgfsdgdsgdsgerwgew"}]
:statuscode 200: OK
:statuscode 404: Not found
@@ -275,8 +277,8 @@ Library Repo Images
Content-Type: application/json
Authorization: Basic akmklmasadalkm==
[{id: 9e89cc6f0bc3c38722009fe6857087b486531f9a779a0c17e3ed29dae8f12c4f,
checksum: b486531f9a779a0c17e3ed29dae8f12c4f9e89cc6f0bc3c38722009fe6857087}]
[{"id": "9e89cc6f0bc3c38722009fe6857087b486531f9a779a0c17e3ed29dae8f12c4f",
"checksum": "b486531f9a779a0c17e3ed29dae8f12c4f9e89cc6f0bc3c38722009fe6857087"}]
:parameter repo_name: the library name for the repo
@@ -318,10 +320,10 @@ Library Repo Images
Vary: Accept
Content-Type: application/json
[{id: 9e89cc6f0bc3c38722009fe6857087b486531f9a779a0c17e3ed29dae8f12c4f,
checksum: b486531f9a779a0c17e3ed29dae8f12c4f9e89cc6f0bc3c38722009fe6857087},
{id: ertwetewtwe38722009fe6857087b486531f9a779a0c1dfddgfgsdgdsgds,
checksum: 34t23f23fc17e3ed29dae8f12c4f9e89cc6f0bsdfgfsdgdsgdsgerwgew}]
[{"id": "9e89cc6f0bc3c38722009fe6857087b486531f9a779a0c17e3ed29dae8f12c4f",
"checksum": "b486531f9a779a0c17e3ed29dae8f12c4f9e89cc6f0bc3c38722009fe6857087"},
{"id": "ertwetewtwe38722009fe6857087b486531f9a779a0c1dfddgfgsdgdsgds",
"checksum": "34t23f23fc17e3ed29dae8f12c4f9e89cc6f0bsdfgfsdgdsgdsgerwgew"}]
:statuscode 200: OK
:statuscode 404: Not found
@@ -541,10 +543,11 @@ Search
Content-Type: application/json
{"query":"search_term",
"num_results": 2,
"num_results": 3,
"results" : [
{"name": "dotcloud/base", "description": "A base ubuntu64 image..."},
{"name": "base2", "description": "A base ubuntu64 image..."},
{"name": "ubuntu", "description": "An ubuntu image..."},
{"name": "centos", "description": "A centos image..."},
{"name": "fedora", "description": "A fedora image..."}
]
}
+114 -77
View File
@@ -6,7 +6,6 @@
Docker Registry API
===================
.. contents:: Table of Contents
1. Brief introduction
=====================
@@ -61,7 +60,7 @@ Layer
Host: registry-1.docker.io
Accept: application/json
Content-Type: application/json
Authorization: Token akmklmasadalkmsdfgsdgdge33
Authorization: Token signature=123abc,repository="foo/bar",access=read
:parameter image_id: the id for the layer you want to get
@@ -71,39 +70,10 @@ Layer
HTTP/1.1 200
Vary: Accept
Content-Type: application/json
X-Docker-Registry-Version: 0.6.0
Cookie: (Cookie provided by the Registry)
{
id: "088b4505aa3adc3d35e79c031fa126b403200f02f51920fbd9b7c503e87c7a2c",
parent: "aeee6396d62273d180a49c96c62e45438d87c7da4a5cf5d2be6bee4e21bc226f",
created: "2013-04-30T17:46:10.843673+03:00",
container: "8305672a76cc5e3d168f97221106ced35a76ec7ddbb03209b0f0d96bf74f6ef7",
container_config: {
Hostname: "host-test",
User: "",
Memory: 0,
MemorySwap: 0,
AttachStdin: false,
AttachStdout: false,
AttachStderr: false,
PortSpecs: null,
Tty: false,
OpenStdin: false,
StdinOnce: false,
Env: null,
Cmd: [
"/bin/bash",
"-c",
"apt-get -q -yy -f install libevent-dev"
],
Dns: null,
Image: "imagename/blah",
Volumes: { },
VolumesFrom: ""
},
docker_version: "0.1.7"
}
{layer binary data stream}
:statuscode 200: OK
:statuscode 401: Requires authorization
@@ -120,40 +90,10 @@ Layer
PUT /v1/images/088b4505aa3adc3d35e79c031fa126b403200f02f51920fbd9b7c503e87c7a2c/layer HTTP/1.1
Host: registry-1.docker.io
Accept: application/json
Content-Type: application/json
Authorization: Token akmklmasadalkmsdfgsdgdge33
Transfer-Encoding: chunked
Authorization: Token signature=123abc,repository="foo/bar",access=write
{
id: "088b4505aa3adc3d35e79c031fa126b403200f02f51920fbd9b7c503e87c7a2c",
parent: "aeee6396d62273d180a49c96c62e45438d87c7da4a5cf5d2be6bee4e21bc226f",
created: "2013-04-30T17:46:10.843673+03:00",
container: "8305672a76cc5e3d168f97221106ced35a76ec7ddbb03209b0f0d96bf74f6ef7",
container_config: {
Hostname: "host-test",
User: "",
Memory: 0,
MemorySwap: 0,
AttachStdin: false,
AttachStdout: false,
AttachStderr: false,
PortSpecs: null,
Tty: false,
OpenStdin: false,
StdinOnce: false,
Env: null,
Cmd: [
"/bin/bash",
"-c",
"apt-get -q -yy -f install libevent-dev"
],
Dns: null,
Image: "imagename/blah",
Volumes: { },
VolumesFrom: ""
},
docker_version: "0.1.7"
}
{layer binary data stream}
:parameter image_id: the id for the layer you want to get
@@ -165,6 +105,7 @@ Layer
HTTP/1.1 200
Vary: Accept
Content-Type: application/json
X-Docker-Registry-Version: 0.6.0
""
@@ -191,13 +132,38 @@ Image
Cookie: (Cookie provided by the Registry)
{
id: 088b4505aa3adc3d35e79c031fa126b403200f02f51920fbd9b7c503e87c7a2c,
“checksum”: “sha256:b486531f9a779a0c17e3ed29dae8f12c4f9e89cc6f0bc3c38722009fe6857087”
}
id: "088b4505aa3adc3d35e79c031fa126b403200f02f51920fbd9b7c503e87c7a2c",
parent: "aeee6396d62273d180a49c96c62e45438d87c7da4a5cf5d2be6bee4e21bc226f",
created: "2013-04-30T17:46:10.843673+03:00",
container: "8305672a76cc5e3d168f97221106ced35a76ec7ddbb03209b0f0d96bf74f6ef7",
container_config: {
Hostname: "host-test",
User: "",
Memory: 0,
MemorySwap: 0,
AttachStdin: false,
AttachStdout: false,
AttachStderr: false,
PortSpecs: null,
Tty: false,
OpenStdin: false,
StdinOnce: false,
Env: null,
Cmd: [
"/bin/bash",
"-c",
"apt-get -q -yy -f install libevent-dev"
],
Dns: null,
Image: "imagename/blah",
Volumes: { },
VolumesFrom: ""
},
docker_version: "0.1.7"
}
:parameter image_id: the id for the layer you want to get
**Example Response**:
.. sourcecode:: http
@@ -205,6 +171,7 @@ Image
HTTP/1.1 200
Vary: Accept
Content-Type: application/json
X-Docker-Registry-Version: 0.6.0
""
@@ -234,11 +201,40 @@ Image
HTTP/1.1 200
Vary: Accept
Content-Type: application/json
X-Docker-Registry-Version: 0.6.0
X-Docker-Size: 456789
X-Docker-Checksum: b486531f9a779a0c17e3ed29dae8f12c4f9e89cc6f0bc3c38722009fe6857087
{
id: 088b4505aa3adc3d35e79c031fa126b403200f02f51920fbd9b7c503e87c7a2c,
“checksum”: “sha256:b486531f9a779a0c17e3ed29dae8f12c4f9e89cc6f0bc3c38722009fe6857087”
}
id: "088b4505aa3adc3d35e79c031fa126b403200f02f51920fbd9b7c503e87c7a2c",
parent: "aeee6396d62273d180a49c96c62e45438d87c7da4a5cf5d2be6bee4e21bc226f",
created: "2013-04-30T17:46:10.843673+03:00",
container: "8305672a76cc5e3d168f97221106ced35a76ec7ddbb03209b0f0d96bf74f6ef7",
container_config: {
Hostname: "host-test",
User: "",
Memory: 0,
MemorySwap: 0,
AttachStdin: false,
AttachStdout: false,
AttachStderr: false,
PortSpecs: null,
Tty: false,
OpenStdin: false,
StdinOnce: false,
Env: null,
Cmd: [
"/bin/bash",
"-c",
"apt-get -q -yy -f install libevent-dev"
],
Dns: null,
Image: "imagename/blah",
Volumes: { },
VolumesFrom: ""
},
docker_version: "0.1.7"
}
:statuscode 200: OK
:statuscode 401: Requires authorization
@@ -271,6 +267,7 @@ Ancestry
HTTP/1.1 200
Vary: Accept
Content-Type: application/json
X-Docker-Registry-Version: 0.6.0
["088b4502f51920fbd9b7c503e87c7a2c05aa3adc3d35e79c031fa126b403200f",
"aeee63968d87c7da4a5cf5d2be6bee4e21bc226fd62273d180a49c96c62e4543",
@@ -297,6 +294,7 @@ Ancestry
Host: registry-1.docker.io
Accept: application/json
Content-Type: application/json
X-Docker-Registry-Version: 0.6.0
Cookie: (Cookie provided by the Registry)
:parameter namespace: namespace for the repo
@@ -309,10 +307,11 @@ Ancestry
HTTP/1.1 200
Vary: Accept
Content-Type: application/json
X-Docker-Registry-Version: 0.6.0
{
"latest": "9e89cc6f0bc3c38722009fe6857087b486531f9a779a0c17e3ed29dae8f12c4f",
0.1.1: b486531f9a779a0c17e3ed29dae8f12c4f9e89cc6f0bc3c38722009fe6857087
"0.1.1": "b486531f9a779a0c17e3ed29dae8f12c4f9e89cc6f0bc3c38722009fe6857087"
}
:statuscode 200: OK
@@ -332,6 +331,7 @@ Ancestry
Host: registry-1.docker.io
Accept: application/json
Content-Type: application/json
X-Docker-Registry-Version: 0.6.0
Cookie: (Cookie provided by the Registry)
:parameter namespace: namespace for the repo
@@ -345,6 +345,7 @@ Ancestry
HTTP/1.1 200
Vary: Accept
Content-Type: application/json
X-Docker-Registry-Version: 0.6.0
"9e89cc6f0bc3c38722009fe6857087b486531f9a779a0c17e3ed29dae8f12c4f"
@@ -377,6 +378,7 @@ Ancestry
HTTP/1.1 200
Vary: Accept
Content-Type: application/json
X-Docker-Registry-Version: 0.6.0
""
@@ -399,7 +401,7 @@ Ancestry
Content-Type: application/json
Cookie: (Cookie provided by the Registry)
9e89cc6f0bc3c38722009fe6857087b486531f9a779a0c17e3ed29dae8f12c4f
"9e89cc6f0bc3c38722009fe6857087b486531f9a779a0c17e3ed29dae8f12c4f"
:parameter namespace: namespace for the repo
:parameter repository: name for the repo
@@ -412,6 +414,7 @@ Ancestry
HTTP/1.1 200
Vary: Accept
Content-Type: application/json
X-Docker-Registry-Version: 0.6.0
""
@@ -449,6 +452,7 @@ Ancestry
HTTP/1.1 200
Vary: Accept
Content-Type: application/json
X-Docker-Registry-Version: 0.6.0
""
@@ -456,8 +460,41 @@ Ancestry
:statuscode 401: Requires authorization
:statuscode 404: Repository not found
3.0 Authorization
=================
2.4 Status
----------
.. http:get:: /v1/_ping
Check status of the registry. This endpoint is also used to determine if
the registry supports SSL.
**Example Request**:
.. sourcecode:: http
GET /v1/_ping HTTP/1.1
Host: registry-1.docker.io
Accept: application/json
Content-Type: application/json
""
**Example Response**:
.. sourcecode:: http
HTTP/1.1 200
Vary: Accept
Content-Type: application/json
X-Docker-Registry-Version: 0.6.0
""
:statuscode 200: OK
3 Authorization
===============
This is where we describe the authorization process, including the tokens and cookies.
TODO: add more info.
+2 -4
View File
@@ -8,8 +8,6 @@
Registry & Index Spec
=====================
.. contents:: Table of Contents
1. The 3 roles
===============
@@ -564,8 +562,8 @@ Next request::
Cookie: session="wD/J7LqL5ctqw8haL10vgfhrb2Q=?foo=UydiYXInCnAxCi4=&timestamp=RjEzNjYzMTQ5NDcuNDc0NjQzCi4="
7.0 Document Version
---------------------
7 Document Version
====================
- 1.0 : May 6th 2013 : initial release
- 1.1 : June 1st 2013 : Added Delete Repository and way to handle new source namespace.
@@ -0,0 +1,37 @@
:title: Registry API
:description: Various client libraries available to use with the Docker remote API
:keywords: API, Docker, index, registry, REST, documentation, clients, Python, Ruby, Javascript, Erlang, Go
==================================
Docker Remote API Client Libraries
==================================
These libraries have not been tested by the Docker Maintainers for
compatibility. Please file issues with the library owners. If you
find more library implementations, please list them in Docker doc bugs
and we will add the libraries here.
+----------------------+----------------+--------------------------------------------+
| Language/Framework | Name | Repository |
+======================+================+============================================+
| Python | docker-py | https://github.com/dotcloud/docker-py |
+----------------------+----------------+--------------------------------------------+
| Ruby | docker-client | https://github.com/geku/docker-client |
+----------------------+----------------+--------------------------------------------+
| Ruby | docker-api | https://github.com/swipely/docker-api |
+----------------------+----------------+--------------------------------------------+
| Javascript (NodeJS) | docker.io | https://github.com/appersonlabs/docker.io |
| | | Install via NPM: `npm install docker.io` |
+----------------------+----------------+--------------------------------------------+
| Javascript | docker-js | https://github.com/dgoujard/docker-js |
+----------------------+----------------+--------------------------------------------+
| Javascript (Angular) | dockerui | https://github.com/crosbymichael/dockerui |
| **WebUI** | | |
+----------------------+----------------+--------------------------------------------+
| Java | docker-java | https://github.com/kpelykh/docker-java |
+----------------------+----------------+--------------------------------------------+
| Erlang | erldocker | https://github.com/proger/erldocker |
+----------------------+----------------+--------------------------------------------+
| Go | go-dockerclient| https://github.com/fsouza/go-dockerclient |
+----------------------+----------------+--------------------------------------------+
+746 -40
View File
@@ -4,11 +4,8 @@
.. _cli:
Overview
======================
Docker Usage
~~~~~~~~~~~~
Command Line Help
-----------------
To list available commands, either run ``docker`` with no parameters or execute
``docker help``::
@@ -21,40 +18,749 @@ To list available commands, either run ``docker`` with no parameters or execute
...
Available Commands
~~~~~~~~~~~~~~~~~~
.. _cli_attach:
``attach``
----------
::
Usage: docker attach CONTAINER
Attach to a running container.
You can detach from the container again (and leave it running) with
``CTRL-c`` (for a quiet exit) or ``CTRL-\`` to get a stacktrace of
the Docker client when it quits.
To stop a container, use ``docker stop``
To kill the container, use ``docker kill``
.. _cli_attach_examples:
Examples:
~~~~~~~~~
.. code-block:: bash
$ ID=$(sudo docker run -d ubuntu /usr/bin/top -b)
$ sudo docker attach $ID
top - 02:05:52 up 3:05, 0 users, load average: 0.01, 0.02, 0.05
Tasks: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie
Cpu(s): 0.1%us, 0.2%sy, 0.0%ni, 99.7%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 373572k total, 355560k used, 18012k free, 27872k buffers
Swap: 786428k total, 0k used, 786428k free, 221740k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 17200 1116 912 R 0 0.3 0:00.03 top
top - 02:05:55 up 3:05, 0 users, load average: 0.01, 0.02, 0.05
Tasks: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie
Cpu(s): 0.0%us, 0.2%sy, 0.0%ni, 99.8%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 373572k total, 355244k used, 18328k free, 27872k buffers
Swap: 786428k total, 0k used, 786428k free, 221776k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 17208 1144 932 R 0 0.3 0:00.03 top
top - 02:05:58 up 3:06, 0 users, load average: 0.01, 0.02, 0.05
Tasks: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie
Cpu(s): 0.2%us, 0.3%sy, 0.0%ni, 99.5%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 373572k total, 355780k used, 17792k free, 27880k buffers
Swap: 786428k total, 0k used, 786428k free, 221776k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 17208 1144 932 R 0 0.3 0:00.03 top
^C$
$ sudo docker stop $ID
.. _cli_build:
``build``
---------
::
Usage: docker build [OPTIONS] PATH | URL | -
Build a new container image from the source code at PATH
-t="": Repository name (and optionally a tag) to be applied to the resulting image in case of success.
-q=false: Suppress verbose build output.
-no-cache: Do not use the cache when building the image.
-rm: Remove intermediate containers after a successful build
When a single Dockerfile is given as URL, then no context is set. When a git repository is set as URL, the repository is used as context
.. _cli_build_examples:
Examples:
~~~~~~~~~
.. code-block:: bash
sudo docker build .
This will read the ``Dockerfile`` from the current directory. It will
also send any other files and directories found in the current
directory to the ``docker`` daemon.
The contents of this directory would be used by ``ADD`` commands found
within the ``Dockerfile``. This will send a lot of data to the
``docker`` daemon if the current directory contains a lot of data. If
the absolute path is provided instead of ``.`` then only the files and
directories required by the ADD commands from the ``Dockerfile`` will be
added to the context and transferred to the ``docker`` daemon.
.. code-block:: bash
sudo docker build -t vieux/apache:2.0 .
This will build like the previous example, but it will then tag the
resulting image. The repository name will be ``vieux/apache`` and the
tag will be ``2.0``
.. code-block:: bash
sudo docker build - < Dockerfile
This will read a ``Dockerfile`` from *stdin* without context. Due to
the lack of a context, no contents of any local directory will be sent
to the ``docker`` daemon. ``ADD`` doesn't work when running in this
mode because the absence of the context provides no source files to
copy to the container.
.. code-block:: bash
sudo docker build github.com/creack/docker-firefox
This will clone the Github repository and use it as context. The
``Dockerfile`` at the root of the repository is used as
``Dockerfile``. Note that you can specify an arbitrary git repository
by using the ``git://`` schema.
.. _cli_commit:
``commit``
----------
::
Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY [TAG]]
Create a new image from a container's changes
-m="": Commit message
-author="": Author (eg. "John Hannibal Smith <hannibal@a-team.com>"
-run="": Configuration to be applied when the image is launched with `docker run`.
(ex: '{"Cmd": ["cat", "/world"], "PortSpecs": ["22"]}')
Full -run example (multiline is ok within a single quote ``'``)
::
$ sudo docker commit -run='
{
"Entrypoint" : null,
"Privileged" : false,
"User" : "",
"VolumesFrom" : "",
"Cmd" : ["cat", "-e", "/etc/resolv.conf"],
"Dns" : ["8.8.8.8", "8.8.4.4"],
"MemorySwap" : 0,
"AttachStdin" : false,
"AttachStderr" : false,
"CpuShares" : 0,
"OpenStdin" : false,
"Volumes" : null,
"Hostname" : "122612f45831",
"PortSpecs" : ["22", "80", "443"],
"Image" : "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
"Tty" : false,
"Env" : [
"HOME=/",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"StdinOnce" : false,
"Domainname" : "",
"WorkingDir" : "/",
"NetworkDisabled" : false,
"Memory" : 0,
"AttachStdout" : false
}' $CONTAINER_ID
.. _cli_cp:
``cp``
------
::
Usage: docker cp CONTAINER:RESOURCE HOSTPATH
Copy files/folders from the containers filesystem to the host
path. Paths are relative to the root of the filesystem.
.. _cli_diff:
``diff``
--------
::
Usage: docker diff CONTAINER [OPTIONS]
Inspect changes on a container's filesystem
.. _cli_events:
``events``
----------
::
Usage: docker events
Get real time events from the server
.. _cli_events_example:
Examples
~~~~~~~~
You'll need two shells for this example.
Shell 1: Listening for events
.............................
.. code-block:: bash
$ sudo docker events
Shell 2: Start and Stop a Container
...................................
.. code-block:: bash
$ sudo docker start 4386fb97867d
$ sudo docker stop 4386fb97867d
Shell 1: (Again .. now showing events)
......................................
.. code-block:: bash
[2013-09-03 15:49:26 +0200 CEST] 4386fb97867d: (from 12de384bfb10) start
[2013-09-03 15:49:29 +0200 CEST] 4386fb97867d: (from 12de384bfb10) die
[2013-09-03 15:49:29 +0200 CEST] 4386fb97867d: (from 12de384bfb10) stop
.. _cli_export:
``export``
----------
::
Usage: docker export CONTAINER
Export the contents of a filesystem as a tar archive
.. _cli_history:
``history``
-----------
::
Usage: docker history [OPTIONS] IMAGE
Show the history of an image
.. _cli_images:
``images``
----------
::
Usage: docker images [OPTIONS] [NAME]
List images
-a=false: show all images
-q=false: only show numeric IDs
-viz=false: output in graphviz format
Displaying images visually
~~~~~~~~~~~~~~~~~~~~~~~~~~
::
sudo docker images -viz | dot -Tpng -o docker.png
.. image:: docker_images.gif
:alt: Example inheritance graph of Docker images.
.. _cli_import:
``import``
----------
::
Usage: docker import URL|- [REPOSITORY [TAG]]
Create a new filesystem image from the contents of a tarball
At this time, the URL must start with ``http`` and point to a single
file archive (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) containing a
root filesystem. If you would like to import from a local directory or
archive, you can use the ``-`` parameter to take the data from
standard in.
Examples
~~~~~~~~
Import from a remote location
.............................
``$ sudo docker import http://example.com/exampleimage.tgz exampleimagerepo``
Import from a local file
........................
Import to docker via pipe and standard in
``$ cat exampleimage.tgz | sudo docker import - exampleimagelocal``
Import from a local directory
.............................
``$ sudo tar -c . | docker import - exampleimagedir``
Note the ``sudo`` in this example -- you must preserve the ownership
of the files (especially root ownership) during the archiving with
tar. If you are not root (or sudo) when you tar, then the ownerships
might not get preserved.
.. _cli_info:
``info``
--------
::
Usage: docker info
Display system-wide information.
.. _cli_insert:
``insert``
----------
::
Usage: docker insert IMAGE URL PATH
Insert a file from URL in the IMAGE at PATH
Examples
~~~~~~~~
Insert file from github
.......................
.. code-block:: bash
$ sudo docker insert 8283e18b24bc https://raw.github.com/metalivedev/django/master/postinstall /tmp/postinstall.sh
.. _cli_inspect:
``inspect``
-----------
::
Usage: docker inspect [OPTIONS] CONTAINER
Return low-level information on a container
.. _cli_kill:
``kill``
--------
::
Usage: docker kill [OPTIONS] CONTAINER [CONTAINER...]
Kill a running container
.. _cli_link:
``link``
--------
::
Usage: docker link CURRENT_NAME NEW_NAME
Link a container to a new name.
Examples:
~~~~~~~~~
.. code-block:: bash
$ docker link /59669e088202c2ebe150b4346cb3301562d073b51261176a354a74e8f618bfbc /redis
$ docker ls
NAME ID IMAGE
/redis 59669e088202c2ebe150b4346cb3301562d073b51261176a354a74e8f618bfbc crosbymichael/redis:latest
/59669e088202c2ebe150b4346cb3301562d073b51261176a354a74e8f618bfbc 59669e088202c2ebe150b4346cb3301562d073b51261176a354a74e8f618bfbc crosbymichael/redis:latest
This will create a new link for the existing name ``/59669e088202c2ebe150b4346cb3301562d073b51261176a354a74e8f618bfbc``
with the new name ``/redis`` so that we can new reference the same container under the new name ``/redis``.
.. _cli_login:
``login``
---------
::
Usage: docker login [OPTIONS] [SERVER]
Register or Login to the docker registry server
-e="": email
-p="": password
-u="": username
If you want to login to a private registry you can
specify this by adding the server name.
example:
docker login localhost:8080
.. _cli_logs:
``logs``
--------
::
Usage: docker logs [OPTIONS] CONTAINER
Fetch the logs of a container
.. _cli_port:
``port``
--------
::
Usage: docker port [OPTIONS] CONTAINER PRIVATE_PORT
Lookup the public-facing port which is NAT-ed to PRIVATE_PORT
.. _cli_ps:
``ps``
------
::
Usage: docker ps [OPTIONS]
List containers
-a=false: Show all containers. Only running containers are shown by default.
-notrunc=false: Don't truncate output
-q=false: Only display numeric IDs
.. _cli_pull:
``pull``
--------
::
Usage: docker pull NAME
Pull an image or a repository from the registry
.. _cli_push:
``push``
--------
::
Usage: docker push NAME
Push an image or a repository to the registry
.. _cli_restart:
``restart``
-----------
::
Usage: docker restart [OPTIONS] NAME
Restart a running container
.. _cli_rm:
``rm``
------
::
Usage: docker rm [OPTIONS] CONTAINER
Remove one or more containers
-link="": Remove the link instead of the actual container
Examples:
~~~~~~~~~
.. code-block:: bash
$ docker rm /redis
/redis
This will remove the container referenced under the link ``/redis``.
.. code-block:: bash
$ docker rm -link /webapp/redis
/webapp/redis
This will remove the underlying link between ``/webapp`` and the ``/redis`` containers removing all
network communication.
.. _cli_rmi:
``rmi``
-------
::
Usage: docker rmi IMAGE [IMAGE...]
Remove one or more images
.. _cli_run:
``run``
-------
::
Usage: docker run [OPTIONS] IMAGE[:TAG] [COMMAND] [ARG...]
Run a command in a new container
-a=map[]: Attach to stdin, stdout or stderr
-c=0: CPU shares (relative weight)
-cidfile="": Write the container ID to the file
-d=false: Detached mode: Run container in the background, print new container id
-e=[]: Set environment variables
-h="": Container host name
-i=false: Keep stdin open even if not attached
-privileged=false: Give extended privileges to this container
-m=0: Memory limit (in bytes)
-n=true: Enable networking for this container
-p=[]: Map a network port to the container
-rm=false: Automatically remove the container when it exits (incompatible with -d)
-t=false: Allocate a pseudo-tty
-u="": Username or UID
-dns=[]: Set custom dns servers for the container
-v=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro]. If "container-dir" is missing, then docker creates a new volume.
-volumes-from="": Mount all volumes from the given container
-entrypoint="": Overwrite the default entrypoint set by the image
-w="": Working directory inside the container
-lxc-conf=[]: Add custom lxc options -lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"
-expose=[]: Expose a port from the container without publishing it to your host
-link="": Add link to another container (containerid:alias)
Examples
--------
.. code-block:: bash
sudo docker run -cidfile /tmp/docker_test.cid ubuntu echo "test"
This will create a container and print "test" to the console. The
``cidfile`` flag makes docker attempt to create a new file and write the
container ID to it. If the file exists already, docker will return an
error. Docker will close this file when docker run exits.
.. code-block:: bash
docker run mount -t tmpfs none /var/spool/squid
This will *not* work, because by default, most potentially dangerous
kernel capabilities are dropped; including ``cap_sys_admin`` (which is
required to mount filesystems). However, the ``-privileged`` flag will
allow it to run:
.. code-block:: bash
docker run -privileged mount -t tmpfs none /var/spool/squid
The ``-privileged`` flag gives *all* capabilities to the container,
and it also lifts all the limitations enforced by the ``device``
cgroup controller. In other words, the container can then do almost
everything that the host can do. This flag exists to allow special
use-cases, like running Docker within Docker.
.. code-block:: bash
docker run -w /path/to/dir/ -i -t ubuntu pwd
The ``-w`` lets the command being executed inside directory given,
here /path/to/dir/. If the path does not exists it is created inside the
container.
.. code-block:: bash
docker run -v `pwd`:`pwd` -w `pwd` -i -t ubuntu pwd
The ``-v`` flag mounts the current working directory into the container.
The ``-w`` lets the command being executed inside the current
working directory, by changing into the directory to the value
returned by ``pwd``. So this combination executes the command
using the container, but inside the current working directory.
.. code-block:: bash
docker run -p 127.0.0.0::80 ubuntu bash
This the ``-p`` flag now allows you to bind a port to a specific
interface of the host machine. In this example port ``80`` of the
container will have a dynamically allocated port bound to 127.0.0.1
of the host.
.. code-block:: bash
docker run -p 127.0.0.1:80:80 ubuntu bash
This will bind port ``80`` of the container to port ``80`` on 127.0.0.1 of your
host machine.
.. code-block:: bash
docker run -expose 80 ubuntu bash
This will expose port ``80`` of the container for use within a link
without publishing the port to the host system's interfaces.
.. code-block:: bash
docker run -link /redis:redis ubuntu bash
The ``-link`` flag will link the container named ``/redis`` into the
newly created container with the alias ``redis``. The new container
can access the network and environment of the redis container via
environment variables.
.. _cli_search:
``search``
----------
::
Usage: docker search TERM
Searches for the TERM parameter on the Docker index and prints out
a list of repositories that match.
.. _cli_start:
``start``
---------
::
Usage: docker start [OPTIONS] NAME
Start a stopped container
.. _cli_stop:
``stop``
--------
::
Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...]
Stop a running container
-t=10: Number of seconds to wait for the container to stop before killing it.
.. _cli_tag:
``tag``
-------
::
Usage: docker tag [OPTIONS] IMAGE REPOSITORY [TAG]
Tag an image into a repository
-f=false: Force
.. _cli_top:
``top``
-------
::
Usage: docker top CONTAINER
Lookup the running processes of a container
.. _cli_version:
``version``
-----------
Show the version of the docker client, daemon, and latest released version.
.. _cli_wait:
``wait``
--------
::
Usage: docker wait [OPTIONS] NAME
Block until a container stops, then print its exit code.
.. toctree::
:maxdepth: 2
command/attach
command/build
command/commit
command/cp
command/diff
command/events
command/export
command/history
command/images
command/import
command/info
command/insert
command/inspect
command/kill
command/login
command/logs
command/port
command/ps
command/pull
command/push
command/restart
command/rm
command/rmi
command/run
command/search
command/start
command/stop
command/tag
command/top
command/version
command/wait
@@ -1,59 +0,0 @@
:title: Attach Command
:description: Attach to a running container
:keywords: attach, container, docker, documentation
===========================================
``attach`` -- Attach to a running container
===========================================
::
Usage: docker attach CONTAINER
Attach to a running container.
You can detach from the container again (and leave it running) with
``CTRL-c`` (for a quiet exit) or ``CTRL-\`` to get a stacktrace of
the Docker client when it quits.
To stop a container, use ``docker stop``
To kill the container, use ``docker kill``
Examples:
---------
.. code-block:: bash
$ ID=$(sudo docker run -d ubuntu /usr/bin/top -b)
$ sudo docker attach $ID
top - 02:05:52 up 3:05, 0 users, load average: 0.01, 0.02, 0.05
Tasks: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie
Cpu(s): 0.1%us, 0.2%sy, 0.0%ni, 99.7%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 373572k total, 355560k used, 18012k free, 27872k buffers
Swap: 786428k total, 0k used, 786428k free, 221740k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 17200 1116 912 R 0 0.3 0:00.03 top
top - 02:05:55 up 3:05, 0 users, load average: 0.01, 0.02, 0.05
Tasks: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie
Cpu(s): 0.0%us, 0.2%sy, 0.0%ni, 99.8%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 373572k total, 355244k used, 18328k free, 27872k buffers
Swap: 786428k total, 0k used, 786428k free, 221776k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 17208 1144 932 R 0 0.3 0:00.03 top
top - 02:05:58 up 3:06, 0 users, load average: 0.01, 0.02, 0.05
Tasks: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie
Cpu(s): 0.2%us, 0.3%sy, 0.0%ni, 99.5%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 373572k total, 355780k used, 17792k free, 27880k buffers
Swap: 786428k total, 0k used, 786428k free, 221776k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 17208 1144 932 R 0 0.3 0:00.03 top
^C$
$ sudo docker stop $ID
@@ -1,65 +0,0 @@
:title: Build Command
:description: Build a new image from the Dockerfile passed via stdin
:keywords: build, docker, container, documentation
================================================
``build`` -- Build a container from a Dockerfile
================================================
::
Usage: docker build [OPTIONS] PATH | URL | -
Build a new container image from the source code at PATH
-t="": Repository name (and optionally a tag) to be applied to the resulting image in case of success.
-q=false: Suppress verbose build output.
-no-cache: Do not use the cache when building the image.
-rm: Remove intermediate containers after a successful build
When a single Dockerfile is given as URL, then no context is set. When a git repository is set as URL, the repository is used as context
Examples
--------
.. code-block:: bash
sudo docker build .
This will read the ``Dockerfile`` from the current directory. It will
also send any other files and directories found in the current
directory to the ``docker`` daemon.
The contents of this directory would be used by ``ADD`` commands found
within the ``Dockerfile``. This will send a lot of data to the
``docker`` daemon if the current directory contains a lot of data. If
the absolute path is provided instead of ``.`` then only the files and
directories required by the ADD commands from the ``Dockerfile`` will be
added to the context and transferred to the ``docker`` daemon.
.. code-block:: bash
sudo docker build -t vieux/apache:2.0 .
This will build like the previous example, but it will then tag the
resulting image. The repository name will be ``vieux/apache`` and the
tag will be ``2.0``
.. code-block:: bash
sudo docker build - < Dockerfile
This will read a ``Dockerfile`` from *stdin* without context. Due to
the lack of a context, no contents of any local directory will be sent
to the ``docker`` daemon. ``ADD`` doesn't work when running in this
mode because the absence of the context provides no source files to
copy to the container.
.. code-block:: bash
sudo docker build github.com/creack/docker-firefox
This will clone the Github repository and use it as context. The
``Dockerfile`` at the root of the repository is used as
``Dockerfile``. Note that you can specify an arbitrary git repository
by using the ``git://`` schema.
@@ -1,49 +0,0 @@
:title: Commit Command
:description: Create a new image from a container's changes
:keywords: commit, docker, container, documentation
===========================================================
``commit`` -- Create a new image from a container's changes
===========================================================
::
Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY [TAG]]
Create a new image from a container's changes
-m="": Commit message
-author="": Author (eg. "John Hannibal Smith <hannibal@a-team.com>"
-run="": Config automatically applied when the image is
run. "+`(ex: {"Cmd": ["cat", "/world"], "PortSpecs": ["22"]}')
Full -run example::
{
"Entrypoint" : null,
"Privileged" : false,
"User" : "",
"VolumesFrom" : "",
"Cmd" : ["cat", "-e", "/etc/resolv.conf"],
"Dns" : ["8.8.8.8", "8.8.4.4"],
"MemorySwap" : 0,
"AttachStdin" : false,
"AttachStderr" : false,
"CpuShares" : 0,
"OpenStdin" : false,
"Volumes" : null,
"Hostname" : "122612f45831",
"PortSpecs" : ["22", "80", "443"],
"Image" : "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
"Tty" : false,
"Env" : [
"HOME=/",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"StdinOnce" : false,
"Domainname" : "",
"WorkingDir" : "/",
"NetworkDisabled" : false,
"Memory" : 0,
"AttachStdout" : false
}
-14
View File
@@ -1,14 +0,0 @@
:title: Cp Command
:description: Copy files/folders from the containers filesystem to the host path
:keywords: cp, docker, container, documentation, copy
============================================================================
``cp`` -- Copy files/folders from the containers filesystem to the host path
============================================================================
::
Usage: docker cp CONTAINER:RESOURCE HOSTPATH
Copy files/folders from the containers filesystem to the host
path. Paths are relative to the root of the filesystem.
-13
View File
@@ -1,13 +0,0 @@
:title: Diff Command
:description: Inspect changes on a container's filesystem
:keywords: diff, docker, container, documentation
=======================================================
``diff`` -- Inspect changes on a container's filesystem
=======================================================
::
Usage: docker diff CONTAINER [OPTIONS]
Inspect changes on a container's filesystem
@@ -1,34 +0,0 @@
:title: Events Command
:description: Get real time events from the server
:keywords: events, docker, documentation
=================================================================
``events`` -- Get real time events from the server
=================================================================
::
Usage: docker events
Get real time events from the server
Examples
--------
Starting and stopping a container
.................................
.. code-block:: bash
$ sudo docker start 4386fb97867d
$ sudo docker stop 4386fb97867d
In another shell
.. code-block:: bash
$ sudo docker events
[2013-09-03 15:49:26 +0200 CEST] 4386fb97867d: (from 12de384bfb10) start
[2013-09-03 15:49:29 +0200 CEST] 4386fb97867d: (from 12de384bfb10) die
[2013-09-03 15:49:29 +0200 CEST] 4386fb97867d: (from 12de384bfb10) stop
@@ -1,13 +0,0 @@
:title: Export Command
:description: Export the contents of a filesystem as a tar archive
:keywords: export, docker, container, documentation
=================================================================
``export`` -- Stream the contents of a container as a tar archive
=================================================================
::
Usage: docker export CONTAINER
Export the contents of a filesystem as a tar archive
@@ -1,13 +0,0 @@
:title: History Command
:description: Show the history of an image
:keywords: history, docker, container, documentation
===========================================
``history`` -- Show the history of an image
===========================================
::
Usage: docker history [OPTIONS] IMAGE
Show the history of an image
@@ -1,26 +0,0 @@
:title: Images Command
:description: List images
:keywords: images, docker, container, documentation
=========================
``images`` -- List images
=========================
::
Usage: docker images [OPTIONS] [NAME]
List images
-a=false: show all images
-q=false: only show numeric IDs
-viz=false: output in graphviz format
Displaying images visually
--------------------------
::
sudo docker images -viz | dot -Tpng -o docker.png
.. image:: images/docker_images.gif
@@ -1,44 +0,0 @@
:title: Import Command
:description: Create a new filesystem image from the contents of a tarball
:keywords: import, tarball, docker, url, documentation
==========================================================================
``import`` -- Create a new filesystem image from the contents of a tarball
==========================================================================
::
Usage: docker import URL|- [REPOSITORY [TAG]]
Create a new filesystem image from the contents of a tarball
At this time, the URL must start with ``http`` and point to a single
file archive (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) containing a
root filesystem. If you would like to import from a local directory or
archive, you can use the ``-`` parameter to take the data from
standard in.
Examples
--------
Import from a remote location
.............................
``$ sudo docker import http://example.com/exampleimage.tgz exampleimagerepo``
Import from a local file
........................
Import to docker via pipe and standard in
``$ cat exampleimage.tgz | sudo docker import - exampleimagelocal``
Import from a local directory
.............................
``$ sudo tar -c . | docker import - exampleimagedir``
Note the ``sudo`` in this example -- you must preserve the ownership
of the files (especially root ownership) during the archiving with
tar. If you are not root (or sudo) when you tar, then the ownerships
might not get preserved.
-13
View File
@@ -1,13 +0,0 @@
:title: Info Command
:description: Display system-wide information.
:keywords: info, docker, information, documentation
===========================================
``info`` -- Display system-wide information
===========================================
::
Usage: docker info
Display system-wide information.
@@ -1,23 +0,0 @@
:title: Insert Command
:description: Insert a file in an image
:keywords: insert, image, docker, documentation
==========================================================================
``insert`` -- Insert a file in an image
==========================================================================
::
Usage: docker insert IMAGE URL PATH
Insert a file from URL in the IMAGE at PATH
Examples
--------
Insert file from github
.......................
.. code-block:: bash
$ sudo docker insert 8283e18b24bc https://raw.github.com/metalivedev/django/master/postinstall /tmp/postinstall.sh
@@ -1,13 +0,0 @@
:title: Inspect Command
:description: Return low-level information on a container
:keywords: inspect, container, docker, documentation
==========================================================
``inspect`` -- Return low-level information on a container
==========================================================
::
Usage: docker inspect [OPTIONS] CONTAINER
Return low-level information on a container
-13
View File
@@ -1,13 +0,0 @@
:title: Kill Command
:description: Kill a running container
:keywords: kill, container, docker, documentation
====================================
``kill`` -- Kill a running container
====================================
::
Usage: docker kill [OPTIONS] CONTAINER [CONTAINER...]
Kill a running container
@@ -1,24 +0,0 @@
:title: Login Command
:description: Register or Login to the docker registry server
:keywords: login, docker, documentation
============================================================
``login`` -- Register or Login to the docker registry server
============================================================
::
Usage: docker login [OPTIONS] [SERVER]
Register or Login to the docker registry server
-e="": email
-p="": password
-u="": username
If you want to login to a private registry you can
specify this by adding the server name.
example:
docker login localhost:8080
-13
View File
@@ -1,13 +0,0 @@
:title: Logs Command
:description: Fetch the logs of a container
:keywords: logs, container, docker, documentation
=========================================
``logs`` -- Fetch the logs of a container
=========================================
::
Usage: docker logs [OPTIONS] CONTAINER
Fetch the logs of a container
-13
View File
@@ -1,13 +0,0 @@
:title: Port Command
:description: Lookup the public-facing port which is NAT-ed to PRIVATE_PORT
:keywords: port, docker, container, documentation
=========================================================================
``port`` -- Lookup the public-facing port which is NAT-ed to PRIVATE_PORT
=========================================================================
::
Usage: docker port [OPTIONS] CONTAINER PRIVATE_PORT
Lookup the public-facing port which is NAT-ed to PRIVATE_PORT
-17
View File
@@ -1,17 +0,0 @@
:title: Ps Command
:description: List containers
:keywords: ps, docker, documentation, container
=========================
``ps`` -- List containers
=========================
::
Usage: docker ps [OPTIONS]
List containers
-a=false: Show all containers. Only running containers are shown by default.
-notrunc=false: Don't truncate output
-q=false: Only display numeric IDs
-13
View File
@@ -1,13 +0,0 @@
:title: Pull Command
:description: Pull an image or a repository from the registry
:keywords: pull, image, repo, repository, documentation, docker
=========================================================================
``pull`` -- Pull an image or a repository from the docker registry server
=========================================================================
::
Usage: docker pull NAME
Pull an image or a repository from the registry
-13
View File
@@ -1,13 +0,0 @@
:title: Push Command
:description: Push an image or a repository to the registry
:keywords: push, docker, image, repository, documentation, repo
=======================================================================
``push`` -- Push an image or a repository to the docker registry server
=======================================================================
::
Usage: docker push NAME
Push an image or a repository to the registry
@@ -1,13 +0,0 @@
:title: Restart Command
:description: Restart a running container
:keywords: restart, container, docker, documentation
==========================================
``restart`` -- Restart a running container
==========================================
::
Usage: docker restart [OPTIONS] NAME
Restart a running container
-13
View File
@@ -1,13 +0,0 @@
:title: Rm Command
:description: Remove a container
:keywords: remove, container, docker, documentation, rm
============================
``rm`` -- Remove a container
============================
::
Usage: docker rm [OPTIONS] CONTAINER
Remove one or more containers
-13
View File
@@ -1,13 +0,0 @@
:title: Rmi Command
:description: Remove an image
:keywords: rmi, remove, image, docker, documentation
==========================
``rmi`` -- Remove an image
==========================
::
Usage: docker rmi IMAGE [IMAGE...]
Remove one or more images
-84
View File
@@ -1,84 +0,0 @@
:title: Run Command
:description: Run a command in a new container
:keywords: run, container, docker, documentation
===========================================
``run`` -- Run a command in a new container
===========================================
::
Usage: docker run [OPTIONS] IMAGE[:TAG] [COMMAND] [ARG...]
Run a command in a new container
-a=map[]: Attach to stdin, stdout or stderr.
-c=0: CPU shares (relative weight)
-cidfile="": Write the container ID to the file
-d=false: Detached mode: Run container in the background, print new container id
-e=[]: Set environment variables
-h="": Container host name
-i=false: Keep stdin open even if not attached
-privileged=false: Give extended privileges to this container
-m=0: Memory limit (in bytes)
-n=true: Enable networking for this container
-p=[]: Map a network port to the container
-t=false: Allocate a pseudo-tty
-u="": Username or UID
-dns=[]: Set custom dns servers for the container
-v=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro]. If "host-dir" is missing, then docker creates a new volume.
-volumes-from="": Mount all volumes from the given container.
-entrypoint="": Overwrite the default entrypoint set by the image.
-w="": Working directory inside the container
-lxc-conf=[]: Add custom lxc options -lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"
Examples
--------
.. code-block:: bash
sudo docker run -cidfile /tmp/docker_test.cid ubuntu echo "test"
This will create a container and print "test" to the console. The
``cidfile`` flag makes docker attempt to create a new file and write the
container ID to it. If the file exists already, docker will return an
error. Docker will close this file when docker run exits.
.. code-block:: bash
docker run mount -t tmpfs none /var/spool/squid
This will *not* work, because by default, most potentially dangerous
kernel capabilities are dropped; including ``cap_sys_admin`` (which is
required to mount filesystems). However, the ``-privileged`` flag will
allow it to run:
.. code-block:: bash
docker run -privileged mount -t tmpfs none /var/spool/squid
The ``-privileged`` flag gives *all* capabilities to the container,
and it also lifts all the limitations enforced by the ``device``
cgroup controller. In other words, the container can then do almost
everything that the host can do. This flag exists to allow special
use-cases, like running Docker within Docker.
.. code-block:: bash
docker run -w /path/to/dir/ -i -t ubuntu pwd
The ``-w`` lets the command being executed inside directory given,
here /path/to/dir/. If the path does not exists it is created inside the
container.
.. code-block:: bash
docker run -v `pwd`:`pwd` -w `pwd` -i -t ubuntu pwd
The ``-v`` flag mounts the current working directory into the container.
The ``-w`` lets the command being executed inside the current
working directory, by changing into the directory to the value
returned by ``pwd``. So this combination executes the command
using the container, but inside the current working directory.
@@ -1,14 +0,0 @@
:title: Search Command
:description: Searches for the TERM parameter on the Docker index and prints out a list of repositories that match.
:keywords: search, docker, image, documentation
===================================================================
``search`` -- Search for an image in the docker index
===================================================================
::
Usage: docker search TERM
Searches for the TERM parameter on the Docker index and prints out
a list of repositories that match.
@@ -1,13 +0,0 @@
:title: Start Command
:description: Start a stopped container
:keywords: start, docker, container, documentation
======================================
``start`` -- Start a stopped container
======================================
::
Usage: docker start [OPTIONS] NAME
Start a stopped container
-15
View File
@@ -1,15 +0,0 @@
:title: Stop Command
:description: Stop a running container
:keywords: stop, container, docker, documentation
====================================
``stop`` -- Stop a running container
====================================
::
Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...]
Stop a running container
-t=10: Number of seconds to wait for the container to stop before killing it.
-15
View File
@@ -1,15 +0,0 @@
:title: Tag Command
:description: Tag an image into a repository
:keywords: tag, docker, image, repository, documentation, repo
=========================================
``tag`` -- Tag an image into a repository
=========================================
::
Usage: docker tag [OPTIONS] IMAGE REPOSITORY [TAG]
Tag an image into a repository
-f=false: Force
-13
View File
@@ -1,13 +0,0 @@
:title: Top Command
:description: Lookup the running processes of a container
:keywords: top, docker, container, documentation
=======================================================
``top`` -- Lookup the running processes of a container
=======================================================
::
Usage: docker top CONTAINER
Lookup the running processes of a container
@@ -1,7 +0,0 @@
:title: Version Command
:description:
:keywords: version, docker, documentation
==================================================
``version`` -- Show the docker version information
==================================================
-13
View File
@@ -1,13 +0,0 @@
:title: Wait Command
:description: Block until a container stops, then print its exit code.
:keywords: wait, docker, container, documentation
===================================================================
``wait`` -- Block until a container stops, then print its exit code
===================================================================
::
Usage: docker wait [OPTIONS] NAME
Block until a container stops, then print its exit code.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

+2 -33
View File
@@ -1,6 +1,6 @@
:title: Commands
:description: -- todo: change me
:keywords: todo, commands, command line, help, docker, documentation
:description: docker command line interface
:keywords: commands, command line, help, docker
Commands
@@ -12,34 +12,3 @@ Contents:
:maxdepth: 1
cli
attach <command/attach>
build <command/build>
commit <command/commit>
cp <command/cp>
diff <command/diff>
events <command/events>
export <command/export>
history <command/history>
images <command/images>
import <command/import>
info <command/info>
insert <command/insert>
inspect <command/inspect>
kill <command/kill>
login <command/login>
logs <command/logs>
port <command/port>
ps <command/ps>
pull <command/pull>
push <command/push>
restart <command/restart>
rm <command/rm>
rmi <command/rmi>
run <command/run>
search <command/search>
start <command/start>
stop <command/stop>
tag <command/tag>
top <command/top>
version <command/version>
wait <command/wait>
+92 -23
View File
@@ -3,7 +3,7 @@
:keywords: Docker, documentation, developers, contributing, dev environment
Setting Up a Dev Environment
============================
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To make it easier to contribute to Docker, we provide a standard
development environment. It is important that the same environment be
@@ -12,11 +12,11 @@ environment defines all build dependencies: system libraries and
binaries, go environment, go dependencies, etc.
Step 1: install docker
Step 1: Install Docker
----------------------
Docker's build environment itself is a Docker container, so the first
step is to install docker on your system.
step is to install Docker on your system.
You can follow the `install instructions most relevant to your system
<https://docs.docker.io/en/latest/installation/>`_. Make sure you have
@@ -24,40 +24,109 @@ a working, up-to-date docker installation, then continue to the next
step.
Step 2: check out the source
Step 2: Check out the Source
----------------------------
::
.. code-block:: bash
git clone http://git@github.com/dotcloud/docker
cd docker
To checkout a different revision just use ``git checkout`` with the name of branch or revision number.
Step 3: build
-------------
When you are ready to build docker, run this command:
Step 3: Build the Environment
-----------------------------
::
This following command will build a development environment using the Dockerfile in the current directory. Essentially, it will install all the build and runtime dependencies necessary to build and test Docker. This command will take some time to complete when you first execute it.
.. code-block:: bash
sudo docker build -t docker .
This will build the revision currently checked out in the
repository. Feel free to check out the version of your choice.
If the build is successful, congratulations! You have produced a clean
build of docker, neatly encapsulated in a standard build environment.
You can run an interactive session in the newly built container:
::
sudo docker run -i -t docker bash
To extract the binaries from the container:
If the build is successful, congratulations! You have produced a clean build of docker, neatly encapsulated in a standard build environment.
::
sudo docker run docker sh -c 'cat $(which docker)' > docker-build && chmod +x docker-build
Step 4: Build the Docker Binary
-------------------------------
To create the Docker binary, run this command:
.. code-block:: bash
sudo docker run -lxc-conf=lxc.aa_profile=unconfined -privileged -v `pwd`:/go/src/github.com/dotcloud/docker docker hack/make.sh binary
This will create the Docker binary in ``./bundles/<version>-dev/binary/``
Step 5: Run the Tests
---------------------
To run the Docker test cases you first need to disable `AppArmor <https://wiki.ubuntu.com/AppArmor>`_ using the following commands
.. code-block:: bash
sudo /etc/init.d/apparmor stop
sudo /etc/init.d/apparmor teardown
To execute the test cases, run this command:
.. code-block:: bash
sudo docker run -lxc-conf=lxc.aa_profile=unconfined -privileged -v `pwd`:/go/src/github.com/dotcloud/docker docker hack/make.sh test
If the test are successful then the tail of the output should look something like this
.. code-block:: bash
--- PASS: TestWriteBroadcaster (0.00 seconds)
=== RUN TestRaceWriteBroadcaster
--- PASS: TestRaceWriteBroadcaster (0.00 seconds)
=== RUN TestTruncIndex
--- PASS: TestTruncIndex (0.00 seconds)
=== RUN TestCompareKernelVersion
--- PASS: TestCompareKernelVersion (0.00 seconds)
=== RUN TestHumanSize
--- PASS: TestHumanSize (0.00 seconds)
=== RUN TestParseHost
--- PASS: TestParseHost (0.00 seconds)
=== RUN TestParseRepositoryTag
--- PASS: TestParseRepositoryTag (0.00 seconds)
=== RUN TestGetResolvConf
--- PASS: TestGetResolvConf (0.00 seconds)
=== RUN TestCheckLocalDns
--- PASS: TestCheckLocalDns (0.00 seconds)
=== RUN TestParseRelease
--- PASS: TestParseRelease (0.00 seconds)
=== RUN TestDependencyGraphCircular
--- PASS: TestDependencyGraphCircular (0.00 seconds)
=== RUN TestDependencyGraph
--- PASS: TestDependencyGraph (0.00 seconds)
PASS
ok github.com/dotcloud/docker/utils 0.017s
Step 6: Use Docker
-------------------
You can run an interactive session in the newly built container:
.. code-block:: bash
sudo docker run -privileged -i -t docker bash
# type 'exit' to exit
.. note:: The binary is available outside the container in the directory ``./bundles/<version>-dev/binary/``. You can swap your host docker executable with this binary for live testing - for example, on ubuntu: ``sudo service docker stop ; sudo cp $(which docker) $(which docker)_ ; sudo cp ./bundles/<version>-dev/binary/docker-<version>-dev $(which docker);sudo service docker start``.
**Need More Help?**
If you need more help then hop on to the `#docker-dev IRC channel <irc://chat.freenode.net#docker-dev>`_ or post a message on the `Docker developer mailinglist <https://groups.google.com/d/forum/docker-dev>`_.
+12 -9
View File
@@ -2,6 +2,11 @@
:description: A simple hello world example with Docker
:keywords: docker, example, hello world
.. _examples:
Hello World
-----------
.. _running_examples:
Running the Examples
@@ -166,13 +171,11 @@ See the example in action
The next example in the series is a :ref:`python_web_app` example, or
you could skip to any of the other examples:
.. toctree::
:maxdepth: 1
python_web_app
nodejs_web_app
running_redis_service
running_ssh_service
couchdb_data_volumes
postgresql_service
mongodb
* :ref:`python_web_app`
* :ref:`nodejs_web_app`
* :ref:`running_redis_service`
* :ref:`running_ssh_service`
* :ref:`running_couchdb_service`
* :ref:`postgresql_service`
* :ref:`mongodb_image`
+3 -1
View File
@@ -1,8 +1,9 @@
:title: Docker Examples
:description: Examples on how to use Docker
:keywords: docker, hello world, node, nodejs, python, couch, couchdb, redis, ssh, sshd, examples, postgresql
:keywords: docker, hello world, node, nodejs, python, couch, couchdb, redis, ssh, sshd, examples, postgresql, link
.. _example_list:
Examples
========
@@ -23,3 +24,4 @@ to more substantial services like you might find in production.
postgresql_service
mongodb
running_riak_service
linking_into_redis
@@ -0,0 +1,132 @@
:title: Linking to an Redis container
:description: Running redis linked into your web app
:keywords: docker, example, networking, redis, link
.. _linking_redis:
Linking Redis
=============
.. include:: example_header.inc
Building a redis container to link as a child of our web application.
Building the redis container
----------------------------
We will use a pre-build version of redis from the index under
the name ``crosbymichael/redis``. If you are interested in the
Dockerfile that was used to build this container here it is.
.. code-block:: bash
# Build redis from source
# Make sure you have the redis source code checked out in
# the same directory as this Dockerfile
FROM ubuntu
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update
RUN apt-get upgrade -y
RUN apt-get install -y gcc make g++ build-essential libc6-dev tcl
ADD . /redis
RUN (cd /redis && make)
RUN (cd /redis && make test)
RUN mkdir -p /redis-data
VOLUME ["/redis-data"]
EXPOSE 6379
ENTRYPOINT ["/redis/src/redis-server"]
CMD ["--dir", "/redis-data"]
We need to ``EXPOSE`` the default port of 6379 so that our link knows what ports
to connect to our redis container on. If you do not expose any ports for the
image then docker will not be able to establish the link between containers.
Run the redis container
-----------------------
.. code-block:: bash
docker run -d -e PASSWORD=docker crosbymichael/redis --requirepass docker
This will run our redis container using the default port of 6379 and using
as password to secure our service. Next we will link the redis container to
a new name using ``docker link``.
Linking an existing container
-----------------------------
Docker will automatically create an initial link with the container's id but
because the is long and not very user friendly we can link the container with
a new name.
.. code-block:: bash
docker link /39588b6a45100ef5b328b2c302ea085624f29e6cbab70f88be04793af02cec89 /redis
Now we can reference our running redis service using the friendly name ``/redis``.
We can issue all the commands that you would expect; start, stop, attach, using the new name.
Linking redis as a child
------------------------
Next we can start a new web application that has a dependency on redis and apply a link
to connect both containers. If you noticed when running our redis service we did not use
the ``-p`` option to publish the redis port to the host system. Redis exposed port 6379
but we did not publish the port. This allows docker to prevent all network traffic to
the redis container except when explicitly specified within a link. This is a big win
for security.
Now lets start our web application with a link into redis.
.. code-block:: bash
docker run -t -i -link /redis:db ubuntu bash
root@4c01db0b339c:/# env
HOSTNAME=4c01db0b339c
DB_NAME=/4c01db0b339cf19958731255a796ee072040a652f51652a4ade190ab8c27006f/db
TERM=xterm
DB_PORT=tcp://172.17.0.8:6379
DB_PORT_6379_TCP=tcp://172.17.0.8:6379
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
DB_ENV_PASSWORD=dockerpass
SHLVL=1
HOME=/
container=lxc
_=/usr/bin/env
root@4c01db0b339c:/#
When we inspect the environment of the linked container we can see a few extra environment
variables have been added. When you specified ``-link /redis:db`` you are telling docker
to link the container named ``/redis`` into this new container with the alias ``db``.
Environment variables are prefixed with the alias so that the parent container can access
network and environment information from the child.
.. code-block:: bash
# The name of the child container
DB_NAME=/4c01db0b339cf19958731255a796ee072040a652f51652a4ade190ab8c27006f/db
# The default protocol, ip, and port of the service running in the container
DB_PORT=tcp://172.17.0.8:6379
# A specific protocol, ip, and port of various services
DB_PORT_6379_TCP=tcp://172.17.0.8:6379
# Get environment variables of the container
DB_ENV_PASSWORD=dockerpass
Accessing the network information along with the environment of the child container allows
us to easily connect to the redis service on the specific ip and port and use the password
specified in the environment.

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