Compare commits

..

83 Commits

Author SHA1 Message Date
Arnaud Porterie d12ea79c9d Update VERSION and CHANGELOG.md
Signed-off-by: Arnaud Porterie <arnaud.porterie@docker.com>
2015-08-12 18:54:41 -07:00
Arnaud Porterie a9aaa66780 Update regression test
Signed-off-by: Arnaud Porterie <arnaud.porterie@docker.com>
2015-08-12 18:52:01 -07:00
Arnaud Porterie e19060dcea Revert #14884
This reverts commit 810d3b2642.

Signed-off-by: Arnaud Porterie <arnaud.porterie@docker.com>
2015-08-12 18:51:57 -07:00
David Calavera b0e0dbb33b Merge pull request #15091 from calavera/bump_v1.8.0
Bump v1.8.0
2015-08-11 13:16:04 -05:00
David Calavera 0d03096b65 Bump version to 1.8.0
Signed-off-by: David Calavera <david.calavera@gmail.com>
2015-08-11 11:35:27 -05:00
Jessica Frazelle 55e9551aaa minor cosmetic change to client output on pull
Signed-off-by: Jessica Frazelle <acidburn@docker.com>
(cherry picked from commit 8bd6322760)
2015-08-11 11:35:27 -05:00
Mary Anthony c65afe6ba8 Updating new vm and with migrate
Signed-off-by: Mary Anthony <mary@docker.com>
(cherry picked from commit e5c160e1d6)
2015-08-11 11:35:27 -05:00
Mary Anthony 5745aaed22 Initial work
Removing references to regsitry 1.0, pointing to distribution
Updating links and title
Adding in comments

Signed-off-by: Mary Anthony <mary@docker.com>
(cherry picked from commit d550d729e1)
2015-08-11 11:35:27 -05:00
Diogo Monica b6f0f93c94 Docker content trust documentation
- started from Diogo's work
- updated after discussions with team
- Updating with new key names
- fixing weight
- adding in sandbox
- adding in gliffy for images
- backing out to old names for now
- Copy edit pass
- Entering comments from the content trust team
- Update name of branch and image name
- Removing the last diogo reference
- Updating with Seb's comments

Signed-off-by: Mary Anthony <mary@docker.com>
(cherry picked from commit 753bf40f15)
2015-08-11 11:35:26 -05:00
Youcef YEKHLEF 33b16fef43 Add fedora 22 install docs warning about systemd-network
With systemd in version 219 IP forwarding should be forced in the interface configuration file.

Signed-off-by: yyekhlef <yyekhlef@gmail.com>
(cherry picked from commit 35aebdc803)
2015-08-10 12:11:42 -05:00
Youcef YEKHLEF 9705c349c5 Add fedora 22 install docs warning about systemd-network
Following @cles commit #6bd15a68c for Arch

Signed-off-by: yyekhlef <yyekhlef@gmail.com>
(cherry picked from commit f224a9f3d6)
2015-08-10 12:11:42 -05:00
Ankush Agarwal 3de34af5d1 Remove note from docker version 1.3 on Env variables
Fixes #14734

Signed-off-by: Ankush Agarwal <ankushagarwal11@gmail.com>
(cherry picked from commit 89ec5399af)
2015-08-10 12:11:42 -05:00
Ankush Agarwal b3f3abfc94 Make official install instructions use curl instead of wget
YOU GO CURL

Fixes #14650

Signed-off-by: Ankush Agarwal <ankushagarwal11@gmail.com>
(cherry picked from commit c76fef1791)
2015-08-10 12:10:42 -05:00
Mary Anthony 783baec49c Fixes #15349 too many apis
Signed-off-by: Mary Anthony <mary@docker.com>
(cherry picked from commit 1d5f479e01)
2015-08-10 12:10:42 -05:00
Vincent Bernat c1d9e7c6fb doc: add a notice about memory accounting overhead
The documentation for Debian and Ubuntu explains how to enable memory
and swap accounting but doesn't explain why it is disabled in the first
place. The problem with those subsystems is that they incurs a
performance hit even when not used at all. Add this explanation.

The provided figure are quite vague. The memory overhead is easily
verifiable. It is for example cited in [RedHat documentation][]. For the
performance hit, maybe the performance is better now, but a few years
ago, it was said to be [between 6 and 15%][].

The goal is that people don't just enable memory accounting if they
don't have a use for it.

[RedHat documentation]: https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Resource_Management_Guide/sec-memory.html
[between 6 and 15%]: https://lwn.net/Articles/517562/

Signed-off-by: Vincent Bernat <vincent@bernat.im>
(cherry picked from commit 56b33e9f27)
2015-08-10 12:10:42 -05:00
Derek McGowan 83f6dbe30a Skip notary tests which update system clock
Currently some notary tests change the system clock to check for expiration.
Skip these tests until the code can be refactored to not rely on updating the system clock.

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
(cherry picked from commit bf3c1e6a3a)
2015-08-07 10:08:37 -07:00
Jessica Frazelle a97b89b585 remove docker-unconfined profile we were not using it and it breaks apparmor on wheezy
Signed-off-by: Jessica Frazelle <acidburn@docker.com>
(cherry picked from commit e542238f2a)
2015-08-06 20:08:25 -07:00
Tibor Vass 29ea36a880 registry: Do not push to mirrors
This patch splits LookupEndpoints into LookupPullEndpoints and
LookupPushEndpoints so that mirrors added with --registry-mirror are
skipped in the list returned by LookupPushEndpoints.

Fixes https://github.com/docker/distribution/issues/823

Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit b899977ee2)
2015-08-06 19:55:06 -07:00
Alessandro Boch ed672d1609 Vendoring libnetwork bd3eecc96f3c05a4acef1bedcf74397bc6850d22
Signed-off-by: Alessandro Boch <aboch@docker.com>
(cherry picked from commit e35a5ae463)
2015-08-06 19:55:05 -07:00
Jessica Frazelle 5916664220 revert apparmor changes back to how it was in 1.7.1, but keep tests
Signed-off-by: Jessica Frazelle <acidburn@docker.com>
(cherry picked from commit ed248207d7)
2015-08-06 19:55:05 -07:00
Lei da4b336233 Remove redundant ip_forward check
Signed-off-by: Lei Jitang <leijitang@huawei.com>
(cherry picked from commit 6a0050d0f0)
2015-08-06 09:55:02 -07:00
Josh Hawn 74df05ccaa [graph] Use a pipe for downloads to write progress
The process of pulling an image spawns a new goroutine for each layer in the
image manifest. If any of these downloads fail we would stop everything and
return the error, even though other goroutines would still be running and
writing output through a progress reader which is attached to an http response
writer. Since the request handler had already returned from the first error,
the http server panics when one of these download goroutines makes a write to
the response writer buffer.

This patch prevents this crash in the daemon http server by waiting for all of
the download goroutines to complete, even if one of them fails. Only then does
it return, terminating the request handler.

Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)

(cherry picked from commit d80c4244d3)
2015-08-06 09:14:16 -07:00
Dimitri John Ledkov 2c875215b1 systemd: set service type to notify.
Currently the service type is 'simple', the default, meaning that
docker.service is considered to be started straight after
spawning. This is incorrect as there is significant amount of time
between spawning and docker ready to accept connections on the passed
sockets. Docker does implement systemd socket activate and
notification protocol, and send the ready signal to systemd, once it
is ready. However for systemd to take those notifications into
account, the service file type should be set to notify.

Signed-off-by: Dimitri John Ledkov <dimitri.j.ledkov@intel.com>
(cherry picked from commit d3e5179c29)
2015-08-06 08:39:11 -07:00
Mary Anthony be40a48c12 - Remove references to sudo in basics.md; see sudo instructions top of file
- Removing references to Boot2Docker replacing with Docker Machine
- Removing sudo warnings in instances where appropriate (no sudo in file)
- Updating with comments

Signed-off-by: Mary Anthony <mary@docker.com>
(cherry picked from commit cc375a1e48)
2015-08-06 08:39:10 -07:00
Filipe Oliveira 85f7f7cfc7 Adding support to forked distributions in installer script.
Signed-off-by: Filipe Oliveira <contato@fmoliveira.com.br>
(cherry picked from commit f618de1543)
2015-08-06 08:35:41 -07:00
David Calavera e15f6fca3f Fail fail when the ps format template is invalid.
Fixes error continuing execution when the parsing fails.

Signed-off-by: David Calavera <david.calavera@gmail.com>
(cherry picked from commit 3d3db0d4af)
2015-08-05 16:21:30 -07:00
Vincent Demeester d3bbaa70cd Update some contributions documentations
- Add a golint entry to coding-style.md

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
(cherry picked from commit b304920021)
2015-08-05 10:54:39 -07:00
Harald Albers cc6f6cb2e2 Add --config to bash completion
The custom configuration will also be used in docker invocations made
by the completion script itself, just like `-H`.

Signed-off-by: Harald Albers <github@albersweb.de>
(cherry picked from commit b898111d3a)
2015-08-05 09:52:08 -07:00
Jessica Frazelle c967dd289f update systemd article to reference dropin file
Signed-off-by: Jessica Frazelle <acidburn@docker.com>
(cherry picked from commit 35e7a7c3e2)
2015-08-04 14:11:36 -07:00
Sally O'Malley 7895ec25ea make man/docker.1.md consistent with docker --help
"Options:" listed when you run "docker --help" and "docker daemon
--help" do not match the options listed in "man/docker.1.md".  This PR
makes 'docker --help', 'docker daemon --help' and 'man docker' consistent.
Also 2 typo fixes.

Signed-off-by: Sally O'Malley <somalley@redhat.com>
(cherry picked from commit f3bea61c80)
2015-08-04 09:35:25 -07:00
Charles Chan 5b06c94701 Fix #15212: Add "Labels" key to output of /containers/json
Applied retroactively from API v1.18 - v1.21.

Signed-off-by: Charles Chan <charleswhchan@users.noreply.github.com>
(cherry picked from commit b245bcd458)
2015-08-04 09:35:25 -07:00
Eric Windisch 5851e2da60 Remove container AA profile from packaging
Signed-off-by: Eric Windisch <eric@windisch.us>
(cherry picked from commit 0f4e5f7149)
2015-08-03 17:49:58 -07:00
Eric Windisch 9eff33735a Fix the proc integration test & include missing AA profile
Integration tests were failing due to proc filter behavior
changes with new apparmor policies.

Also include the missing docker-unconfined policy resolving
potential startup errors. This policy is complain-only so
it should behave identically to the standard unconfined policy,
but will not apply system path-based policies within containers.

Signed-off-by: Eric Windisch <eric@windisch.us>
(cherry picked from commit 5832715052)
2015-08-03 17:49:58 -07:00
Alessandro Boch fc7697b050 Fix preallocated bridge networks
- Because of a bug, all the statically preallocated
  bridge networks have /24 as network mask.

Signed-off-by: Alessandro Boch <aboch@docker.com>
(cherry picked from commit dab0447ae0)
2015-08-03 17:21:31 -07:00
David Calavera 1bf8954d0d Remove key file when migration fails.
Signed-off-by: David Calavera <david.calavera@gmail.com>
(cherry picked from commit 07c45e499d)
2015-08-03 16:22:34 -07:00
Michael Crosby dfd9f5989a Add LXC built in support deprecation notice
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
(cherry picked from commit 06f6c0c7e5)
2015-08-03 16:22:34 -07:00
Josh Hawn d9581e861d [graph] Enforce manifest/layer digest verification
We noticed a regression since the 1.7.1 patch after some refactoring. This
patch corrects the behavior and adds integration tests for modified manifest
and rootfs layer blobs.

Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)

(cherry picked from commit de52a3bcaa)
2015-08-03 16:22:33 -07:00
Stephen Rust c383ceaf37 Docs: Add Blockbridge volume plugin
Signed-off-by: Stephen Rust <srust@blockbridge.com>
(cherry picked from commit 8b15b7958a)
2015-08-03 11:29:25 -07:00
Harald Albers 948912f692 Filter completions of docker inspect by --type
Completion now filters the images and containers by given
`--type`.

Signed-off-by: Harald Albers <github@albersweb.de>
(cherry picked from commit 69cde5a302)
2015-08-03 11:29:25 -07:00
jrabbit d19b1b927b Actually link to the information
Signed-off-by: jrabbit <jackjrabbit@gmail.com>
(cherry picked from commit d2cd142ce1)
2015-08-03 09:44:11 -07:00
Tibor Vass 53f5905379 Add missing LICENSE files for docker/notary
Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit 084af30f39)
2015-08-03 09:43:19 -07:00
Tibor Vass 60cbf4da6c Vendor docker/distribution to 7dc8d4a26b689bd4892f2f2322dbce0b7119d686
Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit 0cce1fb37f)
2015-08-03 09:43:19 -07:00
evalle 183628388c Fix wrong path to YaST's 'Routing' menu for openSUSE Tumbleweed
Signed-off-by: evalle <shmarnev@gmail.com>
(cherry picked from commit 5f1593c7b8)
2015-08-03 09:37:35 -07:00
Charles Chan fbd2267e7d Update docker_remote_api.md
Minor fixes:
* v1.19: GET /containers/(id)/logs - add missing '/'
* v1.18: Break up POST /containers/create and POST /containers/(id)/start into separate lines.

Signed-off-by: Charles Chan <charleswhchan@users.noreply.github.com>
(cherry picked from commit 084d464081)
2015-08-03 09:37:35 -07:00
Derek McGowan a16ab243e5 Updated to use latest version of notary
Update UX to use aliases for root, snapshot, and target key

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
(cherry picked from commit 6ce76cd9ed)
2015-08-03 09:37:35 -07:00
Derek McGowan b3c3c4cddc Vendor latest notary
Use updated notary to pick up updates from security review

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
(cherry picked from commit d594c6fcd8)
2015-08-03 09:37:34 -07:00
Qiang Huang 0fe5aad984 Remove unused variable
Introduced by #15209 unintentionally.

Signed-off-by: Qiang Huang <h.huangqiang@huawei.com>
(cherry picked from commit f5557f4f43)
2015-08-03 09:37:34 -07:00
Brian Goff 0f5e2fd479 Ensure reader position is at the end after tailing
After tailing a file, if the number of lines requested is > the number
of lines in the file, this would cause a json unmarshalling error to
occur when we later try to go follow the file.
So brute force set it to the end if any tailing occurred.

There is potential that there could be some missing log messages if logs
are being written very quickly, however I was not able to make this
happen even with `while true; do echo hello; done`, so this is probably
acceptable.

While testing this I also found a panic in LogWatcher.Close can be
called twice due to a race. Fix channel close to only close when there
has been no signal to the channel.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
(cherry picked from commit c57faa91e2)
2015-08-03 09:37:34 -07:00
David Calavera 2f7145b1c5 Remove read index that causes dead lock.
Let the iterator to lock the index when it needs it.

Signed-off-by: David Calavera <david.calavera@gmail.com>
(cherry picked from commit 5ed84009b3)
2015-07-31 14:56:17 -07:00
Harald Albers 81efe1f32e Fix completion of commands after a global option with arg
Without this fix, `docker -l info ` would not complete the commands.

Signed-off-by: Harald Albers <github@albersweb.de>
(cherry picked from commit aab82c5c22)
2015-07-31 12:20:42 -07:00
Harald Albers 5ba75ac343 Add completion of global options to docker daemon
It's a bit confusing: the "global options" are valid as "global options"
for all client commands (i.e. all but daemon).
Example: `docker --log-level info run`

For `docker daemon`, these "global options" are only valid as "command
options".
Example: `docker daemon --log-level info`

As command completion cannot tell which command the user is going to
type next, completion for the daemon command has to allow illegal
syntaxes like
`docker --log-level info daemon --log-level info`

Signed-off-by: Harald Albers <github@albersweb.de>
(cherry picked from commit e0dad9a153)
2015-07-31 12:20:42 -07:00
Alessandro Boch 290987fcb4 Add test code to cover issue #14859
Signed-off-by: Alessandro Boch <aboch@docker.com>
(cherry picked from commit 4964ab0821)
2015-07-31 08:59:42 -07:00
Alessandro Boch 98855c863d Vendoring libnetwork 31139cdb513aea5ad1ed08b60d4350a68b4c96db
Signed-off-by: Alessandro Boch <aboch@docker.com>
(cherry picked from commit 91274625ba)
2015-07-31 08:59:42 -07:00
Jessica Frazelle b1f394a247 fix regression
Signed-off-by: Jessica Frazelle <acidburn@docker.com>
(cherry picked from commit b0af811272)
2015-07-30 17:21:22 -07:00
Avi Miller a819a60a94 Fix for #14924. Seperates lsb_dist detection from dist_version detection
so that the latter can be distro specific.

Signed-off-by: Avi Miller <avi.miller@oracle.com>
(cherry picked from commit 5c6446f335)
2015-07-30 17:21:21 -07:00
Tibor Vass 33cdc7f2c4 registry: allow fallback on unknown errors
This patch fixes a bug where a user specifies a v1 mirror for
--registry-mirror and pull an image from the Hub.

It used to not fallback because of an unexpected error returned when
trying to JSON marshal nginx output.

We now ensure that any unexpected error falls back to the next endpoint
in the list.

Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit a21ba12f4e)
2015-07-30 17:21:21 -07:00
Jay Kamat 117860577c Fix a couple broken links
Signed-off-by: Jay Kamat <github@jgkamat.33mail.com>
(cherry picked from commit 4ca0aad855)
2015-07-30 17:21:21 -07:00
Dan Walsh b0ac5df367 Labels on network content need to be shared if shared network namespace
If I run two containers with the same network they share the same /etc/resolv.conf.
The current code changes the labels of the /etc/resolv.conf currently to the
private label which causes it to be unusable in the first container.

This patch changes the labels to a shared label if more then one container
will use the content.

Docker-DCO-1.1-Signed-off-by: Dan Walsh dwalsh@redhat.com (github: rhatdan)

Docker-DCO-1.1-Signed-off-by: Dan Walsh <dwalsh@redhat.com> (github: rhatdan)

(cherry picked from commit 90b8cebda6)
2015-07-30 17:21:21 -07:00
Josh Hawn c109095a58 Fix docker cp Behavior With Symlinks
[pkg/archive] Update archive/copy path handling

  - Remove unused TarOptions.Name field.
  - Add new TarOptions.RebaseNames field.
  - Update some of the logic around path dir/base splitting.
  - Update some of the logic behind archive entry name rebasing.

[api/types] Add LinkTarget field to PathStat

[daemon] Fix stat, archive, extract of symlinks

  These operations *should* resolve symlinks that are in the path but if the
  resource itself is a symlink then it *should not* be resolved. This patch
  puts this logic into a common function `resolvePath` which resolves symlinks
  of the path's dir in scope of the container rootfs but does not resolve the
  final element of the path. Now archive, extract, and stat operations will
  return symlinks if the path is indeed a symlink.

[api/client] Update cp path hanling

[docs/reference/api] Update description of stat

  Add the linkTarget field to the header of the archive endpoint.
  Remove path field.

[integration-cli] Fix/Add cp symlink test cases

  Copying a symlink should do just that: copy the symlink NOT
  copy the target of the symlink. Also, the resulting file from
  the copy should have the name of the symlink NOT the name of
  the target file.

  Copying to a symlink should copy to the symlink target and not
  modify the symlink itself.

Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)

(cherry picked from commit 75f6929b44)
2015-07-30 17:21:20 -07:00
Stephen Rust d394113dfe Check for nil before using HostConfig to adjustCpuShares
Fix #14915. Add unit test for #14915.
Thanks @runcom for the test case: when the client calls 1.18 api
version w/o hostconfig it results in a nil pointer dereference.

Signed-off-by: Stephen Rust <srust@blockbridge.com>
(cherry picked from commit c358a4cd35)
2015-07-30 17:21:20 -07:00
Michael Crosby 2af7f63173 Don't mount /proc as ro
This caused a regression with LSM labeling.

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
(cherry picked from commit bfc51cf660)
2015-07-30 17:21:20 -07:00
Eric Windisch f156fb7be5 Only explicitly deny ptrace for container-originated procs
The 'deny ptrace' statement was supposed to only ignore
ptrace failures in the AUDIT log. However, ptrace was implicitly
allowed from unconfined processes (such as the docker daemon and
its integration tests) due to the abstractions/base include.

This rule narrows the definition such that it will only ignore
the failures originating inside of the container and will not
cause denials when the daemon or its tests ptrace inside processes.

Introduces positive and negative tests for ptrace /w apparmor.

Signed-off-by: Eric Windisch <eric@windisch.us>
(cherry picked from commit f5c388b35a)
2015-07-30 12:54:14 -07:00
Tibor Vass 559043b953 tlsconfig: better format for error message in tlsconfig
Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit c7a04fda2a)
2015-07-30 12:54:14 -07:00
Harald Albers ba8abcb3dd Add docker daemon to bash completion
Signed-off-by: Harald Albers <github@albersweb.de>
Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit 8cc8ee9254)
2015-07-30 12:54:14 -07:00
David Calavera ebf396c6e8 Log each release step.
Signed-off-by: David Calavera <david.calavera@gmail.com>
(cherry picked from commit 776600fabb)
2015-07-30 09:07:15 -07:00
Josh Hawn 47d52fb872 [api/client] Tag resolved digest from Dockerfile
Builds where the base images have been resolved to trusted digest
references will now be tagged with the original tag reference from
the Dockerfile on a successful build.

Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)

(cherry picked from commit bb2e6c72d2)
2015-07-29 16:53:10 -07:00
Vincent Batts d167338876 graphdriver/*: expect uncompressed tar for ApplyDiff
The `ApplyDiff` function takes a tar archive stream that is
automagically decompressed later. This was causing a double
decompression, and when the layer was empty, that causes an early EOF.

Signed-off-by: Vincent Batts <vbatts@redhat.com>
(cherry picked from commit 273f50c741)
2015-07-29 16:48:42 -07:00
Vincent Batts e6844381f0 archive, chrootarchive: split out decompression
In `ApplyLayer` and `Untar`, the stream is magically decompressed. Since
this is not able to be toggled, rather than break this ./pkg/ API, add
an `ApplyUncompressedLayer` and `UntarUncompressed` that does not
magically decompress the layer stream.

Signed-off-by: Vincent Batts <vbatts@redhat.com>
(cherry picked from commit 56bf275e32)
2015-07-29 16:48:41 -07:00
Derek McGowan 589922adf0 Fix login and search TLS configuration
Currently login and search do not load per registry certificates.
This is a regression caused by the last refactor since this was recently fixed.

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
(cherry picked from commit e863a07b89)
2015-07-29 16:45:16 -07:00
David Calavera 689c4e6075 Keep backwards compatibility in kill api.
Return an error when the container is stopped only in api versions
equal or greater than 1.20 (docker 1.8).

Signed-off-by: David Calavera <david.calavera@gmail.com>
(cherry picked from commit 621e3d8587)
2015-07-29 16:44:21 -07:00
David Calavera 43da1adedb Use *int64 for MemorySwappiness.
So we marshal/unmarshal its value properly when it's empty.

Signed-off-by: David Calavera <david.calavera@gmail.com>
(cherry picked from commit 4e25d2982b)
2015-07-29 16:44:21 -07:00
Antonio Murdaca 686fe02020 Fix install script to handle debian 8.1 apt repo string
Fix #14911

Signed-off-by: Antonio Murdaca <runcom@linux.com>
(cherry picked from commit 98f15cae89)
2015-07-29 10:46:26 -07:00
Eric Windisch 1d02be1c7a Mark engine AA policy as complain-only
The engine policy will now only complain
as a temporary measure to ensure we do not
cause breakages while users exercise this
policy.

This is NOT the policy for containers, but
for the newly-introduced policy for the
daemon itself.

Signed-off-by: Eric Windisch <eric@windisch.us>
(cherry picked from commit 6c887be769)
2015-07-29 09:54:16 -07:00
Eric Windisch edb60b950a AA: Eliminate 'file' permission
Implements the policies for the remaining binaries
called by the Docker engine and eliminates the
giant whitelisted 'all files' permission in favor
of granular whitelisting and child-specific policies.

It should be possible now to remove the 'file' permission,
but for the sake of keeping Docker unbroken, we'll try
to gradually tighten the policy.

Signed-off-by: Eric Windisch <eric@windisch.us>
(cherry picked from commit 8b2fcddcd2)
2015-07-29 09:54:16 -07:00
Eric Windisch e0e852ee6f Restore AppArmor profile generation
Will attempt to load profiles automatically. If loading fails
but the profiles are already loaded, execution will continue.

A hard failure will only occur if Docker cannot load
the profiles *and* they have not already been loaded via
some other means.

Also introduces documentation for AppArmor.

Signed-off-by: Eric Windisch <eric@windisch.us>
(cherry picked from commit 3edc88f76d)
2015-07-29 09:54:16 -07:00
Jessica Frazelle b537508f8c only write distributions file if dne
Signed-off-by: Jessica Frazelle <princess@docker.com>
(cherry picked from commit 2eee192366)
2015-07-28 17:48:56 -07:00
Avi Miller 37e886eb7b Fix typo.
Signed-off-by: Avi Miller <avi.miller@oracle.com>
(cherry picked from commit 59e48b3468)
2015-07-28 09:39:55 -07:00
Avi Miller 50f65742ef Switch to using only the RPM command to determine the distro version.
Signed-off-by: Avi Miller <avi.miller@oracle.com>
(cherry picked from commit a43199f143)
2015-07-28 09:39:50 -07:00
Alexander Morozov 56d859d052 Use math.MaxInt32 instead of math.MaxUint32
I think it was original intention, because even half of a comment was about
MaxInt32.

Fix #15038

Signed-off-by: Alexander Morozov <lk4d4@docker.com>
(cherry picked from commit eb45602d2f)
2015-07-28 09:35:56 -07:00
Josh Hawn 546a704c63 [api/client] Fix build when context dir is symlink
Symbolic links in the context directory path are now evaluated.

Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)

(cherry picked from commit 01d570ad30)
2015-07-28 09:35:38 -07:00
Aaron Lehmann fa85dc0030 Update vendored distribution repo to new version
This version includes a fix that avoids checking against specific HTTP
status codes. The previous behavior violated the registry API spec.

Fixes #14975

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
(cherry picked from commit 091dbc1034)
2015-07-28 09:35:26 -07:00
Antonio Murdaca 36b6e5884d Format times in inspect command with a template as RFC3339Nano
In 1.6.2 we were decoding inspect API response into interface{}.
time.Time fields were JSON encoded as RFC3339Nano in the response
and when decoded into interface{} they were just strings so the inspect
template treated them as just strings.
From 1.7 we are decoding into types.ContainerJSON and when the template
gets executed it now gets a time.Time and it's formatted as
2015-07-22 05:02:38.091530369 +0000 UTC.
This patch brings back the old behavior by typing time.Time fields
as string so they gets formatted as they were encoded in JSON -- RCF3339Nano

Signed-off-by: Antonio Murdaca <runcom@linux.com>
(cherry picked from commit c9207bc0aa)
2015-07-28 09:35:14 -07:00
Jessica Frazelle 90991ddb9b fix deb packaging systemd files
Signed-off-by: Jessica Frazelle <princess@docker.com>
(cherry picked from commit a2ea8f2ad8)
2015-07-28 09:34:48 -07:00
893 changed files with 19103 additions and 28965 deletions
+3 -3
View File
@@ -4,7 +4,7 @@
### Distribution
* Fix a bug where pushing multiple tags would result in invalid images
- Fix a bug where pushing multiple tags would result in invalid images
## 1.8.0 (2015-08-11)
@@ -42,7 +42,7 @@
+ Add logging driver for GELF via UDP
+ Allow to copy files from host to containers with `docker cp`
+ Promote volume drivers from experimental to master
+ Add rollover options to json-file log driver, and --log-driver-opts flag
+ Add rollover log driver, and --log-driver-opts flag
+ Add memory swappiness tuning options
* Remove cgroup read-only flag when privileged
* Make /proc, /sys, & /dev readonly for readonly containers
@@ -63,7 +63,7 @@
### Bug fixes
- Add missing 'Names' field to /containers/json API output
- Make `docker rmi` of dangling images safe while pulling
- Make `docker rmi --dangling` safe when pulling
- Devicemapper: Change default basesize to 100G
- Go Scheduler issue with sync.Mutex and gcc
- Fix issue where Search API endpoint would panic due to empty AuthConfig
+2 -3
View File
@@ -40,7 +40,6 @@ RUN apt-get update && apt-get install -y \
createrepo \
curl \
dpkg-sig \
gcc-mingw-w64 \
git \
iptables \
libapparmor-dev \
@@ -128,7 +127,7 @@ RUN git clone https://github.com/golang/lint.git /go/src/github.com/golang/lint
RUN gem install --no-rdoc --no-ri fpm --version 1.3.2
# Install registry
ENV REGISTRY_COMMIT ec87e9b6971d831f0eff752ddb54fb64693e51cd
ENV REGISTRY_COMMIT 2317f721a3d8428215a2b65da4ae85212ed473b4
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
@@ -148,7 +147,7 @@ RUN set -x \
&& rm -rf "$GOPATH"
# Get the "docker-py" source so we can run their integration tests
ENV DOCKER_PY_COMMIT 139850f3f3b17357bab5ba3edfb745fb14043764
ENV DOCKER_PY_COMMIT 8a87001d09852058f08a807ab6e8491d57ca1e88
RUN git clone https://github.com/docker/docker-py.git /docker-py \
&& cd /docker-py \
&& git checkout -q $DOCKER_PY_COMMIT
+1 -1
View File
@@ -309,7 +309,7 @@ made through a pull request.
# - If the pull request has some small problems that need to be changed, make
# a comment adressing the issues.
# - If the changes needed to a PR are small, you can add a "LGTM once the
# following comments are addressed..." this will reduce needless back and
# following comments are adressed..." this will reduce needless back and
# forth.
# - If the PR only needs a few changes before being merged, any MAINTAINER can
# make a replacement PR that incorporates the existing commits and fixes the
+8 -13
View File
@@ -1,12 +1,12 @@
Docker: the container engine [![Release](https://img.shields.io/github/release/docker/docker.svg)](https://github.com/docker/docker/releases/latest)
============================
Docker: the Linux container engine
==================================
Docker is an open source project to pack, ship and run any application
as a lightweight container.
Docker containers are both *hardware-agnostic* and *platform-agnostic*.
This means they can run anywhere, from your laptop to the largest
cloud compute instance and everything in between - and they don't require
EC2 compute instance and everything in between - and they don't require
you to use a particular language, framework or packaging system. That
makes them great building blocks for deploying and scaling web apps,
databases, and backend services without depending on a particular stack
@@ -174,14 +174,13 @@ Under the hood, Docker is built on the following components:
capabilities of the Linux kernel
* The [Go](https://golang.org) programming language
* The [Docker Image Specification](https://github.com/docker/docker/blob/master/image/spec/v1.md)
* The [Libcontainer Specification](https://github.com/opencontainers/runc/blob/master/libcontainer/SPEC.md)
* The [Libcontainer Specification](https://github.com/docker/libcontainer/blob/master/SPEC.md)
Contributing to Docker [![GoDoc](https://godoc.org/github.com/docker/docker?status.svg)](https://godoc.org/github.com/docker/docker)
Contributing to Docker
======================
| **Master** (Linux) | **Experimental** (linux) | **Windows** | **FreeBSD** |
|------------------|----------------------|---------|---------|
| [![Jenkins Build Status](https://jenkins.dockerproject.org/view/Docker/job/Docker%20Master/badge/icon)](https://jenkins.dockerproject.org/view/Docker/job/Docker%20Master/) | [![Jenkins Build Status](https://jenkins.dockerproject.org/view/Docker/job/Docker%20Master%20%28experimental%29/badge/icon)](https://jenkins.dockerproject.org/view/Docker/job/Docker%20Master%20%28experimental%29/) | [![Build Status](http://jenkins.dockerproject.org/job/Docker%20Master%20(windows)/badge/icon)](http://jenkins.dockerproject.org/job/Docker%20Master%20(windows)/) | [![Build Status](http://jenkins.dockerproject.org/job/Docker%20Master%20(freebsd)/badge/icon)](http://jenkins.dockerproject.org/job/Docker%20Master%20(freebsd)/) |
[![GoDoc](https://godoc.org/github.com/docker/docker?status.svg)](https://godoc.org/github.com/docker/docker)
[![Jenkins Build Status](https://jenkins.dockerproject.org/job/Docker%20Master/badge/icon)](https://jenkins.dockerproject.org/job/Docker%20Master/)
Want to hack on Docker? Awesome! We have [instructions to help you get
started contributing code or documentation](https://docs.docker.com/project/who-written-for/).
@@ -248,7 +247,7 @@ We are always open to suggestions on process improvements, and are always lookin
<tr>
<td>Stack Overflow</td>
<td>
Stack Overflow has over 7000 Docker questions listed. We regularly
Stack Overflow has over 7000K Docker questions listed. We regularly
monitor <a href="https://stackoverflow.com/search?tab=newest&q=docker" target="_blank">Docker questions</a>
and so do many other knowledgeable Docker users.
</td>
@@ -294,7 +293,3 @@ Docker on Mac and Windows
If you know of another project underway that should be listed here, please help
us keep this list up-to-date by submitting a PR.
Awesome-Docker
==============
You can find more projects, tools and articles related to Docker on the [awesome-docker list](https://github.com/veggiemonk/awesome-docker). Add your project there.
+1 -1
View File
@@ -134,7 +134,7 @@ We won't accept patches expanding the surface of `docker exec`, which we intend
## 2.2 Dockerfile syntax
The Dockerfile syntax as we know it is simple, and has proven successful in supporting all our
The Dockerfile syntax as we know it is simple, and has proven succesful in supporting all our
[official images](https://github.com/docker-library/official-images). Although this is *not* a
definitive move, we temporarily won't accept more patches to the Dockerfile syntax for several
reasons:
+1 -1
View File
@@ -1 +1 @@
1.9.0-dev
1.8.1
+19
View File
@@ -0,0 +1,19 @@
package api
import (
"testing"
)
func TestJsonContentType(t *testing.T) {
if !MatchesContentType("application/json", "application/json") {
t.Fail()
}
if !MatchesContentType("application/json; charset=utf-8", "application/json") {
t.Fail()
}
if MatchesContentType("dockerapplication/json", "application/json") {
t.Fail()
}
}
+18 -41
View File
@@ -31,6 +31,7 @@ import (
"github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/progressreader"
"github.com/docker/docker/pkg/streamformatter"
"github.com/docker/docker/pkg/symlink"
"github.com/docker/docker/pkg/ulimit"
"github.com/docker/docker/pkg/units"
"github.com/docker/docker/pkg/urlutil"
@@ -59,8 +60,8 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
flMemoryString := cmd.String([]string{"m", "-memory"}, "", "Memory limit")
flMemorySwap := cmd.String([]string{"-memory-swap"}, "", "Total memory (memory + swap), '-1' to disable swap")
flCPUShares := cmd.Int64([]string{"c", "-cpu-shares"}, 0, "CPU shares (relative weight)")
flCPUPeriod := cmd.Int64([]string{"-cpu-period"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) period")
flCPUQuota := cmd.Int64([]string{"-cpu-quota"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) quota")
flCpuPeriod := cmd.Int64([]string{"-cpu-period"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) period")
flCpuQuota := cmd.Int64([]string{"-cpu-quota"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) quota")
flCPUSetCpus := cmd.String([]string{"-cpuset-cpus"}, "", "CPUs in which to allow execution (0-3, 0,1)")
flCPUSetMems := cmd.String([]string{"-cpuset-mems"}, "", "MEMs in which to allow execution (0-3, 0,1)")
flCgroupParent := cmd.String([]string{"-cgroup-parent"}, "", "Optional parent cgroup for the container")
@@ -242,8 +243,8 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
v.Set("cpusetcpus", *flCPUSetCpus)
v.Set("cpusetmems", *flCPUSetMems)
v.Set("cpushares", strconv.FormatInt(*flCPUShares, 10))
v.Set("cpuquota", strconv.FormatInt(*flCPUQuota, 10))
v.Set("cpuperiod", strconv.FormatInt(*flCPUPeriod, 10))
v.Set("cpuquota", strconv.FormatInt(*flCpuQuota, 10))
v.Set("cpuperiod", strconv.FormatInt(*flCpuPeriod, 10))
v.Set("memory", strconv.FormatInt(memory, 10))
v.Set("memswap", strconv.FormatInt(memorySwap, 10))
v.Set("cgroupparent", *flCgroupParent)
@@ -251,11 +252,11 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
v.Set("dockerfile", relDockerfile)
ulimitsVar := flUlimits.GetList()
ulimitsJSON, err := json.Marshal(ulimitsVar)
ulimitsJson, err := json.Marshal(ulimitsVar)
if err != nil {
return err
}
v.Set("ulimits", string(ulimitsJSON))
v.Set("ulimits", string(ulimitsJson))
headers := http.Header(make(map[string][]string))
buf, err := json.Marshal(cli.configFile.AuthConfigs)
@@ -307,12 +308,6 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
return nil
}
// isUNC returns true if the path is UNC (one starting \\). It always returns
// false on Linux.
func isUNC(path string) bool {
return runtime.GOOS == "windows" && strings.HasPrefix(path, `\\`)
}
// getDockerfileRelPath uses the given context directory for a `docker build`
// and returns the absolute path to the context directory, the relative path of
// the dockerfile in that context directory, and a non-nil error on success.
@@ -323,16 +318,9 @@ func getDockerfileRelPath(givenContextDir, givenDockerfile string) (absContextDi
// The context dir might be a symbolic link, so follow it to the actual
// target directory.
//
// FIXME. We use isUNC (always false on non-Windows platforms) to workaround
// an issue in golang. On Windows, EvalSymLinks does not work on UNC file
// paths (those starting with \\). This hack means that when using links
// on UNC paths, they will not be followed.
if !isUNC(absContextDir) {
absContextDir, err = filepath.EvalSymlinks(absContextDir)
if err != nil {
return "", "", fmt.Errorf("unable to evaluate symlinks in context path: %v", err)
}
absContextDir, err = filepath.EvalSymlinks(absContextDir)
if err != nil {
return "", "", fmt.Errorf("unable to evaluate symlinks in context path: %v", err)
}
stat, err := os.Lstat(absContextDir)
@@ -366,22 +354,15 @@ func getDockerfileRelPath(givenContextDir, givenDockerfile string) (absContextDi
absDockerfile = filepath.Join(absContextDir, absDockerfile)
}
// Evaluate symlinks in the path to the Dockerfile too.
//
// FIXME. We use isUNC (always false on non-Windows platforms) to workaround
// an issue in golang. On Windows, EvalSymLinks does not work on UNC file
// paths (those starting with \\). This hack means that when using links
// on UNC paths, they will not be followed.
if !isUNC(absDockerfile) {
absDockerfile, err = filepath.EvalSymlinks(absDockerfile)
if err != nil {
return "", "", fmt.Errorf("unable to evaluate symlinks in Dockerfile path: %v", err)
}
// Verify that 'filename' is within the build context
absDockerfile, err = symlink.FollowSymlinkInScope(absDockerfile, absContextDir)
if err != nil {
return "", "", fmt.Errorf("The Dockerfile (%s) must be within the build context (%s)", givenDockerfile, givenContextDir)
}
if _, err := os.Lstat(absDockerfile); err != nil {
if os.IsNotExist(err) {
return "", "", fmt.Errorf("Cannot locate Dockerfile: %q", absDockerfile)
return "", "", fmt.Errorf("Cannot locate Dockerfile: absDockerfile: %q", absDockerfile)
}
return "", "", fmt.Errorf("unable to stat Dockerfile: %v", err)
}
@@ -390,10 +371,6 @@ func getDockerfileRelPath(givenContextDir, givenDockerfile string) (absContextDi
return "", "", fmt.Errorf("unable to get relative Dockerfile path: %v", err)
}
if strings.HasPrefix(relDockerfile, ".."+string(filepath.Separator)) {
return "", "", fmt.Errorf("The Dockerfile (%s) must be within the build context (%s)", givenDockerfile, givenContextDir)
}
return absContextDir, relDockerfile, nil
}
@@ -445,7 +422,7 @@ func getContextFromReader(r io.Reader, dockerfileName string) (absContextDir, re
}
if err := archive.Untar(buf, absContextDir, nil); err != nil {
return "", "", fmt.Errorf("unable to extract stdin to temporary context directory: %v", err)
return "", "", fmt.Errorf("unable to extract stdin to temporary context direcotry: %v", err)
}
return getDockerfileRelPath(absContextDir, dockerfileName)
@@ -482,7 +459,7 @@ func getContextFromURL(out io.Writer, remoteURL, dockerfileName string) (absCont
In: response.Body,
Out: out,
Formatter: streamformatter.NewStreamFormatter(),
Size: response.ContentLength,
Size: int(response.ContentLength),
NewLines: true,
ID: "",
Action: fmt.Sprintf("Downloading build context from remote url: %s", remoteURL),
@@ -567,7 +544,7 @@ func rewriteDockerfileFrom(dockerfileName string, translator func(string, regist
// Replace the line with a resolved "FROM repo@digest"
repo, tag := parsers.ParseRepositoryTag(matches[1])
if tag == "" {
tag = tags.DefaultTag
tag = tags.DEFAULTTAG
}
repoInfo, err := registry.ParseRepositoryInfo(repo)
-5
View File
@@ -58,8 +58,6 @@ type DockerCli struct {
transport *http.Transport
}
// Initialize calls the init function that will setup the configuration for the client
// such as the TLS, tcp and other parameters used to run the client.
func (cli *DockerCli) Initialize() error {
if cli.init == nil {
return nil
@@ -79,8 +77,6 @@ func (cli *DockerCli) CheckTtyInput(attachStdin, ttyMode bool) error {
return nil
}
// PsFormat returns the format string specified in the configuration.
// String contains columns and format specification, for example {{ID}\t{{Name}}.
func (cli *DockerCli) PsFormat() string {
return cli.configFile.PsFormat
}
@@ -98,7 +94,6 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientFlags *cli.ClientF
}
cli.init = func() error {
clientFlags.PostParse()
hosts := clientFlags.Common.Hosts
+2 -3
View File
@@ -15,7 +15,6 @@ import (
Cli "github.com/docker/docker/cli"
"github.com/docker/docker/pkg/archive"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/system"
)
type copyDirection int
@@ -102,7 +101,7 @@ func (cli *DockerCli) CmdCp(args ...string) error {
// client, a `:` could be part of an absolute Windows path, in which case it
// is immediately proceeded by a backslash.
func splitCpArg(arg string) (container, path string) {
if system.IsAbs(arg) {
if filepath.IsAbs(arg) {
// Explicit local absolute path, e.g., `C:\foo` or `/foo`.
return "", arg
}
@@ -237,7 +236,7 @@ func (cli *DockerCli) copyToContainer(srcPath, dstContainer, dstPath string) (er
// If the destination is a symbolic link, we should evaluate it.
if err == nil && dstStat.Mode&os.ModeSymlink != 0 {
linkTarget := dstStat.LinkTarget
if !system.IsAbs(linkTarget) {
if !filepath.IsAbs(linkTarget) {
// Join with the parent directory.
dstParent, _ := archive.SplitPathDirEntry(dstPath)
linkTarget = filepath.Join(dstParent, linkTarget)
+2 -2
View File
@@ -26,7 +26,7 @@ func (cli *DockerCli) pullImageCustomOut(image string, out io.Writer) error {
repos, tag := parsers.ParseRepositoryTag(image)
// pull only the image tagged 'latest' if no tag was specified
if tag == "" {
tag = tags.DefaultTag
tag = tags.DEFAULTTAG
}
v.Set("fromImage", repos)
v.Set("tag", tag)
@@ -96,7 +96,7 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc
repo, tag := parsers.ParseRepositoryTag(config.Image)
if tag == "" {
tag = tags.DefaultTag
tag = tags.DEFAULTTAG
}
ref := registry.ParseReference(tag)
+2 -1
View File
@@ -2,6 +2,7 @@ package client
import (
"errors"
"io"
"os"
Cli "github.com/docker/docker/cli"
@@ -21,7 +22,7 @@ func (cli *DockerCli) CmdExport(args ...string) error {
cmd.ParseFlags(args, true)
var (
output = cli.out
output io.Writer = cli.out
err error
)
if *outfile != "" {
+1 -1
View File
@@ -167,7 +167,7 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
}
if err != nil {
if strings.Contains(err.Error(), "connection refused") {
return fmt.Errorf("Cannot connect to the Docker daemon. Is 'docker daemon' running on this host?")
return fmt.Errorf("Cannot connect to the Docker daemon. Is 'docker -d' running on this host?")
}
return err
}
+1 -1
View File
@@ -22,7 +22,7 @@ import (
//
// Usage: docker images [OPTIONS] [REPOSITORY]
func (cli *DockerCli) CmdImages(args ...string) error {
cmd := Cli.Subcmd("images", []string{"[REPOSITORY[:TAG]]"}, "List images", true)
cmd := Cli.Subcmd("images", []string{"[REPOSITORY]"}, "List images", true)
quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
all := cmd.Bool([]string{"a", "-all"}, false, "Show all images (default hides intermediate images)")
noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
-2
View File
@@ -23,7 +23,6 @@ func (cli *DockerCli) CmdImport(args ...string) error {
cmd := Cli.Subcmd("import", []string{"file|URL|- [REPOSITORY[:TAG]]"}, "Create an empty filesystem image and import the contents of the\ntarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then\noptionally tag it.", true)
flChanges := opts.NewListOpts(nil)
cmd.Var(&flChanges, []string{"c", "-change"}, "Apply Dockerfile instruction to the created image")
message := cmd.String([]string{"m", "-message"}, "", "Set commit message for imported image")
cmd.Require(flag.Min, 1)
cmd.ParseFlags(args, true)
@@ -36,7 +35,6 @@ func (cli *DockerCli) CmdImport(args ...string) error {
v.Set("fromSrc", src)
v.Set("repo", repository)
v.Set("message", *message)
for _, change := range flChanges.GetAll() {
v.Add("changes", change)
}
+4 -4
View File
@@ -61,8 +61,8 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
fmt.Fprintf(cli.out, "Docker Root Dir: %s\n", info.DockerRootDir)
}
ioutils.FprintfIfNotEmpty(cli.out, "Http Proxy: %s\n", info.HTTPProxy)
ioutils.FprintfIfNotEmpty(cli.out, "Https Proxy: %s\n", info.HTTPSProxy)
ioutils.FprintfIfNotEmpty(cli.out, "Http Proxy: %s\n", info.HttpProxy)
ioutils.FprintfIfNotEmpty(cli.out, "Https Proxy: %s\n", info.HttpsProxy)
ioutils.FprintfIfNotEmpty(cli.out, "No Proxy: %s\n", info.NoProxy)
if info.IndexServerAddress != "" {
@@ -82,12 +82,12 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
fmt.Fprintf(cli.err, "WARNING: No swap limit support\n")
}
if !info.IPv4Forwarding {
fmt.Fprintf(cli.err, "WARNING: IPv4 forwarding is disabled\n")
fmt.Fprintf(cli.err, "WARNING: IPv4 forwarding is disabled.\n")
}
if !info.BridgeNfIptables {
fmt.Fprintf(cli.err, "WARNING: bridge-nf-call-iptables is disabled\n")
}
if !info.BridgeNfIP6tables {
if !info.BridgeNfIp6tables {
fmt.Fprintf(cli.err, "WARNING: bridge-nf-call-ip6tables is disabled\n")
}
}
+6 -7
View File
@@ -26,14 +26,13 @@ func (cli *DockerCli) CmdLogout(args ...string) error {
if _, ok := cli.configFile.AuthConfigs[serverAddress]; !ok {
fmt.Fprintf(cli.out, "Not logged in to %s\n", serverAddress)
return nil
}
} else {
fmt.Fprintf(cli.out, "Remove login credentials for %s\n", serverAddress)
delete(cli.configFile.AuthConfigs, serverAddress)
fmt.Fprintf(cli.out, "Remove login credentials for %s\n", serverAddress)
delete(cli.configFile.AuthConfigs, serverAddress)
if err := cli.configFile.Save(); err != nil {
return fmt.Errorf("Failed to save docker config: %v", err)
if err := cli.configFile.Save(); err != nil {
return fmt.Errorf("Failed to save docker config: %v", err)
}
}
return nil
}
-1
View File
@@ -8,7 +8,6 @@ import (
nwclient "github.com/docker/libnetwork/client"
)
// CmdNetwork is used to create, display and configure network endpoints.
func (cli *DockerCli) CmdNetwork(args ...string) error {
nCli := nwclient.NewNetworkCli(cli.out, cli.err, nwclient.CallFunc(cli.callWrapper))
args = append([]string{"network"}, args...)
+1 -1
View File
@@ -95,7 +95,7 @@ func (cli *DockerCli) CmdPs(args ...string) error {
f := *format
if len(f) == 0 {
if len(cli.PsFormat()) > 0 && !*quiet {
if len(cli.PsFormat()) > 0 {
f = cli.PsFormat()
} else {
f = "table"
-3
View File
@@ -64,9 +64,6 @@ func (c *containerContext) Image() string {
if c.c.Image == "" {
return "<no image>"
}
if c.trunc {
return stringutils.Truncate(c.c.Image, 12)
}
return c.c.Image
}
+3 -3
View File
@@ -12,7 +12,7 @@ import (
)
func TestContainerPsContext(t *testing.T) {
containerID := stringid.GenerateRandomID()
containerId := stringid.GenerateRandomID()
unix := time.Now().Unix()
var ctx containerContext
@@ -23,12 +23,12 @@ func TestContainerPsContext(t *testing.T) {
expHeader string
call func() string
}{
{types.Container{ID: containerID}, true, stringid.TruncateID(containerID), idHeader, ctx.ID},
{types.Container{ID: containerId}, true, stringid.TruncateID(containerId), idHeader, ctx.ID},
{types.Container{Names: []string{"/foobar_baz"}}, true, "foobar_baz", namesHeader, ctx.Names},
{types.Container{Image: "ubuntu"}, true, "ubuntu", imageHeader, ctx.Image},
{types.Container{Image: ""}, true, "<no image>", imageHeader, ctx.Image},
{types.Container{Command: "sh -c 'ls -la'"}, true, `"sh -c 'ls -la'"`, commandHeader, ctx.Command},
{types.Container{Created: unix}, true, time.Unix(unix, 0).String(), createdAtHeader, ctx.CreatedAt},
{types.Container{Created: int(unix)}, true, time.Unix(unix, 0).String(), createdAtHeader, ctx.CreatedAt},
{types.Container{Ports: []types.Port{{PrivatePort: 8080, PublicPort: 8080, Type: "tcp"}}}, true, "8080/tcp", portsHeader, ctx.Ports},
{types.Container{Status: "RUNNING"}, true, "RUNNING", statusHeader, ctx.Status},
{types.Container{SizeRw: 10}, true, "10 B", sizeHeader, ctx.Size},
+3 -11
View File
@@ -14,22 +14,14 @@ const (
defaultQuietFormat = "{{.ID}}"
)
// Context contains information required by the formatter to print the output as desired.
type Context struct {
// Output is the output stream to which the formatted string is written.
Output io.Writer
// Format is used to choose raw, table or custom format for the output.
Format string
// Size when set to true will display the size of the output.
Size bool
// Quiet when set to true will simply print minimal information.
Quiet bool
// Trunc when set to true will truncate the output of certain fields such as Container ID.
Trunc bool
Size bool
Quiet bool
Trunc bool
}
// Format helps to format the output using the parameters set in the Context.
// Currently Format allow to display in raw, table or custom format the output.
func Format(ctx Context, containers []types.Container) {
switch ctx.Format {
case tableFormatKey:
+1 -1
View File
@@ -25,7 +25,7 @@ func (cli *DockerCli) CmdPull(args ...string) error {
taglessRemote, tag := parsers.ParseRepositoryTag(remote)
if tag == "" && !*allTags {
tag = tags.DefaultTag
tag = tags.DEFAULTTAG
fmt.Fprintf(cli.out, "Using default tag: %s\n", tag)
} else if tag != "" && *allTags {
return fmt.Errorf("tag can't be used with --all-tags/-a")
+1 -1
View File
@@ -11,7 +11,7 @@ import (
// CmdRestart restarts one or more running containers.
//
// Usage: docker restart [OPTIONS] CONTAINER [CONTAINER...]
// Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...]
func (cli *DockerCli) CmdRestart(args ...string) error {
cmd := Cli.Subcmd("restart", []string{"CONTAINER [CONTAINER...]"}, "Restart a running container", true)
nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Seconds to wait for stop before killing the container")
+2 -2
View File
@@ -63,11 +63,11 @@ func (cli *DockerCli) CmdRun(args ...string) error {
os.Exit(1)
}
if len(hostConfig.DNS) > 0 {
if len(hostConfig.Dns) > 0 {
// check the DNS settings passed via --dns against
// localhost regexp to warn if they are trying to
// set a DNS to a localhost address
for _, dnsIP := range hostConfig.DNS {
for _, dnsIP := range hostConfig.Dns {
if dns.IsLocalhost(dnsIP) {
fmt.Fprintf(cli.err, "WARNING: Localhost DNS setting (--dns=%s) may fail in containers.\n", dnsIP)
break
+3 -2
View File
@@ -2,6 +2,7 @@ package client
import (
"errors"
"io"
"net/url"
"os"
@@ -16,13 +17,13 @@ import (
// Usage: docker save [OPTIONS] IMAGE [IMAGE...]
func (cli *DockerCli) CmdSave(args ...string) error {
cmd := Cli.Subcmd("save", []string{"IMAGE [IMAGE...]"}, "Save an image(s) to a tar archive (streamed to STDOUT by default)", true)
outfile := cmd.String([]string{"o", "-output"}, "", "Write to a file, instead of STDOUT")
outfile := cmd.String([]string{"o", "-output"}, "", "Write to an file, instead of STDOUT")
cmd.Require(flag.Min, 1)
cmd.ParseFlags(args, true)
var (
output = cli.out
output io.Writer = cli.out
err error
)
if *outfile != "" {
-2
View File
@@ -8,8 +8,6 @@ import (
nwclient "github.com/docker/libnetwork/client"
)
// CmdService is used to manage network services.
// service command is user to publish, attach and list a service from a container.
func (cli *DockerCli) CmdService(args ...string) error {
nCli := nwclient.NewNetworkCli(cli.out, cli.err, nwclient.CallFunc(cli.callWrapper))
args = append([]string{"service"}, args...)
+8 -26
View File
@@ -25,8 +25,6 @@ type containerStats struct {
MemoryPercentage float64
NetworkRx float64
NetworkTx float64
BlockRead float64
BlockWrite float64
mu sync.RWMutex
err error
}
@@ -65,10 +63,9 @@ func (s *containerStats) Collect(cli *DockerCli, streamStats bool) {
memPercent = float64(v.MemoryStats.Usage) / float64(v.MemoryStats.Limit) * 100.0
cpuPercent = 0.0
)
previousCPU = v.PreCPUStats.CPUUsage.TotalUsage
previousSystem = v.PreCPUStats.SystemUsage
previousCPU = v.PreCpuStats.CpuUsage.TotalUsage
previousSystem = v.PreCpuStats.SystemUsage
cpuPercent = calculateCPUPercent(previousCPU, previousSystem, v)
blkRead, blkWrite := calculateBlockIO(v.BlkioStats)
s.mu.Lock()
s.CPUPercentage = cpuPercent
s.Memory = float64(v.MemoryStats.Usage)
@@ -76,8 +73,6 @@ func (s *containerStats) Collect(cli *DockerCli, streamStats bool) {
s.MemoryPercentage = memPercent
s.NetworkRx = float64(v.Network.RxBytes)
s.NetworkTx = float64(v.Network.TxBytes)
s.BlockRead = float64(blkRead)
s.BlockWrite = float64(blkWrite)
s.mu.Unlock()
u <- nil
if !streamStats {
@@ -115,13 +110,12 @@ func (s *containerStats) Display(w io.Writer) error {
if s.err != nil {
return s.err
}
fmt.Fprintf(w, "%s\t%.2f%%\t%s / %s\t%.2f%%\t%s / %s\t%s / %s\n",
fmt.Fprintf(w, "%s\t%.2f%%\t%s/%s\t%.2f%%\t%s/%s\n",
s.Name,
s.CPUPercentage,
units.HumanSize(s.Memory), units.HumanSize(s.MemoryLimit),
s.MemoryPercentage,
units.HumanSize(s.NetworkRx), units.HumanSize(s.NetworkTx),
units.HumanSize(s.BlockRead), units.HumanSize(s.BlockWrite))
units.HumanSize(s.NetworkRx), units.HumanSize(s.NetworkTx))
return nil
}
@@ -148,7 +142,7 @@ func (cli *DockerCli) CmdStats(args ...string) error {
fmt.Fprint(cli.out, "\033[2J")
fmt.Fprint(cli.out, "\033[H")
}
io.WriteString(w, "CONTAINER\tCPU %\tMEM USAGE / LIMIT\tMEM %\tNET I/O\tBLOCK I/O\n")
io.WriteString(w, "CONTAINER\tCPU %\tMEM USAGE/LIMIT\tMEM %\tNET I/O\n")
}
for _, n := range names {
s := &containerStats{Name: n}
@@ -196,25 +190,13 @@ func calculateCPUPercent(previousCPU, previousSystem uint64, v *types.Stats) flo
var (
cpuPercent = 0.0
// calculate the change for the cpu usage of the container in between readings
cpuDelta = float64(v.CPUStats.CPUUsage.TotalUsage - previousCPU)
cpuDelta = float64(v.CpuStats.CpuUsage.TotalUsage - previousCPU)
// calculate the change for the entire system between readings
systemDelta = float64(v.CPUStats.SystemUsage - previousSystem)
systemDelta = float64(v.CpuStats.SystemUsage - previousSystem)
)
if systemDelta > 0.0 && cpuDelta > 0.0 {
cpuPercent = (cpuDelta / systemDelta) * float64(len(v.CPUStats.CPUUsage.PercpuUsage)) * 100.0
cpuPercent = (cpuDelta / systemDelta) * float64(len(v.CpuStats.CpuUsage.PercpuUsage)) * 100.0
}
return cpuPercent
}
func calculateBlockIO(blkio types.BlkioStats) (blkRead uint64, blkWrite uint64) {
for _, bioEntry := range blkio.IoServiceBytesRecursive {
switch strings.ToLower(bioEntry.Op) {
case "read":
blkRead = blkRead + bioEntry.Value
case "write":
blkWrite = blkWrite + bioEntry.Value
}
}
return
}
+1 -18
View File
@@ -4,8 +4,6 @@ import (
"bytes"
"sync"
"testing"
"github.com/docker/docker/api/types"
)
func TestDisplay(t *testing.T) {
@@ -17,8 +15,6 @@ func TestDisplay(t *testing.T) {
MemoryPercentage: 100.0 / 2048.0 * 100.0,
NetworkRx: 100 * 1024 * 1024,
NetworkTx: 800 * 1024 * 1024,
BlockRead: 100 * 1024 * 1024,
BlockWrite: 800 * 1024 * 1024,
mu: sync.RWMutex{},
}
var b bytes.Buffer
@@ -26,21 +22,8 @@ func TestDisplay(t *testing.T) {
t.Fatalf("c.Display() gave error: %s", err)
}
got := b.String()
want := "app\t30.00%\t104.9 MB / 2.147 GB\t4.88%\t104.9 MB / 838.9 MB\t104.9 MB / 838.9 MB\n"
want := "app\t30.00%\t104.9 MB/2.147 GB\t4.88%\t104.9 MB/838.9 MB\n"
if got != want {
t.Fatalf("c.Display() = %q, want %q", got, want)
}
}
func TestCalculBlockIO(t *testing.T) {
blkio := types.BlkioStats{
IoServiceBytesRecursive: []types.BlkioStatEntry{{8, 0, "read", 1234}, {8, 1, "read", 4567}, {8, 0, "write", 123}, {8, 1, "write", 456}},
}
blkRead, blkWrite := calculateBlockIO(blkio)
if blkRead != 5801 {
t.Fatalf("blkRead = %d, want 5801", blkRead)
}
if blkWrite != 579 {
t.Fatalf("blkWrite = %d, want 579", blkWrite)
}
}
+39 -43
View File
@@ -30,7 +30,7 @@ import (
)
var (
errConnectionFailed = errors.New("Cannot connect to the Docker daemon. Is the docker daemon running on this host?")
errConnectionRefused = errors.New("Cannot connect to the Docker daemon. Is 'docker -d' running on this host?")
)
type serverResponse struct {
@@ -94,14 +94,13 @@ func (cli *DockerCli) clientRequest(method, path string, in io.Reader, headers m
if resp != nil {
serverResp.statusCode = resp.StatusCode
}
if err != nil {
if types.IsTimeout(err) || strings.Contains(err.Error(), "connection refused") || strings.Contains(err.Error(), "dial unix") {
return serverResp, errConnectionFailed
if strings.Contains(err.Error(), "connection refused") {
return serverResp, errConnectionRefused
}
if cli.tlsConfig == nil && strings.Contains(err.Error(), "malformed HTTP response") {
return serverResp, fmt.Errorf("%v.\n* Are you trying to connect to a TLS-enabled daemon without TLS?", err)
if cli.tlsConfig == nil {
return serverResp, fmt.Errorf("%v.\n* Are you trying to connect to a TLS-enabled daemon without TLS?\n* Is your docker daemon up and running?", err)
}
if cli.tlsConfig != nil && strings.Contains(err.Error(), "remote error: bad certificate") {
return serverResp, fmt.Errorf("The server probably has client authentication (--tlsverify) enabled. Please check your TLS client certification settings: %v", err)
@@ -126,51 +125,48 @@ func (cli *DockerCli) clientRequest(method, path string, in io.Reader, headers m
return serverResp, nil
}
// cmdAttempt builds the corresponding registry Auth Header from the given
// authConfig. It returns the servers body, status, error response
func (cli *DockerCli) cmdAttempt(authConfig cliconfig.AuthConfig, method, path string, in io.Reader, out io.Writer) (io.ReadCloser, int, error) {
buf, err := json.Marshal(authConfig)
if err != nil {
return nil, -1, err
}
registryAuthHeader := []string{
base64.URLEncoding.EncodeToString(buf),
}
// begin the request
serverResp, err := cli.clientRequest(method, path, in, map[string][]string{
"X-Registry-Auth": registryAuthHeader,
})
if err == nil && out != nil {
// If we are streaming output, complete the stream since
// errors may not appear until later.
err = cli.streamBody(serverResp.body, serverResp.header.Get("Content-Type"), true, out, nil)
}
if err != nil {
// Since errors in a stream appear after status 200 has been written,
// we may need to change the status code.
if strings.Contains(err.Error(), "Authentication is required") ||
strings.Contains(err.Error(), "Status 401") ||
strings.Contains(err.Error(), "401 Unauthorized") ||
strings.Contains(err.Error(), "status code 401") {
serverResp.statusCode = http.StatusUnauthorized
}
}
return serverResp.body, serverResp.statusCode, err
}
func (cli *DockerCli) clientRequestAttemptLogin(method, path string, in io.Reader, out io.Writer, index *registry.IndexInfo, cmdName string) (io.ReadCloser, int, error) {
cmdAttempt := func(authConfig cliconfig.AuthConfig) (io.ReadCloser, int, error) {
buf, err := json.Marshal(authConfig)
if err != nil {
return nil, -1, err
}
registryAuthHeader := []string{
base64.URLEncoding.EncodeToString(buf),
}
// begin the request
serverResp, err := cli.clientRequest(method, path, in, map[string][]string{
"X-Registry-Auth": registryAuthHeader,
})
if err == nil && out != nil {
// If we are streaming output, complete the stream since
// errors may not appear until later.
err = cli.streamBody(serverResp.body, serverResp.header.Get("Content-Type"), true, out, nil)
}
if err != nil {
// Since errors in a stream appear after status 200 has been written,
// we may need to change the status code.
if strings.Contains(err.Error(), "Authentication is required") ||
strings.Contains(err.Error(), "Status 401") ||
strings.Contains(err.Error(), "401 Unauthorized") ||
strings.Contains(err.Error(), "status code 401") {
serverResp.statusCode = http.StatusUnauthorized
}
}
return serverResp.body, serverResp.statusCode, err
}
// Resolve the Auth config relevant for this server
authConfig := registry.ResolveAuthConfig(cli.configFile, index)
body, statusCode, err := cli.cmdAttempt(authConfig, method, path, in, out)
body, statusCode, err := cmdAttempt(authConfig)
if statusCode == http.StatusUnauthorized {
fmt.Fprintf(cli.out, "\nPlease login prior to %s:\n", cmdName)
if err = cli.CmdLogin(index.GetAuthConfigKey()); err != nil {
return nil, -1, err
}
authConfig = registry.ResolveAuthConfig(cli.configFile, index)
return cli.cmdAttempt(authConfig, method, path, in, out)
return cmdAttempt(authConfig)
}
return body, statusCode, err
}
@@ -281,7 +277,7 @@ func getExitCode(cli *DockerCli, containerID string) (bool, int, error) {
serverResp, err := cli.call("GET", "/containers/"+containerID+"/json", nil, nil)
if err != nil {
// If we can't connect, then the daemon probably died.
if err != errConnectionFailed {
if err != errConnectionRefused {
return false, -1, err
}
return false, -1, nil
@@ -303,7 +299,7 @@ func getExecExitCode(cli *DockerCli, execID string) (bool, int, error) {
serverResp, err := cli.call("GET", "/exec/"+execID+"/json", nil, nil)
if err != nil {
// If we can't connect, then the daemon probably died.
if err != errConnectionFailed {
if err != errConnectionRefused {
return false, -1, err
}
return false, -1, nil
+7 -7
View File
@@ -13,9 +13,9 @@ import (
"github.com/docker/docker/utils"
)
var versionTemplate = `Client:
var VersionTemplate = `Client:
Version: {{.Client.Version}}
API version: {{.Client.APIVersion}}
API version: {{.Client.ApiVersion}}
Go version: {{.Client.GoVersion}}
Git commit: {{.Client.GitCommit}}
Built: {{.Client.BuildTime}}
@@ -24,14 +24,14 @@ var versionTemplate = `Client:
Server:
Version: {{.Server.Version}}
API version: {{.Server.APIVersion}}
API version: {{.Server.ApiVersion}}
Go version: {{.Server.GoVersion}}
Git commit: {{.Server.GitCommit}}
Built: {{.Server.BuildTime}}
OS/Arch: {{.Server.Os}}/{{.Server.Arch}}{{if .Server.Experimental}}
Experimental: {{.Server.Experimental}}{{end}}{{end}}`
type versionData struct {
type VersionData struct {
Client types.Version
ServerOK bool
Server types.Version
@@ -49,7 +49,7 @@ func (cli *DockerCli) CmdVersion(args ...string) (err error) {
cmd.ParseFlags(args, true)
if *tmplStr == "" {
*tmplStr = versionTemplate
*tmplStr = VersionTemplate
}
var tmpl *template.Template
@@ -58,10 +58,10 @@ func (cli *DockerCli) CmdVersion(args ...string) (err error) {
Status: "Template parsing error: " + err.Error()}
}
vd := versionData{
vd := VersionData{
Client: types.Version{
Version: dockerversion.VERSION,
APIVersion: api.Version,
ApiVersion: api.Version,
GoVersion: runtime.Version(),
GitCommit: dockerversion.GITCOMMIT,
BuildTime: dockerversion.BUILDTIME,
-232
View File
@@ -1,232 +0,0 @@
package client
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/url"
"text/tabwriter"
"text/template"
"github.com/docker/docker/api/types"
Cli "github.com/docker/docker/cli"
"github.com/docker/docker/opts"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/parsers/filters"
)
// CmdVolume is the parent subcommand for all volume commands
//
// Usage: docker volume <COMMAND> <OPTS>
func (cli *DockerCli) CmdVolume(args ...string) error {
description := "Manage Docker volumes\n\nCommands:\n"
commands := [][]string{
{"create", "Create a volume"},
{"inspect", "Return low-level information on a volume"},
{"ls", "List volumes"},
{"rm", "Remove a volume"},
}
for _, cmd := range commands {
description += fmt.Sprintf(" %-25.25s%s\n", cmd[0], cmd[1])
}
description += "\nRun 'docker volume COMMAND --help' for more information on a command."
cmd := Cli.Subcmd("volume", []string{"[COMMAND]"}, description, true)
cmd.Require(flag.Exact, 0)
cmd.ParseFlags(args, true)
return cli.CmdVolumeLs(args...)
}
// CmdVolumeLs outputs a list of Docker volumes.
//
// Usage: docker volume ls [OPTIONS]
func (cli *DockerCli) CmdVolumeLs(args ...string) error {
cmd := Cli.Subcmd("volume ls", nil, "List volumes", true)
quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display volume names")
flFilter := opts.NewListOpts(nil)
cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'dangling=true')")
cmd.Require(flag.Exact, 0)
cmd.ParseFlags(args, true)
volFilterArgs := filters.Args{}
for _, f := range flFilter.GetAll() {
var err error
volFilterArgs, err = filters.ParseFlag(f, volFilterArgs)
if err != nil {
return err
}
}
v := url.Values{}
if len(volFilterArgs) > 0 {
filterJSON, err := filters.ToParam(volFilterArgs)
if err != nil {
return err
}
v.Set("filters", filterJSON)
}
resp, err := cli.call("GET", "/volumes?"+v.Encode(), nil, nil)
if err != nil {
return err
}
var volumes types.VolumesListResponse
if err := json.NewDecoder(resp.body).Decode(&volumes); err != nil {
return err
}
w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
if !*quiet {
fmt.Fprintf(w, "DRIVER \tVOLUME NAME")
fmt.Fprintf(w, "\n")
}
for _, vol := range volumes.Volumes {
if *quiet {
fmt.Fprintln(w, vol.Name)
continue
}
fmt.Fprintf(w, "%s\t%s\n", vol.Driver, vol.Name)
}
w.Flush()
return nil
}
// CmdVolumeInspect displays low-level information on one or more volumes.
//
// Usage: docker volume inspect [OPTIONS] VOLUME [VOLUME...]
func (cli *DockerCli) CmdVolumeInspect(args ...string) error {
cmd := Cli.Subcmd("volume inspect", []string{"[VOLUME NAME]"}, "Return low-level information on a volume", true)
tmplStr := cmd.String([]string{"f", "-format"}, "", "Format the output using the given go template.")
if err := cmd.Parse(args); err != nil {
return nil
}
cmd.Require(flag.Min, 1)
cmd.ParseFlags(args, true)
var tmpl *template.Template
if *tmplStr != "" {
var err error
tmpl, err = template.New("").Funcs(funcMap).Parse(*tmplStr)
if err != nil {
return err
}
}
var status = 0
var volumes []*types.Volume
for _, name := range cmd.Args() {
resp, err := cli.call("GET", "/volumes/"+name, nil, nil)
if err != nil {
return err
}
var volume types.Volume
if err := json.NewDecoder(resp.body).Decode(&volume); err != nil {
fmt.Fprintf(cli.err, "%s\n", err)
status = 1
continue
}
if tmpl == nil {
volumes = append(volumes, &volume)
continue
}
if err := tmpl.Execute(cli.out, &volume); err != nil {
if err := tmpl.Execute(cli.out, &volume); err != nil {
fmt.Fprintf(cli.err, "%s\n", err)
status = 1
continue
}
}
io.WriteString(cli.out, "\n")
}
if tmpl != nil {
return nil
}
b, err := json.MarshalIndent(volumes, "", " ")
if err != nil {
return err
}
_, err = io.Copy(cli.out, bytes.NewReader(b))
if err != nil {
return err
}
io.WriteString(cli.out, "\n")
if status != 0 {
return Cli.StatusError{StatusCode: status}
}
return nil
}
// CmdVolumeCreate creates a new container from a given image.
//
// Usage: docker volume create [OPTIONS]
func (cli *DockerCli) CmdVolumeCreate(args ...string) error {
cmd := Cli.Subcmd("volume create", nil, "Create a volume", true)
flDriver := cmd.String([]string{"d", "-driver"}, "local", "Specify volume driver name")
flName := cmd.String([]string{"-name"}, "", "Specify volume name")
flDriverOpts := opts.NewMapOpts(nil, nil)
cmd.Var(flDriverOpts, []string{"o", "-opt"}, "Set driver specific options")
cmd.Require(flag.Exact, 0)
cmd.ParseFlags(args, true)
volReq := &types.VolumeCreateRequest{
Driver: *flDriver,
DriverOpts: flDriverOpts.GetAll(),
}
if *flName != "" {
volReq.Name = *flName
}
resp, err := cli.call("POST", "/volumes", volReq, nil)
if err != nil {
return err
}
var vol types.Volume
if err := json.NewDecoder(resp.body).Decode(&vol); err != nil {
return err
}
fmt.Fprintf(cli.out, "%s\n", vol.Name)
return nil
}
// CmdVolumeRm removes one or more containers.
//
// Usage: docker volume rm VOLUME [VOLUME...]
func (cli *DockerCli) CmdVolumeRm(args ...string) error {
cmd := Cli.Subcmd("volume rm", []string{"[NAME]"}, "Remove a volume", true)
cmd.Require(flag.Min, 1)
cmd.ParseFlags(args, true)
var status = 0
for _, name := range cmd.Args() {
_, err := cli.call("DELETE", "/volumes/"+name, nil, nil)
if err != nil {
fmt.Fprintf(cli.err, "%s\n", err)
status = 1
continue
}
fmt.Fprintf(cli.out, "%s\n", name)
}
if status != 0 {
return Cli.StatusError{StatusCode: status}
}
return nil
}
+12 -17
View File
@@ -16,26 +16,22 @@ import (
// Common constants for daemon and client.
const (
// Version of Current REST API
Version version.Version = "1.21"
// Current REST API version
Version version.Version = "1.20"
// MinVersion represents Minimun REST API version supported
// Minimun REST API version supported
MinVersion version.Version = "1.12"
// DefaultDockerfileName is the Default filename with Docker commands, read by docker build
// Default filename with Docker commands, read by docker build
DefaultDockerfileName string = "Dockerfile"
)
// byPrivatePort is temporary type used to sort types.Port by PrivatePort
type byPrivatePort []types.Port
type ByPrivatePort []types.Port
func (r byPrivatePort) Len() int { return len(r) }
func (r byPrivatePort) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
func (r byPrivatePort) Less(i, j int) bool { return r[i].PrivatePort < r[j].PrivatePort }
func (r ByPrivatePort) Len() int { return len(r) }
func (r ByPrivatePort) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
func (r ByPrivatePort) Less(i, j int) bool { return r[i].PrivatePort < r[j].PrivatePort }
// DisplayablePorts returns formatted string representing open ports of container
// e.g. "0.0.0.0:80->9090/tcp, 9988/tcp"
// it's used by command 'docker ps'
func DisplayablePorts(ports []types.Port) string {
var (
result = []string{}
@@ -45,7 +41,7 @@ func DisplayablePorts(ports []types.Port) string {
)
firstInGroupMap = make(map[string]int)
lastInGroupMap = make(map[string]int)
sort.Sort(byPrivatePort(ports))
sort.Sort(ByPrivatePort(ports))
for _, port := range ports {
var (
current = port.PrivatePort
@@ -73,18 +69,18 @@ func DisplayablePorts(ports []types.Port) string {
lastInGroupMap[portKey] = current
continue
}
result = append(result, formGroup(portKey, firstInGroup, lastInGroup))
result = append(result, FormGroup(portKey, firstInGroup, lastInGroup))
firstInGroupMap[portKey] = current
lastInGroupMap[portKey] = current
}
for portKey, firstInGroup := range firstInGroupMap {
result = append(result, formGroup(portKey, firstInGroup, lastInGroupMap[portKey]))
result = append(result, FormGroup(portKey, firstInGroup, lastInGroupMap[portKey]))
}
result = append(result, hostMappings...)
return strings.Join(result, ", ")
}
func formGroup(key string, start, last int) string {
func FormGroup(key string, start, last int) string {
var (
group string
parts = strings.Split(key, "/")
@@ -106,7 +102,6 @@ func formGroup(key string, start, last int) string {
return fmt.Sprintf("%s/%s", group, groupType)
}
// MatchesContentType validates the content type against the expected one
func MatchesContentType(contentType, expectedType string) bool {
mimetype, _, err := mime.ParseMediaType(contentType)
if err != nil {
-282
View File
@@ -1,282 +0,0 @@
package api
import (
"io/ioutil"
"path/filepath"
"testing"
"github.com/docker/docker/api/types"
"os"
)
type ports struct {
ports []types.Port
expected string
}
// DisplayablePorts
func TestDisplayablePorts(t *testing.T) {
cases := []ports{
{
[]types.Port{
{
PrivatePort: 9988,
Type: "tcp",
},
},
"9988/tcp"},
{
[]types.Port{
{
PrivatePort: 9988,
Type: "udp",
},
},
"9988/udp",
},
{
[]types.Port{
{
IP: "0.0.0.0",
PrivatePort: 9988,
Type: "tcp",
},
},
"0.0.0.0:0->9988/tcp",
},
{
[]types.Port{
{
PrivatePort: 9988,
PublicPort: 8899,
Type: "tcp",
},
},
"9988/tcp",
},
{
[]types.Port{
{
IP: "4.3.2.1",
PrivatePort: 9988,
PublicPort: 8899,
Type: "tcp",
},
},
"4.3.2.1:8899->9988/tcp",
},
{
[]types.Port{
{
IP: "4.3.2.1",
PrivatePort: 9988,
PublicPort: 9988,
Type: "tcp",
},
},
"4.3.2.1:9988->9988/tcp",
},
{
[]types.Port{
{
PrivatePort: 9988,
Type: "udp",
}, {
PrivatePort: 9988,
Type: "udp",
},
},
"9988/udp, 9988/udp",
},
{
[]types.Port{
{
IP: "1.2.3.4",
PublicPort: 9998,
PrivatePort: 9998,
Type: "udp",
}, {
IP: "1.2.3.4",
PublicPort: 9999,
PrivatePort: 9999,
Type: "udp",
},
},
"1.2.3.4:9998-9999->9998-9999/udp",
},
{
[]types.Port{
{
IP: "1.2.3.4",
PublicPort: 8887,
PrivatePort: 9998,
Type: "udp",
}, {
IP: "1.2.3.4",
PublicPort: 8888,
PrivatePort: 9999,
Type: "udp",
},
},
"1.2.3.4:8887->9998/udp, 1.2.3.4:8888->9999/udp",
},
{
[]types.Port{
{
PrivatePort: 9998,
Type: "udp",
}, {
PrivatePort: 9999,
Type: "udp",
},
},
"9998-9999/udp",
},
{
[]types.Port{
{
IP: "1.2.3.4",
PrivatePort: 6677,
PublicPort: 7766,
Type: "tcp",
}, {
PrivatePort: 9988,
PublicPort: 8899,
Type: "udp",
},
},
"9988/udp, 1.2.3.4:7766->6677/tcp",
},
{
[]types.Port{
{
IP: "1.2.3.4",
PrivatePort: 9988,
PublicPort: 8899,
Type: "udp",
}, {
IP: "1.2.3.4",
PrivatePort: 9988,
PublicPort: 8899,
Type: "tcp",
}, {
IP: "4.3.2.1",
PrivatePort: 2233,
PublicPort: 3322,
Type: "tcp",
},
},
"4.3.2.1:3322->2233/tcp, 1.2.3.4:8899->9988/udp, 1.2.3.4:8899->9988/tcp",
},
{
[]types.Port{
{
PrivatePort: 9988,
PublicPort: 8899,
Type: "udp",
}, {
IP: "1.2.3.4",
PrivatePort: 6677,
PublicPort: 7766,
Type: "tcp",
}, {
IP: "4.3.2.1",
PrivatePort: 2233,
PublicPort: 3322,
Type: "tcp",
},
},
"9988/udp, 4.3.2.1:3322->2233/tcp, 1.2.3.4:7766->6677/tcp",
},
}
for _, port := range cases {
actual := DisplayablePorts(port.ports)
if port.expected != actual {
t.Fatalf("Expected %s, got %s.", port.expected, actual)
}
}
}
// MatchesContentType
func TestJsonContentType(t *testing.T) {
if !MatchesContentType("application/json", "application/json") {
t.Fail()
}
if !MatchesContentType("application/json; charset=utf-8", "application/json") {
t.Fail()
}
if MatchesContentType("dockerapplication/json", "application/json") {
t.Fail()
}
}
// LoadOrCreateTrustKey
func TestLoadOrCreateTrustKeyInvalidKeyFile(t *testing.T) {
tmpKeyFolderPath, err := ioutil.TempDir("", "api-trustkey-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpKeyFolderPath)
tmpKeyFile, err := ioutil.TempFile(tmpKeyFolderPath, "keyfile")
if err != nil {
t.Fatal(err)
}
if _, err := LoadOrCreateTrustKey(tmpKeyFile.Name()); err == nil {
t.Fatalf("expected an error, got nothing.")
}
}
func TestLoadOrCreateTrustKeyCreateKey(t *testing.T) {
tmpKeyFolderPath, err := ioutil.TempDir("", "api-trustkey-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpKeyFolderPath)
// Without the need to create the folder hierarchy
tmpKeyFile := filepath.Join(tmpKeyFolderPath, "keyfile")
if key, err := LoadOrCreateTrustKey(tmpKeyFile); err != nil || key == nil {
t.Fatalf("expected a new key file, got : %v and %v", err, key)
}
if _, err := os.Stat(tmpKeyFile); err != nil {
t.Fatalf("Expected to find a file %s, got %v", tmpKeyFile, err)
}
// With the need to create the folder hierarchy as tmpKeyFie is in a path
// where some folder do not exists.
tmpKeyFile = filepath.Join(tmpKeyFolderPath, "folder/hierarchy/keyfile")
if key, err := LoadOrCreateTrustKey(tmpKeyFile); err != nil || key == nil {
t.Fatalf("expected a new key file, got : %v and %v", err, key)
}
if _, err := os.Stat(tmpKeyFile); err != nil {
t.Fatalf("Expected to find a file %s, got %v", tmpKeyFile, err)
}
// With no path at all
defer os.Remove("keyfile")
if key, err := LoadOrCreateTrustKey("keyfile"); err != nil || key == nil {
t.Fatalf("expected a new key file, got : %v and %v", err, key)
}
if _, err := os.Stat("keyfile"); err != nil {
t.Fatalf("Expected to find a file keyfile, got %v", err)
}
}
func TestLoadOrCreateTrustKeyLoadValidKey(t *testing.T) {
tmpKeyFile := filepath.Join("fixtures", "keyfile")
if key, err := LoadOrCreateTrustKey(tmpKeyFile); err != nil || key == nil {
t.Fatalf("expected a key file, got : %v and %v", err, key)
}
}
-7
View File
@@ -1,7 +0,0 @@
-----BEGIN EC PRIVATE KEY-----
keyID: AWX2:I27X:WQFX:IOMK:CNAK:O7PW:VYNB:ZLKC:CVAE:YJP2:SI4A:XXAY
MHcCAQEEILHTRWdcpKWsnORxSFyBnndJ4ROU41hMtr/GCiLVvwBQoAoGCCqGSM49
AwEHoUQDQgAElpVFbQ2V2UQKajqdE3fVxJ+/pE/YuEFOxWbOxF2be19BY209/iky
NzeFFK7SLpQ4CBJ7zDVXOHsMzrkY/GquGA==
-----END EC PRIVATE KEY-----
-26
View File
@@ -1,26 +0,0 @@
package server
import (
"encoding/json"
"net/http"
"github.com/docker/docker/api/types"
"github.com/docker/docker/cliconfig"
"github.com/docker/docker/pkg/version"
)
func (s *Server) postAuth(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
var config *cliconfig.AuthConfig
err := json.NewDecoder(r.Body).Decode(&config)
r.Body.Close()
if err != nil {
return err
}
status, err := s.daemon.RegistryService.Auth(config)
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, &types.AuthResponse{
Status: status,
})
}
-535
View File
@@ -1,535 +0,0 @@
package server
import (
"fmt"
"io"
"net/http"
"runtime"
"strconv"
"strings"
"time"
"golang.org/x/net/websocket"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api/types"
"github.com/docker/docker/daemon"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/signal"
"github.com/docker/docker/pkg/version"
"github.com/docker/docker/runconfig"
)
func (s *Server) getContainersByName(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if version.LessThan("1.20") && runtime.GOOS != "windows" {
return getContainersByNameDownlevel(w, s, vars["name"])
}
containerJSON, err := s.daemon.ContainerInspect(vars["name"])
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, containerJSON)
}
func (s *Server) getContainersJSON(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
config := &daemon.ContainersConfig{
All: boolValue(r, "all"),
Size: boolValue(r, "size"),
Since: r.Form.Get("since"),
Before: r.Form.Get("before"),
Filters: r.Form.Get("filters"),
}
if tmpLimit := r.Form.Get("limit"); tmpLimit != "" {
limit, err := strconv.Atoi(tmpLimit)
if err != nil {
return err
}
config.Limit = limit
}
containers, err := s.daemon.Containers(config)
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, containers)
}
func (s *Server) getContainersStats(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
stream := boolValueOrDefault(r, "stream", true)
var out io.Writer
if !stream {
w.Header().Set("Content-Type", "application/json")
out = w
} else {
out = ioutils.NewWriteFlusher(w)
}
var closeNotifier <-chan bool
if notifier, ok := w.(http.CloseNotifier); ok {
closeNotifier = notifier.CloseNotify()
}
config := &daemon.ContainerStatsConfig{
Stream: stream,
OutStream: out,
Stop: closeNotifier,
}
return s.daemon.ContainerStats(vars["name"], config)
}
func (s *Server) getContainersLogs(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
// Validate args here, because we can't return not StatusOK after job.Run() call
stdout, stderr := boolValue(r, "stdout"), boolValue(r, "stderr")
if !(stdout || stderr) {
return fmt.Errorf("Bad parameters: you must choose at least one stream")
}
var since time.Time
if r.Form.Get("since") != "" {
s, err := strconv.ParseInt(r.Form.Get("since"), 10, 64)
if err != nil {
return err
}
since = time.Unix(s, 0)
}
var closeNotifier <-chan bool
if notifier, ok := w.(http.CloseNotifier); ok {
closeNotifier = notifier.CloseNotify()
}
c, err := s.daemon.Get(vars["name"])
if err != nil {
return err
}
outStream := ioutils.NewWriteFlusher(w)
// write an empty chunk of data (this is to ensure that the
// HTTP Response is sent immediately, even if the container has
// not yet produced any data)
outStream.Write(nil)
logsConfig := &daemon.ContainerLogsConfig{
Follow: boolValue(r, "follow"),
Timestamps: boolValue(r, "timestamps"),
Since: since,
Tail: r.Form.Get("tail"),
UseStdout: stdout,
UseStderr: stderr,
OutStream: outStream,
Stop: closeNotifier,
}
if err := s.daemon.ContainerLogs(c, logsConfig); err != nil {
fmt.Fprintf(w, "Error running logs job: %s\n", err)
}
return nil
}
func (s *Server) getContainersExport(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
return s.daemon.ContainerExport(vars["name"], w)
}
func (s *Server) postContainersStart(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
// If contentLength is -1, we can assumed chunked encoding
// or more technically that the length is unknown
// https://golang.org/src/pkg/net/http/request.go#L139
// net/http otherwise seems to swallow any headers related to chunked encoding
// including r.TransferEncoding
// allow a nil body for backwards compatibility
var hostConfig *runconfig.HostConfig
if r.Body != nil && (r.ContentLength > 0 || r.ContentLength == -1) {
if err := checkForJSON(r); err != nil {
return err
}
c, err := runconfig.DecodeHostConfig(r.Body)
if err != nil {
return err
}
hostConfig = c
}
if err := s.daemon.ContainerStart(vars["name"], hostConfig); err != nil {
if err.Error() == "Container already started" {
w.WriteHeader(http.StatusNotModified)
return nil
}
return err
}
w.WriteHeader(http.StatusNoContent)
return nil
}
func (s *Server) postContainersStop(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
seconds, _ := strconv.Atoi(r.Form.Get("t"))
if err := s.daemon.ContainerStop(vars["name"], seconds); err != nil {
if err.Error() == "Container already stopped" {
w.WriteHeader(http.StatusNotModified)
return nil
}
return err
}
w.WriteHeader(http.StatusNoContent)
return nil
}
func (s *Server) postContainersKill(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := parseForm(r); err != nil {
return err
}
var sig uint64
name := vars["name"]
// If we have a signal, look at it. Otherwise, do nothing
if sigStr := r.Form.Get("signal"); sigStr != "" {
// Check if we passed the signal as a number:
// The largest legal signal is 31, so let's parse on 5 bits
sigN, err := strconv.ParseUint(sigStr, 10, 5)
if err != nil {
// The signal is not a number, treat it as a string (either like
// "KILL" or like "SIGKILL")
syscallSig, ok := signal.SignalMap[strings.TrimPrefix(sigStr, "SIG")]
if !ok {
return fmt.Errorf("Invalid signal: %s", sigStr)
}
sig = uint64(syscallSig)
} else {
sig = sigN
}
if sig == 0 {
return fmt.Errorf("Invalid signal: %s", sigStr)
}
}
if err := s.daemon.ContainerKill(name, sig); err != nil {
_, isStopped := err.(daemon.ErrContainerNotRunning)
// Return error that's not caused because the container is stopped.
// Return error if the container is not running and the api is >= 1.20
// to keep backwards compatibility.
if version.GreaterThanOrEqualTo("1.20") || !isStopped {
return fmt.Errorf("Cannot kill container %s: %v", name, err)
}
}
w.WriteHeader(http.StatusNoContent)
return nil
}
func (s *Server) postContainersRestart(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
timeout, _ := strconv.Atoi(r.Form.Get("t"))
if err := s.daemon.ContainerRestart(vars["name"], timeout); err != nil {
return err
}
w.WriteHeader(http.StatusNoContent)
return nil
}
func (s *Server) postContainersPause(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := parseForm(r); err != nil {
return err
}
if err := s.daemon.ContainerPause(vars["name"]); err != nil {
return err
}
w.WriteHeader(http.StatusNoContent)
return nil
}
func (s *Server) postContainersUnpause(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := parseForm(r); err != nil {
return err
}
if err := s.daemon.ContainerUnpause(vars["name"]); err != nil {
return err
}
w.WriteHeader(http.StatusNoContent)
return nil
}
func (s *Server) postContainersWait(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
status, err := s.daemon.ContainerWait(vars["name"], -1*time.Second)
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, &types.ContainerWaitResponse{
StatusCode: status,
})
}
func (s *Server) getContainersChanges(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
changes, err := s.daemon.ContainerChanges(vars["name"])
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, changes)
}
func (s *Server) getContainersTop(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := parseForm(r); err != nil {
return err
}
procList, err := s.daemon.ContainerTop(vars["name"], r.Form.Get("ps_args"))
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, procList)
}
func (s *Server) postContainerRename(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
name := vars["name"]
newName := r.Form.Get("name")
if err := s.daemon.ContainerRename(name, newName); err != nil {
return err
}
w.WriteHeader(http.StatusNoContent)
return nil
}
func (s *Server) postContainersCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if err := checkForJSON(r); err != nil {
return err
}
var (
warnings []string
name = r.Form.Get("name")
)
config, hostConfig, err := runconfig.DecodeContainerConfig(r.Body)
if err != nil {
return err
}
adjustCPUShares := version.LessThan("1.19")
container, warnings, err := s.daemon.ContainerCreate(name, config, hostConfig, adjustCPUShares)
if err != nil {
return err
}
return writeJSON(w, http.StatusCreated, &types.ContainerCreateResponse{
ID: container.ID,
Warnings: warnings,
})
}
func (s *Server) deleteContainers(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
name := vars["name"]
config := &daemon.ContainerRmConfig{
ForceRemove: boolValue(r, "force"),
RemoveVolume: boolValue(r, "v"),
RemoveLink: boolValue(r, "link"),
}
if err := s.daemon.ContainerRm(name, config); err != nil {
// Force a 404 for the empty string
if strings.Contains(strings.ToLower(err.Error()), "prefix can't be empty") {
return fmt.Errorf("no such id: \"\"")
}
return err
}
w.WriteHeader(http.StatusNoContent)
return nil
}
func (s *Server) postContainersResize(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
height, err := strconv.Atoi(r.Form.Get("h"))
if err != nil {
return err
}
width, err := strconv.Atoi(r.Form.Get("w"))
if err != nil {
return err
}
return s.daemon.ContainerResize(vars["name"], height, width)
}
func (s *Server) postContainersAttach(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
cont, err := s.daemon.Get(vars["name"])
if err != nil {
return err
}
inStream, outStream, err := hijackServer(w)
if err != nil {
return err
}
defer closeStreams(inStream, outStream)
if _, ok := r.Header["Upgrade"]; ok {
fmt.Fprintf(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n")
} else {
fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
}
attachWithLogsConfig := &daemon.ContainerAttachWithLogsConfig{
InStream: inStream,
OutStream: outStream,
UseStdin: boolValue(r, "stdin"),
UseStdout: boolValue(r, "stdout"),
UseStderr: boolValue(r, "stderr"),
Logs: boolValue(r, "logs"),
Stream: boolValue(r, "stream"),
}
if err := s.daemon.ContainerAttachWithLogs(cont, attachWithLogsConfig); err != nil {
fmt.Fprintf(outStream, "Error attaching: %s\n", err)
}
return nil
}
func (s *Server) wsContainersAttach(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
cont, err := s.daemon.Get(vars["name"])
if err != nil {
return err
}
h := websocket.Handler(func(ws *websocket.Conn) {
defer ws.Close()
wsAttachWithLogsConfig := &daemon.ContainerWsAttachWithLogsConfig{
InStream: ws,
OutStream: ws,
ErrStream: ws,
Logs: boolValue(r, "logs"),
Stream: boolValue(r, "stream"),
}
if err := s.daemon.ContainerWsAttachWithLogs(cont, wsAttachWithLogsConfig); err != nil {
logrus.Errorf("Error attaching websocket: %s", err)
}
})
ws := websocket.Server{Handler: h, Handshake: nil}
ws.ServeHTTP(w, r)
return nil
}
-115
View File
@@ -1,115 +0,0 @@
package server
import (
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"strings"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/version"
)
// postContainersCopy is deprecated in favor of getContainersArchive.
func (s *Server) postContainersCopy(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := checkForJSON(r); err != nil {
return err
}
cfg := types.CopyConfig{}
if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil {
return err
}
if cfg.Resource == "" {
return fmt.Errorf("Path cannot be empty")
}
data, err := s.daemon.ContainerCopy(vars["name"], cfg.Resource)
if err != nil {
if strings.Contains(strings.ToLower(err.Error()), "no such id") {
w.WriteHeader(http.StatusNotFound)
return nil
}
if os.IsNotExist(err) {
return fmt.Errorf("Could not find the file %s in container %s", cfg.Resource, vars["name"])
}
return err
}
defer data.Close()
w.Header().Set("Content-Type", "application/x-tar")
if _, err := io.Copy(w, data); err != nil {
return err
}
return nil
}
// // Encode the stat to JSON, base64 encode, and place in a header.
func setContainerPathStatHeader(stat *types.ContainerPathStat, header http.Header) error {
statJSON, err := json.Marshal(stat)
if err != nil {
return err
}
header.Set(
"X-Docker-Container-Path-Stat",
base64.StdEncoding.EncodeToString(statJSON),
)
return nil
}
func (s *Server) headContainersArchive(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
v, err := archiveFormValues(r, vars)
if err != nil {
return err
}
stat, err := s.daemon.ContainerStatPath(v.name, v.path)
if err != nil {
return err
}
return setContainerPathStatHeader(stat, w.Header())
}
func (s *Server) getContainersArchive(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
v, err := archiveFormValues(r, vars)
if err != nil {
return err
}
tarArchive, stat, err := s.daemon.ContainerArchivePath(v.name, v.path)
if err != nil {
return err
}
defer tarArchive.Close()
if err := setContainerPathStatHeader(stat, w.Header()); err != nil {
return err
}
w.Header().Set("Content-Type", "application/x-tar")
_, err = io.Copy(w, tarArchive)
return err
}
func (s *Server) putContainersArchive(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
v, err := archiveFormValues(r, vars)
if err != nil {
return err
}
noOverwriteDirNonDir := boolValue(r, "noOverwriteDirNonDir")
return s.daemon.ContainerExtractToDir(v.name, v.path, noOverwriteDirNonDir, r.Body)
}
-174
View File
@@ -1,174 +0,0 @@
package server
import (
"encoding/json"
"net/http"
"runtime"
"strconv"
"strings"
"time"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api"
"github.com/docker/docker/api/types"
"github.com/docker/docker/autogen/dockerversion"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/jsonmessage"
"github.com/docker/docker/pkg/parsers/filters"
"github.com/docker/docker/pkg/parsers/kernel"
"github.com/docker/docker/pkg/version"
"github.com/docker/docker/utils"
)
func (s *Server) getVersion(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
v := &types.Version{
Version: dockerversion.VERSION,
APIVersion: api.Version,
GitCommit: dockerversion.GITCOMMIT,
GoVersion: runtime.Version(),
Os: runtime.GOOS,
Arch: runtime.GOARCH,
BuildTime: dockerversion.BUILDTIME,
}
if version.GreaterThanOrEqualTo("1.19") {
v.Experimental = utils.ExperimentalBuild()
}
if kernelVersion, err := kernel.GetKernelVersion(); err == nil {
v.KernelVersion = kernelVersion.String()
}
return writeJSON(w, http.StatusOK, v)
}
func (s *Server) getInfo(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
info, err := s.daemon.SystemInfo()
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, info)
}
func (s *Server) getEvents(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
var since int64 = -1
if r.Form.Get("since") != "" {
s, err := strconv.ParseInt(r.Form.Get("since"), 10, 64)
if err != nil {
return err
}
since = s
}
var until int64 = -1
if r.Form.Get("until") != "" {
u, err := strconv.ParseInt(r.Form.Get("until"), 10, 64)
if err != nil {
return err
}
until = u
}
timer := time.NewTimer(0)
timer.Stop()
if until > 0 {
dur := time.Unix(until, 0).Sub(time.Now())
timer = time.NewTimer(dur)
}
ef, err := filters.FromParam(r.Form.Get("filters"))
if err != nil {
return err
}
isFiltered := func(field string, filter []string) bool {
if len(field) == 0 {
return false
}
if len(filter) == 0 {
return false
}
for _, v := range filter {
if v == field {
return false
}
if strings.Contains(field, ":") {
image := strings.Split(field, ":")
if image[0] == v {
return false
}
}
}
return true
}
d := s.daemon
es := d.EventsService
w.Header().Set("Content-Type", "application/json")
outStream := ioutils.NewWriteFlusher(w)
outStream.Write(nil) // make sure response is sent immediately
enc := json.NewEncoder(outStream)
getContainerID := func(cn string) string {
c, err := d.Get(cn)
if err != nil {
return ""
}
return c.ID
}
sendEvent := func(ev *jsonmessage.JSONMessage) error {
//incoming container filter can be name,id or partial id, convert and replace as a full container id
for i, cn := range ef["container"] {
ef["container"][i] = getContainerID(cn)
}
if isFiltered(ev.Status, ef["event"]) || (isFiltered(ev.ID, ef["image"]) &&
isFiltered(ev.From, ef["image"])) || isFiltered(ev.ID, ef["container"]) {
return nil
}
return enc.Encode(ev)
}
current, l := es.Subscribe()
if since == -1 {
current = nil
}
defer es.Evict(l)
for _, ev := range current {
if ev.Time < since {
continue
}
if err := sendEvent(ev); err != nil {
return err
}
}
var closeNotify <-chan bool
if closeNotifier, ok := w.(http.CloseNotifier); ok {
closeNotify = closeNotifier.CloseNotify()
}
for {
select {
case ev := <-l:
jev, ok := ev.(*jsonmessage.JSONMessage)
if !ok {
continue
}
if err := sendEvent(jev); err != nil {
return err
}
case <-timer.C:
return nil
case <-closeNotify:
logrus.Debug("Client disconnected, stop sending events")
return nil
}
}
}
-127
View File
@@ -1,127 +0,0 @@
package server
import (
"encoding/json"
"fmt"
"io"
"net/http"
"strconv"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/stdcopy"
"github.com/docker/docker/pkg/version"
"github.com/docker/docker/runconfig"
)
func (s *Server) getExecByID(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter 'id'")
}
eConfig, err := s.daemon.ContainerExecInspect(vars["id"])
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, eConfig)
}
func (s *Server) postContainerExecCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if err := checkForJSON(r); err != nil {
return err
}
name := vars["name"]
execConfig := &runconfig.ExecConfig{}
if err := json.NewDecoder(r.Body).Decode(execConfig); err != nil {
return err
}
execConfig.Container = name
if len(execConfig.Cmd) == 0 {
return fmt.Errorf("No exec command specified")
}
// Register an instance of Exec in container.
id, err := s.daemon.ContainerExecCreate(execConfig)
if err != nil {
logrus.Errorf("Error setting up exec command in container %s: %s", name, err)
return err
}
return writeJSON(w, http.StatusCreated, &types.ContainerExecCreateResponse{
ID: id,
})
}
// TODO(vishh): Refactor the code to avoid having to specify stream config as part of both create and start.
func (s *Server) postContainerExecStart(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
var (
execName = vars["name"]
stdin, inStream io.ReadCloser
stdout, stderr, outStream io.Writer
)
execStartCheck := &types.ExecStartCheck{}
if err := json.NewDecoder(r.Body).Decode(execStartCheck); err != nil {
return err
}
if !execStartCheck.Detach {
var err error
// Setting up the streaming http interface.
inStream, outStream, err = hijackServer(w)
if err != nil {
return err
}
defer closeStreams(inStream, outStream)
if _, ok := r.Header["Upgrade"]; ok {
fmt.Fprintf(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n")
} else {
fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
}
stdin = inStream
stdout = outStream
if !execStartCheck.Tty {
stderr = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
stdout = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
}
} else {
outStream = w
}
// Now run the user process in container.
if err := s.daemon.ContainerExecStart(execName, stdin, stdout, stderr); err != nil {
fmt.Fprintf(outStream, "Error running exec in container: %v\n", err)
}
return nil
}
func (s *Server) postContainerExecResize(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
height, err := strconv.Atoi(r.Form.Get("h"))
if err != nil {
return err
}
width, err := strconv.Atoi(r.Form.Get("w"))
if err != nil {
return err
}
return s.daemon.ContainerExecResize(vars["name"], height, width)
}
+1 -2
View File
@@ -3,7 +3,6 @@ package server
import (
"fmt"
"net/http"
"path/filepath"
"strconv"
"strings"
)
@@ -44,7 +43,7 @@ func archiveFormValues(r *http.Request, vars map[string]string) (archiveOptions,
}
name := vars["name"]
path := filepath.FromSlash(r.Form.Get("path"))
path := r.Form.Get("path")
switch {
case name == "":
-425
View File
@@ -1,425 +0,0 @@
package server
import (
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api/types"
"github.com/docker/docker/builder"
"github.com/docker/docker/cliconfig"
"github.com/docker/docker/graph"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/streamformatter"
"github.com/docker/docker/pkg/ulimit"
"github.com/docker/docker/pkg/version"
"github.com/docker/docker/runconfig"
"github.com/docker/docker/utils"
)
func (s *Server) postCommit(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if err := checkForJSON(r); err != nil {
return err
}
cname := r.Form.Get("container")
pause := boolValue(r, "pause")
if r.FormValue("pause") == "" && version.GreaterThanOrEqualTo("1.13") {
pause = true
}
c, _, err := runconfig.DecodeContainerConfig(r.Body)
if err != nil && err != io.EOF { //Do not fail if body is empty.
return err
}
commitCfg := &builder.CommitConfig{
Pause: pause,
Repo: r.Form.Get("repo"),
Tag: r.Form.Get("tag"),
Author: r.Form.Get("author"),
Comment: r.Form.Get("comment"),
Changes: r.Form["changes"],
Config: c,
}
imgID, err := builder.Commit(cname, s.daemon, commitCfg)
if err != nil {
return err
}
return writeJSON(w, http.StatusCreated, &types.ContainerCommitResponse{
ID: imgID,
})
}
// Creates an image from Pull or from Import
func (s *Server) postImagesCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
var (
image = r.Form.Get("fromImage")
repo = r.Form.Get("repo")
tag = r.Form.Get("tag")
message = r.Form.Get("message")
)
authEncoded := r.Header.Get("X-Registry-Auth")
authConfig := &cliconfig.AuthConfig{}
if authEncoded != "" {
authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
if err := json.NewDecoder(authJSON).Decode(authConfig); err != nil {
// for a pull it is not an error if no auth was given
// to increase compatibility with the existing api it is defaulting to be empty
authConfig = &cliconfig.AuthConfig{}
}
}
var (
err error
output = ioutils.NewWriteFlusher(w)
)
w.Header().Set("Content-Type", "application/json")
if image != "" { //pull
if tag == "" {
image, tag = parsers.ParseRepositoryTag(image)
}
metaHeaders := map[string][]string{}
for k, v := range r.Header {
if strings.HasPrefix(k, "X-Meta-") {
metaHeaders[k] = v
}
}
imagePullConfig := &graph.ImagePullConfig{
MetaHeaders: metaHeaders,
AuthConfig: authConfig,
OutStream: output,
}
err = s.daemon.Repositories().Pull(image, tag, imagePullConfig)
} else { //import
if tag == "" {
repo, tag = parsers.ParseRepositoryTag(repo)
}
src := r.Form.Get("fromSrc")
// 'err' MUST NOT be defined within this block, we need any error
// generated from the download to be available to the output
// stream processing below
var newConfig *runconfig.Config
newConfig, err = builder.BuildFromConfig(s.daemon, &runconfig.Config{}, r.Form["changes"])
if err != nil {
return err
}
err = s.daemon.Repositories().Import(src, repo, tag, message, r.Body, output, newConfig)
}
if err != nil {
if !output.Flushed() {
return err
}
sf := streamformatter.NewJSONStreamFormatter()
output.Write(sf.FormatError(err))
}
return nil
}
func (s *Server) postImagesPush(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
metaHeaders := map[string][]string{}
for k, v := range r.Header {
if strings.HasPrefix(k, "X-Meta-") {
metaHeaders[k] = v
}
}
if err := parseForm(r); err != nil {
return err
}
authConfig := &cliconfig.AuthConfig{}
authEncoded := r.Header.Get("X-Registry-Auth")
if authEncoded != "" {
// the new format is to handle the authConfig as a header
authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
if err := json.NewDecoder(authJSON).Decode(authConfig); err != nil {
// to increase compatibility to existing api it is defaulting to be empty
authConfig = &cliconfig.AuthConfig{}
}
} else {
// the old format is supported for compatibility if there was no authConfig header
if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil {
return fmt.Errorf("Bad parameters and missing X-Registry-Auth: %v", err)
}
}
name := vars["name"]
output := ioutils.NewWriteFlusher(w)
imagePushConfig := &graph.ImagePushConfig{
MetaHeaders: metaHeaders,
AuthConfig: authConfig,
Tag: r.Form.Get("tag"),
OutStream: output,
}
w.Header().Set("Content-Type", "application/json")
if err := s.daemon.Repositories().Push(name, imagePushConfig); err != nil {
if !output.Flushed() {
return err
}
sf := streamformatter.NewJSONStreamFormatter()
output.Write(sf.FormatError(err))
}
return nil
}
func (s *Server) getImagesGet(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := parseForm(r); err != nil {
return err
}
w.Header().Set("Content-Type", "application/x-tar")
output := ioutils.NewWriteFlusher(w)
var names []string
if name, ok := vars["name"]; ok {
names = []string{name}
} else {
names = r.Form["names"]
}
if err := s.daemon.Repositories().ImageExport(names, output); err != nil {
if !output.Flushed() {
return err
}
sf := streamformatter.NewJSONStreamFormatter()
output.Write(sf.FormatError(err))
}
return nil
}
func (s *Server) postImagesLoad(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
return s.daemon.Repositories().Load(r.Body, w)
}
func (s *Server) deleteImages(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
name := vars["name"]
if name == "" {
return fmt.Errorf("image name cannot be blank")
}
force := boolValue(r, "force")
prune := !boolValue(r, "noprune")
list, err := s.daemon.ImageDelete(name, force, prune)
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, list)
}
func (s *Server) getImagesByName(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
imageInspect, err := s.daemon.Repositories().Lookup(vars["name"])
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, imageInspect)
}
func (s *Server) postBuild(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
var (
authConfigs = map[string]cliconfig.AuthConfig{}
authConfigsEncoded = r.Header.Get("X-Registry-Config")
buildConfig = builder.NewBuildConfig()
)
if authConfigsEncoded != "" {
authConfigsJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authConfigsEncoded))
if err := json.NewDecoder(authConfigsJSON).Decode(&authConfigs); err != nil {
// for a pull it is not an error if no auth was given
// to increase compatibility with the existing api it is defaulting
// to be empty.
}
}
w.Header().Set("Content-Type", "application/json")
if boolValue(r, "forcerm") && version.GreaterThanOrEqualTo("1.12") {
buildConfig.Remove = true
} else if r.FormValue("rm") == "" && version.GreaterThanOrEqualTo("1.12") {
buildConfig.Remove = true
} else {
buildConfig.Remove = boolValue(r, "rm")
}
if boolValue(r, "pull") && version.GreaterThanOrEqualTo("1.16") {
buildConfig.Pull = true
}
output := ioutils.NewWriteFlusher(w)
buildConfig.Stdout = output
buildConfig.Context = r.Body
buildConfig.RemoteURL = r.FormValue("remote")
buildConfig.DockerfileName = r.FormValue("dockerfile")
buildConfig.RepoName = r.FormValue("t")
buildConfig.SuppressOutput = boolValue(r, "q")
buildConfig.NoCache = boolValue(r, "nocache")
buildConfig.ForceRemove = boolValue(r, "forcerm")
buildConfig.AuthConfigs = authConfigs
buildConfig.MemorySwap = int64ValueOrZero(r, "memswap")
buildConfig.Memory = int64ValueOrZero(r, "memory")
buildConfig.CPUShares = int64ValueOrZero(r, "cpushares")
buildConfig.CPUPeriod = int64ValueOrZero(r, "cpuperiod")
buildConfig.CPUQuota = int64ValueOrZero(r, "cpuquota")
buildConfig.CPUSetCpus = r.FormValue("cpusetcpus")
buildConfig.CPUSetMems = r.FormValue("cpusetmems")
buildConfig.CgroupParent = r.FormValue("cgroupparent")
var buildUlimits = []*ulimit.Ulimit{}
ulimitsJSON := r.FormValue("ulimits")
if ulimitsJSON != "" {
if err := json.NewDecoder(strings.NewReader(ulimitsJSON)).Decode(&buildUlimits); err != nil {
return err
}
buildConfig.Ulimits = buildUlimits
}
// Job cancellation. Note: not all job types support this.
if closeNotifier, ok := w.(http.CloseNotifier); ok {
finished := make(chan struct{})
defer close(finished)
go func() {
select {
case <-finished:
case <-closeNotifier.CloseNotify():
logrus.Infof("Client disconnected, cancelling job: build")
buildConfig.Cancel()
}
}()
}
if err := builder.Build(s.daemon, buildConfig); err != nil {
// Do not write the error in the http output if it's still empty.
// This prevents from writing a 200(OK) when there is an interal error.
if !output.Flushed() {
return err
}
sf := streamformatter.NewJSONStreamFormatter()
w.Write(sf.FormatError(err))
}
return nil
}
func (s *Server) getImagesJSON(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
// FIXME: The filter parameter could just be a match filter
images, err := s.daemon.Repositories().Images(r.Form.Get("filters"), r.Form.Get("filter"), boolValue(r, "all"))
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, images)
}
func (s *Server) getImagesHistory(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
name := vars["name"]
history, err := s.daemon.Repositories().History(name)
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, history)
}
func (s *Server) postImagesTag(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
repo := r.Form.Get("repo")
tag := r.Form.Get("tag")
force := boolValue(r, "force")
name := vars["name"]
if err := s.daemon.Repositories().Tag(repo, tag, name, force); err != nil {
return err
}
s.daemon.EventsService.Log("tag", utils.ImageReference(repo, tag), "")
w.WriteHeader(http.StatusCreated)
return nil
}
func (s *Server) getImagesSearch(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
var (
config *cliconfig.AuthConfig
authEncoded = r.Header.Get("X-Registry-Auth")
headers = map[string][]string{}
)
if authEncoded != "" {
authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
if err := json.NewDecoder(authJSON).Decode(&config); err != nil {
// for a search it is not an error if no auth was given
// to increase compatibility with the existing api it is defaulting to be empty
config = &cliconfig.AuthConfig{}
}
}
for k, v := range r.Header {
if strings.HasPrefix(k, "X-Meta-") {
headers[k] = v
}
}
query, err := s.daemon.RegistryService.Search(r.Form.Get("term"), config, headers)
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, query.Results)
}
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"github.com/gorilla/mux"
)
func profilerSetup(mainRouter *mux.Router, path string) {
func ProfilerSetup(mainRouter *mux.Router, path string) {
var r = mainRouter.PathPrefix(path).Subrouter()
r.HandleFunc("/vars", expVars)
r.HandleFunc("/pprof/", pprof.Index)
+1353 -34
View File
File diff suppressed because it is too large Load Diff
@@ -1,9 +1,9 @@
// +build experimental,!windows
// +build experimental
package server
func (s *Server) registerSubRouter() {
httpHandler := s.daemon.NetworkAPIRouter()
httpHandler := s.daemon.NetworkApiRouter()
subrouter := s.router.PathPrefix("/v{version:[0-9.]+}/networks").Subrouter()
subrouter.Methods("GET", "POST", "PUT", "DELETE").HandlerFunc(httpHandler)
@@ -1,4 +1,4 @@
// +build freebsd linux
// +build linux
package server
@@ -8,12 +8,19 @@ import (
"net/http"
"strconv"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/daemon"
"github.com/docker/docker/pkg/sockets"
"github.com/docker/docker/pkg/systemd"
"github.com/docker/docker/pkg/version"
"github.com/docker/docker/runconfig"
"github.com/docker/libnetwork/portallocator"
)
systemdActivation "github.com/coreos/go-systemd/activation"
systemdDaemon "github.com/coreos/go-systemd/daemon"
const (
// See http://git.kernel.org/cgit/linux/kernel/git/tip/tip.git/tree/kernel/sched/sched.h?id=8cd9234c64c584432f6992fe944ca9e46ca8ea76#n269
linuxMinCpuShares = 2
linuxMaxCpuShares = 262144
)
// newServer sets up the required serverClosers and does protocol specific checking.
@@ -24,7 +31,7 @@ func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
)
switch proto {
case "fd":
ls, err = listenFD(addr)
ls, err = systemd.ListenFD(addr)
if err != nil {
return nil, err
}
@@ -33,7 +40,7 @@ func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
// won't be ready.
<-s.start
case "tcp":
l, err := s.initTCPSocket(addr)
l, err := s.initTcpSocket(addr)
if err != nil {
return nil, err
}
@@ -49,7 +56,7 @@ func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
}
var res []serverCloser
for _, l := range ls {
res = append(res, &HTTPServer{
res = append(res, &HttpServer{
&http.Server{
Addr: addr,
Handler: s.router,
@@ -60,14 +67,11 @@ func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
return res, nil
}
// AcceptConnections allows clients to connect to the API server.
// Referenced Daemon is notified about this server, and waits for the
// daemon acknowledgement before the incoming connections are accepted.
func (s *Server) AcceptConnections(d *daemon.Daemon) {
// Tell the init daemon we are accepting requests
s.daemon = d
s.registerSubRouter()
go systemdDaemon.SdNotify("READY=1")
go systemd.SdNotify("READY=1")
// close the lock so the listeners start accepting connections
select {
case <-s.start:
@@ -103,43 +107,17 @@ func allocateDaemonPort(addr string) error {
return nil
}
// getContainersByNameDownlevel performs processing for pre 1.20 APIs. This
// is only relevant on non-Windows daemons.
func getContainersByNameDownlevel(w http.ResponseWriter, s *Server, namevar string) error {
containerJSONRaw, err := s.daemon.ContainerInspectPre120(namevar)
if err != nil {
return err
func adjustCpuShares(version version.Version, hostConfig *runconfig.HostConfig) {
if version.LessThan("1.19") {
if hostConfig != nil && hostConfig.CpuShares > 0 {
// Handle unsupported CpuShares
if hostConfig.CpuShares < linuxMinCpuShares {
logrus.Warnf("Changing requested CpuShares of %d to minimum allowed of %d", hostConfig.CpuShares, linuxMinCpuShares)
hostConfig.CpuShares = linuxMinCpuShares
} else if hostConfig.CpuShares > linuxMaxCpuShares {
logrus.Warnf("Changing requested CpuShares of %d to maximum allowed of %d", hostConfig.CpuShares, linuxMaxCpuShares)
hostConfig.CpuShares = linuxMaxCpuShares
}
}
}
return writeJSON(w, http.StatusOK, containerJSONRaw)
}
// listenFD returns the specified socket activated files as a slice of
// net.Listeners or all of the activated files if "*" is given.
func listenFD(addr string) ([]net.Listener, error) {
// socket activation
listeners, err := systemdActivation.Listeners(false)
if err != nil {
return nil, err
}
if listeners == nil || len(listeners) == 0 {
return nil, fmt.Errorf("No sockets found")
}
// default to all fds just like unix:// and tcp://
if addr == "" {
addr = "*"
}
fdNum, _ := strconv.Atoi(addr)
fdOffset := fdNum - 3
if (addr != "*") && (len(listeners) < int(fdOffset)+1) {
return nil, fmt.Errorf("Too few socket activated files passed in")
}
if addr == "*" {
return listeners, nil
}
return []net.Listener{listeners[fdOffset]}, nil
}
+68
View File
@@ -0,0 +1,68 @@
// +build linux
package server
import (
"testing"
"github.com/docker/docker/pkg/version"
"github.com/docker/docker/runconfig"
)
func TestAdjustCpuSharesOldApi(t *testing.T) {
apiVersion := version.Version("1.18")
hostConfig := &runconfig.HostConfig{
CpuShares: linuxMinCpuShares - 1,
}
adjustCpuShares(apiVersion, hostConfig)
if hostConfig.CpuShares != linuxMinCpuShares {
t.Errorf("Expected CpuShares to be %d", linuxMinCpuShares)
}
hostConfig.CpuShares = linuxMaxCpuShares + 1
adjustCpuShares(apiVersion, hostConfig)
if hostConfig.CpuShares != linuxMaxCpuShares {
t.Errorf("Expected CpuShares to be %d", linuxMaxCpuShares)
}
hostConfig.CpuShares = 0
adjustCpuShares(apiVersion, hostConfig)
if hostConfig.CpuShares != 0 {
t.Error("Expected CpuShares to be unchanged")
}
hostConfig.CpuShares = 1024
adjustCpuShares(apiVersion, hostConfig)
if hostConfig.CpuShares != 1024 {
t.Error("Expected CpuShares to be unchanged")
}
}
func TestAdjustCpuSharesNoAdjustment(t *testing.T) {
apiVersion := version.Version("1.19")
hostConfig := &runconfig.HostConfig{
CpuShares: linuxMinCpuShares - 1,
}
adjustCpuShares(apiVersion, hostConfig)
if hostConfig.CpuShares != linuxMinCpuShares-1 {
t.Errorf("Expected CpuShares to be %d", linuxMinCpuShares-1)
}
hostConfig.CpuShares = linuxMaxCpuShares + 1
adjustCpuShares(apiVersion, hostConfig)
if hostConfig.CpuShares != linuxMaxCpuShares+1 {
t.Errorf("Expected CpuShares to be %d", linuxMaxCpuShares+1)
}
hostConfig.CpuShares = 0
adjustCpuShares(apiVersion, hostConfig)
if hostConfig.CpuShares != 0 {
t.Error("Expected CpuShares to be unchanged")
}
hostConfig.CpuShares = 1024
adjustCpuShares(apiVersion, hostConfig)
if hostConfig.CpuShares != 1024 {
t.Error("Expected CpuShares to be unchanged")
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
// +build !experimental windows
// +build !experimental
package server
+5 -7
View File
@@ -8,6 +8,8 @@ import (
"net/http"
"github.com/docker/docker/daemon"
"github.com/docker/docker/pkg/version"
"github.com/docker/docker/runconfig"
)
// NewServer sets up the required Server and does protocol specific checking.
@@ -17,7 +19,7 @@ func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
)
switch proto {
case "tcp":
l, err := s.initTCPSocket(addr)
l, err := s.initTcpSocket(addr)
if err != nil {
return nil, err
}
@@ -29,7 +31,7 @@ func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
var res []serverCloser
for _, l := range ls {
res = append(res, &HTTPServer{
res = append(res, &HttpServer{
&http.Server{
Addr: addr,
Handler: s.router,
@@ -41,7 +43,6 @@ func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
}
// AcceptConnections allows router to start listening for the incoming requests.
func (s *Server) AcceptConnections(d *daemon.Daemon) {
s.daemon = d
s.registerSubRouter()
@@ -57,8 +58,5 @@ func allocateDaemonPort(addr string) error {
return nil
}
// getContainersByNameDownlevel performs processing for pre 1.20 APIs. This
// is only relevant on non-Windows daemons.
func getContainersByNameDownlevel(w http.ResponseWriter, s *Server, namevar string) error {
return nil
func adjustCpuShares(version version.Version, hostConfig *runconfig.HostConfig) {
}
-65
View File
@@ -1,65 +0,0 @@
package server
import (
"encoding/json"
"net/http"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/version"
)
func (s *Server) getVolumesList(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
volumes, err := s.daemon.Volumes(r.Form.Get("filters"))
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, &types.VolumesListResponse{Volumes: volumes})
}
func (s *Server) getVolumeByName(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
v, err := s.daemon.VolumeInspect(vars["name"])
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, v)
}
func (s *Server) postVolumesCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if err := checkForJSON(r); err != nil {
return err
}
var req types.VolumeCreateRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return err
}
volume, err := s.daemon.VolumeCreate(req.Name, req.Driver, req.DriverOpts)
if err != nil {
return err
}
return writeJSON(w, http.StatusCreated, volume)
}
func (s *Server) deleteVolumes(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if err := s.daemon.VolumeRm(vars["name"]); err != nil {
return err
}
w.WriteHeader(http.StatusNoContent)
return nil
}
-21
View File
@@ -1,21 +0,0 @@
package types
import (
"net"
"net/url"
)
// IsTimeout takes an error returned from (generally) the http package and determines if it is a timeout error.
func IsTimeout(err error) bool {
switch e := err.(type) {
case net.Error:
return e.Timeout()
case *url.Error:
if t, ok := e.Err.(net.Error); ok {
return t.Timeout()
}
return false
default:
return false
}
}
+12 -19
View File
@@ -1,10 +1,9 @@
// Package types is used for API stability in the types and response to the
// This package is used for API stability in the types and response to the
// consumers of the API stats endpoint.
package types
import "time"
// ThrottlingData stores CPU throttling stats of one running container
type ThrottlingData struct {
// Number of periods with throttling active
Periods uint64 `json:"periods"`
@@ -14,8 +13,8 @@ type ThrottlingData struct {
ThrottledTime uint64 `json:"throttled_time"`
}
// CPUUsage stores All CPU stats aggregated since container inception.
type CPUUsage struct {
// All CPU stats are aggregated since container inception.
type CpuUsage struct {
// Total CPU time consumed.
// Units: nanoseconds.
TotalUsage uint64 `json:"total_usage"`
@@ -30,14 +29,12 @@ type CPUUsage struct {
UsageInUsermode uint64 `json:"usage_in_usermode"`
}
// CPUStats aggregates and wraps all CPU related info of container
type CPUStats struct {
CPUUsage CPUUsage `json:"cpu_usage"`
type CpuStats struct {
CpuUsage CpuUsage `json:"cpu_usage"`
SystemUsage uint64 `json:"system_cpu_usage"`
ThrottlingData ThrottlingData `json:"throttling_data,omitempty"`
}
// MemoryStats aggregates All memory stats since container inception
type MemoryStats struct {
// current res_counter usage for memory
Usage uint64 `json:"usage"`
@@ -51,7 +48,6 @@ type MemoryStats struct {
Limit uint64 `json:"limit"`
}
// BlkioStatEntry is one small entity to store a piece of Blkio stats
// TODO Windows: This can be factored out
type BlkioStatEntry struct {
Major uint64 `json:"major"`
@@ -60,7 +56,6 @@ type BlkioStatEntry struct {
Value uint64 `json:"value"`
}
// BlkioStats stores All IO service stats for data read and write
// TODO Windows: This can be factored out
type BlkioStats struct {
// number of bytes tranferred to and from the block device
@@ -74,9 +69,8 @@ type BlkioStats struct {
SectorsRecursive []BlkioStatEntry `json:"sectors_recursive"`
}
// NetworkStats aggregates All network stats of one container
// TODO Windows: This will require refactoring
type NetworkStats struct {
type Network struct {
RxBytes uint64 `json:"rx_bytes"`
RxPackets uint64 `json:"rx_packets"`
RxErrors uint64 `json:"rx_errors"`
@@ -87,12 +81,11 @@ type NetworkStats struct {
TxDropped uint64 `json:"tx_dropped"`
}
// Stats is Ultimate struct aggregating all types of stats of one container
type Stats struct {
Read time.Time `json:"read"`
Network NetworkStats `json:"network,omitempty"`
PreCPUStats CPUStats `json:"precpu_stats,omitempty"`
CPUStats CPUStats `json:"cpu_stats,omitempty"`
MemoryStats MemoryStats `json:"memory_stats,omitempty"`
BlkioStats BlkioStats `json:"blkio_stats,omitempty"`
Read time.Time `json:"read"`
Network Network `json:"network,omitempty"`
PreCpuStats CpuStats `json:"precpu_stats,omitempty"`
CpuStats CpuStats `json:"cpu_stats,omitempty"`
MemoryStats MemoryStats `json:"memory_stats,omitempty"`
BlkioStats BlkioStats `json:"blkio_stats,omitempty"`
}
+25 -72
View File
@@ -19,41 +19,35 @@ type ContainerCreateResponse struct {
Warnings []string `json:"Warnings"`
}
// ContainerExecCreateResponse contains response of Remote API:
// POST "/containers/{name:.*}/exec"
// POST /containers/{name:.*}/exec
type ContainerExecCreateResponse struct {
// ID is the exec ID.
ID string `json:"Id"`
}
// AuthResponse contains response of Remote API:
// POST "/auth"
// POST /auth
type AuthResponse struct {
// Status is the authentication status
Status string `json:"Status"`
}
// ContainerWaitResponse contains response of Remote API:
// POST "/containers/"+containerID+"/wait"
type ContainerWaitResponse struct {
// StatusCode is the status code of the wait job
StatusCode int `json:"StatusCode"`
}
// ContainerCommitResponse contains response of Remote API:
// POST "/commit?container="+containerID
type ContainerCommitResponse struct {
ID string `json:"Id"`
}
// ContainerChange contains response of Remote API:
// GET "/containers/{name:.*}/changes"
type ContainerChange struct {
Kind int
Path string
}
// ImageHistory contains response of Remote API:
// GET "/images/{name:.*}/history"
type ImageHistory struct {
ID string `json:"Id"`
@@ -64,37 +58,32 @@ type ImageHistory struct {
Comment string
}
// ImageDelete contains response of Remote API:
// DELETE "/images/{name:.*}"
type ImageDelete struct {
Untagged string `json:",omitempty"`
Deleted string `json:",omitempty"`
}
// Image contains response of Remote API:
// GET "/images/json"
type Image struct {
ID string `json:"Id"`
ParentID string `json:"ParentId"`
ParentId string
RepoTags []string
RepoDigests []string
Created int64
Size int64
VirtualSize int64
Created int
Size int
VirtualSize int
Labels map[string]string
}
// GraphDriverData returns Image's graph driver config info
// when calling inspect command
type GraphDriverData struct {
Name string
Data map[string]string
}
// ImageInspect contains response of Remote API:
// GET "/images/{name:.*}/json"
type ImageInspect struct {
ID string `json:"Id"`
Id string
Parent string
Comment string
Created string
@@ -110,8 +99,7 @@ type ImageInspect struct {
GraphDriver GraphDriverData
}
// Port stores open ports info of container
// e.g. {"PrivatePort": 8080, "PublicPort": 80, "Type": "tcp"}
// GET "/containers/json"
type Port struct {
IP string `json:",omitempty"`
PrivatePort int
@@ -119,17 +107,15 @@ type Port struct {
Type string
}
// Container contains response of Remote API:
// GET "/containers/json"
type Container struct {
ID string `json:"Id"`
Names []string
Image string
Command string
Created int64
Created int
Ports []Port
SizeRw int64 `json:",omitempty"`
SizeRootFs int64 `json:",omitempty"`
SizeRw int `json:",omitempty"`
SizeRootFs int `json:",omitempty"`
Labels map[string]string
Status string
HostConfig struct {
@@ -137,15 +123,14 @@ type Container struct {
}
}
// CopyConfig contains request body of Remote API:
// POST "/containers/"+containerID+"/copy"
type CopyConfig struct {
Resource string
}
// ContainerPathStat is used to encode the header from
// GET "/containers/{name:.*}/archive"
// "Name" is the file or directory name.
// GET /containers/{name:.*}/archive
// "name" is basename of the resource.
type ContainerPathStat struct {
Name string `json:"name"`
Size int64 `json:"size"`
@@ -154,18 +139,15 @@ type ContainerPathStat struct {
LinkTarget string `json:"linkTarget"`
}
// ContainerProcessList contains response of Remote API:
// GET "/containers/{name:.*}/top"
type ContainerProcessList struct {
Processes [][]string
Titles []string
}
// Version contains response of Remote API:
// GET "/version"
type Version struct {
Version string
APIVersion version.Version `json:"ApiVersion"`
ApiVersion version.Version
GitCommit string
GoVersion string
Os string
@@ -175,7 +157,6 @@ type Version struct {
BuildTime string `json:",omitempty"`
}
// Info contains response of Remote API:
// GET "/info"
type Info struct {
ID string
@@ -185,11 +166,11 @@ type Info struct {
DriverStatus [][2]string
MemoryLimit bool
SwapLimit bool
CPUCfsPeriod bool `json:"CpuCfsPeriod"`
CPUCfsQuota bool `json:"CpuCfsQuota"`
CpuCfsPeriod bool
CpuCfsQuota bool
IPv4Forwarding bool
BridgeNfIptables bool
BridgeNfIP6tables bool `json:"BridgeNfIp6tables"`
BridgeNfIp6tables bool
Debug bool
NFd int
OomKillDisable bool
@@ -207,15 +188,15 @@ type Info struct {
NCPU int
MemTotal int64
DockerRootDir string
HTTPProxy string `json:"HttpProxy"`
HTTPSProxy string `json:"HttpsProxy"`
HttpProxy string
HttpsProxy string
NoProxy string
Name string
Labels []string
ExperimentalBuild bool
}
// ExecStartCheck is a temp struct used by execStart
// This struct is a temp struct used by execStart
// Config fields is part of ExecConfig in runconfig package
type ExecStartCheck struct {
// ExecStart will first check if it's detached
@@ -224,10 +205,7 @@ type ExecStartCheck struct {
Tty bool
}
// ContainerState stores container's running state
// it's part of ContainerJSONBase and will return by "inspect" command
type ContainerState struct {
Status string
Running bool
Paused bool
Restarting bool
@@ -240,10 +218,9 @@ type ContainerState struct {
FinishedAt string
}
// ContainerJSONBase contains response of Remote API:
// GET "/containers/{name:.*}/json"
type ContainerJSONBase struct {
ID string `json:"Id"`
Id string
Created string
Path string
Args []string
@@ -266,15 +243,13 @@ type ContainerJSONBase struct {
GraphDriver GraphDriverData
}
// ContainerJSON is newly used struct along with MountPoint
type ContainerJSON struct {
*ContainerJSONBase
Mounts []MountPoint
Config *runconfig.Config
}
// ContainerJSONPre120 is a backcompatibility struct along with ContainerConfig.
// Note this is not used by the Windows daemon.
// backcompatibility struct along with ContainerConfig
type ContainerJSONPre120 struct {
*ContainerJSONBase
Volumes map[string]string
@@ -282,15 +257,14 @@ type ContainerJSONPre120 struct {
Config *ContainerConfig
}
// ContainerConfig is a backcompatibility struct used in ContainerJSONPre120
type ContainerConfig struct {
*runconfig.Config
// backward compatibility, they now live in HostConfig
Memory int64
MemorySwap int64
CPUShares int64 `json:"CpuShares"`
CPUSet string `json:"CpuSet"`
CpuShares int64
Cpuset string
}
// MountPoint represents a mount point configuration inside the container.
@@ -299,27 +273,6 @@ type MountPoint struct {
Source string
Destination string
Driver string `json:",omitempty"`
Mode string
Mode string // this is internally named `Relabel`
RW bool
}
// Volume represents the configuration of a volume for the remote API
type Volume struct {
Name string // Name is the name of the volume
Driver string // Driver is the Driver name used to create the volume
Mountpoint string // Mountpoint is the location on disk of the volume
}
// VolumesListResponse contains the response for the remote API:
// GET "/volumes"
type VolumesListResponse struct {
Volumes []*Volume // Volumes is the list of volumes being returned
}
// VolumeCreateRequest contains the response for the remote API:
// POST "/volumes"
type VolumeCreateRequest struct {
Name string // Name is the requested name of the volume
Driver string // Driver is the name of the driver that should be used to create the volume
DriverOpts map[string]string // DriverOpts holds the driver specific options to use for when creating the volume.
}
+1 -13
View File
@@ -38,7 +38,6 @@ func NewBFlags() *BFlags {
}
// AddBool adds a bool flag to BFlags
// Note, any error will be generated when Parse() is called (see Parse).
func (bf *BFlags) AddBool(name string, def bool) *Flag {
flag := bf.addFlag(name, boolType)
if flag == nil {
@@ -53,7 +52,6 @@ func (bf *BFlags) AddBool(name string, def bool) *Flag {
}
// AddString adds a string flag to BFlags
// Note, any error will be generated when Parse() is called (see Parse).
func (bf *BFlags) AddString(name string, def string) *Flag {
flag := bf.addFlag(name, stringType)
if flag == nil {
@@ -63,9 +61,6 @@ func (bf *BFlags) AddString(name string, def string) *Flag {
return flag
}
// addFlag is a generic func used by the other AddXXX() func
// to add a new flag to the BFlags struct.
// Note, any error will be generated when Parse() is called (see Parse).
func (bf *BFlags) addFlag(name string, flagType FlagType) *Flag {
if _, ok := bf.flags[name]; ok {
bf.Err = fmt.Errorf("Duplicate flag defined: %s", name)
@@ -99,14 +94,7 @@ func (fl *Flag) IsTrue() bool {
return fl.Value == "true"
}
// Parse parses and checks if the BFlags is valid.
// Any error noticed during the AddXXX() funcs will be generated/returned
// here. We do this because an error during AddXXX() is more like a
// compile time error so it doesn't matter too much when we stop our
// processing as long as we do stop it, so this allows the code
// around AddXXX() to be just:
// defFlag := AddString("desription", "")
// w/o needing to add an if-statement around each one.
// Parse parses and checks if the BFlags is valid
func (bf *BFlags) Parse() error {
// If there was an error while defining the possible flags
// go ahead and bubble it back up here since we didn't do it
+36 -18
View File
@@ -10,7 +10,7 @@ package builder
import (
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"regexp"
"runtime"
@@ -20,8 +20,6 @@ import (
"github.com/Sirupsen/logrus"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/nat"
"github.com/docker/docker/pkg/stringutils"
"github.com/docker/docker/pkg/system"
"github.com/docker/docker/runconfig"
)
@@ -196,11 +194,7 @@ func from(b *builder, args []string, attributes map[string]bool, original string
name := args[0]
// Windows cannot support a container with no base image.
if name == NoBaseImageSpecifier {
if runtime.GOOS == "windows" {
return fmt.Errorf("Windows does not support FROM scratch")
}
b.image = ""
b.noBaseImage = true
return nil
@@ -273,15 +267,39 @@ func workdir(b *builder, args []string, attributes map[string]bool, original str
return err
}
// This is from the Dockerfile and will not necessarily be in platform
// specific semantics, hence ensure it is converted.
workdir := filepath.FromSlash(args[0])
// Note that workdir passed comes from the Dockerfile. Hence it is in
// Linux format using forward-slashes, even on Windows. However,
// b.Config.WorkingDir is in platform-specific notation (in other words
// on Windows will use `\`
workdir := args[0]
if !system.IsAbs(workdir) {
current := filepath.FromSlash(b.Config.WorkingDir)
workdir = filepath.Join(string(os.PathSeparator), current, workdir)
isAbs := false
if runtime.GOOS == "windows" {
// Alternate processing for Windows here is necessary as we can't call
// filepath.IsAbs(workDir) as that would verify Windows style paths,
// along with drive-letters (eg c:\pathto\file.txt). We (arguably
// correctly or not) check for both forward and back slashes as this
// is what the 1.4.2 GoLang implementation of IsAbs() does in the
// isSlash() function.
isAbs = workdir[0] == '\\' || workdir[0] == '/'
} else {
isAbs = filepath.IsAbs(workdir)
}
if !isAbs {
current := b.Config.WorkingDir
if runtime.GOOS == "windows" {
// Convert to Linux format before join
current = strings.Replace(current, "\\", "/", -1)
}
// Must use path.Join so works correctly on Windows, not filepath
workdir = path.Join("/", current, workdir)
}
// Convert to platform specific format
if runtime.GOOS == "windows" {
workdir = strings.Replace(workdir, "/", "\\", -1)
}
b.Config.WorkingDir = workdir
return b.commit("", b.Config.Cmd, fmt.Sprintf("WORKDIR %v", workdir))
@@ -330,7 +348,7 @@ func run(b *builder, args []string, attributes map[string]bool, original string)
b.Config.Cmd = config.Cmd
runconfig.Merge(b.Config, config)
defer func(cmd *stringutils.StrSlice) { b.Config.Cmd = cmd }(cmd)
defer func(cmd *runconfig.Command) { b.Config.Cmd = cmd }(cmd)
logrus.Debugf("[BUILDER] Command to be executed: %v", b.Config.Cmd)
@@ -383,7 +401,7 @@ func cmd(b *builder, args []string, attributes map[string]bool, original string)
}
}
b.Config.Cmd = stringutils.NewStrSlice(cmdSlice...)
b.Config.Cmd = runconfig.NewCommand(cmdSlice...)
if err := b.commit("", b.Config.Cmd, fmt.Sprintf("CMD %q", cmdSlice)); err != nil {
return err
@@ -414,16 +432,16 @@ func entrypoint(b *builder, args []string, attributes map[string]bool, original
switch {
case attributes["json"]:
// ENTRYPOINT ["echo", "hi"]
b.Config.Entrypoint = stringutils.NewStrSlice(parsed...)
b.Config.Entrypoint = runconfig.NewEntrypoint(parsed...)
case len(parsed) == 0:
// ENTRYPOINT []
b.Config.Entrypoint = nil
default:
// ENTRYPOINT echo hi
if runtime.GOOS != "windows" {
b.Config.Entrypoint = stringutils.NewStrSlice("/bin/sh", "-c", parsed[0])
b.Config.Entrypoint = runconfig.NewEntrypoint("/bin/sh", "-c", parsed[0])
} else {
b.Config.Entrypoint = stringutils.NewStrSlice("cmd", "/S /C", parsed[0])
b.Config.Entrypoint = runconfig.NewEntrypoint("cmd", "/S /C", parsed[0])
}
}
+1 -22
View File
@@ -24,7 +24,6 @@ import (
"io"
"os"
"path/filepath"
"runtime"
"strings"
"github.com/Sirupsen/logrus"
@@ -282,18 +281,11 @@ func (b *builder) readDockerfile() error {
// features.
func (b *builder) dispatch(stepN int, ast *parser.Node) error {
cmd := ast.Value
// To ensure the user is give a decent error message if the platform
// on which the daemon is running does not support a builder command.
if err := platformSupports(strings.ToLower(cmd)); err != nil {
return err
}
attrs := ast.Attributes
original := ast.Original
flags := ast.Flags
strs := []string{}
msg := fmt.Sprintf("Step %d : %s", stepN+1, strings.ToUpper(cmd))
msg := fmt.Sprintf("Step %d : %s", stepN, strings.ToUpper(cmd))
if len(ast.Flags) > 0 {
msg += " " + strings.Join(ast.Flags, " ")
@@ -357,16 +349,3 @@ func (b *builder) dispatch(stepN int, ast *parser.Node) error {
return fmt.Errorf("Unknown instruction: %s", strings.ToUpper(cmd))
}
// platformSupports is a short-term function to give users a quality error
// message if a Dockerfile uses a command not supported on the platform.
func platformSupports(command string) error {
if runtime.GOOS != "windows" {
return nil
}
switch command {
case "expose", "volume", "user":
return fmt.Errorf("The daemon on this platform does not support the command '%s'", command)
}
return nil
}
+30 -28
View File
@@ -33,7 +33,6 @@ import (
"github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/progressreader"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/pkg/stringutils"
"github.com/docker/docker/pkg/system"
"github.com/docker/docker/pkg/tarsum"
"github.com/docker/docker/pkg/urlutil"
@@ -74,7 +73,7 @@ func (b *builder) readContext(context io.Reader) (err error) {
return
}
func (b *builder) commit(id string, autoCmd *stringutils.StrSlice, comment string) error {
func (b *builder) commit(id string, autoCmd *runconfig.Command, comment string) error {
if b.disableCommit {
return nil
}
@@ -85,11 +84,11 @@ func (b *builder) commit(id string, autoCmd *stringutils.StrSlice, comment strin
if id == "" {
cmd := b.Config.Cmd
if runtime.GOOS != "windows" {
b.Config.Cmd = stringutils.NewStrSlice("/bin/sh", "-c", "#(nop) "+comment)
b.Config.Cmd = runconfig.NewCommand("/bin/sh", "-c", "#(nop) "+comment)
} else {
b.Config.Cmd = stringutils.NewStrSlice("cmd", "/S /C", "REM (nop) "+comment)
b.Config.Cmd = runconfig.NewCommand("cmd", "/S /C", "REM (nop) "+comment)
}
defer func(cmd *stringutils.StrSlice) { b.Config.Cmd = cmd }(cmd)
defer func(cmd *runconfig.Command) { b.Config.Cmd = cmd }(cmd)
hit, err := b.probeCache()
if err != nil {
@@ -216,11 +215,11 @@ func (b *builder) runContextCommand(args []string, allowRemote bool, allowDecomp
cmd := b.Config.Cmd
if runtime.GOOS != "windows" {
b.Config.Cmd = stringutils.NewStrSlice("/bin/sh", "-c", fmt.Sprintf("#(nop) %s %s in %s", cmdName, srcHash, dest))
b.Config.Cmd = runconfig.NewCommand("/bin/sh", "-c", fmt.Sprintf("#(nop) %s %s in %s", cmdName, srcHash, dest))
} else {
b.Config.Cmd = stringutils.NewStrSlice("cmd", "/S /C", fmt.Sprintf("REM (nop) %s %s in %s", cmdName, srcHash, dest))
b.Config.Cmd = runconfig.NewCommand("cmd", "/S /C", fmt.Sprintf("REM (nop) %s %s in %s", cmdName, srcHash, dest))
}
defer func(cmd *stringutils.StrSlice) { b.Config.Cmd = cmd }(cmd)
defer func(cmd *runconfig.Command) { b.Config.Cmd = cmd }(cmd)
hit, err := b.probeCache()
if err != nil {
@@ -231,7 +230,7 @@ func (b *builder) runContextCommand(args []string, allowRemote bool, allowDecomp
return nil
}
container, _, err := b.Daemon.ContainerCreate("", b.Config, nil, true)
container, _, err := b.Daemon.Create(b.Config, nil, "")
if err != nil {
return err
}
@@ -242,12 +241,20 @@ func (b *builder) runContextCommand(args []string, allowRemote bool, allowDecomp
}
defer container.Unmount()
if err := container.PrepareStorage(); err != nil {
return err
}
for _, ci := range copyInfos {
if err := b.addContext(container, ci.origPath, ci.destPath, ci.decompress); err != nil {
return err
}
}
if err := container.CleanupStorage(); err != nil {
return err
}
if err := b.commit(container.ID, cmd, fmt.Sprintf("%s %s in %s", cmdName, origPaths, dest)); err != nil {
return err
}
@@ -270,7 +277,7 @@ func calcCopyInfo(b *builder, cmdName string, cInfos *[]*copyInfo, origPath stri
// Twiddle the destPath when its a relative path - meaning, make it
// relative to the WORKINGDIR
if !system.IsAbs(destPath) {
if !filepath.IsAbs(destPath) {
hasSlash := strings.HasSuffix(destPath, string(os.PathSeparator))
destPath = filepath.Join(string(os.PathSeparator), filepath.FromSlash(b.Config.WorkingDir), destPath)
@@ -323,7 +330,7 @@ func calcCopyInfo(b *builder, cmdName string, cInfos *[]*copyInfo, origPath stri
In: resp.Body,
Out: b.OutOld,
Formatter: b.StreamFormatter,
Size: resp.ContentLength,
Size: int(resp.ContentLength),
NewLines: true,
ID: "",
Action: "Downloading",
@@ -348,11 +355,8 @@ func calcCopyInfo(b *builder, cmdName string, cInfos *[]*copyInfo, origPath stri
}
}
// Windows does not support UtimesNano.
if runtime.GOOS != "windows" {
if err := system.UtimesNano(tmpFileName, times); err != nil {
return err
}
if err := system.UtimesNano(tmpFileName, times); err != nil {
return err
}
ci.origPath = filepath.Join(filepath.Base(tmpDirName), filepath.Base(tmpFileName))
@@ -363,7 +367,7 @@ func calcCopyInfo(b *builder, cmdName string, cInfos *[]*copyInfo, origPath stri
if err != nil {
return err
}
path := filepath.FromSlash(u.Path) // Ensure in platform semantics
path := u.Path
if strings.HasSuffix(path, string(os.PathSeparator)) {
path = path[:len(path)-1]
}
@@ -535,11 +539,7 @@ func (b *builder) processImageFrom(img *image.Image) error {
// Process ONBUILD triggers if they exist
if nTriggers := len(b.Config.OnBuild); nTriggers != 0 {
word := "trigger"
if nTriggers > 1 {
word = "triggers"
}
fmt.Fprintf(b.ErrStream, "# Executing %d build %s...\n", nTriggers, word)
fmt.Fprintf(b.ErrStream, "# Executing %d build triggers\n", nTriggers)
}
// Copy the ONBUILD triggers, and remove them from the config, since the config will be committed.
@@ -547,7 +547,7 @@ func (b *builder) processImageFrom(img *image.Image) error {
b.Config.OnBuild = []string{}
// parse the ONBUILD triggers by invoking the parser
for _, step := range onBuildTriggers {
for stepN, step := range onBuildTriggers {
ast, err := parser.Parse(strings.NewReader(step))
if err != nil {
return err
@@ -561,6 +561,8 @@ func (b *builder) processImageFrom(img *image.Image) error {
return fmt.Errorf("%s isn't allowed as an ONBUILD trigger", n.Value)
}
fmt.Fprintf(b.OutStream, "Trigger %d, %s\n", stepN, step)
if err := b.dispatch(i, n); err != nil {
return err
}
@@ -605,9 +607,9 @@ func (b *builder) create() (*daemon.Container, error) {
b.Config.Image = b.image
hostConfig := &runconfig.HostConfig{
CPUShares: b.cpuShares,
CPUPeriod: b.cpuPeriod,
CPUQuota: b.cpuQuota,
CpuShares: b.cpuShares,
CpuPeriod: b.cpuPeriod,
CpuQuota: b.cpuQuota,
CpusetCpus: b.cpuSetCpus,
CpusetMems: b.cpuSetMems,
CgroupParent: b.cgroupParent,
@@ -619,7 +621,7 @@ func (b *builder) create() (*daemon.Container, error) {
config := *b.Config
// Create the container
c, warnings, err := b.Daemon.ContainerCreate("", b.Config, hostConfig, true)
c, warnings, err := b.Daemon.Create(b.Config, hostConfig, "")
if err != nil {
return nil, err
}
@@ -636,7 +638,7 @@ func (b *builder) create() (*daemon.Container, error) {
c.Path = s[0]
c.Args = s[1:]
} else {
config.Cmd = stringutils.NewStrSlice()
config.Cmd = runconfig.NewCommand()
}
return c, nil
@@ -1,4 +1,4 @@
// +build freebsd linux
// +build linux
package builder
+4 -10
View File
@@ -7,7 +7,6 @@ import (
"io"
"io/ioutil"
"os"
"runtime"
"strings"
"sync"
@@ -140,7 +139,7 @@ func Build(d *daemon.Daemon, buildConfig *Config) error {
}
defer f.Body.Close()
ct := f.Header.Get("Content-Type")
clen := f.ContentLength
clen := int(f.ContentLength)
contentType, bodyReader, err := inspectResponse(ct, f.Body, clen)
defer bodyReader.Close()
@@ -183,11 +182,11 @@ func Build(d *daemon.Daemon, buildConfig *Config) error {
builder := &builder{
Daemon: d,
OutStream: &streamformatter.StdoutFormatter{
OutStream: &streamformatter.StdoutFormater{
Writer: buildConfig.Stdout,
StreamFormatter: sf,
},
ErrStream: &streamformatter.StderrFormatter{
ErrStream: &streamformatter.StderrFormater{
Writer: buildConfig.Stdout,
StreamFormatter: sf,
},
@@ -280,11 +279,6 @@ func Commit(name string, d *daemon.Daemon, c *CommitConfig) (string, error) {
return "", err
}
// It is not possible to commit a running container on Windows
if runtime.GOOS == "windows" && container.IsRunning() {
return "", fmt.Errorf("Windows does not support commit of a running container")
}
if c.Config == nil {
c.Config = &runconfig.Config{}
}
@@ -322,7 +316,7 @@ func Commit(name string, d *daemon.Daemon, c *CommitConfig) (string, error) {
// - an io.Reader for the response body
// - an error value which will be non-nil either when something goes wrong while
// reading bytes from r or when the detected content-type is not acceptable.
func inspectResponse(ct string, r io.ReadCloser, clen int64) (string, io.ReadCloser, error) {
func inspectResponse(ct string, r io.ReadCloser, clen int) (string, io.ReadCloser, error) {
plen := clen
if plen <= 0 || plen > maxPreambleLength {
plen = maxPreambleLength
+4 -4
View File
@@ -31,7 +31,7 @@ func TestInspectEmptyResponse(t *testing.T) {
func TestInspectResponseBinary(t *testing.T) {
ct := "application/octet-stream"
br := ioutil.NopCloser(bytes.NewReader(binaryContext))
contentType, bReader, err := inspectResponse(ct, br, int64(len(binaryContext)))
contentType, bReader, err := inspectResponse(ct, br, len(binaryContext))
if err != nil {
t.Fatal(err)
}
@@ -56,7 +56,7 @@ func TestResponseUnsupportedContentType(t *testing.T) {
content := []byte(textPlainDockerfile)
ct := "application/json"
br := ioutil.NopCloser(bytes.NewReader(content))
contentType, bReader, err := inspectResponse(ct, br, int64(len(textPlainDockerfile)))
contentType, bReader, err := inspectResponse(ct, br, len(textPlainDockerfile))
if err == nil {
t.Fatal("Should have returned an error on content-type 'application/json'")
@@ -77,7 +77,7 @@ func TestInspectResponseTextSimple(t *testing.T) {
content := []byte(textPlainDockerfile)
ct := "text/plain"
br := ioutil.NopCloser(bytes.NewReader(content))
contentType, bReader, err := inspectResponse(ct, br, int64(len(content)))
contentType, bReader, err := inspectResponse(ct, br, len(content))
if err != nil {
t.Fatal(err)
}
@@ -96,7 +96,7 @@ func TestInspectResponseTextSimple(t *testing.T) {
func TestInspectResponseEmptyContentType(t *testing.T) {
content := []byte(textPlainDockerfile)
br := ioutil.NopCloser(bytes.NewReader(content))
contentType, bodyReader, err := inspectResponse("", br, int64(len(content)))
contentType, bodyReader, err := inspectResponse("", br, len(content))
if err != nil {
t.Fatal(err)
}
-5
View File
@@ -232,11 +232,6 @@ func parseString(rest string) (*Node, map[string]bool, error) {
// parseJSON converts JSON arrays to an AST.
func parseJSON(rest string) (*Node, map[string]bool, error) {
rest = strings.TrimLeftFunc(rest, unicode.IsSpace)
if !strings.HasPrefix(rest, "[") {
return nil, nil, fmt.Errorf(`Error parsing "%s" as a JSON array`, rest)
}
var myJSON []interface{}
if err := json.NewDecoder(strings.NewReader(rest)).Decode(&myJSON); err != nil {
return nil, nil, err
+1 -1
View File
@@ -42,7 +42,7 @@ var (
func init() {
// Dispatch Table. see line_parsers.go for the parse functions.
// The command is parsed and mapped to the line parser. The line parser
// receives the arguments but not the command, and returns an AST after
// recieves the arguments but not the command, and returns an AST after
// reformulating the arguments according to the rules in the parser
// functions. Errors are propagated up by Parse() and the resulting AST can
// be incorporated directly into the existing AST as a next.
@@ -3,8 +3,6 @@ MAINTAINER Seongyeol Lim <seongyeol37@gmail.com>
COPY . /go/src/github.com/docker/docker
ADD . /
ADD null /
COPY nullfile /tmp
ADD [ "vimrc", "/tmp" ]
COPY [ "bashrc", "/tmp" ]
COPY [ "test file", "/tmp" ]
@@ -2,8 +2,6 @@
(maintainer "Seongyeol Lim <seongyeol37@gmail.com>")
(copy "." "/go/src/github.com/docker/docker")
(add "." "/")
(add "null" "/")
(copy "nullfile" "/tmp")
(add "vimrc" "/tmp")
(copy "bashrc" "/tmp")
(copy "test file" "/tmp")
-42
View File
@@ -49,45 +49,3 @@ func TestShellParser(t *testing.T) {
}
}
}
func TestGetEnv(t *testing.T) {
sw := &shellWord{
word: "",
envs: nil,
pos: 0,
}
sw.envs = []string{}
if sw.getEnv("foo") != "" {
t.Fatalf("2 - 'foo' should map to ''")
}
sw.envs = []string{"foo"}
if sw.getEnv("foo") != "" {
t.Fatalf("3 - 'foo' should map to ''")
}
sw.envs = []string{"foo="}
if sw.getEnv("foo") != "" {
t.Fatalf("4 - 'foo' should map to ''")
}
sw.envs = []string{"foo=bar"}
if sw.getEnv("foo") != "bar" {
t.Fatalf("5 - 'foo' should map to 'bar'")
}
sw.envs = []string{"foo=bar", "car=hat"}
if sw.getEnv("foo") != "bar" {
t.Fatalf("6 - 'foo' should map to 'bar'")
}
if sw.getEnv("car") != "hat" {
t.Fatalf("7 - 'car' should map to 'hat'")
}
// Make sure we grab the first 'car' in the list
sw.envs = []string{"foo=bar", "car=hat", "car=bike"}
if sw.getEnv("car") != "hat" {
t.Fatalf("8 - 'car' should map to 'hat'")
}
}
+59 -106
View File
@@ -4,7 +4,6 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
@@ -15,7 +14,7 @@ import (
)
const (
// ConfigFileName is the name of config file
// ConfigFile is the name of config file
ConfigFileName = "config.json"
oldConfigfile = ".dockercfg"
@@ -71,88 +70,6 @@ func NewConfigFile(fn string) *ConfigFile {
}
}
// LegacyLoadFromReader reads the non-nested configuration data given and sets up the
// auth config information with given directory and populates the receiver object
func (configFile *ConfigFile) LegacyLoadFromReader(configData io.Reader) error {
b, err := ioutil.ReadAll(configData)
if err != nil {
return err
}
if err := json.Unmarshal(b, &configFile.AuthConfigs); err != nil {
arr := strings.Split(string(b), "\n")
if len(arr) < 2 {
return fmt.Errorf("The Auth config file is empty")
}
authConfig := AuthConfig{}
origAuth := strings.Split(arr[0], " = ")
if len(origAuth) != 2 {
return fmt.Errorf("Invalid Auth config file")
}
authConfig.Username, authConfig.Password, err = DecodeAuth(origAuth[1])
if err != nil {
return err
}
origEmail := strings.Split(arr[1], " = ")
if len(origEmail) != 2 {
return fmt.Errorf("Invalid Auth config file")
}
authConfig.Email = origEmail[1]
authConfig.ServerAddress = defaultIndexserver
configFile.AuthConfigs[defaultIndexserver] = authConfig
} else {
for k, authConfig := range configFile.AuthConfigs {
authConfig.Username, authConfig.Password, err = DecodeAuth(authConfig.Auth)
if err != nil {
return err
}
authConfig.Auth = ""
authConfig.ServerAddress = k
configFile.AuthConfigs[k] = authConfig
}
}
return nil
}
// LoadFromReader reads the configuration data given and sets up the auth config
// information with given directory and populates the receiver object
func (configFile *ConfigFile) LoadFromReader(configData io.Reader) error {
if err := json.NewDecoder(configData).Decode(&configFile); err != nil {
return err
}
var err error
for addr, ac := range configFile.AuthConfigs {
ac.Username, ac.Password, err = DecodeAuth(ac.Auth)
if err != nil {
return err
}
ac.Auth = ""
ac.ServerAddress = addr
configFile.AuthConfigs[addr] = ac
}
return nil
}
// LegacyLoadFromReader is a convenience function that creates a ConfigFile object from
// a non-nested reader
func LegacyLoadFromReader(configData io.Reader) (*ConfigFile, error) {
configFile := ConfigFile{
AuthConfigs: make(map[string]AuthConfig),
}
err := configFile.LegacyLoadFromReader(configData)
return &configFile, err
}
// LoadFromReader is a convenience function that creates a ConfigFile object from
// a reader
func LoadFromReader(configData io.Reader) (*ConfigFile, error) {
configFile := ConfigFile{
AuthConfigs: make(map[string]AuthConfig),
}
err := configFile.LoadFromReader(configData)
return &configFile, err
}
// Load reads the configuration files in the given directory, and sets up
// the auth config information and return values.
// FIXME: use the internal golang config parser
@@ -173,8 +90,22 @@ func Load(configDir string) (*ConfigFile, error) {
return &configFile, err
}
defer file.Close()
err = configFile.LoadFromReader(file)
return &configFile, err
if err := json.NewDecoder(file).Decode(&configFile); err != nil {
return &configFile, err
}
for addr, ac := range configFile.AuthConfigs {
ac.Username, ac.Password, err = DecodeAuth(ac.Auth)
if err != nil {
return &configFile, err
}
ac.Auth = ""
ac.ServerAddress = addr
configFile.AuthConfigs[addr] = ac
}
return &configFile, nil
} else if !os.IsNotExist(err) {
// if file is there but we can't stat it for any reason other
// than it doesn't exist then stop
@@ -186,18 +117,49 @@ func Load(configDir string) (*ConfigFile, error) {
if _, err := os.Stat(confFile); err != nil {
return &configFile, nil //missing file is not an error
}
file, err := os.Open(confFile)
b, err := ioutil.ReadFile(confFile)
if err != nil {
return &configFile, err
}
defer file.Close()
err = configFile.LegacyLoadFromReader(file)
return &configFile, err
if err := json.Unmarshal(b, &configFile.AuthConfigs); err != nil {
arr := strings.Split(string(b), "\n")
if len(arr) < 2 {
return &configFile, fmt.Errorf("The Auth config file is empty")
}
authConfig := AuthConfig{}
origAuth := strings.Split(arr[0], " = ")
if len(origAuth) != 2 {
return &configFile, fmt.Errorf("Invalid Auth config file")
}
authConfig.Username, authConfig.Password, err = DecodeAuth(origAuth[1])
if err != nil {
return &configFile, err
}
origEmail := strings.Split(arr[1], " = ")
if len(origEmail) != 2 {
return &configFile, fmt.Errorf("Invalid Auth config file")
}
authConfig.Email = origEmail[1]
authConfig.ServerAddress = defaultIndexserver
configFile.AuthConfigs[defaultIndexserver] = authConfig
} else {
for k, authConfig := range configFile.AuthConfigs {
authConfig.Username, authConfig.Password, err = DecodeAuth(authConfig.Auth)
if err != nil {
return &configFile, err
}
authConfig.Auth = ""
authConfig.ServerAddress = k
configFile.AuthConfigs[k] = authConfig
}
}
return &configFile, nil
}
// SaveToWriter encodes and writes out all the authorization information to
// the given writer
func (configFile *ConfigFile) SaveToWriter(writer io.Writer) error {
// Save encodes and writes out all the authorization information
func (configFile *ConfigFile) Save() error {
// Encode sensitive data into a new/temp struct
tmpAuthConfigs := make(map[string]AuthConfig, len(configFile.AuthConfigs))
for k, authConfig := range configFile.AuthConfigs {
@@ -218,25 +180,16 @@ func (configFile *ConfigFile) SaveToWriter(writer io.Writer) error {
if err != nil {
return err
}
_, err = writer.Write(data)
return err
}
// Save encodes and writes out all the authorization information
func (configFile *ConfigFile) Save() error {
if configFile.Filename() == "" {
return fmt.Errorf("Can't save config with empty filename")
}
if err := system.MkdirAll(filepath.Dir(configFile.filename), 0700); err != nil {
return err
}
f, err := os.OpenFile(configFile.filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
if err := ioutil.WriteFile(configFile.filename, data, 0600); err != nil {
return err
}
defer f.Close()
return configFile.SaveToWriter(f)
return nil
}
// Filename returns the name of the configuration file
+92 -362
View File
@@ -4,41 +4,15 @@ import (
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"github.com/docker/docker/pkg/homedir"
)
func TestEmptyConfigDir(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpHome)
SetConfigDir(tmpHome)
config, err := Load("")
if err != nil {
t.Fatalf("Failed loading on empty config dir: %q", err)
}
expectedConfigFilename := filepath.Join(tmpHome, ConfigFileName)
if config.Filename() != expectedConfigFilename {
t.Fatalf("Expected config filename %s, got %s", expectedConfigFilename, config.Filename())
}
// Now save it and make sure it shows up in new form
saveConfigAndValidateNewFormat(t, config, tmpHome)
}
func TestMissingFile(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpHome)
tmpHome, _ := ioutil.TempDir("", "config-test")
config, err := Load(tmpHome)
if err != nil {
@@ -46,15 +20,19 @@ func TestMissingFile(t *testing.T) {
}
// Now save it and make sure it shows up in new form
saveConfigAndValidateNewFormat(t, config, tmpHome)
err = config.Save()
if err != nil {
t.Fatalf("Failed to save: %q", err)
}
buf, err := ioutil.ReadFile(filepath.Join(tmpHome, ConfigFileName))
if !strings.Contains(string(buf), `"auths":`) {
t.Fatalf("Should have save in new form: %s", string(buf))
}
}
func TestSaveFileToDirs(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpHome)
tmpHome, _ := ioutil.TempDir("", "config-test")
tmpHome += "/.docker"
@@ -64,38 +42,32 @@ func TestSaveFileToDirs(t *testing.T) {
}
// Now save it and make sure it shows up in new form
saveConfigAndValidateNewFormat(t, config, tmpHome)
err = config.Save()
if err != nil {
t.Fatalf("Failed to save: %q", err)
}
buf, err := ioutil.ReadFile(filepath.Join(tmpHome, ConfigFileName))
if !strings.Contains(string(buf), `"auths":`) {
t.Fatalf("Should have save in new form: %s", string(buf))
}
}
func TestEmptyFile(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpHome)
tmpHome, _ := ioutil.TempDir("", "config-test")
fn := filepath.Join(tmpHome, ConfigFileName)
if err := ioutil.WriteFile(fn, []byte(""), 0600); err != nil {
t.Fatal(err)
}
ioutil.WriteFile(fn, []byte(""), 0600)
_, err = Load(tmpHome)
_, err := Load(tmpHome)
if err == nil {
t.Fatalf("Was supposed to fail")
}
}
func TestEmptyJson(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpHome)
tmpHome, _ := ioutil.TempDir("", "config-test")
fn := filepath.Join(tmpHome, ConfigFileName)
if err := ioutil.WriteFile(fn, []byte("{}"), 0600); err != nil {
t.Fatal(err)
}
ioutil.WriteFile(fn, []byte("{}"), 0600)
config, err := Load(tmpHome)
if err != nil {
@@ -103,276 +75,36 @@ func TestEmptyJson(t *testing.T) {
}
// Now save it and make sure it shows up in new form
saveConfigAndValidateNewFormat(t, config, tmpHome)
}
func TestOldInvalidsAuth(t *testing.T) {
invalids := map[string]string{
`username = test`: "The Auth config file is empty",
`username
password
email`: "Invalid Auth config file",
`username = test
email`: "Invalid auth configuration file",
`username = am9lam9lOmhlbGxv
email`: "Invalid Auth config file",
}
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpHome)
homeKey := homedir.Key()
homeVal := homedir.Get()
defer func() { os.Setenv(homeKey, homeVal) }()
os.Setenv(homeKey, tmpHome)
for content, expectedError := range invalids {
fn := filepath.Join(tmpHome, oldConfigfile)
if err := ioutil.WriteFile(fn, []byte(content), 0600); err != nil {
t.Fatal(err)
}
config, err := Load(tmpHome)
if err == nil || err.Error() != expectedError {
t.Fatalf("Should have failed, got: %q, %q", config, err)
}
}
}
func TestOldValidAuth(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
}
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpHome)
homeKey := homedir.Key()
homeVal := homedir.Get()
defer func() { os.Setenv(homeKey, homeVal) }()
os.Setenv(homeKey, tmpHome)
fn := filepath.Join(tmpHome, oldConfigfile)
js := `username = am9lam9lOmhlbGxv
email = user@example.com`
if err := ioutil.WriteFile(fn, []byte(js), 0600); err != nil {
t.Fatal(err)
}
config, err := Load(tmpHome)
if err != nil {
t.Fatal(err)
}
// defaultIndexserver is https://index.docker.io/v1/
ac := config.AuthConfigs["https://index.docker.io/v1/"]
if ac.Email != "user@example.com" || ac.Username != "joejoe" || ac.Password != "hello" {
t.Fatalf("Missing data from parsing:\n%q", config)
}
// Now save it and make sure it shows up in new form
configStr := saveConfigAndValidateNewFormat(t, config, tmpHome)
if !strings.Contains(configStr, "user@example.com") {
t.Fatalf("Should have save in new form: %s", configStr)
}
}
func TestOldJsonInvalid(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpHome)
homeKey := homedir.Key()
homeVal := homedir.Get()
defer func() { os.Setenv(homeKey, homeVal) }()
os.Setenv(homeKey, tmpHome)
fn := filepath.Join(tmpHome, oldConfigfile)
js := `{"https://index.docker.io/v1/":{"auth":"test","email":"user@example.com"}}`
if err := ioutil.WriteFile(fn, []byte(js), 0600); err != nil {
t.Fatal(err)
}
config, err := Load(tmpHome)
if err == nil || err.Error() != "Invalid auth configuration file" {
t.Fatalf("Expected an error got : %v, %v", config, err)
}
}
func TestOldJson(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpHome)
homeKey := homedir.Key()
homeVal := homedir.Get()
defer func() { os.Setenv(homeKey, homeVal) }()
os.Setenv(homeKey, tmpHome)
fn := filepath.Join(tmpHome, oldConfigfile)
js := `{"https://index.docker.io/v1/":{"auth":"am9lam9lOmhlbGxv","email":"user@example.com"}}`
if err := ioutil.WriteFile(fn, []byte(js), 0600); err != nil {
t.Fatal(err)
}
config, err := Load(tmpHome)
if err != nil {
t.Fatalf("Failed loading on empty json file: %q", err)
}
ac := config.AuthConfigs["https://index.docker.io/v1/"]
if ac.Email != "user@example.com" || ac.Username != "joejoe" || ac.Password != "hello" {
t.Fatalf("Missing data from parsing:\n%q", config)
}
// Now save it and make sure it shows up in new form
configStr := saveConfigAndValidateNewFormat(t, config, tmpHome)
if !strings.Contains(configStr, "user@example.com") {
t.Fatalf("Should have save in new form: %s", configStr)
}
}
func TestNewJson(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpHome)
fn := filepath.Join(tmpHome, ConfigFileName)
js := ` { "auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv", "email": "user@example.com" } } }`
if err := ioutil.WriteFile(fn, []byte(js), 0600); err != nil {
t.Fatal(err)
}
config, err := Load(tmpHome)
if err != nil {
t.Fatalf("Failed loading on empty json file: %q", err)
}
ac := config.AuthConfigs["https://index.docker.io/v1/"]
if ac.Email != "user@example.com" || ac.Username != "joejoe" || ac.Password != "hello" {
t.Fatalf("Missing data from parsing:\n%q", config)
}
// Now save it and make sure it shows up in new form
configStr := saveConfigAndValidateNewFormat(t, config, tmpHome)
if !strings.Contains(configStr, "user@example.com") {
t.Fatalf("Should have save in new form: %s", configStr)
}
}
func TestJsonWithPsFormat(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpHome)
fn := filepath.Join(tmpHome, ConfigFileName)
js := `{
"auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv", "email": "user@example.com" } },
"psFormat": "table {{.ID}}\\t{{.Label \"com.docker.label.cpu\"}}"
}`
if err := ioutil.WriteFile(fn, []byte(js), 0600); err != nil {
t.Fatal(err)
}
config, err := Load(tmpHome)
if err != nil {
t.Fatalf("Failed loading on empty json file: %q", err)
}
if config.PsFormat != `table {{.ID}}\t{{.Label "com.docker.label.cpu"}}` {
t.Fatalf("Unknown ps format: %s\n", config.PsFormat)
}
// Now save it and make sure it shows up in new form
configStr := saveConfigAndValidateNewFormat(t, config, tmpHome)
if !strings.Contains(configStr, `"psFormat":`) ||
!strings.Contains(configStr, "{{.ID}}") {
t.Fatalf("Should have save in new form: %s", configStr)
}
}
// Save it and make sure it shows up in new form
func saveConfigAndValidateNewFormat(t *testing.T, config *ConfigFile, homeFolder string) string {
err := config.Save()
err = config.Save()
if err != nil {
t.Fatalf("Failed to save: %q", err)
}
buf, err := ioutil.ReadFile(filepath.Join(homeFolder, ConfigFileName))
buf, err := ioutil.ReadFile(filepath.Join(tmpHome, ConfigFileName))
if !strings.Contains(string(buf), `"auths":`) {
t.Fatalf("Should have save in new form: %s", string(buf))
}
return string(buf)
}
func TestConfigDir(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
func TestOldJson(t *testing.T) {
if runtime.GOOS == "windows" {
return
}
tmpHome, _ := ioutil.TempDir("", "config-test")
defer os.RemoveAll(tmpHome)
if ConfigDir() == tmpHome {
t.Fatalf("Expected ConfigDir to be different than %s by default, but was the same", tmpHome)
}
homeKey := homedir.Key()
homeVal := homedir.Get()
// Update configDir
SetConfigDir(tmpHome)
defer func() { os.Setenv(homeKey, homeVal) }()
os.Setenv(homeKey, tmpHome)
if ConfigDir() != tmpHome {
t.Fatalf("Expected ConfigDir to %s, but was %s", tmpHome, ConfigDir())
}
}
func TestConfigFile(t *testing.T) {
configFilename := "configFilename"
configFile := NewConfigFile(configFilename)
if configFile.Filename() != configFilename {
t.Fatalf("Expected %s, got %s", configFilename, configFile.Filename())
}
}
func TestJsonReaderNoFile(t *testing.T) {
js := ` { "auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv", "email": "user@example.com" } } }`
config, err := LoadFromReader(strings.NewReader(js))
if err != nil {
t.Fatalf("Failed loading on empty json file: %q", err)
}
ac := config.AuthConfigs["https://index.docker.io/v1/"]
if ac.Email != "user@example.com" || ac.Username != "joejoe" || ac.Password != "hello" {
t.Fatalf("Missing data from parsing:\n%q", config)
}
}
func TestOldJsonReaderNoFile(t *testing.T) {
fn := filepath.Join(tmpHome, oldConfigfile)
js := `{"https://index.docker.io/v1/":{"auth":"am9lam9lOmhlbGxv","email":"user@example.com"}}`
ioutil.WriteFile(fn, []byte(js), 0600)
config, err := LegacyLoadFromReader(strings.NewReader(js))
config, err := Load(tmpHome)
if err != nil {
t.Fatalf("Failed loading on empty json file: %q", err)
}
@@ -381,14 +113,59 @@ func TestOldJsonReaderNoFile(t *testing.T) {
if ac.Email != "user@example.com" || ac.Username != "joejoe" || ac.Password != "hello" {
t.Fatalf("Missing data from parsing:\n%q", config)
}
// Now save it and make sure it shows up in new form
err = config.Save()
if err != nil {
t.Fatalf("Failed to save: %q", err)
}
buf, err := ioutil.ReadFile(filepath.Join(tmpHome, ConfigFileName))
if !strings.Contains(string(buf), `"auths":`) ||
!strings.Contains(string(buf), "user@example.com") {
t.Fatalf("Should have save in new form: %s", string(buf))
}
}
func TestJsonWithPsFormatNoFile(t *testing.T) {
func TestNewJson(t *testing.T) {
tmpHome, _ := ioutil.TempDir("", "config-test")
fn := filepath.Join(tmpHome, ConfigFileName)
js := ` { "auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv", "email": "user@example.com" } } }`
ioutil.WriteFile(fn, []byte(js), 0600)
config, err := Load(tmpHome)
if err != nil {
t.Fatalf("Failed loading on empty json file: %q", err)
}
ac := config.AuthConfigs["https://index.docker.io/v1/"]
if ac.Email != "user@example.com" || ac.Username != "joejoe" || ac.Password != "hello" {
t.Fatalf("Missing data from parsing:\n%q", config)
}
// Now save it and make sure it shows up in new form
err = config.Save()
if err != nil {
t.Fatalf("Failed to save: %q", err)
}
buf, err := ioutil.ReadFile(filepath.Join(tmpHome, ConfigFileName))
if !strings.Contains(string(buf), `"auths":`) ||
!strings.Contains(string(buf), "user@example.com") {
t.Fatalf("Should have save in new form: %s", string(buf))
}
}
func TestJsonWithPsFormat(t *testing.T) {
tmpHome, _ := ioutil.TempDir("", "config-test")
fn := filepath.Join(tmpHome, ConfigFileName)
js := `{
"auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv", "email": "user@example.com" } },
"psFormat": "table {{.ID}}\\t{{.Label \"com.docker.label.cpu\"}}"
}`
config, err := LoadFromReader(strings.NewReader(js))
ioutil.WriteFile(fn, []byte(js), 0600)
config, err := Load(tmpHome)
if err != nil {
t.Fatalf("Failed loading on empty json file: %q", err)
}
@@ -397,62 +174,15 @@ func TestJsonWithPsFormatNoFile(t *testing.T) {
t.Fatalf("Unknown ps format: %s\n", config.PsFormat)
}
}
func TestJsonSaveWithNoFile(t *testing.T) {
js := `{
"auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv", "email": "user@example.com" } },
"psFormat": "table {{.ID}}\\t{{.Label \"com.docker.label.cpu\"}}"
}`
config, err := LoadFromReader(strings.NewReader(js))
// Now save it and make sure it shows up in new form
err = config.Save()
if err == nil {
t.Fatalf("Expected error. File should not have been able to save with no file name.")
if err != nil {
t.Fatalf("Failed to save: %q", err)
}
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatalf("Failed to create a temp dir: %q", err)
}
defer os.RemoveAll(tmpHome)
fn := filepath.Join(tmpHome, ConfigFileName)
f, _ := os.OpenFile(fn, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
err = config.SaveToWriter(f)
if err != nil {
t.Fatalf("Failed saving to file: %q", err)
}
buf, err := ioutil.ReadFile(filepath.Join(tmpHome, ConfigFileName))
if !strings.Contains(string(buf), `"auths":`) ||
!strings.Contains(string(buf), "user@example.com") {
t.Fatalf("Should have save in new form: %s", string(buf))
}
}
func TestLegacyJsonSaveWithNoFile(t *testing.T) {
js := `{"https://index.docker.io/v1/":{"auth":"am9lam9lOmhlbGxv","email":"user@example.com"}}`
config, err := LegacyLoadFromReader(strings.NewReader(js))
err = config.Save()
if err == nil {
t.Fatalf("Expected error. File should not have been able to save with no file name.")
}
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatalf("Failed to create a temp dir: %q", err)
}
defer os.RemoveAll(tmpHome)
fn := filepath.Join(tmpHome, ConfigFileName)
f, _ := os.OpenFile(fn, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
err = config.SaveToWriter(f)
if err != nil {
t.Fatalf("Failed saving to file: %q", err)
}
buf, err := ioutil.ReadFile(filepath.Join(tmpHome, ConfigFileName))
if !strings.Contains(string(buf), `"auths":`) ||
!strings.Contains(string(buf), "user@example.com") {
if !strings.Contains(string(buf), `"psFormat":`) ||
!strings.Contains(string(buf), "{{.ID}}") {
t.Fatalf("Should have save in new form: %s", string(buf))
}
}
-59
View File
@@ -41,9 +41,6 @@ profile /usr/bin/docker (attach_disconnected, complain) {
/sbin/iptables rCx,
/sbin/modprobe rCx,
/sbin/auplink rCx,
/sbin/mke2fs rCx,
/sbin/tune2fs rCx,
/sbin/blkid rCx,
/bin/kmod rCx,
/usr/bin/xz rCx,
/bin/ps rCx,
@@ -151,60 +148,4 @@ profile /usr/bin/docker (attach_disconnected, complain) {
file,
capability,
}
profile /sbin/mke2fs (complain) {
/sbin/mke2fs rm,
/lib/** r,
/apparmor/.null w,
/etc/ld.so.cache r,
/etc/mke2fs.conf r,
/etc/mtab r,
/dev/dm-* rw,
/dev/urandom r,
/dev/null rw,
/proc/swaps r,
/proc/[0-9]*/mounts r,
}
profile /sbin/tune2fs (complain) {
/sbin/tune2fs rm,
/lib/** r,
/apparmor/.null w,
/etc/blkid.conf r,
/etc/mtab r,
/etc/ld.so.cache r,
/dev/null rw,
/dev/.blkid.tab r,
/dev/dm-* rw,
/proc/swaps r,
/proc/[0-9]*/mounts r,
}
profile /sbin/blkid (complain) {
/sbin/blkid rm,
/lib/** r,
/apparmor/.null w,
/etc/ld.so.cache r,
/etc/blkid.conf r,
/dev/null rw,
/dev/.blkid.tab rl,
/dev/.blkid.tab* rwl,
/dev/dm-* r,
/sys/devices/virtual/block/** r,
capability mknod,
mount -> @{DOCKER_GRAPH_PATH}/**,
}
}
+3 -2
View File
@@ -2,9 +2,10 @@
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/deb/generate.sh"!
#
FROM debian:wheezy-backports
FROM debian:wheezy
RUN echo deb http://http.debian.net/debian wheezy-backports main > /etc/apt/sources.list.d/wheezy-backports.list
RUN apt-get update && apt-get install -y bash-completion btrfs-tools/wheezy-backports build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
+7 -13
View File
@@ -22,13 +22,6 @@ for version in "${versions[@]}"; do
suite="${version##*-}"
from="${distro}:${suite}"
case "$from" in
debian:wheezy)
# add -backports, like our users have to
from+='-backports'
;;
esac
mkdir -p "$version"
echo "$version -> FROM $from"
cat > "$version/Dockerfile" <<-EOF
@@ -39,6 +32,13 @@ for version in "${versions[@]}"; do
FROM $from
EOF
case "$from" in
debian:wheezy)
# add -backports, like our users have to
echo "RUN echo deb http://http.debian.net/debian $suite-backports main > /etc/apt/sources.list.d/$suite-backports.list" >> "$version/Dockerfile"
;;
esac
echo >> "$version/Dockerfile"
extraBuildTags=
@@ -73,12 +73,6 @@ for version in "${versions[@]}"; do
extraBuildTags+=' exclude_graphdriver_btrfs'
fi
if [ "$suite" = 'wheezy' ]; then
# pull btrfs-toold from backports
backports="/$suite-backports"
packages=( "${packages[@]/btrfs-tools/btrfs-tools$backports}" )
fi
echo "RUN apt-get update && apt-get install -y ${packages[*]} --no-install-recommends && rm -rf /var/lib/apt/lists/*" >> "$version/Dockerfile"
echo >> "$version/Dockerfile"
@@ -2,7 +2,7 @@
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/deb/generate.sh"!
#
FROM ubuntu:precise
FROM ubuntu-debootstrap:precise
RUN apt-get update && apt-get install -y bash-completion build-essential curl ca-certificates debhelper git libapparmor-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
@@ -2,7 +2,7 @@
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/deb/generate.sh"!
#
FROM ubuntu:trusty
FROM ubuntu-debootstrap:trusty
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
@@ -2,7 +2,7 @@
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/deb/generate.sh"!
#
FROM ubuntu:vivid
FROM ubuntu-debootstrap:vivid
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
@@ -2,7 +2,7 @@
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/deb/generate.sh"!
#
FROM ubuntu:wily
FROM ubuntu-debootstrap:wily
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
+1 -1
View File
@@ -6,7 +6,7 @@ FROM centos:7
RUN yum groupinstall -y "Development Tools"
RUN yum -y swap -- remove systemd-container systemd-container-libs -- install systemd systemd-libs
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel selinux-policy selinux-policy-devel sqlite-devel tar
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel sqlite-devel tar
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
+15
View File
@@ -0,0 +1,15 @@
#
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/rpm/generate.sh"!
#
FROM fedora:20
RUN yum install -y @development-tools fedora-packager
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel sqlite-devel tar
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
ENV PATH $PATH:/usr/local/go/bin
ENV AUTO_GOPATH 1
ENV DOCKER_BUILDTAGS selinux
+1 -1
View File
@@ -5,7 +5,7 @@
FROM fedora:21
RUN yum install -y @development-tools fedora-packager
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel selinux-policy selinux-policy-devel sqlite-devel tar
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel sqlite-devel tar
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
+1 -1
View File
@@ -5,7 +5,7 @@
FROM fedora:22
RUN yum install -y @development-tools fedora-packager
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel selinux-policy selinux-policy-devel sqlite-devel tar
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel sqlite-devel tar
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
-2
View File
@@ -58,8 +58,6 @@ for version in "${versions[@]}"; do
device-mapper-devel # for "libdevmapper.h"
glibc-static
libselinux-devel # for "libselinux.so"
selinux-policy
selinux-policy-devel
sqlite-devel # for "sqlite3.h"
tar # older versions of dev-tools do not have tar
)
+1 -1
View File
@@ -5,7 +5,7 @@
FROM oraclelinux:6
RUN yum groupinstall -y "Development Tools"
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel selinux-policy selinux-policy-devel sqlite-devel tar
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel sqlite-devel tar
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
+1 -1
View File
@@ -5,7 +5,7 @@
FROM oraclelinux:7
RUN yum groupinstall -y "Development Tools"
RUN yum install -y --enablerepo=ol7_optional_latest btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel selinux-policy selinux-policy-devel sqlite-devel tar
RUN yum install -y --enablerepo=ol7_optional_latest btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel sqlite-devel tar
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
+2 -8
View File
@@ -191,17 +191,11 @@ if [ "$kernelMajor" -lt 3 ] || [ "$kernelMajor" -eq 3 -a "$kernelMinor" -le 18 ]
check_flags RESOURCE_COUNTERS
fi
if [ "$kernelMajor" -lt 3 ] || [ "$kernelMajor" -eq 3 -a "$kernelMinor" -le 13 ]; then
netprio=NETPRIO_CGROUP
else
netprio=CGROUP_NET_PRIO
fi
flags=(
BLK_CGROUP IOSCHED_CFQ BLK_DEV_THROTTLING
BLK_CGROUP IOSCHED_CFQ
CGROUP_PERF
CGROUP_HUGETLB
NET_CLS_CGROUP $netprio
NET_CLS_CGROUP NETPRIO_CGROUP
CFS_BANDWIDTH FAIR_GROUP_SCHED RT_GROUP_SCHED
)
check_flags "${flags[@]}"
Regular → Executable
+30 -139
View File
@@ -14,22 +14,6 @@
# - copy this file to e.g. ~/.docker-completion.sh and add the line
# below to your .bashrc after bash completion features are loaded
# . ~/.docker-completion.sh
#
# Configuration:
#
# You can tailor completion for the "events", "history", "inspect", "run",
# "rmi" and "save" commands by settings the following environment
# variables:
#
# DOCKER_COMPLETION_SHOW_IMAGE_IDS
# "none" - Show names only (default)
# "non-intermediate" - Show names and ids, but omit intermediate image IDs
# "all" - Show names and ids, including intermediate image IDs
#
# DOCKER_COMPLETION_SHOW_TAGS
# "yes" - include tags in completion options (default)
# "no" - don't include tags in completion options
#
# Note:
# Currently, the completions will not work if the docker daemon is not
@@ -86,40 +70,6 @@ __docker_container_ids() {
COMPREPLY=( $(compgen -W "${containers[*]}" -- "$cur") )
}
__docker_images() {
local images_args=""
case "$DOCKER_COMPLETION_SHOW_IMAGE_IDS" in
all)
images_args="--no-trunc -a"
;;
non-intermediate)
images_args="--no-trunc"
;;
esac
local repo_print_command
if [ "${DOCKER_COMPLETION_SHOW_TAGS:-yes}" = "yes" ]; then
repo_print_command='print $1; print $1":"$2'
else
repo_print_command='print $1'
fi
local awk_script
case "$DOCKER_COMPLETION_SHOW_IMAGE_IDS" in
all|non-intermediate)
awk_script='NR>1 { print $3; if ($1 != "<none>") { '"$repo_print_command"' } }'
;;
none|*)
awk_script='NR>1 && $1 != "<none>" { '"$repo_print_command"' }'
;;
esac
local images=$(__docker_q images $images_args | awk "$awk_script")
COMPREPLY=( $(compgen -W "$images" -- "$cur") )
__ltrim_colon_completions "$cur"
}
__docker_image_repos() {
local repos="$(__docker_q images | awk 'NR>1 && $1 != "<none>" { print $1 }')"
COMPREPLY=( $(compgen -W "$repos" -- "$cur") )
@@ -131,10 +81,16 @@ __docker_image_repos_and_tags() {
__ltrim_colon_completions "$cur"
}
__docker_image_repos_and_tags_and_ids() {
local images="$(__docker_q images -a --no-trunc | awk 'NR>1 { print $3; if ($1 != "<none>") { print $1; print $1":"$2 } }')"
COMPREPLY=( $(compgen -W "$images" -- "$cur") )
__ltrim_colon_completions "$cur"
}
__docker_containers_and_images() {
__docker_containers_all
local containers=( "${COMPREPLY[@]}" )
__docker_images
__docker_image_repos_and_tags_and_ids
COMPREPLY+=( "${containers[@]}" )
}
@@ -183,7 +139,7 @@ __docker_value_of_option() {
local counter=$((command_pos + 1))
while [ $counter -lt $cword ]; do
case ${words[$counter]} in
@($option_glob) )
$option_glob )
echo ${words[$counter + 1]}
break
;;
@@ -273,12 +229,11 @@ __docker_log_driver_options() {
# see docs/reference/logging/index.md
local fluentd_options="fluentd-address fluentd-tag"
local gelf_options="gelf-address gelf-tag"
local json_file_options="max-file max-size"
local syslog_options="syslog-address syslog-facility syslog-tag"
case $(__docker_value_of_option --log-driver) in
'')
COMPREPLY=( $( compgen -W "$fluentd_options $gelf_options $json_file_options $syslog_options" -S = -- "$cur" ) )
COMPREPLY=( $( compgen -W "$fluentd_options $gelf_options $syslog_options" -S = -- "$cur" ) )
;;
fluentd)
COMPREPLY=( $( compgen -W "$fluentd_options" -S = -- "$cur" ) )
@@ -286,9 +241,6 @@ __docker_log_driver_options() {
gelf)
COMPREPLY=( $( compgen -W "$gelf_options" -S = -- "$cur" ) )
;;
json-file)
COMPREPLY=( $( compgen -W "$json_file_options" -S = -- "$cur" ) )
;;
syslog)
COMPREPLY=( $( compgen -W "$syslog_options" -S = -- "$cur" ) )
;;
@@ -368,7 +320,7 @@ __docker_signals() {
_docker_docker() {
local boolean_options="
$global_boolean_options
--help
--help -h
--version -v
"
@@ -386,6 +338,8 @@ _docker_docker() {
;;
esac
__docker_complete_log_driver_options && return
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "$boolean_options $global_options_with_args" -- "$cur" ) )
@@ -506,7 +460,7 @@ _docker_create() {
_docker_daemon() {
local boolean_options="
$global_boolean_options
--help
--help -h
--icc=false
--ip-forward=false
--ip-masq=false
@@ -558,39 +512,7 @@ _docker_daemon() {
return
;;
--storage-driver|-s)
COMPREPLY=( $( compgen -W "aufs btrfs devicemapper overlay vfs zfs" -- "$(echo $cur | tr '[:upper:]' '[:lower:]')" ) )
return
;;
--storage-opt)
local devicemapper_options="
dm.basesize
dm.blkdiscard
dm.blocksize
dm.fs
dm.loopdatasize
dm.loopmetadatasize
dm.mkfsarg
dm.mountopt
dm.override_udev_sync_check
dm.thinpooldev
"
local zfs_options="zfs.fsname"
case $(__docker_value_of_option '--storage-driver|-s') in
'')
COMPREPLY=( $( compgen -W "$devicemapper_options $zfs_options" -S = -- "$cur" ) )
;;
devicemapper)
COMPREPLY=( $( compgen -W "$devicemapper_options" -S = -- "$cur" ) )
;;
zfs)
COMPREPLY=( $( compgen -W "$zfs_options" -S = -- "$cur" ) )
;;
*)
return
;;
esac
compopt -o nospace
COMPREPLY=( $( compgen -W "aufs devicemapper btrfs overlay" -- "$(echo $cur | tr '[:upper:]' '[:lower:]')" ) )
return
;;
--log-level|-l)
@@ -606,28 +528,6 @@ _docker_daemon() {
;;
esac
__docker_complete_log_driver_options && return
# completions for --storage-opt
case "${words[$cword-2]}$prev=" in
*dm.blkdiscard=*)
COMPREPLY=( $( compgen -W "false true" -- "${cur#=}" ) )
return
;;
*dm.fs=*)
COMPREPLY=( $( compgen -W "ext4 xfs" -- "${cur#=}" ) )
return
;;
*dm.override_udev_sync_check=*)
COMPREPLY=( $( compgen -W "false true" -- "${cur#=}" ) )
return
;;
*dm.thinpooldev=*)
_filedir
return
;;
esac
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "$boolean_options $options_with_args" -- "$cur" ) )
@@ -699,7 +599,7 @@ _docker_events() {
;;
*image=*)
cur="${cur#=}"
__docker_images
__docker_image_repos_and_tags_and_ids
return
;;
esac
@@ -720,7 +620,7 @@ _docker_exec() {
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--detach -d --help --interactive -i --privileged -t --tty -u --user" -- "$cur" ) )
COMPREPLY=( $( compgen -W "--detach -d --help --interactive -i -t --tty -u --user" -- "$cur" ) )
;;
*)
__docker_containers_running
@@ -757,7 +657,7 @@ _docker_history() {
*)
local counter=$(__docker_pos_first_nonflag)
if [ $cword -eq $counter ]; then
__docker_images
__docker_image_repos_and_tags_and_ids
fi
;;
esac
@@ -850,7 +750,7 @@ _docker_inspect() {
__docker_containers_all
;;
image)
__docker_images
__docker_image_repos_and_tags_and_ids
;;
esac
esac
@@ -965,21 +865,16 @@ _docker_ps() {
__docker_containers_all
;;
--filter|-f)
COMPREPLY=( $( compgen -S = -W "ancestor exited id label name status" -- "$cur" ) )
COMPREPLY=( $( compgen -S = -W "exited id label name status" -- "$cur" ) )
compopt -o nospace
return
;;
--format|-n)
-n)
return
;;
esac
case "${words[$cword-2]}$prev=" in
*ancestor=*)
cur="${cur#=}"
__docker_images
return
;;
*id=*)
cur="${cur#=}"
__docker_container_ids
@@ -998,7 +893,7 @@ _docker_ps() {
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--all -a --before --filter -f --format --help --latest -l -n --no-trunc --quiet -q --size -s --since" -- "$cur" ) )
COMPREPLY=( $( compgen -W "--all -a --before --filter -f --help --latest -l -n --no-trunc --quiet -q --size -s --since" -- "$cur" ) )
;;
esac
}
@@ -1095,7 +990,7 @@ _docker_rmi() {
COMPREPLY=( $( compgen -W "--force -f --help --no-prune" -- "$cur" ) )
;;
*)
__docker_images
__docker_image_repos_and_tags_and_ids
;;
esac
}
@@ -1103,16 +998,15 @@ _docker_rmi() {
_docker_run() {
local options_with_args="
--add-host
--attach -a
--blkio-weight
--attach -a
--cap-add
--cap-drop
--cgroup-parent
--cidfile
--cpuset
--cpu-period
--cpu-quota
--cpuset-cpus
--cpuset-mems
--cpu-shares -c
--device
--dns
@@ -1124,9 +1018,8 @@ _docker_run() {
--group-add
--hostname -h
--ipc
--kernel-memory
--label-file
--label -l
--label-file
--link
--log-driver
--log-opt
@@ -1134,15 +1027,14 @@ _docker_run() {
--mac-address
--memory -m
--memory-swap
--memory-swappiness
--name
--net
--pid
--publish -p
--restart
--security-opt
--ulimit
--user -u
--ulimit
--uts
--volumes-from
--volume -v
@@ -1150,10 +1042,8 @@ _docker_run() {
"
local all_options="$options_with_args
--disable-content-trust=false
--help
--interactive -i
--oom-kill-disable
--privileged
--publish-all -P
--read-only
@@ -1163,7 +1053,7 @@ _docker_run() {
[ "$command" = "run" ] && all_options="$all_options
--detach -d
--rm
--sig-proxy=false
--sig-proxy
"
local options_with_args_glob=$(__docker_to_extglob "$options_with_args")
@@ -1305,8 +1195,9 @@ _docker_run() {
;;
*)
local counter=$( __docker_pos_first_nonflag $( __docker_to_alternatives "$options_with_args" ) )
if [ $cword -eq $counter ]; then
__docker_images
__docker_image_repos_and_tags_and_ids
fi
;;
esac
@@ -1325,7 +1216,7 @@ _docker_save() {
COMPREPLY=( $( compgen -W "--help --output -o" -- "$cur" ) )
;;
*)
__docker_images
__docker_image_repos_and_tags_and_ids
;;
esac
}
+4 -4
View File
@@ -134,9 +134,9 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s i -l interac
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l ipc -d 'Default is to create a private IPC namespace (POSIX SysV IPC) for the container'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l link -d 'Add link to another container in the form of <name|id>:alias'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l lxc-conf -d '(lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s m -l memory -d 'Memory limit (format: <number>[<unit>], where unit = b, k, m or g)'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s m -l memory -d 'Memory limit (format: <number><optional unit>, where unit = b, k, m or g)'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l mac-address -d 'Container MAC address (e.g. 92:d0:c6:0a:29:33)'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l memory-swap -d "Total memory usage (memory + swap), set '-1' to disable swap (format: <number>[<unit>], where unit = b, k, m or g)"
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l memory-swap -d "Total memory usage (memory + swap), set '-1' to disable swap (format: <number><optional unit>, where unit = b, k, m or g)"
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l name -d 'Assign a name to the container'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l net -d 'Set the Network mode for the container'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s P -l publish-all -d 'Publish all exposed ports to random ports on the host interfaces'
@@ -321,9 +321,9 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s i -l interactiv
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l ipc -d 'Default is to create a private IPC namespace (POSIX SysV IPC) for the container'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l link -d 'Add link to another container in the form of <name|id>:alias'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l lxc-conf -d '(lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s m -l memory -d 'Memory limit (format: <number>[<unit>], where unit = b, k, m or g)'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s m -l memory -d 'Memory limit (format: <number><optional unit>, where unit = b, k, m or g)'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l mac-address -d 'Container MAC address (e.g. 92:d0:c6:0a:29:33)'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l memory-swap -d "Total memory usage (memory + swap), set '-1' to disable swap (format: <number>[<unit>], where unit = b, k, m or g)"
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l memory-swap -d "Total memory usage (memory + swap), set '-1' to disable swap (format: <number><optional unit>, where unit = b, k, m or g)"
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l name -d 'Assign a name to the container'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l net -d 'Set the Network mode for the container'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s P -l publish-all -d 'Publish all exposed ports to random ports on the host interfaces'
-502
View File
@@ -1,502 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
-16
View File
@@ -1,16 +0,0 @@
TARGETS?=docker
MODULES?=${TARGETS:=.pp.bz2}
SHAREDIR?=/usr/share
all: ${TARGETS:=.pp.bz2}
%.pp.bz2: %.pp
@echo Compressing $^ -\> $@
bzip2 -9 $^
%.pp: %.te
make -f ${SHAREDIR}/selinux/devel/Makefile $@
clean:
rm -f *~ *.tc *.pp *.pp.bz2
rm -rf tmp *.tar.gz
-24
View File
@@ -1,24 +0,0 @@
/root/\.docker gen_context(system_u:object_r:docker_home_t,s0)
/usr/bin/docker -- gen_context(system_u:object_r:docker_exec_t,s0)
/usr/lib/systemd/system/docker.service -- gen_context(system_u:object_r:docker_unit_file_t,s0)
/etc/docker(/.*)? gen_context(system_u:object_r:docker_config_t,s0)
/var/lib/docker(/.*)? gen_context(system_u:object_r:docker_var_lib_t,s0)
/var/lib/kublet(/.*)? gen_context(system_u:object_r:docker_var_lib_t,s0)
/var/lib/docker/vfs(/.*)? gen_context(system_u:object_r:svirt_sandbox_file_t,s0)
/var/run/docker\.pid -- gen_context(system_u:object_r:docker_var_run_t,s0)
/var/run/docker\.sock -s gen_context(system_u:object_r:docker_var_run_t,s0)
/var/run/docker-client(/.*)? gen_context(system_u:object_r:docker_var_run_t,s0)
/var/lock/lxc(/.*)? gen_context(system_u:object_r:docker_lock_t,s0)
/var/log/lxc(/.*)? gen_context(system_u:object_r:docker_log_t,s0)
/var/lib/docker/init(/.*)? gen_context(system_u:object_r:docker_share_t,s0)
/var/lib/docker/containers/.*/hosts gen_context(system_u:object_r:docker_share_t,s0)
/var/lib/docker/containers/.*/hostname gen_context(system_u:object_r:docker_share_t,s0)
/var/lib/docker/.*/config\.env gen_context(system_u:object_r:docker_share_t,s0)
-467
View File
@@ -1,467 +0,0 @@
## <summary>The open-source application container engine.</summary>
########################################
## <summary>
## Execute docker in the docker domain.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed to transition.
## </summary>
## </param>
#
interface(`docker_domtrans',`
gen_require(`
type docker_t, docker_exec_t;
')
corecmd_search_bin($1)
domtrans_pattern($1, docker_exec_t, docker_t)
')
########################################
## <summary>
## Execute docker in the caller domain.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed to transition.
## </summary>
## </param>
#
interface(`docker_exec',`
gen_require(`
type docker_exec_t;
')
corecmd_search_bin($1)
can_exec($1, docker_exec_t)
')
########################################
## <summary>
## Search docker lib directories.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_search_lib',`
gen_require(`
type docker_var_lib_t;
')
allow $1 docker_var_lib_t:dir search_dir_perms;
files_search_var_lib($1)
')
########################################
## <summary>
## Execute docker lib directories.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_exec_lib',`
gen_require(`
type docker_var_lib_t;
')
allow $1 docker_var_lib_t:dir search_dir_perms;
can_exec($1, docker_var_lib_t)
')
########################################
## <summary>
## Read docker lib files.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_read_lib_files',`
gen_require(`
type docker_var_lib_t;
')
files_search_var_lib($1)
read_files_pattern($1, docker_var_lib_t, docker_var_lib_t)
')
########################################
## <summary>
## Read docker share files.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_read_share_files',`
gen_require(`
type docker_share_t;
')
files_search_var_lib($1)
read_files_pattern($1, docker_share_t, docker_share_t)
')
########################################
## <summary>
## Manage docker lib files.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_manage_lib_files',`
gen_require(`
type docker_var_lib_t;
')
files_search_var_lib($1)
manage_files_pattern($1, docker_var_lib_t, docker_var_lib_t)
manage_lnk_files_pattern($1, docker_var_lib_t, docker_var_lib_t)
')
########################################
## <summary>
## Manage docker lib directories.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_manage_lib_dirs',`
gen_require(`
type docker_var_lib_t;
')
files_search_var_lib($1)
manage_dirs_pattern($1, docker_var_lib_t, docker_var_lib_t)
')
########################################
## <summary>
## Create objects in a docker var lib directory
## with an automatic type transition to
## a specified private type.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
## <param name="private_type">
## <summary>
## The type of the object to create.
## </summary>
## </param>
## <param name="object_class">
## <summary>
## The class of the object to be created.
## </summary>
## </param>
## <param name="name" optional="true">
## <summary>
## The name of the object being created.
## </summary>
## </param>
#
interface(`docker_lib_filetrans',`
gen_require(`
type docker_var_lib_t;
')
filetrans_pattern($1, docker_var_lib_t, $2, $3, $4)
')
########################################
## <summary>
## Read docker PID files.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_read_pid_files',`
gen_require(`
type docker_var_run_t;
')
files_search_pids($1)
read_files_pattern($1, docker_var_run_t, docker_var_run_t)
')
########################################
## <summary>
## Execute docker server in the docker domain.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed to transition.
## </summary>
## </param>
#
interface(`docker_systemctl',`
gen_require(`
type docker_t;
type docker_unit_file_t;
')
systemd_exec_systemctl($1)
init_reload_services($1)
systemd_read_fifo_file_passwd_run($1)
allow $1 docker_unit_file_t:file read_file_perms;
allow $1 docker_unit_file_t:service manage_service_perms;
ps_process_pattern($1, docker_t)
')
########################################
## <summary>
## Read and write docker shared memory.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_rw_sem',`
gen_require(`
type docker_t;
')
allow $1 docker_t:sem rw_sem_perms;
')
#######################################
## <summary>
## Read and write the docker pty type.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_use_ptys',`
gen_require(`
type docker_devpts_t;
')
allow $1 docker_devpts_t:chr_file rw_term_perms;
')
#######################################
## <summary>
## Allow domain to create docker content
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_filetrans_named_content',`
gen_require(`
type docker_var_lib_t;
type docker_share_t;
type docker_log_t;
type docker_var_run_t;
type docker_home_t;
')
files_pid_filetrans($1, docker_var_run_t, file, "docker.pid")
files_pid_filetrans($1, docker_var_run_t, sock_file, "docker.sock")
files_pid_filetrans($1, docker_var_run_t, dir, "docker-client")
logging_log_filetrans($1, docker_log_t, dir, "lxc")
files_var_lib_filetrans($1, docker_var_lib_t, dir, "docker")
filetrans_pattern($1, docker_var_lib_t, docker_share_t, file, "config.env")
filetrans_pattern($1, docker_var_lib_t, docker_share_t, file, "hosts")
filetrans_pattern($1, docker_var_lib_t, docker_share_t, file, "hostname")
filetrans_pattern($1, docker_var_lib_t, docker_share_t, file, "resolv.conf")
filetrans_pattern($1, docker_var_lib_t, docker_share_t, dir, "init")
userdom_admin_home_dir_filetrans($1, docker_home_t, dir, ".docker")
')
########################################
## <summary>
## Connect to docker over a unix stream socket.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_stream_connect',`
gen_require(`
type docker_t, docker_var_run_t;
')
files_search_pids($1)
stream_connect_pattern($1, docker_var_run_t, docker_var_run_t, docker_t)
')
########################################
## <summary>
## Connect to SPC containers over a unix stream socket.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_spc_stream_connect',`
gen_require(`
type spc_t, spc_var_run_t;
')
files_search_pids($1)
files_write_all_pid_sockets($1)
allow $1 spc_t:unix_stream_socket connectto;
')
########################################
## <summary>
## All of the rules required to administrate
## an docker environment
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_admin',`
gen_require(`
type docker_t;
type docker_var_lib_t, docker_var_run_t;
type docker_unit_file_t;
type docker_lock_t;
type docker_log_t;
type docker_config_t;
')
allow $1 docker_t:process { ptrace signal_perms };
ps_process_pattern($1, docker_t)
admin_pattern($1, docker_config_t)
files_search_var_lib($1)
admin_pattern($1, docker_var_lib_t)
files_search_pids($1)
admin_pattern($1, docker_var_run_t)
files_search_locks($1)
admin_pattern($1, docker_lock_t)
logging_search_logs($1)
admin_pattern($1, docker_log_t)
docker_systemctl($1)
admin_pattern($1, docker_unit_file_t)
allow $1 docker_unit_file_t:service all_service_perms;
optional_policy(`
systemd_passwd_agent_exec($1)
systemd_read_fifo_file_passwd_run($1)
')
')
interface(`domain_stub_named_filetrans_domain',`
gen_require(`
attribute named_filetrans_domain;
')
')
interface(`lvm_stub',`
gen_require(`
type lvm_t;
')
')
interface(`staff_stub',`
gen_require(`
type staff_t;
')
')
interface(`virt_stub_lxc',`
gen_require(`
type virtd_lxc_t;
')
')
interface(`virt_stub_svirt_sandbox_domain',`
gen_require(`
attribute svirt_sandbox_domain;
')
')
interface(`virt_stub_svirt_sandbox_file',`
gen_require(`
type svirt_sandbox_file_t;
')
')
interface(`fs_dontaudit_remount_tmpfs',`
gen_require(`
type tmpfs_t;
')
dontaudit $1 tmpfs_t:filesystem remount;
')
interface(`dev_dontaudit_list_all_dev_nodes',`
gen_require(`
type device_t;
')
dontaudit $1 device_t:dir list_dir_perms;
')
interface(`kernel_unlabeled_entry_type',`
gen_require(`
type unlabeled_t;
')
domain_entry_file($1, unlabeled_t)
')
interface(`kernel_unlabeled_domtrans',`
gen_require(`
type unlabeled_t;
')
read_lnk_files_pattern($1, unlabeled_t, unlabeled_t)
domain_transition_pattern($1, unlabeled_t, $2)
type_transition $1 unlabeled_t:process $2;
')
interface(`files_write_all_pid_sockets',`
gen_require(`
attribute pidfile;
')
allow $1 pidfile:sock_file write_sock_file_perms;
')
interface(`dev_dontaudit_mounton_sysfs',`
gen_require(`
type sysfs_t;
')
dontaudit $1 sysfs_t:dir mounton;
')
-418
View File
@@ -1,418 +0,0 @@
policy_module(docker, 1.0.0)
########################################
#
# Declarations
#
## <desc>
## <p>
## Allow sandbox containers manage fuse files
## </p>
## </desc>
gen_tunable(virt_sandbox_use_fusefs, false)
## <desc>
## <p>
## Determine whether docker can
## connect to all TCP ports.
## </p>
## </desc>
gen_tunable(docker_connect_any, false)
type docker_t;
type docker_exec_t;
init_daemon_domain(docker_t, docker_exec_t)
domain_subj_id_change_exemption(docker_t)
domain_role_change_exemption(docker_t)
type spc_t;
domain_type(spc_t)
role system_r types spc_t;
type spc_var_run_t;
files_pid_file(spc_var_run_t)
type docker_var_lib_t;
files_type(docker_var_lib_t)
type docker_home_t;
userdom_user_home_content(docker_home_t)
type docker_config_t;
files_config_file(docker_config_t)
type docker_lock_t;
files_lock_file(docker_lock_t)
type docker_log_t;
logging_log_file(docker_log_t)
type docker_tmp_t;
files_tmp_file(docker_tmp_t)
type docker_tmpfs_t;
files_tmpfs_file(docker_tmpfs_t)
type docker_var_run_t;
files_pid_file(docker_var_run_t)
type docker_unit_file_t;
systemd_unit_file(docker_unit_file_t)
type docker_devpts_t;
term_pty(docker_devpts_t)
type docker_share_t;
files_type(docker_share_t)
########################################
#
# docker local policy
#
allow docker_t self:capability { chown kill fowner fsetid mknod net_admin net_bind_service net_raw setfcap };
allow docker_t self:tun_socket relabelto;
allow docker_t self:process { getattr signal_perms setrlimit setfscreate };
allow docker_t self:fifo_file rw_fifo_file_perms;
allow docker_t self:unix_stream_socket create_stream_socket_perms;
allow docker_t self:tcp_socket create_stream_socket_perms;
allow docker_t self:udp_socket create_socket_perms;
allow docker_t self:capability2 block_suspend;
manage_files_pattern(docker_t, docker_home_t, docker_home_t)
manage_dirs_pattern(docker_t, docker_home_t, docker_home_t)
manage_lnk_files_pattern(docker_t, docker_home_t, docker_home_t)
userdom_admin_home_dir_filetrans(docker_t, docker_home_t, dir, ".docker")
manage_dirs_pattern(docker_t, docker_config_t, docker_config_t)
manage_files_pattern(docker_t, docker_config_t, docker_config_t)
files_etc_filetrans(docker_t, docker_config_t, dir, "docker")
manage_dirs_pattern(docker_t, docker_lock_t, docker_lock_t)
manage_files_pattern(docker_t, docker_lock_t, docker_lock_t)
files_lock_filetrans(docker_t, docker_lock_t, { dir file }, "lxc")
manage_dirs_pattern(docker_t, docker_log_t, docker_log_t)
manage_files_pattern(docker_t, docker_log_t, docker_log_t)
manage_lnk_files_pattern(docker_t, docker_log_t, docker_log_t)
logging_log_filetrans(docker_t, docker_log_t, { dir file lnk_file })
allow docker_t docker_log_t:dir_file_class_set { relabelfrom relabelto };
manage_dirs_pattern(docker_t, docker_tmp_t, docker_tmp_t)
manage_files_pattern(docker_t, docker_tmp_t, docker_tmp_t)
manage_lnk_files_pattern(docker_t, docker_tmp_t, docker_tmp_t)
files_tmp_filetrans(docker_t, docker_tmp_t, { dir file lnk_file })
manage_dirs_pattern(docker_t, docker_tmpfs_t, docker_tmpfs_t)
manage_files_pattern(docker_t, docker_tmpfs_t, docker_tmpfs_t)
manage_lnk_files_pattern(docker_t, docker_tmpfs_t, docker_tmpfs_t)
manage_fifo_files_pattern(docker_t, docker_tmpfs_t, docker_tmpfs_t)
manage_chr_files_pattern(docker_t, docker_tmpfs_t, docker_tmpfs_t)
manage_blk_files_pattern(docker_t, docker_tmpfs_t, docker_tmpfs_t)
allow docker_t docker_tmpfs_t:dir relabelfrom;
can_exec(docker_t, docker_tmpfs_t)
fs_tmpfs_filetrans(docker_t, docker_tmpfs_t, { dir file })
allow docker_t docker_tmpfs_t:chr_file mounton;
manage_dirs_pattern(docker_t, docker_share_t, docker_share_t)
manage_files_pattern(docker_t, docker_share_t, docker_share_t)
manage_lnk_files_pattern(docker_t, docker_share_t, docker_share_t)
allow docker_t docker_share_t:dir_file_class_set { relabelfrom relabelto };
can_exec(docker_t, docker_share_t)
#docker_filetrans_named_content(docker_t)
manage_dirs_pattern(docker_t, docker_var_lib_t, docker_var_lib_t)
manage_chr_files_pattern(docker_t, docker_var_lib_t, docker_var_lib_t)
manage_blk_files_pattern(docker_t, docker_var_lib_t, docker_var_lib_t)
manage_files_pattern(docker_t, docker_var_lib_t, docker_var_lib_t)
manage_lnk_files_pattern(docker_t, docker_var_lib_t, docker_var_lib_t)
allow docker_t docker_var_lib_t:dir_file_class_set { relabelfrom relabelto };
files_var_lib_filetrans(docker_t, docker_var_lib_t, { dir file lnk_file })
manage_dirs_pattern(docker_t, docker_var_run_t, docker_var_run_t)
manage_files_pattern(docker_t, docker_var_run_t, docker_var_run_t)
manage_sock_files_pattern(docker_t, docker_var_run_t, docker_var_run_t)
manage_lnk_files_pattern(docker_t, docker_var_run_t, docker_var_run_t)
files_pid_filetrans(docker_t, docker_var_run_t, { dir file lnk_file sock_file })
allow docker_t docker_devpts_t:chr_file { relabelfrom rw_chr_file_perms setattr_chr_file_perms };
term_create_pty(docker_t, docker_devpts_t)
kernel_read_system_state(docker_t)
kernel_read_network_state(docker_t)
kernel_read_all_sysctls(docker_t)
kernel_rw_net_sysctls(docker_t)
kernel_setsched(docker_t)
kernel_read_all_proc(docker_t)
domain_use_interactive_fds(docker_t)
domain_dontaudit_read_all_domains_state(docker_t)
corecmd_exec_bin(docker_t)
corecmd_exec_shell(docker_t)
corenet_tcp_bind_generic_node(docker_t)
corenet_tcp_sendrecv_generic_if(docker_t)
corenet_tcp_sendrecv_generic_node(docker_t)
corenet_tcp_sendrecv_generic_port(docker_t)
corenet_tcp_bind_all_ports(docker_t)
corenet_tcp_connect_http_port(docker_t)
corenet_tcp_connect_commplex_main_port(docker_t)
corenet_udp_sendrecv_generic_if(docker_t)
corenet_udp_sendrecv_generic_node(docker_t)
corenet_udp_sendrecv_all_ports(docker_t)
corenet_udp_bind_generic_node(docker_t)
corenet_udp_bind_all_ports(docker_t)
files_read_config_files(docker_t)
files_dontaudit_getattr_all_dirs(docker_t)
files_dontaudit_getattr_all_files(docker_t)
fs_read_cgroup_files(docker_t)
fs_read_tmpfs_symlinks(docker_t)
fs_search_all(docker_t)
fs_getattr_all_fs(docker_t)
storage_raw_rw_fixed_disk(docker_t)
auth_use_nsswitch(docker_t)
auth_dontaudit_getattr_shadow(docker_t)
init_read_state(docker_t)
init_status(docker_t)
logging_send_audit_msgs(docker_t)
logging_send_syslog_msg(docker_t)
miscfiles_read_localization(docker_t)
mount_domtrans(docker_t)
seutil_read_default_contexts(docker_t)
seutil_read_config(docker_t)
sysnet_dns_name_resolve(docker_t)
sysnet_exec_ifconfig(docker_t)
optional_policy(`
rpm_exec(docker_t)
rpm_read_db(docker_t)
rpm_exec(docker_t)
')
optional_policy(`
fstools_domtrans(docker_t)
')
optional_policy(`
iptables_domtrans(docker_t)
')
optional_policy(`
openvswitch_stream_connect(docker_t)
')
#
# lxc rules
#
allow docker_t self:capability { dac_override setgid setpcap setuid sys_admin sys_boot sys_chroot sys_ptrace };
allow docker_t self:process { getcap setcap setexec setpgid setsched signal_perms };
allow docker_t self:netlink_route_socket rw_netlink_socket_perms;;
allow docker_t self:netlink_audit_socket create_netlink_socket_perms;
allow docker_t self:unix_dgram_socket { create_socket_perms sendto };
allow docker_t self:unix_stream_socket { create_stream_socket_perms connectto };
allow docker_t docker_var_lib_t:dir mounton;
allow docker_t docker_var_lib_t:chr_file mounton;
can_exec(docker_t, docker_var_lib_t)
kernel_dontaudit_setsched(docker_t)
kernel_get_sysvipc_info(docker_t)
kernel_request_load_module(docker_t)
kernel_mounton_messages(docker_t)
kernel_mounton_all_proc(docker_t)
kernel_mounton_all_sysctls(docker_t)
kernel_unlabeled_entry_type(spc_t)
kernel_unlabeled_domtrans(docker_t, spc_t)
dev_getattr_all(docker_t)
dev_getattr_sysfs_fs(docker_t)
dev_read_urand(docker_t)
dev_read_lvm_control(docker_t)
dev_rw_sysfs(docker_t)
dev_rw_loop_control(docker_t)
dev_rw_lvm_control(docker_t)
files_getattr_isid_type_dirs(docker_t)
files_manage_isid_type_dirs(docker_t)
files_manage_isid_type_files(docker_t)
files_manage_isid_type_symlinks(docker_t)
files_manage_isid_type_chr_files(docker_t)
files_manage_isid_type_blk_files(docker_t)
files_exec_isid_files(docker_t)
files_mounton_isid(docker_t)
files_mounton_non_security(docker_t)
files_mounton_isid_type_chr_file(docker_t)
fs_mount_all_fs(docker_t)
fs_unmount_all_fs(docker_t)
fs_remount_all_fs(docker_t)
files_mounton_isid(docker_t)
fs_manage_cgroup_dirs(docker_t)
fs_manage_cgroup_files(docker_t)
fs_relabelfrom_xattr_fs(docker_t)
fs_relabelfrom_tmpfs(docker_t)
fs_read_tmpfs_symlinks(docker_t)
fs_list_hugetlbfs(docker_t)
term_use_generic_ptys(docker_t)
term_use_ptmx(docker_t)
term_getattr_pty_fs(docker_t)
term_relabel_pty_fs(docker_t)
term_mounton_unallocated_ttys(docker_t)
modutils_domtrans_insmod(docker_t)
systemd_status_all_unit_files(docker_t)
systemd_start_systemd_services(docker_t)
userdom_stream_connect(docker_t)
userdom_search_user_home_content(docker_t)
userdom_read_all_users_state(docker_t)
userdom_relabel_user_home_files(docker_t)
userdom_relabel_user_tmp_files(docker_t)
userdom_relabel_user_tmp_dirs(docker_t)
optional_policy(`
gpm_getattr_gpmctl(docker_t)
')
optional_policy(`
dbus_system_bus_client(docker_t)
init_dbus_chat(docker_t)
init_start_transient_unit(docker_t)
optional_policy(`
systemd_dbus_chat_logind(docker_t)
')
optional_policy(`
firewalld_dbus_chat(docker_t)
')
')
optional_policy(`
udev_read_db(docker_t)
')
optional_policy(`
virt_read_config(docker_t)
virt_exec(docker_t)
virt_stream_connect(docker_t)
virt_stream_connect_sandbox(docker_t)
virt_exec_sandbox_files(docker_t)
virt_manage_sandbox_files(docker_t)
virt_relabel_sandbox_filesystem(docker_t)
# for lxc
virt_transition_svirt_sandbox(docker_t, system_r)
virt_mounton_sandbox_file(docker_t)
# virt_attach_sandbox_tun_iface(docker_t)
allow docker_t svirt_sandbox_domain:tun_socket relabelfrom;
')
tunable_policy(`docker_connect_any',`
corenet_tcp_connect_all_ports(docker_t)
corenet_sendrecv_all_packets(docker_t)
corenet_tcp_sendrecv_all_ports(docker_t)
')
########################################
#
# spc local policy
#
domain_entry_file(spc_t, docker_share_t)
domain_entry_file(spc_t, docker_var_lib_t)
role system_r types spc_t;
domain_entry_file(spc_t, docker_share_t)
domain_entry_file(spc_t, docker_var_lib_t)
domtrans_pattern(docker_t, docker_share_t, spc_t)
domtrans_pattern(docker_t, docker_var_lib_t, spc_t)
allow docker_t spc_t:process { setsched signal_perms };
ps_process_pattern(docker_t, spc_t)
allow docker_t spc_t:socket_class_set { relabelto relabelfrom };
optional_policy(`
dbus_chat_system_bus(spc_t)
')
optional_policy(`
unconfined_domain_noaudit(spc_t)
')
optional_policy(`
unconfined_domain(docker_t)
')
optional_policy(`
virt_transition_svirt_sandbox(spc_t, system_r)
')
########################################
#
# docker upstream policy
#
optional_policy(`
# domain_stub_named_filetrans_domain()
gen_require(`
attribute named_filetrans_domain;
')
docker_filetrans_named_content(named_filetrans_domain)
')
optional_policy(`
lvm_stub()
docker_rw_sem(lvm_t)
')
optional_policy(`
staff_stub()
docker_stream_connect(staff_t)
docker_exec(staff_t)
')
optional_policy(`
virt_stub_lxc()
docker_exec_lib(virtd_lxc_t)
')
optional_policy(`
virt_stub_svirt_sandbox_domain()
virt_stub_svirt_sandbox_file()
allow svirt_sandbox_domain self:netlink_kobject_uevent_socket create_socket_perms;
docker_read_share_files(svirt_sandbox_domain)
docker_lib_filetrans(svirt_sandbox_domain,svirt_sandbox_file_t, sock_file)
docker_use_ptys(svirt_sandbox_domain)
docker_spc_stream_connect(svirt_sandbox_domain)
fs_list_tmpfs(svirt_sandbox_domain)
fs_rw_hugetlbfs_files(svirt_sandbox_domain)
fs_dontaudit_remount_tmpfs(svirt_sandbox_domain)
dev_dontaudit_mounton_sysfs(svirt_sandbox_domain)
tunable_policy(`virt_sandbox_use_fusefs',`
fs_manage_fusefs_dirs(svirt_sandbox_domain)
fs_manage_fusefs_files(svirt_sandbox_domain)
fs_manage_fusefs_symlinks(svirt_sandbox_domain)
')
gen_require(`
attribute domain;
')
dontaudit svirt_sandbox_domain domain:key {search link};
')
Binary file not shown.
Regular → Executable
+24 -9
View File
@@ -1,19 +1,34 @@
#!/sbin/openrc-run
#!/sbin/runscript
# Copyright 1999-2013 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: $
command="${DOCKER_BINARY:-/usr/bin/docker}"
pidfile="${DOCKER_PIDFILE:-/run/${RC_SVCNAME}.pid}"
command_args="daemon -p \"${pidfile}\" ${DOCKER_OPTS}"
DOCKER_LOGFILE="${DOCKER_LOGFILE:-/var/log/${RC_SVCNAME}.log}"
start_stop_daemon_args="--background \
--stderr \"${DOCKER_LOGFILE}\" --stdout \"${DOCKER_LOGFILE}\""
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_pre() {
start() {
checkpath -f -m 0644 -o root:docker "$DOCKER_LOGFILE"
ulimit -n 1048576
ulimit -u 1048576
return 0
ebegin "Starting docker daemon"
start-stop-daemon --start --background \
--exec "$DOCKER_BINARY" \
--pidfile "$DOCKER_PIDFILE" \
--stdout "$DOCKER_LOGFILE" \
--stderr "$DOCKER_LOGFILE" \
-- daemon -p "$DOCKER_PIDFILE" \
$DOCKER_OPTS
eend $?
}
stop() {
ebegin "Stopping docker daemon"
start-stop-daemon --stop \
--exec "$DOCKER_BINARY" \
--pidfile "$DOCKER_PIDFILE"
eend $?
}
+1 -14
View File
@@ -41,14 +41,7 @@ prestart() {
}
start() {
if [ ! -x $exec ]; then
if [ ! -e $exec ]; then
echo "Docker executable $exec not found"
else
echo "You do not have permission to execute the Docker executable $exec"
fi
exit 5
fi
[ -x $exec ] || exit 5
check_for_cleanup
@@ -65,13 +58,7 @@ start() {
while [ ! -f $pidfile -a $tries -lt 10 ]; do
sleep 1
tries=$((tries + 1))
echo -n '.'
done
if [ ! -f $pidfile ]; then
failure
echo
exit 1
fi
success
echo
else
+1 -1
View File
@@ -31,7 +31,7 @@
*
* This sample list was compiled as a combination of all the syscalls
* available on i386 and amd64 on Ubuntu Precise, as such it may not contain
* everything and not everything may be relevant for your system. This
* everything and not everything may be relevent for your system. This
* shouldn't be a problem.
*/
+1 -2
View File
@@ -8,5 +8,4 @@ targets_from() {
git ls-tree -r --name-only origin/master contrib/builder/deb | grep '/Dockerfile$' | sed -r 's!^contrib/builder/deb/|-debootstrap|/Dockerfile$!!g'
}
release_branch=$(git ls-remote --heads https://github.com/docker/docker.git | awk -F 'refs/heads/' '$2 ~ /^release/ { print $2 }' | sort -V | tail -1)
{ targets_from master; targets_from "$release_branch"; } | sort -u
{ targets_from master; targets_from release; } | sort -u
+1 -1
View File
@@ -31,7 +31,7 @@ stop on runlevel [!2345]
respawn
script
/usr/bin/docker daemon -H=tcp://0.0.0.0:2375
/usr/bin/docker -d -H=tcp://0.0.0.0:2375
end script
```
+1
View File
@@ -3,6 +3,7 @@ This directory contains code pertaining to running containers and storing images
Code pertaining to running containers:
- execdriver
- networkdriver
Code pertaining to storing images:
+28 -28
View File
@@ -5,7 +5,6 @@ import (
"io"
"os"
"path/filepath"
"strings"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/archive"
@@ -18,7 +17,7 @@ import (
// path does not refer to a directory.
var ErrExtractPointNotDirectory = errors.New("extraction point is not a directory")
// ContainerCopy performs a deprecated operation of archiving the resource at
// ContainerCopy performs a depracated operation of archiving the resource at
// the specified path in the conatiner identified by the given name.
func (daemon *Daemon) ContainerCopy(name string, res string) (io.ReadCloser, error) {
container, err := daemon.Get(name)
@@ -26,11 +25,11 @@ func (daemon *Daemon) ContainerCopy(name string, res string) (io.ReadCloser, err
return nil, err
}
if res[0] == '/' || res[0] == '\\' {
if res[0] == '/' {
res = res[1:]
}
return container.copy(res)
return container.Copy(res)
}
// ContainerStatPath stats the filesystem resource at the specified path in the
@@ -96,7 +95,7 @@ func (container *Container) resolvePath(path string) (resolvedPath, absPath stri
}
// statPath is the unexported version of StatPath. Locks and mounts should
// be acquired before calling this method and the given path should be fully
// be aquired before calling this method and the given path should be fully
// resolved to a path on the host corresponding to the given absolute path
// inside the container.
func (container *Container) statPath(resolvedPath, absPath string) (stat *types.ContainerPathStat, err error) {
@@ -143,7 +142,7 @@ func (container *Container) StatPath(path string) (stat *types.ContainerPathStat
defer container.Unmount()
err = container.mountVolumes()
defer container.unmountVolumes(true)
defer container.UnmountVolumes(true)
if err != nil {
return nil, err
}
@@ -178,7 +177,7 @@ func (container *Container) ArchivePath(path string) (content io.ReadCloser, sta
defer func() {
if err != nil {
// unmount any volumes
container.unmountVolumes(true)
container.UnmountVolumes(true)
// unmount the container's rootfs
container.Unmount()
}
@@ -213,13 +212,13 @@ func (container *Container) ArchivePath(path string) (content io.ReadCloser, sta
content = ioutils.NewReadCloserWrapper(data, func() error {
err := data.Close()
container.unmountVolumes(true)
container.UnmountVolumes(true)
container.Unmount()
container.Unlock()
return err
})
container.logEvent("archive-path")
container.LogEvent("archive-path")
return content, stat, nil
}
@@ -240,7 +239,7 @@ func (container *Container) ExtractToDir(path string, noOverwriteDirNonDir bool,
defer container.Unmount()
err = container.mountVolumes()
defer container.unmountVolumes(true)
defer container.UnmountVolumes(true)
if err != nil {
return err
}
@@ -276,22 +275,7 @@ func (container *Container) ExtractToDir(path string, noOverwriteDirNonDir bool,
// Use the resolved path relative to the container rootfs as the new
// absPath. This way we fully follow any symlinks in a volume that may
// lead back outside the volume.
//
// The Windows implementation of filepath.Rel in golang 1.4 does not
// support volume style file path semantics. On Windows when using the
// filter driver, we are guaranteed that the path will always be
// a volume file path.
var baseRel string
if strings.HasPrefix(resolvedPath, `\\?\Volume{`) {
if strings.HasPrefix(resolvedPath, container.basefs) {
baseRel = resolvedPath[len(container.basefs):]
if baseRel[:1] == `\` {
baseRel = baseRel[1:]
}
}
} else {
baseRel, err = filepath.Rel(container.basefs, resolvedPath)
}
baseRel, err := filepath.Rel(container.basefs, resolvedPath)
if err != nil {
return err
}
@@ -304,7 +288,7 @@ func (container *Container) ExtractToDir(path string, noOverwriteDirNonDir bool,
}
if !toVolume && container.hostConfig.ReadonlyRootfs {
return ErrRootFSReadOnly
return ErrContainerRootfsReadonly
}
options := &archive.TarOptions{
@@ -318,7 +302,23 @@ func (container *Container) ExtractToDir(path string, noOverwriteDirNonDir bool,
return err
}
container.logEvent("extract-to-dir")
container.LogEvent("extract-to-dir")
return nil
}
// checkIfPathIsInAVolume checks if the path is in a volume. If it is, it
// cannot be in a read-only volume. If it is not in a volume, the container
// cannot be configured with a read-only rootfs.
func checkIfPathIsInAVolume(container *Container, absPath string) (bool, error) {
var toVolume bool
for _, mnt := range container.MountPoints {
if toVolume = mnt.hasResource(absPath); toVolume {
if mnt.RW {
break
}
return false, ErrVolumeReadonly
}
}
return toVolume, nil
}
-19
View File
@@ -1,19 +0,0 @@
// +build !windows
package daemon
// checkIfPathIsInAVolume checks if the path is in a volume. If it is, it
// cannot be in a read-only volume. If it is not in a volume, the container
// cannot be configured with a read-only rootfs.
func checkIfPathIsInAVolume(container *Container, absPath string) (bool, error) {
var toVolume bool
for _, mnt := range container.MountPoints {
if toVolume = mnt.hasResource(absPath); toVolume {
if mnt.RW {
break
}
return false, ErrVolumeReadonly
}
}
return toVolume, nil
}
-10
View File
@@ -1,10 +0,0 @@
package daemon
// checkIfPathIsInAVolume checks if the path is in a volume. If it is, it
// cannot be in a read-only volume. If it is not in a volume, the container
// cannot be configured with a read-only rootfs.
//
// This is a no-op on Windows which does not support volumes.
func checkIfPathIsInAVolume(container *Container, absPath string) (bool, error) {
return false, nil
}
+2 -7
View File
@@ -6,7 +6,6 @@ import (
"github.com/docker/docker/pkg/stdcopy"
)
// ContainerAttachWithLogsConfig holds the streams to use when connecting to a container to view logs.
type ContainerAttachWithLogsConfig struct {
InStream io.ReadCloser
OutStream io.Writer
@@ -14,7 +13,6 @@ type ContainerAttachWithLogsConfig struct {
Logs, Stream bool
}
// ContainerAttachWithLogs attaches to logs according to the config passed in. See ContainerAttachWithLogsConfig.
func (daemon *Daemon) ContainerAttachWithLogs(container *Container, c *ContainerAttachWithLogsConfig) error {
var errStream io.Writer
@@ -38,18 +36,15 @@ func (daemon *Daemon) ContainerAttachWithLogs(container *Container, c *Container
stderr = errStream
}
return container.attachWithLogs(stdin, stdout, stderr, c.Logs, c.Stream)
return container.AttachWithLogs(stdin, stdout, stderr, c.Logs, c.Stream)
}
// ContainerWsAttachWithLogsConfig attach with websockets, since all
// stream data is delegated to the websocket to handle, there
type ContainerWsAttachWithLogsConfig struct {
InStream io.ReadCloser
OutStream, ErrStream io.Writer
Logs, Stream bool
}
// ContainerWsAttachWithLogs websocket connection
func (daemon *Daemon) ContainerWsAttachWithLogs(container *Container, c *ContainerWsAttachWithLogsConfig) error {
return container.attachWithLogs(c.InStream, c.OutStream, c.ErrStream, c.Logs, c.Stream)
return container.AttachWithLogs(c.InStream, c.OutStream, c.ErrStream, c.Logs, c.Stream)
}

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