Compare commits

...

563 Commits

Author SHA1 Message Date
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
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
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 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
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
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
Michael Crosby a4f14528c2 Ignore dir sizes in TreeSize func 2013-11-13 10:33:24 -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
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
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
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
Victor Vieux 3ff845904d set containers comm to true by default 2013-10-30 15:06:28 -07:00
Victor Vieux ec488fa123 fix warning in build 2013-10-30 15:06:01 -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 1edde0e8a3 Update links and host integration documentation 2013-10-30 13:11:02 -07:00
Victor Vieux 596facd124 fix typos 2013-10-30 13:06:47 -07:00
Victor Vieux 4fd389eee5 fix remove root name and fix error messages 2013-10-30 13:06:43 -07:00
Victor Vieux 6a9fb81c57 improve error message 2013-10-30 13:06:39 -07:00
Victor Vieux 5fb6d6e47c continue build on expose with :, but displays a warning 2013-10-30 13:06:34 -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 79bf2c2b0e Hotfix: Migrate public mappings after upgrade 2013-10-30 09:02:23 -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
Michael Crosby 4f6ce1ba9e Merge pull request #2428 from dotcloud/bump_0.6.5
Bump to version 0.6.5
2013-10-29 14:56:54 -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
Michael Crosby da054148dc Bump to version 0.6.5 2013-10-29 14:42:20 -07:00
Michael Crosby 0174951195 Merge branch 'master' into bump_0.6.5 2013-10-29 14:41:47 -07:00
Michael Crosby caa7cf14c0 Merge pull request #2426 from dotcloud/enable_sigproxy_default
Enable sig-proxy by default in run and attach
2013-10-29 14:39:17 -07:00
Victor Vieux 700a71e6b6 stop proxy at one point 2013-10-29 14:29:01 -07:00
Andy Rothfusz 02e0fdee57 Merge pull request #2429 from SvenDowideit/add-more-doc-pointers
tell potential doc updaters and contributors more details
2013-10-29 14:07:12 -07:00
Andy Rothfusz baf23d3c3e Merge pull request #2443 from tlunter/fix_remote_api_doc
Container commit doesn't use a query parameter, uses POST body
2013-10-29 14:04:22 -07:00
Michael Crosby 5b75aea704 Merge pull request #2449 from tianon/remove-stackbrew-remnants
Remove old remnants of stackbrew now that it's a separate project
2013-10-29 14:00:33 -07:00
Michael Crosby d91e145332 Merge pull request #2448 from keeb/fix-dsfg-readme
Fix export clause in readme
2013-10-29 13:44:03 -07:00
Michael Crosby 1384db5e7f Merge pull request #2451 from tianon/clarify-go-requirement
Clarify Go 1.2rc2 / Go 1.1.2 requirements in hack/PACKAGERS.md
2013-10-29 13:41:01 -07:00
Tianon Gravi ff147707b2 Clarify Go 1.2rc2 / Go 1.1.2 requirements in hack/PACKAGERS.md 2013-10-29 13:41:26 -06:00
Tianon Gravi 05430c7170 Merge pull request #2433 from tianon/sqlite-dep
Add SQLite dep to hack/PACKAGERS.md
2013-10-29 12:27:26 -07:00
Tianon Gravi eb79e8c5dd Remove old remnants of stackbrew now that it's a separate project 2013-10-29 13:14:15 -06:00
Nick Stinemates b48fc96579 Fix export clause
This makes our clause DSFG acceptable.
2013-10-29 12:06:48 -07:00
Victor Vieux e0b59ab52b Enable sig-proxy by default in run and attach 2013-10-29 11:18:34 -07:00
Michael Crosby a6a274f312 Merge pull request #2431 from relateiq/2430-links-ip-env
Expose addr, port, proto env variables when linking, Closes #2430
2013-10-29 11:02:46 -07:00
Todd Lunter 4f5790d104 Update all older docs too 2013-10-29 13:57:42 -04:00
Todd Lunter 70c976de03 Doesn't use a query parameter, uses POST body 2013-10-29 10:17:12 -04:00
Julien Barbier 4947f61c20 Updated dotCloud,Inc. to Docker, Inc. 2013-10-29 06:11:36 -07:00
Scott Bessler 1de23f1b81 Expose IP, port, proto as sep. env vars when linking, Closes #2430 2013-10-28 23:02:28 -07:00
Tianon Gravi b283900764 Add SQLite dep to hack/PACKAGERS.md and clean up a few other tiny inconsistencies 2013-10-28 21:57:20 -06:00
Sven Dowideit 82f1514895 docker stop sends SIGTERM and SIGKILL, docker kill sends SIGKILL 2013-10-29 13:37:43 +10:00
Sven Dowideit e47f9984f8 add links to the Dockerfiles as canonical external requirements, add example of building and exposing the docs and simplify the Dockerfile for cacheability 2013-10-29 12:58:58 +10:00
Michael Crosby b038b0cd44 Merge pull request #2162 from dotcloud/links
Links and Container Naming
2013-10-28 19:24:10 -07:00
Michael Crosby 7e8b2c3836 Make sure only links are removed and not names 2013-10-28 19:19:31 -07: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
Michael Crosby a52e23c5e4 Merge pull request #2425 from dotcloud/links-allow-name
Add -name for docker run
2013-10-28 18:16:06 -07:00
Michael Crosby 0d2924408b Add -name for docker run
Remove docker link
Do not add container id as default name
Create an auto generated container name if not
specified at runtime.
2013-10-28 18:09:08 -07:00
rogaha 91d721aaf4 - Added volumes documentation 2013-10-28 17:24:03 -07:00
Andy Rothfusz 76afb6e73d Merge pull request #2421 from dudebout/patch-1
Fixes the flags for nc in example
2013-10-28 17:01:53 -07:00
Victor Vieux c0662488c7 Merge pull request #2422 from dotcloud/links_names_generator
Add name generator for container without -name
2013-10-28 15:34:16 -07:00
Victor Vieux 971cf56d89 add name generator 2013-10-28 15:19:52 -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
Nicolas Dudebout 50bb4a1636 Fixes the flags for nc
The `-p` flag for `nc` should not be used with `-l`.
2013-10-28 15:48:18 -04:00
Andy Rothfusz 3c0c75bbf9 Merge pull request #2413 from rutsky/patch-1
Fix typo
2013-10-28 12:08:04 -07:00
Andy Rothfusz 7f95c7aeec Merge pull request #2417 from rutsky/patch-2
fix typo
2013-10-28 12:07:46 -07:00
Vladimir Rutsky 395a24ffd5 fix typo 2013-10-28 09:35:09 +03:00
Vladimir Rutsky 45d94944f3 Fix typo 2013-10-28 02:45:12 +03: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
Victor Vieux 54d3b4dd28 Merge pull request #2400 from dotcloud/remove_newline_debugf
Removes \n from debugf calls
2013-10-25 18:01:19 -07:00
Victor Vieux 8f39f0b57d Removes \\n from debugf calls 2013-10-25 17:50:40 -07:00
Victor Vieux d5c7e92a9a fix docker ps display 2013-10-25 17:36:23 -07:00
Michael Crosby 110b944f45 Merge pull request #2399 from dotcloud/fix_race_stdin_cli
Only pass stdin to hijack when needed
2013-10-25 17:32:36 -07:00
Victor Vieux 13c521526d only pass stdin to hijack when needed 2013-10-25 17:17:33 -07:00
Victor Vieux 516cf54843 prevent default name to be deleted and return an error on invalid link 2013-10-25 16:49:49 -07:00
Michael Crosby 356af1540f Ensure child containers are started before parents 2013-10-25 15:13:26 -07:00
Michael Crosby 2e6b241dc7 Add default entity and edge to graph on runtime load 2013-10-25 15:13:26 -07:00
Michael Crosby 94e5081bac Move iptable rules outside of create bridge
This allows the user to toggle enabling and
disabling intercontainer communication when
they run the daemon.
2013-10-25 15:13:26 -07:00
Michael Crosby e179a24ad5 Update TestLinkEnv for default port 2013-10-25 15:13:25 -07:00
Victor Vieux da864a845b Remove proto frpm default port 2013-10-25 15:13:25 -07:00
Tianon Gravi 640682d56c Fix "go test -i" to include the proper LDFLAGS and BUILDFLAGS 2013-10-25 15:13:25 -07:00
Victor Vieux 66a159342b update docker port command 2013-10-25 15:13:25 -07:00
Michael Crosby 7c882a8003 Move name parsing logic to GetByName method 2013-10-25 15:13:25 -07:00
Michael Crosby 7d440f70fd Add missing else when checking for linkgraph.db 2013-10-25 15:13:25 -07:00
Solomon Hykes 0c9b319dd0 Hack: fix test and dyntest to correctly use $TESTFLAGS 2013-10-25 15:13:25 -07:00
Michael Crosby 7c08aeeba4 Use persistent connection for links database
Add close method to Runtime and Server to make sure
that any underlying connections are cleaned up
2013-10-25 15:13:25 -07:00
Michael Crosby 7072d2aaca Close connection in Get method 2013-10-25 15:13:25 -07:00
Tianon Gravi 21161dbd51 Add dynbinary and dyntest scripts for building/testing a separate static dockerinit binary
After a nice long brainstorming session with @shykes on IRC, we decided on using a SHA1 hash of dockerinit compiled into the dynamic docker binary to ensure that we always use the two in a perfect pair, and never mix and match.
2013-10-25 15:13:25 -07:00
Tianon Gravi cf86e2bb22 Rename all cases of "docker-init" to "dockerinit" for consistency 2013-10-25 15:13:25 -07:00
Tianon Gravi d789750851 Refactor the handling of static-related build flags
This is as discussed with @shykes on IRC
2013-10-25 15:13:25 -07:00
Tianon Gravi fb8d488896 Add a few small consistency tweaks in hack 2013-10-25 15:13:25 -07:00
Victor Vieux dbe7d67c18 fix tests 2013-10-25 15:13:25 -07:00
Victor Vieux 6c863b49ef remove docker ls and add docker link in usage and switch to go1.2rc2 2013-10-25 15:13:25 -07:00
Victor Vieux 89fb51f606 fix merge issue and gofmt 2013-10-25 15:13:25 -07:00
Victor Vieux 256b7537e3 no more name encoding 2013-10-25 15:13:25 -07:00
Victor Vieux c4923757f1 replace == by HasPrefix for names and improve error message 2013-10-25 15:13:25 -07:00
Victor Vieux 387aeb78fb refactor notrunc in commands.go to add names support 2013-10-25 15:13:24 -07:00
Victor Vieux 99a9783abc fix typo in docs 2013-10-25 15:13:24 -07:00
Michael Crosby 0e24db3a68 Updated fixes post rebase from master
Removed test cases that are no longer
applicable with links and the port changes.
Remove test case where a test was hitting an
external ip.
2013-10-25 15:13:24 -07:00
Alexander Larsson db99966724 Move SysInit to a submodule
This allows docker-init to not import the main docker
module, which means it won't e.g. pick up any sqlite
dependencies.
2013-10-25 15:13:24 -07:00
Alexander Larsson d063c8d941 Move ListOps to utils submodule
This will be needed for later use in docker-init without a docker
dependency
2013-10-25 15:13:24 -07:00
Alexander Larsson 249f5a65a5 Add a network test
This just tries pinging first 127.0.0.1 and then 8.8.8.8.

We can't ping via a dns name, because libresolv.so is missing
from the test image, so dns resolving doesn't work.
2013-10-25 15:13:24 -07:00
Alexander Larsson 494cd07f72 network: Stop shelling out to /sbin/ip
We have our own netlink version of all the required calls now, so
we can just skip the /sbin/ip dependency.
2013-10-25 15:13:24 -07:00
Alexander Larsson 607c1a520e Use netlink directly instead of /bin/ip in Sysinit
The sysinit code only uses /bin/ip to set a default gateway. This
is pretty easy to do via netlink directly, so we can avoid
the ip dependency.
2013-10-25 15:13:24 -07:00
Alexander Larsson bf61d41d6c Add netlink submodule
This contains various operations that can replace the use of
shelling out to "ip".
2013-10-25 15:13:24 -07:00
Michael Crosby ce965b8c43 Add flag for inter-container communication 2013-10-25 15:13:24 -07:00
Solomon Hykes f7a2f0b937 Typos and FIXMEs 2013-10-25 15:13:24 -07:00
Solomon Hykes 4576d0f802 gograph: fix a bug which caused the unicity of (parent, name) to not be enforced 2013-10-25 15:13:24 -07:00
Michael Crosby 515070d513 Remove docker ls from docs and cli usage 2013-10-25 15:13:24 -07:00
Michael Crosby 1cbdaebaa1 Add links for container relationships and introspection 2013-10-25 15:13:24 -07:00
Michael Crosby ff567f8729 Merge pull request #2385 from dotcloud/suppress_even_more_warnings_test
Improve tests again, remove warnings and prevent some mount issues
2013-10-25 15:04:56 -07:00
Jérôme Petazzoni 279791bc74 Merge pull request #2378 from tianon/linkify-github-ids
Linkify @github references in the infrastructure README.md
2013-10-25 11:30:25 -07:00
Andy Rothfusz 1e704a4ddc Merge pull request #2355 from xdissent/patch-1
Typo in host integration docs
2013-10-24 19:05:22 -07:00
Victor Vieux 31111f61e0 Merge pull request #1963 from rogpeppe/master
Client: Use less reflection in command-line method invocation
2013-10-24 18:03:20 -07:00
Michael Crosby 217b6070f0 Merge pull request #2383 from jpetazzo/cleanup-errclosedpipe-for-stdin
Ignore ErrClosedPipe for stdin in Container.Attach.
2013-10-24 17:18:28 -07:00
Michael Crosby 36c26a0f0f Merge pull request #2384 from dotcloud/suppress_warning_tty_tests
Change logic for tty resize to avoid warning in tests
2013-10-24 16:59:13 -07:00
Victor Vieux a675e249b1 fix workdir, hostname tests and a bunch on mount issue 2013-10-24 16:57:35 -07:00
Victor Vieux acc2aec988 remove log 2013-10-24 15:13:47 -07:00
Victor Vieux 0e021ed470 swap cat by top to prevent 2 warnings 2013-10-24 15:06:10 -07:00
Jérôme Petazzoni b9eb5e04ae Ignore ErrClosedPipe for stdin in Container.Attach.
But pass `err` in the error channel anyway; don't ignore it anymore.
2013-10-24 15:04:58 -07:00
Victor Vieux 0e44864b66 change logic for tty resize to avoid warning in tests 2013-10-24 14:54:04 -07:00
Michael Crosby e661473bcd Merge pull request #2379 from dotcloud/2377-remove_resize_race-fix
Monitor the tty after starting the container
2013-10-24 12:31:31 -07:00
Tianon Gravi 98c94dd4db Merge pull request #2364 from tianon/sudo-modprobe
Fix install.sh with $sh_c to get sudo/su for modprobe
2013-10-24 11:24:23 -07:00
Victor Vieux 656b66e51b monitor the tty after starting the container 2013-10-24 11:19:06 -07:00
Tianon Gravi c9375d14fc Linkify @github references in the infrastructure README.md 2013-10-24 11:54:06 -06:00
Michael Crosby 489c370fcc Merge pull request #2367 from dotcloud/remove_useless_exit
Remove useless os.Exit() after log.Fatalf
2013-10-24 09:18:45 -07:00
Tianon Gravi aa6c99aff6 Merge pull request #2363 from tianon/mkimage-numeric-owner
Update all the mkimage scripts to use --numeric-owner as a tar argument
2013-10-24 06:42:52 -07:00
Victor Vieux 92384649cf remove useless os.Exit() after log.Fatalf 2013-10-24 00:25:55 -07:00
Victor Vieux c2413889bb Merge pull request #2354 from hamo/refac_parsehost
refactor utils.ParseHost with switch-case, so we can add other proto support easily
2013-10-24 00:22:50 -07:00
Yang Bai e81da876df let utils.ParseHost return err when errors happen 2013-10-24 13:23:02 +08:00
Tianon Gravi f0dbdba5c0 Merge pull request #2263 from tianon/hack-release
Update hack/release.sh process to automatically invoke hack/make.sh and bail on building/testing issues
2013-10-23 15:31:16 -07:00
Tianon Gravi 0324e567ad Fix install.sh with $sh_c to get sudo/su for modprobe 2013-10-23 15:48:30 -06:00
Tianon Gravi ef5cf6c1ec Merge pull request #2226 from tianon/init
Add initial init scripts library and better/safer Ubuntu packaging that works for Debian, too
2013-10-23 14:29:41 -07:00
Tianon Gravi afaddd04f7 Merge pull request #2306 from tianon/fix-ubuntu-install-aufs
Update hack/install.sh with some more Ubuntu-specific installation stuff...
2013-10-23 14:22:55 -07:00
Tianon Gravi 8e43db95f2 Update all the mkimage scripts to use --numeric-owner as a tar argument to properly preserve ownership 2013-10-23 14:08:16 -06:00
Victor Vieux 7a116220e7 Merge pull request #2327 from dotcloud/2325_fix_untag_rmi
fix wrong untag while docker rmi
2013-10-23 10:24:20 -07:00
Victor Vieux 894a68d2ee Merge pull request #2349 from shykes/runtime-cleanup
Runtime: remove unused field kernelVersion
2013-10-23 09:54:00 -07:00
Tianon Gravi dc57d4ca26 Merge pull request #2353 from wrouesnel/mkimage-debootstrap-improvements
mkimage-debootstrap.sh: Add -p option to invoke debootstrap with http_proxy
2013-10-23 09:26:45 -07:00
Will Rouesnel bc8a1081b0 mkimage-debootstrap.sh: Add -p option to invoke debootstrap with http_proxy.
This patch allows debootstrap to be run with the http_proxy environment
variable. This is principally useful when you're using apt-cacher and
apt-cacher-ng locally.
2013-10-24 03:21:10 +11:00
Greg Thornton 33ccd29ae7 Typo in host integration docs 2013-10-23 10:19:12 -05:00
Tianon Gravi 2aaaf90320 Update hack/make/ubuntu to make less ubuntu-centric packages, to fix the issue of deleting the docker group on every upgrade, to use the new init library scripts for upstart and sysvinit, and to include the dependency on iptables 2013-10-23 07:38:12 -06:00
Yang Bai 99f1675566 refactor utils.ParseHost with switch-case, so we can add other proto support easily 2013-10-23 18:29:35 +08:00
Solomon Hykes 7e4d008403 Runtime: remove unused field kernelVersion 2013-10-23 00:44:57 -06:00
Victor Vieux b0515a7016 Merge pull request #2279 from dotcloud/fix_docker_inspect
Client: improve docker inspect
2013-10-22 17:17:35 -07:00
Victor Vieux 8ff7b70c91 Merge pull request #2341 from dotcloud/1327-race_build_verbose-fix
fix race condition in docker build with verbose + cleanup hostIntegration debug
2013-10-22 16:46:36 -07:00
Victor Vieux 01284cbf73 fix status code 2013-10-22 15:39:51 -07:00
Victor Vieux 10e10c9573 fix race condition in docker build with verbose + cleanup hostIntegration debug 2013-10-22 15:01:06 -07:00
Michael Crosby b73065ab33 Merge pull request #2338 from proppy/patch-1
Registry: Fix content-type for PushImageJSONIndex
2013-10-22 14:48:12 -07:00
Johan Euphrosine d93023daa9 registry: fix content-type for PushImageJSONIndex 2013-10-22 11:56:48 -07:00
Andy Rothfusz 81866087fe Merge pull request #2261 from edmund-wagner/master
make copy paste user friendly
2013-10-22 11:31:49 -07:00
Michael Crosby e70030a0c3 Merge pull request #2150 from pnasrat/fix-mnt-subdir-volumes
Fixes issues with mounting subdirectories of /mnt in container.
2013-10-22 11:26:50 -07: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
Andy Rothfusz 3bd45824da Merge pull request #2318 from Tranquility/master
Fix github link in docs
2013-10-22 09:55:33 -07:00
Victor Vieux 13c913d883 Merge pull request #2198 from hamo/hamo/chdir_error
check return value of syscall.Chdir when changing working directory
2013-10-22 09:54:25 -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
Tianon Gravi 92beaed066 Merge pull request #2326 from justinforce/commentstring
Set commentstring in Vim syntax plugin
2013-10-22 00:41:34 -07:00
Victor Vieux 6b04913e73 Merge pull request #2307 from gurjeet/sorted_commands_in_help
Place 'top' subcommand's help in proper order.
2013-10-21 18:07:39 -07:00
Victor Vieux 93810b289c fix wrong untag while docker rmi 2013-10-21 17:03:32 -07:00
Justin Force ea59ce60c5 Set commentstring in Vim syntax plugin
By setting the commentstring, you support commenting with plugins like tComment.
Now Vim won't default to incorrect `/* */` comments.
2013-10-21 16:15:10 -07:00
Andy Rothfusz a1fc8e17a7 Clean up level 3 headers. 2013-10-21 14:03:09 -07:00
Ole Reifschneider f903feee03 Fix github link in docs 2013-10-21 22:58:56 +02:00
Andy Rothfusz 26adda6c31 Merge pull request #2303 from metalivedev/2302-fixintro
Fix #2302
2013-10-21 09:39:34 -07:00
Gurjeet Singh 7e09c6332d Place 'top' subcommand's help in proper order. 2013-10-20 02:15:36 -04:00
Tianon Gravi 3b0cbc59ea Update hack/install.sh with some more Ubuntu-specific installation stuff while we're still on AUFS (installing linux-image-extra-$(uname -r) when we can't find AUFS to try to find AUFS) 2013-10-19 23:56:14 -06:00
Daniel Mizyrycki 95f3f77fc4 testing infrastructure, issue #1800: Refactor docker testing using Docker in Docker 2013-10-18 22:33:16 -07:00
Andy Rothfusz bba5fd4555 Fix #2302 2013-10-18 18:00:44 -07:00
Guillaume J. Charmes 9bceae2440 Add a chan to hijack() to block until the hijack is completed 2013-10-18 16:26:29 -07:00
Guillaume J. Charmes e7269b9841 Fix issue with autoremove 2013-10-18 16:26:29 -07:00
Andy Rothfusz 8cf0f2dbe5 Update documentation 2013-10-18 16:26:29 -07:00
Guillaume J. Charmes 3e014aa662 Fix attach race condition, improve unit tests, make sure the container is started before unblocking Start 2013-10-18 16:26:16 -07:00
Guillaume J. Charmes 333bc23f21 Fix issue killing container while sending signal
Fix rebase issue
Update docs
2013-10-18 16:19:27 -07:00
Tianon Gravi 7cf1877098 Add POSIX shell version of host_integration/manager.go in the style of hack/make.sh
Rename host_integration to host-integration for consistency
2013-10-18 16:16:29 -07:00
Guillaume J. Charmes 4918769b1a Add -nostdin and -proxy to docker attach, allow arbirary signal to be sent via docker kill api endpoint
Allow attach from `docker start`
Add host integration script generation
Update doc with host integration
2013-10-18 16:16:29 -07:00
Tianon Gravi 4b7c071e9c Merge pull request #2222 from tianon/debootstrap
Renamed and refactored mkimage-debian to mkimage-debootstrap to more clearly reflect its true function
2013-10-18 14:46:14 -07:00
Tianon Gravi 4870265a9f Add "vendor/pkg/" to .gitignore now that we "go test -i" 2013-10-18 12:18:13 -06:00
Roger Peppe 43fd85eb8f Merge remote-tracking branch 'upstream/master'
Conflicts:
	commands.go
2013-10-18 09:22:20 +01:00
Tianon Gravi ac5bc86771 Merge pull request #1 from jpetazzo/cherry-on-top-of-hack-release
Cherry on top of hack release
2013-10-17 23:21:41 -07:00
Jérôme Petazzoni 85956c70b5 Change bundle order, and fix shell array expansion.
I believe that it is helpful to build the binary first. That way,
if you interrupt the tests, you still get a binary to play with.
If you run the tests first and interrupt them, no binary for you!

Also, the second part of this commit is an undeniable proof that
Bash array syntax is nothing else than an elaborate troll by Bash
authors.
2013-10-17 23:20:18 -07:00
Jérôme Petazzoni 8c38c30985 Remove spurious messages, and use proper args expansion.
Also, display some (hopefully helpful) message when no command was given.
2013-10-17 23:19:36 -07:00
Jérôme Petazzoni 255b6aadfa Work around an exotic bug affecting Docker-in-Docker + systemd. 2013-10-17 20:42:11 -07:00
Victor Vieux 8bce284496 clean split between errors and output. JSON output always valid 2013-10-17 23:40:43 +00:00
Tianon Gravi 83a2e92d47 Update hack/release.sh process to automatically invoke hack/make.sh and bail on building/testing issues 2013-10-17 16:49:35 -06:00
Peter Braden 3db381bf08 Re #2137 Note about vagrant dns in the test documentation 2013-10-17 13:38:39 -07:00
Victor Vieux f248a8e13c Update CHANGELOG.md 2013-10-17 11:27:44 -07:00
Tianon Gravi c405d53b6e Add initial init scripts library, including systemd, sysvinit, upstart, and openrc 2013-10-17 12:03:49 -06:00
Edmund Wagner bc39ac71e6 c&p improvement for 13.04
first line killed sources list
2013-10-17 10:07:12 +02:00
Edmund Wagner 2110b3cca8 make copy paste user friendly
copying only the first line killed my sources.list file
2013-10-17 09:31:35 +02:00
Tianon Gravi 095aab9d97 Refactor mkimage-debootstrap.sh to be much more full-featured
This includes the following:
- options to control certain parameters
- an option specifically for creating tarballs directly, esp. for dockerbrew
- the addition of the updates and security repositories for Debian images
- the addition of the universe, updates, and security repositories for Ubuntu images
- more correct tagging of Debian images
- tagging of Ubuntu image versions (12.04, 12.10, etc) and latest tag for LTS
2013-10-15 03:44:03 -06:00
Tianon Gravi 4967f9f19c Rename mkimage-debian.sh to mkimage-debootstrap.sh to more clearly reflect its true function 2013-10-15 02:26:10 -06:00
Yang Bai 1043055b10 check return value of syscall.Chdir when changing working directory 2013-10-14 15:27:38 +08: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
Paul Nasrat aa3697520a Fixes issues with mounting subdirectories of /mnt in container.
Tested with
mkdir /mnt/data
docker run -v /mnt/data:/mnt/data  -t ubuntu:12.10 touch /mnt/data/bar

Expected /mnt/data/bar on host.
2013-10-09 16:40:46 -04: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
Roger Peppe 181b9baddd use less reflection in command line method invocation 2013-09-23 01:06:31 +01:00
198 changed files with 15473 additions and 4849 deletions
+2
View File
@@ -17,3 +17,5 @@ docs/_templates
bundles/
.hg/
.git/
vendor/pkg/
pyenv
+7
View File
@@ -69,12 +69,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 +94,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>
@@ -140,6 +143,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>
@@ -151,6 +155,7 @@ Roberto Hashioka <roberto_hashioka@hotmail.com>
Ryan Fowler <rwfowler@gmail.com>
Sam Alba <sam.alba@gmail.com>
Sam J Sharpe <sam.sharpe@digital.cabinet-office.gov.uk>
Scott Bessler <scottbessler@gmail.com>
Sean P. Kane <skane@newrelic.com>
Shawn Siefkas <shawn.siefkas@meredith.com>
Shih-Yuan Lee <fourdollars@gmail.com>
@@ -161,6 +166,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>
@@ -185,4 +191,5 @@ Vladimir Kirillov <proger@wilab.org.ua>
Walter Stanish <walter@pratyeka.org>
Wes Morgan <cap10morgan@gmail.com>
Will Dietz <w@wdtz.org>
Yang Bai <hamo.by@gmail.com>
Zaiste! <oh@zaiste.net>
+700 -403
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
+43 -47
View File
@@ -4,77 +4,73 @@
#
# # 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
from ubuntu:12.10
maintainer Solomon Hykes <solomon@dotcloud.com>
docker-version 0.6.1
from ubuntu:12.04
maintainer Solomon Hykes <solomon@dotcloud.com>
# Build dependencies
run apt-get update
run apt-get install -y -q curl
run apt-get install -y -q git
run apt-get install -y -q mercurial
run apt-get install -y -q build-essential
run echo 'deb http://archive.ubuntu.com/ubuntu precise main universe' > /etc/apt/sources.list
run apt-get update
run apt-get install -y -q curl
run apt-get install -y -q git
run apt-get install -y -q mercurial
run apt-get install -y -q build-essential libsqlite3-dev
# Install Go from source (for eventual cross-compiling)
run curl -s https://go.googlecode.com/files/go1.2rc1.src.tar.gz | tar -v -C / -xz && mv /go /goroot
run cd /goroot/src && ./make.bash
env GOROOT /goroot
env PATH $PATH:/goroot/bin
env GOPATH /go:/go/src/github.com/dotcloud/docker/vendor
# Create Go cache with tag netgo (for static compilation of Go while preserving CGO support)
run go install -ldflags '-w -linkmode external -extldflags "-static -Wl,--unresolved-symbols=ignore-in-shared-libs"' -tags netgo -a std
# Get lvm2 source for compiling statically
run git clone git://git.fedorahosted.org/git/lvm2.git /lvm2
run cd /lvm2 && git checkout v2_02_102
# can't use git clone -b because it's not supported by git versions before 1.7.10
run cd /lvm2 && ./configure --enable-static_link && make && make install_device-mapper
# see https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags
# Install Go
run curl -s https://go.googlecode.com/files/go1.2rc4.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
# 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
run apt-get install -y -q ruby1.9.3 rubygems libffi-dev
run gem install --no-rdoc --no-ri fpm
run apt-get install -y -q reprepro dpkg-sig
# Install s3cmd 1.0.1 (earlier versions don't support env variables in the config)
run apt-get install -y -q python-pip
run pip install s3cmd
run pip install python-magic
run /bin/echo -e '[default]\naccess_key=$AWS_ACCESS_KEY\nsecret_key=$AWS_SECRET_KEY\n' > /.s3cfg
run apt-get install -y -q python-pip
run pip install s3cmd
run pip install python-magic
run /bin/echo -e '[default]\naccess_key=$AWS_ACCESS_KEY\nsecret_key=$AWS_SECRET_KEY\n' > /.s3cfg
# Runtime dependencies
run apt-get install -y -q iptables
run dpkg-divert --local --rename --add /sbin/initctl && \
ln -s /bin/true /sbin/initctl && \
apt-get install -y -q lxc
run apt-get install -y -q iptables
run apt-get install -y -q lxc
run apt-get install -y -q aufs-tools
volume /var/lib/docker
workdir /go/src/github.com/dotcloud/docker
# 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
+8 -32
View File
@@ -1,43 +1,19 @@
Docker
Copyright 2012-2013 dotCloud, inc.
Copyright 2012-2013 Docker, Inc.
This product includes software developed at dotCloud,
inc. (http://www.dotcloud.com).
This product includes software developed at Docker, Inc. (http://www.docker.com).
This product contains software (https://github.com/kr/pty) developed
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.
+5 -6
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.
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.
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.4-dev
0.6.6-dev
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.2.12/ ]; 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.2.12/VBoxGuestAdditions_4.2.12.iso
mount -o loop,ro /home/vagrant/VBoxGuestAdditions_4.2.12.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|
+85 -41
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"
@@ -42,6 +43,9 @@ func hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) {
//If we don't do this, POST method without Content-type (even with empty body) will fail
func parseForm(r *http.Request) error {
if r == nil {
return nil
}
if err := r.ParseForm(); err != nil && !strings.HasPrefix(err.Error(), "mime:") {
return err
}
@@ -57,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
@@ -69,12 +76,12 @@ func httpError(w http.ResponseWriter, err error) {
statusCode = http.StatusUnauthorized
} else if strings.Contains(err.Error(), "hasn't been activated") {
statusCode = http.StatusForbidden
}
}
if err != nil {
utils.Errorf("HTTP Error: statusCode=%d %s", statusCode, err.Error())
http.Error(w, err.Error(), statusCode)
}
http.Error(w, err.Error(), statusCode)
}
}
func writeJSON(w http.ResponseWriter, code int, v interface{}) error {
@@ -135,8 +142,23 @@ func postContainersKill(srv *Server, version float64, w http.ResponseWriter, r *
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := parseForm(r); err != nil {
return err
}
name := vars["name"]
if err := srv.ContainerKill(name); err != nil {
signal := 0
if r != nil {
s := r.Form.Get("signal")
if s != "" {
if s, err := strconv.Atoi(s); err != nil {
return err
} else {
signal = s
}
}
}
if err := srv.ContainerKill(name, signal); err != nil {
return err
}
w.WriteHeader(http.StatusNoContent)
@@ -172,10 +194,24 @@ func getImagesJSON(srv *Server, version float64, w http.ResponseWriter, r *http.
return err
}
return writeJSON(w, http.StatusOK, outs)
if version < 1.7 {
outs2 := []APIImagesOld{}
for _, ctnr := range outs {
outs2 = append(outs2, ctnr.ToLegacy()...)
}
return writeJSON(w, http.StatusOK, outs2)
} else {
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
}
@@ -217,6 +253,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 {
@@ -445,15 +482,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 {
@@ -503,39 +541,39 @@ func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http
}
func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
config := &Config{}
if err := parseForm(r); err != nil {
return nil
}
out := &APIRun{}
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.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, err := srv.ContainerCreate(config)
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
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.")
}
@@ -570,12 +608,17 @@ func deleteContainers(srv *Server, version float64, w http.ResponseWriter, r *ht
return fmt.Errorf("Missing parameter")
}
name := vars["name"]
removeVolume, err := getBoolParam(r.Form.Get("v"))
if err != nil {
return err
}
removeLink, err := getBoolParam(r.Form.Get("link"))
if err != nil {
return err
}
if err := srv.ContainerDestroy(name, removeVolume); err != nil {
if err := srv.ContainerDestroy(name, removeVolume, removeLink); err != nil {
return err
}
w.WriteHeader(http.StatusNoContent)
@@ -607,23 +650,23 @@ func deleteImages(srv *Server, version float64, w http.ResponseWriter, r *http.R
}
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"]
if err := srv.ContainerStart(name, hostConfig); err != nil {
utils.Debugf("error ContainerStart: %s", err)
job := srv.Eng.Job("start", name)
if err := job.ImportEnv(HostConfig{}); err != nil {
return fmt.Errorf("Couldn't initialize host configuration")
}
// 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 := job.Run(); err != nil {
return err
}
w.WriteHeader(http.StatusNoContent)
@@ -656,6 +699,7 @@ func postContainersWait(srv *Server, version float64, w http.ResponseWriter, r *
return fmt.Errorf("Missing parameter")
}
name := vars["name"]
status, err := srv.ContainerWait(name)
if err != nil {
return err
@@ -871,7 +915,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
}
@@ -976,7 +1020,7 @@ func makeHttpHandler(srv *Server, logging bool, localMethod string, localRoute s
if err != nil {
version = APIVERSION
}
if srv.enableCors {
if srv.runtime.config.EnableCors {
writeCorsHeaders(w, r)
}
+45 -31
View File
@@ -1,15 +1,25 @@
package docker
import "encoding/json"
import "strings"
type APIHistory struct {
ID string `json:"Id"`
Tags []string `json:",omitempty"`
Created int64
CreatedBy string `json:",omitempty"`
Size int64
}
type APIImages struct {
ID string `json:"Id"`
RepoTags []string `json:",omitempty"`
Created int64
Size int64
VirtualSize int64
ParentId string `json:",omitempty"`
}
type APIImagesOld struct {
Repository string `json:",omitempty"`
Tag string `json:",omitempty"`
ID string `json:"Id"`
@@ -18,24 +28,39 @@ type APIImages struct {
VirtualSize int64
}
func (self *APIImages) ToLegacy() []APIImagesOld {
outs := []APIImagesOld{}
for _, repotag := range self.RepoTags {
components := strings.SplitN(repotag, ":", 2)
outs = append(outs, APIImagesOld{
ID: self.ID,
Repository: components[0],
Tag: components[1],
Created: self.Created,
Size: self.Size,
VirtualSize: self.VirtualSize,
})
}
return outs
}
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"`
DevmapperPool string `json:",omitempty"`
DevmapperDataUsed uint64 `json:",omitempty"`
DevmapperDataTotal uint64 `json:",omitempty"`
DevmapperMetadataUsed uint64 `json:",omitempty"`
DevmapperMetadataTotal uint64 `json:",omitempty"`
Debug bool
Containers int
Images int
NFd int `json:",omitempty"`
NGoroutines int `json:",omitempty"`
MemoryLimit bool `json:",omitempty"`
SwapLimit bool `json:",omitempty"`
IPv4Forwarding bool `json:",omitempty"`
LXCVersion string `json:",omitempty"`
NEventsListener int `json:",omitempty"`
KernelVersion string `json:",omitempty"`
IndexServerAddress string `json:",omitempty"`
}
type APITop struct {
@@ -57,6 +82,7 @@ type APIContainers struct {
Ports []APIPort
SizeRw int64
SizeRootFs int64
Names []string
}
func (self *APIContainers) ToLegacy() APIContainersOld {
@@ -83,11 +109,6 @@ type APIContainersOld struct {
SizeRootFs int64
}
type APISearch struct {
Name string
Description string
}
type APIID struct {
ID string `json:"Id"`
}
@@ -101,14 +122,7 @@ type APIPort struct {
PrivatePort int64
PublicPort int64
Type string
}
func (port *APIPort) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]interface{}{
"PrivatePort": port.PrivatePort,
"PublicPort": port.PublicPort,
"Type": port.Type,
})
IP string
}
type APIVersion struct {
+71 -102
View File
@@ -184,7 +184,7 @@ func TestGetImagesJSON(t *testing.T) {
found := false
for _, img := range images {
if img.Repository == unitTestImageName {
if strings.Contains(img.RepoTags[0], unitTestImageName) {
found = true
break
}
@@ -275,31 +275,6 @@ func TestGetImagesJSON(t *testing.T) {
}
}
func TestGetImagesViz(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
r := httptest.NewRecorder()
if err := getImagesViz(srv, APIVERSION, r, nil, nil); err != nil {
t.Fatal(err)
}
if r.Code != http.StatusOK {
t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
}
reader := bufio.NewReader(r.Body)
line, err := reader.ReadString('\n')
if err != nil {
t.Fatal(err)
}
if line != "digraph docker {\n" {
t.Errorf("Expected digraph docker {\n, %s found", line)
}
}
func TestGetImagesHistory(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
@@ -347,10 +322,12 @@ func TestGetContainersJSON(t *testing.T) {
srv := &Server{runtime: runtime}
container, err := runtime.Create(&Config{
beginLen := runtime.containers.Len()
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"echo", "test"},
})
}, "")
if err != nil {
t.Fatal(err)
}
@@ -362,17 +339,15 @@ func TestGetContainersJSON(t *testing.T) {
}
r := httptest.NewRecorder()
setTimeout(t, "getContainerJSON timed out", 5*time.Second, func() {
if err := getContainersJSON(srv, APIVERSION, r, req, nil); err != nil {
t.Fatal(err)
}
})
if err := getContainersJSON(srv, APIVERSION, r, req, nil); err != nil {
t.Fatal(err)
}
containers := []APIContainers{}
if err := json.Unmarshal(r.Body.Bytes(), &containers); err != nil {
t.Fatal(err)
}
if len(containers) != 1 {
t.Fatalf("Expected %d container, %d found", 1, len(containers))
if len(containers) != beginLen+1 {
t.Fatalf("Expected %d container, %d found (started with: %d)", beginLen+1, len(containers), beginLen)
}
if containers[0].ID != container.ID {
t.Fatalf("Container ID mismatch. Expected: %s, received: %s\n", container.ID, containers[0].ID)
@@ -386,11 +361,12 @@ func TestGetContainersExport(t *testing.T) {
srv := &Server{runtime: runtime}
// Create a container and remove a file
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"touch", "/test"},
},
"",
)
if err != nil {
t.Fatal(err)
@@ -402,7 +378,7 @@ func TestGetContainersExport(t *testing.T) {
}
r := httptest.NewRecorder()
if err := getContainersExport(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil {
if err = getContainersExport(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil {
t.Fatal(err)
}
@@ -436,11 +412,12 @@ func TestGetContainersChanges(t *testing.T) {
srv := &Server{runtime: runtime}
// Create a container and remove a file
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/rm", "/etc/passwd"},
},
"",
)
if err != nil {
t.Fatal(err)
@@ -479,12 +456,13 @@ func TestGetContainersTop(t *testing.T) {
srv := &Server{runtime: runtime}
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/sh", "-c", "cat"},
OpenStdin: true,
},
"",
)
if err != nil {
t.Fatal(err)
@@ -496,8 +474,7 @@ func TestGetContainersTop(t *testing.T) {
container.WaitTimeout(2 * time.Second)
}()
hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
if err := container.Start(); err != nil {
t.Fatal(err)
}
@@ -561,11 +538,12 @@ func TestGetContainersByName(t *testing.T) {
srv := &Server{runtime: runtime}
// Create a container and remove a file
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"echo", "test"},
},
"",
)
if err != nil {
t.Fatal(err)
@@ -592,11 +570,12 @@ func TestPostCommit(t *testing.T) {
srv := &Server{runtime: runtime}
// Create a container and remove a file
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"touch", "/test"},
},
"",
)
if err != nil {
t.Fatal(err)
@@ -630,11 +609,11 @@ func TestPostCommit(t *testing.T) {
}
func TestPostContainersCreate(t *testing.T) {
runtime := mkRuntime(t)
eng := NewTestEngine(t)
srv := mkServerFromEngine(eng, t)
runtime := srv.runtime
defer nuke(runtime)
srv := &Server{runtime: runtime}
configJSON, err := json.Marshal(&Config{
Image: GetTestImage(runtime).ID,
Memory: 33554432,
@@ -671,10 +650,6 @@ func TestPostContainersCreate(t *testing.T) {
t.Fatal(err)
}
if err := container.EnsureMounted(); err != nil {
t.Fatalf("Unable to mount container: %s", err)
}
if _, err := os.Stat(path.Join(container.RootfsPath(), "test")); err != nil {
if os.IsNotExist(err) {
utils.Debugf("Err: %s", err)
@@ -682,10 +657,6 @@ func TestPostContainersCreate(t *testing.T) {
}
t.Fatal(err)
}
if err := container.Unmount(); err != nil {
t.Fatalf("Unable to unmount container: %s", err)
}
}
func TestPostContainersKill(t *testing.T) {
@@ -694,20 +665,20 @@ func TestPostContainersKill(t *testing.T) {
srv := &Server{runtime: runtime}
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/cat"},
OpenStdin: true,
},
"",
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container)
hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
if err := container.Start(); err != nil {
t.Fatal(err)
}
@@ -736,20 +707,20 @@ func TestPostContainersRestart(t *testing.T) {
srv := &Server{runtime: runtime}
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/cat"},
Cmd: []string{"/bin/top"},
OpenStdin: true,
},
"",
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container)
hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
if err := container.Start(); err != nil {
t.Fatal(err)
}
@@ -785,26 +756,23 @@ func TestPostContainersRestart(t *testing.T) {
}
func TestPostContainersStart(t *testing.T) {
runtime := mkRuntime(t)
eng := NewTestEngine(t)
srv := mkServerFromEngine(eng, t)
runtime := srv.runtime
defer nuke(runtime)
srv := &Server{runtime: runtime}
container, err := runtime.Create(
id := createTestContainer(
eng,
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/cat"},
OpenStdin: true,
},
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container)
t)
hostConfigJSON, err := json.Marshal(&HostConfig{})
req, err := http.NewRequest("POST", "/containers/"+container.ID+"/start", bytes.NewReader(hostConfigJSON))
req, err := http.NewRequest("POST", "/containers/"+id+"/start", bytes.NewReader(hostConfigJSON))
if err != nil {
t.Fatal(err)
}
@@ -812,22 +780,26 @@ func TestPostContainersStart(t *testing.T) {
req.Header.Set("Content-Type", "application/json")
r := httptest.NewRecorder()
if err := postContainersStart(srv, APIVERSION, r, req, map[string]string{"name": container.ID}); err != nil {
if err := postContainersStart(srv, APIVERSION, r, req, map[string]string{"name": id}); err != nil {
t.Fatal(err)
}
if r.Code != http.StatusNoContent {
t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
}
container := runtime.Get(id)
if container == nil {
t.Fatalf("Container %s was not created", id)
}
// Give some time to the process to start
// FIXME: use Wait once it's available as a job
container.WaitTimeout(500 * time.Millisecond)
if !container.State.Running {
t.Errorf("Container should be running")
}
r = httptest.NewRecorder()
if err = postContainersStart(srv, APIVERSION, r, req, map[string]string{"name": container.ID}); err == nil {
if err = postContainersStart(srv, APIVERSION, r, req, map[string]string{"name": id}); err == nil {
t.Fatalf("A running container should be able to be started")
}
@@ -842,20 +814,20 @@ func TestPostContainersStop(t *testing.T) {
srv := &Server{runtime: runtime}
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/cat"},
Cmd: []string{"/bin/top"},
OpenStdin: true,
},
"",
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container)
hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
if err := container.Start(); err != nil {
t.Fatal(err)
}
@@ -889,20 +861,20 @@ func TestPostContainersWait(t *testing.T) {
srv := &Server{runtime: runtime}
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/sleep", "1"},
OpenStdin: true,
},
"",
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container)
hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
if err := container.Start(); err != nil {
t.Fatal(err)
}
@@ -931,12 +903,13 @@ func TestPostContainersAttach(t *testing.T) {
srv := &Server{runtime: runtime}
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/cat"},
OpenStdin: true,
},
"",
)
if err != nil {
t.Fatal(err)
@@ -944,8 +917,7 @@ func TestPostContainersAttach(t *testing.T) {
defer runtime.Destroy(container)
// Start the process
hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
if err := container.Start(); err != nil {
t.Fatal(err)
}
@@ -1020,12 +992,13 @@ func TestPostContainersAttachStderr(t *testing.T) {
srv := &Server{runtime: runtime}
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/sh", "-c", "/bin/cat >&2"},
OpenStdin: true,
},
"",
)
if err != nil {
t.Fatal(err)
@@ -1033,8 +1006,7 @@ func TestPostContainersAttachStderr(t *testing.T) {
defer runtime.Destroy(container)
// Start the process
hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
if err := container.Start(); err != nil {
t.Fatal(err)
}
@@ -1112,10 +1084,10 @@ func TestDeleteContainers(t *testing.T) {
srv := &Server{runtime: runtime}
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"touch", "/test"},
})
}, "")
if err != nil {
t.Fatal(err)
}
@@ -1141,7 +1113,7 @@ func TestDeleteContainers(t *testing.T) {
t.Fatalf("The container as not been deleted")
}
if _, err := os.Stat(path.Join(container.rwPath(), "test")); err == nil {
if _, err := os.Stat(path.Join(container.RootfsPath(), "test")); err == nil {
t.Fatalf("The test file has not been deleted")
}
}
@@ -1150,7 +1122,8 @@ func TestOptionsRoute(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime, enableCors: true}
runtime.config.EnableCors = true
srv := &Server{runtime: runtime}
r := httptest.NewRecorder()
router, err := createRouter(srv, false)
@@ -1173,7 +1146,8 @@ func TestGetEnabledCors(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime, enableCors: true}
runtime.config.EnableCors = true
srv := &Server{runtime: runtime}
r := httptest.NewRecorder()
@@ -1227,7 +1201,7 @@ func TestDeleteImages(t *testing.T) {
t.Fatal(err)
}
if len(images) != len(initialImages)+1 {
if len(images[0].RepoTags) != len(initialImages[0].RepoTags)+1 {
t.Errorf("Expected %d images, %d found", len(initialImages)+1, len(images))
}
@@ -1266,17 +1240,11 @@ func TestDeleteImages(t *testing.T) {
t.Fatal(err)
}
if len(images) != len(initialImages) {
if len(images[0].RepoTags) != len(initialImages[0].RepoTags) {
t.Errorf("Expected %d image, %d found", len(initialImages), len(images))
}
/* if c := runtime.Get(container.Id); c != nil {
t.Fatalf("The container as not been deleted")
}
if _, err := os.Stat(path.Join(container.rwPath(), "test")); err == nil {
t.Fatalf("The test file has not been deleted")
} */
// FIXME: check that container has been deleted, and its filesystem too
}
func TestJsonContentType(t *testing.T) {
@@ -1300,11 +1268,12 @@ func TestPostContainersCopy(t *testing.T) {
srv := &Server{runtime: runtime}
// Create a container and remove a file
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"touch", "/test.txt"},
},
"",
)
if err != nil {
t.Fatal(err)
+1
View File
@@ -0,0 +1 @@
Michael Crosby <michael@crosbymichael.com> (@crosbymichael)
+36 -17
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,7 +88,7 @@ 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, true, nil)
return TarFilter(path, &TarOptions{Recursive: true, Compression: compression})
}
func escapeName(name string) string {
@@ -101,25 +109,29 @@ func escapeName(name string) string {
// 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, recursive bool, createFiles []string) (io.Reader, error) {
func TarFilter(path string, options *TarOptions) (io.Reader, error) {
args := []string{"tar", "--numeric-owner", "-f", "-", "-C", path, "-T", "-"}
if filter == nil {
filter = []string{"."}
if options.Includes == nil {
options.Includes = []string{"."}
}
args = append(args, "-c"+compression.Flag())
args = append(args, "-c"+options.Compression.Flag())
if !recursive {
for _, exclude := range options.Excludes {
args = append(args, fmt.Sprintf("--exclude=%s", exclude))
}
if !options.Recursive {
args = append(args, "--no-recursion")
}
files := ""
for _, f := range filter {
for _, f := range options.Includes {
files = files + escapeName(f) + "\n"
}
tmpDir := ""
if createFiles != nil {
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 {
@@ -127,7 +139,7 @@ func TarFilter(path string, compression Compression, filter []string, recursive
}
files = files + "-C" + tmpDir + "\n"
for _, f := range createFiles {
for _, f := range options.CreateFiles {
path := filepath.Join(tmpDir, f)
err := os.MkdirAll(filepath.Dir(path), 0600)
if err != nil {
@@ -155,7 +167,7 @@ func TarFilter(path string, compression Compression, filter []string, recursive
// 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")
}
@@ -176,8 +188,15 @@ func Untar(archive io.Reader, path string) error {
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)
@@ -194,11 +213,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, true, nil)
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
@@ -206,7 +225,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
@@ -275,7 +294,7 @@ 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.
+2 -2
View File
@@ -1,4 +1,4 @@
package docker
package archive
import (
"bytes"
@@ -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 {
+94 -109
View File
@@ -1,4 +1,4 @@
package docker
package archive
import (
"fmt"
@@ -34,6 +34,78 @@ func (change *Change) String() string {
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
@@ -67,21 +139,6 @@ func (info *FileInfo) path() string {
return filepath.Join(info.parent.path(), info.name)
}
func (info *FileInfo) unlink() {
if info.parent != nil {
delete(info.parent.children, info.name)
}
}
func (info *FileInfo) Remove(path string) bool {
child := info.LookUp(path)
if child != nil {
child.unlink()
return true
}
return false
}
func (info *FileInfo) isDir() bool {
return info.parent == nil || info.stat.Mode&syscall.S_IFDIR == syscall.S_IFDIR
}
@@ -118,16 +175,13 @@ func (info *FileInfo) addChanges(oldInfo *FileInfo, changes *[]Change) {
// be visible when actually comparing the stat fields. The only time this
// breaks down is if some code intentionally hides a change by setting
// back mtime
oldMtime := syscall.NsecToTimeval(oldStat.Mtim.Nano())
newMtime := syscall.NsecToTimeval(oldStat.Mtim.Nano())
if oldStat.Mode != newStat.Mode ||
oldStat.Uid != newStat.Uid ||
oldStat.Gid != newStat.Gid ||
oldStat.Rdev != newStat.Rdev ||
// Don't look at size for dirs, its not a good measure of change
(oldStat.Size != newStat.Size && oldStat.Mode&syscall.S_IFDIR != syscall.S_IFDIR) ||
oldMtime.Sec != newMtime.Sec ||
oldMtime.Usec != newMtime.Usec {
oldStat.Mtim != newStat.Mtim {
change := Change{
Path: newChild.path(),
Kind: ChangeModify,
@@ -168,77 +222,6 @@ func newRootFileInfo() *FileInfo {
return root
}
func applyLayer(root *FileInfo, layer string) error {
err := filepath.Walk(layer, func(layerPath string, f os.FileInfo, err error) error {
if err != nil {
return err
}
// Skip root
if layerPath == layer {
return nil
}
// rebase path
relPath, err := filepath.Rel(layer, layerPath)
if err != nil {
return err
}
relPath = filepath.Join("/", relPath)
// Skip AUFS metadata
if matched, err := filepath.Match("/.wh..wh.*", relPath); err != nil || matched {
if err != nil || !f.IsDir() {
return err
}
return filepath.SkipDir
}
var layerStat syscall.Stat_t
err = syscall.Lstat(layerPath, &layerStat)
if err != nil {
return err
}
file := filepath.Base(relPath)
// If there is a whiteout, then the file was removed
if strings.HasPrefix(file, ".wh.") {
originalFile := file[len(".wh."):]
deletePath := filepath.Join(filepath.Dir(relPath), originalFile)
root.Remove(deletePath)
} else {
// Added or changed file
existing := root.LookUp(relPath)
if existing != nil {
// Changed file
existing.stat = layerStat
if !existing.isDir() {
// Changed from dir to non-dir, delete all previous files
existing.children = make(map[string]*FileInfo)
}
} else {
// Added file
parent := root.LookUp(filepath.Dir(relPath))
if parent == nil {
return fmt.Errorf("collectFileInfo: Unexpectedly no parent for %s", relPath)
}
info := &FileInfo{
name: filepath.Base(relPath),
children: make(map[string]*FileInfo),
parent: parent,
stat: layerStat,
}
parent.children[info.name] = info
}
}
return nil
})
return err
}
func collectFileInfo(sourceDir string) (*FileInfo, error) {
root := newRootFileInfo()
@@ -283,24 +266,6 @@ func collectFileInfo(sourceDir string) (*FileInfo, error) {
return root, nil
}
// Compare a directory with an array of layer directories it was based on and
// generate an array of Change objects describing the changes
func ChangesLayers(newDir string, layers []string) ([]Change, error) {
newRoot, err := collectFileInfo(newDir)
if err != nil {
return nil, err
}
oldRoot := newRootFileInfo()
for i := len(layers) - 1; i >= 0; i-- {
layer := layers[i]
if err = applyLayer(oldRoot, layer); err != nil {
return nil, err
}
}
return newRoot.Changes(oldRoot), nil
}
// Compare two directories and generate an array of Change objects describing the changes
func ChangesDirs(newDir, oldDir string) ([]Change, error) {
oldRoot, err := collectFileInfo(oldDir)
@@ -314,3 +279,23 @@ func ChangesDirs(newDir, oldDir string) ([]Change, error) {
return newRoot.Changes(oldRoot), nil
}
func ExportChanges(root, rw string) (Archive, error) {
changes, err := ChangesDirs(root, rw)
if err != nil {
return nil, err
}
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))
}
}
return TarFilter(root, &TarOptions{Compression: Uncompressed, Recursive: false, Includes: files, CreateFiles: deletions})
}
+63
View File
@@ -0,0 +1,63 @@
package archive
import (
"log"
"os"
"path/filepath"
"strings"
)
// 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
}
// 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 {
log.Printf("Removing aufs metadata %s", fullPath)
_ = os.RemoveAll(fullPath)
}
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
log.Printf("Removing whiteout target %s", rmTargetPath)
_ = os.Remove(rmTargetPath)
// Remove the whiteout itself
log.Printf("Removing whiteout %s", fullPath)
_ = os.RemoveAll(fullPath)
}
return nil
})
if err != nil {
return err
}
return nil
}
+316
View File
@@ -0,0 +1,316 @@
/*
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 AufsDriver 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 &AufsDriver{root}, nil
}
return nil, err
}
for _, p := range paths {
if err := os.MkdirAll(path.Join(root, p), 0755); err != nil {
return nil, err
}
}
return &AufsDriver{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 *AufsDriver) rootPath() string {
return a.root
}
func (a *AufsDriver) String() string {
return "aufs"
}
// Three folders are created for each id
// mnt, layers, and diff
func (a *AufsDriver) 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 *AufsDriver) 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 *AufsDriver) 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 {
return err
}
defer os.RemoveAll(tmp)
}
// Remove the layers file for the id
return os.Remove(path.Join(a.rootPath(), "layers", id))
}
// Return the rootfs path for the id
// This will mount the dir at it's given path
func (a *AufsDriver) 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 *AufsDriver) Diff(id string) (archive.Archive, error) {
return archive.TarFilter(path.Join(a.rootPath(), "diff", id), &archive.TarOptions{
Recursive: true,
Compression: archive.Uncompressed,
})
}
func (a *AufsDriver) 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 *AufsDriver) Size(id string) (int64, error) {
return utils.TreeSize(path.Join(a.rootPath(), "diff", id))
}
func (a *AufsDriver) 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 *AufsDriver) 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 *AufsDriver) 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 *AufsDriver) 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 *AufsDriver) 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 *AufsDriver) 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 {
return err
}
}
return nil
}
func (a *AufsDriver) 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
}
+517
View File
@@ -0,0 +1,517 @@
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) *AufsDriver {
if err := os.MkdirAll(tmp, 0755); err != nil {
t.Fatal(err)
}
d, err := Init(tmp)
if err != nil {
t.Fatal(err)
}
return d.(*AufsDriver)
}
func TestNewAufsDriver(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)
}
f.Truncate(size)
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.Size("1")
if err != nil {
t.Fatal(err)
}
if diffSize != size {
t.Fatalf("Expected size to be %d got %d", size, diffSize)
}
}
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)
}
f.Truncate(size)
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()
}
+37
View File
@@ -0,0 +1,37 @@
package aufs
import (
"github.com/dotcloud/docker/utils"
"os"
"os/exec"
"path/filepath"
"syscall"
)
func Unmount(target string) error {
if err := exec.Command("auplink", target, "flush").Run(); err != nil {
utils.Errorf("[warning]: couldn't run auplink before unmount: %s", err)
}
if err := syscall.Unmount(target, 0); err != nil {
return err
}
return nil
}
func Mounted(mountpoint string) (bool, error) {
mntpoint, err := os.Stat(mountpoint)
if err != nil {
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
parent, err := os.Stat(filepath.Join(mountpoint, ".."))
if err != nil {
return false, err
}
mntpointSt := mntpoint.Sys().(*syscall.Stat_t)
parentSt := parent.Sys().(*syscall.Stat_t)
return mntpointSt.Dev != parentSt.Dev, nil
}
+1 -1
View File
@@ -1,4 +1,4 @@
package docker
package aufs
import "errors"
+1 -1
View File
@@ -1,4 +1,4 @@
package docker
package aufs
import "syscall"
+26 -15
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")
}
@@ -176,8 +180,6 @@ func (b *buildFile) CmdEnv(args string) error {
func (b *buildFile) CmdCmd(args string) error {
var cmd []string
if err := json.Unmarshal([]byte(args), &cmd); err != nil {
// If the unmarshal fails, it is not an error, we just use the
// args as a string.
utils.Debugf("Error unmarshalling: %s, setting cmd to /bin/sh -c", err)
cmd = []string{"/bin/sh", "-c", args}
}
@@ -293,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 {
utils.Debugf("[tar] Not a directory nor a tar archive. Copying as a file. Untar error from %s to %s: %s", origPath, destPath, err)
} 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
}
}
@@ -334,7 +336,7 @@ func (b *buildFile) CmdAdd(args string) error {
b.config.Image = b.image
// Create the container and start it
container, err := b.runtime.Create(b.config)
container, _, err := b.runtime.Create(b.config, "")
if err != nil {
return err
}
@@ -369,7 +371,7 @@ func (b *buildFile) run() (string, error) {
b.config.Image = b.image
// Create the container and start it
c, err := b.runtime.Create(b.config)
c, _, err := b.runtime.Create(b.config, "")
if err != nil {
return "", err
}
@@ -380,15 +382,21 @@ func (b *buildFile) run() (string, error) {
c.Path = b.config.Cmd[0]
c.Args = b.config.Cmd[1:]
var errCh chan error
if b.verbose {
errCh = utils.Go(func() error {
return <-c.Attach(nil, nil, b.out, b.out)
})
}
//start the container
hostConfig := &HostConfig{}
if err := c.Start(hostConfig); err != nil {
if err := c.Start(); err != nil {
return "", err
}
if b.verbose {
err = <-c.Attach(nil, nil, b.out, b.out)
if err != nil {
if errCh != nil {
if err := <-errCh; err != nil {
return "", err
}
}
@@ -425,10 +433,13 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
}
}
container, err := b.runtime.Create(b.config)
container, warnings, err := b.runtime.Create(b.config, "")
if err != nil {
return err
}
for _, warning := range warnings {
fmt.Fprintf(b.out, " ---> [Warning] %s\n", warning)
}
b.tmpContainers[container.ID] = struct{}{}
fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(container.ID))
id = container.ID
@@ -465,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)
+35 -1
View File
@@ -2,6 +2,7 @@ package docker
import (
"fmt"
"github.com/dotcloud/docker/archive"
"io/ioutil"
"net"
"net/http"
@@ -12,7 +13,7 @@ import (
// mkTestContext generates a build context from the contents of the provided dockerfile.
// This context is suitable for use as an argument to BuildFile.Build()
func mkTestContext(dockerfile string, files [][2]string, t *testing.T) Archive {
func mkTestContext(dockerfile string, files [][2]string, t *testing.T) archive.Archive {
context, err := mkBuildContext(dockerfile, files)
if err != nil {
t.Fatal(err)
@@ -541,3 +542,36 @@ func TestBuildADDFileNotFound(t *testing.T) {
t.Fail()
}
}
func TestBuildInheritance(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{
runtime: runtime,
pullingPool: make(map[string]struct{}),
pushingPool: make(map[string]struct{}),
}
img := buildImage(testContextTemplate{`
from {IMAGE}
expose 4243
`,
nil, nil}, t, srv, true)
img2 := buildImage(testContextTemplate{fmt.Sprintf(`
from %s
entrypoint ["/bin/echo"]
`, img.ID),
nil, nil}, t, srv, true)
// from child
if img2.Config.Entrypoint[0] != "/bin/echo" {
t.Fail()
}
// from parent
if img.Config.PortSpecs[0] != "4243" {
t.Fail()
}
}
+523 -189
View File
File diff suppressed because it is too large Load Diff
+375 -15
View File
@@ -6,6 +6,9 @@ import (
"github.com/dotcloud/docker/utils"
"io"
"io/ioutil"
"os"
"path"
"regexp"
"strings"
"testing"
"time"
@@ -84,10 +87,24 @@ func TestRunHostname(t *testing.T) {
}
})
setTimeout(t, "CmdRun timed out", 5*time.Second, func() {
container := globalRuntime.List()[0]
setTimeout(t, "CmdRun timed out", 10*time.Second, func() {
<-c
go func() {
cli.CmdWait(container.ID)
}()
if _, err := bufio.NewReader(stdout).ReadString('\n'); err != nil {
t.Fatal(err)
}
})
// Cleanup pipes
if err := closeWrap(stdout, stdoutPipe); err != nil {
t.Fatal(err)
}
}
// TestRunWorkdir checks that 'docker run -w' correctly sets a custom working directory
@@ -115,10 +132,24 @@ func TestRunWorkdir(t *testing.T) {
}
})
setTimeout(t, "CmdRun timed out", 5*time.Second, func() {
container := globalRuntime.List()[0]
setTimeout(t, "CmdRun timed out", 10*time.Second, func() {
<-c
go func() {
cli.CmdWait(container.ID)
}()
if _, err := bufio.NewReader(stdout).ReadString('\n'); err != nil {
t.Fatal(err)
}
})
// Cleanup pipes
if err := closeWrap(stdout, stdoutPipe); err != nil {
t.Fatal(err)
}
}
// TestRunWorkdirExists checks that 'docker run -w' correctly sets a custom working directory, even if it exists
@@ -146,10 +177,24 @@ func TestRunWorkdirExists(t *testing.T) {
}
})
container := globalRuntime.List()[0]
setTimeout(t, "CmdRun timed out", 5*time.Second, func() {
<-c
go func() {
cli.CmdWait(container.ID)
}()
if _, err := bufio.NewReader(stdout).ReadString('\n'); err != nil {
t.Fatal(err)
}
})
// Cleanup pipes
if err := closeWrap(stdout, stdoutPipe); err != nil {
t.Fatal(err)
}
}
func TestRunExit(t *testing.T) {
@@ -262,7 +307,7 @@ func TestRunDisconnectTty(t *testing.T) {
// We're simulating a disconnect so the return value doesn't matter. What matters is the
// fact that CmdRun returns.
if err := cli.CmdRun("-i", "-t", unitTestImageID, "/bin/cat"); err != nil {
utils.Debugf("Error CmdRun: %s\n", err)
utils.Debugf("Error CmdRun: %s", err)
}
close(c1)
@@ -338,8 +383,8 @@ func TestRunAttachStdin(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if cmdOutput != container.ShortID()+"\n" {
t.Fatalf("Wrong output: should be '%s', not '%s'\n", container.ShortID()+"\n", cmdOutput)
if cmdOutput != container.ID+"\n" {
t.Fatalf("Wrong output: should be '%s', not '%s'\n", container.ID+"\n", cmdOutput)
}
})
@@ -393,12 +438,14 @@ func TestRunDetach(t *testing.T) {
container := globalRuntime.List()[0]
setTimeout(t, "Escape sequence timeout", 5*time.Second, func() {
stdinPipe.Write([]byte{'', ''})
stdinPipe.Write([]byte{16, 17})
if err := stdinPipe.Close(); err != nil {
t.Fatal(err)
}
})
closeWrap(stdin, stdinPipe, stdout, stdoutPipe)
// wait for CmdRun to return
setTimeout(t, "Waiting for CmdRun timed out", 15*time.Second, func() {
<-ch
@@ -411,11 +458,10 @@ func TestRunDetach(t *testing.T) {
setTimeout(t, "Waiting for container to die timed out", 20*time.Second, func() {
container.Kill()
container.Wait()
})
}
// TestAttachDetach checks that attach in tty mode can be detached
// TestAttachDetach checks that attach in tty mode can be detached using the long container ID
func TestAttachDetach(t *testing.T) {
stdin, stdinPipe := io.Pipe()
stdout, stdoutPipe := io.Pipe()
@@ -423,6 +469,86 @@ func TestAttachDetach(t *testing.T) {
cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
defer cleanup(globalRuntime)
ch := make(chan struct{})
go func() {
defer close(ch)
if err := cli.CmdRun("-i", "-t", "-d", unitTestImageID, "cat"); err != nil {
t.Fatal(err)
}
}()
var container *Container
setTimeout(t, "Reading container's id timed out", 10*time.Second, func() {
buf := make([]byte, 1024)
n, err := stdout.Read(buf)
if err != nil {
t.Fatal(err)
}
container = globalRuntime.List()[0]
if strings.Trim(string(buf[:n]), " \r\n") != container.ID {
t.Fatalf("Wrong ID received. Expect %s, received %s", container.ID, buf[:n])
}
})
setTimeout(t, "Starting container timed out", 10*time.Second, func() {
<-ch
})
stdin, stdinPipe = io.Pipe()
stdout, stdoutPipe = io.Pipe()
cli = NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
ch = make(chan struct{})
go func() {
defer close(ch)
if err := cli.CmdAttach(container.ID); err != nil {
if err != io.ErrClosedPipe {
t.Fatal(err)
}
}
}()
setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
if err != io.ErrClosedPipe {
t.Fatal(err)
}
}
})
setTimeout(t, "Escape sequence timeout", 5*time.Second, func() {
stdinPipe.Write([]byte{16, 17})
if err := stdinPipe.Close(); err != nil {
t.Fatal(err)
}
})
closeWrap(stdin, stdinPipe, stdout, stdoutPipe)
// wait for CmdRun to return
setTimeout(t, "Waiting for CmdAttach timed out", 15*time.Second, func() {
<-ch
})
time.Sleep(500 * time.Millisecond)
if !container.State.Running {
t.Fatal("The detached container should be still running")
}
setTimeout(t, "Waiting for container to die timedout", 5*time.Second, func() {
container.Kill()
})
}
// TestAttachDetachTruncatedID checks that attach in tty mode can be detached
func TestAttachDetachTruncatedID(t *testing.T) {
stdin, stdinPipe := io.Pipe()
stdout, stdoutPipe := io.Pipe()
cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
defer cleanup(globalRuntime)
go stdout.Read(make([]byte, 1024))
setTimeout(t, "Starting container timed out", 2*time.Second, func() {
if err := cli.CmdRun("-i", "-t", "-d", unitTestImageID, "cat"); err != nil {
@@ -439,23 +565,28 @@ func TestAttachDetach(t *testing.T) {
ch := make(chan struct{})
go func() {
defer close(ch)
if err := cli.CmdAttach(container.ShortID()); err != nil {
t.Fatal(err)
if err := cli.CmdAttach(utils.TruncateID(container.ID)); err != nil {
if err != io.ErrClosedPipe {
t.Fatal(err)
}
}
}()
setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
t.Fatal(err)
if err != io.ErrClosedPipe {
t.Fatal(err)
}
}
})
setTimeout(t, "Escape sequence timeout", 5*time.Second, func() {
stdinPipe.Write([]byte{'', ''})
stdinPipe.Write([]byte{16, 17})
if err := stdinPipe.Close(); err != nil {
t.Fatal(err)
}
})
closeWrap(stdin, stdinPipe, stdout, stdoutPipe)
// wait for CmdRun to return
setTimeout(t, "Waiting for CmdAttach timed out", 15*time.Second, func() {
@@ -469,7 +600,6 @@ func TestAttachDetach(t *testing.T) {
setTimeout(t, "Waiting for container to die timedout", 5*time.Second, func() {
container.Kill()
container.Wait()
})
}
@@ -484,7 +614,7 @@ func TestAttachDisconnect(t *testing.T) {
go func() {
// Start a process in daemon mode
if err := cli.CmdRun("-d", "-i", unitTestImageID, "/bin/cat"); err != nil {
utils.Debugf("Error CmdRun: %s\n", err)
utils.Debugf("Error CmdRun: %s", err)
}
}()
@@ -570,7 +700,7 @@ func TestRunAutoRemove(t *testing.T) {
}
})
setTimeout(t, "CmdRun timed out", 5*time.Second, func() {
setTimeout(t, "CmdRun timed out", 10*time.Second, func() {
<-c
})
@@ -580,3 +710,233 @@ func TestRunAutoRemove(t *testing.T) {
t.Fatalf("failed to remove container automatically: container %s still exists", temporaryContainerID)
}
}
func TestCmdLogs(t *testing.T) {
cli := NewDockerCli(nil, ioutil.Discard, ioutil.Discard, testDaemonProto, testDaemonAddr)
defer cleanup(globalRuntime)
if err := cli.CmdRun(unitTestImageID, "sh", "-c", "ls -l"); err != nil {
t.Fatal(err)
}
if err := cli.CmdRun("-t", unitTestImageID, "sh", "-c", "ls -l"); err != nil {
t.Fatal(err)
}
if err := cli.CmdLogs(globalRuntime.List()[0].ID); err != nil {
t.Fatal(err)
}
}
// Expected behaviour: using / as a bind mount source should throw an error
func TestRunErrorBindMountRootSource(t *testing.T) {
cli := NewDockerCli(nil, nil, ioutil.Discard, testDaemonProto, testDaemonAddr)
defer cleanup(globalRuntime)
c := make(chan struct{})
go func() {
defer close(c)
if err := cli.CmdRun("-v", "/:/tmp", unitTestImageID, "echo 'should fail'"); err == nil {
t.Fatal("should have failed to run when using / as a source for the bind mount")
}
}()
setTimeout(t, "CmdRun timed out", 5*time.Second, func() {
<-c
})
}
// Expected behaviour: error out when attempting to bind mount non-existing source paths
func TestRunErrorBindNonExistingSource(t *testing.T) {
cli := NewDockerCli(nil, nil, ioutil.Discard, testDaemonProto, testDaemonAddr)
defer cleanup(globalRuntime)
c := make(chan struct{})
go func() {
defer close(c)
if err := cli.CmdRun("-v", "/i/dont/exist:/tmp", unitTestImageID, "echo 'should fail'"); err == nil {
t.Fatal("should have failed to run when using /i/dont/exist as a source for the bind mount")
}
}()
setTimeout(t, "CmdRun timed out", 5*time.Second, func() {
<-c
})
}
func TestImagesViz(t *testing.T) {
stdout, stdoutPipe := io.Pipe()
cli := NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
defer cleanup(globalRuntime)
srv := &Server{runtime: globalRuntime}
image := buildTestImages(t, srv)
c := make(chan struct{})
go func() {
defer close(c)
if err := cli.CmdImages("-viz"); err != nil {
t.Fatal(err)
}
stdoutPipe.Close()
}()
setTimeout(t, "Reading command output time out", 2*time.Second, func() {
cmdOutputBytes, err := ioutil.ReadAll(bufio.NewReader(stdout))
if err != nil {
t.Fatal(err)
}
cmdOutput := string(cmdOutputBytes)
regexpStrings := []string{
"digraph docker {",
fmt.Sprintf("base -> \"%s\" \\[style=invis]", unitTestImageIDShort),
fmt.Sprintf("label=\"%s\\\\n%s:latest\"", unitTestImageIDShort, unitTestImageName),
fmt.Sprintf("label=\"%s\\\\n%s:%s\"", utils.TruncateID(image.ID), "test", "latest"),
"base \\[style=invisible]",
}
compiledRegexps := []*regexp.Regexp{}
for _, regexpString := range regexpStrings {
regexp, err := regexp.Compile(regexpString)
if err != nil {
fmt.Println("Error in regex string: ", err)
return
}
compiledRegexps = append(compiledRegexps, regexp)
}
for _, regexp := range compiledRegexps {
if !regexp.MatchString(cmdOutput) {
t.Fatalf("images -viz content '%s' did not match regexp '%s'", cmdOutput, regexp)
}
}
})
}
func TestImagesTree(t *testing.T) {
stdout, stdoutPipe := io.Pipe()
cli := NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
defer cleanup(globalRuntime)
srv := &Server{runtime: globalRuntime}
image := buildTestImages(t, srv)
c := make(chan struct{})
go func() {
defer close(c)
if err := cli.CmdImages("-tree"); err != nil {
t.Fatal(err)
}
stdoutPipe.Close()
}()
setTimeout(t, "Reading command output time out", 2*time.Second, func() {
cmdOutputBytes, err := ioutil.ReadAll(bufio.NewReader(stdout))
if err != nil {
t.Fatal(err)
}
cmdOutput := string(cmdOutputBytes)
regexpStrings := []string{
fmt.Sprintf("└─%s Size: (\\d+.\\d+ MB) \\(virtual \\d+.\\d+ MB\\) Tags: %s:latest", unitTestImageIDShort, unitTestImageName),
"(?m) └─[0-9a-f]+.*",
"(?m) └─[0-9a-f]+.*",
"(?m) └─[0-9a-f]+.*",
fmt.Sprintf("(?m)^ └─%s Size: \\d+.\\d+ MB \\(virtual \\d+.\\d+ MB\\) Tags: test:latest", utils.TruncateID(image.ID)),
}
compiledRegexps := []*regexp.Regexp{}
for _, regexpString := range regexpStrings {
regexp, err := regexp.Compile(regexpString)
if err != nil {
fmt.Println("Error in regex string: ", err)
return
}
compiledRegexps = append(compiledRegexps, regexp)
}
for _, regexp := range compiledRegexps {
if !regexp.MatchString(cmdOutput) {
t.Fatalf("images -tree content '%s' did not match regexp '%s'", cmdOutput, regexp)
}
}
})
}
func buildTestImages(t *testing.T, srv *Server) *Image {
var testBuilder = testContextTemplate{
`
from {IMAGE}
run sh -c 'echo root:testpass > /tmp/passwd'
run mkdir -p /var/run/sshd
run [ "$(cat /tmp/passwd)" = "root:testpass" ]
run [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]
`,
nil,
nil,
}
image := buildImage(testBuilder, t, srv, true)
err := srv.ContainerTag(image.ID, "test", "latest", false)
if err != nil {
t.Fatal(err)
}
return image
}
// #2098 - Docker cidFiles only contain short version of the containerId
//sudo docker run -cidfile /tmp/docker_test.cid ubuntu echo "test"
// TestRunCidFile tests that run -cidfile returns the longid
func TestRunCidFile(t *testing.T) {
stdout, stdoutPipe := io.Pipe()
tmpDir, err := ioutil.TempDir("", "TestRunCidFile")
if err != nil {
t.Fatal(err)
}
tmpCidFile := path.Join(tmpDir, "cid")
cli := NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
defer cleanup(globalRuntime)
c := make(chan struct{})
go func() {
defer close(c)
if err := cli.CmdRun("-cidfile", tmpCidFile, unitTestImageID, "ls"); err != nil {
t.Fatal(err)
}
}()
defer os.RemoveAll(tmpDir)
setTimeout(t, "Reading command output time out", 2*time.Second, func() {
cmdOutput, err := bufio.NewReader(stdout).ReadString('\n')
if err != nil {
t.Fatal(err)
}
if len(cmdOutput) < 1 {
t.Fatalf("'ls' should return something , not '%s'", cmdOutput)
}
//read the tmpCidFile
buffer, err := ioutil.ReadFile(tmpCidFile)
if err != nil {
t.Fatal(err)
}
id := string(buffer)
if len(id) != len("2bf44ea18873287bd9ace8a4cb536a7cbe134bed67e805fdf2f58a57f69b320c") {
t.Fatalf("-cidfile should be a long id, not '%s'", id)
}
//test that its a valid cid? (though the container is gone..)
//remove the file and dir.
})
setTimeout(t, "CmdRun timed out", 5*time.Second, func() {
<-c
})
}
+41
View File
@@ -0,0 +1,41 @@
package docker
import (
"github.com/dotcloud/docker/engine"
"net"
)
// FIXME: separate runtime configuration from http api configuration
type DaemonConfig struct {
Pidfile string
Root string
AutoRestart bool
EnableCors bool
Dns []string
EnableIptables bool
BridgeIface string
DefaultIp net.IP
InterContainerCommunication bool
}
// 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")
return &config
}
+520 -259
View File
File diff suppressed because it is too large Load Diff
+295 -89
View File
@@ -3,6 +3,7 @@ package docker
import (
"bufio"
"fmt"
"github.com/dotcloud/docker/utils"
"io"
"io/ioutil"
"math/rand"
@@ -18,11 +19,12 @@ import (
func TestIDFormat(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container1, err := runtime.Create(
container1, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/sh", "-c", "echo hello world"},
},
"",
)
if err != nil {
t.Fatal(err)
@@ -39,7 +41,7 @@ func TestIDFormat(t *testing.T) {
func TestMultipleAttachRestart(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, hostConfig, _ := mkContainer(
container, _ := mkContainer(
runtime,
[]string{"_", "/bin/sh", "-c", "i=1; while [ $i -le 5 ]; do i=`expr $i + 1`; echo hello; done"},
t,
@@ -60,7 +62,7 @@ func TestMultipleAttachRestart(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if err := container.Start(hostConfig); err != nil {
if err := container.Start(); err != nil {
t.Fatal(err)
}
l1, err := bufio.NewReader(stdout1).ReadString('\n')
@@ -101,7 +103,7 @@ func TestMultipleAttachRestart(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if err := container.Start(hostConfig); err != nil {
if err := container.Start(); err != nil {
t.Fatal(err)
}
@@ -135,7 +137,7 @@ func TestDiff(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
// Create a container and remove a file
container1, _, _ := mkContainer(runtime, []string{"_", "/bin/rm", "/etc/passwd"}, t)
container1, _ := mkContainer(runtime, []string{"_", "/bin/rm", "/etc/passwd"}, t)
defer runtime.Destroy(container1)
// The changelog should be empty and not fail before run. See #1705
@@ -169,15 +171,15 @@ func TestDiff(t *testing.T) {
// Commit the container
rwTar, err := container1.ExportRw()
if err != nil {
t.Error(err)
t.Fatal(err)
}
img, err := runtime.graph.Create(rwTar, container1, "unit test commited image - diff", "", nil)
if err != nil {
t.Error(err)
t.Fatal(err)
}
// Create a new container from the commited image
container2, _, _ := mkContainer(runtime, []string{img.ID, "cat", "/etc/passwd"}, t)
container2, _ := mkContainer(runtime, []string{img.ID, "cat", "/etc/passwd"}, t)
defer runtime.Destroy(container2)
if err := container2.Run(); err != nil {
@@ -196,7 +198,7 @@ func TestDiff(t *testing.T) {
}
// Create a new container
container3, _, _ := mkContainer(runtime, []string{"_", "rm", "/bin/httpd"}, t)
container3, _ := mkContainer(runtime, []string{"_", "rm", "/bin/httpd"}, t)
defer runtime.Destroy(container3)
if err := container3.Run(); err != nil {
@@ -222,7 +224,7 @@ func TestDiff(t *testing.T) {
func TestCommitAutoRun(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container1, _, _ := mkContainer(runtime, []string{"_", "/bin/sh", "-c", "echo hello > /world"}, t)
container1, _ := mkContainer(runtime, []string{"_", "/bin/sh", "-c", "echo hello > /world"}, t)
defer runtime.Destroy(container1)
if container1.State.Running {
@@ -245,7 +247,7 @@ func TestCommitAutoRun(t *testing.T) {
}
// FIXME: Make a TestCommit that stops here and check docker.root/layers/img.id/world
container2, hostConfig, _ := mkContainer(runtime, []string{img.ID}, t)
container2, _ := mkContainer(runtime, []string{img.ID}, t)
defer runtime.Destroy(container2)
stdout, err := container2.StdoutPipe()
if err != nil {
@@ -255,7 +257,7 @@ func TestCommitAutoRun(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if err := container2.Start(hostConfig); err != nil {
if err := container2.Start(); err != nil {
t.Fatal(err)
}
container2.Wait()
@@ -282,7 +284,7 @@ func TestCommitRun(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container1, hostConfig, _ := mkContainer(runtime, []string{"_", "/bin/sh", "-c", "echo hello > /world"}, t)
container1, _ := mkContainer(runtime, []string{"_", "/bin/sh", "-c", "echo hello > /world"}, t)
defer runtime.Destroy(container1)
if container1.State.Running {
@@ -305,7 +307,7 @@ func TestCommitRun(t *testing.T) {
}
// FIXME: Make a TestCommit that stops here and check docker.root/layers/img.id/world
container2, hostConfig, _ := mkContainer(runtime, []string{img.ID, "cat", "/world"}, t)
container2, _ := mkContainer(runtime, []string{img.ID, "cat", "/world"}, t)
defer runtime.Destroy(container2)
stdout, err := container2.StdoutPipe()
if err != nil {
@@ -315,7 +317,7 @@ func TestCommitRun(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if err := container2.Start(hostConfig); err != nil {
if err := container2.Start(); err != nil {
t.Fatal(err)
}
container2.Wait()
@@ -341,7 +343,7 @@ func TestCommitRun(t *testing.T) {
func TestStart(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, hostConfig, _ := mkContainer(runtime, []string{"-m", "33554432", "-c", "1000", "-i", "_", "/bin/cat"}, t)
container, _ := mkContainer(runtime, []string{"-m", "33554432", "-c", "1000", "-i", "_", "/bin/cat"}, t)
defer runtime.Destroy(container)
cStdin, err := container.StdinPipe()
@@ -349,7 +351,7 @@ func TestStart(t *testing.T) {
t.Fatal(err)
}
if err := container.Start(hostConfig); err != nil {
if err := container.Start(); err != nil {
t.Fatal(err)
}
@@ -359,7 +361,7 @@ func TestStart(t *testing.T) {
if !container.State.Running {
t.Errorf("Container should be running")
}
if err := container.Start(hostConfig); err == nil {
if err := container.Start(); err == nil {
t.Fatalf("A running container should be able to be started")
}
@@ -371,7 +373,7 @@ func TestStart(t *testing.T) {
func TestRun(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, _, _ := mkContainer(runtime, []string{"_", "ls", "-al"}, t)
container, _ := mkContainer(runtime, []string{"_", "ls", "-al"}, t)
defer runtime.Destroy(container)
if container.State.Running {
@@ -388,11 +390,12 @@ func TestRun(t *testing.T) {
func TestOutput(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"echo", "-n", "foobar"},
},
"",
)
if err != nil {
t.Fatal(err)
@@ -407,16 +410,39 @@ func TestOutput(t *testing.T) {
}
}
func TestContainerNetwork(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"ping", "-c", "1", "127.0.0.1"},
},
"",
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container)
if err := container.Run(); err != nil {
t.Fatal(err)
}
if container.State.ExitCode != 0 {
t.Errorf("Unexpected ping 127.0.0.1 exit code %d (expected 0)", container.State.ExitCode)
}
}
func TestKillDifferentUser(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"cat"},
OpenStdin: true,
User: "daemon",
},
"",
)
if err != nil {
t.Fatal(err)
@@ -427,7 +453,7 @@ func TestKillDifferentUser(t *testing.T) {
if container.State.Running {
t.Errorf("Container shouldn't be running")
}
if err := container.Start(&HostConfig{}); err != nil {
if err := container.Start(); err != nil {
t.Fatal(err)
}
@@ -471,12 +497,13 @@ func TestCreateVolume(t *testing.T) {
if err != nil {
t.Fatal(err)
}
c, err := runtime.Create(config)
c, _, err := runtime.Create(config, "")
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(c)
if err := c.Start(hc); err != nil {
c.hostConfig = hc
if err := c.Start(); err != nil {
t.Fatal(err)
}
c.WaitTimeout(500 * time.Millisecond)
@@ -486,10 +513,11 @@ func TestCreateVolume(t *testing.T) {
func TestKill(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"sleep", "2"},
},
"",
)
if err != nil {
t.Fatal(err)
@@ -499,8 +527,7 @@ func TestKill(t *testing.T) {
if container.State.Running {
t.Errorf("Container shouldn't be running")
}
hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
if err := container.Start(); err != nil {
t.Fatal(err)
}
@@ -530,10 +557,10 @@ func TestExitCode(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
trueContainer, err := runtime.Create(&Config{
trueContainer, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/true", ""},
})
}, "")
if err != nil {
t.Fatal(err)
}
@@ -545,10 +572,10 @@ func TestExitCode(t *testing.T) {
t.Errorf("Unexpected exit code %d (expected 0)", trueContainer.State.ExitCode)
}
falseContainer, err := runtime.Create(&Config{
falseContainer, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/false", ""},
})
}, "")
if err != nil {
t.Fatal(err)
}
@@ -564,10 +591,11 @@ func TestExitCode(t *testing.T) {
func TestRestart(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"echo", "-n", "foobar"},
},
"",
)
if err != nil {
t.Fatal(err)
@@ -594,12 +622,13 @@ func TestRestart(t *testing.T) {
func TestRestartStdin(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"cat"},
OpenStdin: true,
},
"",
)
if err != nil {
t.Fatal(err)
@@ -614,8 +643,7 @@ func TestRestartStdin(t *testing.T) {
if err != nil {
t.Fatal(err)
}
hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
if err := container.Start(); err != nil {
t.Fatal(err)
}
if _, err := io.WriteString(stdin, "hello world"); err != nil {
@@ -645,7 +673,7 @@ func TestRestartStdin(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if err := container.Start(hostConfig); err != nil {
if err := container.Start(); err != nil {
t.Fatal(err)
}
if _, err := io.WriteString(stdin, "hello world #2"); err != nil {
@@ -672,10 +700,11 @@ func TestUser(t *testing.T) {
defer nuke(runtime)
// Default user must be root
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"id"},
},
"",
)
if err != nil {
t.Fatal(err)
@@ -690,12 +719,13 @@ func TestUser(t *testing.T) {
}
// Set a username
container, err = runtime.Create(&Config{
container, _, err = runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"id"},
User: "root",
},
"",
)
if err != nil {
t.Fatal(err)
@@ -710,12 +740,13 @@ func TestUser(t *testing.T) {
}
// Set a UID
container, err = runtime.Create(&Config{
container, _, err = runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"id"},
User: "0",
},
"",
)
if err != nil || container.State.ExitCode != 0 {
t.Fatal(err)
@@ -730,12 +761,13 @@ func TestUser(t *testing.T) {
}
// Set a different user by uid
container, err = runtime.Create(&Config{
container, _, err = runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"id"},
User: "1",
},
"",
)
if err != nil {
t.Fatal(err)
@@ -752,12 +784,13 @@ func TestUser(t *testing.T) {
}
// Set a different user by username
container, err = runtime.Create(&Config{
container, _, err = runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"id"},
User: "daemon",
},
"",
)
if err != nil {
t.Fatal(err)
@@ -772,12 +805,13 @@ func TestUser(t *testing.T) {
}
// Test an wrong username
container, err = runtime.Create(&Config{
container, _, err = runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"id"},
User: "unknownuser",
},
"",
)
if err != nil {
t.Fatal(err)
@@ -793,20 +827,22 @@ func TestMultipleContainers(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container1, err := runtime.Create(&Config{
container1, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"sleep", "2"},
},
"",
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container1)
container2, err := runtime.Create(&Config{
container2, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"sleep", "2"},
},
"",
)
if err != nil {
t.Fatal(err)
@@ -814,11 +850,10 @@ func TestMultipleContainers(t *testing.T) {
defer runtime.Destroy(container2)
// Start both containers
hostConfig := &HostConfig{}
if err := container1.Start(hostConfig); err != nil {
if err := container1.Start(); err != nil {
t.Fatal(err)
}
if err := container2.Start(hostConfig); err != nil {
if err := container2.Start(); err != nil {
t.Fatal(err)
}
@@ -847,12 +882,13 @@ func TestMultipleContainers(t *testing.T) {
func TestStdin(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"cat"},
OpenStdin: true,
},
"",
)
if err != nil {
t.Fatal(err)
@@ -867,8 +903,7 @@ func TestStdin(t *testing.T) {
if err != nil {
t.Fatal(err)
}
hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
if err := container.Start(); err != nil {
t.Fatal(err)
}
defer stdin.Close()
@@ -892,12 +927,13 @@ func TestStdin(t *testing.T) {
func TestTty(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"cat"},
OpenStdin: true,
},
"",
)
if err != nil {
t.Fatal(err)
@@ -912,8 +948,7 @@ func TestTty(t *testing.T) {
if err != nil {
t.Fatal(err)
}
hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
if err := container.Start(); err != nil {
t.Fatal(err)
}
defer stdin.Close()
@@ -935,13 +970,15 @@ func TestTty(t *testing.T) {
}
func TestEnv(t *testing.T) {
os.Setenv("TRUE", "false")
os.Setenv("TRICKY", "tri\ncky\n")
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"env"},
},
)
config, _, _, err := ParseRun([]string{"-e=FALSE=true", "-e=TRUE", "-e=TRICKY", GetTestImage(runtime).ID, "env"}, nil)
if err != nil {
t.Fatal(err)
}
container, _, err := runtime.Create(config, "")
if err != nil {
t.Fatal(err)
}
@@ -952,8 +989,7 @@ func TestEnv(t *testing.T) {
t.Fatal(err)
}
defer stdout.Close()
hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
if err := container.Start(); err != nil {
t.Fatal(err)
}
container.Wait()
@@ -970,7 +1006,12 @@ func TestEnv(t *testing.T) {
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"HOME=/",
"container=lxc",
"HOSTNAME=" + container.ShortID(),
"HOSTNAME=" + utils.TruncateID(container.ID),
"FALSE=true",
"TRUE=false",
"TRICKY=tri",
"cky",
"",
}
sort.Strings(goodEnv)
if len(goodEnv) != len(actualEnv) {
@@ -986,12 +1027,13 @@ func TestEnv(t *testing.T) {
func TestEntrypoint(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Entrypoint: []string{"/bin/echo"},
Cmd: []string{"-n", "foobar"},
},
"",
)
if err != nil {
t.Fatal(err)
@@ -1009,11 +1051,12 @@ func TestEntrypoint(t *testing.T) {
func TestEntrypointNoCmd(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Entrypoint: []string{"/bin/echo", "foobar"},
},
"",
)
if err != nil {
t.Fatal(err)
@@ -1060,7 +1103,7 @@ func TestLXCConfig(t *testing.T) {
cpuMin := 100
cpuMax := 10000
cpu := cpuMin + rand.Intn(cpuMax-cpuMin)
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/true"},
@@ -1068,11 +1111,13 @@ func TestLXCConfig(t *testing.T) {
Memory: int64(mem),
CpuShares: int64(cpu),
},
"",
)
if err != nil {
t.Fatal(err)
}
container.generateLXCConfig(nil)
defer runtime.Destroy(container)
container.generateLXCConfig()
grepFile(t, container.lxcConfigPath(), "lxc.utsname = foobar")
grepFile(t, container.lxcConfigPath(),
fmt.Sprintf("lxc.cgroup.memory.limit_in_bytes = %d", mem))
@@ -1083,18 +1128,19 @@ func TestLXCConfig(t *testing.T) {
func TestCustomLxcConfig(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/true"},
Hostname: "foobar",
},
"",
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container)
hostConfig := &HostConfig{LxcConf: []KeyValuePair{
container.hostConfig = &HostConfig{LxcConf: []KeyValuePair{
{
Key: "lxc.utsname",
Value: "docker",
@@ -1105,7 +1151,7 @@ func TestCustomLxcConfig(t *testing.T) {
},
}}
container.generateLXCConfig(hostConfig)
container.generateLXCConfig()
grepFile(t, container.lxcConfigPath(), "lxc.utsname = docker")
grepFile(t, container.lxcConfigPath(), "lxc.cgroup.cpuset.cpus = 0,1")
}
@@ -1114,10 +1160,11 @@ func BenchmarkRunSequencial(b *testing.B) {
runtime := mkRuntime(b)
defer nuke(runtime)
for i := 0; i < b.N; i++ {
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"echo", "-n", "foo"},
},
"",
)
if err != nil {
b.Fatal(err)
@@ -1146,18 +1193,18 @@ func BenchmarkRunParallel(b *testing.B) {
complete := make(chan error)
tasks = append(tasks, complete)
go func(i int, complete chan error) {
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"echo", "-n", "foo"},
},
"",
)
if err != nil {
complete <- err
return
}
defer runtime.Destroy(container)
hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
if err := container.Start(); err != nil {
complete <- err
return
}
@@ -1201,7 +1248,7 @@ func TestCopyVolumeUidGid(t *testing.T) {
defer nuke(r)
// Add directory not owned by root
container1, _, _ := mkContainer(r, []string{"_", "/bin/sh", "-c", "mkdir -p /hello && touch /hello/test.txt && chown daemon.daemon /hello"}, t)
container1, _ := mkContainer(r, []string{"_", "/bin/sh", "-c", "mkdir -p /hello && touch /hello/test.txt && chown daemon.daemon /hello"}, t)
defer r.Destroy(container1)
if container1.State.Running {
@@ -1238,7 +1285,7 @@ func TestCopyVolumeContent(t *testing.T) {
defer nuke(r)
// Put some content in a directory of a container and commit it
container1, _, _ := mkContainer(r, []string{"_", "/bin/sh", "-c", "mkdir -p /hello/local && echo hello > /hello/local/world"}, t)
container1, _ := mkContainer(r, []string{"_", "/bin/sh", "-c", "mkdir -p /hello/local && echo hello > /hello/local/world"}, t)
defer r.Destroy(container1)
if container1.State.Running {
@@ -1292,16 +1339,17 @@ func TestBindMounts(t *testing.T) {
}
}
// Test that VolumesRW values are copied to the new container. Regression test for #1201
func TestVolumesFromReadonlyMount(t *testing.T) {
// Test that -volumes-from supports both read-only mounts
func TestFromVolumesInReadonlyMode(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/echo", "-n", "foobar"},
Volumes: map[string]struct{}{"/test": {}},
},
"",
)
if err != nil {
t.Fatal(err)
@@ -1315,12 +1363,74 @@ func TestVolumesFromReadonlyMount(t *testing.T) {
t.Fail()
}
container2, err := runtime.Create(
container2, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/echo", "-n", "foobar"},
VolumesFrom: container.ID + ":ro",
},
"",
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container2)
_, err = container2.Output()
if err != nil {
t.Fatal(err)
}
if container.Volumes["/test"] != container2.Volumes["/test"] {
t.Logf("container volumes do not match: %s | %s ",
container.Volumes["/test"],
container2.Volumes["/test"])
t.Fail()
}
_, exists := container2.VolumesRW["/test"]
if !exists {
t.Logf("container2 is missing '/test' volume: %s", container2.VolumesRW)
t.Fail()
}
if container2.VolumesRW["/test"] != false {
t.Log("'/test' volume mounted in read-write mode, expected read-only")
t.Fail()
}
}
// Test that VolumesRW values are copied to the new container. Regression test for #1201
func TestVolumesFromReadonlyMount(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/echo", "-n", "foobar"},
Volumes: map[string]struct{}{"/test": {}},
},
"",
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container)
_, err = container.Output()
if err != nil {
t.Fatal(err)
}
if !container.VolumesRW["/test"] {
t.Fail()
}
container2, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/echo", "-n", "foobar"},
VolumesFrom: container.ID,
},
"",
)
if err != nil {
t.Fatal(err)
@@ -1351,11 +1461,12 @@ func TestRestartWithVolumes(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"echo", "-n", "foobar"},
Volumes: map[string]struct{}{"/test": {}},
},
"",
)
if err != nil {
t.Fatal(err)
@@ -1394,11 +1505,12 @@ func TestVolumesFromWithVolumes(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"sh", "-c", "echo -n bar > /test/foo"},
Volumes: map[string]struct{}{"/test": {}},
},
"",
)
if err != nil {
t.Fatal(err)
@@ -1421,13 +1533,14 @@ func TestVolumesFromWithVolumes(t *testing.T) {
t.Fail()
}
container2, err := runtime.Create(
container2, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"cat", "/test/foo"},
VolumesFrom: container.ID,
Volumes: map[string]struct{}{"/test": {}},
},
"",
)
if err != nil {
t.Fatal(err)
@@ -1462,7 +1575,7 @@ func TestOnlyLoopbackExistsWhenUsingDisableNetworkOption(t *testing.T) {
if err != nil {
t.Fatal(err)
}
c, err := runtime.Create(config)
c, _, err := runtime.Create(config, "")
if err != nil {
t.Fatal(err)
}
@@ -1470,9 +1583,9 @@ func TestOnlyLoopbackExistsWhenUsingDisableNetworkOption(t *testing.T) {
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(c)
if err := c.Start(hc); err != nil {
c.hostConfig = hc
if err := c.Start(); err != nil {
t.Fatal(err)
}
c.WaitTimeout(500 * time.Millisecond)
@@ -1528,11 +1641,12 @@ func TestMultipleVolumesFrom(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := runtime.Create(&Config{
container, _, err := runtime.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"sh", "-c", "echo -n bar > /test/foo"},
Volumes: map[string]struct{}{"/test": {}},
},
"",
)
if err != nil {
t.Fatal(err)
@@ -1555,12 +1669,13 @@ func TestMultipleVolumesFrom(t *testing.T) {
t.Fail()
}
container2, err := runtime.Create(
container2, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"sh", "-c", "echo -n bar > /other/foo"},
Volumes: map[string]struct{}{"/other": {}},
},
"",
)
if err != nil {
t.Fatal(err)
@@ -1576,12 +1691,12 @@ func TestMultipleVolumesFrom(t *testing.T) {
t.Fatal(err)
}
container3, err := runtime.Create(
container3, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/echo", "-n", "foobar"},
VolumesFrom: strings.Join([]string{container.ID, container2.ID}, ","),
})
}, "")
if err != nil {
t.Fatal(err)
@@ -1592,7 +1707,6 @@ func TestMultipleVolumesFrom(t *testing.T) {
t.Fatal(err)
}
t.Log(container3.Volumes)
if container3.Volumes["/test"] != container.Volumes["/test"] {
t.Fail()
}
@@ -1600,3 +1714,95 @@ func TestMultipleVolumesFrom(t *testing.T) {
t.Fail()
}
}
func TestRestartGhost(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, _, err := runtime.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"sh", "-c", "echo -n bar > /test/foo"},
Volumes: map[string]struct{}{"/test": {}},
},
"",
)
if err != nil {
t.Fatal(err)
}
if err := container.Kill(); err != nil {
t.Fatal(err)
}
container.State.Ghost = true
_, err = container.Output()
if err != nil {
t.Fatal(err)
}
}
func TestRemoveFile(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container1, _ := mkContainer(runtime, []string{"_", "/bin/sh", "-c", "touch test.txt"}, t)
defer runtime.Destroy(container1)
if container1.State.Running {
t.Errorf("Container shouldn't be running")
}
if err := container1.Run(); err != nil {
t.Fatal(err)
}
if container1.State.Running {
t.Errorf("Container shouldn't be running")
}
commit := func(container *Container) (*Image, error) {
rwTar, err := container.ExportRw()
if err != nil {
return nil, err
}
img, err := runtime.graph.Create(rwTar, container, "unit test commited image", "", nil)
if err != nil {
return nil, err
}
return img, nil
}
img, err := commit(container1)
if err != nil {
t.Fatal(err)
}
container2, _ := mkContainer(runtime, []string{img.ID, "/bin/sh", "-c", "rm /test.txt"}, t)
defer runtime.Destroy(container2)
if err := container2.Run(); err != nil {
t.Fatal(err)
}
containerMount, err := runtime.driver.Get(container2.ID)
if err != nil {
t.Fatal(err)
}
if _, err := os.Stat(path.Join(containerMount, "test.txt")); err == nil {
t.Fatalf("test.txt should not exist")
}
img, err = commit(container2)
if err != nil {
t.Fatal(err)
}
mountPoint, err := runtime.driver.Get(img.ID)
if err != nil {
t.Fatal(err)
}
file := path.Join(mountPoint, "test.txt")
if _, err := os.Stat(file); err == nil {
t.Fatalf("The file %s should not exist\n", file)
}
}
-1
View File
@@ -1 +0,0 @@
*.pyc
-78
View File
@@ -1,78 +0,0 @@
# docker-brew
docker-brew is a command-line tool used to build the docker standard library.
## Install instructions
1. Install python if it isn't already available on your OS of choice
1. Install the easy_install tool (`sudo apt-get install python-setuptools`
for Debian)
1. Install the python package manager, `pip` (`easy_install pip`)
1. Run the following command: `sudo pip install -r requirements.txt`
1. You should now be able to use the `docker-brew` script as such.
## Basics
./docker-brew -h
Display usage and help.
./docker-brew
Default build from the default repo/branch. Images will be created under the
`library/` namespace. Does not perform a remote push.
./docker-brew -n mycorp.com -b stable --push git://github.com/mycorp/docker
Will fetch the library definition files in the `stable` branch of the
`git://github.com/mycorp/docker` repository and create images under the
`mycorp.com` namespace (e.g. `mycorp.com/ubuntu`). Created images will then
be pushed to the official docker repository (pending: support for private
repositories)
## Library definition files
The library definition files are plain text files found in the `library/`
subfolder of the docker repository.
### File names
The name of a definition file will determine the name of the image(s) it
creates. For example, the `library/ubuntu` file will create images in the
`<namespace>/ubuntu` repository. If multiple instructions are present in
a single file, all images are expected to be created under a different tag.
### Instruction format
Each line represents a build instruction.
There are different formats that `docker-brew` is able to parse.
<git-url>
git://github.com/dotcloud/hipache
https://github.com/dotcloud/docker.git
The simplest format. `docker-brew` will fetch data from the provided git
repository from the `HEAD`of its `master` branch. Generated image will be
tagged as `latest`. Use of this format is discouraged because there is no
way to ensure stability.
<docker-tag> <git-url>
bleeding-edge git://github.com/dotcloud/docker
unstable https://github.com/dotcloud/docker-redis.git
A more advanced format. `docker-brew` will fetch data from the provided git
repository from the `HEAD`of its `master` branch. Generated image will be
tagged as `<docker-tag>`. Recommended if we always want to provide a snapshot
of the latest development. Again, no way to ensure stability.
<docker-tag> <git-url> T:<git-tag>
2.4.0 git://github.com/dotcloud/docker-redis T:2.4.0
<docker-tag> <git-url> B:<git-branch>
zfs git://github.com/dotcloud/docker B:zfs-support
<docker-tag> <git-url> C:<git-commit-id>
2.2.0 https://github.com/dotcloud/docker-redis.git C:a4bf8923ee4ec566d3ddc212
The most complete format. `docker-brew` will fetch data from the provided git
repository from the provided reference (if it's a branch, brew will fetch its
`HEAD`). Generated image will be tagged as `<docker-tag>`. Recommended whenever
possible.
-1
View File
@@ -1 +0,0 @@
from brew import build_library, DEFAULT_REPOSITORY, DEFAULT_BRANCH
-185
View File
@@ -1,185 +0,0 @@
import os
import logging
from shutil import rmtree
import docker
import git
DEFAULT_REPOSITORY = 'git://github.com/dotcloud/docker'
DEFAULT_BRANCH = 'master'
logger = logging.getLogger(__name__)
logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
level='INFO')
client = docker.Client()
processed = {}
processed_folders = []
def build_library(repository=None, branch=None, namespace=None, push=False,
debug=False, prefill=True, registry=None):
dst_folder = None
summary = Summary()
if repository is None:
repository = DEFAULT_REPOSITORY
if branch is None:
branch = DEFAULT_BRANCH
if debug:
logger.setLevel('DEBUG')
if not (repository.startswith('https://') or repository.startswith('git://')):
logger.info('Repository provided assumed to be a local path')
dst_folder = repository
try:
client.version()
except Exception as e:
logger.error('Could not reach the docker daemon. Please make sure it '
'is running.')
logger.warning('Also make sure you have access to the docker UNIX '
'socket (use sudo)')
return
#FIXME: set destination folder and only pull latest changes instead of
# cloning the whole repo everytime
if not dst_folder:
logger.info('Cloning docker repo from {0}, branch: {1}'.format(
repository, branch))
try:
rep, dst_folder = git.clone_branch(repository, branch)
except Exception as e:
logger.exception(e)
logger.error('Source repository could not be fetched. Check '
'that the address is correct and the branch exists.')
return
try:
dirlist = os.listdir(os.path.join(dst_folder, 'library'))
except OSError as e:
logger.error('The path provided ({0}) could not be found or didn\'t'
'contain a library/ folder.'.format(dst_folder))
return
for buildfile in dirlist:
if buildfile == 'MAINTAINERS':
continue
f = open(os.path.join(dst_folder, 'library', buildfile))
linecnt = 0
for line in f:
linecnt = linecnt + 1
logger.debug('{0} ---> {1}'.format(buildfile, line))
args = line.split()
try:
if len(args) > 3:
raise RuntimeError('Incorrect line format, '
'please refer to the docs')
url = None
ref = 'refs/heads/master'
tag = None
if len(args) == 1: # Just a URL, simple mode
url = args[0]
elif len(args) == 2 or len(args) == 3: # docker-tag url
url = args[1]
tag = args[0]
if len(args) == 3: # docker-tag url B:branch or T:tag
ref = None
if args[2].startswith('B:'):
ref = 'refs/heads/' + args[2][2:]
elif args[2].startswith('T:'):
ref = 'refs/tags/' + args[2][2:]
elif args[2].startswith('C:'):
ref = args[2][2:]
else:
raise RuntimeError('Incorrect line format, '
'please refer to the docs')
if prefill:
logger.debug('Pulling {0} from official repository (cache '
'fill)'.format(buildfile))
client.pull(buildfile)
img = build_repo(url, ref, buildfile, tag, namespace, push,
registry)
summary.add_success(buildfile, (linecnt, line), img)
processed['{0}@{1}'.format(url, ref)] = img
except Exception as e:
logger.exception(e)
summary.add_exception(buildfile, (linecnt, line), e)
f.close()
if dst_folder != repository:
rmtree(dst_folder, True)
for d in processed_folders:
rmtree(d, True)
summary.print_summary(logger)
def build_repo(repository, ref, docker_repo, docker_tag, namespace, push, registry):
docker_repo = '{0}/{1}'.format(namespace or 'library', docker_repo)
img_id = None
dst_folder = None
if '{0}@{1}'.format(repository, ref) not in processed.keys():
logger.info('Cloning {0} (ref: {1})'.format(repository, ref))
if repository not in processed:
rep, dst_folder = git.clone(repository, ref)
processed[repository] = rep
processed_folders.append(dst_folder)
else:
dst_folder = git.checkout(processed[repository], ref)
if not 'Dockerfile' in os.listdir(dst_folder):
raise RuntimeError('Dockerfile not found in cloned repository')
logger.info('Building using dockerfile...')
img_id, logs = client.build(path=dst_folder, quiet=True)
else:
img_id = processed['{0}@{1}'.format(repository, ref)]
logger.info('Committing to {0}:{1}'.format(docker_repo,
docker_tag or 'latest'))
client.tag(img_id, docker_repo, docker_tag)
if push:
logger.info('Pushing result to registry {0}'.format(
registry or "default"))
if registry is not None:
docker_repo = '{0}/{1}'.format(registry, docker_repo)
logger.info('Also tagging {0}'.format(docker_repo))
client.tag(img_id, docker_repo, docker_tag)
client.push(docker_repo)
return img_id
class Summary(object):
def __init__(self):
self._summary = {}
self._has_exc = False
def _add_data(self, image, linestr, data):
if image not in self._summary:
self._summary[image] = { linestr: data }
else:
self._summary[image][linestr] = data
def add_exception(self, image, line, exc):
lineno, linestr = line
self._add_data(image, linestr, { 'line': lineno, 'exc': str(exc) })
self._has_exc = True
def add_success(self, image, line, img_id):
lineno, linestr = line
self._add_data(image, linestr, { 'line': lineno, 'id': img_id })
def print_summary(self, logger=None):
linesep = ''.center(61, '-') + '\n'
s = 'BREW BUILD SUMMARY\n' + linesep
success = 'OVERALL SUCCESS: {}\n'.format(not self._has_exc)
details = linesep
for image, lines in self._summary.iteritems():
details = details + '{}\n{}'.format(image, linesep)
for linestr, data in lines.iteritems():
details = details + '{0:2} | {1} | {2:50}\n'.format(
data['line'],
'KO' if 'exc' in data else 'OK',
data['exc'] if 'exc' in data else data['id']
)
details = details + linesep
if logger:
logger.info(s + success + details)
else:
print s, success, details
-63
View File
@@ -1,63 +0,0 @@
import tempfile
import logging
from dulwich import index
from dulwich.client import get_transport_and_path
from dulwich.repo import Repo
logger = logging.getLogger(__name__)
def clone_branch(repo_url, branch="master", folder=None):
return clone(repo_url, 'refs/heads/' + branch, folder)
def clone_tag(repo_url, tag, folder=None):
return clone(repo_url, 'refs/tags/' + tag, folder)
def checkout(rep, ref=None):
is_commit = False
if ref is None:
ref = 'refs/heads/master'
elif not ref.startswith('refs/'):
is_commit = True
if is_commit:
rep['HEAD'] = rep.commit(ref)
else:
rep['HEAD'] = rep.refs[ref]
indexfile = rep.index_path()
tree = rep["HEAD"].tree
index.build_index_from_tree(rep.path, indexfile, rep.object_store, tree)
return rep.path
def clone(repo_url, ref=None, folder=None):
is_commit = False
if ref is None:
ref = 'refs/heads/master'
elif not ref.startswith('refs/'):
is_commit = True
logger.debug("clone repo_url={0}, ref={1}".format(repo_url, ref))
if folder is None:
folder = tempfile.mkdtemp()
logger.debug("folder = {0}".format(folder))
rep = Repo.init(folder)
client, relative_path = get_transport_and_path(repo_url)
logger.debug("client={0}".format(client))
remote_refs = client.fetch(relative_path, rep)
for k, v in remote_refs.iteritems():
try:
rep.refs.add_if_new(k, v)
except:
pass
if is_commit:
rep['HEAD'] = rep.commit(ref)
else:
rep['HEAD'] = remote_refs[ref]
indexfile = rep.index_path()
tree = rep["HEAD"].tree
index.build_index_from_tree(rep.path, indexfile, rep.object_store, tree)
logger.debug("done")
return rep, folder
-35
View File
@@ -1,35 +0,0 @@
#!/usr/bin/env python
import argparse
import sys
try:
import brew
except ImportError as e:
print str(e)
print 'Please install the required dependencies first'
print 'sudo pip install -r requirements.txt'
sys.exit(1)
if __name__ == '__main__':
parser = argparse.ArgumentParser('Build the docker standard library')
parser.add_argument('--push', action='store_true', default=False,
help='Push generated repositories')
parser.add_argument('--debug', default=False, action='store_true',
help='Enable debugging output')
parser.add_argument('--noprefill', default=True, action='store_false',
dest='prefill', help='Disable cache prefill')
parser.add_argument('-n', metavar='NAMESPACE', default='library',
help='Namespace used for generated repositories.'
' Default is library')
parser.add_argument('-b', metavar='BRANCH', default=brew.DEFAULT_BRANCH,
help='Branch in the repository where the library definition'
' files will be fetched. Default is ' + brew.DEFAULT_BRANCH)
parser.add_argument('repository', default=brew.DEFAULT_REPOSITORY,
nargs='?', help='git repository containing the library definition'
' files. Default is ' + brew.DEFAULT_REPOSITORY)
parser.add_argument('--reg', default=None, help='Registry address to'
' push build results to. Also sets push to true.')
args = parser.parse_args()
brew.build_library(args.repository, args.b, args.n,
args.push or args.reg is not None, args.debug, args.prefill, args.reg)
-2
View File
@@ -1,2 +0,0 @@
dulwich==0.9.0
-e git://github.com/dotcloud/docker-py.git#egg=docker-py
-22
View File
@@ -1,22 +0,0 @@
#!/usr/bin/env python
import os
from setuptools import setup
ROOT_DIR = os.path.dirname(__file__)
SOURCE_DIR = os.path.join(ROOT_DIR)
test_requirements = []
setup(
name="docker-brew",
version='0.0.1',
description="-",
packages=['dockerbrew'],
install_requires=['dulwich', 'docker'] + test_requirements,
zip_safe=False,
classifiers=['Development Status :: 3 - Alpha',
'Environment :: Other Environment',
'Intended Audience :: Developers',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Topic :: Utilities'],
)
+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"]
+27
View File
@@ -0,0 +1,27 @@
#
# This Dockerfile will create an image that allows to generate upstart and
# systemd scripts (more to come)
#
# docker-version 0.6.2
#
FROM ubuntu:12.10
MAINTAINER Guillaume J. Charmes <guillaume@dotcloud.com>
RUN apt-get update && apt-get install -y wget git mercurial
# Install Go
RUN wget --no-check-certificate https://go.googlecode.com/files/go1.1.2.linux-amd64.tar.gz -O go-1.1.2.tar.gz
RUN tar -xzvf go-1.1.2.tar.gz && mv /go /goroot
RUN mkdir /go
ENV GOROOT /goroot
ENV GOPATH /go
ENV PATH $GOROOT/bin:$PATH
RUN go get github.com/dotcloud/docker && cd /go/src/github.com/dotcloud/docker && git checkout v0.6.3
ADD manager.go /manager/
RUN cd /manager && go build -o /usr/bin/manager
ENTRYPOINT ["/usr/bin/manager"]
+4
View File
@@ -0,0 +1,4 @@
FROM busybox
MAINTAINER Guillaume J. Charmes <guillaume@dotcloud.com>
ADD manager /usr/bin/
ENTRYPOINT ["/usr/bin/manager"]
+130
View File
@@ -0,0 +1,130 @@
package main
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"github.com/dotcloud/docker"
"os"
"strings"
"text/template"
)
var templates = map[string]string{
"upstart": `description "{{.description}}"
author "{{.author}}"
start on filesystem and started lxc-net and started docker
stop on runlevel [!2345]
respawn
exec /home/vagrant/goroot/bin/docker start -a {{.container_id}}
`,
"systemd": `[Unit]
Description={{.description}}
Author={{.author}}
After=docker.service
[Service]
Restart=always
ExecStart=/usr/bin/docker start -a {{.container_id}}
ExecStop=/usr/bin/docker stop -t 2 {{.container_id}}
[Install]
WantedBy=local.target
`,
}
func main() {
// Parse command line for custom options
kind := flag.String("t", "upstart", "Type of manager requested")
author := flag.String("a", "<none>", "Author of the image")
description := flag.String("d", "<none>", "Description of the image")
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "\nUsage: manager <container id>\n\n")
flag.PrintDefaults()
}
flag.Parse()
// We require at least the container ID
if flag.NArg() != 1 {
println(flag.NArg())
flag.Usage()
return
}
// Check that the requested process manager is supported
if _, exists := templates[*kind]; !exists {
panic("Unkown script template")
}
// Load the requested template
tpl, err := template.New("processManager").Parse(templates[*kind])
if err != nil {
panic(err)
}
// Create stdout/stderr buffers
bufOut := bytes.NewBuffer(nil)
bufErr := bytes.NewBuffer(nil)
// Instanciate the Docker CLI
cli := docker.NewDockerCli(nil, bufOut, bufErr, "unix", "/var/run/docker.sock")
// Retrieve the container info
if err := cli.CmdInspect(flag.Arg(0)); err != nil {
// As of docker v0.6.3, CmdInspect always returns nil
panic(err)
}
// If there is nothing in the error buffer, then the Docker daemon is there and the container has been found
if bufErr.Len() == 0 {
// Unmarshall the resulting container data
c := []*docker.Container{{}}
if err := json.Unmarshal(bufOut.Bytes(), &c); err != nil {
panic(err)
}
// Reset the buffers
bufOut.Reset()
bufErr.Reset()
// Retrieve the info of the linked image
if err := cli.CmdInspect(c[0].Image); err != nil {
panic(err)
}
// If there is nothing in the error buffer, then the image has been found.
if bufErr.Len() == 0 {
// Unmarshall the resulting image data
img := []*docker.Image{{}}
if err := json.Unmarshal(bufOut.Bytes(), &img); err != nil {
panic(err)
}
// If no author has been set, use the one from the image
if *author == "<none>" && img[0].Author != "" {
*author = strings.Replace(img[0].Author, "\"", "", -1)
}
// If no description has been set, use the comment from the image
if *description == "<none>" && img[0].Comment != "" {
*description = strings.Replace(img[0].Comment, "\"", "", -1)
}
}
}
/// Old version: Wrtie the resulting script to file
// f, err := os.OpenFile(kind, os.O_CREATE|os.O_WRONLY, 0755)
// if err != nil {
// panic(err)
// }
// defer f.Close()
// Create a map with needed data
data := map[string]string{
"author": *author,
"description": *description,
"container_id": flag.Arg(0),
}
// Process the template and output it on Stdout
if err := tpl.Execute(os.Stdout, data); err != nil {
panic(err)
}
}
+53
View File
@@ -0,0 +1,53 @@
#!/bin/sh
set -e
usage() {
echo >&2 "usage: $0 [-a author] [-d description] container [manager]"
echo >&2 " ie: $0 -a 'John Smith' 4ec9612a37cd systemd"
echo >&2 " ie: $0 -d 'Super Cool System' 4ec9612a37cd # defaults to upstart"
exit 1
}
auth='<none>'
desc='<none>'
have_auth=
have_desc=
while getopts a:d: opt; do
case "$opt" in
a)
auth="$OPTARG"
have_auth=1
;;
d)
desc="$OPTARG"
have_desc=1
;;
esac
done
shift $(($OPTIND - 1))
[ $# -ge 1 -a $# -le 2 ] || usage
cid="$1"
script="${2:-upstart}"
if [ ! -e "manager/$script" ]; then
echo >&2 "Error: manager type '$script' is unknown (PRs always welcome!)."
echo >&2 'The currently supported types are:'
echo >&2 " $(cd manager && echo *)"
exit 1
fi
# TODO https://github.com/dotcloud/docker/issues/734 (docker inspect formatting)
#if command -v docker > /dev/null 2>&1; then
# image="$(docker inspect -f '{{.Image}}' "$cid")"
# if [ "$image" ]; then
# if [ -z "$have_auth" ]; then
# auth="$(docker inspect -f '{{.Author}}' "$image")"
# fi
# if [ -z "$have_desc" ]; then
# desc="$(docker inspect -f '{{.Comment}}' "$image")"
# fi
# fi
#fi
exec "manager/$script" "$cid" "$auth" "$desc"
+20
View File
@@ -0,0 +1,20 @@
#!/bin/sh
set -e
cid="$1"
auth="$2"
desc="$3"
cat <<-EOF
[Unit]
Description=$desc
Author=$auth
After=docker.service
[Service]
ExecStart=/usr/bin/docker start -a $cid
ExecStop=/usr/bin/docker stop -t 2 $cid
[Install]
WantedBy=local.target
EOF
+15
View File
@@ -0,0 +1,15 @@
#!/bin/sh
set -e
cid="$1"
auth="$2"
desc="$3"
cat <<-EOF
description "$(echo "$desc" | sed 's/"/\\"/g')"
author "$(echo "$auth" | sed 's/"/\\"/g')"
start on filesystem and started lxc-net and started docker
stop on runlevel [!2345]
respawn
exec /usr/bin/docker start -a "$cid"
EOF
+13
View File
@@ -0,0 +1,13 @@
# /etc/conf.d/docker: config file for /etc/init.d/docker
# where the docker daemon output gets piped
#DOCKER_LOGFILE="/var/log/docker.log"
# where docker's pid get stored
#DOCKER_PIDFILE="/run/docker.pid"
# where the docker daemon itself is run from
#DOCKER_BINARY="/usr/bin/docker"
# any other random options you want to pass to docker
DOCKER_OPTS=""
+31
View File
@@ -0,0 +1,31 @@
#!/sbin/runscript
# Copyright 1999-2013 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: $
DOCKER_LOGFILE=${DOCKER_LOGFILE:-/var/log/${SVCNAME}.log}
DOCKER_PIDFILE=${DOCKER_PIDFILE:-/run/${SVCNAME}.pid}
DOCKER_BINARY=${DOCKER_BINARY:-/usr/bin/docker}
DOCKER_OPTS=${DOCKER_OPTS:-}
start() {
checkpath -f -m 0644 -o root:docker "$DOCKER_LOGFILE"
ebegin "Starting docker daemon"
start-stop-daemon --start --background \
--exec "$DOCKER_BINARY" \
--pidfile "$DOCKER_PIDFILE" \
--stdout "$DOCKER_LOGFILE" \
--stderr "$DOCKER_LOGFILE" \
-- -d -p "$DOCKER_PIDFILE" \
$DOCKER_OPTS
eend $?
}
stop() {
ebegin "Stopping docker daemon"
start-stop-daemon --stop \
--exec "$DOCKER_BINARY" \
--pidfile "$DOCKER_PIDFILE"
eend $?
}
+13
View File
@@ -0,0 +1,13 @@
[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.io
Requires=network.target
After=multi-user.target
[Service]
Type=simple
ExecStartPre=/bin/mount --make-rprivate /
ExecStart=/usr/bin/docker -d
[Install]
WantedBy=multi-user.target
+96
View File
@@ -0,0 +1,96 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: docker
# Required-Start: $syslog $remote_fs
# Required-Stop: $syslog $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# 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
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
# Get lsb functions
. /lib/lsb/init-functions
if [ -f /etc/default/$BASE ]; then
. /etc/default/$BASE
fi
# 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 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)
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 \
--exec "$DOCKER" \
--pidfile "$DOCKER_PIDFILE" \
-- -d -p "$DOCKER_PIDFILE" \
$DOCKER_OPTS
log_end_msg $?
;;
stop)
fail_unless_root
log_begin_msg "Stopping Docker: $BASE"
start-stop-daemon --stop \
--pidfile "$DOCKER_PIDFILE"
log_end_msg $?
;;
restart)
fail_unless_root
docker_pid=`cat "$DOCKER_PIDFILE" 2>/dev/null`
[ -n "$docker_pid" ] \
&& ps -p $docker_pid > /dev/null 2>&1 \
&& $0 stop
$0 start
;;
force-reload)
fail_unless_root
$0 restart
;;
status)
status_of_proc -p "$DOCKER_PIDFILE" "$DOCKER" docker
;;
*)
echo "Usage: $0 {start|stop|restart|status}"
exit 1
;;
esac
exit 0
+15
View File
@@ -0,0 +1,15 @@
description "Docker daemon"
start on filesystem and started lxc-net
stop on runlevel [!2345]
respawn
script
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
+1 -1
View File
@@ -62,6 +62,6 @@ mknod -m 666 ${DEV}/full c 1 7
mknod -m 600 ${DEV}/initctl p
mknod -m 666 ${DEV}/ptmx c 5 2
tar -C $ROOTFS -c . | docker import - archlinux
tar --numeric-owner -C $ROOTFS -c . | docker import - archlinux
docker run -i -t archlinux echo Success.
rm -rf $ROOTFS
+1 -1
View File
@@ -35,5 +35,5 @@ do
cp -a /dev/$X dev
done
tar -cf- . | docker import - busybox
tar --numeric-owner -cf- . | docker import - busybox
docker run -i -u root busybox /bin/echo Success.
-83
View File
@@ -1,83 +0,0 @@
#!/bin/bash
set -e
# these should match the names found at http://www.debian.org/releases/
stableSuite='wheezy'
testingSuite='jessie'
unstableSuite='sid'
variant='minbase'
include='iproute,iputils-ping'
repo="$1"
suite="$2"
mirror="${3:-}" # stick to the default debootstrap mirror if one is not provided
if [ ! "$repo" ] || [ ! "$suite" ]; then
echo >&2 "usage: $0 repo suite [mirror]"
echo >&2
echo >&2 " ie: $0 tianon/debian squeeze"
echo >&2 " $0 tianon/debian squeeze http://ftp.uk.debian.org/debian/"
echo >&2
echo >&2 " ie: $0 tianon/ubuntu precise"
echo >&2 " $0 tianon/ubuntu precise http://mirrors.melbourne.co.uk/ubuntu/"
echo >&2
exit 1
fi
target="/tmp/docker-rootfs-debian-$suite-$$-$RANDOM"
cd "$(dirname "$(readlink -f "$BASH_SOURCE")")"
returnTo="$(pwd -P)"
set -x
# bootstrap
mkdir -p "$target"
sudo debootstrap --verbose --variant="$variant" --include="$include" "$suite" "$target" "$mirror"
cd "$target"
# prevent init scripts from running during install/update
# policy-rc.d (for most scripts)
echo $'#!/bin/sh\nexit 101' | sudo tee usr/sbin/policy-rc.d > /dev/null
sudo chmod +x usr/sbin/policy-rc.d
# initctl (for some pesky upstart scripts)
sudo chroot . dpkg-divert --local --rename --add /sbin/initctl
sudo ln -sf /bin/true sbin/initctl
# see https://github.com/dotcloud/docker/issues/446#issuecomment-16953173
# shrink the image, since apt makes us fat (wheezy: ~157.5MB vs ~120MB)
sudo chroot . apt-get clean
# while we're at it, apt is unnecessarily slow inside containers
# this forces dpkg not to call sync() after package extraction and speeds up install
# the benefit is huge on spinning disks, and the penalty is nonexistent on SSD or decent server virtualization
echo 'force-unsafe-io' | sudo tee etc/dpkg/dpkg.cfg.d/02apt-speedup > /dev/null
# we want to effectively run "apt-get clean" after every install to keep images small
echo 'DPkg::Post-Invoke {"/bin/rm -f /var/cache/apt/archives/*.deb || true";};' | sudo tee etc/apt/apt.conf.d/no-cache > /dev/null
# helpful undo lines for each the above tweaks (for lack of a better home to keep track of them):
# rm /usr/sbin/policy-rc.d
# rm /sbin/initctl; dpkg-divert --rename --remove /sbin/initctl
# rm /etc/dpkg/dpkg.cfg.d/02apt-speedup
# rm /etc/apt/apt.conf.d/no-cache
# create the image (and tag $repo:$suite)
sudo tar -c . | docker import - $repo $suite
# test the image
docker run -i -t $repo:$suite echo success
if [ "$suite" = "$stableSuite" -o "$suite" = 'stable' ]; then
# tag latest
docker tag $repo:$suite $repo latest
# tag the specific debian release version
ver=$(docker run $repo:$suite cat /etc/debian_version)
docker tag $repo:$suite $repo $ver
fi
# cleanup
cd "$returnTo"
sudo rm -rf "$target"
+233
View File
@@ -0,0 +1,233 @@
#!/bin/bash
set -e
variant='minbase'
include='iproute,iputils-ping'
arch='amd64' # intentionally undocumented for now
skipDetection=
strictDebootstrap=
justTar=
usage() {
echo >&2
echo >&2 "usage: $0 [options] repo suite [mirror]"
echo >&2
echo >&2 'options: (not recommended)'
echo >&2 " -p set an http_proxy for debootstrap"
echo >&2 " -v $variant # change default debootstrap variant"
echo >&2 " -i $include # change default package includes"
echo >&2 " -d # strict debootstrap (do not apply any docker-specific tweaks)"
echo >&2 " -s # skip version detection and tagging (ie, precise also tagged as 12.04)"
echo >&2 " # note that this will also skip adding universe and/or security/updates to sources.list"
echo >&2 " -t # just create a tarball, especially for dockerbrew (uses repo as tarball name)"
echo >&2
echo >&2 " ie: $0 username/debian squeeze"
echo >&2 " $0 username/debian squeeze http://ftp.uk.debian.org/debian/"
echo >&2
echo >&2 " ie: $0 username/ubuntu precise"
echo >&2 " $0 username/ubuntu precise http://mirrors.melbourne.co.uk/ubuntu/"
echo >&2
echo >&2 " ie: $0 -t precise.tar.bz2 precise"
echo >&2 " $0 -t wheezy.tgz wheezy"
echo >&2 " $0 -t wheezy-uk.tar.xz wheezy http://ftp.uk.debian.org/debian/"
echo >&2
}
# these should match the names found at http://www.debian.org/releases/
debianStable=wheezy
debianUnstable=sid
# this should match the name found at http://releases.ubuntu.com/
ubuntuLatestLTS=precise
while getopts v:i:a:p:dst name; do
case "$name" in
p)
http_proxy="$OPTARG"
;;
v)
variant="$OPTARG"
;;
i)
include="$OPTARG"
;;
a)
arch="$OPTARG"
;;
d)
strictDebootstrap=1
;;
s)
skipDetection=1
;;
t)
justTar=1
;;
?)
usage
exit 0
;;
esac
done
shift $(($OPTIND - 1))
repo="$1"
suite="$2"
mirror="${3:-}" # stick to the default debootstrap mirror if one is not provided
if [ ! "$repo" ] || [ ! "$suite" ]; then
usage
exit 1
fi
# some rudimentary detection for whether we need to "sudo" our docker calls
docker=''
if docker version > /dev/null 2>&1; then
docker='docker'
elif sudo docker version > /dev/null 2>&1; then
docker='sudo docker'
elif command -v docker > /dev/null 2>&1; then
docker='docker'
else
echo >&2 "warning: either docker isn't installed, or your current user cannot run it;"
echo >&2 " this script is not likely to work as expected"
sleep 3
docker='docker' # give us a command-not-found later
fi
# make sure we have an absolute path to our final tarball so we can still reference it properly after we change directory
if [ "$justTar" ]; then
if [ ! -d "$(dirname "$repo")" ]; then
echo >&2 "error: $(dirname "$repo") does not exist"
exit 1
fi
repo="$(cd "$(dirname "$repo")" && pwd -P)/$(basename "$repo")"
fi
# will be filled in later, if [ -z "$skipDetection" ]
lsbDist=''
target="/tmp/docker-rootfs-debootstrap-$suite-$$-$RANDOM"
cd "$(dirname "$(readlink -f "$BASH_SOURCE")")"
returnTo="$(pwd -P)"
set -x
# bootstrap
mkdir -p "$target"
sudo http_proxy=$http_proxy debootstrap --verbose --variant="$variant" --include="$include" --arch="$arch" "$suite" "$target" "$mirror"
cd "$target"
if [ -z "$strictDebootstrap" ]; then
# prevent init scripts from running during install/update
# policy-rc.d (for most scripts)
echo $'#!/bin/sh\nexit 101' | sudo tee usr/sbin/policy-rc.d > /dev/null
sudo chmod +x usr/sbin/policy-rc.d
# initctl (for some pesky upstart scripts)
sudo chroot . dpkg-divert --local --rename --add /sbin/initctl
sudo ln -sf /bin/true sbin/initctl
# see https://github.com/dotcloud/docker/issues/446#issuecomment-16953173
# shrink the image, since apt makes us fat (wheezy: ~157.5MB vs ~120MB)
sudo chroot . apt-get clean
# while we're at it, apt is unnecessarily slow inside containers
# this forces dpkg not to call sync() after package extraction and speeds up install
# the benefit is huge on spinning disks, and the penalty is nonexistent on SSD or decent server virtualization
echo 'force-unsafe-io' | sudo tee etc/dpkg/dpkg.cfg.d/02apt-speedup > /dev/null
# we want to effectively run "apt-get clean" after every install to keep images small
echo 'DPkg::Post-Invoke {"/bin/rm -f /var/cache/apt/archives/*.deb || true";};' | sudo tee etc/apt/apt.conf.d/no-cache > /dev/null
# helpful undo lines for each the above tweaks (for lack of a better home to keep track of them):
# rm /usr/sbin/policy-rc.d
# rm /sbin/initctl; dpkg-divert --rename --remove /sbin/initctl
# rm /etc/dpkg/dpkg.cfg.d/02apt-speedup
# rm /etc/apt/apt.conf.d/no-cache
if [ -z "$skipDetection" ]; then
# see also rudimentary platform detection in hack/install.sh
lsbDist=''
if [ -r etc/lsb-release ]; then
lsbDist="$(. etc/lsb-release && echo "$DISTRIB_ID")"
fi
if [ -z "$lsbDist" ] && [ -r etc/debian_version ]; then
lsbDist='Debian'
fi
case "$lsbDist" in
Debian)
# add the updates and security repositories
if [ "$suite" != "$debianUnstable" -a "$suite" != 'unstable' ]; then
# ${suite}-updates only applies to non-unstable
sudo sed -i "p; s/ $suite main$/ ${suite}-updates main/" etc/apt/sources.list
# same for security updates
echo "deb http://security.debian.org/ $suite/updates main" | sudo tee -a etc/apt/sources.list > /dev/null
fi
;;
Ubuntu)
# add the universe, updates, and security repositories
sudo sed -i "
s/ $suite main$/ $suite main universe/; p;
s/ $suite main/ ${suite}-updates main/; p;
s/ $suite-updates main/ ${suite}-security main/
" etc/apt/sources.list
;;
esac
fi
fi
if [ "$justTar" ]; then
# create the tarball file so it has the right permissions (ie, not root)
touch "$repo"
# fill the tarball
sudo tar --numeric-owner -caf "$repo" .
else
# create the image (and tag $repo:$suite)
sudo tar --numeric-owner -c . | $docker import - $repo $suite
# test the image
$docker run -i -t $repo:$suite echo success
if [ -z "$skipDetection" ]; then
case "$lsbDist" in
Debian)
if [ "$suite" = "$debianStable" -o "$suite" = 'stable' ] && [ -r etc/debian_version ]; then
# tag 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
fi
fi
;;
Ubuntu)
if [ "$suite" = "$ubuntuLatestLTS" ]; then
# tag 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
fi
fi
;;
esac
fi
fi
# cleanup
cd "$returnTo"
sudo rm -rf "$target"
+1 -1
View File
@@ -44,6 +44,6 @@ do
done
chmod 0755 $ROOTFS # See #486
tar -cf- . | docker import - docker-ut
tar --numeric-owner -cf- . | docker import - docker-ut
docker run -i -u root docker-ut /bin/echo Success.
rm -rf $ROOTFS
+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)
+2
View File
@@ -20,3 +20,5 @@ highlight link dockerfileString String
syntax match dockerfileComment "\v^\s*#.*$"
highlight link dockerfileComment Comment
set commentstring=#\ %s
+28 -75
View File
@@ -23,11 +23,11 @@ var (
)
type DevInfo struct {
Hash string `json:"-"`
DeviceId int `json:"device_id"`
Size uint64 `json:"size"`
TransactionId uint64 `json:"transaction_id"`
Initialized bool `json:"initialized"`
Hash string `json:"-"`
DeviceId int `json:"device_id"`
Size uint64 `json:"size"`
TransactionId uint64 `json:"transaction_id"`
Initialized bool `json:"initialized"`
devices *DeviceSet `json:"-"`
}
@@ -38,7 +38,6 @@ type MetaData struct {
type DeviceSet struct {
MetaData
sync.Mutex
initialized bool
root string
devicePrefix string
TransactionId uint64
@@ -48,16 +47,16 @@ type DeviceSet struct {
}
type DiskUsage struct {
Used uint64
Used uint64
Total uint64
}
type Status struct {
PoolName string
DataLoopback string
PoolName string
DataLoopback string
MetadataLoopback string
Data DiskUsage
Metadata DiskUsage
Data DiskUsage
Metadata DiskUsage
}
func getDevName(name string) string {
@@ -121,6 +120,7 @@ func (devices *DeviceSet) ensureImage(name string, size int64) (string, error) {
if err != nil {
return "", err
}
defer file.Close()
if err = file.Truncate(size); err != nil {
return "", err
@@ -349,11 +349,11 @@ func (devices *DeviceSet) log(level int, file string, line int, dmError int, mes
utils.Debugf("libdevmapper(%d): %s:%d (%d) %s", level, file, line, dmError, message)
}
func major (device uint64) uint64 {
return (device >> 8) & 0xfff
func major(device uint64) uint64 {
return (device >> 8) & 0xfff
}
func minor (device uint64) uint64 {
func minor(device uint64) uint64 {
return (device & 0xff) | ((device >> 12) & 0xfff00)
}
@@ -450,11 +450,6 @@ func (devices *DeviceSet) AddDevice(hash, baseHash string) error {
devices.Lock()
defer devices.Unlock()
if err := devices.ensureInit(); err != nil {
utils.Debugf("Error init: %s\n", err)
return err
}
if devices.Devices[hash] != nil {
return fmt.Errorf("hash %s already exists", hash)
}
@@ -522,11 +517,6 @@ func (devices *DeviceSet) RemoveDevice(hash string) error {
devices.Lock()
defer devices.Unlock()
if err := devices.ensureInit(); err != nil {
utils.Debugf("\n--->Err: %s\n", err)
return err
}
return devices.removeDevice(hash)
}
@@ -635,10 +625,6 @@ func (devices *DeviceSet) Shutdown() error {
utils.Debugf("[devmapper] Shutting down DeviceSet: %s", devices.root)
defer devices.Unlock()
if !devices.initialized {
return nil
}
for path, count := range devices.activeMounts {
for i := count; i > 0; i-- {
if err := syscall.Unmount(path, 0); err != nil {
@@ -671,10 +657,6 @@ func (devices *DeviceSet) MountDevice(hash, path string, readOnly bool) error {
devices.Lock()
defer devices.Unlock()
if err := devices.ensureInit(); err != nil {
return fmt.Errorf("Error initializing devmapper: %s", err)
}
if err := devices.activateDeviceIfNeeded(hash); err != nil {
return fmt.Errorf("Error activating devmapper device for '%s': %s", hash, err)
}
@@ -698,7 +680,7 @@ func (devices *DeviceSet) MountDevice(hash, path string, readOnly bool) error {
count := devices.activeMounts[path]
devices.activeMounts[path] = count + 1
return nil
return devices.setInitialized(hash)
}
func (devices *DeviceSet) UnmountDevice(hash, path string, deactivate bool) error {
@@ -736,9 +718,6 @@ func (devices *DeviceSet) HasDevice(hash string) bool {
devices.Lock()
defer devices.Unlock()
if err := devices.ensureInit(); err != nil {
return false
}
return devices.Devices[hash] != nil
}
@@ -746,10 +725,6 @@ func (devices *DeviceSet) HasInitializedDevice(hash string) bool {
devices.Lock()
defer devices.Unlock()
if err := devices.ensureInit(); err != nil {
return false
}
info := devices.Devices[hash]
return info != nil && info.Initialized
}
@@ -758,10 +733,6 @@ func (devices *DeviceSet) HasActivatedDevice(hash string) bool {
devices.Lock()
defer devices.Unlock()
if err := devices.ensureInit(); err != nil {
return false
}
info := devices.Devices[hash]
if info == nil {
return false
@@ -770,15 +741,7 @@ func (devices *DeviceSet) HasActivatedDevice(hash string) bool {
return devinfo != nil && devinfo.Exists != 0
}
func (devices *DeviceSet) SetInitialized(hash string) error {
devices.Lock()
defer devices.Unlock()
if err := devices.ensureInit(); err != nil {
utils.Debugf("\n--->Err: %s\n", err)
return err
}
func (devices *DeviceSet) setInitialized(hash string) error {
info := devices.Devices[hash]
if info == nil {
return fmt.Errorf("Unknown device %s", hash)
@@ -798,22 +761,18 @@ func (devices *DeviceSet) Status() *Status {
devices.Lock()
defer devices.Unlock()
status := &Status {}
if err := devices.ensureInit(); err != nil {
return status
}
status := &Status{}
status.PoolName = devices.getPoolName()
status.DataLoopback = path.Join( devices.loopbackDir(), "data")
status.MetadataLoopback = path.Join( devices.loopbackDir(), "metadata")
status.DataLoopback = path.Join(devices.loopbackDir(), "data")
status.MetadataLoopback = path.Join(devices.loopbackDir(), "metadata")
_, totalSizeInSectors, _, params, err := getStatus(devices.getPoolName())
if err == nil {
var transactionId, dataUsed, dataTotal, metadataUsed, metadataTotal uint64
if _, err := fmt.Sscanf(params, "%d %d/%d %d/%d", &transactionId, &metadataUsed, &metadataTotal, &dataUsed, &dataTotal); err == nil {
// Convert from blocks to bytes
blockSizeInSectors := totalSizeInSectors / dataTotal;
blockSizeInSectors := totalSizeInSectors / dataTotal
status.Data.Used = dataUsed * blockSizeInSectors * 512
status.Data.Total = dataTotal * blockSizeInSectors * 512
@@ -827,24 +786,18 @@ func (devices *DeviceSet) Status() *Status {
return status
}
func (devices *DeviceSet) ensureInit() error {
if !devices.initialized {
devices.initialized = true
if err := devices.initDevmapper(); err != nil {
utils.Debugf("\n--->Err: %s\n", err)
return err
}
}
return nil
}
func NewDeviceSet(root string) *DeviceSet {
func NewDeviceSet(root string) (*DeviceSet, error) {
SetDevDir("/dev")
return &DeviceSet{
initialized: false,
devices := &DeviceSet{
root: root,
MetaData: MetaData{Devices: make(map[string]*DevInfo)},
activeMounts: make(map[string]int),
}
if err := devices.initDevmapper(); err != nil {
return nil, err
}
return devices, nil
}
+66 -270
View File
@@ -1,163 +1,11 @@
package devmapper
/*
#cgo LDFLAGS: -L. -ldevmapper
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libdevmapper.h>
#include <linux/loop.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <errno.h>
#ifndef LOOP_CTL_GET_FREE
#define LOOP_CTL_GET_FREE 0x4C82
#endif
// FIXME: this could easily be rewritten in go
char* attach_loop_device(const char *filename, int *loop_fd_out)
{
struct loop_info64 loopinfo = {0};
struct stat st;
char buf[64];
int i, loop_fd, fd, start_index;
char* loopname;
*loop_fd_out = -1;
start_index = 0;
fd = open("/dev/loop-control", O_RDONLY);
if (fd >= 0) {
start_index = ioctl(fd, LOOP_CTL_GET_FREE);
close(fd);
if (start_index < 0)
start_index = 0;
}
fd = open(filename, O_RDWR);
if (fd < 0) {
perror("open");
return NULL;
}
loop_fd = -1;
for (i = start_index ; loop_fd < 0 ; i++ ) {
if (sprintf(buf, "/dev/loop%d", i) < 0) {
close(fd);
return NULL;
}
if (stat(buf, &st)) {
if (!S_ISBLK(st.st_mode)) {
fprintf(stderr, "[error] Loopback device %s is not a block device.\n", buf);
} else if (errno == ENOENT) {
fprintf(stderr, "[error] There are no more loopback device available.\n");
} else {
fprintf(stderr, "[error] Unkown error trying to stat the loopback device %s (errno: %d).\n", buf, errno);
}
close(fd);
return NULL;
}
loop_fd = open(buf, O_RDWR);
if (loop_fd < 0 && errno == ENOENT) {
fprintf(stderr, "[error] The loopback device %s does not exists.\n", buf);
close(fd);
return NULL;
} else if (loop_fd < 0) {
fprintf(stderr, "[error] Unkown error openning the loopback device %s. (errno: %d)\n", buf, errno);
continue;
}
if (ioctl(loop_fd, LOOP_SET_FD, (void *)(size_t)fd) < 0) {
int errsv = errno;
close(loop_fd);
loop_fd = -1;
if (errsv != EBUSY) {
close(fd);
fprintf(stderr, "cannot set up loopback device %s: %s", buf, strerror(errsv));
return NULL;
}
continue;
}
close(fd);
strncpy((char*)loopinfo.lo_file_name, buf, LO_NAME_SIZE);
loopinfo.lo_offset = 0;
loopinfo.lo_flags = LO_FLAGS_AUTOCLEAR;
if (ioctl(loop_fd, LOOP_SET_STATUS64, &loopinfo) < 0) {
perror("ioctl LOOP_SET_STATUS64");
if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) {
perror("ioctl LOOP_CLR_FD");
}
close(loop_fd);
fprintf (stderr, "cannot set up loopback device info");
return (NULL);
}
loopname = strdup(buf);
if (loopname == NULL) {
close(loop_fd);
return (NULL);
}
*loop_fd_out = loop_fd;
return (loopname);
}
return (NULL);
}
static int64_t get_block_size(int fd)
{
uint64_t size;
if (ioctl(fd, BLKGETSIZE64, &size) == -1)
return -1;
return ((int64_t)size);
}
extern void DevmapperLogCallback(int level, char *file, int line, int dm_errno_or_class, char *str);
static void
log_cb(int level, const char *file, int line,
int dm_errno_or_class, const char *f, ...)
{
char buffer[256];
va_list ap;
va_start(ap, f);
vsnprintf(buffer, 256, f, ap);
va_end(ap);
DevmapperLogCallback(level, (char *)file, line, dm_errno_or_class, buffer);
}
static void
log_with_errno_init ()
{
dm_log_with_errno_init(log_cb);
}
*/
import "C"
import (
"errors"
"fmt"
"github.com/dotcloud/docker/utils"
"os"
"runtime"
"syscall"
"unsafe"
)
type DevmapperLogger interface {
@@ -196,9 +44,13 @@ var (
ErrTaskSetName = errors.New("dm_task_set_name failed")
ErrTaskSetMessage = errors.New("dm_task_set_message failed")
ErrTaskSetAddNode = errors.New("dm_task_set_add_node failed")
ErrTaskSetRO = errors.New("dm_task_set_ro failed")
ErrTaskSetRo = errors.New("dm_task_set_ro failed")
ErrTaskAddTarget = errors.New("dm_task_add_target failed")
ErrGetDriverVersion = errors.New("dm_task_get_driver_version failed")
ErrTaskSetSector = errors.New("dm_task_set_sector failed")
ErrTaskGetInfo = errors.New("dm_task_get_info failed")
ErrTaskGetDriverVersion = errors.New("dm_task_get_driver_version failed")
ErrTaskSetCookie = errors.New("dm_task_set_cookie failed")
ErrNilCookie = errors.New("cookie ptr can't be nil")
ErrAttachLoopbackDevice = errors.New("loopback mounting failed")
ErrGetBlockSize = errors.New("Can't get block size")
ErrUdevWait = errors.New("wait on udev cookie failed")
@@ -206,11 +58,12 @@ var (
ErrGetLibraryVersion = errors.New("dm_get_library_version failed")
ErrCreateRemoveTask = errors.New("Can't create task of type DeviceRemove")
ErrRunRemoveDevice = errors.New("running removeDevice failed")
ErrInvalidAddNode = errors.New("Invalide AddNoce type")
)
type (
Task struct {
unmanaged *C.struct_dm_task
unmanaged *CDmTask
}
Info struct {
Exists int
@@ -230,167 +83,111 @@ type (
func (t *Task) destroy() {
if t != nil {
C.dm_task_destroy(t.unmanaged)
DmTaskDestory(t.unmanaged)
runtime.SetFinalizer(t, nil)
}
}
func TaskCreate(tasktype TaskType) *Task {
c_task := C.dm_task_create(C.int(tasktype))
if c_task == nil {
Ctask := DmTaskCreate(int(tasktype))
if Ctask == nil {
return nil
}
task := &Task{unmanaged: c_task}
task := &Task{unmanaged: Ctask}
runtime.SetFinalizer(task, (*Task).destroy)
return task
}
func (t *Task) Run() error {
if res := C.dm_task_run(t.unmanaged); res != 1 {
if res := DmTaskRun(t.unmanaged); res != 1 {
return ErrTaskRun
}
return nil
}
func (t *Task) SetName(name string) error {
c_name := C.CString(name)
defer free(c_name)
if res := C.dm_task_set_name(t.unmanaged, c_name); res != 1 {
if res := DmTaskSetName(t.unmanaged, name); res != 1 {
return ErrTaskSetName
}
return nil
}
func (t *Task) SetMessage(message string) error {
c_message := C.CString(message)
defer free(c_message)
if res := C.dm_task_set_message(t.unmanaged, c_message); res != 1 {
if res := DmTaskSetMessage(t.unmanaged, message); res != 1 {
return ErrTaskSetMessage
}
return nil
}
func (t *Task) SetSector(sector uint64) error {
if res := C.dm_task_set_sector(t.unmanaged, C.uint64_t(sector)); res != 1 {
return ErrTaskSetAddNode
if res := DmTaskSetSector(t.unmanaged, sector); res != 1 {
return ErrTaskSetSector
}
return nil
}
func (t *Task) SetCookie(cookie *uint32, flags uint16) error {
c_cookie := C.uint32_t(*cookie)
if res := C.dm_task_set_cookie(t.unmanaged, &c_cookie, C.uint16_t(flags)); res != 1 {
return ErrTaskSetAddNode
func (t *Task) SetCookie(cookie *uint, flags uint16) error {
if cookie == nil {
return ErrNilCookie
}
if res := DmTaskSetCookie(t.unmanaged, cookie, flags); res != 1 {
return ErrTaskSetCookie
}
*cookie = uint32(c_cookie)
return nil
}
func (t *Task) SetAddNode(add_node AddNodeType) error {
if res := C.dm_task_set_add_node(t.unmanaged, C.dm_add_node_t(add_node)); res != 1 {
func (t *Task) SetAddNode(addNode AddNodeType) error {
if addNode != AddNodeOnResume && addNode != AddNodeOnCreate {
return ErrInvalidAddNode
}
if res := DmTaskSetAddNode(t.unmanaged, addNode); res != 1 {
return ErrTaskSetAddNode
}
return nil
}
func (t *Task) SetRo() error {
if res := C.dm_task_set_ro(t.unmanaged); res != 1 {
return ErrTaskSetRO
if res := DmTaskSetRo(t.unmanaged); res != 1 {
return ErrTaskSetRo
}
return nil
}
func (t *Task) AddTarget(start uint64, size uint64, ttype string, params string) error {
c_ttype := C.CString(ttype)
defer free(c_ttype)
c_params := C.CString(params)
defer free(c_params)
if res := C.dm_task_add_target(t.unmanaged, C.uint64_t(start), C.uint64_t(size), c_ttype, c_params); res != 1 {
func (t *Task) AddTarget(start, size uint64, ttype, params string) error {
if res := DmTaskAddTarget(t.unmanaged, start, size,
ttype, params); res != 1 {
return ErrTaskAddTarget
}
return nil
}
func (t *Task) GetDriverVersion() (string, error) {
buffer := C.CString(string(make([]byte, 128)))
defer free(buffer)
if res := C.dm_task_get_driver_version(t.unmanaged, buffer, 128); res != 1 {
return "", ErrGetDriverVersion
}
return C.GoString(buffer), nil
}
func (t *Task) GetInfo() (*Info, error) {
c_info := C.struct_dm_info{}
if res := C.dm_task_get_info(t.unmanaged, &c_info); res != 1 {
return nil, ErrGetDriverVersion
info := &Info{}
if res := DmTaskGetInfo(t.unmanaged, info); res != 1 {
return nil, ErrTaskGetInfo
}
return &Info{
Exists: int(c_info.exists),
Suspended: int(c_info.suspended),
LiveTable: int(c_info.live_table),
InactiveTable: int(c_info.inactive_table),
OpenCount: int32(c_info.open_count),
EventNr: uint32(c_info.event_nr),
Major: uint32(c_info.major),
Minor: uint32(c_info.minor),
ReadOnly: int(c_info.read_only),
TargetCount: int32(c_info.target_count),
}, nil
return info, nil
}
func (t *Task) GetNextTarget(next uintptr) (uintptr, uint64, uint64, string, string) {
var (
c_start, c_length C.uint64_t
c_target_type, c_params *C.char
)
func (t *Task) GetNextTarget(next uintptr) (nextPtr uintptr, start uint64,
length uint64, targetType string, params string) {
nextp := C.dm_get_next_target(t.unmanaged, unsafe.Pointer(next), &c_start, &c_length, &c_target_type, &c_params)
return uintptr(nextp), uint64(c_start), uint64(c_length), C.GoString(c_target_type), C.GoString(c_params)
return DmGetNextTarget(t.unmanaged, next, &start, &length,
&targetType, &params),
start, length, targetType, params
}
func AttachLoopDevice(filename string) (*os.File, error) {
c_filename := C.CString(filename)
defer free(c_filename)
var fd C.int
res := C.attach_loop_device(c_filename, &fd)
if res == nil {
if os.Getenv("DEBUG") != "" {
C.perror(C.CString(fmt.Sprintf("[debug] Error attach_loop_device(%s, %d)", filename, int(fd))))
}
var fd int
res := DmAttachLoopDevice(filename, &fd)
if res == "" {
return nil, ErrAttachLoopbackDevice
}
defer free(res)
return os.NewFile(uintptr(fd), C.GoString(res)), nil
return os.NewFile(uintptr(fd), res), nil
}
func getBlockSize(fd uintptr) int {
var size uint64
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, C.BLKGETSIZE64, uintptr(unsafe.Pointer(&size))); err != 0 {
utils.Debugf("Error ioctl: %s", err)
return -1
}
return int(size)
}
func GetBlockDeviceSize(file *os.File) (uint64, error) {
if size := C.get_block_size(C.int(file.Fd())); size == -1 {
return 0, ErrGetBlockSize
} else {
return uint64(size), nil
}
}
func UdevWait(cookie uint32) error {
if res := C.dm_udev_wait(C.uint32_t(cookie)); res != 1 {
func UdevWait(cookie uint) error {
if res := DmUdevWait(cookie); res != 1 {
utils.Debugf("Failed to wait on udev cookie %d", cookie)
return ErrUdevWait
}
@@ -398,21 +195,18 @@ func UdevWait(cookie uint32) error {
}
func LogInitVerbose(level int) {
C.dm_log_init_verbose(C.int(level))
DmLogInitVerbose(level)
}
var dmLogger DevmapperLogger = nil
func logInit(logger DevmapperLogger) {
dmLogger = logger
C.log_with_errno_init()
LogWithErrnoInit()
}
func SetDevDir(dir string) error {
c_dir := C.CString(dir)
defer free(c_dir)
if res := C.dm_set_dev_dir(c_dir); res != 1 {
if res := DmSetDevDir(dir); res != 1 {
utils.Debugf("Error dm_set_dev_dir")
return ErrSetDevDir
}
@@ -420,13 +214,11 @@ func SetDevDir(dir string) error {
}
func GetLibraryVersion() (string, error) {
buffer := C.CString(string(make([]byte, 128)))
defer free(buffer)
if res := C.dm_get_library_version(buffer, 128); res != 1 {
var version string
if res := DmGetLibraryVersion(&version); res != 1 {
return "", ErrGetLibraryVersion
}
return C.GoString(buffer), nil
return version, nil
}
// Useful helper for cleanup
@@ -445,8 +237,12 @@ func RemoveDevice(name string) error {
return nil
}
func free(p *C.char) {
C.free(unsafe.Pointer(p))
func GetBlockDeviceSize(file *os.File) (uint64, error) {
size, errno := DmGetBlockSize(file.Fd())
if size == -1 || errno != 0 {
return 0, ErrGetBlockSize
}
return uint64(size), nil
}
// This is the programmatic example of "dmsetup create"
@@ -466,13 +262,13 @@ func createPool(poolName string, dataFile *os.File, metadataFile *os.File) error
return fmt.Errorf("Can't add target")
}
var cookie uint32 = 0
var cookie uint = 0
if err := task.SetCookie(&cookie, 0); err != nil {
return fmt.Errorf("Can't set cookie")
}
if err := task.Run(); err != nil {
return fmt.Errorf("Error running DeviceCreate")
return fmt.Errorf("Error running DeviceCreate (createPool)")
}
UdevWait(cookie)
@@ -564,7 +360,7 @@ func resumeDevice(name string) error {
return err
}
var cookie uint32 = 0
var cookie uint = 0
if err := task.SetCookie(&cookie, 0); err != nil {
return fmt.Errorf("Can't set cookie")
}
@@ -646,13 +442,13 @@ func activateDevice(poolName string, name string, deviceId int, size uint64) err
return fmt.Errorf("Can't add node")
}
var cookie uint32 = 0
var cookie uint = 0
if err := task.SetCookie(&cookie, 0); err != nil {
return fmt.Errorf("Can't set cookie")
}
if err := task.Run(); err != nil {
return fmt.Errorf("Error running DeviceCreate")
return fmt.Errorf("Error running DeviceCreate (activateDevice)")
}
UdevWait(cookie)
@@ -696,7 +492,7 @@ func (devices *DeviceSet) createSnapDevice(poolName string, deviceId int, baseNa
if doSuspend {
resumeDevice(baseName)
}
return fmt.Errorf("Error running DeviceCreate")
return fmt.Errorf("Error running DeviceCreate (createSnapDevice)")
}
if doSuspend {
+285
View File
@@ -0,0 +1,285 @@
package devmapper
import (
"syscall"
"testing"
)
func TestTaskCreate(t *testing.T) {
// Test success
taskCreate(t, DeviceInfo)
// Test Failure
DmTaskCreate = dmTaskCreateFail
defer func() { DmTaskCreate = dmTaskCreateFct }()
if task := TaskCreate(-1); task != nil {
t.Fatalf("An error should have occured while creating an invalid task.")
}
}
func TestTaskRun(t *testing.T) {
task := taskCreate(t, DeviceInfo)
// Test success
// Perform the RUN
if err := task.Run(); err != nil {
t.Fatal(err)
}
// Make sure we don't have error with GetInfo
if _, err := task.GetInfo(); err != nil {
t.Fatal(err)
}
// Test failure
DmTaskRun = dmTaskRunFail
defer func() { DmTaskRun = dmTaskRunFct }()
task = taskCreate(t, DeviceInfo)
// Perform the RUN
if err := task.Run(); err != ErrTaskRun {
t.Fatalf("An error should have occured while running task.")
}
// Make sure GetInfo also fails
if _, err := task.GetInfo(); err != ErrTaskGetInfo {
t.Fatalf("GetInfo should fail if task.Run() failed.")
}
}
func TestTaskSetName(t *testing.T) {
task := taskCreate(t, DeviceInfo)
// Test success
if err := task.SetName("test"); err != nil {
t.Fatal(err)
}
// Test failure
DmTaskSetName = dmTaskSetNameFail
defer func() { DmTaskSetName = dmTaskSetNameFct }()
if err := task.SetName("test"); err != ErrTaskSetName {
t.Fatalf("An error should have occured while runnign SetName.")
}
}
func TestTaskSetMessage(t *testing.T) {
task := taskCreate(t, DeviceInfo)
// Test success
if err := task.SetMessage("test"); err != nil {
t.Fatal(err)
}
// Test failure
DmTaskSetMessage = dmTaskSetMessageFail
defer func() { DmTaskSetMessage = dmTaskSetMessageFct }()
if err := task.SetMessage("test"); err != ErrTaskSetMessage {
t.Fatalf("An error should have occured while runnign SetMessage.")
}
}
func TestTaskSetSector(t *testing.T) {
task := taskCreate(t, DeviceInfo)
// Test success
if err := task.SetSector(128); err != nil {
t.Fatal(err)
}
DmTaskSetSector = dmTaskSetSectorFail
defer func() { DmTaskSetSector = dmTaskSetSectorFct }()
// Test failure
if err := task.SetSector(0); err != ErrTaskSetSector {
t.Fatalf("An error should have occured while running SetSector.")
}
}
func TestTaskSetCookie(t *testing.T) {
var (
cookie uint = 0
task = taskCreate(t, DeviceInfo)
)
// Test success
if err := task.SetCookie(&cookie, 0); err != nil {
t.Fatal(err)
}
// Test failure
if err := task.SetCookie(nil, 0); err != ErrNilCookie {
t.Fatalf("An error should have occured while running SetCookie with nil cookie.")
}
DmTaskSetCookie = dmTaskSetCookieFail
defer func() { DmTaskSetCookie = dmTaskSetCookieFct }()
if err := task.SetCookie(&cookie, 0); err != ErrTaskSetCookie {
t.Fatalf("An error should have occured while running SetCookie.")
}
}
func TestTaskSetAddNode(t *testing.T) {
task := taskCreate(t, DeviceInfo)
// Test success
if err := task.SetAddNode(0); err != nil {
t.Fatal(err)
}
// Test failure
if err := task.SetAddNode(-1); err != ErrInvalidAddNode {
t.Fatalf("An error should have occured running SetAddNode with wrong node.")
}
DmTaskSetAddNode = dmTaskSetAddNodeFail
defer func() { DmTaskSetAddNode = dmTaskSetAddNodeFct }()
if err := task.SetAddNode(0); err != ErrTaskSetAddNode {
t.Fatalf("An error should have occured running SetAddNode.")
}
}
func TestTaskSetRo(t *testing.T) {
task := taskCreate(t, DeviceInfo)
// Test success
if err := task.SetRo(); err != nil {
t.Fatal(err)
}
// Test failure
DmTaskSetRo = dmTaskSetRoFail
defer func() { DmTaskSetRo = dmTaskSetRoFct }()
if err := task.SetRo(); err != ErrTaskSetRo {
t.Fatalf("An error should have occured running SetRo.")
}
}
func TestTaskAddTarget(t *testing.T) {
task := taskCreate(t, DeviceInfo)
// Test success
if err := task.AddTarget(0, 128, "thinp", ""); err != nil {
t.Fatal(err)
}
// Test failure
DmTaskAddTarget = dmTaskAddTargetFail
defer func() { DmTaskAddTarget = dmTaskAddTargetFct }()
if err := task.AddTarget(0, 128, "thinp", ""); err != ErrTaskAddTarget {
t.Fatalf("An error should have occured running AddTarget.")
}
}
// func TestTaskGetInfo(t *testing.T) {
// task := taskCreate(t, DeviceInfo)
// // Test success
// if _, err := task.GetInfo(); err != nil {
// t.Fatal(err)
// }
// // Test failure
// DmTaskGetInfo = dmTaskGetInfoFail
// defer func() { DmTaskGetInfo = dmTaskGetInfoFct }()
// if _, err := task.GetInfo(); err != ErrTaskGetInfo {
// t.Fatalf("An error should have occured running GetInfo.")
// }
// }
// func TestTaskGetNextTarget(t *testing.T) {
// task := taskCreate(t, DeviceInfo)
// if next, _, _, _, _ := task.GetNextTarget(0); next == 0 {
// t.Fatalf("The next target should not be 0.")
// }
// }
/// Utils
func taskCreate(t *testing.T, taskType TaskType) *Task {
task := TaskCreate(taskType)
if task == nil {
t.Fatalf("Error creating task")
}
return task
}
/// Failure function replacement
func dmTaskCreateFail(t int) *CDmTask {
return nil
}
func dmTaskRunFail(task *CDmTask) int {
return -1
}
func dmTaskSetNameFail(task *CDmTask, name string) int {
return -1
}
func dmTaskSetMessageFail(task *CDmTask, message string) int {
return -1
}
func dmTaskSetSectorFail(task *CDmTask, sector uint64) int {
return -1
}
func dmTaskSetCookieFail(task *CDmTask, cookie *uint, flags uint16) int {
return -1
}
func dmTaskSetAddNodeFail(task *CDmTask, addNode AddNodeType) int {
return -1
}
func dmTaskSetRoFail(task *CDmTask) int {
return -1
}
func dmTaskAddTargetFail(task *CDmTask,
start, size uint64, ttype, params string) int {
return -1
}
func dmTaskGetDriverVersionFail(task *CDmTask, version *string) int {
return -1
}
func dmTaskGetInfoFail(task *CDmTask, info *Info) int {
return -1
}
func dmGetNextTargetFail(task *CDmTask, next uintptr, start, length *uint64,
target, params *string) uintptr {
return 0
}
func dmAttachLoopDeviceFail(filename string, fd *int) string {
return ""
}
func sysGetBlockSizeFail(fd uintptr, size *uint64) syscall.Errno {
return 1
}
func dmGetBlockSizeFail(fd uintptr) int64 {
return -1
}
func dmUdevWaitFail(cookie uint) int {
return -1
}
func dmSetDevDirFail(dir string) int {
return -1
}
func dmGetLibraryVersionFail(version *string) int {
return -1
}
+330
View File
@@ -0,0 +1,330 @@
package devmapper
/*
#cgo LDFLAGS: -L. -ldevmapper
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libdevmapper.h>
#include <linux/loop.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <errno.h>
#ifndef LOOP_CTL_GET_FREE
#define LOOP_CTL_GET_FREE 0x4C82
#endif
// FIXME: this could easily be rewritten in go
char* attach_loop_device(const char *filename, int *loop_fd_out)
{
struct loop_info64 loopinfo = {0};
struct stat st;
char buf[64];
int i, loop_fd, fd, start_index;
char* loopname;
*loop_fd_out = -1;
start_index = 0;
fd = open("/dev/loop-control", O_RDONLY);
if (fd >= 0) {
start_index = ioctl(fd, LOOP_CTL_GET_FREE);
close(fd);
if (start_index < 0)
start_index = 0;
}
fd = open(filename, O_RDWR);
if (fd < 0) {
perror("open");
return NULL;
}
loop_fd = -1;
for (i = start_index ; loop_fd < 0 ; i++ ) {
if (sprintf(buf, "/dev/loop%d", i) < 0) {
close(fd);
return NULL;
}
if (stat(buf, &st)) {
if (!S_ISBLK(st.st_mode)) {
fprintf(stderr, "[error] Loopback device %s is not a block device.\n", buf);
} else if (errno == ENOENT) {
fprintf(stderr, "[error] There are no more loopback device available.\n");
} else {
fprintf(stderr, "[error] Unkown error trying to stat the loopback device %s (errno: %d).\n", buf, errno);
}
close(fd);
return NULL;
}
loop_fd = open(buf, O_RDWR);
if (loop_fd < 0 && errno == ENOENT) {
fprintf(stderr, "[error] The loopback device %s does not exists.\n", buf);
close(fd);
return NULL;
} else if (loop_fd < 0) {
fprintf(stderr, "[error] Unkown error openning the loopback device %s. (errno: %d)\n", buf, errno);
continue;
}
if (ioctl(loop_fd, LOOP_SET_FD, (void *)(size_t)fd) < 0) {
int errsv = errno;
close(loop_fd);
loop_fd = -1;
if (errsv != EBUSY) {
close(fd);
fprintf(stderr, "cannot set up loopback device %s: %s", buf, strerror(errsv));
return NULL;
}
continue;
}
close(fd);
strncpy((char*)loopinfo.lo_file_name, buf, LO_NAME_SIZE);
loopinfo.lo_offset = 0;
loopinfo.lo_flags = LO_FLAGS_AUTOCLEAR;
if (ioctl(loop_fd, LOOP_SET_STATUS64, &loopinfo) < 0) {
perror("ioctl LOOP_SET_STATUS64");
if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) {
perror("ioctl LOOP_CLR_FD");
}
close(loop_fd);
fprintf (stderr, "cannot set up loopback device info");
return (NULL);
}
loopname = strdup(buf);
if (loopname == NULL) {
close(loop_fd);
return (NULL);
}
*loop_fd_out = loop_fd;
return (loopname);
}
return (NULL);
}
extern void DevmapperLogCallback(int level, char *file, int line, int dm_errno_or_class, char *str);
static void log_cb(int level, const char *file, int line,
int dm_errno_or_class, const char *f, ...)
{
char buffer[256];
va_list ap;
va_start(ap, f);
vsnprintf(buffer, 256, f, ap);
va_end(ap);
DevmapperLogCallback(level, (char *)file, line, dm_errno_or_class, buffer);
}
static void log_with_errno_init()
{
dm_log_with_errno_init(log_cb);
}
*/
import "C"
import (
"syscall"
"unsafe"
)
type (
CDmTask C.struct_dm_task
)
var (
DmTaskDestory = dmTaskDestroyFct
DmTaskCreate = dmTaskCreateFct
DmTaskRun = dmTaskRunFct
DmTaskSetName = dmTaskSetNameFct
DmTaskSetMessage = dmTaskSetMessageFct
DmTaskSetSector = dmTaskSetSectorFct
DmTaskSetCookie = dmTaskSetCookieFct
DmTaskSetAddNode = dmTaskSetAddNodeFct
DmTaskSetRo = dmTaskSetRoFct
DmTaskAddTarget = dmTaskAddTargetFct
DmTaskGetInfo = dmTaskGetInfoFct
DmGetNextTarget = dmGetNextTargetFct
DmGetBlockSize = dmGetBlockSizeFct
DmAttachLoopDevice = dmAttachLoopDeviceFct
DmUdevWait = dmUdevWaitFct
DmLogInitVerbose = dmLogInitVerboseFct
DmSetDevDir = dmSetDevDirFct
DmGetLibraryVersion = dmGetLibraryVersionFct
LogWithErrnoInit = logWithErrnoInitFct
GetBlockSize = getBlockSizeFct
)
func free(p *C.char) {
C.free(unsafe.Pointer(p))
}
func dmTaskDestroyFct(task *CDmTask) {
C.dm_task_destroy((*C.struct_dm_task)(task))
}
func dmTaskCreateFct(taskType int) *CDmTask {
return (*CDmTask)(C.dm_task_create(C.int(taskType)))
}
func dmTaskRunFct(task *CDmTask) int {
return int(C.dm_task_run((*C.struct_dm_task)(task)))
}
func dmTaskSetNameFct(task *CDmTask, name string) int {
Cname := C.CString(name)
defer free(Cname)
return int(C.dm_task_set_name((*C.struct_dm_task)(task),
Cname))
}
func dmTaskSetMessageFct(task *CDmTask, message string) int {
Cmessage := C.CString(message)
defer free(Cmessage)
return int(C.dm_task_set_message((*C.struct_dm_task)(task),
Cmessage))
}
func dmTaskSetSectorFct(task *CDmTask, sector uint64) int {
return int(C.dm_task_set_sector((*C.struct_dm_task)(task),
C.uint64_t(sector)))
}
func dmTaskSetCookieFct(task *CDmTask, cookie *uint, flags uint16) int {
cCookie := C.uint32_t(*cookie)
defer func() {
*cookie = uint(cCookie)
}()
return int(C.dm_task_set_cookie((*C.struct_dm_task)(task), &cCookie,
C.uint16_t(flags)))
}
func dmTaskSetAddNodeFct(task *CDmTask, addNode AddNodeType) int {
return int(C.dm_task_set_add_node((*C.struct_dm_task)(task),
C.dm_add_node_t(addNode)))
}
func dmTaskSetRoFct(task *CDmTask) int {
return int(C.dm_task_set_ro((*C.struct_dm_task)(task)))
}
func dmTaskAddTargetFct(task *CDmTask,
start, size uint64, ttype, params string) int {
Cttype := C.CString(ttype)
defer free(Cttype)
Cparams := C.CString(params)
defer free(Cparams)
return int(C.dm_task_add_target((*C.struct_dm_task)(task),
C.uint64_t(start), C.uint64_t(size), Cttype, Cparams))
}
func dmGetBlockSizeFct(fd uintptr) (int64, syscall.Errno) {
var size int64
_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, C.BLKGETSIZE64,
uintptr(unsafe.Pointer(&size)))
return size, err
}
func dmTaskGetInfoFct(task *CDmTask, info *Info) int {
Cinfo := C.struct_dm_info{}
defer func() {
info.Exists = int(Cinfo.exists)
info.Suspended = int(Cinfo.suspended)
info.LiveTable = int(Cinfo.live_table)
info.InactiveTable = int(Cinfo.inactive_table)
info.OpenCount = int32(Cinfo.open_count)
info.EventNr = uint32(Cinfo.event_nr)
info.Major = uint32(Cinfo.major)
info.Minor = uint32(Cinfo.minor)
info.ReadOnly = int(Cinfo.read_only)
info.TargetCount = int32(Cinfo.target_count)
}()
return int(C.dm_task_get_info((*C.struct_dm_task)(task), &Cinfo))
}
func dmGetNextTargetFct(task *CDmTask, next uintptr, start, length *uint64,
target, params *string) uintptr {
var (
Cstart, Clength C.uint64_t
CtargetType, Cparams *C.char
)
defer func() {
*start = uint64(Cstart)
*length = uint64(Clength)
*target = C.GoString(CtargetType)
*params = C.GoString(Cparams)
}()
nextp := C.dm_get_next_target((*C.struct_dm_task)(task),
unsafe.Pointer(next), &Cstart, &Clength, &CtargetType, &Cparams)
return uintptr(nextp)
}
func dmAttachLoopDeviceFct(filename string, fd *int) string {
cFilename := C.CString(filename)
defer free(cFilename)
var cFd C.int
defer func() {
*fd = int(cFd)
}()
ret := C.attach_loop_device(cFilename, &cFd)
defer free(ret)
return C.GoString(ret)
}
func getBlockSizeFct(fd uintptr, size *uint64) syscall.Errno {
_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, C.BLKGETSIZE64,
uintptr(unsafe.Pointer(&size)))
return err
}
func dmUdevWaitFct(cookie uint) int {
return int(C.dm_udev_wait(C.uint32_t(cookie)))
}
func dmLogInitVerboseFct(level int) {
C.dm_log_init_verbose(C.int(level))
}
func logWithErrnoInitFct() {
C.log_with_errno_init()
}
func dmSetDevDirFct(dir string) int {
Cdir := C.CString(dir)
defer free(Cdir)
return int(C.dm_set_dev_dir(Cdir))
}
func dmGetLibraryVersionFct(version *string) int {
buffer := C.CString(string(make([]byte, 128)))
defer free(buffer)
defer func() {
*version = C.GoString(buffer)
}()
return int(C.dm_get_library_version(buffer, 128))
}
+77
View File
@@ -0,0 +1,77 @@
package devmapper
import (
"fmt"
"github.com/dotcloud/docker/graphdriver"
"os"
"path"
)
func init() {
graphdriver.Register("devicemapper", Init)
}
// Placeholder interfaces, to be replaced
// at integration.
// End of placeholder interfaces.
type Driver struct {
*DeviceSet
home string
}
func Init(home string) (graphdriver.Driver, error) {
deviceSet, err := NewDeviceSet(home)
if err != nil {
return nil, err
}
d := &Driver{
DeviceSet: deviceSet,
home: home,
}
return d, nil
}
func (d *Driver) String() string {
return "devicemapper"
}
func (d *Driver) Cleanup() error {
return d.DeviceSet.Shutdown()
}
func (d *Driver) Create(id string, parent string) error {
return d.DeviceSet.AddDevice(id, parent)
}
func (d *Driver) Remove(id string) error {
return d.DeviceSet.RemoveDevice(id)
}
func (d *Driver) Get(id string) (string, error) {
mp := path.Join(d.home, "mnt", id)
if err := d.mount(id, mp); err != nil {
return "", err
}
return mp, nil
}
func (d *Driver) Size(id string) (int64, error) {
return -1, fmt.Errorf("Not implemented")
}
func (d *Driver) mount(id, mountPoint string) error {
// Create the target directories if they don't exist
if err := os.MkdirAll(mountPoint, 0755); err != nil && !os.IsExist(err) {
return err
}
// If mountpoint is already mounted, do nothing
if mounted, err := Mounted(mountPoint); err != nil {
return fmt.Errorf("Error checking mountpoint: %s", err)
} else if mounted {
return nil
}
// Mount the device
return d.DeviceSet.MountDevice(id, mountPoint, false)
}
+301
View File
@@ -0,0 +1,301 @@
package devmapper
import (
"io/ioutil"
"os"
"path"
"testing"
)
func init() {
// Reduce the size the the base fs and loopback for the tests
DefaultDataLoopbackSize = 300 * 1024 * 1024
DefaultMetaDataLoopbackSize = 200 * 1024 * 1024
DefaultBaseFsSize = 300 * 1024 * 1024
}
func mkTestDirectory(t *testing.T) string {
dir, err := ioutil.TempDir("", "docker-test-devmapper-")
if err != nil {
t.Fatal(err)
}
return dir
}
func newDriver(t *testing.T) *Driver {
home := mkTestDirectory(t)
d, err := Init(home)
if err != nil {
t.Fatal(err)
}
return d.(*Driver)
}
func cleanup(d *Driver) {
d.Cleanup()
os.RemoveAll(d.home)
}
func TestInit(t *testing.T) {
home := mkTestDirectory(t)
defer os.RemoveAll(home)
driver, err := Init(home)
if err != nil {
t.Fatal(err)
}
defer func() {
if err := driver.Cleanup(); err != nil {
t.Fatal(err)
}
}()
id := "foo"
if err := driver.Create(id, ""); err != nil {
t.Fatal(err)
}
dir, err := driver.Get(id)
if err != nil {
t.Fatal(err)
}
if st, err := os.Stat(dir); err != nil {
t.Fatal(err)
} else if !st.IsDir() {
t.Fatalf("Get(%V) did not return a directory", id)
}
}
func TestDriverName(t *testing.T) {
d := newDriver(t)
defer cleanup(d)
if d.String() != "devicemapper" {
t.Fatalf("Expected driver name to be devicemapper got %s", d.String())
}
}
func TestDriverCreate(t *testing.T) {
d := newDriver(t)
defer cleanup(d)
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
}
func TestDriverRemove(t *testing.T) {
d := newDriver(t)
defer cleanup(d)
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
if err := d.Remove("1"); err != nil {
t.Fatal(err)
}
}
func TestCleanup(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(d.home)
mountPoints := make([]string, 2)
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
// Mount the id
p, err := d.Get("1")
if err != nil {
t.Fatal(err)
}
mountPoints[0] = p
if err := d.Create("2", "1"); err != nil {
t.Fatal(err)
}
p, err = d.Get("2")
if err != nil {
t.Fatal(err)
}
mountPoints[1] = p
// Ensure that all the mount points are currently mounted
for _, p := range mountPoints {
if mounted, err := Mounted(p); err != nil {
t.Fatal(err)
} else if !mounted {
t.Fatalf("Expected %s to be mounted", p)
}
}
// Ensure that devices are active
for _, p := range []string{"1", "2"} {
if !d.HasActivatedDevice(p) {
t.Fatalf("Expected %s to have an active device", p)
}
}
if err := d.Cleanup(); err != nil {
t.Fatal(err)
}
// Ensure that all the mount points are no longer mounted
for _, p := range mountPoints {
if mounted, err := Mounted(p); err != nil {
t.Fatal(err)
} else if mounted {
t.Fatalf("Expected %s to not be mounted", p)
}
}
// Ensure that devices are no longer activated
for _, p := range []string{"1", "2"} {
if d.HasActivatedDevice(p) {
t.Fatalf("Expected %s not be an active device", p)
}
}
}
func TestNotMounted(t *testing.T) {
d := newDriver(t)
defer cleanup(d)
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
mounted, err := Mounted(path.Join(d.home, "mnt", "1"))
if err != nil {
t.Fatal(err)
}
if mounted {
t.Fatal("Id 1 should not be mounted")
}
}
func TestMounted(t *testing.T) {
d := newDriver(t)
defer cleanup(d)
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
if _, err := d.Get("1"); err != nil {
t.Fatal(err)
}
mounted, err := Mounted(path.Join(d.home, "mnt", "1"))
if err != nil {
t.Fatal(err)
}
if !mounted {
t.Fatal("Id 1 should be mounted")
}
}
func TestInitCleanedDriver(t *testing.T) {
d := newDriver(t)
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
if _, err := d.Get("1"); err != nil {
t.Fatal(err)
}
if err := d.Cleanup(); err != nil {
t.Fatal(err)
}
driver, err := Init(d.home)
if err != nil {
t.Fatal(err)
}
d = driver.(*Driver)
defer cleanup(d)
if _, err := d.Get("1"); err != nil {
t.Fatal(err)
}
}
func TestMountMountedDriver(t *testing.T) {
d := newDriver(t)
defer cleanup(d)
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
// Perform get on same id to ensure that it will
// not be mounted twice
if _, err := d.Get("1"); err != nil {
t.Fatal(err)
}
if _, err := d.Get("1"); err != nil {
t.Fatal(err)
}
}
func TestGetReturnsValidDevice(t *testing.T) {
d := newDriver(t)
defer cleanup(d)
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
if !d.HasDevice("1") {
t.Fatalf("Expected id 1 to be in device set")
}
if _, err := d.Get("1"); err != nil {
t.Fatal(err)
}
if !d.HasActivatedDevice("1") {
t.Fatalf("Expected id 1 to be activated")
}
if !d.HasInitializedDevice("1") {
t.Fatalf("Expected id 1 to be initialized")
}
}
func TestDriverGetSize(t *testing.T) {
t.Skipf("Size is currently not implemented")
d := newDriver(t)
defer cleanup(d)
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
mountPoint, err := d.Get("1")
if err != nil {
t.Fatal(err)
}
size := int64(1024)
f, err := os.Create(path.Join(mountPoint, "test_file"))
if err != nil {
t.Fatal(err)
}
if err := f.Truncate(size); err != nil {
t.Fatal(err)
}
f.Close()
diffSize, err := d.Size("1")
if err != nil {
t.Fatal(err)
}
if diffSize != size {
t.Fatalf("Expected size %d got %d", size, diffSize)
}
}
+4 -1
View File
@@ -1,4 +1,4 @@
package docker
package devmapper
import (
"os"
@@ -6,6 +6,9 @@ import (
"syscall"
)
// FIXME: this is copy-pasted from the aufs driver.
// It should be moved into the core.
func Mounted(mountpoint string) (bool, error) {
mntpoint, err := os.Stat(mountpoint)
if err != nil {
+38 -92
View File
@@ -4,14 +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"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
)
var (
@@ -22,7 +20,7 @@ var (
func main() {
if selfPath := utils.SelfPath(); selfPath == "/sbin/init" || selfPath == "/.dockerinit" {
// Running in init mode
docker.SysInit()
sysinit.SysInit()
return
}
// FIXME: Switch d and D ? (to be more sshd like)
@@ -32,12 +30,17 @@ func main() {
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.")
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 requests in the remote api.")
flDns := flag.String("dns", "", "Set custom dns servers")
flHosts := docker.ListOpts{fmt.Sprintf("unix://%s", docker.DEFAULTUNIXSOCKET)}
flHosts := utils.ListOpts{fmt.Sprintf("unix://%s", docker.DEFAULTUNIXSOCKET)}
flag.Var(&flHosts, "H", "tcp://host:port to bind/connect to or unix://path/to/socket to use")
flEnableIptables := flag.Bool("iptables", true, "Disable iptables within docker")
flDefaultIp := flag.String("ip", "0.0.0.0", "Default ip address to use when binding a containers ports")
flInterContainerComm := flag.Bool("icc", true, "Enable inter-container communication")
flag.Parse()
if *flVersion {
showVersion()
return
@@ -46,14 +49,14 @@ func main() {
flHosts = flHosts[1:] //trick to display a nice default value in the usage
}
for i, flHost := range flHosts {
flHosts[i] = utils.ParseHost(docker.DEFAULTHTTPHOST, docker.DEFAULTHTTPPORT, flHost)
host, err := utils.ParseHost(docker.DEFAULTHTTPHOST, docker.DEFAULTHTTPPORT, flHost)
if err == nil {
flHosts[i] = host
} else {
log.Fatal(err)
}
}
if *bridgeName != "" {
docker.NetworkBridgeIface = *bridgeName
} else {
docker.NetworkBridgeIface = docker.DefaultNetworkBridge
}
if *flDebug {
os.Setenv("DEBUG", "1")
}
@@ -64,14 +67,33 @@ func main() {
flag.Usage()
return
}
if err := daemon(*pidfile, *flGraphPath, flHosts, *flAutoRestart, *flEnableCors, *flDns); err != nil {
eng, err := engine.New(*flRoot)
if err != nil {
log.Fatal(err)
}
// 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)
if err := job.Run(); err != nil {
log.Fatal(err)
}
// Serve api
job = eng.Job("serveapi", flHosts...)
job.SetenvBool("Logging", true)
if err := job.Run(); err != nil {
log.Fatal(err)
os.Exit(-1)
}
} else {
if len(flHosts) > 1 {
log.Fatal("Please specify only one -H")
return
}
protoAddrParts := strings.SplitN(flHosts[0], "://", 2)
if err := docker.ParseCommands(protoAddrParts[0], protoAddrParts[1], flag.Args()...); err != nil {
@@ -79,7 +101,6 @@ func main() {
os.Exit(sterr.Status)
}
log.Fatal(err)
os.Exit(-1)
}
}
}
@@ -87,78 +108,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(pidfile string, flGraphPath string, protoAddrs []string, autoRestart, enableCors bool, flDns string) error {
if err := createPidFile(pidfile); err != nil {
log.Fatal(err)
}
defer removePidFile(pidfile)
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGTERM)
go func() {
sig := <-c
log.Printf("Received signal '%v', exiting\n", sig)
removePidFile(pidfile)
os.Exit(0)
}()
var dns []string
if flDns != "" {
dns = []string{flDns}
}
server, err := docker.NewServer(flGraphPath, autoRestart, enableCors, dns)
if err != nil {
return err
}
chErrors := make(chan error, len(protoAddrs))
for _, protoAddr := range protoAddrs {
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 {
log.Fatal("Invalid protocol format.")
os.Exit(-1)
}
go func() {
chErrors <- docker.ListenAndServe(protoAddrParts[0], protoAddrParts[1], server, true)
}()
}
for i := 0; i < len(protoAddrs); i += 1 {
err := <-chErrors
if err != nil {
return err
}
}
return nil
}
@@ -1,7 +1,7 @@
package main
import (
"github.com/dotcloud/docker"
"github.com/dotcloud/docker/sysinit"
)
var (
@@ -11,6 +11,6 @@ var (
func main() {
// Running in init mode
docker.SysInit()
sysinit.SysInit()
return
}
+6 -1
View File
@@ -1,11 +1,16 @@
from ubuntu:12.04
maintainer Nick Stinemates
#
# docker build -t docker:docs . && docker run -p 8000:8000 docker:docs
#
run apt-get update
run apt-get install -y python-setuptools make
run easy_install pip
#from docs/requirements.txt, but here to increase cacheability
run pip install Sphinx==1.1.3
run pip install sphinxcontrib-httpdomain==1.1.8
add . /docs
run pip install -r /docs/requirements.txt
run cd /docs; make docs
expose 8000
+5 -4
View File
@@ -39,8 +39,7 @@ Getting Started
To edit and test the docs, you'll need to install the Sphinx tool and
its dependencies. There are two main ways to install this tool:
Native Installation
...................
###Native Installation
* Install sphinx: `pip install sphinx`
* Mac OS X: `[sudo] pip-2.7 install sphinx`
@@ -48,8 +47,7 @@ Native Installation
* Mac OS X: `[sudo] pip-2.7 install sphinxcontrib-httpdomain`
* If pip is not available you can probably install it using your favorite package manager as **python-pip**
Alternative Installation: Docker Container
..........................................
###Alternative Installation: Docker Container
If you're running ``docker`` on your development machine then you may
find it easier and cleaner to use the Dockerfile. This installs Sphinx
@@ -59,6 +57,9 @@ docs inside the container, even starting a simple HTTP server on port
build .`` and run the resulting image. This is the equivalent to
``make clean server`` since each container starts clean.
In the ``docs/`` directory, run:
```docker build -t docker:docs . && docker run -p 8000:8000 docker:docs```
Usage
-----
* Follow the contribution guidelines (``../CONTRIBUTING.md``)
+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
****
+21 -16
View File
@@ -970,28 +970,33 @@ Create a new image from a container's changes
**Example request**:
.. sourcecode:: http
.. sourcecode:: http
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
Content-Type: application/json
{
"Cmd": ["cat", "/world"],
"PortSpecs":["22"]
}
**Example response**:
**Example response**:
.. sourcecode:: http
.. sourcecode:: http
HTTP/1.1 201 OK
Content-Type: application/vnd.docker.raw-stream
HTTP/1.1 201 OK
Content-Type: application/vnd.docker.raw-stream
{"Id":"596069db4bf5"}
{"Id":"596069db4bf5"}
:query container: source container
:query repo: repository
:query tag: tag
:query m: commit message
:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
:query run: config automatically applied when the image is run. (ex: {"Cmd": ["cat", "/world"], "PortSpecs":["22"]})
:statuscode 201: no error
:statuscode 404: no such container
:statuscode 500: server error
:query container: source container
:query repo: repository
:query tag: tag
:query m: commit message
:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
:statuscode 201: no error
:statuscode 404: no such container
:statuscode 500: server error
3. Going further
+28 -23
View File
@@ -977,32 +977,37 @@ Create a new image from a container's changes
.. http:post:: /commit
Create a new image from a container's changes
Create a new image from a container's changes
**Example request**:
**Example request**:
.. sourcecode:: http
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
Content-Type: application/json
{
"Cmd": ["cat", "/world"],
"PortSpecs":["22"]
}
**Example response**:
.. sourcecode:: http
HTTP/1.1 201 OK
Content-Type: application/vnd.docker.raw-stream
.. sourcecode:: http
{"Id":"596069db4bf5"}
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
**Example response**:
.. sourcecode:: http
HTTP/1.1 201 OK
Content-Type: application/vnd.docker.raw-stream
{"Id":"596069db4bf5"}
:query container: source container
:query repo: repository
:query tag: tag
:query m: commit message
:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
:query run: config automatically applied when the image is run. (ex: {"Cmd": ["cat", "/world"], "PortSpecs":["22"]})
:statuscode 201: no error
:statuscode 404: no such container
:statuscode 500: server error
:query container: source container
:query repo: repository
:query tag: tag
:query m: commit message
:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
:statuscode 201: no error
:statuscode 404: no such container
:statuscode 500: server error
3. Going further
+22 -17
View File
@@ -985,32 +985,37 @@ Create a new image from a container's changes
.. http:post:: /commit
Create a new image from a container's changes
Create a new image from a container's changes
**Example request**:
**Example request**:
.. sourcecode:: http
.. sourcecode:: http
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
Content-Type: application/json
{
"Cmd": ["cat", "/world"],
"PortSpecs":["22"]
}
**Example response**:
**Example response**:
.. sourcecode:: http
.. sourcecode:: http
HTTP/1.1 201 OK
HTTP/1.1 201 OK
Content-Type: application/vnd.docker.raw-stream
{"Id":"596069db4bf5"}
{"Id":"596069db4bf5"}
:query container: source container
:query repo: repository
:query tag: tag
:query m: commit message
:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
:query run: config automatically applied when the image is run. (ex: {"Cmd": ["cat", "/world"], "PortSpecs":["22"]})
:statuscode 201: no error
:statuscode 404: no such container
:statuscode 500: server error
:query container: source container
:query repo: repository
:query tag: tag
:query m: commit message
:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
:statuscode 201: no error
:statuscode 404: no such container
:statuscode 500: server error
3. Going further
+22 -17
View File
@@ -1034,32 +1034,37 @@ Create a new image from a container's changes
.. http:post:: /commit
Create a new image from a container's changes
Create a new image from a container's changes
**Example request**:
**Example request**:
.. sourcecode:: http
.. sourcecode:: http
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
Content-Type: application/json
{
"Cmd": ["cat", "/world"],
"PortSpecs":["22"]
}
**Example response**:
**Example response**:
.. sourcecode:: http
.. sourcecode:: http
HTTP/1.1 201 OK
HTTP/1.1 201 OK
Content-Type: application/vnd.docker.raw-stream
{"Id":"596069db4bf5"}
{"Id":"596069db4bf5"}
:query container: source container
:query repo: repository
:query tag: tag
:query m: commit message
:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
:query run: config automatically applied when the image is run. (ex: {"Cmd": ["cat", "/world"], "PortSpecs":["22"]})
:statuscode 201: no error
:statuscode 404: no such container
:statuscode 500: server error
:query container: source container
:query repo: repository
:query tag: tag
:query m: commit message
:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
:statuscode 201: no error
:statuscode 404: no such container
:statuscode 500: server error
Monitor Docker's events
+29 -24
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
@@ -1084,23 +1084,28 @@ Create a new image from a container's changes
.. sourcecode:: http
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
Content-Type: application/json
{
"Cmd": ["cat", "/world"],
"PortSpecs":["22"]
}
**Example response**:
.. sourcecode:: http
HTTP/1.1 201 OK
Content-Type: application/vnd.docker.raw-stream
HTTP/1.1 201 OK
Content-Type: application/vnd.docker.raw-stream
{"Id":"596069db4bf5"}
{"Id":"596069db4bf5"}
:query container: source container
:query repo: repository
:query tag: tag
:query m: commit message
:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
:query run: config automatically applied when the image is run. (ex: {"Cmd": ["cat", "/world"], "PortSpecs":["22"]})
:statuscode 201: no error
:statuscode 404: no such container
:statuscode 500: server error
+23 -18
View File
@@ -1050,32 +1050,37 @@ Create a new image from a container's changes
.. http:post:: /commit
Create a new image from a container's changes
Create a new image from a container's changes
**Example request**:
**Example request**:
.. sourcecode:: http
.. sourcecode:: http
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
Content-Type: application/json
{
"Cmd": ["cat", "/world"],
"PortSpecs":["22"]
}
**Example response**:
**Example response**:
.. sourcecode:: http
.. sourcecode:: http
HTTP/1.1 201 OK
Content-Type: application/vnd.docker.raw-stream
HTTP/1.1 201 OK
Content-Type: application/vnd.docker.raw-stream
{"Id":"596069db4bf5"}
{"Id":"596069db4bf5"}
:query container: source container
:query repo: repository
:query tag: tag
:query m: commit message
:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
:query run: config automatically applied when the image is run. (ex: {"Cmd": ["cat", "/world"], "PortSpecs":["22"]})
:statuscode 201: no error
:statuscode 404: no such container
:statuscode 500: server error
:query container: source container
:query repo: repository
:query tag: tag
:query m: commit message
:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
:statuscode 201: no error
:statuscode 404: no such container
:statuscode 500: server error
Monitor Docker's events
***********************
+94 -30
View File
@@ -13,9 +13,12 @@ Docker Remote API v1.6
1. Brief introduction
=====================
- The Remote API is replacing rcli
- Default port in the docker daemon is 4243
- The API tends to be REST, but for some complex commands, like attach or pull, the HTTP connection is hijacked to transport stdout stdin and stderr
- The Remote API has replaced rcli
- The daemon listens on ``unix:///var/run/docker.sock``, but you can
:ref:`bind_docker`.
- The API tends to be REST, but for some complex commands, like
``attach`` or ``pull``, the HTTP connection is hijacked to transport
``stdout, stdin`` and ``stderr``
2. Endpoints
============
@@ -118,8 +121,7 @@ Create a container
"AttachStdin":false,
"AttachStdout":true,
"AttachStderr":true,
"PortSpecs":null,
"Privileged": false,
"ExposedPorts":{},
"Tty":false,
"OpenStdin":false,
"StdinOnce":false,
@@ -132,7 +134,6 @@ Create a container
"Volumes":{},
"VolumesFrom":"",
"WorkingDir":""
}
**Example response**:
@@ -148,11 +149,63 @@ Create a container
}
:jsonparam config: the container's configuration
:query name: container name to use
:statuscode 201: no error
:statuscode 404: no such 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
*******************
@@ -187,7 +240,7 @@ Inspect a container
"AttachStdin": false,
"AttachStdout": true,
"AttachStderr": true,
"PortSpecs": null,
"ExposedPorts": {},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
@@ -358,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**:
@@ -442,7 +500,8 @@ Kill a container
.. sourcecode:: http
HTTP/1.1 204 OK
:query signal: Signal to send to the container (integer). When not set, SIGKILL is assumed and the call will waits for the container to exit.
:statuscode 204: no error
:statuscode 404: no such container
:statuscode 500: server error
@@ -790,7 +849,7 @@ Inspect an image
"AttachStdin":false,
"AttachStdout":false,
"AttachStderr":false,
"PortSpecs":null,
"ExposedPorts":{},
"Tty":true,
"OpenStdin":true,
"StdinOnce":false,
@@ -990,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
@@ -1131,7 +1190,13 @@ Create a new image from a container's changes
.. sourcecode:: http
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
Content-Type: application/json
{
"Cmd": ["cat", "/world"],
"ExposedPorts":{"22/tcp":{}}
}
**Example response**:
@@ -1147,7 +1212,6 @@ Create a new image from a container's changes
:query tag: tag
:query m: commit message
:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
:query run: config automatically applied when the image is run. (ex: {"Cmd": ["cat", "/world"], "PortSpecs":["22"]})
:statuscode 201: no error
:statuscode 404: no such container
:statuscode 500: server error
File diff suppressed because it is too large Load Diff
@@ -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 |
+----------------------+----------------+--------------------------------------------+----------+
+216 -39
View File
@@ -29,6 +29,9 @@ To list available commands, either run ``docker`` with no parameters or execute
Attach to a running container.
-nostdin=false: Do not attach stdin
-sig-proxy=true: Proxify all received signal to the process (even in non-tty mode)
You can detach from the container again (and leave it running) with
``CTRL-c`` (for a quiet exit) or ``CTRL-\`` to get a stacktrace of
the Docker client when it quits.
@@ -38,7 +41,7 @@ To stop a container, use ``docker stop``
To kill the container, use ``docker kill``
.. _cli_attach_examples:
Examples:
~~~~~~~~~
@@ -52,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
@@ -61,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
@@ -71,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:
@@ -93,8 +96,8 @@ Examples:
.. _cli_build_examples:
Examples
~~~~~~~~
Examples:
~~~~~~~~~
.. code-block:: bash
@@ -130,7 +133,6 @@ to the ``docker`` daemon. ``ADD`` doesn't work when running in this
mode because the absence of the context provides no source files to
copy to the container.
.. code-block:: bash
sudo docker build github.com/creack/docker-firefox
@@ -148,16 +150,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`.
-run="": Configuration to be applied when the image is launched with `docker run`.
(ex: '{"Cmd": ["cat", "/world"], "PortSpecs": ["22"]}')
Full -run example (multiline is ok within a single quote ``'``)
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)
S
Full -run example
.................
(multiline is ok within a single quote ``'``)
::
@@ -224,6 +245,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:
@@ -236,7 +260,7 @@ Shell 1: Listening for events
.............................
.. code-block:: bash
$ sudo docker events
Shell 2: Start and Stop a Container
@@ -256,6 +280,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:
@@ -279,6 +320,9 @@ Shell 1: (Again .. now showing events)
Show the history of an image
-notrunc=false: Don't truncate output
-q=false: only show numeric IDs
.. _cli_images:
``images``
@@ -291,8 +335,10 @@ Shell 1: (Again .. now showing events)
List images
-a=false: show all images
-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
Displaying images visually
~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -304,6 +350,36 @@ Displaying images visually
.. image:: docker_images.gif
:alt: Example inheritance graph of Docker images.
Displaying image hierarchy
~~~~~~~~~~~~~~~~~~~~~~~~~~
::
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``
@@ -311,7 +387,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
@@ -327,14 +403,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
.............................
@@ -396,9 +474,17 @@ Insert file from github
::
Usage: docker kill [OPTIONS] CONTAINER [CONTAINER...]
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_login:
@@ -427,7 +513,6 @@ Insert file from github
``logs``
--------
::
Usage: docker logs [OPTIONS] CONTAINER
@@ -507,6 +592,44 @@ Insert file from github
Usage: docker rm [OPTIONS] CONTAINER
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:
~~~~~~~~~
.. code-block:: bash
$ docker rm /redis
/redis
This will remove the container referenced under the link ``/redis``.
.. code-block:: bash
$ docker rm -link /webapp/redis
/webapp/redis
This will remove the underlying link between ``/webapp`` and the ``/redis`` containers removing all
network communication.
.. 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:
@@ -530,7 +653,7 @@ Insert file from github
Run a command in a new container
-a=map[]: Attach to stdin, stdout or stderr.
-a=map[]: Attach to stdin, stdout or stderr
-c=0: CPU shares (relative weight)
-cidfile="": Write the container ID to the file
-d=false: Detached mode: Run container in the background, print new container id
@@ -538,7 +661,7 @@ Insert file from github
-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)
@@ -546,13 +669,18 @@ Insert file from github
-u="": Username or UID
-dns=[]: Set custom dns servers for the container
-v=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro]. If "container-dir" is missing, then docker creates a new volume.
-volumes-from="": Mount all volumes from the given container.
-entrypoint="": Overwrite the default entrypoint set by the image.
-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"
-sig-proxy=true: Proxify all received signal to the process (even in non-tty mode)
-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
~~~~~~~~
--------
.. code-block:: bash
@@ -586,20 +714,64 @@ 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.1:80:8080 ubuntu bash
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 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
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
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``
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.
.. _cli_search:
``search``
@@ -609,8 +781,11 @@ using the container, but inside the current working directory.
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:
@@ -623,6 +798,9 @@ using the container, but inside the current working directory.
Start a stopped container
-a=false: Attach container's stdout/stderr and forward all signals to the process
-i=false: Attach container's stdin
.. _cli_stop:
``stop``
@@ -632,10 +810,12 @@ using the container, but inside the current working directory.
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``
@@ -643,7 +823,7 @@ using the container, but inside the current working directory.
::
Usage: docker tag [OPTIONS] IMAGE REPOSITORY [TAG]
Usage: docker tag [OPTIONS] IMAGE REPOSITORY[:TAG]
Tag an image into a repository
@@ -656,7 +836,7 @@ using the container, but inside the current working directory.
::
Usage: docker top CONTAINER
Usage: docker top CONTAINER [ps OPTIONS]
Lookup the running processes of a container
@@ -678,6 +858,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.
+5 -1
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']
+17 -1
View File
@@ -5,5 +5,21 @@
Contributing to Docker
======================
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>`_.
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>`_
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>`_
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>`_.
+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
@@ -25,8 +25,8 @@ Note that we're marking ``/var/lib/couchdb`` as a data volume.
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
@@ -37,7 +37,7 @@ replace `localhost` with the public IP of your docker host.
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
@@ -52,5 +52,5 @@ Browse data on the second database
URL="http://$HOST:$(sudo docker port $COUCH2 5984)/_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.
+10 -9
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
+2 -2
View File
@@ -1,6 +1,6 @@
:title: Docker Examples
:description: Examples on how to use Docker
:keywords: docker, hello world, node, nodejs, python, couch, couchdb, redis, ssh, sshd, examples, postgresql
:keywords: docker, hello world, node, nodejs, python, couch, couchdb, redis, ssh, sshd, examples, postgresql, link
.. _example_list:
@@ -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
+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``.
+21 -21
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,22 +20,22 @@ 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
@@ -43,13 +43,13 @@ container. BUILD_JOB will be set with the new container_id.
[...]
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. You can use Ctrl-C to disconnect.
.. 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 +57,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 +72,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 +97,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 environmental varaibles 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 create a little screencast to show how to create a SSHd service
and connect to it. It is something like 11 minutes and not entirely
smooth, but 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:**
+27 -8
View File
@@ -102,26 +102,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!
+1 -1
View File
@@ -69,7 +69,7 @@ to run LXC containers. Note that 2.6.32 has some documented issues regarding
network namespace setup and teardown; those issues are not a risk if you
run containers in a private environment, but can lead to denial-of-service
attacks if you want to run untrusted code in your containers. For more details,
see `[LP#720095 <https://bugs.launchpad.net/ubuntu/+source/linux/+bug/720095>`_.
see `LP#720095 <https://bugs.launchpad.net/ubuntu/+source/linux/+bug/720095>`_.
Kernels 2.6.38, and every version since 3.2, have been deployed successfully
to run containerized production workloads. Feature-wise, there is no huge
+6 -4
View File
@@ -78,7 +78,8 @@ Docker is available as a Debian package, which makes installation easy.
sudo sh -c "wget -qO- https://get.docker.io/gpg | apt-key add -"
# Add the Docker repository to your apt sources list.
sudo sh -c "echo deb http://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list"
sudo sh -c "echo deb http://get.docker.io/ubuntu docker main\
> /etc/apt/sources.list.d/docker.list"
# Update your sources
sudo apt-get update
@@ -132,7 +133,8 @@ to follow them again.*
sudo sh -c "wget -qO- https://get.docker.io/gpg | apt-key add -"
# Add the Docker repository to your apt sources list.
sudo sh -c "echo deb http://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list"
sudo sh -c "echo deb http://get.docker.io/ubuntu docker main\
> /etc/apt/sources.list.d/docker.list"
# update
sudo apt-get update
@@ -160,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
```````````````````````

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