Compare commits

..

821 Commits

Author SHA1 Message Date
Michael Crosby ea7811c83d Bump to 0.7.0-rc7 2013-11-21 17:29:08 -08:00
Michael Crosby 0cecc2a78c Merge branch 'master' into 0.6.5-dm-plugin
Conflicts:
	container.go
	image.go
2013-11-21 17:18:41 -08:00
Michael Crosby 437bdeee59 Merge pull request #62 from shykes/devmapper-unit-tests
Devmapper unit tests
2013-11-21 16:54:50 -08:00
Michael Crosby 25e443a3c7 Merge pull request #2798 from dotcloud/fix_state_race
Refactor State to be 100% thread safe
2013-11-21 16:39:50 -08:00
Guillaume J. Charmes 33e70864a2 Refactor State to be 100% thread safe 2013-11-21 16:34:58 -08:00
Guillaume J. Charmes bc82940a57 Forbid syscalls in tests, add 2 new unit tests 2013-11-21 16:32:16 -08:00
Michael Crosby d6e6214d37 Merge pull request #2678 from cxmcc/minor
Minor code simplification for Containers api
2013-11-21 16:27:15 -08:00
Michael Crosby 70f1bd3104 Merge pull request #2488 from viirya/fix_container_volumes_delete
Skip the volumes mounted when deleting the volumes of container.
2013-11-21 16:20:22 -08:00
Michael Crosby f7c2a00557 Merge pull request #2304 from unclejack/fix_layer_size_computation
Fix layer size computation: handle hard links correctly
2013-11-21 16:10:24 -08:00
Victor Vieux 8498b44eac Merge pull request #2731 from SvenDowideit/docker-commit-doc
make the docker commit help more copy&pasteable
2013-11-21 15:33:05 -08:00
Andy Rothfusz e2dcfc2cf7 Merge pull request #2772 from bitoiu/patch-3
Change to documentation for AWS AMI request
2013-11-21 15:15:04 -08:00
Andy Rothfusz 9b4c151142 Merge pull request #2717 from metalivedev/2342-uploadingcontext
Fix #2342. Harmonize information about ADD. Cross-link build info.
2013-11-21 15:09:47 -08:00
Andy Rothfusz 50239e0573 Merge pull request #2799 from rosenhouse/patch-1
Fix title on doc page for remote_api_client_libraries.rst
2013-11-21 14:40:33 -08:00
Guillaume J. Charmes 42c23b0f04 Merge pull request #2763 from dotcloud/use_full_id_delete
Do ont truncate ID on docker rmi
2013-11-21 14:39:38 -08:00
Guillaume J. Charmes eec91e7941 Merge pull request #2805 from pmorie/typo
Fix typo in pullImage
2013-11-21 14:35:07 -08:00
Paul Morie 3f17844b6e Fix typo in pullImage 2013-11-21 17:29:03 -05:00
Guillaume J. Charmes bcdeb37bb6 Merge pull request #2794 from dotcloud/fix_status_code_and_usage
fix status code and usage
2013-11-21 13:48:38 -08:00
Gabe Rosenhouse 362e9d6b3c Fix title on doc page for remote_api_client_libraries.rst 2013-11-21 12:45:01 -08:00
Guillaume J. Charmes c4ab498920 Merge pull request #2797 from crosbymichael/revert-exit-lock
Revert "Lock state before we modify."
2013-11-21 12:19:23 -08:00
Michael Crosby cb70eedfda Revert "Lock state before we modify."
This reverts commit d7e2fc8982.
2013-11-21 12:11:25 -08:00
Victor Vieux 75a7f4d90c Return status exit status 2 on usage, move parserun into commands.go, display usage on stderr 2013-11-21 11:43:07 -08:00
Victor Vieux da824b4a5a Merge pull request #63 from tianon/flag-help-consistency
Update a few flag help strings for consistency and clarity
2013-11-21 11:31:34 -08:00
Tianon Gravi 1ab6b8bf49 Update a few flag help strings for consistency and clarity 2013-11-21 12:30:17 -07:00
Victor Vieux eaeb969138 Merge pull request #2795 from pnasrat/docker-testmultipleattachrestart-race
Lock state before we modify.
2013-11-21 11:28:02 -08:00
Michael Crosby 253214f07d Update ImageExport after merge fail 2013-11-21 10:26:21 -08:00
Michael Crosby a2c9d2da93 Merge branch 'master' into 0.6.5-dm-plugin 2013-11-21 10:21:30 -08:00
Paul Nasrat d7e2fc8982 Lock state before we modify.
When we start a container we lock state, we should do the same in stop.

Detected via -race.
2013-11-21 08:06:02 -05:00
Victor Vieux f20c738963 Merge pull request #2793 from crosbymichael/offline-ids
Allow images to be saved and loaded by id and repository
2013-11-21 02:44:00 -08:00
Solomon Hykes df258f5861 Devmapper: test driver initialization and its interaction with libdevmapper 2013-11-21 02:17:03 +00:00
Solomon Hykes 60f728b170 Devmapper: wrap calls to os/exec for easier mocking 2013-11-21 02:16:26 +00:00
Solomon Hykes 2b7c63b1b5 devmapper: skip test which are not unit tests 2013-11-21 02:12:51 +00:00
Michael Crosby fd7ab143bf Allow images to be saved and loaded by id and repository 2013-11-20 17:28:19 -08:00
Andy Rothfusz 82cdd21a34 Merge pull request #2727 from SvenDowideit/docker-images-doc
add some common examples for docker images, and tell the user what -a filters out
2013-11-20 16:30:48 -08:00
Michael Crosby a9230af52e Merge pull request #57 from shykes/wait_on_pull_already
Wait on pull already in progress
2013-11-20 15:58:51 -08:00
Victor Vieux 2f0d18ac4a Merge pull request #59 from crosbymichael/fix-image-save-size
Fix image save size
2013-11-20 15:58:31 -08:00
Michael Crosby 6469422465 Merge pull request #58 from crosbymichael/update-aufs-tests
Add more aufs tests and implement Status
2013-11-20 15:41:59 -08:00
Michael Crosby 5306053e21 Add more aufs tests and implement Status 2013-11-20 15:41:37 -08:00
Solomon Hykes e2390318bb Devmapper: mock all calls to libdevmapper in the unit tests, and deny them by default 2013-11-20 23:39:02 +00:00
Michael Crosby 4e0c76b321 Ensure that only the layers are compressed and not mnt points 2013-11-20 15:37:26 -08:00
Solomon Hykes da514223d1 Devmapper: remove deprecated test helpers 2013-11-20 23:25:27 +00:00
Solomon Hykes 023ff36704 devmapper: fix typo 2013-11-20 23:12:19 +00:00
Michael Crosby 8fdbf46afb Fix image size calc on initial save 2013-11-20 14:51:04 -08:00
Guillaume J. Charmes d233894c25 Add devmapper struct doc 2013-11-20 14:09:46 -08:00
Victor Vieux 8a756f417e wait on pull already in progress 2013-11-20 14:04:19 -08:00
Guillaume J. Charmes a39bd65662 Remove os from devmapper 2013-11-20 13:05:17 -08:00
Guillaume J. Charmes 5690139785 Remove all syscall calls from devicemapper 2013-11-20 12:49:01 -08:00
Solomon Hykes 92f94f06ae Mock calls to system functions to facilitate unit testing 2013-11-20 20:05:10 +00:00
Michael Crosby 2bc35287a0 Merge pull request #2723 from SvenDowideit/doc-build-image
Use the work Path for docker cp CONTAINER:PATH
2013-11-20 11:10:13 -08:00
Michael Crosby 2382a0f920 Merge branch 'master' into 0.6.5-dm-plugin
Conflicts:
	server.go
2013-11-20 11:07:42 -08:00
Guillaume J. Charmes 579a5c843b Merge pull request #51 from crosbymichael/driver-specific-image
Handle image metadata when drivers are switched
2013-11-20 10:45:51 -08:00
Guillaume J. Charmes 6ebb236aa1 Merge pull request #55 from alexlarsson/dm-plugins-cleanup-graph-test
graph_test: Clean up drivers allocated in tempGraph()
2013-11-20 10:41:18 -08:00
Guillaume J. Charmes b4f7078a02 Merge pull request #2773 from dotcloud/speed_up_docker_ps
speedup docker ps
2013-11-20 10:40:03 -08:00
Guillaume J. Charmes 9e68913397 Merge pull request #2760 from dotcloud/improve_engine_test
improve tests on the engine
2013-11-20 10:38:46 -08:00
Michael Crosby 1b28cdc7f9 Handle image metadata when drivers are switched 2013-11-20 10:31:51 -08:00
Victor Vieux 304a80fcd5 Merge pull request #2747 from jpoimboe/test-fixes
Test fixes
2013-11-20 10:07:40 -08:00
Guillaume J. Charmes 04f1d4dcdb Merge pull request #2788 from jpoimboe/resize-after-start
resize pty after starting
2013-11-20 10:01:59 -08:00
Josh Poimboeuf 171d681724 resize pty after starting
Since ptyMaster is created during container start (startPty), it should
resized after starting, not before.
2013-11-20 11:40:30 -06:00
Alexander Larsson cfdc284abe tags test: cleanup driver
If not we leak a devicemapper pool
2013-11-20 14:52:06 +01:00
Alexander Larsson 7192be47c5 graph_test: Clean up drivers allocated in tempGraph()
If we don't do this we leak devicemapper pools with the dm backend.
2013-11-20 14:42:32 +01:00
Michael Crosby cd4c1ac356 Merge pull request #2779 from crosbymichael/pin-python-deps
Pip python deps to a specific version
2013-11-19 21:29:09 -08:00
Michael Crosby b8af68a92b Merge pull request #1974 from dotcloud/1155-offline-image-transfer
Implement offline image transfers
2013-11-19 20:00:58 -08:00
Michael Crosby 9de4590498 Add typo in remove all. Ensure tmpDir is removed 2013-11-20 03:52:33 +00:00
Michael Crosby 0ef6fed5c7 Fix error checks for offline transfer and remove unneeded debug output 2013-11-20 03:52:33 +00:00
Frederick F. Kautz IV 383f95bba1 Adding 1.7 documentation 2013-11-20 03:52:33 +00:00
Frederick F. Kautz IV 1211065c8d Adding content type to images/(name)/get 2013-11-20 03:52:33 +00:00
Frederick F. Kautz IV 844c13bce6 Fixing build 2013-11-20 03:52:33 +00:00
Frederick F. Kautz IV 6014db4a7e Setting offline package version to 1.0 2013-11-20 03:52:33 +00:00
Frederick F. Kautz IV bf504f2afa Adding spaces to fix docs build 2013-11-20 03:52:33 +00:00
Frederick F. Kautz IV 61a8020e51 Adding version info, switching to defer for cleanup 2013-11-20 03:52:33 +00:00
Frederick F. Kautz IV 7eaa59f626 Offline Image Transfers #1155 2013-11-20 03:52:33 +00:00
Michael Crosby 2cccbbdadd Pip python deps to a specific version 2013-11-19 19:25:54 -08:00
Michael Crosby 24586d7af5 Merge pull request #54 from shykes/vieux_merge_master
Merge from master
2013-11-19 18:38:15 -08:00
Victor Vieux b700ee006a Merge pull request #2777 from dotcloud/fix_port_stop_start
don't import emport empty hostconfig
2013-11-19 18:36:22 -08:00
Victor Vieux 880a0e9c36 Merge branch 'master' into vieux_merge_master 2013-11-19 18:34:19 -08:00
Victor Vieux 0169cf15dd don't import emport empty hostconfig 2013-11-19 18:28:50 -08:00
Victor Vieux cd022376b8 Merge branch 'master' into vieux_merge_master
Conflicts:
	runtime.go
2013-11-19 17:32:08 -08:00
Michael Crosby 234f5ac39f Merge pull request #2750 from jpoimboe/simplify-register-reconnect
Simplify the runtime Register reconnect logic
2013-11-19 17:30:59 -08:00
Michael Crosby d4ef551d65 Merge pull request #53 from shykes/improve_cleanup
Improve aufs cleanup and debugging
2013-11-19 17:16:36 -08:00
Victor Vieux 76f54f3a28 Merge pull request #39 from crosbymichael/add-driver-flag
Add flag to set default graph driver
2013-11-19 17:16:25 -08:00
Victor Vieux 43b709ab36 Merge pull request #52 from crosbymichael/rename-aufs-driver
Rename AufsDriver to Driver to be consistent
2013-11-19 17:13:44 -08:00
Victor Vieux 43899a77bf improve aufs cleanup and debugging 2013-11-19 17:12:37 -08:00
Victor Vieux d575918038 Merge pull request #2748 from jpoimboe/fix-restart-race-condition
fix container restart race condition
2013-11-19 16:26:13 -08:00
Guillaume J. Charmes f6629bbbd5 Merge pull request #50 from crosbymichael/limit-dm
Prohibit more than 42 layers in the core
2013-11-19 15:42:00 -08:00
Guillaume J. Charmes 91330243b5 Merge pull request #48 from crosbymichael/reset-mtime
Ensure same atime, mtime after applying whiteouts
2013-11-19 15:40:12 -08:00
Guillaume J. Charmes 3e0a5ac48b Merge pull request #41 from alexlarsson/dm-plugin-device-tool
Update docker-device-tool
2013-11-19 15:38:47 -08:00
Michael Crosby 0d603df6dc Merge pull request #49 from shykes/creack-merge-master
Merge master into 0.6.5-dm-plugin
2013-11-19 15:29:09 -08:00
Guillaume J. Charmes 12e993549d Fix unit-tests 2013-11-19 15:24:14 -08:00
Guillaume J. Charmes 28d4cbbc59 Merge branch 'master' into creack-merge-master
Conflicts:
	api_params.go
	graph.go
	graph_test.go
	image.go
	integration/api_test.go
	integration/container_test.go
	integration/runtime_test.go
	runtime.go
2013-11-19 14:58:12 -08:00
Victor Vieux 5a4113140e Merge pull request #43 from alexlarsson/dm-plugin-use-root-subdir
devmapper: Use a "root" subdirectory in the devmapper volume
2013-11-19 13:51:04 -08:00
Victor Vieux 85b5062502 Merge pull request #44 from crosbymichael/container-migration
Container and Image migration for aufs
2013-11-19 13:47:23 -08:00
Tianon Gravi 66beafa9f3 rename file to remove testing flags from docker binary 2013-11-19 12:41:29 -08:00
Josh Poimboeuf 3cbec95177 simplify the runtime Register reconnect logic
Refactor the Register code a little bit to make it easier to comprehend.
2013-11-19 14:09:30 -06:00
Victor Vieux 8e5ab5bfca improve tests on the engine 2013-11-19 11:47:47 -08:00
Michael Crosby 9d867a389b Merge pull request #2759 from dotcloud/lintify-1
Lintify code with confidence=1
2013-11-19 11:26:15 -08:00
Andy Rothfusz 4f9f83d6c6 Fix #2342. Harmonize information about ADD. Cross-link build info. 2013-11-19 11:16:28 -08:00
Victor Vieux 145c2008ae speedup docker ps 2013-11-19 11:02:10 -08:00
Andy Rothfusz 4eaba8de91 Merge pull request #2757 from Painted-Fox/patch-2
Simplify the upstart example in host_integration.rst
2013-11-19 10:29:54 -08:00
Andy Rothfusz 434c1613a4 Merge pull request #2770 from tianon/better-man-page
Switch sphinx man_pages generation to use commandline/cli
2013-11-19 10:28:50 -08:00
Andy Rothfusz 18da26c62a Merge pull request #2766 from sbellem/doc-improvements
fixed typos, and made small improvements to the wording
2013-11-19 10:27:25 -08:00
Michael Crosby 4c2624a277 Merge pull request #45 from alexlarsson/dm-plugin-diff-size
Implement fallback for getting the size of a container
2013-11-19 10:25:31 -08:00
Michael Crosby f4b3b7c055 Merge pull request #47 from alexlarsson/dm-plugin-ummount-when-removing
Devicemapper: Unmount when removing device
2013-11-19 10:24:44 -08:00
Michael Crosby 9af1b07086 Merge pull request #46 from alexlarsson/dm-plugin-dummy-use-cp
Dummy driver: Use cp --reflink=auto to copy directories
2013-11-19 10:16:56 -08:00
Vitor Monteiro aeb304b37c Change to documentation for AWS AMI request
Hi guys, it just might be me, but clicking the AMI from http://cloud-images.ubuntu.com/locator/ec2/ is broken to me. So I just did it via the normal Create Instance Wizard.

I just though some people might have the same issue.

Sorry if my markdown for links is screwed up, I went by the examples, since I'm used to the `[]()` traditional one.

Cheers.
2013-11-19 17:50:38 +00:00
Ryan Seto 1da8c50ded Fix quote mistake. 2013-11-19 12:14:39 -05:00
Tianon Gravi 1cd9529ad3 Switch sphinx man_pages generation to use commandline/cli instead of toctree for a more relevant/useful man page 2013-11-19 10:10:42 -07:00
Daniel Mizyrycki f78d45863c Merge pull request #2734 from zitrusmedia/master
Vagrantfile modified to support VBoxGuestAdditions_4.3.2
2013-11-19 09:04:28 -08:00
Sylvain Bellemare 3656db66d2 fixed typos, and made small improvements to the wording 2013-11-19 14:44:50 +01:00
Alexander Larsson 0ed762f2d2 devicemapper: Unmount when removing device
Without this the remove will fail due to a busy device.
2013-11-19 14:40:15 +01:00
Alexander Larsson 242fd4b3ef dummy driver: Use cp --reflink=auto to copy directories
On systems that supports reflinking (i.e. btrfs) this means the dummy
backend is much faster at copying files and will be sharing file data in
a CoW fashion.

On my (btrfs) system this makes "docker run ubuntu echo hello world" go
from about 3 seconds to about 1 second. Not instant, but clearly better.

cp --reflink=auto is availible since coreutils 7.5 (around 2009), so this
seems pretty ok to rely on.

cp is also better at preserving file metadata than tar, so for instance
it will copy xattrs.
2013-11-19 13:09:36 +01:00
unclejack 78c843c8ef fix container size computation: handle hard links
This change makes docker compute container size correctly.

The old code isn't taking hard links into account. Containers could
seem like they're up to 1-1.5x larger than they really were.
2013-11-19 13:53:34 +02:00
unclejack ac821f2446 fix layer size computation: handle hard links
This change makes docker compute layer size correctly.

The old code isn't taking hard links into account. Layers could
seem like they're up to 1-1.5x larger than they really were.
2013-11-19 13:37:54 +02:00
Michael Crosby 51a972f38d Rename AufsDriver to Driver to be consistent 2013-11-19 03:27:59 -08:00
Michael Crosby aea6001baf Check env var for setting driver in tests 2013-11-19 03:13:22 -08:00
Michael Crosby 6dbeed89c0 Add flag to set default graph driver
Remove the env var DOCKER_DRIVER
2013-11-19 02:37:44 -08:00
Alexander Larsson 5d76681c3d Implement fallback for getting the size of a container
This moves Driver.Size() to Differ.DiffSize(), removing the empty
implementations in devmapper and dummy, and renaming the one in aufs.

Then we fall back to a container.Changes() implementation in the non-aufs
case.
2013-11-19 10:36:54 +01:00
Alexander Larsson 9415c2b1f0 Move docker-device-tool to contrib 2013-11-19 10:03:04 +01:00
Alexander Larsson a0224e61b4 devicemapper tool: Add support for pool resizing 2013-11-19 09:59:13 +01:00
Michael Crosby af753cbad8 Prohibit more than 42 layers in the core
We need to do this because we still support aufs
and users on other drivers can push incompat images
to the registory that aufs users cannot use.
2013-11-19 00:51:16 -08:00
Alexander Larsson 80aecc7014 devmapper: Update device-mapper-tool
This makes the device mapper tool work again and adds new features
to get pool status, device status and to list all devices.
2013-11-19 09:44:19 +01:00
Michael Crosby 3edb4af663 Ensure same atime, mtime after applying whiteouts 2013-11-19 00:35:03 -08:00
Alexander Larsson 00401a30b7 devmapper: Use a "rootfs" subdirectory in the devmapper volume
We place the actual image/containers in the "rootfs" directory, which
allows us to have other data in the toplevel directory in the mount.

For starters, this means the "lost+found" directory from mkfs will
not always be in your container/image.

Secondly, we can create a file "id" in the toplevel dir which is not
visible from the container. This is useful because it allows us to map
back from the device fs to the container if something goes wrong with
the devicemapper metadata.
2013-11-19 09:29:42 +01:00
Michael Crosby 5ee8e41e43 Retry moving dirs on every daemon startup
This will try to move the directories that were
previously symlinked until a full migration is complete.
2013-11-18 23:28:45 -08:00
Michael Crosby 29f07f8544 Add container migration to aufs driver 2013-11-18 18:39:21 -08:00
Victor Vieux 2fe4467d73 Do ont truncate ID on docker rmi 2013-11-18 18:39:02 -08:00
Ryan Seto 194d4b9376 Correct the quotations in the command to add the -r=false flag. Thanks to @tianon for pointing this out. 2013-11-18 21:23:00 -05:00
Andy Rothfusz 1de02a70de Merge pull request #2719 from metalivedev/2702-knownissue-lxc-start-failed-to-mount
Fixes #2702. Also cleans up formatting and long lines in volumes doc.
2013-11-18 17:27:49 -08:00
Guillaume J. Charmes 5e941f1ca0 Lintify code with confidence=1 2013-11-18 16:24:11 -08:00
Michael Crosby f88b760809 Migrate images with parent relationship 2013-11-18 16:17:43 -08:00
Andy Rothfusz 511a62a099 Merge pull request #2755 from metalivedev/test-2592
Replace PR#2592
2013-11-18 15:29:48 -08:00
Andy Rothfusz 256d46fe68 Merge pull request #2721 from metalivedev/2701-addmedia
Add security section and embed private registry video.
2013-11-18 15:29:35 -08:00
Ryan Seto 76ee860ece Simplify the upstart example in host_integration.rst
Taking some pointers from @tianon on my pull request #2685.
2013-11-18 16:21:03 -05:00
Michael Crosby 94e854823f Use tryRelocate to fall back to symlink if rename fails 2013-11-18 13:16:28 -08:00
Guillaume J. Charmes e42b574579 Merge pull request #42 from alexlarsson/dm-plugin-archive-test-skip
Mark archive.TestApplyLayer as skipped
2013-11-18 13:10:39 -08:00
Andy Rothfusz 2ae1f29dfe Fixes #2702. Also cleans up formatting and long lines in volumes doc. 2013-11-18 13:09:13 -08:00
Josh Poimboeuf 4b80ec9aae test: remove extra args in TestExitCode
The extra blank argument isn't needed and confuses libvirt.
2013-11-18 15:07:11 -06:00
Josh Poimboeuf fef41ef7bf test: fix TestRmi race condition 2013-11-18 15:07:06 -06:00
Victor Vieux f946a486ea Merge pull request #2718 from dotcloud/fix_tmp_dir_never_cleanup
Fix tmp dir never cleanup
2013-11-18 12:20:23 -08:00
Guillaume J. Charmes e008c7c068 Merge pull request #2743 from tianon/go1.2rc5
Update to go1.2rc5
2013-11-18 12:11:56 -08:00
Andy Rothfusz 669e4bac30 Merge pull request #2729 from SvenDowideit/docker-info-doc
add example for docker info
2013-11-18 11:44:54 -08:00
Andy Rothfusz f6362fbb0e Merge pull request #2726 from SvenDowideit/docker-history-doc
add example for docker history
2013-11-18 11:43:44 -08:00
Andy Rothfusz c1cd824570 Merge pull request #2742 from rick/patch-1
Tiny typo cleanup
2013-11-18 11:37:37 -08:00
Michael Crosby 4546832507 Merge pull request #2752 from dotcloud/gofmt_test
Go fmt tests
2013-11-18 11:34:59 -08:00
Andy Rothfusz b5934711d0 Merge pull request #2724 from SvenDowideit/docker-diff-example
add an example of what to expect from docker diff, and what the 3 codes mean
2013-11-18 11:34:05 -08:00
Victor Vieux ed8f75d25c gofmt_test 2013-11-18 11:25:13 -08:00
Michael Crosby cfbd9ea16d Merge pull request #2749 from jpoimboe/dont-forward-SIGCHLD
Do not forward SIGCHLD to container
2013-11-18 11:24:08 -08:00
Michael Crosby 75dd1663e0 Merge pull request #2638 from FreakyDazio/2506-name-conflict-error
More informative error message on name collisions
2013-11-18 11:13:43 -08:00
Darren Coxall 3c67a28493 More informative error message on name collisions
This is the proposed fix for #2506. It provides a more complete message
with regards to name collisions including informing of the opposing
containers ID.

I have included a test to ensure that the correct short id is displayed
to make the message easier to understand.
2013-11-18 17:51:47 +00:00
Josh Poimboeuf 440422a963 don't forward SIGCHLD to container
It makes no sense to forward SIGCHLD to the container.
2013-11-18 11:45:29 -06:00
Josh Poimboeuf fc2f5758cf fix container restart race condition
Finish container cleanup before setting the state to stopped.
Otherwise, for an application that exits quickly, a call to Restart
can allow Start to be called again before cleanup is done, resulting in
overritten data in the Container struct.
2013-11-18 11:42:30 -06:00
Josh Poimboeuf fe302fbfd2 test: 2 second timeout (not 2000) 2013-11-18 10:23:30 -06:00
Josh Poimboeuf 72d02ecdde test: skip TestCreate on Fedora due to lxc utils bug
In the dind environment running on a Fedora host, the lxc utils get
confused by the /sys/fs/cgroup/cpuacct,cpu cgroup mount and lxc-start
fails trying to access the wrong cgroup directory.
2013-11-18 10:23:30 -06:00
Josh Poimboeuf baa687bed2 test: fix TestCreateStartRestartStopStartKillRm
cat needs stdin opened, otherwise it dies immediately.
2013-11-18 10:23:30 -06:00
Josh Poimboeuf 30ea0bebce test: put each arg in a separate string
Each arg to docker run should be placed in a separate string.
Otherwise, when starting the command via exec.Cmd, the command is
interpreted as "echo test", which can't be found.
2013-11-18 10:23:06 -06:00
Alexander Larsson 8ed4307f50 Mark archive.TestApplyLayer as skipped
Instead of just returning we call Skip to log that the test
was skipped.
2013-11-18 14:31:34 +01:00
Tianon Gravi 9e1da3ec9c Update to go1.2rc5 2013-11-17 22:36:26 -07:00
Rick Bradley b76574f855 Tiny typo cleanup 2013-11-17 21:10:06 -08:00
Tianon Gravi 457375ea37 Merge pull request #2732 from jplock/patch-2
Fix images not being properly tagged in mkimage-debootstrap.sh
2013-11-17 08:06:58 -08:00
Frederik Loeffert 7e580aacec Vagrantfile modified to support VBoxGuestAdditions_4.3.2 2013-11-17 01:20:21 +01:00
Justin Plock 0e64b987e8 Fix images not being properly tagged 2013-11-16 11:05:38 -05:00
Sven Dowideit bc74f65068 make the docker commit help more copy&pasteable 2013-11-16 21:11:34 +10:00
Sven Dowideit 5c741ef11d add example 2013-11-16 20:53:45 +10:00
Sven Dowideit 152459b727 add some common examples for docker images, and tell the user what -a filters out 2013-11-16 20:45:30 +10:00
Sven Dowideit f04142c1f7 add example for docker history 2013-11-16 20:36:33 +10:00
Sven Dowideit af05ab399e add an example of what to expect from docker diff, and what the 3 codes mean 2013-11-16 20:26:47 +10:00
Sven Dowideit 27159ce6ba expunge the word 'Resource' in reference to a file/dir in a CONTAINER - that way users don't wonder how its different from a Path 2013-11-16 20:15:04 +10:00
Michael Crosby 51576069ad Merge pull request #2694 from shykes/separate-integration-tests
Separate integration tests
2013-11-15 18:21:34 -08:00
Andy Rothfusz d33ffe44a9 Fixes #2701. Adds security section. 2013-11-15 18:12:35 -08:00
Solomon Hykes afe230718e Re-enable api integration tests using only public remote API. 2013-11-16 02:12:14 +00:00
Michael Crosby 427649eee1 Merge pull request #40 from shykes/creack-0.6.5-dm-plugin
Rename gograph and move drivers to sub pkg
2013-11-15 17:31:50 -08:00
Guillaume J. Charmes a518b84751 WIP 2013-11-15 17:16:30 -08:00
Victor Vieux 9261690593 Fix tmp dir never cleanup 2013-11-15 16:23:55 -08:00
Guillaume J. Charmes cbd1281ec9 rename gograph in graphdb 2013-11-15 15:55:45 -08:00
Guillaume J. Charmes 035c144242 Move all drivers to the same subdir graphdriver 2013-11-15 15:48:24 -08:00
Guillaume J. Charmes fb245f7903 Merge pull request #38 from crosbymichael/add-container-driver
Save driver to container and skip incompat containers
2013-11-15 14:20:19 -08:00
Guillaume J. Charmes dc5b7b32c3 Merge pull request #36 from crosbymichael/unlink-init-files
Unlink docker init files
2013-11-15 14:09:51 -08:00
Andy Rothfusz e12bba66ea Merge pull request #2709 from eugenkrizo/patch-1
path needs to be specified to 'docker build' command
2013-11-15 13:34:08 -08:00
Andy Rothfusz 92c3a319fb Merge pull request #2713 from eugenkrizo/patch-2
port published explicitly (for docker 0.6.6)
2013-11-15 13:32:18 -08:00
Andy Rothfusz 323e86032d Merge pull request #2685 from Painted-Fox/patch-1
Add more depth to the upstart example in host_integration.rst
2013-11-15 12:28:07 -08:00
Victor Vieux c06d903edd bring back tests about LXCConfig 2013-11-15 11:48:18 -08:00
Andy Rothfusz 9a9d3239e1 Fix typos, add links, streamline content of #2592 2013-11-15 11:38:03 -08:00
Andy Rothfusz 33110ddc3f Merge branch 'fix_examples_use_docs' of git://github.com/rogaha/docker into test-2592 2013-11-15 11:15:14 -08:00
Andy Rothfusz 6341768393 Merge pull request #2689 from metalivedev/fix-syntax
Clean up sphinx syntax
2013-11-15 11:09:51 -08:00
Victor Vieux ad96d5ff04 Merge pull request #2712 from makinacorpus/master
Do not drop sys_boot
2013-11-15 10:33:41 -08:00
Michael Crosby 7cad77b1e2 Merge pull request #33 from alexlarsson/dm-plugin-status
Add driver plugin status
2013-11-15 10:15:59 -08:00
Guillaume J. Charmes 2b23da1d2f Merge pull request #34 from alexlarsson/dm-plugin-dummy-volumes
Use dummy driver for volumes
2013-11-15 09:41:16 -08:00
Guillaume J. Charmes bcf96d95bc Merge pull request #30 from alexlarsson/dm-plugins-archive-tests
Dm plugins archive tests
2013-11-15 09:38:17 -08:00
eugenkrizo 492ce4c665 port published explicitly (for docker 0.6.6)
port 5984 to couchdb needs to be published explicitly in docker version 0.6.6
2013-11-15 17:12:48 +01:00
Mathieu Le Marec - Pasquet 76ab8fa00f Merge pull request #1 from jpetazzo/2392-add-kernel-docs
Add warning about SYS_BOOT capability with pre-3.4 kernels and pre-0.8 LXC.
2013-11-15 07:58:54 -08:00
eugenkrizo 007964793d path needs to be specified to 'docker build' command
current folder '.' appended as a path
2013-11-15 16:16:59 +01:00
Alexander Larsson 10f23a94f6 Use dummy driver for volumes
It makes no sense to use the aufs or devicemapper drivers for volumes.
The aufs one is perhaps not a big problem, but the devicemapper one
certainly is. It will be unnecessarily using a dm
blockdevice-over-loopback with a limited size base FS.

This just hardcodes the driver to be the dummy, perhaps in the future
we can have other drivers that make sense for the volumes.
2013-11-15 11:30:28 +01:00
Alexander Larsson 243843c078 Print devicemapper status details in docker info
This adds a generic Status call in the Driver api and
implements if for the devicemapper backend.

The status is an array of key/value strings rather than a map so that
we can guarantee some static order of the docker info output.
2013-11-15 11:04:02 +01:00
Alexander Larsson 062810caed Show active driver in docker info output 2013-11-15 10:24:48 +01:00
Alexander Larsson f7238f94e8 Add tests for the changes detection code
This adds 3 tests:

Verify that ChangesDirs() returns nothing when run on a copy of the
same directory.

Verify that various mutations of a directory get reported with the
right changes.

Verify that ExportChanges() + ApplyLayer() of the above mutation gets
an identical directory.

Unfortunately the last test is disabled because it fails in multiple
ways atm. But I want to get it in so that we can fix it.
2013-11-15 09:49:46 +01:00
Alexander Larsson d69a6a20f0 Use ExportChanges() in runtime.Diff()
This code was duplicated in two places, one which was unused. This
syncs the code and removes the unused version.
2013-11-15 09:49:42 +01:00
Michael Crosby 4908d7f81d Save driver to container and skip incompat containers
For people who toggle drivers we want to save the driver used
to create a container so that if the driver changes we can skip
loading the container and it should not show up in docker ps
2013-11-14 22:53:59 -08:00
Michael Crosby 29fa1b6666 Unlink docker init files 2013-11-14 21:23:23 -08:00
Andy Rothfusz bed87ea103 Merge pull request #2690 from codevin/master
Improvise documentation for builder.rst / VOLUME command
2013-11-14 19:23:18 -08:00
Solomon Hykes 823674816e Move iptables test to integration tests 2013-11-15 01:15:39 +00:00
Solomon Hykes 8d3e35cd8d Split auth tests between unit tests and integration tests 2013-11-15 01:13:20 +00:00
Michael Crosby 0c38f86e5e Merge pull request #32 from shykes/shykes-0.6.5-dm-plugin
Merge bug fix from dotcloud/docker master
2013-11-14 16:21:19 -08:00
Guillaume J. Charmes 8a358e8833 Merge branch 'master' into shykes-0.6.5-dm-plugin 2013-11-14 16:18:33 -08:00
Guillaume J. Charmes 84ed18827a Merge pull request #2704 from shykes/fix-auto-pull
Fix the brittle errorstring-to-httperror recognition code
2013-11-14 16:15:46 -08:00
Solomon Hykes 693ff4d2ae Fix the brittle errorstring-to-httperror recognition code which in turn is required by autopull (the client issues a pull if container creation returns 404) 2013-11-14 23:54:28 +00:00
Victor Vieux 596810d8db move TestMount to integration 2013-11-14 15:17:31 -08:00
Victor Vieux 661a8a0e0c fix Integration tests 2013-11-14 14:46:13 -08:00
Michael Crosby eb06a7b8f8 Merge pull request #31 from shykes/shykes-0.6.5-dm-plugin
Merge from dotcloud/docker master
2013-11-14 14:14:13 -08:00
Guillaume J. Charmes 7cf60da388 Merge branch 'master' into shykes-0.6.5-dm-plugin
Conflicts:
	utils.go
	utils_test.go
2013-11-14 14:02:44 -08:00
Alexander Larsson 006e2a600c ApplyLayer() use RemoveAll to handle removing directories
rmTargetPath can be a directory, so we have to use RemoveAll() or we
will fail to whiteout non-empty directories.
2013-11-14 22:56:18 +01:00
Michael Crosby eace2dbe1d Merge branch 'dm-plugin-new-ChangesDirs' of https://github.com/alexlarsson/docker into alexlarsson-dm-plugin-new-ChangesDirs
Conflicts:
	archive/changes.go
2013-11-14 12:23:01 -08:00
Michael Crosby 629c6e3649 Merge pull request #2445 from alexlarsson/fix-shared-root-from-dm
Fix lxc start for shared root filesystems
2013-11-14 11:20:53 -08:00
Andy Rothfusz c7aaf831d7 Merge pull request #2691 from SvenDowideit/add-instruction-path-limitations
except URL-based ADDs
2013-11-14 11:12:08 -08:00
Solomon Hykes e9624bf715 Remove deprecated tags_test.go 2013-11-14 10:50:43 -08:00
Solomon Hykes 2a209afe5f gofmt 2013-11-14 10:50:43 -08:00
Victor Vieux c001a5af67 Integration tests: remove dependency on private APIs 2013-11-14 10:50:43 -08:00
Solomon Hykes 359a6f49b9 Move integration tests to integration/, expose missing public methods in the core 2013-11-14 10:50:00 -08:00
Solomon Hykes 099c53b28e Merge pull request #29 from crosbymichael/try-load-aufs
Try to load aufs first then check in filesystems for aufs support
2013-11-14 10:11:19 -08:00
Michael Crosby 7b2d59b91e Try to load aufs first then check in filesystems for aufs support 2013-11-14 09:42:12 -08:00
Guillaume J. Charmes 529c30261e Merge pull request #28 from crosbymichael/close-sparse-files
Close sparse files when done
2013-11-14 07:02:47 -08:00
¨Sven e42144674f thankyou @tomdz - I forgot about URL based ADDs 2013-11-14 14:53:55 +10:00
Vinod Kulkarni 37abc07852 Improvise documentation for builder.rst / VOLUME command 2013-11-14 09:54:31 +05:30
Andy Rothfusz 61abc3f8ac Merge pull request #2688 from dhrp/doc-layout-dotcloud-to-docker-inc
Updated documentation footer to say "Docker Inc." instead of dotCloud. And added Read the Docs.
2013-11-13 18:31:21 -08:00
Andy Rothfusz 5fc56b6b47 Merge pull request #2661 from rogaha/links_docs
- Added a doc about Links and Container Naming
2013-11-13 18:15:25 -08:00
Andy Rothfusz 059950b095 Clean up sphinx syntax, upgrade http markup package, minor link changes, update intro. 2013-11-13 17:45:22 -08:00
Michael Crosby bbc9fc7907 Close sparse files when done 2013-11-13 17:05:32 -08:00
Michael Crosby 7682ec04cd Merge pull request #27 from shykes/refactor_dm
Add more dm unit tests
2013-11-13 16:50:26 -08:00
Guillaume J. Charmes 590465b395 Merge branch 'shykes-0.6.5-dm-plugin' into refactor_dm 2013-11-13 16:47:37 -08:00
Guillaume J. Charmes 05d70cbcf4 More dm unit tests 2013-11-13 16:46:10 -08:00
Thatcher Peskens 9ab85f4d12 Updated documentation footer to say "Docker Inc." instead of dotCloud. And added link to Read the Docs for giving them credit to hosting us. (Thanks Read The Docs!) 2013-11-13 16:09:23 -08:00
Michael Crosby 539708aa8a Merge pull request #26 from shykes/refactor_dm
Refactor dm
2013-11-13 15:45:58 -08:00
Guillaume J. Charmes 3aaef96e36 Merge branch 'shykes-0.6.5-dm-plugin' into refactor_dm 2013-11-13 15:44:13 -08:00
Guillaume J. Charmes 921e2e9ae2 Merge pull request #25 from crosbymichael/add-aufs-diff-test
Add test for ApplyDiff
2013-11-13 15:43:26 -08:00
Guillaume J. Charmes b50838c359 Merge pull request #24 from crosbymichael/dm-tests
Add device mapper tests for driver.go
2013-11-13 15:41:59 -08:00
Guillaume J. Charmes 4bebca848e Add devmapper_test.go 2013-11-13 15:35:52 -08:00
Michael Crosby 6b3dd02bb8 Add test coverage for devicemapper driver.go 2013-11-13 14:56:26 -08:00
Michael Crosby 80e7319558 Make sure setInitialized is called when device is mounted 2013-11-13 14:54:47 -08:00
Guillaume J. Charmes 1d188c8737 Create devmapper_wrapper.go 2013-11-13 14:36:31 -08:00
Andy Rothfusz 3cf23b93ea Merge pull request #2679 from FreekKalter/master
fix error in python webapp example
2013-11-13 13:35:01 -08:00
Guillaume J. Charmes 3ba6835ead Merge pull request #2676 from tianon/go1.2rc4
Update to go1.2rc4
2013-11-13 11:45:56 -08:00
Guillaume J. Charmes dc13b9473f Merge pull request #2686 from shykes/gofmt
gofmt
2013-11-13 11:35:37 -08:00
Solomon Hykes b00d5f0185 gofmt 2013-11-13 19:25:55 +00:00
Andy Rothfusz 8e71391572 Merge pull request #2660 from SvenDowideit/2601-remote-api-json-case
update the API docs to reflect the change in the case of the /index/search reposnse
2013-11-13 11:17:54 -08:00
Michael Crosby a69d86e0b1 Add test for ApplyDiff 2013-11-13 11:03:56 -08:00
Andy Rothfusz 077c2496ed Merge pull request #2681 from SvenDowideit/add-instruction-path-limitations
add a little more info about the limitations of ADD wrt ../ and docker build
2013-11-13 10:56:35 -08:00
Guillaume J. Charmes 46ab7d1e8a Merge pull request #15 from alexlarsson/dm-plugin-explicit-init
Remove devicemapper lazy initialization
2013-11-13 10:46:24 -08:00
Tianon Gravi b94e9ed0de Merge pull request #2652 from tianon/upstart-defaults-too
Add /etc/default/docker support to upstart, too (mirroring sysvinit)
2013-11-13 10:42:41 -08:00
Guillaume J. Charmes e3597624dd Merge pull request #23 from crosbymichael/ignore-dir-sizes
Ignore dir sizes in TreeSize func
2013-11-13 10:40:03 -08:00
Ryan Seto 02884ee429 Add more depth to the upstart example in host_integration.rst
I found that the original example wasn't starting the docker container when docker is started.  So, I modified it using information I found from https://groups.google.com/forum/#!msg/docker-user/OWz8EOpiXuo/L_uxGFQuYlkJ

Also, upstart wasn't starting docker if it wasn't running ahead of time.  So, I added a change to the docker upstart script to solve this.
2013-11-13 13:34:34 -05:00
Michael Crosby a4f14528c2 Ignore dir sizes in TreeSize func 2013-11-13 10:33:24 -08:00
Jérôme Petazzoni 8145e57cee Add warning about SYS_BOOT capability with pre-3.4 kernels and pre-0.8 LXC. 2013-11-13 10:29:29 -08:00
Solomon Hykes c964494d31 Merge pull request #2673 from shykes/engine-patch-2
* Engine: expand the engine API with 'create' and 'start' jobs Edit
2013-11-13 10:14:56 -08:00
Solomon Hykes c6e83b8779 Merge pull request #2656 from shykes/export-restrictions-debian
Change crypto export notice to meet Debian requirements
2013-11-13 09:37:23 -08:00
Guillaume J. Charmes 369e39aea1 Merge pull request #2680 from inglesp/patch-1
Typo in ROADMAP.md
2013-11-13 09:19:37 -08:00
¨Sven af0b2e38c3 add a little more info about the limitations of ADD wrt ../ and docker build - 2013-11-13 22:55:55 +10:00
inglesp 87b4bb9fcc Typo in ROADMAP.md 2013-11-13 12:32:49 +00:00
Freek Kalter f5e6c2d060 fix error in python webapp example
When getting the private port used by a container using
`docker port` returns 0.0.0.0:49353, stript just the portnumber of the address with awk to used it in the rest of the example code.
2013-11-13 13:20:38 +01:00
¨Sven f0f8462d18 update the v1.7 API to reflect the case change in the /index/search response, and note that its to align better with the registry server response that its proxying 2013-11-13 22:11:20 +10:00
Xiuming Chen 0013aa7d9f Minor code simplification for Containers api 2013-11-13 01:29:00 -08:00
Liang-Chi Hsieh 1d7f22c0d4 use Binds key in hostConfig to detect volumes mounted from external. 2013-11-13 15:08:46 +08:00
Liang-Chi Hsieh 6a693176d6 skip the volumes mounted when deleting the volumes of container. 2013-11-13 14:58:24 +08:00
Tianon Gravi 8523d5518c Update to go1.2rc4 2013-11-12 21:51:12 -07:00
Solomon Hykes 6c4393ccbb Merge branch 'job-create-start-clean' into engine-patch-2
Conflicts:
	engine/engine.go
	engine/job.go
	server.go
	utils_test.go
2013-11-13 00:36:20 +00:00
Solomon Hykes 3885ef585b Merge pull request #2612 from tianon/release-script-tweaks
* Hack: release script tweaks
2013-11-12 15:04:26 -08:00
Victor Vieux 388057f11a Merge pull request #2648 from dotcloud/docker_kill_exit_code
Make sure docker kill exit with failure in case of error
2013-11-12 14:40:17 -08:00
Michael Crosby a06edd77e5 Merge pull request #22 from shykes/shykes-0.6.5-dm-plugin
Fix ImageTree test
2013-11-12 12:30:30 -08:00
Guillaume J. Charmes c69e6a90e4 Merge pull request #2663 from viirya/fix_nameserver_regex
Fix nameserver regex
2013-11-12 12:29:40 -08:00
Guillaume J. Charmes 08623dc216 Fix ImageTree test 2013-11-12 12:25:35 -08:00
Guillaume J. Charmes 50d80a8938 Merge pull request #17 from alexlarsson/dm-plugin-whiteout-directory
archive.ApplyLayer() - handle directory whiteouts
2013-11-12 12:16:30 -08:00
Alexander Larsson 6f3c32eb18 archive.ApplyLayer() - handle directory whiteouts
When directories are white-outed we can get called with the previously
removed directories. Handle this with os.IsNotExist(error).
2013-11-12 21:14:54 +01:00
Guillaume J. Charmes 0dd92d8f1c Merge pull request #21 from crosbymichael/pull-parent-layers
Pull parent layers first before children
2013-11-12 11:50:20 -08:00
Michael Crosby 7301fbe035 Pull parent layers first before children 2013-11-12 11:48:35 -08:00
Guillaume J. Charmes 4ec05b5dbf Merge pull request #20 from crosbymichael/force-driver-to-implement-differ
Force driver to implement differ
2013-11-12 11:48:20 -08:00
Victor Vieux 71c05bb87c Merge pull request #2662 from dotcloud/do_not_cleanup_start_if_running
on docker start, do not cleanup if already running
2013-11-12 11:02:10 -08:00
Victor Vieux 637850063c Merge pull request #2614 from dotcloud/prevent_delete_image_running_container
Runtime: prevent deletion if image is used by a running container
2013-11-12 11:01:51 -08:00
Victor Vieux dcc9980550 Merge pull request #2657 from dotcloud/fix_docker_images_output
use utils.ParseRepositoryTag instead of strings.split in docker images
2013-11-12 11:01:29 -08:00
Victor Vieux e405337926 Merge pull request #2669 from tianon/clarify-test-calls
Add clarification of multiple "go test" calls in hack/make/*test
2013-11-12 10:42:24 -08:00
Tianon Gravi 5cdb3aec50 Add clarification of multiple "go test" calls in hack/make/*test 2013-11-12 11:23:06 -07:00
Victor Vieux b314f19db8 Merge branch 'tests/insert' of https://github.com/mrallen1/docker into mrallen1-tests/insert
Conflicts:
	server.go
2013-11-12 10:19:29 -08:00
Roberto Gandolfo Hashioka 353243a725 - Improved documentation and typos fixing (Thanks to @jamtur01) 2013-11-12 10:11:52 -08:00
Liang-Chi Hsieh 879aa29cb0 modify test of GetNameserversAsCIDR for its regex change. 2013-11-12 18:18:30 +08:00
Michael Crosby 5d9723002b Allow drivers to implement ApplyDiff in Differ interface 2013-11-11 19:09:57 -08:00
Liang-Chi Hsieh 1e5ba57de3 fix nameserver regex. 2013-11-12 10:53:34 +08:00
Victor Vieux bc6d872841 on docker start, do not cleanup if already running 2013-11-11 18:15:38 -08:00
Roberto Gandolfo Hashioka 981560c436 - Added a doc about Links and Container Naming 2013-11-11 17:38:54 -08:00
Victor Vieux d589cc3622 Merge pull request #2527 from jpoimboe/fedora-iptables-fix
Fix container networking on Fedora
2013-11-11 15:12:40 -08:00
Andy Rothfusz 69a9614cb4 Merge pull request #2621 from rogaha/rm_del_all_example
- Added delete all the containers example (docker rm `docker ps -a -q`)
2013-11-11 14:55:50 -08:00
Victor Vieux e2ac0e6b80 add wait, stop, start, restart, rm, rmi 2013-11-11 14:47:23 -08:00
Michael Crosby 2c7f50a77d Add ability to exclude files from tar 2013-11-11 14:30:38 -08:00
Solomon Hykes 01dd7e7459 Change crypto export notice to meet Debian requirements 2013-11-11 22:08:37 +00:00
Victor Vieux 84a3600ea8 use utils.ParseRepositoryTag instead of strings.split in docker images 2013-11-11 13:54:17 -08:00
Andy Rothfusz cb9e0aee48 Merge pull request #2646 from fgrehm/contrib-vagrant
Update contrib/vagrant-docker with projects available
2013-11-11 13:49:15 -08:00
Andy Rothfusz 52d3137713 Merge pull request #2641 from artagnon/master
CONTRIBUTING: wrap a couple of long lines
2013-11-11 13:43:30 -08:00
Victor Vieux 4c7d24bc8b Merge branch 'master' of https://github.com/zilin/docker into zilin-master
Conflicts:
	container.go
2013-11-11 12:59:18 -08:00
Victor Vieux 87c8437a90 Merge pull request #2140 from SvenDowideit/2098-run-cidfile-should-return-longid
Server: always return long id's
2013-11-11 13:06:19 -08:00
Daniel Mizyrycki 6fab249b21 Merge pull request #2313 from wazboy/master
Vagrant AWS update
2013-11-11 13:01:20 -08:00
Victor Vieux da24945070 Merge branch 'master' of https://github.com/aanand/docker into aanand-master 2013-11-11 12:34:16 -08:00
Michael Crosby 4d1a537433 Remove Differ and Changer interfaces
Add the methods to the Driver interface
to force the drivers to implement the methods
2013-11-11 12:10:53 -08:00
Tianon Gravi ca113bb1b2 Merge pull request #2613 from tianon/ubuntu-fpm-tweaks
Update ubuntu packaging script, especially to stop docker group deletion
2013-11-11 12:01:40 -08:00
Andy Rothfusz 9ff36cb00c Merge pull request #2630 from jamtur01/api_status
Added status column to API client table
2013-11-11 11:56:04 -08:00
Mark Allen 62f873aa1f Just return the id; nothing else. 2013-11-11 13:26:24 -06:00
Tianon Gravi 2091b59721 Merge pull request #2653 from tianon/sysvinit-upstart-check
Update upstart check in sysvinit to be exactly the same as the init_is_upstart function
2013-11-11 11:00:07 -08:00
Tianon Gravi 88edba7e86 Update upstart check in sysvinit to be exactly the same as the init_is_upstart function from /lib/lsb/init-functions (which isn't available in 12.04 or we'd use it directly) 2013-11-11 11:57:25 -07:00
Solomon Hykes ec6fe9f200 Hack: set NONUKE environment variable to run the tests without cleanup, to investigate temp directories 2013-11-11 18:56:21 +00:00
Tianon Gravi 5fe4c9a39a Merge pull request #2651 from tianon/fix-sysvinit-upstart-logic
Fix sysvinit upstart detection and give it a pretty message
2013-11-11 10:39:51 -08:00
Michael Crosby 2fc0084f6b Merge pull request #2633 from danderson/2598-fix-iptables-anydest
Correctly express "any address" to iptables.
2013-11-11 10:22:02 -08:00
Tianon Gravi 7cf7dda87d Add /etc/default/docker support to upstart, too (mirroring sysvinit) 2013-11-11 11:13:16 -07:00
Tianon Gravi bb76157d24 Fix sysvinit upstart detection and give it a pretty message 2013-11-11 11:10:19 -07:00
Solomon Hykes e87c3ea342 Merge pull request #19 from alexlarsson/dm-plugin-Diff-fallback
Implement fallback operation for driver.Diff()
2013-11-11 10:09:12 -08:00
Andy Rothfusz 1d9139bb89 Merge pull request #2574 from crosbymichael/api-port-changes
Update documentation to reflect changes in Config and HostConfig
2013-11-11 09:59:48 -08:00
Guillaume J. Charmes 8149439d95 Make sure docker kill exit with failure in case of error 2013-11-11 09:15:51 -08:00
Guillaume J. Charmes 402a58a75a Fix formatting in tests 2013-11-11 09:05:38 -08:00
Alexander Larsson e82f8c1661 Implement fallback operation for driver.Diff()
This moves the Diff() operation to a separate Differ interface and
implements a fallback that uses the Changes() results to encode
a diff tar.
2013-11-11 17:46:07 +01:00
Fabio Rehm 9c7a8edddd Update contrib/vagrant-docker with projects available 2013-11-11 13:36:44 -02:00
Alexander Larsson b6ef4bc952 archive.ChagesDir() - faster and better implementation
This replaces the current version with the latest version from the
dm branch. Advantages in this version:

We only scan each directory tree once, which means less i/o and less chance
of container changes inbetween the two scans causing inconsistencies.

We avoid comparing some fields for change detection:

* Inode
* size-in-blocks
  These can change during a copy operation (e.g. in the dummy backend)
  without needing to actually reflect a change in content or metadata.

* Ctime
  Any copy operation will create a new Ctime value, and there is no
  API to change it to the "source" value.

* size for directories
  The size of a directory doesn't have to be the same just because you
  recreated the same content as another director. Internal details in
  the filesystem may make these different with no "real" change.
2013-11-11 14:51:19 +01:00
Alexander Larsson b5795749d1 Remove devicemapper lazy initialization
We now always initialize devicemapper on startup, so
no need for the code that did lazy initialization, we
just delete it.
2013-11-11 13:29:27 +01:00
Ramkumar Ramachandra cf30b85eb1 CONTRIBUTING: wrap a couple of long lines
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
2013-11-11 16:21:34 +05:30
Galen Sampson ccbb5d3492 Vagrantfile updates.
- Remove the overrides config.vm.box and config.vm.box_url and use
  the same values for all providers.
- Use the same private key path for all providers.  It is still possible
  to set a different private key path through the environment variable
  SSH_PRIVKEY_PATH if desired (your AWS key may be different from your
  Virtualbox key).
- Allow the environment variable AWS_INSTANCE_TYPE to specify the
  instance type of instead of hard coding the AWS instance type as
  't1.micro'.  't1.micro' is still the default if unspecified.
- Use the same environment variables for keys as the Amazon provided EC2
  API tools.  This allows people who already have the EC2 tools set up
  correctly to use 'vagrant up' with less environment configuration
  than before.
- Rewrite the provisioning code.  The goal is to be idempotent and to
  correctly install docker for all providers instead of just virtualbox.
  It will conditionally install the virtualbox guest additions if
  virtualbox is the provider.
- Update the AWS install documentation to reflect the changes.
2013-11-10 23:39:26 -08:00
James Turnbull 5a1bfd9aa9 Added status column to API client table 2013-11-10 12:14:45 -05:00
Mark Allen 8cc19765b4 Edits after code review
Return long image ID
Return streamformatted error or "raw" error
2013-11-10 00:06:55 -06:00
David Anderson 8ba8783bcc Correctly express "any address" to iptables.
Iptables interprets "-d 0.0.0.0" as "-d 0.0.0.0/32", not /0. This
results in the DNAT rule never matching any traffic if not bound
to a specific host IP.

Fixes #2598
2013-11-09 19:40:56 -08:00
Roberto Gandolfo Hashioka 4ec0b51578 - Updated description 2013-11-09 11:08:43 -08:00
Tianon Gravi 7f1b179c67 Fix the display of get.docker.io in Firefox by making our index files text/plain 2013-11-09 02:28:04 -07:00
Sven Dowideit b3974abe4f make all image ID and container ID API responses use the Long ID (Closes #2098) 2013-11-09 12:16:49 +10:00
Solomon Hykes 948bb29d27 Don't use drivers to store temporary image downloads 2013-11-09 00:53:58 +00:00
Roberto Gandolfo Hashioka 403f9fc357 - Added delete all the containers example 2013-11-08 16:47:42 -08:00
Michael Crosby 1f35531f39 Merge pull request #13 from crosbymichael/fix-volume-mount
Do not pass container information when creating a volume
2013-11-08 16:35:00 -08:00
Michael Crosby f30c660f6f Merge pull request #12 from crosbymichael/core-driver-test-failures
Core driver test failures
2013-11-08 16:33:53 -08:00
Tianon Gravi 498b6031b1 Update ubuntu packaging script, especially to stop docker group deletion 2013-11-08 17:23:37 -07:00
Michael Crosby ddb27268c9 Do not pass container information when creating a volume 2013-11-08 16:11:57 -08:00
Andy Rothfusz f26da9638f Merge pull request #2590 from metalivedev/2585-addphplib
Fix 2585 and clean up warning in contributing.rst
2013-11-08 15:35:24 -08:00
Michael Crosby 1eb00e1d5b Allow drivers to export their own diff 2013-11-08 15:32:50 -08:00
Guillaume J. Charmes 126b17a0ff Merge pull request #2615 from jpoimboe/ghost-networking-fix
setup network when reconnecting to ghost container
2013-11-08 15:31:55 -08:00
Andy Rothfusz 34d294c461 Fix 2585, rebase to master 2013-11-08 15:15:45 -08:00
Victor Vieux 45c2b5dc1a prevent deletion if image is used by a running container 2013-11-08 15:01:01 -08:00
Michael Crosby 9514767587 Allow driver to provide changes if it impl the Changer interface 2013-11-08 14:54:20 -08:00
Tianon Gravi f56945d71b Update release script to move https://get.docker.io/ubuntu/info to https://get.docker.io/ubuntu/ and provide a backwards-compatibility redirect (same for /builds/info) 2013-11-08 15:45:18 -07:00
Tianon Gravi b8e7ec1b74 Update release script with proper support for non-*.docker.io bucket URLs 2013-11-08 15:44:52 -07:00
Guillaume J. Charmes 3bbe8ee055 Merge pull request #2611 from seancron/changelog-edit
Removes duplicate changelog entry
2013-11-08 14:39:02 -08:00
Josh Poimboeuf 2448058ee2 setup network when reconnecting to ghost container
Re-adding the line to setup the network when reconnecting to a ghost
container.  It was inadvertently removed by commit
31638ab2ad.
2013-11-08 16:28:41 -06:00
Sean Cronin ca174ae84d Removes duplicate changelog entry 2013-11-08 17:17:39 -05:00
Victor Vieux f9dd0da182 Merge pull request #2610 from stapelberg/patch-1
Return “err” instead of “nil” when MkdirAll() fails when binding a volume
2013-11-08 14:00:06 -08:00
Michael Stapelberg e7fdcc15c5 Return “err” instead of “nil” when MkdirAll() fails when binding a volume 2013-11-08 22:52:10 +01:00
Michael Crosby f512049c8f Add unit test for child changes diff in aufs 2013-11-08 12:25:17 -08:00
Andy Rothfusz 67b0b97a8f Merge pull request #2526 from metalivedev/2074-AddKnownIssues
Add Known Issue
2013-11-08 12:14:04 -08:00
Michael Crosby 20f690f176 Make sure dirs are created before injecting file 2013-11-08 12:06:15 -08:00
Michael Crosby 6669c86fdf Use tmp dir in driver home 2013-11-08 11:56:34 -08:00
Solomon Hykes 78ef0bd998 Merge pull request #6 from alexlarsson/fix-ApplyLayer-remove
archive.ApplyLayer() remove files recursively
2013-11-08 11:46:55 -08:00
Solomon Hykes c1563de7a1 Merge pull request #10 from crosbymichael/aufs-fixes
Aufs fixes and driver dir namespaceing
2013-11-08 11:45:45 -08:00
Michael Crosby 08a276986c Name sure drivers are confined into their own dir 2013-11-08 11:36:58 -08:00
Michael Crosby ed18844613 Implement changes for aufs driver 2013-11-08 11:10:33 -08:00
Michael Crosby 52f31657cc Do not remove mountpoint on umount 2013-11-08 10:17:51 -08:00
Michael Crosby 6d0b3f350e Merge pull request #9 from crosbymichael/fix-aufs-tests
Fix aufs error at startup
2013-11-08 09:55:24 -08:00
Guillaume J. Charmes 310fbe7bb7 Merge pull request #2565 from danielnorberg/master
lock around read operations in graph
2013-11-08 09:34:18 -08:00
Michael Crosby 3f2a5912ee Merge pull request #2593 from dotcloud/2578
Fix mergeConfig with new ports
2013-11-08 09:23:06 -08:00
Michael Crosby 65102d6b36 Merge pull request #2597 from dotcloud/deprecate_separate_tag
Deprecate old tagging format
2013-11-08 09:15:47 -08:00
Michael Crosby 997a32706f Merge pull request #2599 from dotcloud/prevent_panic_wrong_api_use
Prevent panic if you use API in a wrong way
2013-11-08 09:09:03 -08:00
Guillaume J. Charmes 5cf6ad4565 Merge pull request #2584 from dotcloud/docker-ci
docker-ci production sync
2013-11-08 08:24:09 -08:00
Mark Allen bf8e0277bb Add ImageInsert tests 2013-11-08 00:16:45 -06:00
David Sissitka 5957dd9091 Make "docker insert" errors obvious
Closes #1130
See also #1942
2013-11-08 00:15:19 -06:00
Michael Crosby 51c93c0f33 Fix aufs error at startup
Add String methods to other drivers
2013-11-07 19:02:15 -08:00
Victor Vieux 49d7b87cfc prevent panic if you use API in a wrong way 2013-11-07 18:54:00 -08:00
Solomon Hykes 8c21d2acd3 Set DOCKER_DRIVER to override the choice of driver (aufs, devicemapper or dummy) 2013-11-08 02:49:32 +00:00
Solomon Hykes 1e5c61041f Don't hardcode dependency on aufs in the tests 2013-11-08 02:49:08 +00:00
Solomon Hykes 99210c9c6e Don't rely on drivers for diff and export 2013-11-08 02:48:52 +00:00
Solomon Hykes 1764cf1990 Fix a bug which caused Graph.Register to fail when Graph.Mktemp() returns an existing directory. 2013-11-08 02:13:11 +00:00
Victor Vieux f417c4b099 Merge branch '1887-allow_ro_volumes-from' of https://github.com/daniel-garcia/docker into daniel-garcia-1887-allow_ro_volumes-from 2013-11-07 17:59:55 -08:00
Solomon Hykes 9afe475edb Merge pull request #8 from crosbymichael/improve-aufs-detection
aufs: Improve aufs detection by looking at proc fs
2013-11-07 17:59:24 -08:00
Michael Crosby 043a576171 Improve aufs detection by looking at proc fs 2013-11-07 17:57:14 -08:00
Solomon Hykes 81674fbbdf New 'dummy' driver uses plain directories and regular copy 2013-11-08 01:52:56 +00:00
Solomon Hykes 0a9df6bc1a Merge pull request #7 from crosbymichael/updated-interfaces
Updated aufs driver for new interface
2013-11-07 17:43:31 -08:00
Guillaume J. Charmes ef57752bce Deprecate old tagging format 2013-11-07 17:30:51 -08:00
Michael Crosby 12ffead71a Fix test for aufs graph and add aufs driver import 2013-11-07 17:01:57 -08:00
Michael Crosby b8b509e1c8 Update aufs driver to new interface spec 2013-11-07 16:46:47 -08:00
Solomon Hykes 01990b65a3 Move Change to the archive package 2013-11-07 16:46:47 -08:00
Solomon Hykes 9ae4bcaaf8 Move Change to the archive package, and fix a leftover merge in
Container.Inject()
2013-11-08 00:45:07 +00:00
Solomon Hykes f1127b9308 gofmt 2013-11-07 23:58:03 +00:00
Guillaume J. Charmes 4f8b6c3283 Merge pull request #2348 from SvenDowideit/2328-docker-events-since-date-string
Use string timestamp for docker events -since
2013-11-07 15:47:41 -08:00
Sven Dowideit 01fea3cf11 Closes #2328 - allow the user to specify a string timestamp (not just a unix epoch) in the string format that the docker cli shows to the user 2013-11-08 09:32:13 +10:00
Solomon Hykes 165d1bdbc0 Merge branch 'master' into 0.6.5-dm-plugin
Conflicts:
	container.go
	runtime.go
2013-11-07 23:26:52 +00:00
Roberto Gandolfo Hashioka eba3c36b38 - Included the sudo alternative as an example_header 2013-11-07 14:44:07 -08:00
Solomon Hykes 4a8a7d4edd devmapper: port to the new driver API and reactivate driver 2013-11-07 22:41:55 +00:00
Solomon Hykes f2bab1557c Simplify graphdriver interface: Create, Get. No more external mounting or Dir/Image interface 2013-11-07 22:38:50 +00:00
Victor Vieux 49c4231f07 fix mergeConfig with new ports 2013-11-07 14:31:25 -08:00
Josh Poimboeuf ec4657b28a network: add iptables rules to explicitly allow forwarding
Explicitly enable container networking for Fedora and other distros that
have a REJECT all rule at the end of their FORWARD table.
2013-11-07 16:23:39 -06:00
Roberto Gandolfo Hashioka 304d39cc50 - Fix the attach examples according to the new attach behavior
- Add the option of adding the user to docker's group and avoid the usage of "sudo" before each command
2013-11-07 14:06:49 -08:00
Alexander Larsson 484804abff archive.ApplyLayer() remove files recursively
Some aufs metadata are directories, and whiteouts can be for
directories, so use os.RemoveAll() for these.
2013-11-07 22:46:44 +01:00
Michael Crosby cd4f7321c9 Merge pull request #2589 from dotcloud/gofmt
Go fmt
2013-11-07 12:32:58 -08:00
Solomon Hykes a63ff8da46 Fix a crash in graphdriver init 2013-11-07 20:31:50 +00:00
Solomon Hykes 77ae9789d3 Internal cleanup: use the mounted container filesystem instead of manipulating the aufs layers directly 2013-11-07 20:30:56 +00:00
Michael Crosby 132db329d4 Merge pull request #2591 from dotcloud/fix_Assign_id_as_name_when_all_else_fails
Fix Assign id as name when all else fails
2013-11-07 12:29:02 -08:00
Guillaume J. Charmes 6998c3c387 go fmt 2013-11-07 12:27:33 -08:00
Victor Vieux 26f846bf77 fix Assign id as name when all else fails 2013-11-07 12:23:29 -08:00
Andy Rothfusz 97c3de7e6b Fix 2585 and clean up warning in contributing.rst 2013-11-07 12:20:23 -08:00
Michael Crosby b5c984f9b4 Merge pull request #2561 from dotcloud/add_iptabled_errors
Make iptable return an error in case of output
2013-11-07 09:15:09 -08:00
Daniel Mizyrycki 249f76bebd docker-ci 0.4.5: Sync tests with progress in docker and docker-registry. Use revamped shiny DinD. 2013-11-06 20:05:26 -08:00
Daniel Mizyrycki e7df38dbd0 docker-ci 0.40. Migrate docker-ci to Digital Ocean. 2013-11-06 19:13:58 -08:00
Daniel Mizyrycki efb4c800a7 docker-ci 0.37. Patch hack/dind with latest code for docker-test. 2013-11-06 19:13:58 -08:00
Daniel Mizyrycki 0cbeda7391 docker-ci 0.36. Patch hack/dind with latest code for nightly release to work. 2013-11-06 19:13:58 -08:00
Daniel Mizyrycki 1717227636 docker-ci 0.35. Push docker coverage and testing into docker-ci production. Update docker nightlyrelease 2013-11-06 19:13:58 -08:00
Daniel Mizyrycki 50dd9791f7 testing infrastructure, issue #1800: Refactor docker testing using Docker in Docker 2013-11-06 19:13:58 -08:00
Andy Rothfusz 9990db2f5a Fix bold 2013-11-06 18:07:55 -08:00
andy diller 2d1155407a updated create, showing how to set expose port and bind to public port for ssh 2013-11-06 18:07:55 -08:00
Andy Rothfusz 37dcff0c13 Merge pull request #2557 from jamtur01/new_redis
Updated Redis service example to use links. Removed "Linking Redis" example as redundant.
2013-11-06 17:54:34 -08:00
Andy Rothfusz 38f1838e82 Merge pull request #2567 from mck-/patch-1
Add -p when running the container (node example)
2013-11-06 17:34:11 -08:00
Andy Rothfusz 807a305f36 Merge pull request #1794 from justone/add-images-tree
add -tree option to images
2013-11-06 16:12:36 -08:00
Victor Vieux cb1c90975b Merge pull request #2577 from dotcloud/bump_v0.6.6
Bump v0.6.6
2013-11-06 13:41:52 -08:00
Nate Jones 363738b8f2 updating cli help doc for images 2013-11-06 12:03:45 -08:00
Alexander Larsson 157d99a727 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 rshared.

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-11-06 20:43:06 +01:00
Victor Vieux 360a694c52 Bump version to v0.6.6 2013-11-06 11:43:02 -08:00
Alexander Larsson c5bc7d5158 Utils: Add ShellQuoteArguments 2013-11-06 20:39:09 +01:00
Nate Jones 16eba6bbb5 fix /images/json doc for 1.7 2013-11-06 11:30:04 -08:00
Victor Vieux 0dd6c6645b Merge pull request #2568 from mrallen1/fix/1965
See if a path exists before injecting Reader there
2013-11-06 10:57:06 -08:00
Michael Crosby 70f44d5531 Update documentation to reflect changes in Config and HostConfig 2013-11-06 10:01:58 -08:00
Guillaume J. Charmes 45aba3dc95 Merge pull request #2334 from SvenDowideit/2149-small-cli-usability-change
change ID to CONTAINER ID/IMAGE ID
2013-11-06 09:45:23 -08:00
Guillaume J. Charmes c22ff0296e Merge pull request #1577 from mrallen1/fix/1502
Prevent DNS server conflicts in CreateBridgeIface
2013-11-06 07:52:50 -08:00
Guillaume J. Charmes 00f1398f7a Add debug to iptables 2013-11-06 07:37:43 -08:00
Mark Allen 74f853a2ae See if a path exists before injecting Reader there
Closes #1965
2013-11-05 23:44:52 -06:00
Daniel Norberg 20881f1f78 gograph: allow Walk() reentrance
Hold the read lock while reading the child graph,
then walk over the children without any lock, in
order to avoid deadlock.
2013-11-06 00:18:45 -05:00
Marc Kuo 3108f0526e Add -p when running the container
Without it, docker was not mapping/exposing the private port

Docker version 0.6.5, build 3ff8459
2013-11-05 20:48:16 -08:00
Nate Jones 22ef38ee79 fixup for rebase 2013-11-06 04:23:07 +00:00
Nate Jones 6d5b73c2a6 update "images" documentation 2013-11-06 04:23:07 +00:00
Nate Jones b7d1d35c27 add image size to -tree 2013-11-06 04:23:07 +00:00
Nate Jones f1aeac361a adding test for "images -tree" 2013-11-06 04:23:02 +00:00
Nate Jones d9fe0647cb adding test for "images -viz" 2013-11-06 04:04:24 +00:00
Nate Jones 059bb7a262 make existing tests pass 2013-11-06 03:58:16 +00:00
Nate Jones ec9a9a08b8 implement "images -tree" 2013-11-06 03:58:16 +00:00
Nate Jones 8f64759881 bring back /images/viz, but 404 for latest 2013-11-06 03:58:15 +00:00
Nate Jones 2a5998baf1 move "images -viz" to client 2013-11-06 03:58:15 +00:00
Nate Jones dcf0279a50 fix "images -a" 2013-11-06 03:58:15 +00:00
Nate Jones d7928b9a67 bump api version and ensure backward compat 2013-11-06 03:58:15 +00:00
Nate Jones 15867ff430 rework images JSON 2013-11-06 03:58:15 +00:00
Mark Allen 3560c922b1 Prevent DNS server conflicts in CreateBridgeIface
Retrieve /etc/resolv.conf data (if available)

Add checkNameserverOverlaps and call it to
make sure there are no conflicts

Add utils.GetNameserversAsCIDR and tests

Read /etc/resolv.conf and pull out nameservers,
formatting them as a CIDR block ("1.2.3.4/32")
2013-11-05 21:24:37 -06:00
Daniel Norberg 04aca7c9e3 gograph: Use RWMutex to allow concurrent readers 2013-11-05 22:07:14 -05:00
Guillaume J. Charmes 6113e1d62d Merge pull request #2566 from unclejack/fix_commands_test
fix build for commands_test
2013-11-05 15:45:22 -08:00
unclejack cdf0cf495d fix build for commands_test 2013-11-06 01:41:54 +02:00
Daniel Norberg 1dc34e2b96 lock around read operations in graph
Writes and reads will fail with ErrBusy if there's
concurrent reads or writes, respectively. It is
not sufficient to only lock around writes.
2013-11-05 18:26:07 -05:00
Solomon Hykes 4d90e91243 Merge branch 'finalize-interfaces' into 0.6.5-dm-plugin 2013-11-05 23:24:46 +00:00
Solomon Hykes 8d6df3a7e2 Remove debug messages 2013-11-05 23:00:20 +00:00
Solomon Hykes e5f8ab6160 Engine: 'create' creates a container and prints its ID on stdout 2013-11-05 23:00:20 +00:00
Solomon Hykes 5c42b2b512 Fix main() 2013-11-05 23:00:20 +00:00
Solomon Hykes d3f074494a Better error reporting in engine logs and unit tests 2013-11-05 23:00:20 +00:00
Solomon Hykes 434f06d03d Engine: fix a bug when encoding a job environment to json 2013-11-05 23:00:20 +00:00
Solomon Hykes 5a85456d48 Hack: simplify the creation of test directories 2013-11-05 23:00:16 +00:00
Andy Rothfusz 980eda4c25 Merge pull request #2562 from tchaudhri/patch-1
(doc) Update ubuntulinux.rst
2013-11-05 14:52:07 -08:00
Andy Rothfusz bf05eb8ac0 Merge pull request #2423 from rogaha/volumes_doc
Added volumes documentation
2013-11-05 14:38:28 -08:00
Tianon Gravi f3f9f652e1 Merge pull request #2563 from mzdaniel/desktop-integration
contrib: Desktop integration. Firefox usecase.
2013-11-05 14:02:13 -08:00
Victor Vieux 2205bb43ea Merge pull request #2298 from unclejack/2070-validate_src_for_bind_mounts
validate source for bind mounts
2013-11-05 13:31:10 -08:00
Daniel Mizyrycki 5af87d1475 contrib: Desktop integration. Firefox usecase. 2013-11-05 13:21:52 -08:00
unclejack 35430e8920 test: error out when bind mount source doesn't exist
This adds a test to verify that the server is checking whether the path
to be bind mounted actually exists on the server.
2013-11-05 22:54:24 +02:00
unclejack 4d2ba779e1 validate bind mounts on the server side
This changes the server side code to make sure that:
1) the source of a bind mount isn't /
   The bind mount "/:/foo" isn't allowed.
2) Check that the source exists
   The source to be bind mounted must exist.

This fixes issue #2070.
2013-11-05 22:54:24 +02:00
unclejack f1f39616eb add test to ensure / can't be bind mounted
This adds a test which checks that we're erroring out when we attempt
to bind mount root in a container.
2013-11-05 22:54:24 +02:00
unclejack 4b8c41c4a2 disallow / as source for bind mount in the cli
This makes the docker cli reject docker run commands which include bind
mounts like "/:/some/path/in/the/container".
Bind mounting the root directory is a bad idea and the cli should throw
an error right away.

The same check will also be made by the remote API via another commit.
2013-11-05 22:52:54 +02:00
James Turnbull e88368b34c Removed redundant linking example 2013-11-05 14:28:57 -06:00
Tehmasp Chaudhri 4d5ecdbeb4 (doc) Update ubuntulinux.rst
small grammar changes - hopefully not worse than original :)
2013-11-05 12:08:56 -07:00
Victor Vieux 114e01cdc1 Merge pull request #2554 from dotcloud/copy-config-on-build
Use parent image config in buildfile
2013-11-05 10:54:49 -08:00
Victor Vieux 7f7926525a Merge pull request #2517 from gurjeet/patch-2
Add gurjeet  as an author
2013-11-05 10:52:54 -08:00
Solomon Hykes 02ddaad5d9 Engine: optional environment variable 'Logging' in 'serveapi' 2013-11-05 18:39:59 +00:00
Solomon Hykes 4e7cb37dcc Engine: improved logging and identification of jobs 2013-11-05 18:39:59 +00:00
Solomon Hykes ca6f0aa107 Engine: don't export private testing utilities 2013-11-05 18:39:59 +00:00
Solomon Hykes 847411a1ee Engine: fix a bug which caused handlers to be shared between multiple engine instances 2013-11-05 18:39:59 +00:00
Solomon Hykes 7b17d55599 httpapi: don't create a pidfile if it isn't set in the configuration 2013-11-05 18:39:59 +00:00
Solomon Hykes 958b4a8757 Engine: 'start' starts the specified container 2013-11-05 18:39:59 +00:00
Andy Rothfusz 714acf5ade Merge pull request #2559 from pattichen/master
Fix typo
2013-11-05 10:30:15 -08:00
Andy Rothfusz 962a66cd36 Merge pull request #2460 from SvenDowideit/2294-use-repo-colon-tag-everywhere
covert docker (commit|import|tag) to use REPOSITORY[:TAG]
2013-11-05 10:29:54 -08:00
Daniel Garcia f9cb6ae46a Add ability to mount volumes in readonly mode using -volumes-from 2013-11-05 11:58:51 -06:00
Solomon Hykes 433c8e9c7d Separate a) initialization of the http api and b) actually serving the api into 2 distinct jobs 2013-11-05 17:41:37 +00:00
Solomon Hykes 140da580d4 Merge pull request #2 from tianon/dm-plugin-dockerfile
Hack: Add lvm2 static compilation to Dockerfile
2013-11-05 09:35:03 -08:00
Guillaume J. Charmes ff8a4ba0aa Check the output of iptables command. 2013-11-05 08:33:13 -08:00
Victor Vieux dcaaecc815 Merge pull request #2558 from tianon/go-bump
Bump Dockerfile to go1.2rc3
2013-11-04 23:39:10 -08:00
pattichen 2cac813937 Fix typo 2013-11-04 22:36:57 -08:00
Michael Crosby ed572b457d Finalize driver interfaces 2013-11-04 20:51:12 -08:00
Tianon Gravi fcc0ac6109 Bump Dockerfile to go1.2rc3 2013-11-04 21:12:18 -07:00
Victor Vieux c5d4459a02 Merge pull request #2502 from hamo/unlink_err_v4
rewrite protocol check with switch-case in Server.Daemon
2013-11-04 17:46:46 -08:00
James Turnbull 1182797c6d Updated Redis service example to use links 2013-11-04 19:18:37 -06:00
Victor Vieux a482bfd715 Merge pull request #2382 from dotcloud/reflect_future_changes_search_api
Update docker search to reflect future changes of the api
2013-11-04 16:14:14 -08:00
Solomon Hykes 66bf395e4d Merge branch 'dm-plugin-dockerfile' into 0.6.5-dm-plugin 2013-11-04 23:41:23 +00:00
Tianon Gravi 8ad46ef401 Merge pull request #2365 from tianon/sysvinit-consistency
Update sysvinit script to fix a few inconsistencies and be more useful/correct downstream
2013-11-04 15:34:51 -08:00
Victor Vieux 854cc5f559 remove column size hack 2013-11-04 15:34:51 -08:00
Solomon Hykes 5bad7d7229 Merge pull request #1 from crosbymichael/register-plugins
Add graph driver registration
2013-11-04 15:25:57 -08:00
Michael Crosby 752bfba2c5 Add graph driver registration 2013-11-04 15:22:34 -08:00
Tianon Gravi d11f75b505 Add libdevmapper static compilation to Dockerfile for device-mapper 2013-11-04 16:11:33 -07:00
Tianon Gravi 24dd838aee Update Dockerfile to consistently use tabs as the command argument separator 2013-11-04 15:39:16 -07:00
Michael Crosby 57cd17f656 Merge pull request #2499 from dotcloud/2414-logs_tty-fix
Fix logs with tty
2013-11-04 14:22:08 -08:00
Michael Crosby 99141ea3ca Use parent image config in buildfile 2013-11-04 13:20:14 -08:00
Roberto Gandolfo Hashioka 3061e9f374 - Removed some unconfirmed info
- Added reference to the index.rst
2013-11-04 13:16:51 -08:00
Andy Rothfusz 19ad299600 Merge pull request #2534 from jamtur01/examples_fixes
A variety of syntax and style fixes for the Docker examples
2013-11-04 12:35:57 -08:00
Victor Vieux 177a2f5946 add CmdLogs test 2013-11-04 12:23:35 -08:00
Victor Vieux 1f44fd8624 Fix logs with tty 2013-11-04 12:19:20 -08:00
Guillaume J. Charmes c065e564fb Merge pull request #2549 from dotcloud/ensure-container-name
Ensure container name on register
2013-11-04 12:12:42 -08:00
Guillaume J. Charmes 342bd43b76 Merge pull request #2525 from dotcloud/fix_hostnames
Fix regression in /etc/hosts
2013-11-04 11:26:27 -08:00
Guillaume J. Charmes b380866f44 Merge pull request #2551 from dotcloud/concurrent-db-access
Add lock around write operations in graph
2013-11-04 11:24:59 -08:00
Andy Rothfusz dc333878d2 Merge pull request #2533 from jamtur01/add_sudo
Some format and syntax changes.
2013-11-04 11:24:51 -08:00
Guillaume J. Charmes 261c2e23d3 Merge pull request #2501 from dotcloud/2480-check_port-fix
check port is valid
2013-11-04 11:23:55 -08:00
Michael Crosby 957db15ef4 Add lock around write operations in graph
The graph uses a persistent database connection so
a lock is required because our current sqlite3 driver
does not implement retry logic when the ErrBusy is received.
2013-11-04 10:28:38 -08:00
Michael Crosby a9ed238bb7 Ensure container name on register 2013-11-04 09:28:40 -08:00
Solomon Hykes 98c3693acf Integrate devmapper and aufs into the common "graphdriver" framework.
aufs is still enabled by default, no mechanism for switching drivers
yet.
2013-11-04 17:28:35 +00:00
Solomon Hykes 6c77f2c189 devmapper: rename plugin*.go to driver*.go 2013-11-04 17:23:46 +00:00
Solomon Hykes b77c5c5984 devmapper: renamed DMBackend to Driver 2013-11-04 17:22:43 +00:00
Michael Crosby 35690e76b4 Merge pull request #2409 from pnasrat/2089-fix-restart-runtime-error
Fix restart runtime error with ghost container networking
2013-11-04 08:55:11 -08:00
Michael Crosby 2a0efb2324 Merge pull request #2427 from thequux/send-headers-immediately
Make /events API send headers immediately
2013-11-04 08:49:27 -08:00
Michael Crosby a4ccbc6e95 Merge pull request #2542 from oguzbilgic/changelog-0.6.5
Remove duplicate titles in changelog entries of v0.6.5
2013-11-04 08:25:22 -08:00
Michael Crosby 2824b05235 Merge pull request #2537 from jamtur01/more_names
Added some more colors and animals to increase the pool
2013-11-04 08:23:23 -08:00
Michael Crosby 3cd4232e52 Merge pull request #2541 from shykes/graph-backend-rename
Rename graph backends to 'drivers' which is probably more self-explanatory
2013-11-04 08:22:07 -08:00
Oguz Bilgic fbfb7595b1 Remove duplicate titles in changelog entries of v0.6.5 2013-11-04 08:20:05 -05:00
Sven Dowideit b840b73b08 tiny table heading tweak for #2149 - change ID to CONTAINER ID/IMAGE ID or IMAGE (the later if it could be an ID or a repo:tag 2013-11-04 22:10:51 +10:00
Sven Dowideit 1f3cdc11ee conert docker (commit|import|tag) to use REPOSITORY[:TAG] (and repove support for REPOSITORY TAG) 2013-11-04 22:07:55 +10:00
Solomon Hykes ff42748bc5 Rename graph backends to 'drivers' which is probably more self-explanatory 2013-11-04 01:54:51 +00:00
Paul Nasrat 95708dd35c Create new network on dead ghosts on restart.
Fixes #2089
2013-11-03 14:13:18 -05:00
James Turnbull a51fb4dd35 Added some more colors and animals to increase the pool 2013-11-03 11:49:29 -06:00
Paul Nasrat 4cbb6ce13b Introduce failing test case for #2089 2013-11-03 11:14:59 -05:00
James Turnbull 1cb4557cc8 A variety of syntax and style fixes for the Docker examples
* Made Docker a proper noun when needed.
* Fixed code syntax
* Fixed some whitespace issues
* Fixed some typos and grammar
* Tidied up some examples
2013-11-02 18:26:52 -07:00
James Turnbull c33d26a8da Some format and syntax changes.
* Added sudo as per convention to docker commands
* Break the Dockerfile block up
* Redis is a proper noun
* Minor whitespace fixes
2013-11-02 17:53:44 -07:00
Solomon Hykes d23b9e8734 devmapper: implement OnRemove 2013-11-02 21:25:06 +00:00
Andy Rothfusz 5a9adfe9fb Add known issues. Fix build warnings. 2013-11-01 16:06:46 -07:00
Victor Vieux f3685333c0 fix regression in /etc/hosts 2013-11-01 15:46:26 -07:00
Victor Vieux fc45535197 Merge pull request #2503 from dotcloud/2500-inspect-fix
Client: Inspect fix
2013-11-01 15:24:05 -07:00
Victor Vieux 8f27e23b4b Merge pull request #2457 from dotcloud/2454_do_not_split_last_column
RemoteAPI: Do not split last column docker top
2013-11-01 15:21:47 -07:00
Andy Rothfusz 4194617bfe Add known issues to sections via new "issues" extension. 2013-11-01 15:15:06 -07:00
Victor Vieux d8bcd1c231 Merge pull request #2497 from dotcloud/jpetazzo-escape-apparmor-confinement
Runtime: escape apparmor confinement
2013-11-01 15:07:54 -07:00
Andy Rothfusz f6b4a1ec95 Merge pull request #2521 from jamtur01/porttypo
Fixed 127.0.0.0 typo in cli.rst
2013-11-01 14:08:27 -07:00
Victor Vieux 7ddd4fe66a rebase 2013-11-01 14:01:32 -07:00
James Turnbull dcf4633e95 Fixed 127.0.0.0 typo in cli.rst 2013-11-01 14:00:02 -07:00
Andy Rothfusz b30dc8c3ea Merge pull request #2510 from GrilloPress/patch-1
Update windows.rst
2013-11-01 13:56:23 -07:00
Andy Rothfusz feef16bd88 Merge pull request #2512 from dudebout/correct-basics-doc
Corrects the TCP section of the basics use
2013-11-01 13:55:28 -07:00
Victor Vieux f9901ead06 use a symlink instead of a copy 2013-11-01 13:55:19 -07:00
Jérôme Petazzoni 31638ab2ad Refactor HostConfig and escape apparmor confinement 2013-11-01 13:55:19 -07:00
Andy Rothfusz 33d8c736fc Merge pull request #2479 from dudebout/port-redirection-doc
Port redirection doc
2013-11-01 13:43:53 -07:00
Solomon Hykes d2c2c2c116 devmapper: rename Create() to OnCreate(), cleanup tests 2013-11-01 19:30:30 +00:00
Solomon Hykes d64df7c765 Work In Progress: fix devmapper plugin, first independent test passes. 2013-11-01 19:04:08 +00:00
Gurjeet Singh 9ebac49be0 Add myself as an author 7e09c633
One of my patches was incorporated into Docker, and at that time I didn't know that I was supposed to add myself into this list of contributors.

Commit ID: 7e09c6332d

And a few other patches are already in the pipeline.
2013-11-01 12:31:50 -05:00
Michael Crosby 65ba2868d7 Merge pull request #2492 from dotcloud/publish-all-flag
Add -P flag to publish all exposed ports
2013-11-01 10:21:02 -07:00
Dan Hirsch a963ff5d8d Added explicit Flush method to utils.WriteFlusher 2013-11-01 13:11:21 -04:00
Nicolas Dudebout c0e51a8f27 Rework the port direction documentation
+ remove PUBLIC and PRIVATE keywords
+ add the <host_interface>
+ add the -expose flag through a simple link example
+ update the meaning of the EXPOSE command
2013-11-01 12:18:04 -04:00
Nicolas Dudebout f2ebccb5aa Corrects the TCP section of the basics use 2013-11-01 12:14:43 -04:00
Andrew Duckworth db2e2e831b Update windows.rst
Added further information regarding how to access BIOS menus on Windows machines (laptops). My laptop required restarting to find the options and this information will undoubtedly help other users.
2013-11-01 13:59:25 +00:00
Aanand Prasad 9ee9d2f995 Container memory limit can be specified in kilobytes, megabytes or gigabytes
-m 10  # 10 bytes
    -m 10b # 10 bytes
    -m 10k # 10240 bytes (10 * 1024)
    -m 10m # 10485760 bytes (10 * 1024 * 1024)
    -m 10g # 10737418240 bytes (10 * 1024 * 1024 * 1024)

Units are case-insensitive, and 'kb', 'mb' and 'gb' are equivalent to 'k', 'm' and 'g'.
2013-11-01 12:00:17 +00:00
Solomon Hykes 86dd2473c1 Work In Progress: devmapper backend plugin 2013-11-01 05:06:49 +00:00
Solomon Hykes 318dd33fb7 archive.ApplyLayer(): parse a tar archive as a standard aufs-compatible diff, and apply it on a directory 2013-11-01 05:06:35 +00:00
Solomon Hykes a5031d47d9 Re-incorporate ChangesDirs() for the use of the devmapper backend,
without changing existing prototypes.

This is a neutral change. The primary aufs backend is still in place
and not affected.
2013-11-01 04:52:39 +00:00
Solomon Hykes 36c7a7ae94 Partial merge of devmapper/ in order to integrate it as a backend
plugin.

The merge is inert, in other words the devmapper code is not called
and the primary aufs backend is untouched.
2013-11-01 04:24:17 +00:00
Solomon Hykes 4dc156252b Merge pull request #2498 from dotcloud/move-archive
Move archive.go to sub package
2013-10-31 20:33:53 -07:00
Victor Vieux 747967b4a4 rebase and add some filters 2013-10-31 19:25:55 -07:00
Victor Vieux 02b5202432 update docker search to reflect future changes of the api 2013-10-31 19:14:11 -07:00
Victor Vieux 7f07ae9e42 check port is valid 2013-10-31 19:00:14 -07:00
Victor Vieux a89a98e594 fix inspect error message 2013-10-31 18:50:58 -07:00
Yang Bai 7848007c3a rewrite protocol check with switch-case in Server.Daemon 2013-11-01 09:42:44 +08:00
Victor Vieux 40ed10cc32 fix inspect when it returns nothing valid 2013-10-31 18:39:44 -07:00
Michael Crosby 699a1074fb Initial work on moving aufs to a subpackage 2013-10-31 18:07:54 -07:00
Michael Crosby 96d1e9bb5a Move archive.go to sub package 2013-10-31 16:57:45 -07:00
Victor Vieux e3c49843d7 Merge pull request #2494 from shykes/engine-links
Engine: Minimal, unintrusive implementation of a cleaner Job API.
2013-10-31 16:32:49 -07:00
Tianon Gravi 3e7b9763aa Merge pull request #2496 from philips/patch-1
Update systemd service file with a better description
2013-10-31 14:55:30 -07:00
Brandon Philips 393562340c fix(systemd): provide a better description
Fix-up the docker service file description to declare what the service is not what it does.

When a systemd machine starts up the Description of each unit scrolls by instead of the service's filename. Because the current description doesn't say what it is it isn't very friendly:

```
Oct 31 20:40:49 localhost systemd[1]: Started Update Engine.
Oct 31 20:40:49 localhost systemd[1]: Starting Multi-User System.
Oct 31 20:40:49 localhost systemd[1]: Reached target Multi-User System.
Oct 31 20:40:49 localhost systemd[1]: Starting Easily create lightweight, portable, self-sufficient containers from any application!...
Oct 31 20:40:49 localhost systemd[1]: Started Easily create lightweight, portable, self-sufficient containers from any application!.
```
2013-10-31 14:41:49 -07:00
Andy Rothfusz d5891f9fb0 Merge pull request #2482 from elee/patch-1
correct assignment of $PORT from docker port output
2013-10-31 12:18:24 -07:00
Andy Rothfusz 09607bb8f6 Merge pull request #2475 from dudebout/patch-2
Fixes the password value in the redis/links example
2013-10-31 12:17:43 -07:00
Andy Rothfusz 35044efce5 Merge pull request #2477 from dudebout/patch-3
Fixes typo in the CLI documentation
2013-10-31 12:17:06 -07:00
Michael Crosby 652f07bb59 Add -P flag to publish all exposed ports 2013-10-31 11:28:30 -07:00
Andy Rothfusz 54024ddd8a Merge pull request #2462 from tlunter/fix_remote_api_doc
Fix formatting on build-an-image-from-dockerfile-via-stdin
2013-10-31 10:56:38 -07:00
Zilin Du b543516556 Merge remote-tracking branch 'upstream/master'
Conflicts:
	container.go
2013-10-31 10:53:40 -07:00
Michael Crosby e37a7d4981 Merge pull request #2305 from mzdaniel/1800-testing-dind
Testing infrastructure, issue #1800: Refactor docker testing using Docker in Docker
2013-10-31 09:42:19 -07:00
Nicolas Dudebout 7e7c931d2b Fixes another instant of the password 2013-10-31 08:55:14 -04:00
Todd Lunter 3a14d4c923 Fixed the quoted text 2013-10-31 08:46:16 -04:00
Victor Vieux 15457febbb Merge pull request #2481 from tmc/patch-1
Fix typo in redis doc
2013-10-31 01:24:04 -07:00
Eric Lee df1621914b correct assignment of $PORT from docker port output
in the example, PORT is assigned to "0.0.0.0:<port>" vs "<port>" as in previous versions of docker (I encountered this documentation discrepancy tonight after installing docker v0.6.5)
2013-10-31 01:08:16 -04:00
Travis Cline f77bbfca56 Fix typo 2013-10-31 00:07:58 -05:00
Nicolas Dudebout 87a250b711 Fixes typo in the CLI documentation 2013-10-30 23:09:02 -04:00
Nicolas Dudebout ccc1a5dcfb Fixes the password value in the redis/links example 2013-10-30 22:52:47 -04:00
Victor Vieux ca2bbe716c add 0.6.5 2013-10-30 19:30:32 -07:00
Oguz Bilgic 13ab83a8a5 Reformat CHANGELOG.md
* Add line after headers
* Remove space before bullet points
* Fix ' character
* Create sub-headers
* Group add fix etc. Upper-case
* Use head to trac current progress
2013-10-30 19:30:32 -07:00
Victor Vieux 429c3108da Merge pull request #2473 from dotcloud/remove-panic-from-name
Assign id as name when all else fails
2013-10-30 19:22:57 -07:00
Victor Vieux bdbb0371a7 Merge pull request #1536 from griff/envfile
Runtime: Keep env variables out of the command line
2013-10-30 19:20:29 -07:00
Victor Vieux c1c65f972a Merge pull request #2470 from metalivedev/2369-docuncompress
Documenting decompression behavior.
2013-10-30 19:14:51 -07:00
Victor Vieux 4b8a176ee0 Merge pull request #2432 from SvenDowideit/doc-stop-kill-details
IRC: add SIGTERM and SIGKILL details to docker stop and kill docco
2013-10-30 18:57:07 -07:00
Victor Vieux 4dfa28fb95 Merge pull request #2299 from tmc/master
Client: Add -notrunc and -q flags to docker history
RemoteAPI: Add size to history
2013-10-30 18:52:18 -07:00
Michael Crosby 8227ea35cf Assign id as name when all else fails 2013-10-30 18:31:18 -07:00
Travis Cline 1099d172a2 Add flags to history, add size flag 2013-10-30 19:41:20 -05:00
Brian Olsen 1c3a674444 Fixed problem with variables containing \n.
The /.dockerenv file is now a marshalled json array so that environment
variables with \n and other weird values are supported.
2013-10-31 01:19:32 +01:00
Brian Olsen 25c4c87c86 Support copying value from env with -e option. 2013-10-31 01:19:09 +01:00
Andy Rothfusz 26f4d6bf59 Fix #2369 by documenting decompression behavior. 2013-10-30 16:50:58 -07:00
Brian Olsen be7eb4bfcb Set environment variables using a file. 2013-10-31 00:48:12 +01:00
Michael Crosby 5eb472025a Merge pull request #2456 from dotcloud/update_release_checklist.md
Update RELEASE-CHECKLIST.md to reflect new changes
2013-10-30 16:38:09 -07:00
Andy Rothfusz bdd12bb703 Merge pull request #2274 from peterbraden/2137-docs
Re #2137 Note about vagrant dns in the test documentation
2013-10-30 16:32:35 -07:00
Michael Crosby ef00317a70 Merge branch 'release' back to master 2013-10-30 16:09:02 -07:00
Michael Crosby d7fac67e0a Merge pull request #2469 from dotcloud/hotfix_release2
Hotfix changes for default values in 0.6.5
2013-10-30 15:04:38 -07:00
Victor Vieux f7c40a87f3 set containers comm to true by default 2013-10-30 14:48:19 -07:00
Victor Vieux ee81405567 fix warning in build 2013-10-30 14:36:38 -07:00
Michael Crosby 23b3747945 Merge pull request #2467 from dotcloud/release_hotfix
0.6.5 hotfixes
2013-10-30 13:21:20 -07:00
Victor Vieux 1c7ca51f32 fix typos 2013-10-30 13:18:48 -07:00
Michael Crosby a4d97a4e80 Update links and host integration documentation 2013-10-30 11:59:05 -07:00
Victor Vieux 3362aaa4df fix remove root name and fix error messages 2013-10-30 11:45:11 -07:00
Victor Vieux 8fa6e2b103 improve error message 2013-10-30 11:24:50 -07:00
Victor Vieux b2503a72f1 continue build on expose with :, but displays a warning 2013-10-30 11:13:10 -07:00
Michael Crosby bb662bc12c Merge pull request #2466 from dotcloud/hot-fix-restart-public-mappings
Hotfix: Migrate public mappings after upgrade
2013-10-30 09:35:56 -07:00
Michael Crosby 746ba127bf Hotfix: Migrate public mappings after upgrade 2013-10-30 08:15:12 -07:00
Todd Lunter e7402ed9cc Fix formatted on build 2013-10-30 08:50:21 -04:00
Victor Vieux fb4672c52c do not split last column docker top 2013-10-29 19:03:41 -07:00
Victor Vieux 9420e8def7 update RELEASE-CHECKLIST.md to reflect new changes 2013-10-29 15:34:33 -07:00
Victor Vieux 2a9c18af52 Merge pull request #2453 from dotcloud/remove_logs_from_tests
Testing: remove some logs from tests
2013-10-29 14:43:37 -07:00
Victor Vieux 86970d00bb remove some logs from tests 2013-10-29 14:42:34 -07:00
Sven Dowideit 82f1514895 docker stop sends SIGTERM and SIGKILL, docker kill sends SIGKILL 2013-10-29 13:37:43 +10:00
Dan Hirsch dd9f4524d1 Make /events API send headers immediately
Go's net/http API does not send headers until the first call to
ResponseWriter.Write().  Ordinarily, this is fine, because in most
cases, responses are returned immediately.  However, for the events
API, nothing is written until some event is sent, which causes
timeouts and/or hangs in some HTTP client APIs, which wait for headers
before returning from the "make request" call.
2013-10-28 21:39:21 -04:00
rogaha 91d721aaf4 - Added volumes documentation 2013-10-28 17:24:03 -07:00
Tianon Gravi 865649d7ac Update sysvinit script to fix a few inconsistencies and be more useful/correct downstream 2013-10-28 14:08:21 -06:00
Solomon Hykes a13241d370 Engine: Engine.Job() never fails, to mimic the os/exec API (and make usage less verbose) 2013-10-26 17:49:16 -07:00
Solomon Hykes e8491ae54c Engine: cleanly log the start and end of each engine job 2013-10-26 17:17:45 -07:00
Solomon Hykes 464ded79fc Close sqlite persistent connection on SIGINT, SITERM or SIGKILL 2013-10-26 14:28:53 -07:00
Solomon Hykes c1ae1a0e1c Setup daemon pidfile/cleanup in Server.Daemon() instead of main() 2013-10-26 14:26:07 -07:00
Solomon Hykes c542b2f873 Rename ConfigGetenv to ConfigFromJob 2013-10-26 14:24:25 -07:00
Solomon Hykes 7e691e11b0 Rename 'GraphPath' to the more logical 'Root'. This does not affect users except for a slight text change in the usage messge 2013-10-26 14:24:13 -07:00
Solomon Hykes 1b8eef4efb Engine: centralize checks for supported architectures and kernel versions 2013-10-26 14:21:04 -07:00
Solomon Hykes 2a29bf6245 Engine: basic testing harness 2013-10-26 14:18:28 -07:00
Solomon Hykes 0d1a825137 Minimal, unintrusive implementation of a cleaner Job API.
* Implement a new package: engine. It exposes a useful but minimalist job API.
* Refactor main() to instanciate an Engine instead of a Server directly.
* Refactor server.go to register an engine job.

This is the smallest possible refactor which can include the new Engine design
into master. More gradual refactoring will follow.
2013-10-26 14:18:13 -07:00
Solomon Hykes 60b97576cf Fix build on darwin 2013-10-26 14:14:50 -07:00
Mathieu Le Marec - Pasquet b64ce8e33c Do not drop sys_boot
This fixes #2391
2013-10-25 18:41:03 +02:00
Victor Vieux 1fe08e0046 Merge pull request #2330 from alexlarsson/dm-fix-change-detection
Fix typo that made change detection break
2013-10-22 10:20:53 -07:00
Alexander Larsson bc1c5ddf2e Fix typo that made change detection break
We were comparing the old and old mtimes rather than the old and
the new. This meant we missed some file changes where only the mtime
changed.
2013-10-22 11:13:24 +02:00
Daniel Mizyrycki 95f3f77fc4 testing infrastructure, issue #1800: Refactor docker testing using Docker in Docker 2013-10-18 22:33:16 -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
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 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
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
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 d034aafac7 devicemapper: Add fixme 2013-10-18 00:58:20 +00: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
Guillaume J. Charmes 31b883b076 Add error checking and error messages 2013-10-17 15:04:14 -07:00
Peter Braden 3db381bf08 Re #2137 Note about vagrant dns in the test documentation 2013-10-17 13:38:39 -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
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
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
Solomon Hykes 1711de4b09 devmapper: wait for devices to be effectively unmounted before removing them 2013-10-16 23:06:07 +00: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
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
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 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 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
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
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
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
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
Solomon Hykes 1804fcba93 Merged master into device-mapper branch 2013-10-10 12:50:30 -07:00
Zilin Du c2912c82aa change 127.0.0.1 -> 127.0.1.1 & remove ::1 -> hostname mapping 2013-10-10 09:44:48 -07:00
Zilin Du 7d95d300ab replace 127.0.0.1 by the assigned IP address in the container's /etc/hosts file. 2013-10-08 14:29:22 -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
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
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
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
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
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
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
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
178 changed files with 16483 additions and 5059 deletions
+1
View File
@@ -18,3 +18,4 @@ bundles/
.hg/
.git/
vendor/pkg/
pyenv
+7
View File
@@ -44,6 +44,7 @@ Daniel Nordberg <dnordberg@gmail.com>
Daniel Robinson <gottagetmac@gmail.com>
Daniel Von Fange <daniel@leancoder.com>
Daniel YC Lin <dlin.tw@gmail.com>
Darren Coxall <darren@darrencoxall.com>
David Calavera <david.calavera@gmail.com>
David Sissitka <me@dsissitka.com>
Deni Bertovic <deni@kset.org>
@@ -69,12 +70,14 @@ Gabriel Monroy <gabriel@opdemand.com>
Gareth Rushgrove <gareth@morethanseven.net>
Greg Thornton <xdissent@me.com>
Guillaume J. Charmes <guillaume.charmes@dotcloud.com>
Gurjeet Singh <gurjeet@singh.im>
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>
James Turnbull <james@lovedthanlost.net>
Jason McVetta <jason.mcvetta@gmail.com>
Jean-Baptiste Barth <jeanbaptiste.barth@gmail.com>
Jeff Lindsay <progrium@gmail.com>
@@ -92,6 +95,7 @@ Jonathan Rudenberg <jonathan@titanous.com>
Joost Cassee <joost@cassee.net>
Jordan Arentsen <blissdev@gmail.com>
Joseph Anthony Pasquale Holsten <joseph@josephholsten.com>
Josh Poimboeuf <jpoimboe@redhat.com>
Julien Barbier <write0@gmail.com>
Jérôme Petazzoni <jerome.petazzoni@dotcloud.com>
Karan Lyons <karan@karanlyons.com>
@@ -117,6 +121,7 @@ Marko Mikulicic <mmikulicic@gmail.com>
Markus Fix <lispmeister@gmail.com>
Martin Redmond <martin@tinychat.com>
Matt Apperson <me@mattapperson.com>
Mathieu Le Marec - Pasquet <kiorky@cryptelium.net>
Matt Bachmann <bachmann.matt@gmail.com>
Matthew Mueller <mattmuelle@gmail.com>
Maxim Treskin <zerthurd@gmail.com>
@@ -140,6 +145,7 @@ odk- <github@odkurzacz.org>
Pascal Borreli <pascal@borreli.com>
Paul Bowsher <pbowsher@globalpersonals.co.uk>
Paul Hammond <paul@paulhammond.org>
Paul Nasrat <pnasrat@gmail.com>
Phil Spitler <pspitler@gmail.com>
Piotr Bogdan <ppbogdan@gmail.com>
pysqz <randomq@126.com>
@@ -162,6 +168,7 @@ Sridatta Thatipamala <sthatipamala@gmail.com>
Sridhar Ratnakumar <sridharr@activestate.com>
Steeve Morin <steeve.morin@gmail.com>
Stefan Praszalowicz <stefan@greplin.com>
Sven Dowideit <SvenDowideit@home.org.au>
Thatcher Peskens <thatcher@dotcloud.com>
Thermionix <bond711@gmail.com>
Thijs Terlouw <thijsterlouw@gmail.com>
+692 -424
View File
File diff suppressed because it is too large Load Diff
+6 -3
View File
@@ -1,11 +1,14 @@
# Contributing to Docker
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.
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/).
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
+23 -15
View File
@@ -4,26 +4,26 @@
#
# # Assemble the full dev environment. This is slow the first time.
# docker build -t docker .
# # Apparmor messes with privileged mode: disable it
# /etc/init.d/apparmor stop ; /etc/init.d/apparmor teardown
#
# # Mount your source in an interactive container for quick testing:
# docker run -v `pwd`:/go/src/github.com/dotcloud/docker -privileged -lxc-conf=lxc.aa_profile=unconfined -i -t docker bash
#
# docker run -v `pwd`:/go/src/github.com/dotcloud/docker -privileged -i -t docker bash
#
# # Run the test suite:
# docker run -privileged -lxc-conf=lxc.aa_profile=unconfined docker hack/make.sh test
# docker run -privileged docker hack/make.sh test
#
# # Publish a release:
# docker run -privileged -lxc-conf=lxc.aa_profile=unconfined \
# docker run -privileged \
# -e AWS_S3_BUCKET=baz \
# -e AWS_ACCESS_KEY=foo \
# -e AWS_SECRET_KEY=bar \
# -e GPG_PASSPHRASE=gloubiboulga \
# docker hack/release.sh
#
# Note: Apparmor used to mess with privileged mode, but this is no longer
# the case. Therefore, you don't have to disable it anymore.
#
docker-version 0.6.1
docker-version 0.6.1
from ubuntu:12.04
maintainer Solomon Hykes <solomon@dotcloud.com>
@@ -33,23 +33,22 @@ 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 libsqlite3-dev
run apt-get install -y -q build-essential libsqlite3-dev
# Install Go
run curl -s https://go.googlecode.com/files/go1.2rc2.src.tar.gz | tar -v -C /usr/local -xz
run curl -s https://go.googlecode.com/files/go1.2rc5.src.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
run cd /usr/local/go/src && ./make.bash && go install -ldflags '-w -linkmode external -extldflags "-static -Wl,--unresolved-symbols=ignore-in-shared-libs"' -tags netgo -a std
run cd /usr/local/go/src && ./make.bash && go install -ldflags '-w -linkmode external -extldflags "-static -Wl,--unresolved-symbols=ignore-in-shared-libs"' -tags netgo -a std
# Ubuntu stuff
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 pip install s3cmd==1.1.0-beta3
run pip install python-magic==0.4.6
run /bin/echo -e '[default]\naccess_key=$AWS_ACCESS_KEY\nsecret_key=$AWS_SECRET_KEY\n' > /.s3cfg
# Runtime dependencies
@@ -57,11 +56,20 @@ run apt-get install -y -q iptables
run apt-get install -y -q lxc
run apt-get install -y -q aufs-tools
# Get lvm2 source for compiling statically
run git clone git://git.fedorahosted.org/git/lvm2.git /usr/local/lvm2 && cd /usr/local/lvm2 && git checkout v2_02_103
# see https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags
# note: we can't use "git clone -b" above because it requires at least git 1.7.10 to be able to use that on a tag instead of a branch and we only have 1.7.9.5
# Compile and install lvm2
run cd /usr/local/lvm2 && ./configure --enable-static_link && make device-mapper && make install_device-mapper
# see https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
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"]
entrypoint ["hack/dind"]
# Upload docker source
add . /go/src/github.com/dotcloud/docker
add . /go/src/github.com/dotcloud/docker
+6 -29
View File
@@ -8,35 +8,12 @@ by Keith Rarick, licensed under the MIT License.
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:
Use and transfer of Docker may be subject to certain restrictions by the
United States and other governments.
It is your responsibility to ensure that your use and/or transfer does not
violate applicable laws.
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.
For more information, please see http://www.bis.doc.gov
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.
See also http://www.apache.org/dev/crypto.html and/or seek legal counsel.
+4 -5
View File
@@ -193,10 +193,9 @@ wrong or incomplete.
*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. Without limiting the
foregoing, Docker shall not be distributed or downloaded to any individual or
location if such distribution or download would violate the applicable US
government export regulations.
Use and transfer of Docker may be subject to certain restrictions by the
United States and other governments.
It is your responsibility to ensure that your use and/or transfer does not
violate applicable laws.
For more information, please see http://www.bis.doc.gov
+1 -1
View File
@@ -1 +1 @@
0.6.5
0.7.0-rc7
Vendored
+119 -44
View File
@@ -4,65 +4,135 @@
BOX_NAME = ENV['BOX_NAME'] || "ubuntu"
BOX_URI = ENV['BOX_URI'] || "http://files.vagrantup.com/precise64.box"
VF_BOX_URI = ENV['BOX_URI'] || "http://files.vagrantup.com/precise64_vmware_fusion.box"
AWS_BOX_URI = ENV['BOX_URI'] || "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box"
AWS_REGION = ENV['AWS_REGION'] || "us-east-1"
AWS_AMI = ENV['AWS_AMI'] || "ami-d0f89fb9"
AWS_AMI = ENV['AWS_AMI'] || "ami-69f5a900"
AWS_INSTANCE_TYPE = ENV['AWS_INSTANCE_TYPE'] || 't1.micro'
FORWARD_DOCKER_PORTS = ENV['FORWARD_DOCKER_PORTS']
SSH_PRIVKEY_PATH = ENV["SSH_PRIVKEY_PATH"]
# A script to upgrade from the 12.04 kernel to the raring backport kernel (3.8)
# and install docker.
$script = <<SCRIPT
# The username to add to the docker group will be passed as the first argument
# to the script. If nothing is passed, default to "vagrant".
user="$1"
if [ -z "$user" ]; then
user=vagrant
fi
# Adding an apt gpg key is idempotent.
wget -q -O - https://get.docker.io/gpg | apt-key add -
# Creating the docker.list file is idempotent, but it may overrite desired
# settings if it already exists. This could be solved with md5sum but it
# doesn't seem worth it.
echo 'deb http://get.docker.io/ubuntu docker main' > \
/etc/apt/sources.list.d/docker.list
# Update remote package metadata. 'apt-get update' is idempotent.
apt-get update -q
# Install docker. 'apt-get install' is idempotent.
apt-get install -q -y lxc-docker
usermod -a -G docker "$user"
tmp=`mktemp -q` && {
# Only install the backport kernel, don't bother upgrade if the backport is
# already installed. We want parse the output of apt so we need to save it
# with 'tee'. NOTE: The installation of the kernel will trigger dkms to
# install vboxguest if needed.
apt-get install -q -y --no-upgrade linux-image-generic-lts-raring | \
tee "$tmp"
# Parse the number of installed packages from the output
NUM_INST=`awk '$2 == "upgraded," && $4 == "newly" { print $3 }' "$tmp"`
rm "$tmp"
}
# If the number of installed packages is greater than 0, we want to reboot (the
# backport kernel was installed but is not running).
if [ "$NUM_INST" -gt 0 ];
then
echo "Rebooting down to activate new kernel."
echo "/vagrant will not be mounted. Use 'vagrant halt' followed by"
echo "'vagrant up' to ensure /vagrant is mounted."
shutdown -r now
fi
SCRIPT
# We need to install the virtualbox guest additions *before* we do the normal
# docker installation. As such this script is prepended to the common docker
# install script above. This allows the install of the backport kernel to
# trigger dkms to build the virtualbox guest module install.
$vbox_script = <<VBOX_SCRIPT + $script
# Install the VirtualBox guest additions if they aren't already installed.
if [ ! -d /opt/VBoxGuestAdditions-4.3.2/ ]; then
# Update remote package metadata. 'apt-get update' is idempotent.
apt-get update -q
# Kernel Headers and dkms are required to build the vbox guest kernel
# modules.
apt-get install -q -y linux-headers-generic-lts-raring dkms
echo 'Downloading VBox Guest Additions...'
wget -cq http://dlc.sun.com.edgesuite.net/virtualbox/4.3.2/VBoxGuestAdditions_4.3.2.iso
mount -o loop,ro /home/vagrant/VBoxGuestAdditions_4.3.2.iso /mnt
/mnt/VBoxLinuxAdditions.run --nox11
umount /mnt
fi
VBOX_SCRIPT
Vagrant::Config.run do |config|
# Setup virtual machine box. This VM configuration code is always executed.
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?
# Add lxc-docker package
pkg_cmd = "wget -q -O - https://get.docker.io/gpg | apt-key add -;" \
"echo deb http://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list;" \
"apt-get update -qq; apt-get install -q -y --force-yes lxc-docker; "
# Add Ubuntu raring backported kernel
pkg_cmd << "apt-get update -qq; apt-get install -q -y linux-image-generic-lts-raring; "
# Add guest additions if local vbox VM. As virtualbox is the default provider,
# it is assumed it won't be explicitly stated.
if ENV["VAGRANT_DEFAULT_PROVIDER"].nil? && ARGV.none? { |arg| arg.downcase.start_with?("--provider") }
pkg_cmd << "apt-get install -q -y linux-headers-generic-lts-raring dkms; " \
"echo 'Downloading VBox Guest Additions...'; " \
"wget -q http://dlc.sun.com.edgesuite.net/virtualbox/4.2.12/VBoxGuestAdditions_4.2.12.iso; "
# Prepare the VM to add guest additions after reboot
pkg_cmd << "echo -e 'mount -o loop,ro /home/vagrant/VBoxGuestAdditions_4.2.12.iso /mnt\n" \
"echo yes | /mnt/VBoxLinuxAdditions.run\numount /mnt\n" \
"rm /root/guest_additions.sh; ' > /root/guest_additions.sh; " \
"chmod 700 /root/guest_additions.sh; " \
"sed -i -E 's#^exit 0#[ -x /root/guest_additions.sh ] \\&\\& /root/guest_additions.sh#' /etc/rc.local; " \
"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
# Use the specified private key path if it is specified and not empty.
if SSH_PRIVKEY_PATH
config.ssh.private_key_path = SSH_PRIVKEY_PATH
end
config.ssh.forward_agent = true
end
# Providers were added on Vagrant >= 1.1.0
#
# NOTE: The vagrant "vm.provision" appends its arguments to a list and executes
# them in order. If you invoke "vm.provision :shell, :inline => $script"
# twice then vagrant will run the script two times. Unfortunately when you use
# providers and the override argument to set up provisioners (like the vbox
# guest extensions) they 1) don't replace the other provisioners (they append
# to the end of the list) and 2) you can't control the order the provisioners
# are executed (you can only append to the list). If you want the virtualbox
# only script to run before the other script, you have to jump through a lot of
# hoops.
#
# Here is my only repeatable solution: make one script that is common ($script)
# and another script that is the virtual box guest *prepended* to the common
# script. Only ever use "vm.provision" *one time* per provider. That means
# every single provider has an override, and every single one configures
# "vm.provision". Much saddness, but such is life.
Vagrant::VERSION >= "1.1.0" and Vagrant.configure("2") do |config|
config.vm.provider :aws do |aws, override|
aws.access_key_id = ENV["AWS_ACCESS_KEY_ID"]
aws.secret_access_key = ENV["AWS_SECRET_ACCESS_KEY"]
username = "ubuntu"
override.vm.box_url = AWS_BOX_URI
override.vm.provision :shell, :inline => $script, :args => username
aws.access_key_id = ENV["AWS_ACCESS_KEY"]
aws.secret_access_key = ENV["AWS_SECRET_KEY"]
aws.keypair_name = ENV["AWS_KEYPAIR_NAME"]
override.ssh.private_key_path = ENV["AWS_SSH_PRIVKEY"]
override.ssh.username = "ubuntu"
override.ssh.username = username
aws.region = AWS_REGION
aws.ami = AWS_AMI
aws.instance_type = "t1.micro"
aws.instance_type = AWS_INSTANCE_TYPE
end
config.vm.provider :rackspace do |rs|
config.ssh.private_key_path = ENV["RS_PRIVATE_KEY"]
config.vm.provider :rackspace do |rs, override|
override.vm.provision :shell, :inline => $script
rs.username = ENV["RS_USERNAME"]
rs.api_key = ENV["RS_API_KEY"]
rs.public_key_path = ENV["RS_PUBLIC_KEY"]
@@ -71,20 +141,25 @@ Vagrant::VERSION >= "1.1.0" and Vagrant.configure("2") do |config|
end
config.vm.provider :vmware_fusion do |f, override|
override.vm.box = BOX_NAME
override.vm.box_url = VF_BOX_URI
override.vm.synced_folder ".", "/vagrant", disabled: true
override.vm.provision :shell, :inline => $script
f.vmx["displayName"] = "docker"
end
config.vm.provider :virtualbox do |vb|
config.vm.box = BOX_NAME
config.vm.box_url = BOX_URI
config.vm.provider :virtualbox do |vb, override|
override.vm.provision :shell, :inline => $vbox_script
vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
vb.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
end
end
# If this is a version 1 config, virtualbox is the only option. A version 2
# config would have already been set in the above provider section.
Vagrant::VERSION < "1.1.0" and Vagrant::Config.run do |config|
config.vm.provision :shell, :inline => $vbox_script
end
if !FORWARD_DOCKER_PORTS.nil?
Vagrant::VERSION < "1.1.0" and Vagrant::Config.run do |config|
(49000..49900).each do |port|
+84 -57
View File
@@ -5,6 +5,7 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"github.com/dotcloud/docker/archive"
"github.com/dotcloud/docker/auth"
"github.com/dotcloud/docker/utils"
"github.com/gorilla/mux"
@@ -22,7 +23,7 @@ import (
)
const (
APIVERSION = 1.6
APIVERSION = 1.7
DEFAULTHTTPHOST = "127.0.0.1"
DEFAULTHTTPPORT = 4243
DEFAULTUNIXSOCKET = "/var/run/docker.sock"
@@ -60,7 +61,10 @@ func parseMultipartForm(r *http.Request) error {
func httpError(w http.ResponseWriter, err error) {
statusCode := http.StatusInternalServerError
if strings.HasPrefix(err.Error(), "No such") {
// FIXME: this is brittle and should not be necessary.
// If we need to differentiate between different possible error types, we should
// create appropriate error types with clearly defined meaning.
if strings.Contains(err.Error(), "No such") {
statusCode = http.StatusNotFound
} else if strings.HasPrefix(err.Error(), "Bad parameter") {
statusCode = http.StatusBadRequest
@@ -145,13 +149,12 @@ func postContainersKill(srv *Server, version float64, w http.ResponseWriter, r *
signal := 0
if r != nil {
s := r.Form.Get("signal")
if s != "" {
if s, err := strconv.Atoi(s); err != nil {
if s := r.Form.Get("signal"); s != "" {
s, err := strconv.Atoi(s)
if err != nil {
return err
} else {
signal = s
}
signal = s
}
}
if err := srv.ContainerKill(name, signal); err != nil {
@@ -190,10 +193,23 @@ func getImagesJSON(srv *Server, version float64, w http.ResponseWriter, r *http.
return err
}
if version < 1.7 {
outs2 := []APIImagesOld{}
for _, ctnr := range outs {
outs2 = append(outs2, ctnr.ToLegacy()...)
}
return writeJSON(w, http.StatusOK, outs2)
}
return writeJSON(w, http.StatusOK, outs)
}
func getImagesViz(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if version > 1.6 {
w.WriteHeader(http.StatusNotFound)
return fmt.Errorf("This is now implemented in the client.")
}
if err := srv.ImagesViz(w); err != nil {
return err
}
@@ -235,6 +251,7 @@ func getEvents(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
}
w.Header().Set("Content-Type", "application/json")
wf := utils.NewWriteFlusher(w)
wf.Flush()
if since != 0 {
// If since, send previous events that happened after the timestamp
for _, event := range srv.events {
@@ -297,13 +314,10 @@ func getContainersTop(srv *Server, version float64, w http.ResponseWriter, r *ht
if err := parseForm(r); err != nil {
return err
}
name := vars["name"]
ps_args := r.Form.Get("ps_args")
procsStr, err := srv.ContainerTop(name, ps_args)
procsStr, err := srv.ContainerTop(vars["name"], r.Form.Get("ps_args"))
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, procsStr)
}
@@ -331,13 +345,12 @@ func getContainersJSON(srv *Server, version float64, w http.ResponseWriter, r *h
if version < 1.5 {
outs2 := []APIContainersOld{}
for _, ctnr := range outs {
outs2 = append(outs2, ctnr.ToLegacy())
outs2 = append(outs2, *ctnr.ToLegacy())
}
return writeJSON(w, http.StatusOK, outs2)
} else {
return writeJSON(w, http.StatusOK, outs)
}
return writeJSON(w, http.StatusOK, outs)
}
func postImagesTag(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
@@ -463,15 +476,16 @@ func postImagesInsert(srv *Server, version float64, w http.ResponseWriter, r *ht
w.Header().Set("Content-Type", "application/json")
}
sf := utils.NewStreamFormatter(version > 1.0)
imgID, err := srv.ImageInsert(name, url, path, w, sf)
err := srv.ImageInsert(name, url, path, w, sf)
if err != nil {
if sf.Used() {
w.Write(sf.FormatError(err))
return nil
}
return err
}
return writeJSON(w, http.StatusOK, &APIID{ID: imgID})
return nil
}
func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
@@ -520,47 +534,52 @@ func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http
return nil
}
func getImagesGet(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
name := vars["name"]
if version > 1.0 {
w.Header().Set("Content-Type", "application/x-tar")
}
return srv.ImageExport(name, w)
}
func postImagesLoad(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
return srv.ImageLoad(r.Body)
}
func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return nil
}
config := &Config{}
out := &APIRun{}
name := r.Form.Get("name")
if err := json.NewDecoder(r.Body).Decode(config); err != nil {
job := srv.Eng.Job("create", r.Form.Get("name"))
if err := job.DecodeEnv(r.Body); err != nil {
return err
}
resolvConf, err := utils.GetResolvConf()
if err != nil {
return err
}
if !config.NetworkDisabled && len(config.Dns) == 0 && len(srv.runtime.config.Dns) == 0 && utils.CheckLocalDns(resolvConf) {
if !job.GetenvBool("NetworkDisabled") && len(job.Getenv("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
job.SetenvList("Dns", defaultDns)
}
id, warnings, err := srv.ContainerCreate(config, name)
if err != nil {
// Read container ID from the first line of stdout
job.StdoutParseString(&out.ID)
// Read warnings from stderr
job.StderrParseLines(&out.Warnings, 0)
if err := job.Run(); 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 {
if job.GetenvInt("Memory") > 0 && !srv.runtime.capabilities.MemoryLimit {
log.Println("WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.")
out.Warnings = append(out.Warnings, "Your kernel does not support memory limit capabilities. Limitation discarded.")
}
if config.Memory > 0 && !srv.runtime.capabilities.SwapLimit {
if job.GetenvInt("Memory") > 0 && !srv.runtime.capabilities.SwapLimit {
log.Println("WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.")
out.Warnings = append(out.Warnings, "Your kernel does not support memory swap capabilities. Limitation discarded.")
}
if !config.NetworkDisabled && srv.runtime.capabilities.IPv4ForwardingDisabled {
if !job.GetenvBool("NetworkDisabled") && srv.runtime.capabilities.IPv4ForwardingDisabled {
log.Println("Warning: IPv4 forwarding is disabled.")
out.Warnings = append(out.Warnings, "IPv4 forwarding is disabled.")
}
@@ -627,36 +646,28 @@ func deleteImages(srv *Server, version float64, w http.ResponseWriter, r *http.R
if imgs != nil {
if len(imgs) != 0 {
return writeJSON(w, http.StatusOK, imgs)
} else {
return fmt.Errorf("Conflict, %s wasn't deleted", name)
}
} else {
w.WriteHeader(http.StatusNoContent)
return fmt.Errorf("Conflict, %s wasn't deleted", name)
}
w.WriteHeader(http.StatusNoContent)
return nil
}
func postContainersStart(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
var hostConfig *HostConfig
// allow a nil body for backwards compatibility
if r.Body != nil {
if matchesContentType(r.Header.Get("Content-Type"), "application/json") {
hostConfig = &HostConfig{}
if err := json.NewDecoder(r.Body).Decode(hostConfig); err != nil {
return err
}
}
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
name := vars["name"]
// Register any links from the host config before starting the container
if err := srv.RegisterLinks(name, hostConfig); err != nil {
return err
job := srv.Eng.Job("start", name)
// allow a nil body for backwards compatibility
if r.Body != nil {
if matchesContentType(r.Header.Get("Content-Type"), "application/json") {
if err := job.DecodeEnv(r.Body); err != nil {
return err
}
}
}
if err := srv.ContainerStart(name, hostConfig); err != nil {
if err := job.Run(); err != nil {
return err
}
w.WriteHeader(http.StatusNoContent)
@@ -905,7 +916,7 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
return fmt.Errorf("Error trying to use git: %s (%s)", err, output)
}
c, err := Tar(root, Bzip2)
c, err := archive.Tar(root, archive.Bzip2)
if err != nil {
return err
}
@@ -920,7 +931,7 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
if err != nil {
return err
}
c, err := mkBuildContext(string(dockerFile), nil)
c, err := MkBuildContext(string(dockerFile), nil)
if err != nil {
return err
}
@@ -968,7 +979,7 @@ func postContainersCopy(srv *Server, version float64, w http.ResponseWriter, r *
}
if copyData.Resource == "" {
return fmt.Errorf("Resource cannot be empty")
return fmt.Errorf("Path cannot be empty")
}
if copyData.Resource[0] == '/' {
copyData.Resource = copyData.Resource[1:]
@@ -1037,6 +1048,7 @@ func createRouter(srv *Server, logging bool) (*mux.Router, error) {
"/images/json": getImagesJSON,
"/images/viz": getImagesViz,
"/images/search": getImagesSearch,
"/images/{name:.*}/get": getImagesGet,
"/images/{name:.*}/history": getImagesHistory,
"/images/{name:.*}/json": getImagesByName,
"/containers/ps": getContainersJSON,
@@ -1053,6 +1065,7 @@ func createRouter(srv *Server, logging bool) (*mux.Router, error) {
"/build": postBuild,
"/images/create": postImagesCreate,
"/images/{name:.*}/insert": postImagesInsert,
"/images/load": postImagesLoad,
"/images/{name:.*}/push": postImagesPush,
"/images/{name:.*}/tag": postImagesTag,
"/containers/create": postContainersCreate,
@@ -1098,6 +1111,20 @@ func createRouter(srv *Server, logging bool) (*mux.Router, error) {
return r, nil
}
// ServeRequest processes a single http request to the docker remote api.
// FIXME: refactor this to be part of Server and not require re-creating a new
// router each time. This requires first moving ListenAndServe into Server.
func ServeRequest(srv *Server, apiversion float64, w http.ResponseWriter, req *http.Request) error {
router, err := createRouter(srv, false)
if err != nil {
return err
}
// Insert APIVERSION into the request as a convenience
req.URL.Path = fmt.Sprintf("/v%g%s", apiversion, req.URL.Path)
router.ServeHTTP(w, req)
return nil
}
func ListenAndServe(proto, addr string, srv *Server, logging bool) error {
log.Printf("Listening for HTTP on %s (%s)\n", addr, proto)
+144 -117
View File
@@ -1,123 +1,150 @@
package docker
type APIHistory struct {
ID string `json:"Id"`
Tags []string `json:",omitempty"`
Created int64
CreatedBy string `json:",omitempty"`
import "strings"
type (
APIHistory struct {
ID string `json:"Id"`
Tags []string `json:",omitempty"`
Created int64
CreatedBy string `json:",omitempty"`
Size int64
}
APIImages struct {
ID string `json:"Id"`
RepoTags []string `json:",omitempty"`
Created int64
Size int64
VirtualSize int64
ParentId string `json:",omitempty"`
}
APIImagesOld struct {
Repository string `json:",omitempty"`
Tag string `json:",omitempty"`
ID string `json:"Id"`
Created int64
Size int64
VirtualSize int64
}
APIInfo struct {
Debug bool
Containers int
Images int
Driver string `json:",omitempty"`
DriverStatus [][2]string `json:",omitempty"`
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"`
}
APITop struct {
Titles []string
Processes [][]string
}
APIRmi struct {
Deleted string `json:",omitempty"`
Untagged string `json:",omitempty"`
}
APIContainers struct {
ID string `json:"Id"`
Image string
Command string
Created int64
Status string
Ports []APIPort
SizeRw int64
SizeRootFs int64
Names []string
}
APIContainersOld struct {
ID string `json:"Id"`
Image string
Command string
Created int64
Status string
Ports string
SizeRw int64
SizeRootFs int64
}
APIID struct {
ID string `json:"Id"`
}
APIRun struct {
ID string `json:"Id"`
Warnings []string `json:",omitempty"`
}
APIPort struct {
PrivatePort int64
PublicPort int64
Type string
IP string
}
APIVersion struct {
Version string
GitCommit string `json:",omitempty"`
GoVersion string `json:",omitempty"`
}
APIWait struct {
StatusCode int
}
APIAuth struct {
Status string
}
APIImageConfig struct {
ID string `json:"Id"`
*Config
}
APICopy struct {
Resource string
HostPath string
}
)
func (api APIImages) ToLegacy() []APIImagesOld {
outs := []APIImagesOld{}
for _, repotag := range api.RepoTags {
components := strings.SplitN(repotag, ":", 2)
outs = append(outs, APIImagesOld{
ID: api.ID,
Repository: components[0],
Tag: components[1],
Created: api.Created,
Size: api.Size,
VirtualSize: api.VirtualSize,
})
}
return outs
}
type APIImages struct {
Repository string `json:",omitempty"`
Tag string `json:",omitempty"`
ID string `json:"Id"`
Created int64
Size int64
VirtualSize int64
}
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"`
}
type APITop struct {
Titles []string
Processes [][]string
}
type APIRmi struct {
Deleted string `json:",omitempty"`
Untagged string `json:",omitempty"`
}
type APIContainers struct {
ID string `json:"Id"`
Image string
Command string
Created int64
Status string
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,
SizeRootFs: self.SizeRootFs,
func (api APIContainers) ToLegacy() *APIContainersOld {
return &APIContainersOld{
ID: api.ID,
Image: api.Image,
Command: api.Command,
Created: api.Created,
Status: api.Status,
Ports: displayablePorts(api.Ports),
SizeRw: api.SizeRw,
SizeRootFs: api.SizeRootFs,
}
}
type APIContainersOld struct {
ID string `json:"Id"`
Image string
Command string
Created int64
Status string
Ports string
SizeRw int64
SizeRootFs int64
}
type APISearch struct {
Name string
Description string
}
type APIID struct {
ID string `json:"Id"`
}
type APIRun struct {
ID string `json:"Id"`
Warnings []string `json:",omitempty"`
}
type APIPort struct {
PrivatePort int64
PublicPort int64
Type string
IP string
}
type APIVersion struct {
Version string
GitCommit string `json:",omitempty"`
GoVersion string `json:",omitempty"`
}
type APIWait struct {
StatusCode int
}
type APIAuth struct {
Status string
}
type APIImageConfig struct {
ID string `json:"Id"`
*Config
}
type APICopy struct {
Resource string
HostPath string
}
+19
View File
@@ -0,0 +1,19 @@
package docker
import (
"testing"
)
func TestJsonContentType(t *testing.T) {
if !matchesContentType("application/json", "application/json") {
t.Fail()
}
if !matchesContentType("application/json; charset=utf-8", "application/json") {
t.Fail()
}
if matchesContentType("dockerapplication/json", "application/json") {
t.Fail()
}
}
+118 -21
View File
@@ -1,4 +1,4 @@
package docker
package archive
import (
"archive/tar"
@@ -15,7 +15,15 @@ import (
type Archive io.Reader
type Compression uint32
type Compression int
type TarOptions struct {
Includes []string
Excludes []string
Recursive bool
Compression Compression
CreateFiles []string
}
const (
Uncompressed Compression = iota
@@ -80,20 +88,78 @@ 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, &TarOptions{Recursive: true, Compression: compression})
}
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}
if filter == nil {
filter = []string{"."}
func TarFilter(path string, options *TarOptions) (io.Reader, error) {
args := []string{"tar", "--numeric-owner", "-f", "-", "-C", path, "-T", "-"}
if options.Includes == nil {
options.Includes = []string{"."}
}
for _, f := range filter {
args = append(args, "-c"+compression.Flag(), f)
args = append(args, "-c"+options.Compression.Flag())
for _, exclude := range options.Excludes {
args = append(args, fmt.Sprintf("--exclude=%s", exclude))
}
return CmdStream(exec.Command(args[0], args[1:]...))
if !options.Recursive {
args = append(args, "--no-recursion")
}
files := ""
for _, f := range options.Includes {
files = files + escapeName(f) + "\n"
}
tmpDir := ""
if options.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 options.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,
@@ -101,7 +167,7 @@ func TarFilter(path string, compression Compression, filter []string) (io.Reader
// The archive may be compressed with one of the following algorithms:
// identity (uncompressed), gzip, bzip2, xz.
// FIXME: specify behavior when target path exists vs. doesn't exist.
func Untar(archive io.Reader, path string) error {
func Untar(archive io.Reader, path string, options *TarOptions) error {
if archive == nil {
return fmt.Errorf("Empty archive")
}
@@ -109,21 +175,29 @@ func Untar(archive io.Reader, path string) error {
buf := make([]byte, 10)
totalN := 0
for totalN < 10 {
if n, err := archive.Read(buf[totalN:]); err != nil {
n, err := archive.Read(buf[totalN:])
if err != nil {
if err == io.EOF {
return fmt.Errorf("Tarball too short")
}
return err
} else {
totalN += n
utils.Debugf("[tar autodetect] n: %d", n)
}
totalN += n
utils.Debugf("[tar autodetect] n: %d", n)
}
compression := DetectCompression(buf)
utils.Debugf("Archive compression detected: %s", compression.Extension())
args := []string{"--numeric-owner", "-f", "-", "-C", path, "-x" + compression.Flag()}
cmd := exec.Command("tar", "--numeric-owner", "-f", "-", "-C", path, "-x"+compression.Flag())
if options != nil {
for _, exclude := range options.Excludes {
args = append(args, fmt.Sprintf("--exclude=%s", exclude))
}
}
cmd := exec.Command("tar", args...)
cmd.Stdin = io.MultiReader(bytes.NewReader(buf), archive)
// Hardcode locale environment for predictable outcome regardless of host configuration.
// (see https://github.com/dotcloud/docker/issues/355)
@@ -140,11 +214,11 @@ 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, &TarOptions{Compression: Uncompressed, Includes: filter, Recursive: true})
if err != nil {
return err
}
return Untar(archive, dst)
return Untar(archive, dst, nil)
}
// UntarPath is a convenience function which looks for an archive
@@ -152,7 +226,7 @@ func TarUntar(src string, filter []string, dst string) error {
func UntarPath(src, dst string) error {
if archive, err := os.Open(src); err != nil {
return err
} else if err := Untar(archive, dst); err != nil {
} else if err := Untar(archive, dst, nil); err != nil {
return err
}
return nil
@@ -221,19 +295,39 @@ func CopyFileWithTar(src, dst string) error {
return err
}
tw.Close()
return Untar(buf, filepath.Dir(dst))
return Untar(buf, filepath.Dir(dst), nil)
}
// 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 +352,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 {
+5 -5
View File
@@ -1,4 +1,4 @@
package docker
package archive
import (
"bytes"
@@ -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)
}
@@ -83,7 +83,7 @@ func tarUntar(t *testing.T, origin string, compression Compression) error {
return err
}
defer os.RemoveAll(tmp)
if err := Untar(archive, tmp); err != nil {
if err := Untar(archive, tmp, nil); err != nil {
return err
}
if _, err := os.Stat(tmp); err != nil {
+317
View File
@@ -0,0 +1,317 @@
package archive
import (
"fmt"
"os"
"path/filepath"
"strings"
"syscall"
)
type ChangeType int
const (
ChangeModify = iota
ChangeAdd
ChangeDelete
)
type Change struct {
Path string
Kind ChangeType
}
func (change *Change) String() string {
var kind string
switch change.Kind {
case ChangeModify:
kind = "C"
case ChangeAdd:
kind = "A"
case ChangeDelete:
kind = "D"
}
return fmt.Sprintf("%s %s", kind, change.Path)
}
func Changes(layers []string, rw string) ([]Change, error) {
var changes []Change
err := filepath.Walk(rw, func(path string, f os.FileInfo, err error) error {
if err != nil {
return err
}
// Rebase path
path, err = filepath.Rel(rw, path)
if err != nil {
return err
}
path = filepath.Join("/", path)
// Skip root
if path == "/" {
return nil
}
// Skip AUFS metadata
if matched, err := filepath.Match("/.wh..wh.*", path); err != nil || matched {
return err
}
change := Change{
Path: path,
}
// 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) {
return nil, err
}
return changes, nil
}
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) 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
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) ||
oldStat.Mtim != newStat.Mtim {
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
info.addChanges(oldInfo, &changes)
return changes
}
func newRootFileInfo() *FileInfo {
root := &FileInfo{
name: "/",
children: make(map[string]*FileInfo),
}
return root
}
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
relPath, err := filepath.Rel(sourceDir, path)
if err != nil {
return err
}
relPath = filepath.Join("/", relPath)
if relPath == "/" {
return nil
}
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
}
parent.children[info.name] = info
return nil
})
if err != nil {
return nil, err
}
return root, 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
}
func ChangesSize(newDir string, changes []Change) int64 {
var size int64
for _, change := range changes {
if change.Kind == ChangeModify || change.Kind == ChangeAdd {
file := filepath.Join(newDir, change.Path)
fileInfo, _ := os.Lstat(file)
if fileInfo != nil && !fileInfo.IsDir() {
size += fileInfo.Size()
}
}
}
return size
}
func ExportChanges(dir string, changes []Change) (Archive, error) {
files := make([]string, 0)
deletions := make([]string, 0)
for _, change := range changes {
if change.Kind == ChangeModify || change.Kind == ChangeAdd {
files = append(files, change.Path)
}
if change.Kind == ChangeDelete {
base := filepath.Base(change.Path)
dir := filepath.Dir(change.Path)
deletions = append(deletions, filepath.Join(dir, ".wh."+base))
}
}
// FIXME: Why do we create whiteout files inside Tar code ?
return TarFilter(dir, &TarOptions{
Compression: Uncompressed,
Includes: files,
Recursive: false,
CreateFiles: deletions,
})
}
+298
View File
@@ -0,0 +1,298 @@
package archive
import (
"io/ioutil"
"os"
"os/exec"
"path"
"sort"
"testing"
"time"
)
func max(x, y int) int {
if x >= y {
return x
}
return y
}
func copyDir(src, dst string) error {
cmd := exec.Command("cp", "-a", src, dst)
if err := cmd.Run(); err != nil {
return err
}
return nil
}
// Helper to sort []Change by path
type byPath struct{ changes []Change }
func (b byPath) Less(i, j int) bool { return b.changes[i].Path < b.changes[j].Path }
func (b byPath) Len() int { return len(b.changes) }
func (b byPath) Swap(i, j int) { b.changes[i], b.changes[j] = b.changes[j], b.changes[i] }
type FileType uint32
const (
Regular FileType = iota
Dir
Symlink
)
type FileData struct {
filetype FileType
path string
contents string
permissions os.FileMode
}
func createSampleDir(t *testing.T, root string) {
files := []FileData{
{Regular, "file1", "file1\n", 0600},
{Regular, "file2", "file2\n", 0666},
{Regular, "file3", "file3\n", 0404},
{Regular, "file4", "file4\n", 0600},
{Regular, "file5", "file5\n", 0600},
{Regular, "file6", "file6\n", 0600},
{Regular, "file7", "file7\n", 0600},
{Dir, "dir1", "", 0740},
{Regular, "dir1/file1-1", "file1-1\n", 01444},
{Regular, "dir1/file1-2", "file1-2\n", 0666},
{Dir, "dir2", "", 0700},
{Regular, "dir2/file2-1", "file2-1\n", 0666},
{Regular, "dir2/file2-2", "file2-2\n", 0666},
{Dir, "dir3", "", 0700},
{Regular, "dir3/file3-1", "file3-1\n", 0666},
{Regular, "dir3/file3-2", "file3-2\n", 0666},
{Dir, "dir4", "", 0700},
{Regular, "dir4/file3-1", "file4-1\n", 0666},
{Regular, "dir4/file3-2", "file4-2\n", 0666},
{Symlink, "symlink1", "target1", 0666},
{Symlink, "symlink2", "target2", 0666},
}
for _, info := range files {
if info.filetype == Dir {
if err := os.MkdirAll(path.Join(root, info.path), info.permissions); err != nil {
t.Fatal(err)
}
} else if info.filetype == Regular {
if err := ioutil.WriteFile(path.Join(root, info.path), []byte(info.contents), info.permissions); err != nil {
t.Fatal(err)
}
} else if info.filetype == Symlink {
if err := os.Symlink(info.contents, path.Join(root, info.path)); err != nil {
t.Fatal(err)
}
}
}
}
// Create an directory, copy it, make sure we report no changes between the two
func TestChangesDirsEmpty(t *testing.T) {
src, err := ioutil.TempDir("", "docker-changes-test")
if err != nil {
t.Fatal(err)
}
createSampleDir(t, src)
dst := src + "-copy"
if err := copyDir(src, dst); err != nil {
t.Fatal(err)
}
changes, err := ChangesDirs(dst, src)
if err != nil {
t.Fatal(err)
}
if len(changes) != 0 {
t.Fatalf("Reported changes for identical dirs: %v", changes)
}
os.RemoveAll(src)
os.RemoveAll(dst)
}
func mutateSampleDir(t *testing.T, root string) {
// Remove a regular file
if err := os.RemoveAll(path.Join(root, "file1")); err != nil {
t.Fatal(err)
}
// Remove a directory
if err := os.RemoveAll(path.Join(root, "dir1")); err != nil {
t.Fatal(err)
}
// Remove a symlink
if err := os.RemoveAll(path.Join(root, "symlink1")); err != nil {
t.Fatal(err)
}
// Rewrite a file
if err := ioutil.WriteFile(path.Join(root, "file2"), []byte("fileN\n"), 0777); err != nil {
t.Fatal(err)
}
// Replace a file
if err := os.RemoveAll(path.Join(root, "file3")); err != nil {
t.Fatal(err)
}
if err := ioutil.WriteFile(path.Join(root, "file3"), []byte("fileM\n"), 0404); err != nil {
t.Fatal(err)
}
// Touch file
if err := os.Chtimes(path.Join(root, "file4"), time.Now(), time.Now()); err != nil {
t.Fatal(err)
}
// Replace file with dir
if err := os.RemoveAll(path.Join(root, "file5")); err != nil {
t.Fatal(err)
}
if err := os.MkdirAll(path.Join(root, "file5"), 0666); err != nil {
t.Fatal(err)
}
// Create new file
if err := ioutil.WriteFile(path.Join(root, "filenew"), []byte("filenew\n"), 0777); err != nil {
t.Fatal(err)
}
// Create new dir
if err := os.MkdirAll(path.Join(root, "dirnew"), 0766); err != nil {
t.Fatal(err)
}
// Create a new symlink
if err := os.Symlink("targetnew", path.Join(root, "symlinknew")); err != nil {
t.Fatal(err)
}
// Change a symlink
if err := os.RemoveAll(path.Join(root, "symlink2")); err != nil {
t.Fatal(err)
}
if err := os.Symlink("target2change", path.Join(root, "symlink2")); err != nil {
t.Fatal(err)
}
// Replace dir with file
if err := os.RemoveAll(path.Join(root, "dir2")); err != nil {
t.Fatal(err)
}
if err := ioutil.WriteFile(path.Join(root, "dir2"), []byte("dir2\n"), 0777); err != nil {
t.Fatal(err)
}
// Touch dir
if err := os.Chtimes(path.Join(root, "dir3"), time.Now(), time.Now()); err != nil {
t.Fatal(err)
}
}
func TestChangesDirsMutated(t *testing.T) {
src, err := ioutil.TempDir("", "docker-changes-test")
if err != nil {
t.Fatal(err)
}
createSampleDir(t, src)
dst := src + "-copy"
if err := copyDir(src, dst); err != nil {
t.Fatal(err)
}
mutateSampleDir(t, dst)
changes, err := ChangesDirs(dst, src)
if err != nil {
t.Fatal(err)
}
sort.Sort(byPath{changes})
expectedChanges := []Change{
{"/dir1", ChangeDelete},
{"/dir2", ChangeModify},
{"/dir3", ChangeModify},
{"/dirnew", ChangeAdd},
{"/file1", ChangeDelete},
{"/file2", ChangeModify},
{"/file3", ChangeModify},
{"/file4", ChangeModify},
{"/file5", ChangeModify},
{"/filenew", ChangeAdd},
{"/symlink1", ChangeDelete},
{"/symlink2", ChangeModify},
{"/symlinknew", ChangeAdd},
}
i := 0
for ; i < max(len(changes), len(expectedChanges)); i++ {
if i >= len(expectedChanges) {
t.Fatalf("unexpected change %s\n", changes[i].String())
}
if i >= len(changes) {
t.Fatalf("no change for expected change %s\n", expectedChanges[i].String())
}
if changes[i].Path == expectedChanges[i].Path {
if changes[i] != expectedChanges[i] {
t.Fatalf("Wrong change for %s, expected %s, got %d\n", changes[i].Path, changes[i].String(), expectedChanges[i].String())
}
} else if changes[i].Path < expectedChanges[i].Path {
t.Fatalf("unexpected change %s\n", changes[i].String())
} else {
t.Fatalf("no change for expected change %s\n", expectedChanges[i].String())
}
}
for ; i < len(expectedChanges); i++ {
}
os.RemoveAll(src)
os.RemoveAll(dst)
}
func TestApplyLayer(t *testing.T) {
t.Skip("Skipping TestApplyLayer due to known failures") // Disable this for now as it is broken
return
src, err := ioutil.TempDir("", "docker-changes-test")
if err != nil {
t.Fatal(err)
}
createSampleDir(t, src)
dst := src + "-copy"
if err := copyDir(src, dst); err != nil {
t.Fatal(err)
}
mutateSampleDir(t, dst)
changes, err := ChangesDirs(dst, src)
if err != nil {
t.Fatal(err)
}
layer, err := ExportChanges(dst, changes)
if err != nil {
t.Fatal(err)
}
layerCopy, err := NewTempArchive(layer, "")
if err != nil {
t.Fatal(err)
}
if err := ApplyLayer(src, layerCopy); err != nil {
t.Fatal(err)
}
changes2, err := ChangesDirs(src, dst)
if err != nil {
t.Fatal(err)
}
if len(changes2) != 0 {
t.Fatalf("Unexpected differences after re applying mutation: %v", changes)
}
os.RemoveAll(src)
os.RemoveAll(dst)
}
+95
View File
@@ -0,0 +1,95 @@
package archive
import (
"os"
"path/filepath"
"strings"
"syscall"
"time"
)
// ApplyLayer parses a diff in the standard layer format from `layer`, and
// applies it to the directory `dest`.
func ApplyLayer(dest string, layer Archive) error {
// Poor man's diff applyer in 2 steps:
// Step 1: untar everything in place
if err := Untar(layer, dest, nil); err != nil {
return err
}
modifiedDirs := make(map[string]*syscall.Stat_t)
addDir := func(file string) {
d := filepath.Dir(file)
if _, exists := modifiedDirs[d]; !exists {
if s, err := os.Lstat(d); err == nil {
if sys := s.Sys(); sys != nil {
if stat, ok := sys.(*syscall.Stat_t); ok {
modifiedDirs[d] = stat
}
}
}
}
}
// Step 2: walk for whiteouts and apply them, removing them in the process
err := filepath.Walk(dest, func(fullPath string, f os.FileInfo, err error) error {
if err != nil {
if os.IsNotExist(err) {
// This happens in the case of whiteouts in parent dir removing a directory
// We just ignore it
return filepath.SkipDir
}
return err
}
// Rebase path
path, err := filepath.Rel(dest, fullPath)
if err != nil {
return err
}
path = filepath.Join("/", path)
// Skip AUFS metadata
if matched, err := filepath.Match("/.wh..wh.*", path); err != nil {
return err
} else if matched {
addDir(fullPath)
if err := os.RemoveAll(fullPath); err != nil {
return err
}
}
filename := filepath.Base(path)
if strings.HasPrefix(filename, ".wh.") {
rmTargetName := filename[len(".wh."):]
rmTargetPath := filepath.Join(filepath.Dir(fullPath), rmTargetName)
// Remove the file targeted by the whiteout
addDir(rmTargetPath)
if err := os.RemoveAll(rmTargetPath); err != nil {
return err
}
// Remove the whiteout itself
addDir(fullPath)
if err := os.RemoveAll(fullPath); err != nil {
return err
}
}
return nil
})
if err != nil {
return err
}
for k, v := range modifiedDirs {
aTime := time.Unix(v.Atim.Unix())
mTime := time.Unix(v.Mtim.Unix())
if err := os.Chtimes(k, aTime, mTime); err != nil {
return err
}
}
return nil
}
+2 -3
View File
@@ -196,10 +196,9 @@ func Login(authConfig *AuthConfig, factory *utils.HTTPRequestFactory) (string, e
if loginAgainstOfficialIndex {
return "", fmt.Errorf("Login: Your account hasn't been activated. " +
"Please check your e-mail for a confirmation link.")
} else {
return "", fmt.Errorf("Login: Your account hasn't been activated. " +
"Please see the documentation of the registry " + serverAddress + " for instructions how to activate it.")
}
return "", fmt.Errorf("Login: Your account hasn't been activated. " +
"Please see the documentation of the registry " + serverAddress + " for instructions how to activate it.")
} else if reqStatusCode == 400 {
if string(reqBody) == "\"Username or email already exists\"" {
req, err := factory.NewRequest("GET", serverAddress+"users/", nil)
-49
View File
@@ -1,11 +1,8 @@
package auth
import (
"crypto/rand"
"encoding/hex"
"io/ioutil"
"os"
"strings"
"testing"
)
@@ -29,52 +26,6 @@ func TestEncodeAuth(t *testing.T) {
}
}
func TestLogin(t *testing.T) {
os.Setenv("DOCKER_INDEX_URL", "https://indexstaging-docker.dotcloud.com")
defer os.Setenv("DOCKER_INDEX_URL", "")
authConfig := &AuthConfig{Username: "unittester", Password: "surlautrerivejetattendrai", Email: "noise+unittester@dotcloud.com"}
status, err := Login(authConfig, nil)
if err != nil {
t.Fatal(err)
}
if status != "Login Succeeded" {
t.Fatalf("Expected status \"Login Succeeded\", found \"%s\" instead", status)
}
}
func TestCreateAccount(t *testing.T) {
os.Setenv("DOCKER_INDEX_URL", "https://indexstaging-docker.dotcloud.com")
defer os.Setenv("DOCKER_INDEX_URL", "")
tokenBuffer := make([]byte, 16)
_, err := rand.Read(tokenBuffer)
if err != nil {
t.Fatal(err)
}
token := hex.EncodeToString(tokenBuffer)[:12]
username := "ut" + token
authConfig := &AuthConfig{Username: username, Password: "test42", Email: "docker-ut+" + token + "@example.com"}
status, err := Login(authConfig, nil)
if err != nil {
t.Fatal(err)
}
expectedStatus := "Account created. Please use the confirmation link we sent" +
" to your e-mail to activate it."
if status != expectedStatus {
t.Fatalf("Expected status: \"%s\", found \"%s\" instead.", expectedStatus, status)
}
status, err = Login(authConfig, nil)
if err == nil {
t.Fatalf("Expected error but found nil instead")
}
expectedError := "Login: Account is not Active"
if !strings.Contains(err.Error(), expectedError) {
t.Fatalf("Expected message \"%s\" but found \"%s\" instead", expectedError, err)
}
}
func setupTempConfigFile() (*ConfigFile, error) {
root, err := ioutil.TempDir("", "docker-test-auth")
if err != nil {
+9 -6
View File
@@ -3,6 +3,7 @@ package docker
import (
"encoding/json"
"fmt"
"github.com/dotcloud/docker/archive"
"github.com/dotcloud/docker/utils"
"io"
"io/ioutil"
@@ -64,6 +65,9 @@ func (b *buildFile) CmdFrom(name string) error {
}
b.image = image.ID
b.config = &Config{}
if image.Config != nil {
b.config = image.Config
}
if b.config.Env == nil || len(b.config.Env) == 0 {
b.config.Env = append(b.config.Env, "HOME=/", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin")
}
@@ -291,17 +295,17 @@ func (b *buildFile) addContext(container *Container, orig, dest string) error {
return fmt.Errorf("%s: no such file or directory", orig)
}
if fi.IsDir() {
if err := CopyWithTar(origPath, destPath); err != nil {
if err := archive.CopyWithTar(origPath, destPath); err != nil {
return err
}
// First try to unpack the source as an archive
} else if err := UntarPath(origPath, destPath); err != nil {
} else if err := archive.UntarPath(origPath, destPath); err != nil {
utils.Debugf("Couldn't untar %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
}
if err := CopyWithTar(origPath, destPath); err != nil {
if err := archive.CopyWithTar(origPath, destPath); err != nil {
return err
}
}
@@ -387,8 +391,7 @@ func (b *buildFile) run() (string, error) {
}
//start the container
hostConfig := &HostConfig{}
if err := c.Start(hostConfig); err != nil {
if err := c.Start(); err != nil {
return "", err
}
@@ -473,7 +476,7 @@ func (b *buildFile) Build(context io.Reader) (string, error) {
if err != nil {
return "", err
}
if err := Untar(context, name); err != nil {
if err := archive.Untar(context, name, nil); err != nil {
return "", err
}
defer os.RemoveAll(name)
-106
View File
@@ -1,106 +0,0 @@
package docker
import (
"fmt"
"os"
"path/filepath"
"strings"
)
type ChangeType int
const (
ChangeModify = iota
ChangeAdd
ChangeDelete
)
type Change struct {
Path string
Kind ChangeType
}
func (change *Change) String() string {
var kind string
switch change.Kind {
case ChangeModify:
kind = "C"
case ChangeAdd:
kind = "A"
case ChangeDelete:
kind = "D"
}
return fmt.Sprintf("%s %s", kind, change.Path)
}
func Changes(layers []string, rw string) ([]Change, error) {
var changes []Change
err := filepath.Walk(rw, func(path string, f os.FileInfo, err error) error {
if err != nil {
return err
}
// Rebase path
path, err = filepath.Rel(rw, path)
if err != nil {
return err
}
path = filepath.Join("/", path)
// Skip root
if path == "/" {
return nil
}
// Skip AUFS metadata
if matched, err := filepath.Match("/.wh..wh.*", path); err != nil || matched {
return err
}
change := Change{
Path: path,
}
// 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) {
return nil, err
}
return changes, nil
}
+586 -120
View File
File diff suppressed because it is too large Load Diff
+27 -2
View File
@@ -1,13 +1,14 @@
package docker
import (
"github.com/dotcloud/docker/engine"
"net"
)
// FIXME: separate runtime configuration from http api configuration
type DaemonConfig struct {
Pidfile string
GraphPath string
ProtoAddresses []string
Root string
AutoRestart bool
EnableCors bool
Dns []string
@@ -15,4 +16,28 @@ type DaemonConfig struct {
BridgeIface string
DefaultIp net.IP
InterContainerCommunication bool
GraphDriver string
}
// ConfigFromJob creates and returns a new DaemonConfig object
// by parsing the contents of a job's environment.
func ConfigFromJob(job *engine.Job) *DaemonConfig {
var config DaemonConfig
config.Pidfile = job.Getenv("Pidfile")
config.Root = job.Getenv("Root")
config.AutoRestart = job.GetenvBool("AutoRestart")
config.EnableCors = job.GetenvBool("EnableCors")
if dns := job.Getenv("Dns"); dns != "" {
config.Dns = []string{dns}
}
config.EnableIptables = job.GetenvBool("EnableIptables")
if br := job.Getenv("BridgeIface"); br != "" {
config.BridgeIface = br
} else {
config.BridgeIface = DefaultNetworkBridge
}
config.DefaultIp = net.ParseIP(job.Getenv("DefaultIp"))
config.InterContainerCommunication = job.GetenvBool("InterContainerCommunication")
config.GraphDriver = job.Getenv("GraphDriver")
return &config
}
+149
View File
@@ -0,0 +1,149 @@
package docker
import (
"testing"
)
func TestCompareConfig(t *testing.T) {
volumes1 := make(map[string]struct{})
volumes1["/test1"] = struct{}{}
config1 := Config{
Dns: []string{"1.1.1.1", "2.2.2.2"},
PortSpecs: []string{"1111:1111", "2222:2222"},
Env: []string{"VAR1=1", "VAR2=2"},
VolumesFrom: "11111111",
Volumes: volumes1,
}
config2 := Config{
Dns: []string{"0.0.0.0", "2.2.2.2"},
PortSpecs: []string{"1111:1111", "2222:2222"},
Env: []string{"VAR1=1", "VAR2=2"},
VolumesFrom: "11111111",
Volumes: volumes1,
}
config3 := Config{
Dns: []string{"1.1.1.1", "2.2.2.2"},
PortSpecs: []string{"0000:0000", "2222:2222"},
Env: []string{"VAR1=1", "VAR2=2"},
VolumesFrom: "11111111",
Volumes: volumes1,
}
config4 := Config{
Dns: []string{"1.1.1.1", "2.2.2.2"},
PortSpecs: []string{"0000:0000", "2222:2222"},
Env: []string{"VAR1=1", "VAR2=2"},
VolumesFrom: "22222222",
Volumes: volumes1,
}
volumes2 := make(map[string]struct{})
volumes2["/test2"] = struct{}{}
config5 := Config{
Dns: []string{"1.1.1.1", "2.2.2.2"},
PortSpecs: []string{"0000:0000", "2222:2222"},
Env: []string{"VAR1=1", "VAR2=2"},
VolumesFrom: "11111111",
Volumes: volumes2,
}
if CompareConfig(&config1, &config2) {
t.Fatalf("CompareConfig should return false, Dns are different")
}
if CompareConfig(&config1, &config3) {
t.Fatalf("CompareConfig should return false, PortSpecs are different")
}
if CompareConfig(&config1, &config4) {
t.Fatalf("CompareConfig should return false, VolumesFrom are different")
}
if CompareConfig(&config1, &config5) {
t.Fatalf("CompareConfig should return false, Volumes are different")
}
if !CompareConfig(&config1, &config1) {
t.Fatalf("CompareConfig should return true")
}
}
func TestMergeConfig(t *testing.T) {
volumesImage := make(map[string]struct{})
volumesImage["/test1"] = struct{}{}
volumesImage["/test2"] = struct{}{}
configImage := &Config{
Dns: []string{"1.1.1.1", "2.2.2.2"},
PortSpecs: []string{"1111:1111", "2222:2222"},
Env: []string{"VAR1=1", "VAR2=2"},
VolumesFrom: "1111",
Volumes: volumesImage,
}
volumesUser := make(map[string]struct{})
volumesUser["/test3"] = struct{}{}
configUser := &Config{
Dns: []string{"3.3.3.3"},
PortSpecs: []string{"3333:2222", "3333:3333"},
Env: []string{"VAR2=3", "VAR3=3"},
Volumes: volumesUser,
}
if err := MergeConfig(configUser, configImage); err != nil {
t.Error(err)
}
if len(configUser.Dns) != 3 {
t.Fatalf("Expected 3 dns, 1.1.1.1, 2.2.2.2 and 3.3.3.3, found %d", len(configUser.Dns))
}
for _, dns := range configUser.Dns {
if dns != "1.1.1.1" && dns != "2.2.2.2" && dns != "3.3.3.3" {
t.Fatalf("Expected 1.1.1.1 or 2.2.2.2 or 3.3.3.3, found %s", dns)
}
}
if len(configUser.ExposedPorts) != 3 {
t.Fatalf("Expected 3 ExposedPorts, 1111, 2222 and 3333, found %d", len(configUser.ExposedPorts))
}
for portSpecs := range configUser.ExposedPorts {
if portSpecs.Port() != "1111" && portSpecs.Port() != "2222" && portSpecs.Port() != "3333" {
t.Fatalf("Expected 1111 or 2222 or 3333, found %s", portSpecs)
}
}
if len(configUser.Env) != 3 {
t.Fatalf("Expected 3 env var, VAR1=1, VAR2=3 and VAR3=3, found %d", len(configUser.Env))
}
for _, env := range configUser.Env {
if env != "VAR1=1" && env != "VAR2=3" && env != "VAR3=3" {
t.Fatalf("Expected VAR1=1 or VAR2=3 or VAR3=3, found %s", env)
}
}
if len(configUser.Volumes) != 3 {
t.Fatalf("Expected 3 volumes, /test1, /test2 and /test3, found %d", len(configUser.Volumes))
}
for v := range configUser.Volumes {
if v != "/test1" && v != "/test2" && v != "/test3" {
t.Fatalf("Expected /test1 or /test2 or /test3, found %s", v)
}
}
if configUser.VolumesFrom != "1111" {
t.Fatalf("Expected VolumesFrom to be 1111, found %s", configUser.VolumesFrom)
}
ports, _, err := parsePortSpecs([]string{"0000"})
if err != nil {
t.Error(err)
}
configImage2 := &Config{
ExposedPorts: ports,
}
if err := MergeConfig(configUser, configImage2); err != nil {
t.Error(err)
}
if len(configUser.ExposedPorts) != 4 {
t.Fatalf("Expected 4 ExposedPorts, 0000, 1111, 2222 and 3333, found %d", len(configUser.ExposedPorts))
}
for portSpecs := range configUser.ExposedPorts {
if portSpecs.Port() != "0000" && portSpecs.Port() != "1111" && portSpecs.Port() != "2222" && portSpecs.Port() != "3333" {
t.Fatalf("Expected 0000 or 1111 or 2222 or 3333, found %s", portSpecs)
}
}
}
+292 -372
View File
File diff suppressed because it is too large Load Diff
+161
View File
@@ -0,0 +1,161 @@
package docker
import (
"testing"
)
func TestParseLxcConfOpt(t *testing.T) {
opts := []string{"lxc.utsname=docker", "lxc.utsname = docker "}
for _, o := range opts {
k, v, err := parseLxcOpt(o)
if err != nil {
t.FailNow()
}
if k != "lxc.utsname" {
t.Fail()
}
if v != "docker" {
t.Fail()
}
}
}
func TestParseNetworkOptsPrivateOnly(t *testing.T) {
ports, bindings, err := parsePortSpecs([]string{"192.168.1.100::80"})
if err != nil {
t.Fatal(err)
}
if len(ports) != 1 {
t.Logf("Expected 1 got %d", len(ports))
t.FailNow()
}
if len(bindings) != 1 {
t.Logf("Expected 1 got %d", len(bindings))
t.FailNow()
}
for k := range ports {
if k.Proto() != "tcp" {
t.Logf("Expected tcp got %s", k.Proto())
t.Fail()
}
if k.Port() != "80" {
t.Logf("Expected 80 got %s", k.Port())
t.Fail()
}
b, exists := bindings[k]
if !exists {
t.Log("Binding does not exist")
t.FailNow()
}
if len(b) != 1 {
t.Logf("Expected 1 got %d", len(b))
t.FailNow()
}
s := b[0]
if s.HostPort != "" {
t.Logf("Expected \"\" got %s", s.HostPort)
t.Fail()
}
if s.HostIp != "192.168.1.100" {
t.Fail()
}
}
}
func TestParseNetworkOptsPublic(t *testing.T) {
ports, bindings, err := parsePortSpecs([]string{"192.168.1.100:8080:80"})
if err != nil {
t.Fatal(err)
}
if len(ports) != 1 {
t.Logf("Expected 1 got %d", len(ports))
t.FailNow()
}
if len(bindings) != 1 {
t.Logf("Expected 1 got %d", len(bindings))
t.FailNow()
}
for k := range ports {
if k.Proto() != "tcp" {
t.Logf("Expected tcp got %s", k.Proto())
t.Fail()
}
if k.Port() != "80" {
t.Logf("Expected 80 got %s", k.Port())
t.Fail()
}
b, exists := bindings[k]
if !exists {
t.Log("Binding does not exist")
t.FailNow()
}
if len(b) != 1 {
t.Logf("Expected 1 got %d", len(b))
t.FailNow()
}
s := b[0]
if s.HostPort != "8080" {
t.Logf("Expected 8080 got %s", s.HostPort)
t.Fail()
}
if s.HostIp != "192.168.1.100" {
t.Fail()
}
}
}
func TestParseNetworkOptsUdp(t *testing.T) {
ports, bindings, err := parsePortSpecs([]string{"192.168.1.100::6000/udp"})
if err != nil {
t.Fatal(err)
}
if len(ports) != 1 {
t.Logf("Expected 1 got %d", len(ports))
t.FailNow()
}
if len(bindings) != 1 {
t.Logf("Expected 1 got %d", len(bindings))
t.FailNow()
}
for k := range ports {
if k.Proto() != "udp" {
t.Logf("Expected udp got %s", k.Proto())
t.Fail()
}
if k.Port() != "6000" {
t.Logf("Expected 6000 got %s", k.Port())
t.Fail()
}
b, exists := bindings[k]
if !exists {
t.Log("Binding does not exist")
t.FailNow()
}
if len(b) != 1 {
t.Logf("Expected 1 got %d", len(b))
t.FailNow()
}
s := b[0]
if s.HostPort != "" {
t.Logf("Expected \"\" got %s", s.HostPort)
t.Fail()
}
if s.HostIp != "192.168.1.100" {
t.Fail()
}
}
}
func TestGetFullName(t *testing.T) {
name, err := getFullName("testing")
if err != nil {
t.Fatal(err)
}
if name != "/testing" {
t.Fatalf("Expected /testing got %s", name)
}
if _, err := getFullName(""); err == nil {
t.Fatal("Error should not be nil")
}
}
+1 -1
View File
@@ -426,7 +426,7 @@ _docker_run()
_docker_search()
{
COMPREPLY=( $( compgen -W "-notrunc" -- "$cur" ) )
COMPREPLY=( $( compgen -W "-notrunc" "-stars" "-trusted" -- "$cur" ) )
}
_docker_start()
+11
View File
@@ -0,0 +1,11 @@
Desktop Integration
===================
The ./contrib/desktop-integration contains examples of typical dockerized
desktop applications.
Examples
========
* Data container: ./data/Dockerfile creates a data image sharing /data volume
* Firefox: ./firefox/Dockerfile shows a way to dockerize a common multimedia application
@@ -0,0 +1,38 @@
# VERSION: 0.1
# DESCRIPTION: Create data image sharing /data volume
# AUTHOR: Daniel Mizyrycki <daniel@dotcloud.com>
# COMMENTS:
# This image is used as base for all data containers.
# /data volume is owned by sysadmin.
# USAGE:
# # Download data Dockerfile
# wget http://raw.github.com/dotcloud/docker/master/contrib/desktop-integration/data/Dockerfile
#
# # Build data image
# docker build -t data -rm .
#
# # Create a data container. (eg: firefox-data)
# docker run -name firefox-data data true
#
# # List data from it
# docker run -volumes-from firefox-data busybox ls -al /data
docker-version 0.6.5
# Smallest base image, just to launch a container
from busybox
maintainer Daniel Mizyrycki <daniel@docker.com>
# Create a regular user
run echo 'sysadmin:x:1000:1000::/data:/bin/sh' >> /etc/passwd
run echo 'sysadmin:x:1000:' >> /etc/group
# Create directory for that user
run mkdir /data
run chown sysadmin.sysadmin /data
# Add content to /data. This will keep sysadmin ownership
run touch /data/init_volume
# Create /data volume
VOLUME /data
@@ -0,0 +1,49 @@
# VERSION: 0.7
# DESCRIPTION: Create firefox container with its dependencies
# AUTHOR: Daniel Mizyrycki <daniel@dotcloud.com>
# COMMENTS:
# This file describes how to build a Firefox container with all
# dependencies installed. It uses native X11 unix socket and alsa
# sound devices. Tested on Debian 7.2
# USAGE:
# # Download Firefox Dockerfile
# wget http://raw.github.com/dotcloud/docker/master/contrib/desktop-integration/firefox/Dockerfile
#
# # Build firefox image
# docker build -t firefox -rm .
#
# # Run stateful data-on-host firefox. For ephemeral, remove -v /data/firefox:/data
# docker run -v /data/firefox:/data -v /tmp/.X11-unix:/tmp/.X11-unix \
# -v /dev/snd:/dev/snd -lxc-conf='lxc.cgroup.devices.allow = c 116:* rwm' \
# -e DISPLAY=unix$DISPLAY firefox
#
# # To run stateful dockerized data containers
# docker run -volumes-from firefox-data -v /tmp/.X11-unix:/tmp/.X11-unix \
# -v /dev/snd:/dev/snd -lxc-conf='lxc.cgroup.devices.allow = c 116:* rwm' \
# -e DISPLAY=unix$DISPLAY firefox
docker-version 0.6.5
# Base docker image
from tianon/debian:wheezy
maintainer Daniel Mizyrycki <daniel@docker.com>
# Install firefox dependencies
run echo "deb http://ftp.debian.org/debian/ wheezy main contrib" > /etc/apt/sources.list
run apt-get update
run DEBIAN_FRONTEND=noninteractive apt-get install -y libXrender1 libasound2 \
libdbus-glib-1-2 libgtk2.0-0 libpango1.0-0 libxt6 wget bzip2 sudo
# Install Firefox
run mkdir /application
run cd /application; wget -O - \
http://ftp.mozilla.org/pub/mozilla.org/firefox/releases/25.0/linux-x86_64/en-US/firefox-25.0.tar.bz2 | tar jx
# create sysadmin account
run useradd -m -d /data -p saIVpsc0EVTwA sysadmin
run sed -Ei 's/sudo:x:27:/sudo:x:27:sysadmin/' /etc/group
run sed -Ei 's/(\%sudo\s+ALL=\(ALL\:ALL\) )ALL/\1 NOPASSWD:ALL/' /etc/sudoers
# Autorun firefox. -no-remote is necessary to create a new container, as firefox
# appears to communicate with itself through X11.
cmd ["/bin/sh", "-c", "/usr/bin/sudo -u sysadmin -H -E /application/firefox/firefox -no-remote"]
+170
View File
@@ -0,0 +1,170 @@
package main
import (
"flag"
"fmt"
"github.com/dotcloud/docker/graphdriver/devmapper"
"os"
"path"
"sort"
"strconv"
"strings"
)
func usage() {
fmt.Fprintf(os.Stderr, "Usage: %s <flags> [status] | [list] | [device id] | [resize new-pool-size] | [snap new-id base-id] | [remove id] | [mount id mountpoint]\n", os.Args[0])
flag.PrintDefaults()
os.Exit(1)
}
func byteSizeFromString(arg string) (int64, error) {
digits := ""
rest := ""
last := strings.LastIndexAny(arg, "0123456789")
if last >= 0 {
digits = arg[:last+1]
rest = arg[last+1:]
}
val, err := strconv.ParseInt(digits, 10, 64)
if err != nil {
return val, err
}
rest = strings.ToLower(strings.TrimSpace(rest))
var multiplier int64 = 1
switch rest {
case "":
multiplier = 1
case "k", "kb":
multiplier = 1024
case "m", "mb":
multiplier = 1024 * 1024
case "g", "gb":
multiplier = 1024 * 1024 * 1024
case "t", "tb":
multiplier = 1024 * 1024 * 1024 * 1024
default:
return 0, fmt.Errorf("Unknown size unit: %s", rest)
}
return val * multiplier, nil
}
func main() {
root := flag.String("r", "/var/lib/docker", "Docker root dir")
flDebug := flag.Bool("D", false, "Debug mode")
flag.Parse()
if *flDebug {
os.Setenv("DEBUG", "1")
}
if flag.NArg() < 1 {
usage()
}
args := flag.Args()
home := path.Join(*root, "devicemapper")
devices, err := devmapper.NewDeviceSet(home, false)
if err != nil {
fmt.Println("Can't initialize device mapper: ", err)
os.Exit(1)
}
switch args[0] {
case "status":
status := devices.Status()
fmt.Printf("Pool name: %s\n", status.PoolName)
fmt.Printf("Data Loopback file: %s\n", status.DataLoopback)
fmt.Printf("Metadata Loopback file: %s\n", status.MetadataLoopback)
fmt.Printf("Sector size: %d\n", status.SectorSize)
fmt.Printf("Data use: %d of %d (%.1f %%)\n", status.Data.Used, status.Data.Total, 100.0*float64(status.Data.Used)/float64(status.Data.Total))
fmt.Printf("Metadata use: %d of %d (%.1f %%)\n", status.Metadata.Used, status.Metadata.Total, 100.0*float64(status.Metadata.Used)/float64(status.Metadata.Total))
break
case "list":
ids := devices.List()
sort.Strings(ids)
for _, id := range ids {
fmt.Println(id)
}
break
case "device":
if flag.NArg() < 2 {
usage()
}
status, err := devices.GetDeviceStatus(args[1])
if err != nil {
fmt.Println("Can't get device info: ", err)
os.Exit(1)
}
fmt.Printf("Id: %d\n", status.DeviceId)
fmt.Printf("Size: %d\n", status.Size)
fmt.Printf("Transaction Id: %d\n", status.TransactionId)
fmt.Printf("Size in Sectors: %d\n", status.SizeInSectors)
fmt.Printf("Mapped Sectors: %d\n", status.MappedSectors)
fmt.Printf("Highest Mapped Sector: %d\n", status.HighestMappedSector)
break
case "resize":
if flag.NArg() < 2 {
usage()
}
size, err := byteSizeFromString(args[1])
if err != nil {
fmt.Println("Invalid size: ", err)
os.Exit(1)
}
err = devices.ResizePool(size)
if err != nil {
fmt.Println("Error resizeing pool: ", err)
os.Exit(1)
}
break
case "snap":
if flag.NArg() < 3 {
usage()
}
err := devices.AddDevice(args[1], args[2])
if err != nil {
fmt.Println("Can't create snap device: ", err)
os.Exit(1)
}
break
case "remove":
if flag.NArg() < 2 {
usage()
}
err := devices.RemoveDevice(args[1])
if err != nil {
fmt.Println("Can't remove device: ", err)
os.Exit(1)
}
break
case "mount":
if flag.NArg() < 3 {
usage()
}
err := devices.MountDevice(args[1], args[2], false)
if err != nil {
fmt.Println("Can't create snap device: ", err)
os.Exit(1)
}
break
default:
fmt.Printf("Unknown command %s\n", args[0])
usage()
os.Exit(1)
}
return
}
+1 -1
View File
@@ -1,5 +1,5 @@
[Unit]
Description=Easily create lightweight, portable, self-sufficient containers from any application!
Description=Docker Application Container Engine
Documentation=http://docs.docker.io
Requires=network.target
After=multi-user.target
+32 -21
View File
@@ -6,43 +6,54 @@
# Required-Stop: $syslog $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Linux container runtime
# Description: Linux container runtime
# Short-Description: Create lightweight, portable, self-sufficient containers.
# Description:
# Docker is an open-source project to easily create lightweight, portable,
# self-sufficient containers from any application. The same container that a
# developer builds and tests on a laptop can run at scale, in production, on
# VMs, bare metal, OpenStack clusters, public clouds and more.
### END INIT INFO
DOCKER=/usr/bin/docker
DOCKER_PIDFILE=/var/run/docker.pid
BASE=$(basename $0)
DOCKER=/usr/bin/$BASE
DOCKER_PIDFILE=/var/run/$BASE.pid
DOCKER_OPTS=
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
# Check lxc-docker is present
[ -x $DOCKER ] || (log_failure_msg "docker not present"; exit 1)
# Get lsb functions
. /lib/lsb/init-functions
if [ -f /etc/default/lxc ]; then
. /etc/default/lxc
if [ -f /etc/default/$BASE ]; then
. /etc/default/$BASE
fi
if [ "$1" = start ] && which initctl >/dev/null && initctl version | grep -q upstart; then
# see also init_is_upstart in /lib/lsb/init-functions (which isn't available in Ubuntu 12.04, or we'd use it)
if [ -x /sbin/initctl ] && /sbin/initctl version 2>/dev/null | /bin/grep -q upstart; then
log_failure_msg "Docker is managed via upstart, try using service $BASE $1"
exit 1
fi
check_root_id ()
{
if [ "$(id -u)" != "0" ]; then
log_failure_msg "Docker must be run as root"; exit 1
# Check docker is present
if [ ! -x $DOCKER ]; then
log_failure_msg "$DOCKER not present or not executable"
exit 1
fi
fail_unless_root() {
if [ "$(id -u)" != '0' ]; then
log_failure_msg "Docker must be run as root"
exit 1
fi
}
case "$1" in
start)
check_root_id || exit 1
log_begin_msg "Starting Docker"
fail_unless_root
log_begin_msg "Starting Docker: $BASE"
mount | grep cgroup >/dev/null || mount -t cgroup none /sys/fs/cgroup 2>/dev/null
start-stop-daemon --start --background $NO_CLOSE \
start-stop-daemon --start --background \
--exec "$DOCKER" \
--pidfile "$DOCKER_PIDFILE" \
-- -d -p "$DOCKER_PIDFILE" \
@@ -51,15 +62,15 @@ case "$1" in
;;
stop)
check_root_id || exit 1
log_begin_msg "Stopping Docker"
fail_unless_root
log_begin_msg "Stopping Docker: $BASE"
start-stop-daemon --stop \
--pidfile "$DOCKER_PIDFILE"
log_end_msg $?
;;
restart)
check_root_id || exit 1
fail_unless_root
docker_pid=`cat "$DOCKER_PIDFILE" 2>/dev/null`
[ -n "$docker_pid" ] \
&& ps -p $docker_pid > /dev/null 2>&1 \
@@ -68,7 +79,7 @@ case "$1" in
;;
force-reload)
check_root_id || exit 1
fail_unless_root
$0 restart
;;
+6 -1
View File
@@ -6,5 +6,10 @@ stop on runlevel [!2345]
respawn
script
/usr/bin/docker -d
DOCKER=/usr/bin/$UPSTART_JOB
DOCKER_OPTS=
if [ -f /etc/default/$UPSTART_JOB ]; then
. /etc/default/$UPSTART_JOB
fi
"$DOCKER" -d $DOCKER_OPTS
end script
+5 -5
View File
@@ -192,7 +192,7 @@ if [ "$justTar" ]; then
sudo tar --numeric-owner -caf "$repo" .
else
# create the image (and tag $repo:$suite)
sudo tar --numeric-owner -c . | $docker import - $repo $suite
sudo tar --numeric-owner -c . | $docker import - $repo:$suite
# test the image
$docker run -i -t $repo:$suite echo success
@@ -202,25 +202,25 @@ else
Debian)
if [ "$suite" = "$debianStable" -o "$suite" = 'stable' ] && [ -r etc/debian_version ]; then
# tag latest
$docker tag $repo:$suite $repo latest
$docker tag $repo:$suite $repo:latest
if [ -r etc/debian_version ]; then
# tag the specific debian release version (which is only reasonable to tag on debian stable)
ver=$(cat etc/debian_version)
$docker tag $repo:$suite $repo $ver
$docker tag $repo:$suite $repo:$ver
fi
fi
;;
Ubuntu)
if [ "$suite" = "$ubuntuLatestLTS" ]; then
# tag latest
$docker tag $repo:$suite $repo latest
$docker tag $repo:$suite $repo:latest
fi
if [ -r etc/lsb-release ]; then
lsbRelease="$(. etc/lsb-release && echo "$DISTRIB_RELEASE")"
if [ "$lsbRelease" ]; then
# tag specific Ubuntu version number, if available (12.04, etc.)
$docker tag $repo:$suite $repo $lsbRelease
$docker tag $repo:$suite $repo:$lsbRelease
fi
fi
;;
+18 -2
View File
@@ -1,3 +1,19 @@
# Vagrant-docker
# Vagrant integration
This is a placeholder for the official vagrant-docker, a plugin for Vagrant (http://vagrantup.com) which exposes Docker as a provider.
Currently there are at least 4 different projects that we are aware of that deals
with integration with [Vagrant](http://vagrantup.com/) at different levels. One
approach is to use Docker as a [provisioner](http://docs.vagrantup.com/v2/provisioning/index.html)
which means you can create containers and pull base images on VMs using Docker's
CLI and the other is to use Docker as a [provider](http://docs.vagrantup.com/v2/providers/index.html),
meaning you can use Vagrant to control Docker containers.
### Provisioners
* [Vocker](https://github.com/fgrehm/vocker)
* [Ventriloquist](https://github.com/fgrehm/ventriloquist)
### Providers
* [docker-provider](https://github.com/fgrehm/docker-provider)
* [vagrant-shell](https://github.com/destructuring/vagrant-shell)
+33 -113
View File
@@ -4,16 +4,12 @@ import (
"flag"
"fmt"
"github.com/dotcloud/docker"
"github.com/dotcloud/docker/engine"
"github.com/dotcloud/docker/sysinit"
"github.com/dotcloud/docker/utils"
"io/ioutil"
"log"
"net"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
)
var (
@@ -29,19 +25,20 @@ func main() {
}
// 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")
flDaemon := flag.Bool("d", false, "Enable daemon mode")
flDebug := flag.Bool("D", false, "Enable debug mode")
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")
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", "Path to use for daemon PID file")
flRoot := flag.String("g", "/var/lib/docker", "Path to use as the root of the docker runtime")
flEnableCors := flag.Bool("api-enable-cors", false, "Enable CORS headers in the remote API")
flDns := flag.String("dns", "", "Force docker to use specific DNS servers")
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")
flag.Var(&flHosts, "H", "Multiple tcp://host:port or unix://path/to/socket to bind in daemon mode, single connection otherwise")
flEnableIptables := flag.Bool("iptables", true, "Disable docker's addition of iptables rules")
flDefaultIp := flag.String("ip", "0.0.0.0", "Default IP address to use when binding container ports")
flInterContainerComm := flag.Bool("icc", true, "Enable inter-container communication")
flGraphDriver := flag.String("graph-driver", "", "Force docker runtime to use a specific graph driver")
flag.Parse()
@@ -61,10 +58,6 @@ func main() {
}
}
bridge := docker.DefaultNetworkBridge
if *bridgeName != "" {
bridge = *bridgeName
}
if *flDebug {
os.Setenv("DEBUG", "1")
}
@@ -75,26 +68,29 @@ func main() {
flag.Usage()
return
}
var dns []string
if *flDns != "" {
dns = []string{*flDns}
eng, err := engine.New(*flRoot)
if err != nil {
log.Fatal(err)
}
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,
// Load plugin: httpapi
job := eng.Job("initapi")
job.Setenv("Pidfile", *pidfile)
job.Setenv("Root", *flRoot)
job.SetenvBool("AutoRestart", *flAutoRestart)
job.SetenvBool("EnableCors", *flEnableCors)
job.Setenv("Dns", *flDns)
job.SetenvBool("EnableIptables", *flEnableIptables)
job.Setenv("BridgeIface", *bridgeName)
job.Setenv("DefaultIp", *flDefaultIp)
job.SetenvBool("InterContainerCommunication", *flInterContainerComm)
job.Setenv("GraphDriver", *flGraphDriver)
if err := job.Run(); err != nil {
log.Fatal(err)
}
if err := daemon(config); err != nil {
// Serve api
job = eng.Job("serveapi", flHosts...)
job.SetenvBool("Logging", true)
if err := job.Run(); err != nil {
log.Fatal(err)
}
} else {
@@ -114,79 +110,3 @@ func main() {
func showVersion() {
fmt.Printf("Docker version %s, build %s\n", VERSION, GITCOMMIT)
}
func createPidFile(pidfile string) error {
if pidString, err := ioutil.ReadFile(pidfile); err == nil {
pid, err := strconv.Atoi(string(pidString))
if err == nil {
if _, err := os.Stat(fmt.Sprintf("/proc/%d/", pid)); err == nil {
return fmt.Errorf("pid file found, ensure docker is not running or delete %s", pidfile)
}
}
}
file, err := os.Create(pidfile)
if err != nil {
return err
}
defer file.Close()
_, err = fmt.Fprintf(file, "%d", os.Getpid())
return err
}
func removePidFile(pidfile string) {
if err := os.Remove(pidfile); err != nil {
log.Printf("Error removing %s: %s", pidfile, err)
}
}
func daemon(config *docker.DaemonConfig) error {
if err := createPidFile(config.Pidfile); err != nil {
log.Fatal(err)
}
defer removePidFile(config.Pidfile)
server, err := docker.NewServer(config)
if err != nil {
return err
}
defer server.Close()
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, os.Kill, os.Signal(syscall.SIGTERM))
go func() {
sig := <-c
log.Printf("Received signal '%v', exiting\n", sig)
server.Close()
removePidFile(config.Pidfile)
os.Exit(0)
}()
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])
} else if protoAddrParts[0] == "tcp" {
if !strings.HasPrefix(protoAddrParts[1], "127.0.0.1") {
log.Println("/!\\ DON'T BIND ON ANOTHER IP ADDRESS THAN 127.0.0.1 IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
}
} else {
server.Close()
removePidFile(config.Pidfile)
log.Fatal("Invalid protocol format.")
}
go func() {
chErrors <- docker.ListenAndServe(protoAddrParts[0], protoAddrParts[1], server, true)
}()
}
for i := 0; i < len(config.ProtoAddresses); i += 1 {
err := <-chErrors
if err != nil {
return err
}
}
return nil
}
+1 -1
View File
@@ -31,7 +31,7 @@ help:
# @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
# @echo " latexpdf to make LaTeX files and run them through pdflatex"
# @echo " text to make text files"
# @echo " man to make manual pages"
@echo " man to make a manual page"
# @echo " texinfo to make Texinfo files"
# @echo " info to make Texinfo files and run them through makeinfo"
# @echo " gettext to make PO message catalogs"
+1 -1
View File
@@ -1,2 +1,2 @@
Sphinx==1.1.3
sphinxcontrib-httpdomain==1.1.8
sphinxcontrib-httpdomain==1.1.9
+106 -2
View File
@@ -26,14 +26,118 @@ Docker Remote API
2. Versions
===========
The current version of the API is 1.6
The current version of the API is 1.7
Calling /images/<name>/insert is the same as calling
/v1.6/images/<name>/insert
/v1.7/images/<name>/insert
You can still call an old version of the api using
/v1.0/images/<name>/insert
v1.7
****
Full Documentation
------------------
:doc:`docker_remote_api_v1.7`
What's new
----------
.. http:get:: /images/json
The format of the json returned from this uri changed. Instead of an entry
for each repo/tag on an image, each image is only represented once, with a
nested attribute indicating the repo/tags that apply to that image.
Instead of:
.. sourcecode:: http
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"VirtualSize": 131506275,
"Size": 131506275,
"Created": 1365714795,
"Id": "8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c",
"Tag": "12.04",
"Repository": "ubuntu"
},
{
"VirtualSize": 131506275,
"Size": 131506275,
"Created": 1365714795,
"Id": "8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c",
"Tag": "latest",
"Repository": "ubuntu"
},
{
"VirtualSize": 131506275,
"Size": 131506275,
"Created": 1365714795,
"Id": "8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c",
"Tag": "precise",
"Repository": "ubuntu"
},
{
"VirtualSize": 180116135,
"Size": 24653,
"Created": 1364102658,
"Id": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
"Tag": "12.10",
"Repository": "ubuntu"
},
{
"VirtualSize": 180116135,
"Size": 24653,
"Created": 1364102658,
"Id": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
"Tag": "quantal",
"Repository": "ubuntu"
}
]
The returned json looks like this:
.. sourcecode:: http
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"RepoTag": [
"ubuntu:12.04",
"ubuntu:precise",
"ubuntu:latest"
],
"Id": "8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c",
"Created": 1365714795,
"Size": 131506275,
"VirtualSize": 131506275
},
{
"RepoTag": [
"ubuntu:12.10",
"ubuntu:quantal"
],
"ParentId": "27cf784147099545",
"Id": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
"Created": 1364102658,
"Size": 24653,
"VirtualSize": 180116135
}
]
.. http:get:: /images/viz
This URI no longer exists. The ``images -viz`` output is now generated in
the client, using the ``/images/json`` data.
v1.6
****
+19 -19
View File
@@ -943,36 +943,36 @@ Build an image from Dockerfile via stdin
.. http:post:: /build
Build an image from Dockerfile via stdin
Build an image from Dockerfile via stdin
**Example request**:
**Example request**:
.. sourcecode:: http
.. sourcecode:: http
POST /build HTTP/1.1
POST /build HTTP/1.1
{{ STREAM }}
{{ STREAM }}
**Example response**:
**Example response**:
.. sourcecode:: http
.. sourcecode:: http
HTTP/1.1 200 OK
HTTP/1.1 200 OK
{{ STREAM }}
{{ STREAM }}
The stream must be a tar archive compressed with one of the following algorithms:
identity (no compression), gzip, bzip2, xz. The archive must include a file called
`Dockerfile` at its root. It may include any number of other files, which will be
accessible in the build context (See the ADD build command).
The stream must be a tar archive compressed with one of the following algorithms:
identity (no compression), gzip, bzip2, xz. The archive must include a file called
`Dockerfile` at its root. It may include any number of other files, which will be
accessible in the build context (See the ADD build command).
The Content-type header should be set to "application/tar".
The Content-type header should be set to "application/tar".
:query t: repository name (and optionally a tag) to be applied to the resulting image in case of success
:query q: suppress verbose build output
:query t: repository name (and optionally a tag) to be applied to the resulting image in case of success
:query q: suppress verbose build output
:query nocache: do not use the cache when building the image
:statuscode 200: no error
:statuscode 200: no error
:statuscode 500: server error
@@ -1069,8 +1069,8 @@ Show the docker version information
"GoVersion":"go1.0.3"
}
:statuscode 200: no error
:statuscode 500: server error
:statuscode 200: no error
:statuscode 500: server error
Create a new image from a container's changes
+79 -25
View File
@@ -121,8 +121,7 @@ Create a container
"AttachStdin":false,
"AttachStdout":true,
"AttachStderr":true,
"PortSpecs":null,
"Privileged": false,
"ExposedPorts":{},
"Tty":false,
"OpenStdin":false,
"StdinOnce":false,
@@ -135,7 +134,6 @@ Create a container
"Volumes":{},
"VolumesFrom":"",
"WorkingDir":""
}
**Example response**:
@@ -157,6 +155,57 @@ Create a container
:statuscode 406: impossible to attach (container not running)
:statuscode 500: server error
**More Complex Example request, in 2 steps.**
**First, use create to expose a Private Port, which can be bound back to a Public Port at startup**:
.. sourcecode:: http
POST /containers/create HTTP/1.1
Content-Type: application/json
{
"Cmd":[
"/usr/sbin/sshd","-D"
],
"Image":"image-with-sshd",
"ExposedPorts":{"22/tcp":{}}
}
**Example response**:
.. sourcecode:: http
HTTP/1.1 201 OK
Content-Type: application/json
{
"Id":"e90e34656806"
"Warnings":[]
}
**Second, start (using the ID returned above) the image we just created, mapping the ssh port 22 to something on the host**:
.. sourcecode:: http
POST /containers/e90e34656806/start HTTP/1.1
Content-Type: application/json
{
"PortBindings": { "22/tcp": [{ "HostPort": "11022" }]}
}
**Example response**:
.. sourcecode:: http
HTTP/1.1 204 No Content
Content-Type: text/plain; charset=utf-8
Content-Length: 0
**Now you can ssh into your new container on port 11022.**
Inspect a container
*******************
@@ -191,7 +240,7 @@ Inspect a container
"AttachStdin": false,
"AttachStdout": true,
"AttachStderr": true,
"PortSpecs": null,
"ExposedPorts": {},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
@@ -362,7 +411,12 @@ Start a container
{
"Binds":["/tmp:/tmp"],
"LxcConf":{"lxc.utsname":"docker"}
"LxcConf":{"lxc.utsname":"docker"},
"ContainerIDFile": "",
"Privileged": false,
"PortBindings": {"22/tcp": [{HostIp:"", HostPort:""}]},
"Links": [],
"PublishAllPorts": false
}
**Example response**:
@@ -795,7 +849,7 @@ Inspect an image
"AttachStdin":false,
"AttachStdout":false,
"AttachStderr":false,
"PortSpecs":null,
"ExposedPorts":{},
"Tty":true,
"OpenStdin":true,
"StdinOnce":false,
@@ -995,36 +1049,36 @@ Build an image from Dockerfile via stdin
.. http:post:: /build
Build an image from Dockerfile via stdin
Build an image from Dockerfile via stdin
**Example request**:
**Example request**:
.. sourcecode:: http
.. sourcecode:: http
POST /build HTTP/1.1
POST /build HTTP/1.1
{{ STREAM }}
{{ STREAM }}
**Example response**:
**Example response**:
.. sourcecode:: http
.. sourcecode:: http
HTTP/1.1 200 OK
HTTP/1.1 200 OK
{{ STREAM }}
{{ STREAM }}
The stream must be a tar archive compressed with one of the following algorithms:
identity (no compression), gzip, bzip2, xz. The archive must include a file called
`Dockerfile` at its root. It may include any number of other files, which will be
accessible in the build context (See the ADD build command).
The stream must be a tar archive compressed with one of the following algorithms:
identity (no compression), gzip, bzip2, xz. The archive must include a file called
`Dockerfile` at its root. It may include any number of other files, which will be
accessible in the build context (See the ADD build command).
The Content-type header should be set to "application/tar".
The Content-type header should be set to "application/tar".
:query t: repository name (and optionally a tag) to be applied to the resulting image in case of success
:query q: suppress verbose build output
:query t: repository name (and optionally a tag) to be applied to the resulting image in case of success
:query q: suppress verbose build output
:query nocache: do not use the cache when building the image
:statuscode 200: no error
:statuscode 200: no error
:statuscode 500: server error
@@ -1141,7 +1195,7 @@ Create a new image from a container's changes
{
"Cmd": ["cat", "/world"],
"PortSpecs":["22"]
"ExposedPorts":{"22/tcp":{}}
}
**Example response**:
File diff suppressed because it is too large Load Diff
@@ -1,4 +1,4 @@
:title: Registry API
:title: Remote API Client Libraries
: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
@@ -12,26 +12,28 @@ 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 |
+----------------------+----------------+--------------------------------------------+
+----------------------+----------------+--------------------------------------------+----------+
| Language/Framework | Name | Repository | Status |
+======================+================+============================================+==========+
| Python | docker-py | https://github.com/dotcloud/docker-py | Active |
+----------------------+----------------+--------------------------------------------+----------+
| Ruby | docker-client | https://github.com/geku/docker-client | Outdated |
+----------------------+----------------+--------------------------------------------+----------+
| Ruby | docker-api | https://github.com/swipely/docker-api | Active |
+----------------------+----------------+--------------------------------------------+----------+
| Javascript (NodeJS) | docker.io | https://github.com/appersonlabs/docker.io | Active |
| | | Install via NPM: `npm install docker.io` | |
+----------------------+----------------+--------------------------------------------+----------+
| Javascript | docker-js | https://github.com/dgoujard/docker-js | Active |
+----------------------+----------------+--------------------------------------------+----------+
| Javascript (Angular) | dockerui | https://github.com/crosbymichael/dockerui | Active |
| **WebUI** | | | |
+----------------------+----------------+--------------------------------------------+----------+
| Java | docker-java | https://github.com/kpelykh/docker-java | Active |
+----------------------+----------------+--------------------------------------------+----------+
| Erlang | erldocker | https://github.com/proger/erldocker | Active |
+----------------------+----------------+--------------------------------------------+----------+
| Go | go-dockerclient| https://github.com/fsouza/go-dockerclient | Active |
+----------------------+----------------+--------------------------------------------+----------+
| PHP | Alvine | http://pear.alvine.io/ (alpha) | Active |
+----------------------+----------------+--------------------------------------------+----------+
+353 -73
View File
@@ -41,7 +41,7 @@ To stop a container, use ``docker stop``
To kill the container, use ``docker kill``
.. _cli_attach_examples:
Examples:
~~~~~~~~~
@@ -55,8 +55,8 @@ Examples:
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
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
@@ -64,8 +64,8 @@ Examples:
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
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
@@ -74,9 +74,9 @@ Examples:
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$
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:
@@ -88,31 +88,65 @@ Examples:
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.
-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
The files at PATH or URL are called the "context" of the build. The
build process may refer to any of the files in the context, for
example when using an :ref:`ADD <dockerfile_add>` instruction. When a
single ``Dockerfile`` is given as URL, then no context is set. When a
git repository is set as URL, then the repository is used as the
context
.. _cli_build_examples:
.. seealso:: :ref:`dockerbuilder`.
Examples:
~~~~~~~~~
.. code-block:: bash
sudo docker build .
Uploading context 10240 bytes
Step 1 : FROM busybox
Pulling repository busybox
---> e9aa60c60128MB/2.284 MB (100%) endpoint: https://cdn-registry-1.docker.io/v1/
Step 2 : RUN ls -lh /
---> Running in 9c9e81692ae9
total 24
drwxr-xr-x 2 root root 4.0K Mar 12 2013 bin
drwxr-xr-x 5 root root 4.0K Oct 19 00:19 dev
drwxr-xr-x 2 root root 4.0K Oct 19 00:19 etc
drwxr-xr-x 2 root root 4.0K Nov 15 23:34 lib
lrwxrwxrwx 1 root root 3 Mar 12 2013 lib64 -> lib
dr-xr-xr-x 116 root root 0 Nov 15 23:34 proc
lrwxrwxrwx 1 root root 3 Mar 12 2013 sbin -> bin
dr-xr-xr-x 13 root root 0 Nov 15 23:34 sys
drwxr-xr-x 2 root root 4.0K Mar 12 2013 tmp
drwxr-xr-x 2 root root 4.0K Nov 15 23:34 usr
---> b35f4035db3f
Step 3 : CMD echo Hello World
---> Running in 02071fceb21b
---> f52f38b7823e
Successfully built f52f38b7823e
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.
This example specifies that the PATH is ``.``, and so all the files in
the local directory get tar'd and sent to the Docker daemon. The PATH
specifies where to find the files for the "context" of the build on
the Docker daemon. Remember that the daemon could be running on a
remote machine and that no parsing of the Dockerfile happens at the
client side (where you're running ``docker build``). That means that
*all* the files at PATH get sent, not just the ones listed to
:ref:`ADD <dockerfile_add>` in the ``Dockerfile``.
The transfer of context from the local machine to the Docker daemon is
what the ``docker`` client means when you see the "Uploading context"
message.
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
@@ -129,17 +163,15 @@ tag will be ``2.0``
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.
to the ``docker`` daemon. Since there is no context, a Dockerfile
``ADD`` only works if it refers to a remote URL.
.. 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
This will clone the Github repository and use the cloned repository 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.
@@ -151,16 +183,35 @@ by using the ``git://`` schema.
::
Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY [TAG]]
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"]}')
-run="": Configuration to be applied when the image is launched with `docker run`.
(ex: -run='{"Cmd": ["cat", "/world"], "PortSpecs": ["22"]}')
Full -run example (multiline is ok within a single quote ``'``)
Simple commit of an existing container
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: bash
$ docker ps
ID IMAGE COMMAND CREATED STATUS PORTS
c3f279d17e0a ubuntu:12.04 /bin/bash 7 days ago Up 25 hours
197387f1b436 ubuntu:12.04 /bin/bash 7 days ago Up 25 hours
$ docker commit c3f279d17e0a SvenDowideit/testimage:version3
f5283438590d
$ docker images | head
REPOSITORY TAG ID CREATED SIZE
SvenDowideit/testimage version3 f5283438590d 16 seconds ago 204.2 MB (virtual 335.7 MB)
Full -run example
.................
(multiline is ok within a single quote ``'``)
::
@@ -201,10 +252,15 @@ Full -run example (multiline is ok within a single quote ``'``)
::
Usage: docker cp CONTAINER:RESOURCE HOSTPATH
Usage: docker cp CONTAINER:PATH HOSTPATH
Copy files/folders from the containers filesystem to the host
path. Paths are relative to the root of the filesystem.
.. code-block:: bash
$ sudo docker cp 7bb0e258aefe:/etc/debian_version .
$ sudo docker cp blue_frog:/etc/hosts .
.. _cli_diff:
@@ -213,9 +269,33 @@ Full -run example (multiline is ok within a single quote ``'``)
::
Usage: docker diff CONTAINER [OPTIONS]
Usage: docker diff CONTAINER
List the changed files and directories in a container's filesystem
Inspect changes on a container's filesystem
There are 3 events that are listed in the 'diff':
1. ```A``` - Add
2. ```D``` - Delete
3. ```C``` - Change
for example:
.. code-block:: bash
$ sudo docker diff 7bb0e258aefe
C /dev
A /dev/kmsg
C /etc
A /etc/mtab
A /go
A /go/src
A /go/src/github.com
A /go/src/github.com/dotcloud
A /go/src/github.com/dotcloud/docker
A /go/src/github.com/dotcloud/docker/.git
....
.. _cli_events:
@@ -227,6 +307,9 @@ Full -run example (multiline is ok within a single quote ``'``)
Usage: docker events
Get real time events from the server
-since="": Show previously created events and then stream.
(either seconds since epoch, or date string as below)
.. _cli_events_example:
@@ -239,7 +322,7 @@ Shell 1: Listening for events
.............................
.. code-block:: bash
$ sudo docker events
Shell 2: Start and Stop a Container
@@ -259,6 +342,23 @@ Shell 1: (Again .. now showing events)
[2013-09-03 15:49:29 +0200 CEST] 4386fb97867d: (from 12de384bfb10) die
[2013-09-03 15:49:29 +0200 CEST] 4386fb97867d: (from 12de384bfb10) stop
Show events in the past from a specified time
.............................................
.. code-block:: bash
$ sudo docker events -since 1378216169
[2013-09-03 15:49:29 +0200 CEST] 4386fb97867d: (from 12de384bfb10) die
[2013-09-03 15:49:29 +0200 CEST] 4386fb97867d: (from 12de384bfb10) stop
$ sudo docker events -since '2013-09-03'
[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
$ sudo docker events -since '2013-09-03 15:49:29 +0200 CEST'
[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:
@@ -282,6 +382,43 @@ Shell 1: (Again .. now showing events)
Show the history of an image
-notrunc=false: Don't truncate output
-q=false: only show numeric IDs
To see how the docker:latest image was built:
.. code-block:: bash
$ docker history docker
ID CREATED CREATED BY
docker:latest 19 hours ago /bin/sh -c #(nop) ADD . in /go/src/github.com/dotcloud/docker
cf5f2467662d 2 weeks ago /bin/sh -c #(nop) ENTRYPOINT ["hack/dind"]
3538fbe372bf 2 weeks ago /bin/sh -c #(nop) WORKDIR /go/src/github.com/dotcloud/docker
7450f65072e5 2 weeks ago /bin/sh -c #(nop) VOLUME /var/lib/docker
b79d62b97328 2 weeks ago /bin/sh -c apt-get install -y -q lxc
36714852a550 2 weeks ago /bin/sh -c apt-get install -y -q iptables
8c4c706df1d6 2 weeks ago /bin/sh -c /bin/echo -e '[default]\naccess_key=$AWS_ACCESS_KEY\nsecret_key=$AWS_SECRET_KEYn' > /.s3cfg
b89989433c48 2 weeks ago /bin/sh -c pip install python-magic
a23e640d85b5 2 weeks ago /bin/sh -c pip install s3cmd
41f54fec7e79 2 weeks ago /bin/sh -c apt-get install -y -q python-pip
d9bc04add907 2 weeks ago /bin/sh -c apt-get install -y -q reprepro dpkg-sig
e74f4760fa70 2 weeks ago /bin/sh -c gem install --no-rdoc --no-ri fpm
1e43224726eb 2 weeks ago /bin/sh -c apt-get install -y -q ruby1.9.3 rubygems libffi-dev
460953ae9d7f 2 weeks ago /bin/sh -c #(nop) ENV GOPATH=/go:/go/src/github.com/dotcloud/docker/vendor
8b63eb1d666b 2 weeks ago /bin/sh -c #(nop) ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/goroot/bin
3087f3bcedf2 2 weeks ago /bin/sh -c #(nop) ENV GOROOT=/goroot
635840d198e5 2 weeks ago /bin/sh -c cd /goroot/src && ./make.bash
439f4a0592ba 2 weeks ago /bin/sh -c curl -s https://go.googlecode.com/files/go1.1.2.src.tar.gz | tar -v -C / -xz && mv /go /goroot
13967ed36e93 2 weeks ago /bin/sh -c #(nop) ENV CGO_ENABLED=0
bf7424458437 2 weeks ago /bin/sh -c apt-get install -y -q build-essential
a89ec997c3bf 2 weeks ago /bin/sh -c apt-get install -y -q mercurial
b9f165c6e749 2 weeks ago /bin/sh -c apt-get install -y -q git
17a64374afa7 2 weeks ago /bin/sh -c apt-get install -y -q curl
d5e85dc5b1d8 2 weeks ago /bin/sh -c apt-get update
13e642467c11 2 weeks ago /bin/sh -c echo 'deb http://archive.ubuntu.com/ubuntu precise main universe' > /etc/apt/sources.list
ae6dde92a94e 2 weeks ago /bin/sh -c #(nop) MAINTAINER Solomon Hykes <solomon@dotcloud.com>
ubuntu:12.04 6 months ago
.. _cli_images:
``images``
@@ -293,20 +430,86 @@ Shell 1: (Again .. now showing events)
List images
-a=false: show all images
-a=false: show all images (by default filter out the intermediate images used to build)
-notrunc=false: Don't truncate output
-q=false: only show numeric IDs
-viz=false: output in graphviz format
-tree=false: output graph in tree format
-viz=false: output graph in graphviz format
Listing the most recently created images
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: bash
$ sudo docker images | head
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 77af4d6b9913 19 hours ago 30.53 MB (virtual 1.089 GB)
committest latest b6fa739cedf5 19 hours ago 30.53 MB (virtual 1.089 GB)
<none> <none> 78a85c484f71 19 hours ago 30.53 MB (virtual 1.089 GB)
docker latest 30557a29d5ab 20 hours ago 30.53 MB (virtual 1.089 GB)
<none> <none> 0124422dd9f9 20 hours ago 30.53 MB (virtual 1.089 GB)
<none> <none> 18ad6fad3402 22 hours ago 23.68 MB (virtual 1.082 GB)
<none> <none> f9f1e26352f0 23 hours ago 30.46 MB (virtual 1.089 GB)
tryout latest 2629d1fa0b81 23 hours ago 16.4 kB (virtual 131.5 MB)
<none> <none> 5ed6274db6ce 24 hours ago 30.44 MB (virtual 1.089 GB)
Listing the full length image IDs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: bash
$ sudo docker images -notrunc | head
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 77af4d6b9913e693e8d0b4b294fa62ade6054e6b2f1ffb617ac955dd63fb0182 19 hours ago 30.53 MB (virtual 1.089 GB)
committest latest b6fa739cedf5ea12a620a439402b6004d057da800f91c7524b5086a5e4749c9f 19 hours ago 30.53 MB (virtual 1.089 GB)
<none> <none> 78a85c484f71509adeaace20e72e941f6bdd2b25b4c75da8693efd9f61a37921 19 hours ago 30.53 MB (virtual 1.089 GB)
docker latest 30557a29d5abc51e5f1d5b472e79b7e296f595abcf19fe6b9199dbbc809c6ff4 20 hours ago 30.53 MB (virtual 1.089 GB)
<none> <none> 0124422dd9f9cf7ef15c0617cda3931ee68346455441d66ab8bdc5b05e9fdce5 20 hours ago 30.53 MB (virtual 1.089 GB)
<none> <none> 18ad6fad340262ac2a636efd98a6d1f0ea775ae3d45240d3418466495a19a81b 22 hours ago 23.68 MB (virtual 1.082 GB)
<none> <none> f9f1e26352f0a3ba6a0ff68167559f64f3e21ff7ada60366e2d44a04befd1d3a 23 hours ago 30.46 MB (virtual 1.089 GB)
tryout latest 2629d1fa0b81b222fca63371ca16cbf6a0772d07759ff80e8d1369b926940074 23 hours ago 16.4 kB (virtual 131.5 MB)
<none> <none> 5ed6274db6ceb2397844896966ea239290555e74ef307030ebb01ff91b1914df 24 hours ago 30.44 MB (virtual 1.089 GB)
Displaying images visually
~~~~~~~~~~~~~~~~~~~~~~~~~~
::
.. code-block:: bash
sudo docker images -viz | dot -Tpng -o docker.png
$ sudo docker images -viz | dot -Tpng -o docker.png
.. image:: docker_images.gif
:alt: Example inheritance graph of Docker images.
Displaying image hierarchy
~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: bash
$ sudo docker images -tree
|─8dbd9e392a96 Size: 131.5 MB (virtual 131.5 MB) Tags: ubuntu:12.04,ubuntu:latest,ubuntu:precise
└─27cf78414709 Size: 180.1 MB (virtual 180.1 MB)
└─b750fe79269d Size: 24.65 kB (virtual 180.1 MB) Tags: ubuntu:12.10,ubuntu:quantal
|─f98de3b610d5 Size: 12.29 kB (virtual 180.1 MB)
| └─7da80deb7dbf Size: 16.38 kB (virtual 180.1 MB)
| └─65ed2fee0a34 Size: 20.66 kB (virtual 180.2 MB)
| └─a2b9ea53dddc Size: 819.7 MB (virtual 999.8 MB)
| └─a29b932eaba8 Size: 28.67 kB (virtual 999.9 MB)
| └─e270a44f124d Size: 12.29 kB (virtual 999.9 MB) Tags: progrium/buildstep:latest
└─17e74ac162d8 Size: 53.93 kB (virtual 180.2 MB)
└─339a3f56b760 Size: 24.65 kB (virtual 180.2 MB)
└─904fcc40e34d Size: 96.7 MB (virtual 276.9 MB)
└─b1b0235328dd Size: 363.3 MB (virtual 640.2 MB)
└─7cb05d1acb3b Size: 20.48 kB (virtual 640.2 MB)
└─47bf6f34832d Size: 20.48 kB (virtual 640.2 MB)
└─f165104e82ed Size: 12.29 kB (virtual 640.2 MB)
└─d9cf85a47b7e Size: 1.911 MB (virtual 642.2 MB)
└─3ee562df86ca Size: 17.07 kB (virtual 642.2 MB)
└─b05fc2d00e4a Size: 24.96 kB (virtual 642.2 MB)
└─c96a99614930 Size: 12.29 kB (virtual 642.2 MB)
└─a6a357a48c49 Size: 12.29 kB (virtual 642.2 MB) Tags: ndj/mongodb:latest
.. _cli_import:
``import``
@@ -314,7 +517,7 @@ Displaying images visually
::
Usage: docker import URL|- [REPOSITORY [TAG]]
Usage: docker import URL|- [REPOSITORY[:TAG]]
Create a new filesystem image from the contents of a tarball
@@ -330,14 +533,16 @@ Examples
Import from a remote location
.............................
``$ sudo docker import http://example.com/exampleimage.tgz exampleimagerepo``
This will create a new untagged image.
``$ sudo docker import http://example.com/exampleimage.tgz``
Import from a local file
........................
Import to docker via pipe and standard in
``$ cat exampleimage.tgz | sudo docker import - exampleimagelocal``
``$ cat exampleimage.tgz | sudo docker import - exampleimagelocal:new``
Import from a local directory
.............................
@@ -360,6 +565,21 @@ might not get preserved.
Display system-wide information.
.. code-block:: bash
$ sudo docker info
Containers: 292
Images: 194
Debug mode (server): false
Debug mode (client): false
Fds: 22
Goroutines: 67
LXC Version: 0.9.0
EventsListeners: 115
Kernel Version: 3.8.0-33-generic
WARNING: No swap limit support
.. _cli_insert:
``insert``
@@ -401,7 +621,27 @@ Insert file from github
Usage: docker kill CONTAINER [CONTAINER...]
Kill a running container
Kill a running container (Send SIGKILL)
The main process inside the container will be sent SIGKILL.
Known Issues (kill)
~~~~~~~~~~~~~~~~~~~
* :issue:`197` indicates that ``docker kill`` may leave directories
behind and make it difficult to remove the container.
.. _cli_load:
``load``
--------
::
Usage: docker load < repository.tar
Loads a tarred repository from the standard input stream.
Restores both images and tags.
.. _cli_login:
@@ -510,7 +750,13 @@ Insert file from github
Remove one or more containers
-link="": Remove the link instead of the actual container
Known Issues (rm)
~~~~~~~~~~~~~~~~~~~
* :issue:`197` indicates that ``docker kill`` may leave directories
behind and make it difficult to remove the container.
Examples:
~~~~~~~~~
@@ -533,6 +779,15 @@ This will remove the container referenced under the link ``/redis``.
This will remove the underlying link between ``/webapp`` and the ``/redis`` containers removing all
network communication.
.. code-block:: bash
$ docker rm `docker ps -a -q`
This command will delete all stopped containers. The command ``docker ps -a -q`` will return all
existing container IDs and pass them to the ``rm`` command which will delete them. Any running
containers will not be deleted.
.. _cli_rmi:
``rmi``
@@ -563,7 +818,7 @@ network communication.
-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)
-m="": Memory limit (format: <number><optional unit>, where unit = b, k, m or g)
-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)
@@ -571,7 +826,7 @@ network communication.
-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
-volumes-from="": Mount all volumes from the given container(s)
-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"
@@ -579,6 +834,7 @@ network communication.
-expose=[]: Expose a port from the container without publishing it to your host
-link="": Add link to another container (name:alias)
-name="": Assign the specified name to the container. If no name is specific docker will generate a random name
-P=false: Publish all exposed ports to the host interfaces
Examples
--------
@@ -615,60 +871,82 @@ use-cases, like running Docker within Docker.
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
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
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
docker run -p 127.0.0.1:80:8080 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.
This binds port ``8080`` of the container to port ``80`` on 127.0.0.1 of the
host machine. :ref:`port_redirection` explains in detail how to manipulate ports
in Docker.
.. 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.
This exposes port ``80`` of the container for use within a link without
publishing the port to the host system's interfaces. :ref:`port_redirection`
explains in detail how to manipulate ports in Docker.
.. code-block:: bash
docker run -name console -t -i ubuntu bash
This will create and run a new container with the container name
This will create and run a new container with the container name
being ``console``.
.. code-block:: bash
docker run -link /redis:redis -name console ubuntu bash
The ``-link`` flag will link the container named ``/redis`` into the
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. The ``-name`` flag will assign the name ``console``
environment variables. The ``-name`` flag will assign the name ``console``
to the newly created container.
.. code-block:: bash
docker run -volumes-from 777f7dc92da7,ba8c0c54f0f2:ro -i -t ubuntu pwd
The ``-volumes-from`` flag mounts all the defined volumes from the
refrence containers. Containers can be specified by a comma seperated
list or by repetitions of the ``-volumes-from`` argument. The container
id may be optionally suffixed with ``:ro`` or ``:rw`` to mount the volumes in
read-only or read-write mode, respectively. By default, the volumes are mounted
in the same mode (rw or ro) as the reference container.
Known Issues (run -volumes-from)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* :issue:`2702`: "lxc-start: Permission denied - failed to mount"
could indicate a permissions problem with AppArmor. Please see the
issue for a workaround.
.. _cli_save:
``save``
::
Usage: docker save image > repository.tar
Streams a tarred repository to the standard output stream.
Contains all parent layers, and all tags + versions.
.. _cli_search:
``search``
@@ -678,8 +956,11 @@ to the newly created container.
Usage: docker search TERM
Searches for the TERM parameter on the Docker index and prints out
a list of repositories that match.
Search the docker index for images
-notrunc=false: Don't truncate output
-stars=0: Only displays with at least xxx stars
-trusted=false: Only show trusted builds
.. _cli_start:
@@ -704,10 +985,12 @@ to the newly created container.
Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...]
Stop a running container
Stop a running container (Send SIGTERM, and then SIGKILL after grace period)
-t=10: Number of seconds to wait for the container to stop before killing it.
The main process inside the container will receive SIGTERM, and after a grace period, SIGKILL
.. _cli_tag:
``tag``
@@ -715,7 +998,7 @@ to the newly created container.
::
Usage: docker tag [OPTIONS] IMAGE REPOSITORY [TAG]
Usage: docker tag [OPTIONS] IMAGE REPOSITORY[:TAG]
Tag an image into a repository
@@ -728,7 +1011,7 @@ to the newly created container.
::
Usage: docker top CONTAINER
Usage: docker top CONTAINER [ps OPTIONS]
Lookup the running processes of a container
@@ -750,6 +1033,3 @@ Show the version of the docker client, daemon, and latest released version.
Usage: docker wait [OPTIONS] NAME
Block until a container stops, then print its exit code.
+6 -2
View File
@@ -40,7 +40,11 @@ html_additional_pages = {
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinxcontrib.httpdomain']
extensions = ['sphinxcontrib.httpdomain', 'sphinx.ext.extlinks']
# Configure extlinks
extlinks = { 'issue': ('https://github.com/dotcloud/docker/issues/%s',
'Issue ') }
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
@@ -231,7 +235,7 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('toctree', 'docker', u'Docker Documentation',
('commandline/cli', 'docker', u'Docker Documentation',
[u'Team Docker'], 1)
]
+6 -3
View File
@@ -10,13 +10,16 @@ Want to hack on Docker? Awesome!
The repository includes `all the instructions you need to get
started <https://github.com/dotcloud/docker/blob/master/CONTRIBUTING.md>`_.
The developer environment `Dockerfile <https://github.com/dotcloud/docker/blob/master/Dockerfile>`_
The `developer environment Dockerfile
<https://github.com/dotcloud/docker/blob/master/Dockerfile>`_
specifies the tools and versions used to test and build Docker.
If you're making changes to the documentation, see the
`README.md <https://github.com/dotcloud/docker/blob/master/docs/README.md>`_.
The documentation environment `Dockerfile <https://github.com/dotcloud/docker/blob/master/docs/Dockerfile>`_
The `documentation environment Dockerfile
<https://github.com/dotcloud/docker/blob/master/docs/Dockerfile>`_
specifies the tools and versions used to build the Documentation.
Further interesting details can be found in the `Packaging hints <https://github.com/dotcloud/docker/blob/master/hack/PACKAGERS.md>`_.
Further interesting details can be found in the `Packaging hints
<https://github.com/dotcloud/docker/blob/master/hack/PACKAGERS.md>`_.
+4 -9
View File
@@ -56,7 +56,7 @@ 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
sudo docker run -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/``
@@ -64,20 +64,15 @@ 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
sudo docker run -privileged -v `pwd`:/go/src/github.com/dotcloud/docker docker hack/make.sh test
Note: if you're running the tests in vagrant, you need to specify a dns entry in the command: `-dns 8.8.8.8`
If the test are successful then the tail of the output should look something like this
.. code-block:: bash
@@ -10,7 +10,7 @@ CouchDB Service
.. include:: example_header.inc
Here's an example of using data volumes to share the same data between
2 CouchDB containers. This could be used for hot upgrades, testing
two CouchDB containers. This could be used for hot upgrades, testing
different versions of CouchDB on the same data, etc.
Create first database
@@ -20,28 +20,28 @@ Note that we're marking ``/var/lib/couchdb`` as a data volume.
.. code-block:: bash
COUCH1=$(sudo docker run -d -v /var/lib/couchdb shykes/couchdb:2013-05-03)
COUCH1=$(sudo docker run -d -p 5984 -v /var/lib/couchdb shykes/couchdb:2013-05-03)
Add data to the first database
------------------------------
We're assuming your docker host is reachable at `localhost`. If not,
replace `localhost` with the public IP of your docker host.
We're assuming your Docker host is reachable at ``localhost``. If not,
replace ``localhost`` with the public IP of your Docker host.
.. code-block:: bash
HOST=localhost
URL="http://$HOST:$(sudo docker port $COUCH1 5984)/_utils/"
URL="http://$HOST:$(sudo docker port $COUCH1 5984 | grep -Po '\d+$')/_utils/"
echo "Navigate to $URL in your browser, and use the couch interface to add data"
Create second database
----------------------
This time, we're requesting shared access to $COUCH1's volumes.
This time, we're requesting shared access to ``$COUCH1``'s volumes.
.. code-block:: bash
COUCH2=$(sudo docker run -d -volumes-from $COUCH1 shykes/couchdb:2013-05-03)
COUCH2=$(sudo docker run -d -p 5984 -volumes-from $COUCH1 shykes/couchdb:2013-05-03)
Browse data on the second database
----------------------------------
@@ -49,8 +49,8 @@ Browse data on the second database
.. code-block:: bash
HOST=localhost
URL="http://$HOST:$(sudo docker port $COUCH2 5984)/_utils/"
URL="http://$HOST:$(sudo docker port $COUCH2 5984 | grep -Po '\d+$')/_utils/"
echo "Navigate to $URL in your browser. You should see the same data as in the first database"'!'
Congratulations, you are running 2 Couchdb containers, completely
Congratulations, you are now running two Couchdb containers, completely
isolated from each other *except* for their data.
+4 -1
View File
@@ -1,4 +1,7 @@
.. note::
This example assumes you have Docker running in daemon mode. For more information please see :ref:`running_examples`
* This example assumes you have Docker running in daemon mode. For
more information please see :ref:`running_examples`.
* **If you don't like sudo** then see :ref:`dockergroup`
+13 -10
View File
@@ -12,16 +12,16 @@ Hello World
Running the Examples
====================
All the examples assume your machine is running the docker daemon. To
run the docker daemon in the background, simply type:
All the examples assume your machine is running the ``docker`` daemon. To
run the ``docker`` daemon in the background, simply type:
.. code-block:: bash
sudo docker -d &
Now you can run docker in client mode: by default all commands will be
Now you can run Docker in client mode: by default all commands will be
forwarded to the ``docker`` daemon via a protected Unix socket, so you
must run as root.
must run as the ``root`` or via the ``sudo`` command.
.. code-block:: bash
@@ -38,23 +38,24 @@ Hello World
This is the most basic example available for using Docker.
Download the base image (named "ubuntu"):
Download the base image which is named ``ubuntu``:
.. code-block:: bash
# Download an ubuntu image
sudo docker pull ubuntu
Alternatively to the *ubuntu* image, you can select *busybox*, a bare
Alternatively to the ``ubuntu`` image, you can select ``busybox``, a bare
minimal Linux system. The images are retrieved from the Docker
repository.
.. code-block:: bash
#run a simple echo command, that will echo hello world back to the console over standard out.
sudo docker run ubuntu /bin/echo hello world
This command will run a simple ``echo`` command, that will echo ``hello world`` back to the console over standard out.
**Explanation:**
- **"sudo"** execute the following commands as user *root*
@@ -100,9 +101,9 @@ we stop it.
CONTAINER_ID=$(sudo docker run -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done")
We are going to run a simple hello world daemon in a new container
made from the *ubuntu* image.
made from the ``ubuntu`` image.
- **"docker run -d "** run a command in a new container. We pass "-d"
- **"sudo docker run -d "** run a command in a new container. We pass "-d"
so it runs as a daemon.
- **"ubuntu"** is the image we want to run the command inside of.
- **"/bin/sh -c"** is the command we want to run in the container
@@ -126,10 +127,12 @@ Check the logs make sure it is working correctly.
sudo docker attach $CONTAINER_ID
Attach to the container to see the results in realtime.
Attach to the container to see the results in real-time.
- **"docker attach**" This will allow us to attach to a background
process to see what is going on.
- **"-sig-proxy=true"** Proxify all received signal to the process
(even in non-tty mode)
- **$CONTAINER_ID** The Id of the container we want to attach too.
Exit from the container attachment by pressing Control-C.
+1 -2
View File
@@ -10,7 +10,7 @@ Examples
Here are some examples of how to use Docker to create running
processes, starting from a very simple *Hello World* and progressing
to more substantial services like you might find in production.
to more substantial services like those which you might find in production.
.. toctree::
:maxdepth: 1
@@ -24,4 +24,3 @@ to more substantial services like you might find in production.
postgresql_service
mongodb
running_riak_service
linking_into_redis
@@ -1,132 +0,0 @@
: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
----------------------------
Lets build a redis image with the following Dockerfile.
.. code-block:: bash
git clone https://github.com/antirez/redis.git
cd redis
git checkout 2.6
# Save this Dockerfile to the root of the redis repository.
# 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 mkdir -p /redis-data
VOLUME ["/redis-data"]
EXPOSE 6379
ENTRYPOINT ["/redis/src/redis-server"]
CMD ["--dir", "/redis-data"]
# docker build our new redis image from source
docker build -t redis-2.6 .
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 -name redis redis-2.6 --requirepass docker
This will run our redis container wit the password docker
to secure our service. By specifying the ``-name`` flag on run
we will assign the name ``redis`` to this container. If we do not specify a name for
our container via the ``-name`` flag docker will automatically generate a name for us.
We can issue all the commands that you would expect; start, stop, attach, using the name for our container.
The name also allows us to link other containers into this one.
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 server we did not use
the ``-p`` flag to publish the redis port to the host system. Redis exposed port 6379 via the Dockerfile
and this is all we need to establish a link.
Now lets start our web application with a link into redis.
.. code-block:: bash
docker run -t -i -link redis:db -name webapp ubuntu bash
root@4c01db0b339c:/# env
HOSTNAME=4c01db0b339c
DB_NAME=/webapp/db
TERM=xterm
DB_PORT=tcp://172.17.0.8:6379
DB_PORT_6379_TCP=tcp://172.17.0.8:6379
DB_PORT_6379_TCP_PROTO=tcp
DB_PORT_6379_TCP_ADDR=172.17.0.8
DB_PORT_6379_TCP_PORT=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 containers that are linked into it.
.. code-block:: bash
# The name of the child container
DB_NAME=/webapp/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
DB_PORT_6379_TCP_PROTO=tcp
DB_PORT_6379_TCP_ADDR=172.17.0.8
DB_PORT_6379_TCP_PORT=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.
+9 -9
View File
@@ -10,8 +10,8 @@ Building an Image with MongoDB
.. include:: example_header.inc
The goal of this example is to show how you can build your own
docker images with MongoDB preinstalled. We will do that by
constructing a Dockerfile that downloads a base image, adds an
Docker images with MongoDB pre-installed. We will do that by
constructing a ``Dockerfile`` that downloads a base image, adds an
apt source and installs the database software on Ubuntu.
Creating a ``Dockerfile``
@@ -41,7 +41,7 @@ Since we want to be running the latest version of MongoDB we'll need to add the
RUN echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | tee /etc/apt/sources.list.d/10gen.list
Then, we don't want Ubuntu to complain about init not being available so we'll
divert /sbin/initctl to /bin/true so it thinks everything is working.
divert ``/sbin/initctl`` to ``/bin/true`` so it thinks everything is working.
.. code-block:: bash
@@ -65,8 +65,8 @@ run without needing to provide a special configuration file)
# Create the MongoDB data directory
RUN mkdir -p /data/db
Finally, we'll expose the standard port that MongoDB runs on (27107) as well as
define an ENTRYPOINT for the container.
Finally, we'll expose the standard port that MongoDB runs on, 27107, as well as
define an ``ENTRYPOINT`` instruction for the container.
.. code-block:: bash
@@ -78,7 +78,7 @@ run all of the commands.
.. code-block:: bash
docker build -t <yourname>/mongodb .
sudo docker build -t <yourname>/mongodb .
Now you should be able to run ``mongod`` as a daemon and be able to connect on
the local port!
@@ -86,13 +86,13 @@ the local port!
.. code-block:: bash
# Regular style
MONGO_ID=$(docker run -d <yourname>/mongodb)
MONGO_ID=$(sudo docker run -d <yourname>/mongodb)
# Lean and mean
MONGO_ID=$(docker run -d <yourname>/mongodb --noprealloc --smallfiles)
MONGO_ID=$(sudo docker run -d <yourname>/mongodb --noprealloc --smallfiles)
# Check the logs out
docker logs $MONGO_ID
sudo docker logs $MONGO_ID
# Connect and play around
mongo --port <port you get from `docker ps`>
+18 -18
View File
@@ -10,7 +10,7 @@ Node.js Web App
.. include:: example_header.inc
The goal of this example is to show you how you can build your own
docker images from a parent image using a ``Dockerfile`` . We will do
Docker images from a parent image using a ``Dockerfile`` . We will do
that by making a simple Node.js hello world web application running on
CentOS. You can get the full source code at
https://github.com/gasi/docker-node-hello.
@@ -55,7 +55,7 @@ Then, create an ``index.js`` file that defines a web app using the
In the next steps, well look at how you can run this app inside a CentOS
container using docker. First, youll need to build a docker image of your app.
container using Docker. First, youll need to build a Docker image of your app.
Creating a ``Dockerfile``
+++++++++++++++++++++++++
@@ -67,8 +67,8 @@ Create an empty file called ``Dockerfile``:
touch Dockerfile
Open the ``Dockerfile`` in your favorite text editor and add the following line
that defines the version of docker the image requires to build
(this example uses docker 0.3.4):
that defines the version of Docker the image requires to build
(this example uses Docker 0.3.4):
.. code-block:: bash
@@ -76,7 +76,7 @@ that defines the version of docker the image requires to build
Next, define the parent image you want to use to build your own image on top of.
Here, well use `CentOS <https://index.docker.io/_/centos/>`_ (tag: ``6.4``)
available on the `docker index`_:
available on the `Docker index`_:
.. code-block:: bash
@@ -95,23 +95,23 @@ To install the right package for CentOS, well use the instructions from the
# Install Node.js and npm
RUN yum install -y npm
To bundle your apps source code inside the docker image, use the ``ADD``
command:
To bundle your apps source code inside the Docker image, use the ``ADD``
instruction:
.. code-block:: bash
# Bundle app source
ADD . /src
Install your app dependencies using npm:
Install your app dependencies using the ``npm`` binary:
.. code-block:: bash
# Install app dependencies
RUN cd /src; npm install
Your app binds to port ``8080`` so youll use the ``EXPOSE`` command
to have it mapped by the docker daemon:
Your app binds to port ``8080`` so youll use the ``EXPOSE`` instruction
to have it mapped by the ``docker`` daemon:
.. code-block:: bash
@@ -152,7 +152,7 @@ Building your image
+++++++++++++++++++
Go to the directory that has your ``Dockerfile`` and run the following
command to build a docker image. The ``-t`` flag lets you tag your
command to build a Docker image. The ``-t`` flag lets you tag your
image so its easier to find later using the ``docker images``
command:
@@ -160,7 +160,7 @@ command:
sudo docker build -t <your username>/centos-node-hello .
Your image will now be listed by docker:
Your image will now be listed by Docker:
.. code-block:: bash
@@ -176,11 +176,11 @@ Run the image
+++++++++++++
Running your image with ``-d`` runs the container in detached mode, leaving the
container running in the background. Run the image you previously built:
container running in the background. The ``-p`` flag redirects a public port to a private port in the container. Run the image you previously built:
.. code-block:: bash
sudo docker run -d <your username>/centos-node-hello
sudo docker run -p 49160:8080 -d <your username>/centos-node-hello
Print the output of your app:
@@ -199,17 +199,17 @@ Print the output of your app:
Test
++++
To test your app, get the the port of your app that docker mapped:
To test your app, get the the port of your app that Docker mapped:
.. code-block:: bash
docker ps
sudo docker ps
> # Example
> ID IMAGE COMMAND ... PORTS
> ecce33b30ebf gasi/centos-node-hello:latest node /src/index.js 49160->8080
In the example above, docker mapped the ``8080`` port of the container to
In the example above, Docker mapped the ``8080`` port of the container to
``49160``.
Now you can call your app using ``curl`` (install if needed via:
@@ -229,7 +229,7 @@ Now you can call your app using ``curl`` (install if needed via:
> Hello World
We hope this tutorial helped you get up and running with Node.js and
CentOS on docker. You can get the full source code at
CentOS on Docker. You can get the full source code at
https://github.com/gasi/docker-node-hello.
Continue to :ref:`running_redis_service`.
+4 -5
View File
@@ -13,7 +13,7 @@ PostgreSQL Service
.. note::
As of version 0.5.2, docker requires root privileges to run.
As of version 0.5.2, Docker requires root privileges to run.
You have to either manually adjust your system configuration (permissions on
/var/run/docker.sock or sudo config), or prefix `docker` with `sudo`. Check
`this thread`_ for details.
@@ -24,8 +24,7 @@ PostgreSQL Service
Installing PostgreSQL on Docker
-------------------------------
For clarity I won't be showing commands output.
For clarity I won't be showing command output.
Run an interactive shell in Docker container.
@@ -62,7 +61,7 @@ Finally, install PostgreSQL 9.2
Now, create a PostgreSQL superuser role that can create databases and
other roles. Following Vagrant's convention the role will be named
`docker` with `docker` password assigned to it.
``docker`` with ``docker`` password assigned to it.
.. code-block:: bash
@@ -108,7 +107,7 @@ Bash prompt; you can also locate it using ``docker ps -a``.
.. code-block:: bash
docker commit <container_id> <your username>/postgresql
sudo docker commit <container_id> <your username>/postgresql
Finally, run PostgreSQL server via ``docker``.
+23 -22
View File
@@ -10,9 +10,9 @@ Python Web App
.. include:: example_header.inc
The goal of this example is to show you how you can author your own
docker images using a parent image, making changes to it, and then
Docker images using a parent image, making changes to it, and then
saving the results as a new image. We will do that by making a simple
hello flask web application image.
hello Flask web application image.
**Steps:**
@@ -20,36 +20,37 @@ hello flask web application image.
sudo docker pull shykes/pybuilder
We are downloading the "shykes/pybuilder" docker image
We are downloading the ``shykes/pybuilder`` Docker image
.. code-block:: bash
URL=http://github.com/shykes/helloflask/archive/master.tar.gz
We set a URL variable that points to a tarball of a simple helloflask web app
We set a ``URL`` variable that points to a tarball of a simple helloflask web app
.. code-block:: bash
BUILD_JOB=$(sudo docker run -d -t shykes/pybuilder:latest /usr/local/bin/buildapp $URL)
Inside of the "shykes/pybuilder" image there is a command called
buildapp, we are running that command and passing the $URL variable
Inside of the ``shykes/pybuilder`` image there is a command called
``buildapp``, we are running that command and passing the ``$URL`` variable
from step 2 to it, and running the whole thing inside of a new
container. BUILD_JOB will be set with the new container_id.
container. The ``BUILD_JOB`` environment variable will be set with the new container ID.
.. code-block:: bash
sudo docker attach $BUILD_JOB
sudo docker attach -sig-proxy=false $BUILD_JOB
[...]
While this container is running, we can attach to the new container to
see what is going on. Ctrl-C to disconnect.
see what is going on. The flag ``-sig-proxy`` set as ``false`` allows you to connect and
disconnect (Ctrl-C) to it without stopping the container.
.. code-block:: bash
sudo docker ps -a
List all docker containers. If this container has already finished
List all Docker containers. If this container has already finished
running, it will still be listed here.
.. code-block:: bash
@@ -57,8 +58,8 @@ running, it will still be listed here.
BUILD_IMG=$(sudo docker commit $BUILD_JOB _/builds/github.com/shykes/helloflask/master)
Save the changes we just made in the container to a new image called
``_/builds/github.com/hykes/helloflask/master`` and save the image id in
the BUILD_IMG variable name.
``_/builds/github.com/hykes/helloflask/master`` and save the image ID in
the ``BUILD_IMG`` variable name.
.. code-block:: bash
@@ -72,24 +73,24 @@ the BUILD_IMG variable name.
- **/usr/local/bin/runapp** is the command which starts the web app.
Use the new image we just created and create a new container with
network port 5000, and return the container id and store in the
WEB_WORKER variable.
network port 5000, and return the container ID and store in the
``WEB_WORKER`` variable.
.. code-block:: bash
sudo docker logs $WEB_WORKER
* Running on http://0.0.0.0:5000/
View the logs for the new container using the WEB_WORKER variable, and
if everything worked as planned you should see the line "Running on
http://0.0.0.0:5000/" in the log output.
View the logs for the new container using the ``WEB_WORKER`` variable, and
if everything worked as planned you should see the line ``Running on
http://0.0.0.0:5000/`` in the log output.
.. code-block:: bash
WEB_PORT=$(sudo docker port $WEB_WORKER 5000)
WEB_PORT=$(sudo docker port $WEB_WORKER 5000 | awk -F: '{ print $2 }')
Look up the public-facing port which is NAT-ed. Find the private port
used by the container and store it inside of the WEB_PORT variable.
used by the container and store it inside of the ``WEB_PORT`` variable.
.. code-block:: bash
@@ -97,8 +98,8 @@ used by the container and store it inside of the WEB_PORT variable.
curl http://127.0.0.1:$WEB_PORT
Hello world!
Access the web app using curl. If everything worked as planned you
should see the line "Hello world!" inside of your console.
Access the web app using the ``curl`` binary. If everything worked as planned you
should see the line ``Hello world!`` inside of your console.
**Video:**
+66 -47
View File
@@ -9,74 +9,93 @@ Redis Service
.. include:: example_header.inc
Very simple, no frills, redis service.
Very simple, no frills, Redis service attached to a web application using a link.
Open a docker container
-----------------------
Create a docker container for Redis
-----------------------------------
Firstly, we create a ``Dockerfile`` for our new Redis image.
.. code-block:: bash
sudo docker run -i -t ubuntu /bin/bash
FROM ubuntu:12.10
RUN apt-get update
RUN apt-get -y install redis-server
EXPOSE 6379
ENTRYPOINT ["/usr/bin/redis-server"]
Building your image
-------------------
Update your Docker container, install the Redis server. Once
installed, exit out of the Docker container.
Next we build an image from our ``Dockerfile``. Replace ``<your username>``
with your own user name.
.. code-block:: bash
apt-get update
apt-get install redis-server
exit
Snapshot the installation
-------------------------
.. code-block:: bash
docker ps -a # grab the container id (this will be the first one in the list)
docker commit <container_id> <your username>/redis
sudo docker build -t <your username>/redis .
Run the service
---------------
Running the service with `-d` runs the container in detached mode, leaving the
container running in the background. Use your snapshot.
Use the image we've just created and name your container ``redis``.
Running the service with ``-d`` runs the container in detached mode, leaving the
container running in the background.
Importantly, we're not exposing any ports on our container. Instead we're going to
use a container link to provide access to our Redis database.
.. code-block:: bash
sudo docker run -d -p 6379 <your username>/redis /usr/bin/redis-server
sudo docker run -name redis -d <your username>/redis
Test 1
++++++
Create your web application container
-------------------------------------
Connect to the container with the redis-cli.
Next we can create a container for our application. We're going to use the ``-link``
flag to create a link to the ``redis`` container we've just created with an alias of
``db``. This will create a secure tunnel to the ``redis`` container and expose the
Redis instance running inside that container to only this container.
.. code-block:: bash
sudo docker ps # grab the new container id
sudo docker inspect <container_id> # grab the ipaddress of the container
redis-cli -h <ipaddress> -p 6379
redis 10.0.3.32:6379> set docker awesome
sudo docker run -link redis:db -i -t ubuntu:12.10 /bin/bash
Once inside our freshly created container we need to install Redis to get the
``redis-cli`` binary to test our connection.
.. code-block:: bash
apt-get update
apt-get -y install redis-server
service redis-server stop
Now we can test the connection. Firstly, let's look at the available environmental
variables in our web application container. We can use these to get the IP and port
of our ``redis`` container.
.. code-block:: bash
env
. . .
DB_NAME=/violet_wolf/db
DB_PORT_6379_TCP_PORT=6379
DB_PORT=tcp://172.17.0.33:6379
DB_PORT_6379_TCP=tcp://172.17.0.33:6379
DB_PORT_6379_TCP_ADDR=172.17.0.33
DB_PORT_6379_TCP_PROTO=tcp
We can see that we've got a small list of environment variables prefixed with ``DB``.
The ``DB`` comes from the link alias specified when we launched the container. Let's use
the ``DB_PORT_6379_TCP_ADDR`` variable to connect to our Redis container.
.. code-block:: bash
redis-cli -h $DB_PORT_6379_TCP_ADDR
redis 172.17.0.33:6379>
redis 172.17.0.33:6379> set docker awesome
OK
redis 10.0.3.32:6379> get docker
redis 172.17.0.33:6379> get docker
"awesome"
redis 10.0.3.32:6379> exit
redis 172.17.0.33:6379> exit
Test 2
++++++
We could easily use this or other environment variables in our web application to make a
connection to our ``redis`` container.
Connect to the host os with the redis-cli.
.. code-block:: bash
sudo docker ps # grab the new container id
sudo docker port <container_id> 6379 # grab the external port
ip addr show # grab the host ip address
redis-cli -h <host ipaddress> -p <external port>
redis 192.168.0.1:49153> set docker awesome
OK
redis 192.168.0.1:49153> get docker
"awesome"
redis 192.168.0.1:49153> exit
@@ -107,7 +107,7 @@ Create a ``supervisord`` configuration file
+++++++++++++++++++++++++++++++++++++++++++
Create an empty file called ``supervisord.conf``. Make sure it's at the same
level as your ``Dockerfile``:
directory level as your ``Dockerfile``:
.. code-block:: bash
@@ -12,14 +12,14 @@ SSH Daemon Service
**Video:**
I've create a little screencast to show how to create a sshd service
I've created a little screencast to show how to create an SSHd service
and connect to it. It is something like 11 minutes and not entirely
smooth, but gives you a good idea.
smooth, but it gives you a good idea.
.. note::
This screencast was created before ``docker`` version 0.5.2, so the
This screencast was created before Docker version 0.5.2, so the
daemon is unprotected and available via a TCP port. When you run
through the same steps in a newer version of ``docker``, you will
through the same steps in a newer version of Docker, you will
need to add ``sudo`` in front of each ``docker`` command in order
to reach the daemon over its protected Unix socket.
@@ -29,13 +29,14 @@ smooth, but gives you a good idea.
<iframe width="800" height="400" src="http://ascii.io/a/2637/raw" frameborder="0"></iframe>
</div>
You can also get this sshd container by using
::
You can also get this sshd container by using:
.. code-block:: bash
sudo docker pull dhrp/sshd
The password is 'screencast'
The password is ``screencast``.
**Video's Transcription:**
+31 -14
View File
@@ -22,12 +22,10 @@ Amazon QuickStart
1. **Choose an image:**
* Open http://cloud-images.ubuntu.com/locator/ec2/
* Enter ``amd64 precise`` in the search field (it will search as you
type)
* Pick an image by clicking on the image name. *An EBS-enabled
image will let you use a t1.micro instance.* Clicking on the image
name will take you to your AWS Console.
* Launch the `Create Instance Wizard` <https://console.aws.amazon.com/ec2/v2/home?#LaunchInstanceWizard:> menu on your AWS Console
* Select "Community AMIs" option and serch for ``amd64 precise`` (click enter to search)
* If you choose a EBS enabled AMI you will be able to launch a `t1.micro` instance (more info on `pricing` <http://aws.amazon.com/en/ec2/pricing/> )
* When you click select you'll be taken to the instance setup, and you're one click away from having your Ubuntu VM up and running.
2. **Tell CloudInit to install Docker:**
@@ -102,26 +100,45 @@ Docker that way too. Vagrant 1.1 or higher is required.
we need to set them there first. Make sure you have everything on
amazon aws setup so you can (manually) deploy a new image to EC2.
Note that where possible these variables are the same as those honored by
the ec2 api tools.
::
export AWS_ACCESS_KEY_ID=xxx
export AWS_SECRET_ACCESS_KEY=xxx
export AWS_ACCESS_KEY=xxx
export AWS_SECRET_KEY=xxx
export AWS_KEYPAIR_NAME=xxx
export AWS_SSH_PRIVKEY=xxx
export SSH_PRIVKEY_PATH=xxx
The environment variables are:
export BOX_NAME=xxx
export AWS_REGION=xxx
export AWS_AMI=xxx
export AWS_INSTANCE_TYPE=xxx
* ``AWS_ACCESS_KEY_ID`` - The API key used to make requests to AWS
* ``AWS_SECRET_ACCESS_KEY`` - The secret key to make AWS API requests
The required environment variables are:
* ``AWS_ACCESS_KEY`` - The API key used to make requests to AWS
* ``AWS_SECRET_KEY`` - The secret key to make AWS API requests
* ``AWS_KEYPAIR_NAME`` - The name of the keypair used for this EC2 instance
* ``AWS_SSH_PRIVKEY`` - The path to the private key for the named
* ``SSH_PRIVKEY_PATH`` - The path to the private key for the named
keypair, for example ``~/.ssh/docker.pem``
There are a number of optional environment variables:
* ``BOX_NAME`` - The name of the vagrant box to use. Defaults to
``ubuntu``.
* ``AWS_REGION`` - The aws region to spawn the vm in. Defaults to
``us-east-1``.
* ``AWS_AMI`` - The aws AMI to start with as a base. This must be
be an ubuntu 12.04 precise image. You must change this value if
``AWS_REGION`` is set to a value other than ``us-east-1``.
This is because AMIs are region specific. Defaults to ``ami-69f5a900``.
* ``AWS_INSTANCE_TYPE`` - The aws instance type. Defaults to ``t1.micro``.
You can check if they are set correctly by doing something like
::
echo $AWS_ACCESS_KEY_ID
echo $AWS_ACCESS_KEY
6. Do the magic!
+3 -2
View File
@@ -19,11 +19,12 @@ Contents:
ubuntulinux
binaries
security
upgrading
kernel
vagrant
windows
amazon
rackspace
archlinux
gentoolinux
upgrading
kernel
+10
View File
@@ -25,6 +25,7 @@ If you cannot or do not want to use the "official" kernels,
here is some technical background about the features (both optional and
mandatory) that docker needs to run successfully.
Linux version 3.8 or above
--------------------------
@@ -39,6 +40,15 @@ The symptoms include:
- kernel crash causing the machine to freeze for a few minutes, or even
completely.
Additionally, kernels prior 3.4 did not implement ``reboot_pid_ns``,
which means that the ``reboot()`` syscall could reboot the host machine,
instead of terminating the container. To work around that problem,
LXC userland tools (since version 0.8) automatically drop the ``SYS_BOOT``
capability when necessary. Still, if you run a pre-3.4 kernel with pre-0.8
LXC tools, be aware that containers can reboot the whole host! This is
not something that Docker wants to address in the short term, since you
shouldn't use kernels prior 3.8 with Docker anyway.
While it is still possible to use older kernels for development, it is
really not advised to do so.
+267
View File
@@ -0,0 +1,267 @@
:title: Docker Security
:description: Review of the Docker Daemon attack surface
:keywords: Docker, Docker documentation, security
.. _dockersecurity:
Docker Security
===============
*Adapted from* `Containers & Docker: How Secure are They? <blogsecurity>`_
There are three major areas to consider when reviewing Docker security:
* the intrinsic security of containers, as implemented by kernel
namespaces and cgroups;
* the attack surface of the Docker daemon itself;
* the "hardening" security features of the kernel and how they
interact with containers.
Kernel Namespaces
-----------------
Docker containers are essentially LXC containers, and they come with
the same security features. When you start a container with ``docker
run``, behind the scenes Docker uses ``lxc-start`` to execute the
Docker container. This creates a set of namespaces and control groups
for the container. Those namespaces and control groups are not created
by Docker itself, but by ``lxc-start``. This means that as the LXC
userland tools evolve (and provide additional namespaces and isolation
features), Docker will automatically make use of them.
**Namespaces provide the first and most straightforward form of
isolation**: processes running within a container cannot see, and even
less affect, processes running in another container, or in the host
system.
**Each container also gets its own network stack**, meaning that a
container doesnt get a privileged access to the sockets or interfaces
of another container. Of course, if the host system is setup
accordingly, containers can interact with each other through their
respective network interfaces — just like they can interact with
external hosts. When you specify public ports for your containers or
use :ref:`links <working_with_links_names>` then IP traffic is allowed
between containers. They can ping each other, send/receive UDP
packets, and establish TCP connections, but that can be restricted if
necessary. From a network architecture point of view, all containers
on a given Docker host are sitting on bridge interfaces. This means
that they are just like physical machines connected through a common
Ethernet switch; no more, no less.
How mature is the code providing kernel namespaces and private
networking? Kernel namespaces were introduced `between kernel version
2.6.15 and 2.6.26
<http://lxc.sourceforge.net/index.php/about/kernel-namespaces/>`_. This
means that since July 2008 (date of the 2.6.26 release, now 5 years
ago), namespace code has been exercised and scrutinized on a large
number of production systems. And there is more: the design and
inspiration for the namespaces code are even older. Namespaces are
actually an effort to reimplement the features of `OpenVZ
<http://en.wikipedia.org/wiki/OpenVZ>`_ in such a way that they could
be merged within the mainstream kernel. And OpenVZ was initially
released in 2005, so both the design and the implementation are
pretty mature.
Control Groups
--------------
Control Groups are the other key component of Linux Containers. They
implement resource accounting and limiting. They provide a lot of very
useful metrics, but they also help to ensure that each container gets
its fair share of memory, CPU, disk I/O; and, more importantly, that a
single container cannot bring the system down by exhausting one of
those resources.
So while they do not play a role in preventing one container from
accessing or affecting the data and processes of another container,
they are essential to fend off some denial-of-service attacks. They
are particularly important on multi-tenant platforms, like public and
private PaaS, to guarantee a consistent uptime (and performance) even
when some applications start to misbehave.
Control Groups have been around for a while as well: the code was
started in 2006, and initially merged in kernel 2.6.24.
Docker Daemon Attack Surface
----------------------------
Running containers (and applications) with Docker implies running the
Docker daemon. This daemon currently requires root privileges, and you
should therefore be aware of some important details.
First of all, **only trusted users should be allowed to control your
Docker daemon**. This is a direct consequence of some powerful Docker
features. Specifically, Docker allows you to share a directory between
the Docker host and a guest container; and it allows you to do so
without limiting the access rights of the container. This means that
you can start a container where the ``/host`` directory will be the
``/`` directory on your host; and the container will be able to alter
your host filesystem without any restriction. This sounds crazy? Well,
you have to know that **all virtualization systems allowing filesystem
resource sharing behave the same way**. Nothing prevents you from
sharing your root filesystem (or even your root block device) with a
virtual machine.
This has a strong security implication: if you instrument Docker from
e.g. a web server to provision containers through an API, you should
be even more careful than usual with parameter checking, to make sure
that a malicious user cannot pass crafted parameters causing Docker to
create arbitrary containers.
For this reason, the REST API endpoint (used by the Docker CLI to
communicate with the Docker daemon) changed in Docker 0.5.2, and now
uses a UNIX socket instead of a TCP socket bound on 127.0.0.1 (the
latter being prone to cross-site-scripting attacks if you happen to
run Docker directly on your local machine, outside of a VM). You can
then use traditional UNIX permission checks to limit access to the
control socket.
You can also expose the REST API over HTTP if you explicitly decide
so. However, if you do that, being aware of the abovementioned
security implication, you should ensure that it will be reachable
only from a trusted network or VPN; or protected with e.g. ``stunnel``
and client SSL certificates.
Recent improvements in Linux namespaces will soon allow to run
full-featured containers without root privileges, thanks to the new
user namespace. This is covered in detail `here
<http://s3hh.wordpress.com/2013/07/19/creating-and-using-containers-without-privilege/>`_. Moreover,
this will solve the problem caused by sharing filesystems between host
and guest, since the user namespace allows users within containers
(including the root user) to be mapped to other users in the host
system.
The end goal for Docker is therefore to implement two additional
security improvements:
* map the root user of a container to a non-root user of the Docker
host, to mitigate the effects of a container-to-host privilege
escalation;
* allow the Docker daemon to run without root privileges, and delegate
operations requiring those privileges to well-audited sub-processes,
each with its own (very limited) scope: virtual network setup,
filesystem management, etc.
Finally, if you run Docker on a server, it is recommended to run
exclusively Docker in the server, and move all other services within
containers controlled by Docker. Of course, it is fine to keep your
favorite admin tools (probably at least an SSH server), as well as
existing monitoring/supervision processes (e.g. NRPE, collectd, etc).
Linux Kernel Capabilities
-------------------------
By default, Docker starts containers with a very restricted set of
capabilities. What does that mean?
Capabilities turn the binary "root/non-root" dichotomy into a
fine-grained access control system. Processes (like web servers) that
just need to bind on a port below 1024 do not have to run as root:
they can just be granted the ``net_bind_service`` capability
instead. And there are many other capabilities, for almost all the
specific areas where root privileges are usually needed.
This means a lot for container security; lets see why!
Your average server (bare metal or virtual machine) needs to run a
bunch of processes as root. Those typically include SSH, cron,
syslogd; hardware management tools (to e.g. load modules), network
configuration tools (to handle e.g. DHCP, WPA, or VPNs), and much
more. A container is very different, because almost all of those tasks
are handled by the infrastructure around the container:
* SSH access will typically be managed by a single server running in
the Docker host;
* ``cron``, when necessary, should run as a user process, dedicated
and tailored for the app that needs its scheduling service, rather
than as a platform-wide facility;
* log management will also typically be handed to Docker, or by
third-party services like Loggly or Splunk;
* hardware management is irrelevant, meaning that you never need to
run ``udevd`` or equivalent daemons within containers;
* network management happens outside of the containers, enforcing
separation of concerns as much as possible, meaning that a container
should never need to perform ``ifconfig``, ``route``, or ip commands
(except when a container is specifically engineered to behave like a
router or firewall, of course).
This means that in most cases, containers will not need "real" root
privileges *at all*. And therefore, containers can run with a reduced
capability set; meaning that "root" within a container has much less
privileges than the real "root". For instance, it is possible to:
* deny all "mount" operations;
* deny access to raw sockets (to prevent packet spoofing);
* deny access to some filesystem operations, like creating new device
nodes, changing the owner of files, or altering attributes
(including the immutable flag);
* deny module loading;
* and many others.
This means that even if an intruder manages to escalate to root within
a container, it will be much harder to do serious damage, or to
escalate to the host.
This won't affect regular web apps; but malicious users will find that
the arsenal at their disposal has shrunk considerably! You can see
`the list of dropped capabilities in the Docker code
<https://github.com/dotcloud/docker/blob/v0.5.0/lxc_template.go#L97>`_,
and a full list of available capabilities in `Linux manpages
<http://man7.org/linux/man-pages/man7/capabilities.7.html>`_.
Of course, you can always enable extra capabilities if you really need
them (for instance, if you want to use a FUSE-based filesystem), but
by default, Docker containers will be locked down to ensure maximum
safety.
Other Kernel Security Features
------------------------------
Capabilities are just one of the many security features provided by
modern Linux kernels. It is also possible to leverage existing,
well-known systems like TOMOYO, AppArmor, SELinux, GRSEC, etc. with
Docker.
While Docker currently only enables capabilities, it doesn't interfere
with the other systems. This means that there are many different ways
to harden a Docker host. Here are a few examples.
* You can run a kernel with GRSEC and PAX. This will add many safety
checks, both at compile-time and run-time; it will also defeat many
exploits, thanks to techniques like address randomization. It
doesnt require Docker-specific configuration, since those security
features apply system-wide, independently of containers.
* If your distribution comes with security model templates for LXC
containers, you can use them out of the box. For instance, Ubuntu
comes with AppArmor templates for LXC, and those templates provide
an extra safety net (even though it overlaps greatly with
capabilities).
* You can define your own policies using your favorite access control
mechanism. Since Docker containers are standard LXC containers,
there is nothing “magic” or specific to Docker.
Just like there are many third-party tools to augment Docker
containers with e.g. special network topologies or shared filesystems,
you can expect to see tools to harden existing Docker containers
without affecting Dockers core.
Conclusions
-----------
Docker containers are, by default, quite secure; especially if you
take care of running your processes inside the containers as
non-privileged users (i.e. non root).
You can add an extra layer of safety by enabling Apparmor, SELinux,
GRSEC, or your favorite hardening solution.
Last but not least, if you see interesting security features in other
containerization systems, you will be able to implement them as well
with Docker, since everything is provided by the kernel anyway.
For more context and especially for comparisons with VMs and other
container systems, please also see the `original blog post
<blogsecurity>`_.
.. _blogsecurity: http://blog.docker.io/2013/08/containers-docker-how-secure-are-they/
+2 -2
View File
@@ -162,8 +162,8 @@ Verify it worked
Docker and UFW
^^^^^^^^^^^^^^
Docker uses a bridge to manage containers networking, by default UFW
drop all `forwarding`, a first step is to enable forwarding:
Docker uses a bridge to manage container networking. By default, UFW
drops all `forwarding`, thus a first step is to enable UFW forwarding:
.. code-block:: bash
+1 -1
View File
@@ -9,7 +9,7 @@ Using Vagrant (Mac, Linux)
This guide will setup a new virtualbox virtual machine with docker
installed on your computer. This works on most operating systems,
including MacOX, Windows, Linux, FreeBSD and others. If you can
including MacOSX, Windows, Linux, FreeBSD and others. If you can
install these and have at least 400MB RAM to spare you should be good.
Install Vagrant and Virtualbox
+4
View File
@@ -208,6 +208,10 @@ configuration / Device configuration)
.. image:: images/win/hp_bios_vm.JPG
On some machines the BIOS menu can only be accessed before startup.
To access BIOS in this scenario you should restart your computer and
press ESC/Enter when prompted to access the boot and BIOS controls. Typically
the option to allow virtualization is contained within the BIOS/Security menu.
Docker is not installed
```````````````````````
+7
View File
@@ -38,3 +38,10 @@ was when the container was stopped.
You can promote a container to an :ref:`image_def` with ``docker
commit``. Once a container is an image, you can use it as a parent for
new containers.
Container IDs
.............
All containers are identified by a 64 hexadecimal digit string (internally a 256bit
value). To simplify their use, a short ID of the first 12 characters can be used
on the commandline. There is a small possibility of short id collisions, so the
docker server will always return the long ID.
+8
View File
@@ -36,3 +36,11 @@ Base Image
..........
An image that has no parent is a **base image**.
Image IDs
.........
All images are identified by a 64 hexadecimal digit string (internally a 256bit
value). To simplify their use, a short ID of the first 12 characters can be used
on the command line. There is a small possibility of short id collisions, so the
docker server will always return the long ID.
+39 -25
View File
@@ -22,15 +22,29 @@ specify the path to it and manually start it.
# Run docker in daemon mode
sudo <path to>/docker -d &
Running an interactive shell
----------------------------
Download a pre-built image
--------------------------
.. code-block:: bash
# Download an ubuntu image
sudo docker pull ubuntu
This will find the ``ubuntu`` image by name in the :ref:`Central Index
<searching_central_index>` and download it from the top-level Central
Repository to a local image cache.
.. NOTE:: When the image has successfully downloaded, you will see a
12 character hash ``539c0211cd76: Download complete`` which is the
short form of the image ID. These short image IDs are the first 12
characters of the full image ID - which can be found using ``docker
inspect`` or ``docker images -notrunc=true``
Running an interactive shell
----------------------------
.. code-block:: bash
# Run an interactive shell in the ubuntu image,
# allocate a tty, attach stdin and stdout
# To detach the tty without exiting the shell,
@@ -39,32 +53,36 @@ Running an interactive shell
.. _dockergroup:
Why ``sudo``?
-------------
sudo and the docker Group
-------------------------
The ``docker`` daemon always runs as root, and since ``docker``
version 0.5.2, ``docker`` binds to a Unix socket instead of a TCP
port. By default that Unix socket is owned by the user *root*, and so,
by default, you can access it with ``sudo``.
Starting in version 0.5.3, if you create a Unix group called *docker*
and add users to it, then the ``docker`` daemon will make the
ownership of the Unix socket read/writable by the *docker* group when
the daemon starts. The ``docker`` daemon must always run as root, but
if you run the ``docker`` client as a user in the *docker* group then
you don't need to add ``sudo`` to all the client commands.
Starting in version 0.5.3, if you (or your Docker installer) create a
Unix group called *docker* and add users to it, then the ``docker``
daemon will make the ownership of the Unix socket read/writable by the
*docker* group when the daemon starts. The ``docker`` daemon must
always run as root, but if you run the ``docker`` client as a user in
the *docker* group then you don't need to add ``sudo`` to all the
client commands.
**Example:**
.. code-block:: bash
# Add the docker group
# Add the docker group if it doesn't already exist.
sudo groupadd docker
# Add the ubuntu user to the docker group
# Add the user "ubuntu" to the docker group.
# Change the user name to match your preferred user.
# You may have to logout and log back in again for
# this to take effect
# this to take effect.
sudo gpasswd -a ubuntu docker
# Restart the docker daemon
# Restart the docker daemon.
sudo service docker restart
.. _bind_docker:
@@ -72,7 +90,7 @@ you don't need to add ``sudo`` to all the client commands.
Bind Docker to another host/port or a Unix socket
-------------------------------------------------
.. DANGER:: Changing the default ``docker`` daemon binding to a TCP
.. warning:: Changing the default ``docker`` daemon binding to a TCP
port or Unix *docker* user group will increase your security risks
by allowing non-root users to potentially gain *root* access on the
host (`e.g. #1369
@@ -138,22 +156,19 @@ Listing all running containers
sudo docker ps
Expose a service on a TCP port
Bind a service on a TCP port
------------------------------
.. code-block:: bash
# Expose port 4444 of this container, and tell netcat to listen on it
# Bind port 4444 of this container, and tell netcat to listen on it
JOB=$(sudo docker run -d -p 4444 ubuntu:12.10 /bin/nc -l 4444)
# Which public port is NATed to my container?
PORT=$(sudo docker port $JOB 4444)
PORT=$(sudo docker port $JOB 4444 | awk -F: '{ print $2 }')
# Connect to the public port via the host's public address
# Please note that because of how routing works connecting to localhost or 127.0.0.1 $PORT will not work.
# Replace *eth0* according to your local interface name.
IP=$(ip -o -4 addr list eth0 | perl -n -e 'if (m{inet\s([\d\.]+)\/\d+\s}xms) { print $1 }')
echo hello world | nc $IP $PORT
# Connect to the public port
echo hello world | nc 127.0.0.1 $PORT
# Verify that the network connection worked
echo "Daemon received: $(sudo docker logs $JOB)"
@@ -183,4 +198,3 @@ You now have a image state from which you can create new instances.
Read more about :ref:`working_with_the_repository` or continue to the
complete :ref:`cli`
+75 -21
View File
@@ -15,27 +15,39 @@ commit them along the way, giving you a final image.
.. contents:: Table of Contents
.. _dockerfile_usage:
1. Usage
========
To build an image from a source repository, create a description file
called ``Dockerfile`` at the root of your repository. This file will
describe the steps to assemble the image.
To :ref:`build <cli_build>` an image from a source repository, create
a description file called ``Dockerfile`` at the root of your
repository. This file will describe the steps to assemble the image.
Then call ``docker build`` with the path of your source repository as
argument:
argument (for example, ``.``):
``sudo docker build .``
The path to the source repository defines where to find the *context*
of the build. The build is run by the Docker daemon, not by the CLI,
so the whole context must be transferred to the daemon. The Docker CLI
reports "Uploading context" when the context is sent to the daemon.
You can specify a repository and tag at which to save the new image if the
build succeeds:
``sudo docker build -t shykes/myapp .``
Docker will run your steps one-by-one, committing the result if necessary,
before finally outputting the ID of your new image.
The Docker daemon will run your steps one-by-one, committing the
result if necessary, before finally outputting the ID of your new
image. The Docker daemon will automatically clean up the context you
sent.
When you're done with your build, you're ready to look into :ref:`image_push`.
When you're done with your build, you're ready to look into
:ref:`image_push`.
.. _dockerfile_format:
2. Format
=========
@@ -63,12 +75,16 @@ allows statements like:
# Comment
RUN echo 'we are running some # of cool things'
.. _dockerfile_instructions:
3. Instructions
===============
Here is the set of instructions you can use in a ``Dockerfile`` for
building images.
.. _dockerfile_from:
3.1 FROM
--------
@@ -94,6 +110,8 @@ output by the commit before each new ``FROM`` command.
If no ``tag`` is given to the ``FROM`` instruction, ``latest`` is
assumed. If the used tag does not exist, an error will be returned.
.. _dockerfile_maintainer:
3.2 MAINTAINER
--------------
@@ -102,6 +120,8 @@ assumed. If the used tag does not exist, an error will be returned.
The ``MAINTAINER`` instruction allows you to set the *Author* field of
the generated images.
.. _dockerfile_run:
3.3 RUN
-------
@@ -116,6 +136,16 @@ core concepts of Docker where commits are cheap and containers can be
created from any point in an image's history, much like source
control.
Known Issues (RUN)
..................
* :issue:`783` is about file permissions problems that can occur when
using the AUFS file system. You might notice it during an attempt to
``rm`` a file, for example. The issue describes a workaround.
* :issue:`2424` Locale will not be set automatically.
.. _dockerfile_cmd:
3.4 CMD
-------
@@ -159,7 +189,7 @@ array:
If you would like your container to run the same executable every
time, then you should consider using ``ENTRYPOINT`` in combination
with ``CMD``. See :ref:`entrypoint_def`.
with ``CMD``. See :ref:`dockerfile_entrypoint`.
If the user specifies arguments to ``docker run`` then they will
override the default specified in CMD.
@@ -169,15 +199,19 @@ override the default specified in CMD.
command and commits the result; ``CMD`` does not execute anything at
build time, but specifies the intended command for the image.
.. _dockerfile_expose:
3.5 EXPOSE
----------
``EXPOSE <port> [<port>...]``
The ``EXPOSE`` instruction sets ports to be publicly exposed when
running the image. This is functionally equivalent to running ``docker
commit -run '{"PortSpecs": ["<port>", "<port2>"]}'`` outside the
builder. Take a look at :ref:`port_redirection` for more information.
The ``EXPOSE`` instruction exposes ports for use within links. This is
functionally equivalent to running ``docker commit -run '{"PortSpecs":
["<port>", "<port2>"]}'`` outside the builder. Refer to
:ref:`port_redirection` for detailed information.
.. _dockerfile_env:
3.6 ENV
-------
@@ -193,6 +227,8 @@ with ``<key>=<value>``
The environment variables will persist when a container is run
from the resulting image.
.. _dockerfile_add:
3.7 ADD
-------
@@ -208,8 +244,19 @@ a remote file URL.
``<dest>`` is the path at which the source will be copied in the
destination container.
All new files and directories are created with mode 0755, uid and gid
0.
.. note::
if you build using STDIN (``docker build - < somefile``), there is no build
context, so the Dockerfile can only contain an URL based ADD statement.
The copy obeys the following rules:
* The ``<src>`` path must be inside the *context* of the build; you cannot
``ADD ../something /something``, because the first step of a
``docker build`` is to send the context directory (and subdirectories) to
the docker daemon.
* If ``<src>`` is a URL and ``<dest>`` does not end with a trailing slash,
then a file is downloaded from the URL and copied to ``<dest>``.
* If ``<src>`` is a URL and ``<dest>`` does end with a trailing slash,
@@ -220,8 +267,9 @@ The copy obeys the following rules:
(``http://example.com`` will not work).
* If ``<src>`` is a directory, the entire directory is copied,
including filesystem metadata.
* If ``<src>`` is a tar archive in a recognized compression format
(identity, gzip, bzip2 or xz), it is unpacked as a directory.
* If ``<src>`` is a *local* tar archive in a recognized compression
format (identity, gzip, bzip2 or xz) then it is unpacked as a
directory. Resources from *remote* URLs are **not** decompressed.
When a directory is copied or unpacked, it has the same behavior as
``tar -x``: the result is the union of
@@ -229,7 +277,7 @@ The copy obeys the following rules:
1. whatever existed at the destination path and
2. the contents of the source tree,
with conflicts resolved in favor of 2) on a file-by-file basis.
with conflicts resolved in favor of "2." on a file-by-file basis.
* If ``<src>`` is any other kind of file, it is copied individually
along with its metadata. In this case, if ``<dest>`` ends with a
@@ -237,12 +285,11 @@ The copy obeys the following rules:
contents of ``<src>`` will be written at ``<dest>/base(<src>)``.
* If ``<dest>`` does not end with a trailing slash, it will be
considered a regular file and the contents of ``<src>`` will be
written at ``<dst>``.
written at ``<dest>``.
* If ``<dest>`` doesn't exist, it is created along with all missing
directories in its path. All new files and directories are created
with mode 0755, uid and gid 0.
directories in its path.
.. _entrypoint_def:
.. _dockerfile_entrypoint:
3.8 ENTRYPOINT
--------------
@@ -291,14 +338,18 @@ this optional but default, you could use a CMD:
CMD ["-l", "-"]
ENTRYPOINT ["/usr/bin/wc"]
.. _dockerfile_volume:
3.9 VOLUME
----------
``VOLUME ["/data"]``
The ``VOLUME`` instruction will add one or more new volumes to any
container created from the image.
The ``VOLUME`` instruction will create a mount point with the specified name and mark it
as holding externally mounted volumes from native host or other containers. For more information/examples
and mounting instructions via docker client, refer to :ref:`volume_def` documentation.
.. _dockerfile_user:
3.10 USER
---------
@@ -308,6 +359,8 @@ container created from the image.
The ``USER`` instruction sets the username or UID to use when running
the image.
.. _dockerfile_workdir:
3.11 WORKDIR
------------
@@ -316,6 +369,7 @@ the image.
The ``WORKDIR`` instruction sets the working directory in which
the command given by ``CMD`` is executed.
.. _dockerfile_examples:
4. Dockerfile Examples
======================
+20 -2
View File
@@ -29,14 +29,32 @@ Here are a few sample scripts for systemd and upstart to integrate with docker.
Sample Upstart Script
---------------------
In this example we've already created a container to run Redis with an id of
0a7e070b698b. To create an upstart script for our container, we create a file
named ``/etc/init/redis.conf`` and place the following into it:
.. code-block:: bash
description "Redis container"
author "Me"
start on filesystem and started lxc-net and started docker
start on filesystem and started docker
stop on runlevel [!2345]
respawn
exec docker start -a 0a7e070b698b
script
# Wait for docker to finish starting up first.
FILE=/var/run/docker.sock
while [ ! -e $FILE ] ; do
inotifywait -t 2 -e create $(dirname $FILE)
done
/usr/bin/docker start -a 0a7e070b698b
end script
Next, we have to configure docker so that it's run with the option ``-r=false``.
Run the following command:
.. code-block:: bash
$ sudo sh -c "echo 'DOCKER_OPTS=\"-r=false\"' > /etc/default/docker"
Sample systemd Script
+2
View File
@@ -19,3 +19,5 @@ Contents:
port_redirection
puppet
host_integration
working_with_volumes
working_with_links_names
+124 -17
View File
@@ -8,29 +8,136 @@
Port redirection
================
Docker can redirect public TCP and UDP ports to your container, so it can be
reached over the network. Port redirection is done on ``docker run``
using the -p flag.
A port redirect is specified as *PUBLIC:PRIVATE*, where TCP port
*PUBLIC* will be redirected to TCP port *PRIVATE*. As a special case,
the public port can be omitted, in which case a random public port
will be allocated.
Interacting with a service is commonly done through a connection to a
port. When this service runs inside a container, one can connect to
the port after finding the IP address of the container as follows:
.. code-block:: bash
# A random PUBLIC port is redirected to PRIVATE port 80 on the container
sudo docker run -p 80 <image> <cmd>
# Find IP address of container with ID <container_id>
docker inspect <container_id> | grep IPAddress | cut -d '"' -f 4
# PUBLIC port 80 is redirected to PRIVATE port 80
sudo docker run -p 80:80 <image> <cmd>
However, this IP address is local to the host system and the container
port is not reachable by the outside world. Furthermore, even if the
port is used locally, e.g. by another container, this method is
tedious as the IP address of the container changes every time it
starts.
To redirect a UDP port the redirection must be expressed as *PUBLIC:PRIVATE/udp*:
Docker addresses these two problems and give a simple and robust way
to access services running inside containers.
To allow non-local clients to reach the service running inside the
container, Docker provide ways to bind the container port to an
interface of the host system. To simplify communication between
containers, Docker provides the linking mechanism.
Binding a port to an host interface
-----------------------------------
To bind a port of the container to a specific interface of the host
system, use the ``-p`` parameter of the ``docker run`` command:
.. code-block:: bash
# PUBLIC port 5300 is redirected to the PRIVATE port 53 using UDP
sudo docker run -p 5300:53/udp <image> <cmd>
# General syntax
docker run -p [([<host_interface>:[host_port]])|(<host_port>):]<container_port>[/udp] <image> <cmd>
Default port redirects can be built into a container with the
``EXPOSE`` build command.
When no host interface is provided, the port is bound to all available
interfaces of the host machine (aka INADDR_ANY, or 0.0.0.0).When no host port is
provided, one is dynamically allocated. The possible combinations of options for
TCP port are the following:
.. code-block:: bash
# Bind TCP port 8080 of the container to TCP port 80 on 127.0.0.1 of the host machine.
docker run -p 127.0.0.1:80:8080 <image> <cmd>
# Bind TCP port 8080 of the container to a dynamically allocated TCP port on 127.0.0.1 of the host machine.
docker run -p 127.0.0.1::8080 <image> <cmd>
# Bind TCP port 8080 of the container to TCP port 80 on all available interfaces of the host machine.
docker run -p 80:8080 <image> <cmd>
# Bind TCP port 8080 of the container to a dynamically allocated TCP port on all available interfaces of the host machine.
docker run -p 8080 <image> <cmd>
UDP ports can also be bound by adding a trailing ``/udp``. All the
combinations described for TCP work. Here is only one example:
.. code-block:: bash
# Bind UDP port 5353 of the container to UDP port 53 on 127.0.0.1 of the host machine.
docker run -p 127.0.0.1:53:5353/udp <image> <cmd>
The command ``docker port`` lists the interface and port on the host
machine bound to a given container port. It is useful when using
dynamically allocated ports:
.. code-block:: bash
# Bind to a dynamically allocated port
docker run -p 127.0.0.1::8080 -name dyn-bound <image> <cmd>
# Lookup the actual port
docker port dyn-bound 8080
127.0.0.1:49160
Linking a container
-------------------
Communication between two containers can also be established in a
docker-specific way called linking.
To briefly present the concept of linking, let us consider two
containers: ``server``, containing the service, and ``client``,
accessing the service. Once ``server`` is running, ``client`` is
started and links to server. Linking sets environment variables in
``client`` giving it some information about ``server``. In this sense,
linking is a method of service discovery.
Let us now get back to our topic of interest; communication between
the two containers. We mentioned that the tricky part about this
communication was that the IP address of ``server`` was not
fixed. Therefore, some of the environment variables are going to be
used to inform ``client`` about this IP address. This process called
exposure, is possible because ``client`` is started after ``server``
has been started.
Here is a full example. On ``server``, the port of interest is
exposed. The exposure is done either through the ``-expose`` parameter
to the ``docker run`` command, or the ``EXPOSE`` build command in a
Dockerfile:
.. code-block:: bash
# Expose port 80
docker run -expose 80 -name server <image> <cmd>
The ``client`` then links to the ``server``:
.. code-block:: bash
# Link
docker run -name client -link server:linked-server <image> <cmd>
``client`` locally refers to ``server`` as ``linked-server``. The
following environment variables, among others, are available on
``client``:
.. code-block:: bash
# The default protocol, ip, and port of the service running in the container
LINKED-SERVER_PORT=tcp://172.17.0.8:80
# A specific protocol, ip, and port of various services
LINKED-SERVER_PORT_80_TCP=tcp://172.17.0.8:80
LINKED-SERVER_PORT_80_TCP_PROTO=tcp
LINKED-SERVER_PORT_80_TCP_ADDR=172.17.0.8
LINKED-SERVER_PORT_80_TCP_PORT=80
This tells ``client`` that a service is running on port 80 of
``server`` and that ``server`` is accessible at the IP address
172.17.0.8
Note: Using the ``-p`` parameter also exposes the port..
@@ -0,0 +1,104 @@
:title: Working with Links and Names
:description: How to create and use links and names
:keywords: Examples, Usage, links, docker, documentation, examples, names, name, container naming
.. _working_with_links_names:
Working with Links and Names
============================
From version 0.6.5 you are now able to ``name`` a container and ``link`` it to another
container by referring to its name. This will create a parent -> child relationship
where the parent container can see selected information about its child.
.. _run_name:
Container Naming
----------------
.. versionadded:: v0.6.5
You can now name your container by using the ``-name`` flag. If no name is provided, Docker
will automatically generate a name. You can see this name using the ``docker ps`` command.
.. code-block:: bash
# format is "sudo docker run -name <container_name> <image_name> <command>"
$ sudo docker run -name test ubuntu /bin/bash
# the flag "-a" Show all containers. Only running containers are shown by default.
$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2522602a0d99 ubuntu:12.04 /bin/bash 14 seconds ago Exit 0 test
.. _run_link:
Links: service discovery for docker
-----------------------------------
.. versionadded:: v0.6.5
Links allow containers to discover and securely communicate with each other by using the
flag ``-link name:alias``. Inter-container communication can be disabled with the daemon
flag ``-icc=false``. With this flag set to false, Container A cannot access Container B
unless explicitly allowed via a link. This is a huge win for securing your containers.
When two containers are linked together Docker creates a parent child relationship
between the containers. The parent container will be able to access information via
environment variables of the child such as name, exposed ports, IP and other selected
environment variables.
When linking two containers Docker will use the exposed ports of the container to create
a secure tunnel for the parent to access. If a database container only exposes port 8080
then the linked container will only be allowed to access port 8080 and nothing else if
inter-container communication is set to false.
.. code-block:: bash
# Example: there is an image called redis-2.6 that exposes the port 6379 and starts redis-server.
# Let's name the container as "redis" based on that image and run it as daemon.
$ sudo docker run -d -name redis redis-2.6
We can issue all the commands that you would expect using the name "redis"; start, stop,
attach, using the name for our container. The name also allows us to link other containers
into this one.
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 server we did not use
the -p flag to publish the Redis port to the host system. Redis exposed port 6379 and
this is all we need to establish a link.
.. code-block:: bash
# Linking the redis container as a child
$ sudo docker run -t -i -link redis:db -name webapp ubuntu bash
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 containers
that are linked into it.
If we inspect the environment variables of the second container, we would see all the information
about the child container.
.. code-block:: bash
$ root@4c01db0b339c:/# env
HOSTNAME=4c01db0b339c
DB_NAME=/webapp/db
TERM=xterm
DB_PORT=tcp://172.17.0.8:6379
DB_PORT_6379_TCP=tcp://172.17.0.8:6379
DB_PORT_6379_TCP_PROTO=tcp
DB_PORT_6379_TCP_ADDR=172.17.0.8
DB_PORT_6379_TCP_PORT=6379
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
SHLVL=1
HOME=/
container=lxc
_=/usr/bin/env
root@4c01db0b339c:/#
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 in the environment.
+89
View File
@@ -0,0 +1,89 @@
:title: Working with Volumes
:description: How to create and share volumes
:keywords: Examples, Usage, volume, docker, documentation, examples
.. _volume_def:
Data Volume
===========
.. versionadded:: v0.3.0
Data volumes have been available since version 1 of the
:doc:`../api/docker_remote_api`
A *data volume* is a specially-designated directory within one or more
containers that bypasses the :ref:`ufs_def` to provide several useful
features for persistant or shared data:
* **Data volumes can be shared and reused between containers.** This
is the feature that makes data volumes so powerful. You can use it
for anything from hot database upgrades to custom backup or
replication tools. See the example below.
* **Changes to a data volume are made directly**, without the overhead
of a copy-on-write mechanism. This is good for very large files.
* **Changes to a data volume will not be included at the next commit**
because they are not recorded as regular filesystem changes in the
top layer of the :ref:`ufs_def`
Each container can have zero or more data volumes.
Getting Started
...............
Using data volumes is as simple as adding a new flag: ``-v``. The
parameter ``-v`` can be used more than once in order to create more
volumes within the new container. The example below shows the
instruction to create a container with two new volumes::
docker run -v /var/volume1 -v /var/volume2 shykes/couchdb
For a Dockerfile, the VOLUME instruction will add one or more new
volumes to any container created from the image::
VOLUME ["/var/volume1", "/var/volume2"]
Mount Volumes from an Existing Container:
-----------------------------------------
The command below creates a new container which is runnning as daemon
``-d`` and with one volume ``/var/lib/couchdb``::
COUCH1=$(sudo docker run -d -v /var/lib/couchdb shykes/couchdb:2013-05-03)
From the container id of that previous container ``$COUCH1`` it's
possible to create new container sharing the same volume using the
parameter ``-volumes-from container_id``::
COUCH2=$(sudo docker run -d -volumes-from $COUCH1 shykes/couchdb:2013-05-03)
Now, the second container has the all the information from the first volume.
Mount a Host Directory as a Container Volume:
---------------------------------------------
::
-v=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro].
If "host-dir" is missing, then docker creates a new volume.
This is not available for a Dockerfile due the portability and sharing
purpose of it. The [host-dir] volumes is something 100% host dependent
and will break on any other machine.
For example::
sudo docker run -v /var/logs:/var/host_logs:ro shykes/couchdb:2013-05-03
The command above mounts the host directory ``/var/logs`` into the
container with read only permissions as ``/var/host_logs``.
.. versionadded:: v0.5.0
Known Issues
............
* :issue:`2702`: "lxc-start: Permission denied - failed to mount"
could indicate a permissions problem with AppArmor. Please see the
issue for a workaround.
@@ -177,6 +177,15 @@ you can push and pull it like any other repository, but it will
there will be no user name checking performed. Your registry will
function completely independently from the Central Index.
.. raw:: html
<iframe width="640" height="360"
src="//www.youtube.com/embed/CAewZCBT4PI?rel=0" frameborder="0"
allowfullscreen></iframe>
.. seealso:: `Docker Blog: How to use your own registry
<http://blog.docker.io/2013/07/how-to-use-your-own-registry/>`_
Authentication file
-------------------
+2 -1
View File
@@ -129,7 +129,8 @@
<div class="row footer">
<div class="span12 tbox">
<div class="tbox">
<p>Docker is an open source project, sponsored by <a href="https://dotcloud.com">dotCloud</a>, under the <a href="https://github.com/dotcloud/docker/blob/master/LICENSE" title="Docker licence, hosted in the Github repository">apache 2.0 licence</a></p>
<p>Docker is an open source project, sponsored by <a href="https://www.docker.com">Docker Inc.</a>, under the <a href="https://github.com/dotcloud/docker/blob/master/LICENSE" title="Docker licence, hosted in the Github repository">apache 2.0 licence</a></p>
<p>Documentation proudly hosted by <a href="http://www.readthedocs.org">Read the Docs</a></p>
</div>
<div class="social links">
+1
View File
@@ -0,0 +1 @@
Solomon Hykes <solomon@dotcloud.com>
+116
View File
@@ -0,0 +1,116 @@
package engine
import (
"fmt"
"github.com/dotcloud/docker/utils"
"log"
"os"
"runtime"
"strings"
)
type Handler func(*Job) string
var globalHandlers map[string]Handler
func init() {
globalHandlers = make(map[string]Handler)
}
func Register(name string, handler Handler) error {
_, exists := globalHandlers[name]
if exists {
return fmt.Errorf("Can't overwrite global handler for command %s", name)
}
globalHandlers[name] = handler
return nil
}
// The Engine is the core of Docker.
// It acts as a store for *containers*, and allows manipulation of these
// containers by executing *jobs*.
type Engine struct {
root string
handlers map[string]Handler
hack Hack // data for temporary hackery (see hack.go)
id string
}
func (eng *Engine) Root() string {
return eng.root
}
func (eng *Engine) Register(name string, handler Handler) error {
eng.Logf("Register(%s) (handlers=%v)", name, eng.handlers)
_, exists := eng.handlers[name]
if exists {
return fmt.Errorf("Can't overwrite handler for command %s", name)
}
eng.handlers[name] = handler
return nil
}
// New initializes a new engine managing the directory specified at `root`.
// `root` is used to store containers and any other state private to the engine.
// Changing the contents of the root without executing a job will cause unspecified
// behavior.
func New(root string) (*Engine, error) {
// Check for unsupported architectures
if runtime.GOARCH != "amd64" {
return nil, fmt.Errorf("The docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting.", runtime.GOARCH)
}
// Check for unsupported kernel versions
// FIXME: it would be cleaner to not test for specific versions, but rather
// test for specific functionalities.
// Unfortunately we can't test for the feature "does not cause a kernel panic"
// without actually causing a kernel panic, so we need this workaround until
// the circumstances of pre-3.8 crashes are clearer.
// For details see http://github.com/dotcloud/docker/issues/407
if k, err := utils.GetKernelVersion(); err != nil {
log.Printf("WARNING: %s\n", err)
} else {
if utils.CompareKernelVersion(k, &utils.KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0}) < 0 {
log.Printf("WARNING: You are running linux kernel version %s, which might be unstable running docker. Please upgrade your kernel to 3.8.0.", k.String())
}
}
if err := os.MkdirAll(root, 0700); err != nil && !os.IsExist(err) {
return nil, err
}
eng := &Engine{
root: root,
handlers: make(map[string]Handler),
id: utils.RandomString(),
}
// Copy existing global handlers
for k, v := range globalHandlers {
eng.handlers[k] = v
}
return eng, nil
}
func (eng *Engine) String() string {
return fmt.Sprintf("%s|%s", eng.Root(), eng.id[:8])
}
// Job creates a new job which can later be executed.
// This function mimics `Command` from the standard os/exec package.
func (eng *Engine) Job(name string, args ...string) *Job {
job := &Job{
Eng: eng,
Name: name,
Args: args,
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
}
handler, exists := eng.handlers[name]
if exists {
job.handler = handler
}
return job
}
func (eng *Engine) Logf(format string, args ...interface{}) (n int, err error) {
prefixedFormat := fmt.Sprintf("[%s] %s\n", eng, strings.TrimRight(format, "\n"))
return fmt.Fprintf(os.Stderr, prefixedFormat, args...)
}
+55
View File
@@ -0,0 +1,55 @@
package engine
import (
"testing"
)
func TestRegister(t *testing.T) {
if err := Register("dummy1", nil); err != nil {
t.Fatal(err)
}
if err := Register("dummy1", nil); err == nil {
t.Fatalf("Expecting error, got none")
}
eng := newTestEngine(t)
//Should fail because globan handlers are copied
//at the engine creation
if err := eng.Register("dummy1", nil); err == nil {
t.Fatalf("Expecting error, got none")
}
if err := eng.Register("dummy2", nil); err != nil {
t.Fatal(err)
}
if err := eng.Register("dummy2", nil); err == nil {
t.Fatalf("Expecting error, got none")
}
}
func TestJob(t *testing.T) {
eng := newTestEngine(t)
job1 := eng.Job("dummy1", "--level=awesome")
if job1.handler != nil {
t.Fatalf("job1.handler should be empty")
}
h := func(j *Job) string {
return j.Name
}
eng.Register("dummy2", h)
job2 := eng.Job("dummy2", "--level=awesome")
if job2.handler == nil {
t.Fatalf("job2.handler shouldn't be nil")
}
if job2.handler(job2) != job2.Name {
t.Fatalf("handler dummy2 was not found in job2")
}
}
+123
View File
@@ -0,0 +1,123 @@
package engine
import (
"testing"
)
func TestNewJob(t *testing.T) {
job := mkJob(t, "dummy", "--level=awesome")
if job.Name != "dummy" {
t.Fatalf("Wrong job name: %s", job.Name)
}
if len(job.Args) != 1 {
t.Fatalf("Wrong number of job arguments: %d", len(job.Args))
}
if job.Args[0] != "--level=awesome" {
t.Fatalf("Wrong job arguments: %s", job.Args[0])
}
}
func TestSetenv(t *testing.T) {
job := mkJob(t, "dummy")
job.Setenv("foo", "bar")
if val := job.Getenv("foo"); val != "bar" {
t.Fatalf("Getenv returns incorrect value: %s", val)
}
job.Setenv("bar", "")
if val := job.Getenv("bar"); val != "" {
t.Fatalf("Getenv returns incorrect value: %s", val)
}
if val := job.Getenv("nonexistent"); val != "" {
t.Fatalf("Getenv returns incorrect value: %s", val)
}
}
func TestSetenvBool(t *testing.T) {
job := mkJob(t, "dummy")
job.SetenvBool("foo", true)
if val := job.GetenvBool("foo"); !val {
t.Fatalf("GetenvBool returns incorrect value: %b", val)
}
job.SetenvBool("bar", false)
if val := job.GetenvBool("bar"); val {
t.Fatalf("GetenvBool returns incorrect value: %b", val)
}
if val := job.GetenvBool("nonexistent"); val {
t.Fatalf("GetenvBool returns incorrect value: %b", val)
}
}
func TestSetenvInt(t *testing.T) {
job := mkJob(t, "dummy")
job.SetenvInt("foo", -42)
if val := job.GetenvInt("foo"); val != -42 {
t.Fatalf("GetenvInt returns incorrect value: %d", val)
}
job.SetenvInt("bar", 42)
if val := job.GetenvInt("bar"); val != 42 {
t.Fatalf("GetenvInt returns incorrect value: %d", val)
}
if val := job.GetenvInt("nonexistent"); val != -1 {
t.Fatalf("GetenvInt returns incorrect value: %d", val)
}
}
func TestSetenvList(t *testing.T) {
job := mkJob(t, "dummy")
job.SetenvList("foo", []string{"bar"})
if val := job.GetenvList("foo"); len(val) != 1 || val[0] != "bar" {
t.Fatalf("GetenvList returns incorrect value: %v", val)
}
job.SetenvList("bar", nil)
if val := job.GetenvList("bar"); val != nil {
t.Fatalf("GetenvList returns incorrect value: %v", val)
}
if val := job.GetenvList("nonexistent"); val != nil {
t.Fatalf("GetenvList returns incorrect value: %v", val)
}
}
func TestImportEnv(t *testing.T) {
type dummy struct {
DummyInt int
DummyStringArray []string
}
job := mkJob(t, "dummy")
if err := job.ImportEnv(&dummy{42, []string{"foo", "bar"}}); err != nil {
t.Fatal(err)
}
dmy := dummy{}
if err := job.ExportEnv(&dmy); err != nil {
t.Fatal(err)
}
if dmy.DummyInt != 42 {
t.Fatalf("Expected 42, got %d", dmy.DummyInt)
}
if len(dmy.DummyStringArray) != 2 || dmy.DummyStringArray[0] != "foo" || dmy.DummyStringArray[1] != "bar" {
t.Fatalf("Expected {foo, bar}, got %v", dmy.DummyStringArray)
}
}
func TestEnviron(t *testing.T) {
job := mkJob(t, "dummy")
job.Setenv("foo", "bar")
val, exists := job.Environ()["foo"]
if !exists {
t.Fatalf("foo not found in the environ")
}
if val != "bar" {
t.Fatalf("bar not found in the environ")
}
}
+21
View File
@@ -0,0 +1,21 @@
package engine
type Hack map[string]interface{}
func (eng *Engine) Hack_GetGlobalVar(key string) interface{} {
if eng.hack == nil {
return nil
}
val, exists := eng.hack[key]
if !exists {
return nil
}
return val
}
func (eng *Engine) Hack_SetGlobalVar(key string, val interface{}) {
if eng.hack == nil {
eng.hack = make(Hack)
}
eng.hack[key] = val
}
+38
View File
@@ -0,0 +1,38 @@
package engine
import (
"fmt"
"github.com/dotcloud/docker/utils"
"io/ioutil"
"runtime"
"strings"
"testing"
)
var globalTestID string
func newTestEngine(t *testing.T) *Engine {
// Use the caller function name as a prefix.
// This helps trace temp directories back to their test.
pc, _, _, _ := runtime.Caller(1)
callerLongName := runtime.FuncForPC(pc).Name()
parts := strings.Split(callerLongName, ".")
callerShortName := parts[len(parts)-1]
if globalTestID == "" {
globalTestID = utils.RandomString()[:4]
}
prefix := fmt.Sprintf("docker-test%s-%s-", globalTestID, callerShortName)
root, err := ioutil.TempDir("", prefix)
if err != nil {
t.Fatal(err)
}
eng, err := New(root)
if err != nil {
t.Fatal(err)
}
return eng
}
func mkJob(t *testing.T, name string, args ...string) *Job {
return newTestEngine(t).Job(name, args...)
}
+342
View File
@@ -0,0 +1,342 @@
package engine
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"strconv"
"strings"
"sync"
)
// A job is the fundamental unit of work in the docker engine.
// Everything docker can do should eventually be exposed as a job.
// For example: execute a process in a container, create a new container,
// download an archive from the internet, serve the http api, etc.
//
// The job API is designed after unix processes: a job has a name, arguments,
// environment variables, standard streams for input, output and error, and
// an exit status which can indicate success (0) or error (anything else).
//
// One slight variation is that jobs report their status as a string. The
// string "0" indicates success, and any other strings indicates an error.
// This allows for richer error reporting.
//
type Job struct {
Eng *Engine
Name string
Args []string
env []string
Stdin io.Reader
Stdout io.Writer
Stderr io.Writer
handler func(*Job) string
status string
onExit []func()
}
// Run executes the job and blocks until the job completes.
// If the job returns a failure status, an error is returned
// which includes the status.
func (job *Job) Run() error {
defer func() {
var wg sync.WaitGroup
for _, f := range job.onExit {
wg.Add(1)
go func(f func()) {
f()
wg.Done()
}(f)
}
wg.Wait()
}()
if job.Stdout != nil && job.Stdout != os.Stdout {
job.Stdout = io.MultiWriter(job.Stdout, os.Stdout)
}
if job.Stderr != nil && job.Stderr != os.Stderr {
job.Stderr = io.MultiWriter(job.Stderr, os.Stderr)
}
job.Eng.Logf("+job %s", job.CallString())
defer func() {
job.Eng.Logf("-job %s%s", job.CallString(), job.StatusString())
}()
if job.handler == nil {
job.status = "command not found"
} else {
job.status = job.handler(job)
}
if job.status != "0" {
return fmt.Errorf("%s: %s", job.Name, job.status)
}
return nil
}
func (job *Job) StdoutParseLines(dst *[]string, limit int) {
job.parseLines(job.StdoutPipe(), dst, limit)
}
func (job *Job) StderrParseLines(dst *[]string, limit int) {
job.parseLines(job.StderrPipe(), dst, limit)
}
func (job *Job) parseLines(src io.Reader, dst *[]string, limit int) {
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
scanner := bufio.NewScanner(src)
for scanner.Scan() {
// If the limit is reached, flush the rest of the source and return
if limit > 0 && len(*dst) >= limit {
io.Copy(ioutil.Discard, src)
return
}
line := scanner.Text()
// Append the line (with delimitor removed)
*dst = append(*dst, line)
}
}()
job.onExit = append(job.onExit, wg.Wait)
}
func (job *Job) StdoutParseString(dst *string) {
lines := make([]string, 0, 1)
job.StdoutParseLines(&lines, 1)
job.onExit = append(job.onExit, func() {
if len(lines) >= 1 {
*dst = lines[0]
}
})
}
func (job *Job) StderrParseString(dst *string) {
lines := make([]string, 0, 1)
job.StderrParseLines(&lines, 1)
job.onExit = append(job.onExit, func() { *dst = lines[0] })
}
func (job *Job) StdoutPipe() io.ReadCloser {
r, w := io.Pipe()
job.Stdout = w
job.onExit = append(job.onExit, func() { w.Close() })
return r
}
func (job *Job) StderrPipe() io.ReadCloser {
r, w := io.Pipe()
job.Stderr = w
job.onExit = append(job.onExit, func() { w.Close() })
return r
}
func (job *Job) CallString() string {
return fmt.Sprintf("%s(%s)", job.Name, strings.Join(job.Args, ", "))
}
func (job *Job) StatusString() string {
// FIXME: if a job returns the empty string, it will be printed
// as not having returned.
// (this only affects String which is a convenience function).
if job.status != "" {
var okerr string
if job.status == "0" {
okerr = "OK"
} else {
okerr = "ERR"
}
return fmt.Sprintf(" = %s (%s)", okerr, job.status)
}
return ""
}
// String returns a human-readable description of `job`
func (job *Job) String() string {
return fmt.Sprintf("%s.%s%s", job.Eng, job.CallString(), job.StatusString())
}
func (job *Job) Getenv(key string) (value string) {
for _, kv := range job.env {
if strings.Index(kv, "=") == -1 {
continue
}
parts := strings.SplitN(kv, "=", 2)
if parts[0] != key {
continue
}
if len(parts) < 2 {
value = ""
} else {
value = parts[1]
}
}
return
}
func (job *Job) GetenvBool(key string) (value bool) {
s := strings.ToLower(strings.Trim(job.Getenv(key), " \t"))
if s == "" || s == "0" || s == "no" || s == "false" || s == "none" {
return false
}
return true
}
func (job *Job) SetenvBool(key string, value bool) {
if value {
job.Setenv(key, "1")
} else {
job.Setenv(key, "0")
}
}
func (job *Job) GetenvInt(key string) int64 {
s := strings.Trim(job.Getenv(key), " \t")
val, err := strconv.ParseInt(s, 10, 64)
if err != nil {
return -1
}
return val
}
func (job *Job) SetenvInt(key string, value int64) {
job.Setenv(key, fmt.Sprintf("%d", value))
}
// Returns nil if key not found
func (job *Job) GetenvList(key string) []string {
sval := job.Getenv(key)
if sval == "" {
return nil
}
l := make([]string, 0, 1)
if err := json.Unmarshal([]byte(sval), &l); err != nil {
l = append(l, sval)
}
return l
}
func (job *Job) SetenvJson(key string, value interface{}) error {
sval, err := json.Marshal(value)
if err != nil {
return err
}
job.Setenv(key, string(sval))
return nil
}
func (job *Job) SetenvList(key string, value []string) error {
return job.SetenvJson(key, value)
}
func (job *Job) Setenv(key, value string) {
job.env = append(job.env, key+"="+value)
}
// DecodeEnv decodes `src` as a json dictionary, and adds
// each decoded key-value pair to the environment.
//
// If `src` cannot be decoded as a json dictionary, an error
// is returned.
func (job *Job) DecodeEnv(src io.Reader) error {
m := make(map[string]interface{})
if err := json.NewDecoder(src).Decode(&m); err != nil {
return err
}
for k, v := range m {
// FIXME: we fix-convert float values to int, because
// encoding/json decodes integers to float64, but cannot encode them back.
// (See http://golang.org/src/pkg/encoding/json/decode.go#L46)
if fval, ok := v.(float64); ok {
job.SetenvInt(k, int64(fval))
} else if sval, ok := v.(string); ok {
job.Setenv(k, sval)
} else if val, err := json.Marshal(v); err == nil {
job.Setenv(k, string(val))
} else {
job.Setenv(k, fmt.Sprintf("%v", v))
}
}
return nil
}
func (job *Job) EncodeEnv(dst io.Writer) error {
m := make(map[string]interface{})
for k, v := range job.Environ() {
var val interface{}
if err := json.Unmarshal([]byte(v), &val); err == nil {
// FIXME: we fix-convert float values to int, because
// encoding/json decodes integers to float64, but cannot encode them back.
// (See http://golang.org/src/pkg/encoding/json/decode.go#L46)
if fval, isFloat := val.(float64); isFloat {
val = int(fval)
}
m[k] = val
} else {
m[k] = v
}
}
if err := json.NewEncoder(dst).Encode(&m); err != nil {
return err
}
return nil
}
func (job *Job) ExportEnv(dst interface{}) (err error) {
defer func() {
if err != nil {
err = fmt.Errorf("ExportEnv %s", err)
}
}()
var buf bytes.Buffer
// step 1: encode/marshal the env to an intermediary json representation
if err := job.EncodeEnv(&buf); err != nil {
return err
}
// step 2: decode/unmarshal the intermediary json into the destination object
if err := json.NewDecoder(&buf).Decode(dst); err != nil {
return err
}
return nil
}
func (job *Job) ImportEnv(src interface{}) (err error) {
defer func() {
if err != nil {
err = fmt.Errorf("ImportEnv: %s", err)
}
}()
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(src); err != nil {
return err
}
if err := job.DecodeEnv(&buf); err != nil {
return err
}
return nil
}
func (job *Job) Environ() map[string]string {
m := make(map[string]string)
for _, kv := range job.env {
parts := strings.SplitN(kv, "=", 2)
m[parts[0]] = parts[1]
}
return m
}
func (job *Job) Logf(format string, args ...interface{}) (n int, err error) {
prefixedFormat := fmt.Sprintf("[%s] %s\n", job, strings.TrimRight(format, "\n"))
return fmt.Fprintf(job.Stderr, prefixedFormat, args...)
}
func (job *Job) Printf(format string, args ...interface{}) (n int, err error) {
return fmt.Fprintf(job.Stdout, format, args...)
}
func (job *Job) Errorf(format string, args ...interface{}) (n int, err error) {
return fmt.Fprintf(job.Stderr, format, args...)
}
+70 -50
View File
@@ -2,6 +2,8 @@ package docker
import (
"fmt"
"github.com/dotcloud/docker/archive"
"github.com/dotcloud/docker/graphdriver"
"github.com/dotcloud/docker/utils"
"io"
"io/ioutil"
@@ -9,6 +11,7 @@ import (
"path"
"path/filepath"
"strings"
"syscall"
"time"
)
@@ -16,11 +19,12 @@ import (
type Graph struct {
Root string
idIndex *utils.TruncIndex
driver graphdriver.Driver
}
// NewGraph instantiates a new graph at the given root path in the filesystem.
// `root` will be created if it doesn't exist.
func NewGraph(root string) (*Graph, error) {
func NewGraph(root string, driver graphdriver.Driver) (*Graph, error) {
abspath, err := filepath.Abs(root)
if err != nil {
return nil, err
@@ -29,9 +33,11 @@ func NewGraph(root string) (*Graph, error) {
if err := os.MkdirAll(root, 0700); err != nil && !os.IsExist(err) {
return nil, err
}
graph := &Graph{
Root: abspath,
idIndex: utils.NewTruncIndex(),
driver: driver,
}
if err := graph.restore(); err != nil {
return nil, err
@@ -46,7 +52,9 @@ func (graph *Graph) restore() error {
}
for _, v := range dir {
id := v.Name()
graph.idIndex.Add(id)
if graph.driver.Exists(id) {
graph.idIndex.Add(id)
}
}
return nil
}
@@ -77,16 +85,22 @@ func (graph *Graph) Get(name string) (*Image, error) {
if err != nil {
return nil, err
}
// Check that the filesystem layer exists
rootfs, err := graph.driver.Get(img.ID)
if err != nil {
return nil, fmt.Errorf("Driver %s failed to get image rootfs %s: %s", graph.driver, img.ID, err)
}
if img.ID != id {
return nil, fmt.Errorf("Image stored at '%s' has wrong id '%s'", id, img.ID)
}
img.graph = graph
if img.Size == 0 {
root, err := img.root()
size, err := utils.TreeSize(rootfs)
if err != nil {
return nil, err
return nil, fmt.Errorf("Error computing size of rootfs %s: %s", img.ID, err)
}
if err := StoreSize(img, root); err != nil {
img.Size = size
if err := img.SaveSize(graph.imageRoot(id)); err != nil {
return nil, err
}
}
@@ -94,7 +108,7 @@ func (graph *Graph) Get(name string) (*Image, error) {
}
// Create creates a new image and registers it in the graph.
func (graph *Graph) Create(layerData Archive, container *Container, comment, author string, config *Config) (*Image, error) {
func (graph *Graph) Create(layerData archive.Archive, container *Container, comment, author string, config *Config) (*Image, error) {
img := &Image{
ID: GenerateID(),
Comment: comment,
@@ -117,7 +131,7 @@ func (graph *Graph) Create(layerData Archive, container *Container, comment, aut
// Register imports a pre-existing image into the graph.
// FIXME: pass img as first argument
func (graph *Graph) Register(jsonData []byte, layerData Archive, img *Image) error {
func (graph *Graph) Register(jsonData []byte, layerData archive.Archive, img *Image) error {
if err := ValidateID(img.ID); err != nil {
return err
}
@@ -125,19 +139,37 @@ func (graph *Graph) Register(jsonData []byte, layerData Archive, img *Image) err
if graph.Exists(img.ID) {
return fmt.Errorf("Image %s already exists", img.ID)
}
// Ensure that the image root does not exist on the filesystem
// when it is not registered in the graph.
// This is common when you switch from one graph driver to another
if err := os.RemoveAll(graph.imageRoot(img.ID)); err != nil && !os.IsNotExist(err) {
return err
}
tmp, err := graph.Mktemp("")
defer os.RemoveAll(tmp)
if err != nil {
return fmt.Errorf("Mktemp failed: %s", err)
}
if err := StoreImage(img, jsonData, layerData, tmp); err != nil {
// Create root filesystem in the driver
if err := graph.driver.Create(img.ID, img.Parent); err != nil {
return fmt.Errorf("Driver %s failed to create image rootfs %s: %s", graph.driver, img.ID, err)
}
// Mount the root filesystem so we can apply the diff/layer
rootfs, err := graph.driver.Get(img.ID)
if err != nil {
return fmt.Errorf("Driver %s failed to get image rootfs %s: %s", graph.driver, img.ID, err)
}
img.graph = graph
if err := StoreImage(img, jsonData, layerData, tmp, rootfs); err != nil {
return err
}
// Commit
if err := os.Rename(tmp, graph.imageRoot(img.ID)); err != nil {
return err
}
img.graph = graph
graph.idIndex.Add(img.ID)
return nil
}
@@ -146,98 +178,83 @@ func (graph *Graph) Register(jsonData []byte, layerData Archive, img *Image) err
// The archive is stored on disk and will be automatically deleted as soon as has been read.
// If output is not nil, a human-readable progress bar will be written to it.
// FIXME: does this belong in Graph? How about MktempFile, let the caller use it for archives?
func (graph *Graph) TempLayerArchive(id string, compression Compression, sf *utils.StreamFormatter, output io.Writer) (*TempArchive, error) {
func (graph *Graph) TempLayerArchive(id string, compression archive.Compression, sf *utils.StreamFormatter, output io.Writer) (*archive.TempArchive, error) {
image, err := graph.Get(id)
if err != nil {
return nil, err
}
tmp, err := graph.tmp()
tmp, err := graph.Mktemp("")
if err != nil {
return nil, err
}
archive, err := image.TarLayer(compression)
a, err := image.TarLayer()
if err != nil {
return nil, err
}
return NewTempArchive(utils.ProgressReader(ioutil.NopCloser(archive), 0, output, sf.FormatProgress("", "Buffering to disk", "%v/%v (%v)"), sf, true), tmp.Root)
return archive.NewTempArchive(utils.ProgressReader(ioutil.NopCloser(a), 0, output, sf.FormatProgress("", "Buffering to disk", "%v/%v (%v)"), sf, true), tmp)
}
// Mktemp creates a temporary sub-directory inside the graph's filesystem.
func (graph *Graph) Mktemp(id string) (string, error) {
if id == "" {
id = GenerateID()
dir := path.Join(graph.Root, "_tmp", GenerateID())
if err := os.MkdirAll(dir, 0700); err != nil {
return "", err
}
tmp, err := graph.tmp()
if err != nil {
return "", fmt.Errorf("Couldn't create temp: %s", err)
}
if tmp.Exists(id) {
return "", fmt.Errorf("Image %s already exists", id)
}
return tmp.imageRoot(id), nil
return dir, nil
}
// getDockerInitLayer returns the path of a layer containing a mountpoint suitable
// setupInitLayer populates a directory with mountpoints suitable
// for bind-mounting dockerinit into the container. The mountpoint is simply an
// empty file at /.dockerinit
//
// This extra layer is used by all containers as the top-most ro layer. It protects
// the container from unwanted side-effects on the rw layer.
func (graph *Graph) getDockerInitLayer() (string, error) {
tmp, err := graph.tmp()
if err != nil {
return "", err
}
initLayer := tmp.imageRoot("_dockerinit")
if err := os.Mkdir(initLayer, 0755); err != nil && !os.IsExist(err) {
// If directory already existed, keep going.
// For all other errors, abort.
return "", err
}
func setupInitLayer(initLayer string) error {
for pth, typ := range map[string]string{
"/dev/pts": "dir",
"/dev/shm": "dir",
"/proc": "dir",
"/sys": "dir",
"/.dockerinit": "file",
"/.dockerenv": "file",
"/etc/resolv.conf": "file",
"/etc/hosts": "file",
"/etc/hostname": "file",
// "var/run": "dir",
// "var/lock": "dir",
} {
parts := strings.Split(pth, "/")
prev := "/"
for _, p := range parts[1:] {
prev = path.Join(prev, p)
syscall.Unlink(path.Join(initLayer, prev))
}
if _, err := os.Stat(path.Join(initLayer, pth)); err != nil {
if os.IsNotExist(err) {
switch typ {
case "dir":
if err := os.MkdirAll(path.Join(initLayer, pth), 0755); err != nil {
return "", err
return err
}
case "file":
if err := os.MkdirAll(path.Join(initLayer, path.Dir(pth)), 0755); err != nil {
return "", err
return err
}
if f, err := os.OpenFile(path.Join(initLayer, pth), os.O_CREATE, 0755); err != nil {
return "", err
} else {
f.Close()
f, err := os.OpenFile(path.Join(initLayer, pth), os.O_CREATE, 0755)
if err != nil {
return err
}
f.Close()
}
} else {
return "", err
return err
}
}
}
// Layer is ready to use, if it wasn't before.
return initLayer, nil
}
func (graph *Graph) tmp() (*Graph, error) {
// Changed to _tmp from :tmp:, because it messed with ":" separators in aufs branch syntax...
return NewGraph(path.Join(graph.Root, "_tmp"))
return nil
}
// Check if given error is "not empty".
@@ -269,6 +286,9 @@ func (graph *Graph) Delete(name string) error {
if err != nil {
return err
}
// Remove rootfs data from the driver
graph.driver.Remove(id)
// Remove the trashed image directory
return os.RemoveAll(tmp)
}
+20 -45
View File
@@ -4,18 +4,19 @@ import (
"archive/tar"
"bytes"
"errors"
"github.com/dotcloud/docker/archive"
"github.com/dotcloud/docker/graphdriver"
"github.com/dotcloud/docker/utils"
"io"
"io/ioutil"
"os"
"path"
"testing"
"time"
)
func TestInit(t *testing.T) {
graph := tempGraph(t)
defer os.RemoveAll(graph.Root)
defer nukeGraph(graph)
// Root should exist
if _, err := os.Stat(graph.Root); err != nil {
t.Fatal(err)
@@ -31,7 +32,7 @@ func TestInit(t *testing.T) {
// Test that Register can be interrupted cleanly without side effects
func TestInterruptedRegister(t *testing.T) {
graph := tempGraph(t)
defer os.RemoveAll(graph.Root)
defer nukeGraph(graph)
badArchive, w := io.Pipe() // Use a pipe reader as a fake archive which never yields data
image := &Image{
ID: GenerateID(),
@@ -58,7 +59,7 @@ func TestInterruptedRegister(t *testing.T) {
// create multiple, check the amount of images and paths, etc..)
func TestGraphCreate(t *testing.T) {
graph := tempGraph(t)
defer os.RemoveAll(graph.Root)
defer nukeGraph(graph)
archive, err := fakeTar()
if err != nil {
t.Fatal(err)
@@ -89,7 +90,7 @@ func TestGraphCreate(t *testing.T) {
func TestRegister(t *testing.T) {
graph := tempGraph(t)
defer os.RemoveAll(graph.Root)
defer nukeGraph(graph)
archive, err := fakeTar()
if err != nil {
t.Fatal(err)
@@ -120,45 +121,10 @@ func TestRegister(t *testing.T) {
}
}
func TestMount(t *testing.T) {
graph := tempGraph(t)
defer os.RemoveAll(graph.Root)
archive, err := fakeTar()
if err != nil {
t.Fatal(err)
}
image, err := graph.Create(archive, nil, "Testing", "", nil)
if err != nil {
t.Fatal(err)
}
tmp, err := ioutil.TempDir("", "docker-test-graph-mount-")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmp)
rootfs := path.Join(tmp, "rootfs")
if err := os.MkdirAll(rootfs, 0700); err != nil {
t.Fatal(err)
}
rw := path.Join(tmp, "rw")
if err := os.MkdirAll(rw, 0700); err != nil {
t.Fatal(err)
}
if err := image.Mount(rootfs, rw); err != nil {
t.Fatal(err)
}
// FIXME: test for mount contents
defer func() {
if err := Unmount(rootfs); err != nil {
t.Error(err)
}
}()
}
// Test that an image can be deleted by its shorthand prefix
func TestDeletePrefix(t *testing.T) {
graph := tempGraph(t)
defer os.RemoveAll(graph.Root)
defer nukeGraph(graph)
img := createTestImage(graph, t)
if err := graph.Delete(utils.TruncateID(img.ID)); err != nil {
t.Fatal(err)
@@ -180,7 +146,7 @@ func createTestImage(graph *Graph, t *testing.T) *Image {
func TestDelete(t *testing.T) {
graph := tempGraph(t)
defer os.RemoveAll(graph.Root)
defer nukeGraph(graph)
archive, err := fakeTar()
if err != nil {
t.Fatal(err)
@@ -244,7 +210,7 @@ func TestByParent(t *testing.T) {
archive3, _ := fakeTar()
graph := tempGraph(t)
defer os.RemoveAll(graph.Root)
defer nukeGraph(graph)
parentImage := &Image{
ID: GenerateID(),
Comment: "parent",
@@ -294,14 +260,23 @@ func tempGraph(t *testing.T) *Graph {
if err != nil {
t.Fatal(err)
}
graph, err := NewGraph(tmp)
backend, err := graphdriver.New(tmp)
if err != nil {
t.Fatal(err)
}
graph, err := NewGraph(tmp, backend)
if err != nil {
t.Fatal(err)
}
return graph
}
func testArchive(t *testing.T) Archive {
func nukeGraph(graph *Graph) {
graph.driver.Cleanup()
os.RemoveAll(graph.Root)
}
func testArchive(t *testing.T) archive.Archive {
archive, err := fakeTar()
if err != nil {
t.Fatal(err)
+1
View File
@@ -0,0 +1 @@
Michael Crosby <michael@crosbymichael.com> (@crosbymichael)
+94 -44
View File
@@ -1,9 +1,10 @@
package gograph
package graphdb
import (
"database/sql"
"fmt"
"path"
"sync"
)
const (
@@ -47,6 +48,7 @@ type WalkFunc func(fullPath string, entity *Entity) error
// Graph database for storing entities and their relationships
type Database struct {
conn *sql.DB
mux sync.RWMutex
}
// Create a new graph database initialized with a root entity
@@ -54,7 +56,7 @@ func NewDatabase(conn *sql.DB, init bool) (*Database, error) {
if conn == nil {
return nil, fmt.Errorf("Database connection cannot be nil")
}
db := &Database{conn}
db := &Database{conn: conn}
if init {
if _, err := conn.Exec(createEntityTable); err != nil {
@@ -99,7 +101,9 @@ func (db *Database) Close() error {
// Set the entity id for a given path
func (db *Database) Set(fullPath, id string) (*Entity, error) {
// FIXME: is rollback implicit when closing the connection?
db.mux.Lock()
defer db.mux.Unlock()
rollback := func() {
db.conn.Exec("ROLLBACK")
}
@@ -134,7 +138,14 @@ func (db *Database) Set(fullPath, id string) (*Entity, error) {
// Return true if a name already exists in the database
func (db *Database) Exists(name string) bool {
return db.Get(name) != nil
db.mux.RLock()
defer db.mux.RUnlock()
e, err := db.get(name)
if err != nil {
return false
}
return e != nil
}
func (db *Database) setEdge(parentPath, name string, e *Entity) error {
@@ -161,6 +172,9 @@ func (db *Database) RootEntity() *Entity {
// Return the entity for a given path
func (db *Database) Get(name string) *Entity {
db.mux.RLock()
defer db.mux.RUnlock()
e, err := db.get(name)
if err != nil {
return nil
@@ -196,23 +210,36 @@ func (db *Database) get(name string) (*Entity, error) {
// List all entities by from the name
// The key will be the full path of the entity
func (db *Database) List(name string, depth int) Entities {
db.mux.RLock()
defer db.mux.RUnlock()
out := Entities{}
e, err := db.get(name)
if err != nil {
return out
}
for c := range db.children(e, name, depth) {
children, err := db.children(e, name, depth, nil)
if err != nil {
return out
}
for _, c := range children {
out[c.FullPath] = c.Entity
}
return out
}
// Walk through the child graph of an entity, calling walkFunc for each child entity.
// It is safe for walkFunc to call graph functions.
func (db *Database) Walk(name string, walkFunc WalkFunc, depth int) error {
e, err := db.get(name)
children, err := db.Children(name, depth)
if err != nil {
return err
}
for c := range db.children(e, name, depth) {
// Note: the database lock must not be held while calling walkFunc
for _, c := range children {
if err := walkFunc(c.FullPath, c.Entity); err != nil {
return err
}
@@ -220,8 +247,24 @@ func (db *Database) Walk(name string, walkFunc WalkFunc, depth int) error {
return nil
}
// Return the children of the specified entity
func (db *Database) Children(name string, depth int) ([]WalkMeta, error) {
db.mux.RLock()
defer db.mux.RUnlock()
e, err := db.get(name)
if err != nil {
return nil, err
}
return db.children(e, name, depth, nil)
}
// Return the refrence count for a specified id
func (db *Database) Refs(id string) int {
db.mux.RLock()
defer db.mux.RUnlock()
var count int
if err := db.conn.QueryRow("SELECT COUNT(*) FROM edge WHERE entity_id = ?;", id).Scan(&count); err != nil {
return 0
@@ -231,6 +274,9 @@ func (db *Database) Refs(id string) int {
// Return all the id's path references
func (db *Database) RefPaths(id string) Edges {
db.mux.RLock()
defer db.mux.RUnlock()
refs := Edges{}
rows, err := db.conn.Query("SELECT name, parent_id FROM edge WHERE entity_id = ?;", id)
@@ -256,6 +302,9 @@ func (db *Database) RefPaths(id string) Edges {
// Delete the reference to an entity at a given path
func (db *Database) Delete(name string) error {
db.mux.Lock()
defer db.mux.Unlock()
if name == "/" {
return fmt.Errorf("Cannot delete root entity")
}
@@ -276,6 +325,9 @@ func (db *Database) Delete(name string) error {
// Walk the graph to make sure all references to the entity
// are removed and return the number of references removed
func (db *Database) Purge(id string) (int, error) {
db.mux.Lock()
defer db.mux.Unlock()
rollback := func() {
db.conn.Exec("ROLLBACK")
}
@@ -310,6 +362,9 @@ func (db *Database) Purge(id string) (int, error) {
// Rename an edge for a given path
func (db *Database) Rename(currentName, newName string) error {
db.mux.Lock()
defer db.mux.Unlock()
parentPath, name := splitPath(currentName)
newParentPath, newEdgeName := splitPath(newName)
@@ -343,56 +398,51 @@ type WalkMeta struct {
Edge *Edge
}
func (db *Database) children(e *Entity, name string, depth int) <-chan WalkMeta {
out := make(chan WalkMeta)
func (db *Database) children(e *Entity, name string, depth int, entities []WalkMeta) ([]WalkMeta, error) {
if e == nil {
close(out)
return out
return entities, nil
}
go func() {
rows, err := db.conn.Query("SELECT entity_id, name FROM edge where parent_id = ?;", e.id)
if err != nil {
close(out)
rows, err := db.conn.Query("SELECT entity_id, name FROM edge where parent_id = ?;", e.id)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var entityId, entityName string
if err := rows.Scan(&entityId, &entityName); err != nil {
return nil, err
}
child := &Entity{entityId}
edge := &Edge{
ParentID: e.id,
Name: entityName,
EntityID: child.id,
}
defer rows.Close()
for rows.Next() {
var entityId, entityName string
if err := rows.Scan(&entityId, &entityName); err != nil {
// Log error
continue
}
child := &Entity{entityId}
edge := &Edge{
ParentID: e.id,
Name: entityName,
EntityID: child.id,
}
meta := WalkMeta{
Parent: e,
Entity: child,
FullPath: path.Join(name, edge.Name),
Edge: edge,
}
meta := WalkMeta{
Parent: e,
Entity: child,
FullPath: path.Join(name, edge.Name),
Edge: edge,
}
entities = append(entities, meta)
out <- meta
if depth == 0 {
continue
}
if depth != 0 {
nDepth := depth
if depth != -1 {
nDepth -= 1
}
sc := db.children(child, meta.FullPath, nDepth)
for c := range sc {
out <- c
entities, err = db.children(child, meta.FullPath, nDepth, entities)
if err != nil {
return nil, err
}
}
close(out)
}()
return out
}
return entities, nil
}
// Return the entity based on the parent path and name
@@ -1,8 +1,9 @@
package gograph
package graphdb
import (
_ "code.google.com/p/gosqlite/sqlite3"
"database/sql"
"fmt"
"os"
"path"
"strconv"
@@ -501,3 +502,39 @@ func TestGetNameWithTrailingSlash(t *testing.T) {
t.Fatalf("Entity should not be nil")
}
}
func TestConcurrentWrites(t *testing.T) {
db, dbpath := newTestDb(t)
defer destroyTestDb(dbpath)
errs := make(chan error, 2)
save := func(name string, id string) {
if _, err := db.Set(fmt.Sprintf("/%s", name), id); err != nil {
errs <- err
}
errs <- nil
}
purge := func(id string) {
if _, err := db.Purge(id); err != nil {
errs <- err
}
errs <- nil
}
save("/1", "1")
go purge("1")
go save("/2", "2")
any := false
for i := 0; i < 2; i++ {
if err := <-errs; err != nil {
any = true
t.Log(err)
}
}
if any {
t.Fatal()
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
package gograph
package graphdb
import "sort"
@@ -1,4 +1,4 @@
package gograph
package graphdb
import (
"testing"
+1 -1
View File
@@ -1,4 +1,4 @@
package gograph
package graphdb
import (
"path"
+336
View File
@@ -0,0 +1,336 @@
/*
aufs driver directory structure
.
├── layers // Metadata of layers
│   ├── 1
│   ├── 2
│   └── 3
├── diffs // Content of the layer
│   ├── 1 // Contains layers that need to be mounted for the id
│   ├── 2
│   └── 3
└── mnt // Mount points for the rw layers to be mounted
├── 1
├── 2
└── 3
*/
package aufs
import (
"bufio"
"fmt"
"github.com/dotcloud/docker/archive"
"github.com/dotcloud/docker/graphdriver"
"github.com/dotcloud/docker/utils"
"log"
"os"
"os/exec"
"path"
"strings"
)
func init() {
graphdriver.Register("aufs", Init)
}
type Driver struct {
root string
}
// New returns a new AUFS driver.
// An error is returned if AUFS is not supported.
func Init(root string) (graphdriver.Driver, error) {
// Try to load the aufs kernel module
if err := supportsAufs(); err != nil {
return nil, err
}
paths := []string{
"mnt",
"diff",
"layers",
}
// Create the root aufs driver dir and return
// if it already exists
// If not populate the dir structure
if err := os.MkdirAll(root, 0755); err != nil {
if os.IsExist(err) {
return &Driver{root}, nil
}
return nil, err
}
for _, p := range paths {
if err := os.MkdirAll(path.Join(root, p), 0755); err != nil {
return nil, err
}
}
return &Driver{root}, nil
}
// Return a nil error if the kernel supports aufs
// We cannot modprobe because inside dind modprobe fails
// to run
func supportsAufs() error {
// We can try to modprobe aufs first before looking at
// proc/filesystems for when aufs is supported
exec.Command("modprobe", "aufs").Run()
f, err := os.Open("/proc/filesystems")
if err != nil {
return err
}
defer f.Close()
s := bufio.NewScanner(f)
for s.Scan() {
if strings.Contains(s.Text(), "aufs") {
return nil
}
}
return fmt.Errorf("AUFS was not found in /proc/filesystems")
}
func (a Driver) rootPath() string {
return a.root
}
func (Driver) String() string {
return "aufs"
}
func (a Driver) Status() [][2]string {
ids, _ := loadIds(path.Join(a.rootPath(), "layers"))
return [][2]string{
{"Root Dir", a.rootPath()},
{"Dirs", fmt.Sprintf("%d", len(ids))},
}
}
// Exists returns true if the given id is registered with
// this driver
func (a Driver) Exists(id string) bool {
if _, err := os.Lstat(path.Join(a.rootPath(), "layers", id)); err != nil {
return false
}
return true
}
// Three folders are created for each id
// mnt, layers, and diff
func (a *Driver) Create(id, parent string) error {
if err := a.createDirsFor(id); err != nil {
return err
}
// Write the layers metadata
f, err := os.Create(path.Join(a.rootPath(), "layers", id))
if err != nil {
return err
}
defer f.Close()
if parent != "" {
ids, err := getParentIds(a.rootPath(), parent)
if err != nil {
return err
}
if _, err := fmt.Fprintln(f, parent); err != nil {
return err
}
for _, i := range ids {
if _, err := fmt.Fprintln(f, i); err != nil {
return err
}
}
}
return nil
}
func (a *Driver) createDirsFor(id string) error {
paths := []string{
"mnt",
"diff",
}
for _, p := range paths {
if err := os.MkdirAll(path.Join(a.rootPath(), p, id), 0755); err != nil {
return err
}
}
return nil
}
// Unmount and remove the dir information
func (a *Driver) Remove(id string) error {
// Make sure the dir is umounted first
if err := a.unmount(id); err != nil {
return err
}
tmpDirs := []string{
"mnt",
"diff",
}
// Remove the dirs atomically
for _, p := range tmpDirs {
// We need to use a temp dir in the same dir as the driver so Rename
// does not fall back to the slow copy if /tmp and the driver dir
// are on different devices
tmp := path.Join(a.rootPath(), "tmp", p, id)
if err := os.MkdirAll(tmp, 0755); err != nil {
return err
}
realPath := path.Join(a.rootPath(), p, id)
if err := os.Rename(realPath, tmp); err != nil && !os.IsNotExist(err) {
return err
}
defer os.RemoveAll(tmp)
}
// Remove the layers file for the id
if err := os.Remove(path.Join(a.rootPath(), "layers", id)); err != nil && !os.IsNotExist(err) {
return err
}
return nil
}
// Return the rootfs path for the id
// This will mount the dir at it's given path
func (a *Driver) Get(id string) (string, error) {
ids, err := getParentIds(a.rootPath(), id)
if err != nil {
if !os.IsNotExist(err) {
return "", err
}
ids = []string{}
}
// If a dir does not have a parent ( no layers )do not try to mount
// just return the diff path to the data
out := path.Join(a.rootPath(), "diff", id)
if len(ids) > 0 {
out = path.Join(a.rootPath(), "mnt", id)
if err := a.mount(id); err != nil {
return "", err
}
}
return out, nil
}
// Returns an archive of the contents for the id
func (a *Driver) Diff(id string) (archive.Archive, error) {
return archive.TarFilter(path.Join(a.rootPath(), "diff", id), &archive.TarOptions{
Recursive: true,
Compression: archive.Uncompressed,
})
}
func (a *Driver) ApplyDiff(id string, diff archive.Archive) error {
return archive.Untar(diff, path.Join(a.rootPath(), "diff", id), nil)
}
// Returns the size of the contents for the id
func (a *Driver) DiffSize(id string) (int64, error) {
return utils.TreeSize(path.Join(a.rootPath(), "diff", id))
}
func (a *Driver) Changes(id string) ([]archive.Change, error) {
layers, err := a.getParentLayerPaths(id)
if err != nil {
return nil, err
}
return archive.Changes(layers, path.Join(a.rootPath(), "diff", id))
}
func (a *Driver) getParentLayerPaths(id string) ([]string, error) {
parentIds, err := getParentIds(a.rootPath(), id)
if err != nil {
return nil, err
}
if len(parentIds) == 0 {
return nil, fmt.Errorf("Dir %s does not have any parent layers", id)
}
layers := make([]string, len(parentIds))
// Get the diff paths for all the parent ids
for i, p := range parentIds {
layers[i] = path.Join(a.rootPath(), "diff", p)
}
return layers, nil
}
func (a *Driver) mount(id string) error {
// If the id is mounted or we get an error return
if mounted, err := a.mounted(id); err != nil || mounted {
return err
}
var (
target = path.Join(a.rootPath(), "mnt", id)
rw = path.Join(a.rootPath(), "diff", id)
)
layers, err := a.getParentLayerPaths(id)
if err != nil {
return err
}
if err := a.aufsMount(layers, rw, target); err != nil {
return err
}
return nil
}
func (a *Driver) unmount(id string) error {
if mounted, err := a.mounted(id); err != nil || !mounted {
return err
}
target := path.Join(a.rootPath(), "mnt", id)
return Unmount(target)
}
func (a *Driver) mounted(id string) (bool, error) {
target := path.Join(a.rootPath(), "mnt", id)
return Mounted(target)
}
// During cleanup aufs needs to unmount all mountpoints
func (a *Driver) Cleanup() error {
ids, err := loadIds(path.Join(a.rootPath(), "layers"))
if err != nil {
return err
}
for _, id := range ids {
if err := a.unmount(id); err != nil {
utils.Errorf("Unmounting %s: %s", utils.TruncateID(id), err)
}
}
return nil
}
func (a *Driver) aufsMount(ro []string, rw, target string) error {
rwBranch := fmt.Sprintf("%v=rw", rw)
roBranches := ""
for _, layer := range ro {
roBranches += fmt.Sprintf("%v=ro+wh:", layer)
}
branches := fmt.Sprintf("br:%v:%v,xino=/dev/shm/aufs.xino", rwBranch, roBranches)
//if error, try to load aufs kernel module
if err := mount("none", target, "aufs", 0, branches); err != nil {
log.Printf("Kernel does not support AUFS, trying to load the AUFS module with modprobe...")
if err := exec.Command("modprobe", "aufs").Run(); err != nil {
return fmt.Errorf("Unable to load the AUFS module")
}
log.Printf("...module loaded.")
if err := mount("none", target, "aufs", 0, branches); err != nil {
return fmt.Errorf("Unable to mount using aufs %s", err)
}
}
return nil
}
+623
View File
@@ -0,0 +1,623 @@
package aufs
import (
"github.com/dotcloud/docker/archive"
"os"
"path"
"testing"
)
var (
tmp = path.Join(os.TempDir(), "aufs-tests", "aufs")
)
func newDriver(t *testing.T) *Driver {
if err := os.MkdirAll(tmp, 0755); err != nil {
t.Fatal(err)
}
d, err := Init(tmp)
if err != nil {
t.Fatal(err)
}
return d.(*Driver)
}
func TestNewDriver(t *testing.T) {
if err := os.MkdirAll(tmp, 0755); err != nil {
t.Fatal(err)
}
d, err := Init(tmp)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmp)
if d == nil {
t.Fatalf("Driver should not be nil")
}
}
func TestAufsString(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if d.String() != "aufs" {
t.Fatalf("Expected aufs got %s", d.String())
}
}
func TestCreateDirStructure(t *testing.T) {
newDriver(t)
defer os.RemoveAll(tmp)
paths := []string{
"mnt",
"layers",
"diff",
}
for _, p := range paths {
if _, err := os.Stat(path.Join(tmp, p)); err != nil {
t.Fatal(err)
}
}
}
// We should be able to create two drivers with the same dir structure
func TestNewDriverFromExistingDir(t *testing.T) {
if err := os.MkdirAll(tmp, 0755); err != nil {
t.Fatal(err)
}
if _, err := Init(tmp); err != nil {
t.Fatal(err)
}
if _, err := Init(tmp); err != nil {
t.Fatal(err)
}
os.RemoveAll(tmp)
}
func TestCreateNewDir(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
}
func TestCreateNewDirStructure(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
paths := []string{
"mnt",
"diff",
"layers",
}
for _, p := range paths {
if _, err := os.Stat(path.Join(tmp, p, "1")); err != nil {
t.Fatal(err)
}
}
}
func TestRemoveImage(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
if err := d.Remove("1"); err != nil {
t.Fatal(err)
}
paths := []string{
"mnt",
"diff",
"layers",
}
for _, p := range paths {
if _, err := os.Stat(path.Join(tmp, p, "1")); err == nil {
t.Fatalf("Error should not be nil because dirs with id 1 should be delted: %s", p)
}
}
}
func TestGetWithoutParent(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
diffPath, err := d.Get("1")
if err != nil {
t.Fatal(err)
}
expected := path.Join(tmp, "diff", "1")
if diffPath != expected {
t.Fatalf("Expected path %s got %s", expected, diffPath)
}
}
func TestCleanupWithNoDirs(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Cleanup(); err != nil {
t.Fatal(err)
}
}
func TestCleanupWithDir(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
if err := d.Cleanup(); err != nil {
t.Fatal(err)
}
}
func TestMountedFalseResponse(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
response, err := d.mounted("1")
if err != nil {
t.Fatal(err)
}
if response != false {
t.Fatalf("Response if dir id 1 is mounted should be false")
}
}
func TestMountedTrueReponse(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
defer d.Cleanup()
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
if err := d.Create("2", "1"); err != nil {
t.Fatal(err)
}
_, err := d.Get("2")
if err != nil {
t.Fatal(err)
}
response, err := d.mounted("2")
if err != nil {
t.Fatal(err)
}
if response != true {
t.Fatalf("Response if dir id 2 is mounted should be true")
}
}
func TestMountWithParent(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
if err := d.Create("2", "1"); err != nil {
t.Fatal(err)
}
defer func() {
if err := d.Cleanup(); err != nil {
t.Fatal(err)
}
}()
mntPath, err := d.Get("2")
if err != nil {
t.Fatal(err)
}
if mntPath == "" {
t.Fatal("mntPath should not be empty string")
}
expected := path.Join(tmp, "mnt", "2")
if mntPath != expected {
t.Fatalf("Expected %s got %s", expected, mntPath)
}
}
func TestRemoveMountedDir(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
if err := d.Create("2", "1"); err != nil {
t.Fatal(err)
}
defer func() {
if err := d.Cleanup(); err != nil {
t.Fatal(err)
}
}()
mntPath, err := d.Get("2")
if err != nil {
t.Fatal(err)
}
if mntPath == "" {
t.Fatal("mntPath should not be empty string")
}
mounted, err := d.mounted("2")
if err != nil {
t.Fatal(err)
}
if !mounted {
t.Fatalf("Dir id 2 should be mounted")
}
if err := d.Remove("2"); err != nil {
t.Fatal(err)
}
}
func TestCreateWithInvalidParent(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", "docker"); err == nil {
t.Fatalf("Error should not be nil with parent does not exist")
}
}
func TestGetDiff(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
diffPath, err := d.Get("1")
if err != nil {
t.Fatal(err)
}
// Add a file to the diff path with a fixed size
size := int64(1024)
f, err := os.Create(path.Join(diffPath, "test_file"))
if err != nil {
t.Fatal(err)
}
if err := f.Truncate(size); err != nil {
t.Fatal(err)
}
f.Close()
a, err := d.Diff("1")
if err != nil {
t.Fatal(err)
}
if a == nil {
t.Fatalf("Archive should not be nil")
}
}
func TestChanges(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
if err := d.Create("2", "1"); err != nil {
t.Fatal(err)
}
defer func() {
if err := d.Cleanup(); err != nil {
t.Fatal(err)
}
}()
mntPoint, err := d.Get("2")
if err != nil {
t.Fatal(err)
}
// Create a file to save in the mountpoint
f, err := os.Create(path.Join(mntPoint, "test.txt"))
if err != nil {
t.Fatal(err)
}
if _, err := f.WriteString("testline"); err != nil {
t.Fatal(err)
}
if err := f.Close(); err != nil {
t.Fatal(err)
}
changes, err := d.Changes("2")
if err != nil {
t.Fatal(err)
}
if len(changes) != 1 {
t.Fatalf("Dir 2 should have one change from parent got %d", len(changes))
}
change := changes[0]
expectedPath := "/test.txt"
if change.Path != expectedPath {
t.Fatalf("Expected path %s got %s", expectedPath, change.Path)
}
if change.Kind != archive.ChangeAdd {
t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
}
if err := d.Create("3", "2"); err != nil {
t.Fatal(err)
}
mntPoint, err = d.Get("3")
if err != nil {
t.Fatal(err)
}
// Create a file to save in the mountpoint
f, err = os.Create(path.Join(mntPoint, "test2.txt"))
if err != nil {
t.Fatal(err)
}
if _, err := f.WriteString("testline"); err != nil {
t.Fatal(err)
}
if err := f.Close(); err != nil {
t.Fatal(err)
}
changes, err = d.Changes("3")
if err != nil {
t.Fatal(err)
}
if len(changes) != 1 {
t.Fatalf("Dir 2 should have one change from parent got %d", len(changes))
}
change = changes[0]
expectedPath = "/test2.txt"
if change.Path != expectedPath {
t.Fatalf("Expected path %s got %s", expectedPath, change.Path)
}
if change.Kind != archive.ChangeAdd {
t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
}
}
func TestDiffSize(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
diffPath, err := d.Get("1")
if err != nil {
t.Fatal(err)
}
// Add a file to the diff path with a fixed size
size := int64(1024)
f, err := os.Create(path.Join(diffPath, "test_file"))
if err != nil {
t.Fatal(err)
}
if err := f.Truncate(size); err != nil {
t.Fatal(err)
}
s, err := f.Stat()
if err != nil {
t.Fatal(err)
}
size = s.Size()
if err := f.Close(); err != nil {
t.Fatal(err)
}
diffSize, err := d.DiffSize("1")
if err != nil {
t.Fatal(err)
}
if diffSize != size {
t.Fatalf("Expected size to be %d got %d", size, diffSize)
}
}
func TestChildDiffSize(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
defer d.Cleanup()
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
diffPath, err := d.Get("1")
if err != nil {
t.Fatal(err)
}
// Add a file to the diff path with a fixed size
size := int64(1024)
f, err := os.Create(path.Join(diffPath, "test_file"))
if err != nil {
t.Fatal(err)
}
if err := f.Truncate(size); err != nil {
t.Fatal(err)
}
s, err := f.Stat()
if err != nil {
t.Fatal(err)
}
size = s.Size()
if err := f.Close(); err != nil {
t.Fatal(err)
}
diffSize, err := d.DiffSize("1")
if err != nil {
t.Fatal(err)
}
if diffSize != size {
t.Fatalf("Expected size to be %d got %d", size, diffSize)
}
if err := d.Create("2", "1"); err != nil {
t.Fatal(err)
}
diffSize, err = d.DiffSize("2")
if err != nil {
t.Fatal(err)
}
// The diff size for the child should be zero
if diffSize != 0 {
t.Fatalf("Expected size to be %d got %d", 0, diffSize)
}
}
func TestExists(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
defer d.Cleanup()
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
if d.Exists("none") {
t.Fatal("id name should not exist in the driver")
}
if !d.Exists("1") {
t.Fatal("id 1 should exist in the driver")
}
}
func TestStatus(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
defer d.Cleanup()
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
status := d.Status()
if status == nil || len(status) == 0 {
t.Fatal("Status should not be nil or empty")
}
rootDir := status[0]
dirs := status[1]
if rootDir[0] != "Root Dir" {
t.Fatalf("Expected Root Dir got %s", rootDir[0])
}
if rootDir[1] != d.rootPath() {
t.Fatalf("Expected %s got %s", d.rootPath(), rootDir[1])
}
if dirs[0] != "Dirs" {
t.Fatalf("Expected Dirs got %s", dirs[0])
}
if dirs[1] != "1" {
t.Fatalf("Expected 1 got %s", dirs[1])
}
}
func TestApplyDiff(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
defer d.Cleanup()
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
diffPath, err := d.Get("1")
if err != nil {
t.Fatal(err)
}
// Add a file to the diff path with a fixed size
size := int64(1024)
f, err := os.Create(path.Join(diffPath, "test_file"))
if err != nil {
t.Fatal(err)
}
if err := f.Truncate(size); err != nil {
t.Fatal(err)
}
f.Close()
diff, err := d.Diff("1")
if err != nil {
t.Fatal(err)
}
if err := d.Create("2", ""); err != nil {
t.Fatal(err)
}
if err := d.Create("3", "2"); err != nil {
t.Fatal(err)
}
if err := d.ApplyDiff("3", diff); err != nil {
t.Fatal(err)
}
// Ensure that the file is in the mount point for id 3
mountPoint, err := d.Get("3")
if err != nil {
t.Fatal(err)
}
if _, err := os.Stat(path.Join(mountPoint, "test_file")); err != nil {
t.Fatal(err)
}
}
+46
View File
@@ -0,0 +1,46 @@
package aufs
import (
"bufio"
"io/ioutil"
"os"
"path"
)
// Return all the directories
func loadIds(root string) ([]string, error) {
dirs, err := ioutil.ReadDir(root)
if err != nil {
return nil, err
}
out := []string{}
for _, d := range dirs {
if !d.IsDir() {
out = append(out, d.Name())
}
}
return out, nil
}
// Read the layers file for the current id and return all the
// layers represented by new lines in the file
//
// If there are no lines in the file then the id has no parent
// and an empty slice is returned.
func getParentIds(root, id string) ([]string, error) {
f, err := os.Open(path.Join(root, "layers", id))
if err != nil {
return nil, err
}
defer f.Close()
out := []string{}
s := bufio.NewScanner(f)
for s.Scan() {
if t := s.Text(); t != "" {
out = append(out, s.Text())
}
}
return out, s.Err()
}
+194
View File
@@ -0,0 +1,194 @@
package aufs
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path"
)
type metadata struct {
ID string `json:"id"`
ParentID string `json:"parent,omitempty"`
Image string `json:"Image,omitempty"`
parent *metadata
}
func pathExists(pth string) bool {
if _, err := os.Stat(pth); err != nil {
return false
}
return true
}
// Migrate existing images and containers from docker < 0.7.x
//
// The format pre 0.7 is for docker to store the metadata and filesystem
// content in the same directory. For the migration to work we need to move Image layer
// data from /var/lib/docker/graph/<id>/layers to the diff of the registered id.
//
// Next we need to migrate the container's rw layer to diff of the driver. After the
// contents are migrated we need to register the image and container ids with the
// driver.
//
// For the migration we try to move the folder containing the layer files, if that
// fails because the data is currently mounted we will fallback to creating a
// symlink.
func (a *Driver) Migrate(pth string, setupInit func(p string) error) error {
if pathExists(path.Join(pth, "graph")) {
if err := a.migrateRepositories(pth); err != nil {
return err
}
if err := a.migrateImages(path.Join(pth, "graph")); err != nil {
return err
}
return a.migrateContainers(path.Join(pth, "containers"), setupInit)
}
return nil
}
func (a *Driver) migrateRepositories(pth string) error {
name := path.Join(pth, "repositories")
if err := os.Rename(name, name+"-aufs"); err != nil && !os.IsNotExist(err) {
return err
}
return nil
}
func (a *Driver) migrateContainers(pth string, setupInit func(p string) error) error {
fis, err := ioutil.ReadDir(pth)
if err != nil {
return err
}
for _, fi := range fis {
if id := fi.Name(); fi.IsDir() && pathExists(path.Join(pth, id, "rw")) {
if err := tryRelocate(path.Join(pth, id, "rw"), path.Join(a.rootPath(), "diff", id)); err != nil {
return err
}
if !a.Exists(id) {
metadata, err := loadMetadata(path.Join(pth, id, "config.json"))
if err != nil {
return err
}
initID := fmt.Sprintf("%s-init", id)
if err := a.Create(initID, metadata.Image); err != nil {
return err
}
initPath, err := a.Get(initID)
if err != nil {
return err
}
// setup init layer
if err := setupInit(initPath); err != nil {
return err
}
if err := a.Create(id, initID); err != nil {
return err
}
}
}
}
return nil
}
func (a *Driver) migrateImages(pth string) error {
fis, err := ioutil.ReadDir(pth)
if err != nil {
return err
}
var (
m = make(map[string]*metadata)
current *metadata
exists bool
)
for _, fi := range fis {
if id := fi.Name(); fi.IsDir() && pathExists(path.Join(pth, id, "layer")) {
if current, exists = m[id]; !exists {
current, err = loadMetadata(path.Join(pth, id, "json"))
if err != nil {
return err
}
m[id] = current
}
}
}
for _, v := range m {
v.parent = m[v.ParentID]
}
migrated := make(map[string]bool)
for _, v := range m {
if err := a.migrateImage(v, pth, migrated); err != nil {
return err
}
}
return nil
}
func (a *Driver) migrateImage(m *metadata, pth string, migrated map[string]bool) error {
if !migrated[m.ID] {
if m.parent != nil {
a.migrateImage(m.parent, pth, migrated)
}
if err := tryRelocate(path.Join(pth, m.ID, "layer"), path.Join(a.rootPath(), "diff", m.ID)); err != nil {
return err
}
if !a.Exists(m.ID) {
if err := a.Create(m.ID, m.ParentID); err != nil {
return err
}
}
migrated[m.ID] = true
}
return nil
}
// tryRelocate will try to rename the old path to the new pack and if
// the operation fails, it will fallback to a symlink
func tryRelocate(oldPath, newPath string) error {
s, err := os.Lstat(newPath)
if err != nil && !os.IsNotExist(err) {
return err
}
// If the destination is a symlink then we already tried to relocate once before
// and it failed so we delete it and try to remove
if s != nil && s.Mode()&os.ModeSymlink == os.ModeSymlink {
if err := os.RemoveAll(newPath); err != nil {
return err
}
}
if err := os.Rename(oldPath, newPath); err != nil {
if sErr := os.Symlink(oldPath, newPath); sErr != nil {
return fmt.Errorf("Unable to relocate %s to %s: Rename err %s Symlink err %s", oldPath, newPath, err, sErr)
}
}
return nil
}
func loadMetadata(pth string) (*metadata, error) {
f, err := os.Open(pth)
if err != nil {
return nil, err
}
defer f.Close()
var (
out = &metadata{}
dec = json.NewDecoder(f)
)
if err := dec.Decode(out); err != nil {
return nil, err
}
return out, nil
}
+3 -19
View File
@@ -1,13 +1,11 @@
package docker
package aufs
import (
"fmt"
"github.com/dotcloud/docker/utils"
"os"
"os/exec"
"path/filepath"
"syscall"
"time"
)
func Unmount(target string) error {
@@ -17,22 +15,7 @@ func Unmount(target string) error {
if err := syscall.Unmount(target, 0); err != nil {
return err
}
// Even though we just unmounted the filesystem, AUFS will prevent deleting the mntpoint
// for some time. We'll just keep retrying until it succeeds.
for retries := 0; retries < 1000; retries++ {
err := os.Remove(target)
if err == nil {
// rm mntpoint succeeded
return nil
}
if os.IsNotExist(err) {
// mntpoint doesn't exist anymore. Success.
return nil
}
// fmt.Printf("(%v) Remove %v returned: %v\n", retries, target, err)
time.Sleep(10 * time.Millisecond)
}
return fmt.Errorf("Umount: Failed to umount %v", target)
return nil
}
func Mounted(mountpoint string) (bool, error) {
@@ -49,5 +32,6 @@ func Mounted(mountpoint string) (bool, error) {
}
mntpointSt := mntpoint.Sys().(*syscall.Stat_t)
parentSt := parent.Sys().(*syscall.Stat_t)
return mntpointSt.Dev != parentSt.Dev, nil
}
@@ -1,4 +1,4 @@
package docker
package aufs
import "errors"

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