Compare commits

...

212 Commits

Author SHA1 Message Date
Michael Crosby
7c8fca2ddb Bump to version 1.6.2
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
2015-05-11 15:05:16 -07:00
Michael Crosby
376188dcd3 Update libcontainer to 227771c8f611f03639f0ee
This fixes regressions for docker containers mounting into
/sys/fs/cgroup.

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
2015-05-11 15:05:07 -07:00
David Calavera
dc610864aa Merge pull request #13072 from jfrazelle/bump_v1.6.1
Bump v1.6.1
2015-05-07 14:59:23 -07:00
Jessica Frazelle
97cd073598 Bump version to 1.6.1
Signed-off-by: Jessica Frazelle <jess@docker.com>
2015-05-07 10:07:01 -07:00
Michael Crosby
d5ebb60bdd Allow libcontainer to eval symlink destination
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>

Add tests for mounting into /proc and /sys

These two locations should be prohibited from mounting volumes into
those destinations.

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
2015-04-30 14:08:02 -07:00
Michael Crosby
83c5131acd Update libcontainer to 1b471834b45063b61e0aedefbb1
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
2015-04-30 14:07:52 -07:00
Michael Crosby
b6a9dc399b Mask reads from timer_stats and latency_stats
These files in /proc should not be able to be read as well
as written to.

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
2015-04-30 10:25:26 -07:00
Michael Crosby
614a9690e7 Mount RO for timer_stats and latency_stats in proc
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
2015-04-22 11:15:26 -07:00
Michael Crosby
545b440a80 Mount /proc/fs as readonly
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
2015-04-22 11:15:17 -07:00
Michael Crosby
3162024e28 Prevent write access to /proc/asound
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>

Conflicts:
	integration-cli/docker_cli_run_test.go
2015-04-22 11:14:46 -07:00
Jessie Frazelle
769acfec29 Merge pull request #11635 from jfrazelle/bump_v1.6.0
Bump v1.6.0
2015-04-16 12:31:02 -07:00
Jessica Frazelle
47496519da Bump version to v1.6.0
Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)
2015-04-16 11:38:05 -07:00
Mary Anthony
fdd21bf032 for 1.6
Signed-off-by: Mary Anthony <mary@docker.com>
(cherry picked from commit f44aa3b1fb)
2015-04-16 11:37:59 -07:00
Mary Anthony
d928dad8c8 In with the old menu layout
Signed-off-by: Mary Anthony <mary@docker.com>
(cherry picked from commit fe8fb24b53)
2015-04-15 21:34:50 -07:00
Mary Anthony
82366ce059 Adding environment variables for sub projects
Fixes issue #12186
Fixing variables per Jess

Signed-off-by: Mary Anthony <mary@docker.com>
(cherry picked from commit ef8b917fac)
2015-04-15 21:34:49 -07:00
Mary Anthony
6410c3c066 Updating with man pages for distribution
Went through the man pages to update for the
v2 instance. Checked against the commands.

Signed-off-by: Mary Anthony <mary@docker.com>
(cherry picked from commit b6d55ebcbc)
2015-04-15 21:34:49 -07:00
Michael Crosby
9231dc9cc0 Ensure state is destroyed on daemont restart
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
(cherry picked from commit a5f7c4aa31)
2015-04-15 21:34:49 -07:00
Deng Guangxing
6a3f37386b Inspect show right LogPath in json-file driver
Signed-off-by: Deng Guangxing <dengguangxing@huawei.com>
(cherry picked from commit acf025ad1b)
2015-04-15 17:37:43 -07:00
Darren Shepherd
d9a0c05208 Change syslog format and facility
This patch changes two things

1. Set facility to LOG_DAEMON
2. Remove ": " from tag so that the tag + pid become a single column in
   the log

Signed-off-by: Darren Shepherd <darren@rancher.com>
(cherry picked from commit 05641ccffc)
2015-04-15 14:49:24 -07:00
Jessica Frazelle
24cb9df189 try to modprobe bridge
Signed-off-by: Jessica Frazelle <jess@docker.com>
(cherry picked from commit b3867b8899)
2015-04-15 09:10:56 -07:00
Lewis Marshall
c51cd3298c Prevent Upstart post-start stanza from hanging
Once the job has failed and is respawned, the status becomes `docker
respawn/post-start` after subsequent failures (as opposed to `docker
stop/post-start`), so the post-start script needs to take this into
account.

I could not find specific documentation on the job transitioning to the
`respawn/post-start` state, but this was observed on Ubuntu 14.04.2.

Signed-off-by: Lewis Marshall <lewis@lmars.net>
(cherry picked from commit 302e3834a0)
2015-04-14 16:23:59 -07:00
Alexander Morozov
10affa8018 Get process list after PID 1 dead
Fix #11087

Signed-off-by: Alexander Morozov <lk4d4@docker.com>
(cherry picked from commit ac8bd12b39)
2015-04-13 12:28:22 -07:00
Deng Guangxing
ce27fa2716 move syslog-tag to syslog.New function
Signed-off-by: Deng Guangxing <dengguangxing@huawei.com>
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
(cherry picked from commit 4f91a333d5)
2015-04-13 12:17:26 -07:00
Brendan Dixon
8d83409e85 Turned off Ctrl+C processing by Windows shell
Signed-off-by: Brendan Dixon <brendand@microsoft.com>
(cherry picked from commit c337bfd2e0)
2015-04-10 16:41:59 -07:00
Nathan LeClaire
3a73b6a2bf Allow SEO crawling from docs site
Signed-off-by: Nathan LeClaire <nathan.leclaire@gmail.com>

Docker-DCO-1.1-Signed-off-by: Nathan LeClaire <nathan.leclaire@gmail.com> (github: nathanleclaire)

(cherry picked from commit de03f4797b)
2015-04-10 15:59:35 -07:00
Tianon Gravi
f99269882f Commonalize more bits of install.sh (especially standardizing around "cat <<-EOF")
Signed-off-by: Andrew "Tianon" Page <admwiggin@gmail.com>
(cherry picked from commit 6842bba163)
2015-04-10 11:20:15 -07:00
Eric Windisch
568a9703ac Wrap installer in a function
This will assure that the install script will not
begin executing until after it has been downloaded should
it be utilized in a 'curl | bash' workflow.

Signed-off-by: Eric Windisch <eric@windisch.us>
(cherry picked from commit fa961ce046)
2015-04-10 11:20:15 -07:00
Aaron Welch
faaeb5162d add centos to supported distros
Signed-off-by: Aaron Welch <welch@packet.net>
(cherry picked from commit a6b8f2e3fe)
2015-04-10 11:20:15 -07:00
Brendan Dixon
b5613baac2 Corrected int16 overflow and buffer sizes
Signed-off-by: Brendan Dixon <brendand@microsoft.com>
(cherry picked from commit a264e1e83d)
2015-04-10 11:20:15 -07:00
Alexander Morozov
c956efcd52 Update libcontainer to bd8ec36106086f72b66e1be85a81202b93503e44
Fix #12130

Signed-off-by: Alexander Morozov <lk4d4@docker.com>
(cherry picked from commit 2f853b9493)
2015-04-07 16:22:37 -07:00
Alexander Morozov
5455864187 Test case for network mode chain container -> container -> host
Issue #12130

Signed-off-by: Alexander Morozov <lk4d4@docker.com>
(cherry picked from commit ce69dafe4d)
2015-04-07 16:22:37 -07:00
Ahmet Alp Balkan
ceb72fab34 Swap width/height in GetWinsize and monitorTtySize
Signed-off-by: Ahmet Alp Balkan <ahmetalpbalkan@gmail.com>
(cherry picked from commit 6e44246fed)
2015-04-06 16:55:38 -07:00
Brendan Dixon
c6ea062a26 Windows console fixes
Corrected integer size passed to Windows
Corrected DisableEcho / SetRawTerminal to not modify state
Cleaned up and made routines more idiomatic
Corrected raw mode state bits
Removed duplicate IsTerminal
Corrected off-by-one error
Minor idiomatic change

Signed-off-by: Brendan Dixon <brendand@microsoft.com>
(cherry picked from commit 1a36a113d4)
2015-04-06 11:48:33 -07:00
Ahmet Alp Balkan
0e045ab50c docs: Add new windows installation tutorials
Updated Windows installation documentation with newest
screencasts and Chocolatey instructions to install windows
client CLI.

Signed-off-by: Ahmet Alp Balkan <ahmetalpbalkan@gmail.com>
(cherry picked from commit 2b320a2309)
2015-04-03 13:51:53 -07:00
Michael Crosby
eeb05fc081 Update libcontainaer to d00b8369852285d6a830a8d3b9
Fixes #12015

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
(cherry picked from commit d12fef1515)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)
2015-04-02 14:52:27 -07:00
Michael Crosby
e1381ae328 Return closed channel if oom notification fails
When working with Go channels you must not set it to nil or else the
channel will block forever.  It will not panic reading from a nil chan
but it blocks.  The correct way to do this is to create the channel then
close it as the correct results to the caller will be returned.

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
(cherry picked from commit 7061a993c5)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)
2015-04-01 16:14:14 -07:00
Alexander Morozov
45ad064150 Fix panic in integration tests
Closing activationLock only if it's not closed already. This is needed
only because integration tests using docker code directly and doesn't
care about global state.

Signed-off-by: Alexander Morozov <lk4d4@docker.com>
(cherry picked from commit c717475714)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)
2015-03-31 16:43:16 -07:00
Darren Shepherd
72e14a1566 Avoid ServeApi race condition
If job "acceptconnections" is called before "serveapi" the API Accept()
method will hang forever waiting for activation.  This is due to the fact
that when "acceptconnections" ran the activation channel was nil.

Signed-off-by: Darren Shepherd <darren@rancher.com>
(cherry picked from commit 8f6a14452d)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)
2015-03-31 16:43:16 -07:00
Vincent Batts
7d7bec86c9 graphdriver: promote overlay above vfs
It's about time to let folks not hit 'vfs', when 'overlay' is supported
on their kernel. Especially now that v3.18.y is a long-term kernel.

Signed-off-by: Vincent Batts <vbatts@redhat.com>
(cherry picked from commit 2c72ff1dbf)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)
2015-03-31 14:46:09 -07:00
Derek McGowan
a39d49d676 Fix progress reader output on close
Currently the progress reader won't close properly by not setting the close size.

fixes #11849

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
(cherry picked from commit aa3083f577)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)
2015-03-31 14:18:42 -07:00
Brian Goff
5bf15a013b Use getResourcePath instead
Also cleans up tests to not shell out for file creation.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
(cherry picked from commit 63708dca8a)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)
2015-03-31 14:06:32 -07:00
Lei Jitang
9461967eec Fix create volume in a directory which is a symbolic link
Signed-off-by: Lei Jitang <leijitang@huawei.com>
(cherry picked from commit 7583b49125)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)
2015-03-31 14:06:32 -07:00
Alexander Morozov
3be7d11cee Initialize portMapper in RequestPort too
Api requesting port for daemon before init_networkdriver called.
Problem is that now initialization of api depends on initialization of
daemon and their intializations runs in parallel. Proper fix will be
just do it sequentially. For now I don't want refactor it, because it
can bring additional problems in 1.6.0.

Signed-off-by: Alexander Morozov <lk4d4@docker.com>
(cherry picked from commit 584180fce7)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)
2015-03-31 14:00:02 -07:00
Vivek Goyal
d9910b8fd8 container: Do not remove contianer if any of the resource failed cleanup
Do not remove container if any of the resource could not be cleaned up. We
don't want to leak resources.

Two new states have been created. RemovalInProgress and Dead. Once container
is Dead, it can not be started/restarted. Dead container signifies the
container where we tried to remove it but removal failed. User now needs to
figure out what went wrong, corrent the situation and try cleanup again.

RemovalInProgress signifies that container is already being removed. Only
one removal can be in progress.

Also, do not allow start of a container if it is already dead or removal is
in progress.

Also extend existing force option (-f) to docker rm to not return an error
and remove container from user view even if resource cleanup failed.
This will allow a user to get back to old behavior where resources
might leak but atleast user will be able to make progress.

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
(cherry picked from commit 40945fc186)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)
2015-03-31 14:00:02 -07:00
Michael Crosby
f115c32f6b Ensure that bridge driver does not use global mappers
This has a few hacks in it but it ensures that the bridge driver does
not use global state in the mappers, atleast as much as possible at this
point without further refactoring.  Some of the exported fields are
hacks to handle the daemon port mapping but this results in a much
cleaner approach and completely remove the global state from the mapper
and allocator.

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
(cherry picked from commit d8c628cf08)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)
2015-03-31 10:53:09 -07:00
Michael Crosby
57939badc3 Refactor port allocator to not have ANY global state
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
(cherry picked from commit 43a50b0618)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)
2015-03-31 10:53:09 -07:00
Michael Crosby
51ee02d478 Refactor portmapper to remove ALL global state
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
(cherry picked from commit 62522c9853)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)
2015-03-31 10:53:09 -07:00
Paul Bellamy
c92860748c Refactor global portallocator and portmapper state
Continuation of: #11660, working on issue #11626.

Wrapped portmapper global state into a struct. Now portallocator and
portmapper have no global state (except configuration, and a default
instance).

Unfortunately, removing the global default instances will break
```api/server/server.go:1539```, and ```daemon/daemon.go:832```, which
both call the global portallocator directly. Fixing that would be a much
bigger change, so for now, have postponed that.

Signed-off-by: Paul Bellamy <paul.a.bellamy@gmail.com>
(cherry picked from commit 87df5ab41b)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)
2015-03-31 10:53:09 -07:00
Paul Bellamy
f582f9717f Refactor global portallocator state into a global struct
Signed-off-by: Paul Bellamy <paul.a.bellamy@gmail.com>
(cherry picked from commit 1257679876)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)
2015-03-31 10:53:09 -07:00
Ahmet Alp Balkan
ebcb36a8d2 windows: monitorTtySize correctly by polling
This change makes `monitorTtySize` work correctly on windows by polling
into win32 API to get terminal size (because there's no SIGWINCH on
windows) and send it to the engine over Remove API properly.

Average getttysize syscall takes around 30-40 ms on an average windows
machine as far as I can tell, therefore in a `for` loop, checking every
250ms if size has changed or not.

I'm not sure if there's a better way to do it on windows, if so,
somebody please send a link 'cause I could not find.

Signed-off-by: Ahmet Alp Balkan <ahmetalpbalkan@gmail.com>
(cherry picked from commit ebbceea8a7)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)
2015-03-31 10:39:59 -07:00
Michael Crosby
e6e8f2d717 Update libcontainer to c8512754166539461fd860451ff
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
(cherry picked from commit 17ecbcf8ff)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)
2015-03-30 17:19:49 -07:00
Alexander Morozov
317a510261 Use proper wait function for --pid=host
Signed-off-by: Alexander Morozov <lk4d4@docker.com>
(cherry picked from commit 489ab77f4a)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)
2015-03-30 17:19:48 -07:00
Alexander Morozov
5d3a080178 Get child processes before main process die
Signed-off-by: Alexander Morozov <lk4d4@docker.com>

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)
2015-03-30 17:19:48 -07:00
Alexander Morozov
542c84c2d2 Do not mask *exec.ExitError
Fix #11764

Signed-off-by: Alexander Morozov <lk4d4@docker.com>
(cherry picked from commit f468bbb7e8)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)
2015-03-30 17:19:48 -07:00
Harald Albers
f1df74d09d Add missing filters to bash completion for docker images and docker ps
Signed-off-by: Harald Albers <github@albersweb.de>
(cherry picked from commit cf438a542e)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)
2015-03-30 16:42:53 -07:00
Derek McGowan
4ddbc7a62f Compress layers on push to a v2 registry
When buffering to file add support for compressing the tar contents. Since digest should be computed while writing buffer, include digest creation during buffer.

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
(cherry picked from commit 851c64725d)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)
2015-03-30 15:42:14 -07:00
Harald Albers
f72b2c02b8 Do not complete --cgroup-parent as _filedir
This is a follow-up on PR 11708, as suggested by tianon.

Signed-off-by: Harald Albers <github@albersweb.de>
(cherry picked from commit a09cc935c3)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)
2015-03-30 12:02:48 -07:00
Daniel, Dao Quang Minh
af9dab70f8 aufs: apply dirperm1 by default if supported
Automatically detect support for aufs `dirperm1` option and apply it.
`dirperm1` tells aufs to check the permission bits of the directory on the
topmost branch and ignore the permission bits on all lower branches.
It can be used to fix aufs' permission bug (i.e., upper layer having
broader mask than the lower layer).

More information about the bug can be found at https://github.com/docker/docker/issues/783
`dirperm1` man page is at: http://aufs.sourceforge.net/aufs3/man.html

Signed-off-by: Daniel, Dao Quang Minh <dqminh89@gmail.com>
(cherry picked from commit 281abd2c8a)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)
2015-03-30 12:02:48 -07:00
Daniel, Dao Quang Minh
10425e83f2 document dirperm1 fix for #783 in known issues
Since `dirperm1` requires a more recent aufs patch than many current OS release,
we cant remove #783 completely. This documents that docker will apply `dirperm1`
automatically for systems that support it

Signed-off-by: Daniel, Dao Quang Minh <dqminh89@gmail.com>
(cherry picked from commit d7bbe2fcb5)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)
2015-03-30 12:02:48 -07:00
Daniel, Dao Quang Minh
9c528dca85 print dirperm1 supported status in docker info
It's easier for users to check if their systems support dirperm1 just by using
docker info

Signed-off-by: Daniel, Dao Quang Minh <dqminh89@gmail.com>
(cherry picked from commit d68d5f2e4b)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)
2015-03-30 12:02:48 -07:00
Ahmet Alp Balkan
cb2c25ad2d docs: remove unused windows images
These images was just sitting around and referenced from
nowhere, nor they seemed any useful.

Signed-off-by: Ahmet Alp Balkan <ahmetalpbalkan@gmail.com>
(cherry picked from commit 986ae5d52a)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)
2015-03-30 10:46:16 -07:00
Ahmet Alp Balkan
962dec81ec Update boot2docker on Windows documentation
Boot2Docker experience is updated now that we have a Docker
client on Windows. Instead of running `boot2docker ssh`, users
can also use boot2docker on Windows Command Prompt (`cmd.exe`)
and PowerShell.

Updated documentation and screenshots, added a few details,
reorganized sections by importance, fixed a few errors.

Remaining: the video link in the Demonstration section needs
to be updated once I shoot a new video.

Signed-off-by: Ahmet Alp Balkan <ahmetalpbalkan@gmail.com>
(cherry picked from commit de09c55394)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)
2015-03-30 10:46:16 -07:00
unclejack
1eae925a3d pkg/broadcastwriter: avoid alloc w/ WriteString
Signed-off-by: Cristian Staretu <cristian.staretu@gmail.com>
(cherry picked from commit db877d8a42)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)
2015-03-30 10:46:16 -07:00
Lei Jitang
3ce2cc8ee7 Add some run option to bash completion
Signed-off-by: Lei Jitang <leijitang@huawei.com>
(cherry picked from commit 7d70736015)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)
2015-03-27 15:11:59 -07:00
Ahmet Alp Balkan
054acc4bee term/winconsole: Identify tty correctly, fix resize problem
This change fixes a bug where stdout/stderr handles are not identified
correctly.

Previously we used to set the window size to fixed size to fit the default
tty size on the host (80x24). Now the attach/exec commands can correctly
get the terminal size from windows.

We still do not `monitorTtySize()` correctly on windows and update the tty
size on the host-side, in order to fix that we'll provide a
platform-specific `monitorTtySize` implementation in the future.

Signed-off-by: Ahmet Alp Balkan <ahmetalpbalkan@gmail.com>
(cherry picked from commit 0532dcf3dc)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)
2015-03-26 16:24:40 -07:00
Don Kjer
63cb03a55b Fix for issue 9922: private registry search with auth returns 401
Signed-off-by: Don Kjer <don.kjer@gmail.com>
(cherry picked from commit 6b2eeaf896)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)
2015-03-26 13:03:50 -07:00
Arnaud Porterie
49b6f23696 Remove unused runconfig.Config.SecurityOpt field
Signed-off-by: Arnaud Porterie <arnaud.porterie@docker.com>
(cherry picked from commit e39646d2e1)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)
2015-03-25 16:22:34 -07:00
Michael Crosby
299ae6a2e6 Update libcontainer to a6044b701c166fe538fc760f9e2
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)
2015-03-25 12:23:08 -07:00
Vincent Batts
97b521bf10 make.sh: leave around the generated version
For positerity (largely of packagers) lets leave around the generated
version files that happen during build.
They're already ignored in git, and recreated on every build.

Signed-off-by: Vincent Batts <vbatts@redhat.com>

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)
2015-03-25 11:34:55 -07:00
Vincent Batts
7f5937d46c btrfs: #ifdef for build version
We removed it, because upstream removed it. But now it will be coming
back, so work with it either way.

Signed-off-by: Vincent Batts <vbatts@redhat.com>

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)
2015-03-25 11:34:55 -07:00
Jessica Frazelle
b6166b9496 btrfs_noversion: including what was in merge commit from 8fc9e40086 (diff-479b910834cf0e4daea2e02767fd5dc9R1) pr #11417
Docker-DCO-1.1-Signed-off-by: Jessica Frazelle <jess@docker.com> (github: jfrazelle)
2015-03-24 22:15:08 -07:00
Jessica Frazelle
b596d025f5 fix 2 integration tests on lxc
Docker-DCO-1.1-Signed-off-by: Jessica Frazelle <jess@docker.com> (github: jfrazelle)
2015-03-24 21:47:42 -07:00
Jessica Frazelle
ca32446950 Get rid of panic in stats for lxc
Fix containers dir

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessica Frazelle <jess@docker.com> (github: jfrazelle)
2015-03-24 21:47:42 -07:00
Michal Fojtik
5328d6d620 Fix lxc-start in lxc>1.1.0 where containers start daemonized by default
Signed-off-by: Michal Fojtik <mfojtik@redhat.com>

Docker-DCO-1.1-Signed-off-by: Michal Fojtik <mfojtik@redhat.com> (github: jfrazelle)
2015-03-24 21:38:01 -07:00
Michael Crosby
d0023242ab Mkdir for lxc root dir before setup of symlink
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)
2015-03-24 16:30:38 -07:00
Alexander Morozov
3ff002aa1a Use /var/run/docker as root for execdriver
Signed-off-by: Alexander Morozov <lk4d4@docker.com>

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)
2015-03-24 15:43:08 -07:00
Dan Walsh
ea9b357be2 Btrfs has eliminated the BTRFS_BUILD_VERSION in latest version
They say we should only use the BTRFS_LIB_VERSION

They will no longer support this since it had to be managed manually

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

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)
2015-03-24 13:12:49 -07:00
Harald Albers
bf1829459f restrict bash completion for hostdir arg to directories
The previous state assumed that the HOSTPATH argument referred to a
file. As clarified by moxiegirl in PR #11305, it is a directory.
Adjusted completion to reflect this.

Signed-off-by: Harald Albers <github@albersweb.de>

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)
2015-03-24 13:12:49 -07:00
Vincent Batts
4f744ca781 pkg/archive: ignore mtime changes on directories
on overlay fs, the mtime of directories changes in a container where new
files are added in an upper layer (e.g. '/etc'). This flags the
directory as a change where there was none.

Closes #9874

Signed-off-by: Vincent Batts <vbatts@redhat.com>

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)
2015-03-23 15:29:10 -07:00
Michael Crosby
7dab04383b Update libcontainer to fd0087d3acdc4c5865de1829d4a
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)
2015-03-23 15:05:44 -07:00
Brian Goff
8a003c8134 Improve err message when parsing kernel port range
Signed-off-by: Brian Goff <cpuguy83@gmail.com>

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)
2015-03-23 14:26:42 -07:00
Ahmet Alp Balkan
208178c799 Disable ANSI emulation in certain windows shells
This disables recently added ANSI emulation feature in certain Windows
shells (like ConEmu) where ANSI output is emulated by default with builtin
functionality in the shell.

MSYS (mingw) runs in cmd.exe window and it doesn't support emulation.

Cygwin doesn't even pass terminal handles to docker.exe as far as I can
tell, stdin/stdout/stderr handles are behaving like non-TTY. Therefore not
even including that in the check.

Signed-off-by: Ahmet Alp Balkan <ahmetalpbalkan@gmail.com>

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)
2015-03-23 13:32:40 -07:00
sidharthamani
03b36f3451 add syslog driver
Signed-off-by: wlan0 <sid@rancher.com>

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)
2015-03-23 11:41:35 -07:00
Doug Davis
7758553239 Fix some escaping around env var processing
Clarify in the docs that ENV is not recursive

Closes #10391

Signed-off-by: Doug Davis <dug@us.ibm.com>

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)
2015-03-23 11:37:10 -07:00
Arnaud Porterie
10fb5ce6d0 Restore TestPullVerified test
Signed-off-by: Arnaud Porterie <arnaud.porterie@docker.com>

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)
2015-03-23 11:33:08 -07:00
Brian Goff
0959aec1a9 Allow normal volume to overwrite in start Binds
Fixes #9981
Allows a volume which was created by docker (ie, in
/var/lib/docker/vfs/dir) to be used as a Bind argument via the container
start API and overwrite an existing volume.

For example:

```bash
docker create -v /foo --name one
docker create -v /foo --name two
```

This allows the volume from `one` to be passed into the container start
API as a bind to `two`, and it will overwrite it.

This was possible before 7107898d5c

Signed-off-by: Brian Goff <cpuguy83@gmail.com>

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)
2015-03-23 11:04:27 -07:00
Mabin
773f74eb71 Fix hanging up problem when start and attach multiple containers
Signed-off-by: Mabin <bin.ma@huawei.com>

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)
2015-03-23 11:04:27 -07:00
unclejack
7070d9255a pkg/ioutils: add tests for BufReader
Signed-off-by: Cristian Staretu <cristian.staretu@gmail.com>

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)
2015-03-23 11:04:27 -07:00
unclejack
2cb4b7f65c pkg/ioutils: avoid huge Buffer growth in bufreader
Signed-off-by: Cristian Staretu <cristian.staretu@gmail.com>

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)
2015-03-23 11:04:27 -07:00
Mitch Capper
2d80652d8a Change windows default permissions to 755 not 711, read access for all poses little security risk and prevents breaking existing Dockerfiles
Signed-off-by: Mitch Capper <mitch.capper@gmail.com>

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)
2015-03-23 11:04:27 -07:00
Jessica Frazelle
81b4691406 Merge origin/master into origin/release
Signed-off-by: Jessica Frazelle <jess@docker.com>

Docker-DCO-1.1-Signed-off-by: Jessica Frazelle <jess@docker.com> (github: jfrazelle)
2015-03-22 23:45:58 -07:00
Arnaud Porterie
4bae33ef9f Merge pull request #10286 from icecrime/bump_v1.5.0
Bump to version v1.5.0
2015-02-10 10:50:09 -08:00
Arnaud Porterie
a8a31eff10 Bump to version v1.5.0
Signed-off-by: Arnaud Porterie <arnaud.porterie@docker.com>
2015-02-10 08:14:37 -08:00
Sven Dowideit
68a8fd5c4e updates from review
Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>
2015-02-10 08:14:37 -08:00
unclejack
8387c5ab65 update kernel reqs doc; recommend updates on RHEL
Signed-off-by: Cristian Staretu <cristian.staretu@gmail.com>
2015-02-10 08:14:37 -08:00
Sven Dowideit
69498943c3 remove the text-indent and increase the font size
Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>
2015-02-10 08:14:37 -08:00
Sven Dowideit
1aeb78c2ae Simplfy the sidebar html and css, and then allow the text to wrap
Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>
2015-02-10 08:14:36 -08:00
Tibor Vass
331d37f35d Minor nits
Signed-off-by: Tibor Vass <tibor@docker.com>
2015-02-10 08:14:36 -08:00
Tibor Vass
edf3bf7f33 Clarify docs review role
Signed-off-by: Tibor Vass <teabee89@gmail.com>
2015-02-10 08:14:36 -08:00
Tibor Vass
9ee8dca246 A few fixes
Signed-off-by: Tibor Vass <teabee89@gmail.com>
2015-02-10 08:14:36 -08:00
Tibor Vass
aa98bb6c13 New pull request workflow
Signed-off-by: Tibor Vass <teabee89@gmail.com>
2015-02-10 08:14:36 -08:00
Zhang Wei
2aba3c69f9 docs: fix a typo in registry_mirror.md
Signed-off-by: Zhang Wei <zhangwei555@huawei.com>
2015-02-10 08:14:36 -08:00
Steve Koch
71a44c769e Add link to user guide to end of 14.04 section
Adding instructions to exit the test shell and a link to the user guide (as is done in the following sections for 12.04 and 13.04/10

Signed-off-by: Steven Koch <sjkoch@unm.edu>
2015-02-10 08:14:36 -08:00
Wei-Ting Kuo
d8381fad2b Update certificates.md
`openssl req -new -x509 -text -key client.key -out client.cert` creates a self-sign certificate but not a certificate request.

Signed-off-by: Wei-Ting Kuo <waitingkuo0527@gmail.com>
2015-02-09 08:49:05 -08:00
Chen Hanxiao
be379580d0 docs: fix a typo in Dockerfile.5.md
s/Mutliple/Multiple

Signed-off-by: Chen Hanxiao <chenhanxiao@cn.fujitsu.com>
2015-02-09 08:49:05 -08:00
Alexander Morozov
7ea8513479 Fix example about ps and linked containers
Signed-off-by: Alexander Morozov <lk4d4@docker.com>
2015-02-09 08:49:05 -08:00
Sven Dowideit
3b2fe01c78 Documentation on boolean flags is wrong #10517
Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>
2015-02-09 08:49:05 -08:00
Sven Dowideit
e8afc22b1f Do some major rearranging of the fedora/centos/rhel installation docs
Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>
2015-02-09 08:49:05 -08:00
Lokesh Mandvekar
4e407e6b77 update fedora docs to reflect latest rpm changes
Signed-off-by: Lokesh Mandvekar <lsm5@fedoraproject.org>
2015-02-09 08:49:05 -08:00
unclejack
23f1c2ea9e docs/articles/systemd: correct --storage-driver
Signed-off-by: Cristian Staretu <cristian.staretu@gmail.com>
2015-02-09 08:49:05 -08:00
Katie McLaughlin
788047cafb Format awsconfig sample config correctly
Reflow change in commit 195f3a3f removed newlines in the config format.

This change reverts the sample config to the original formatting, which
matches the actual config format of a `awsconfig` file.

Signed-off-by: Katie McLaughlin <katie@glasnt.com>
2015-02-09 08:49:05 -08:00
Sven Dowideit
0c0e7b1b60 Fix a small spelling error in the dm.blkdiscard docs
Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>
2015-02-09 08:49:05 -08:00
Sven Dowideit
09d41529a0 Add an initial list of new features in Docker Engine 1.5.0
Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>
2015-02-09 08:49:04 -08:00
Sven Dowideit
cb288fefee remove swarm, machine and compose from the 1.5.0 release docs
Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>
2015-02-09 08:49:04 -08:00
Sven Dowideit
f7636796c5 The DHE documentation will not be published with 1.5.0
Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>
2015-02-09 08:49:04 -08:00
Sven Dowideit
cb5af83444 For now, docker stats appears to be libcontainer only
Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>
2015-02-09 08:49:04 -08:00
Mihai Borobocea
96feaf1920 docs: fix typo
There are 2 not 3 RUN instructions in the userguide's Dockerfile.

Signed-off-by: Mihai Borobocea <MihaiBorobocea@gmail.com>
2015-02-09 08:49:04 -08:00
Vincent Giersch
1f03944950 Documents build API "remote" parameter
Introduced in Docker v0.4.5 / Remove API v1.1 (#848), the remote
parameter of the API method POST /build allows to specify a buildable
remote URL (HTTPS, HTTP or Git).

Signed-off-by: Vincent Giersch <vincent.giersch@ovh.net>
2015-02-09 08:49:04 -08:00
Sven Dowideit
6060eedf9c The Hub build webhooks now list the images that have been built
And fix some spelling - repo isn't really a word :)

Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>
2015-02-09 08:49:04 -08:00
Sven Dowideit
d217da854a Spelling mistake in dockerlinks
Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>
2015-02-09 08:49:04 -08:00
Victor Vieux
d74d6d981b add crosbymichael and Github -> GitHub
Signed-off-by: Victor Vieux <vieux@docker.com>
2015-02-09 08:49:04 -08:00
Victor Vieux
0205ac33d2 update MAINTAINERS file
Signed-off-by: Victor Vieux <vieux@docker.com>
2015-02-09 08:49:04 -08:00
Sven Dowideit
dbb9d47bdc The reference menu is too big to list more than the latest API docs, so the others can be hidden - they're still linked from the API summary
Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>
2015-02-09 08:49:03 -08:00
Sven Dowideit
ddd1d081d7 use the same paths as in the swarm repo, so that their links magically work
Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>
2015-02-09 08:49:03 -08:00
Sven Dowideit
d6ac36d929 Docker attach documentation didn't make sense to me
Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>
2015-02-09 08:49:03 -08:00
Michael A. Smith
715b94f664 Distinguish ENV from setting environment inline
It's ambiguous to say that `ENV` is _functionally equivalent to prefixing the command with `<key>=<value>`_. `ENV` sets the environment for all future commands, but `RUN` can take chained commands like `RUN foo=bar bash -c 'echo $foo' && bash -c 'echo $foo $bar'`. Users with a solid understanding of `exec` may grok this without confusion, but less experienced users may need this distinction.

Signed-off-by: Michael A. Smith <msmith3@ebay.com>

Improve Environment Handling Descriptions

- Link `ENV` and `Environment Replacement`
- Improve side-effects of `ENV` text
- Rearrange avoiding side effects text

Signed-off-by: Michael A. Smith <msmith3@ebay.com>
2015-02-09 08:49:03 -08:00
Chen Hanxiao
16baca9277 docs: change events --since to fit RFC3339Nano
PR6931 changed time format to RFC3339Nano.
But the example in cli.md does not changed.

Signed-off-by: Chen Hanxiao <chenhanxiao@cn.fujitsu.com>
2015-02-09 08:49:03 -08:00
J Bruni
627f8a6cd5 Remove File List
This list is outdated. It could be updated instead of removed... but why should it be maintained? I do not see a reason.

Signed-off-by: João Bruni <contato@jbruni.com.br>
2015-02-09 08:49:03 -08:00
Sebastiaan van Stijn
a8a7df203a Fix broken link to project/MAINTAINERS.md
The link to project/MAINTAINERS.md was broken, in
addition, /MAINTAINERS containers more relevant
information on the LGTM process and contains info
about maintainers of all subsystems.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2015-02-09 08:49:03 -08:00
Thell 'Bo' Fowler
580cbcefd3 Update dockerfile_best-practices.md
Signed-off-by: Thell Fowler <Thell@tbfowler.name>
2015-02-09 08:49:03 -08:00
Yihang Ho
d9c5ce6e97 Fix a tiny typo.
'saving', not 'saveing'

Signed-off-by: Yihang Ho <hoyihang5@gmail.com>
2015-02-09 08:49:03 -08:00
Bradley Cicenas
0fe9b95415 fix project url in readme to point to the correct location,
https://github.com/docker/docker/tree/master/project

Signed-off-by: Bradley Cicenas <bradley.cicenas@gmail.com>
2015-02-09 08:49:03 -08:00
Alexandr Morozov
41d0e4293e Update events format in man page
Signed-off-by: Alexandr Morozov <lk4d4@docker.com>
2015-02-09 08:49:03 -08:00
Doug Davis
26fe640da1 Add builder folks to the top-level maintainers file
Signed-off-by: Doug Davis <dug@us.ibm.com>
2015-02-09 08:49:02 -08:00
Jessica Frazelle
198ca26969 Added tianon's info and changed a typo.
Docker-DCO-1.1-Signed-off-by: Jessica Frazelle <jess@docker.com> (github: jfrazelle)
2015-02-09 08:49:02 -08:00
Phil Estes
d5365f6fc4 Fix incorrect IPv6 addresses/subnet notations in docs
Fixes a few typos in IPv6 addresses. Will make it easier for users who
actually try and copy/paste or use the example addresses directly.

Docker-DCO-1.1-Signed-off-by: Phil Estes <estesp@linux.vnet.ibm.com> (github: estesp)
2015-02-09 08:49:02 -08:00
Brian Goff
5f7e814ee7 Update go-md2man
Update fixes some rendering issues, including improperly escaping '$' in
blocks, and actual parsing of blockcode.

`ID=$(sudo docker run -d fedora /usr/bin/top -b)` was being converted to
`ID=do docker run -d fedora/usr/bin/top -b)`

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2015-02-09 08:49:02 -08:00
Doug Davis
a84aca0985 Fix docs so WORKDIR mentions it works for COPY and ADD too
The docs around COPY/ADD already mentioned that it will do a relative
copy/add based on WORKDIR, so that part is already ok.  Just needed to
tweak the WORKDIR section since w/o mentioning COPY/ADD it can be misleading.

Noticed by @phemmer

Signed-off-by: Doug Davis <dug@us.ibm.com>
2015-02-09 08:49:02 -08:00
Solomon Hykes
68ec22876a Proposal for an improved project structure.
Note: this deprecates the fine-grained, high-overlap cascading MAINTAINERS files,
and replaces them with a single top-level file, using a new structure:

* More coarse grained subsystems with dedicated teams of maintainers
* Core maintainers with a better-defined role and a wider scope (if it's
not in a subsystem, it's up to the core maintainers to figure it out)
* Architects
* Operators

This is work in progress, the goal is to start a conversation

Signed-off-by: Solomon Hykes <solomon@docker.com>
Signed-off-by: Erik Hollensbe <github@hollensbe.org>
Signed-off-by: Arnaud Porterie <arnaud.porterie@docker.com>
Signed-off-by: Tibor Vass <teabee89@gmail.com>
Signed-off-by: Victor Vieux <vieux@docker.com>
Signed-off-by: Vincent Batts <vbatts@redhat.com>
2015-02-09 08:49:02 -08:00
Josh Hawn
0dcc3559e9 Updated image spec docs to clarify image JSON
The title `Image JSON Schema` was used as a header in the section
which describes the layout and fields of the image metadata JSON
file. It was pointed out that `JSON Schema` is its own term for
describing JSON in a machine-and-human-readable format, while the
word "Schema" in this context was used more generically to say that
the section is meant to be an example and outline of the Image JSON.

http://spacetelescope.github.io/understanding-json-schema/

This section now has the title `Image JSON Description` in order
to not cause this confusion.

Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)
2015-02-09 08:49:02 -08:00
Derek McGowan
d4c731ecd6 Limit push and pull to v2 official registry
No longer push to the official v2 registry when it is available. This allows pulling images from the v2 registry without defaulting push. Only pull official images from the v2 official registry.

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
2015-02-04 10:05:16 -08:00
Arnaud Porterie
2dba4e1386 Fix client-side validation of Dockerfile path
Arguments to `filepath.Rel` were reversed, making all builder tests to
fail.

Signed-off-by: Arnaud Porterie <arnaud.porterie@docker.com>
2015-02-03 09:07:17 -08:00
Tibor Vass
06a7f471e0 builder: prevent Dockerfile to leave build context
Signed-off-by: Tibor Vass <teabee89@gmail.com>
2015-02-03 09:07:17 -08:00
Doug Davis
4683d01691 Add an API test for docker build -f Dockerfile
I noticed that while we have tests to make sure that people don't
specify a Dockerfile (via -f) that's outside of the build context
when using the docker cli, we don't check on the server side to make
sure that API users have the same check done. This would be a security
risk.

While in there I had to add a new util func for the tests to allow us to
send content to the server that isn't json encoded - in this case a tarball

Signed-off-by: Doug Davis <dug@us.ibm.com>
2015-02-03 09:07:17 -08:00
Michael Crosby
6020a06399 Print zeros for initial stats collection on stopped container
When calling stats on stopped container's print out zeros for all of the
values to populate the initial table.  This signals to the user that the
operations completed and will not block.

Closes #10504

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
2015-02-03 08:50:47 -08:00
Sebastiaan van Stijn
cc0bfccdf4 Replace "base" with "ubuntu" in documentation
The API documentation uses the "base" image in various
places. The "base" image is deprecated and it is no longer
possible to download this image.

This changes the API documentation to use "ubuntu" in stead.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2015-02-02 13:34:12 -08:00
Chen Hanxiao
0c18ec62f3 docs: fix another typo in docker-build man page
s/arbtrary/arbitrary

Signed-off-by: Chen Hanxiao <chenhanxiao@cn.fujitsu.com>
2015-02-02 13:30:11 -08:00
John Tims
a9825c9bd8 Fix documentation typo
Signed-off-by: John Tims <john.k.tims@gmail.com>
2015-02-02 13:30:11 -08:00
Josh Hawn
908be50c44 Handle gorilla/mux route url bug
When getting the URL from a v2 registry url builder, it does not
honor the scheme from the endpoint object and will cause an https
endpoint to return urls starting with http.

Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)
2015-02-02 13:30:11 -08:00
Josh Hawn
2a82dba34d Fix token basic auth header issue
When requesting a token, the basic auth header is always being set even
if there is no username value. This patch corrects this and does not set
the basic auth header if the username is empty.

Also fixes an issue where pulling all tags from a v2 registry succeeds
when the image does not actually exist on the registry.

Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)
2015-02-02 13:30:11 -08:00
Erik Hollensbe
13fd2a908c Remove "OMG IPV6" log message
Signed-off-by: Erik Hollensbe <erik+github@hollensbe.org>
2015-02-02 13:30:11 -08:00
Arnaud Porterie
464891aaf8 Fix race in test registry setup
Wait for the local registry-v2 test instance to become available to
avoid random tests failures.

Signed-off-by: Arnaud Porterie <arnaud.porterie@docker.com>
2015-02-02 13:30:10 -08:00
Phil Estes
9974663ed7 Add missing $HOST in a couple places in HTTPS/TLS setup docs
Fix typos in setup docs where tcp://:2376 is used without the $HOST
parameter.

Docker-DCO-1.1-Signed-off-by: Phil Estes <estesp@linux.vnet.ibm.com>
2015-02-02 13:30:10 -08:00
Derek McGowan
76269e5c9d Add push fallback to v1 for the official registry
Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
2015-02-02 13:30:10 -08:00
Jessica Frazelle
1121d7c4fd Validate toml
Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)
2015-02-02 13:30:10 -08:00
Josh Hawn
7e197575a2 Remove Checksum field from image.Image struct
The checksum is now being stored in a separate file beside the image
JSON file.

Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)
2015-02-02 13:30:10 -08:00
Derek McGowan
3dc3059d94 Store tar checksum in separate file
Fixes #10432

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
2015-02-02 13:30:10 -08:00
Derek McGowan
7b6de74c9a Revert client signature
Supports multiple tag push with daemon signature

Fixes #10444

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
2015-02-02 13:30:10 -08:00
Phil Estes
cad8adacb8 Setup TCP keep-alive on hijacked HTTP(S) client <--> daemon sessions
Fixes #10387

Without TCP keep-alive set on socket connections to the daemon, any
long-running container with std{out,err,in} attached that doesn't
read/write for a minute or longer will end in ECONNTIMEDOUT (depending
on network settings/OS defaults, etc.), leaving the docker client side
believing it is still waiting on data with no actual underlying socket
connection.

This patch turns on TCP keep-alive for the underlying TCP connection
for both TLS and standard HTTP hijacked daemon connections from the
docker client, with a keep-alive timeout of 30 seconds.

Docker-DCO-1.1-Signed-off-by: Phil Estes <estesp@linux.vnet.ibm.com>
2015-02-02 13:30:10 -08:00
Srini Brahmaroutu
6226deeaf4 Removing the check on Architecture to build and run Docker on IBM Power and Z platforms
Signed-off-by: Srini Brahmaroutu <srbrahma@us.ibm.com>
2015-02-02 13:30:10 -08:00
gdi2290
3ec19f56cf Update AUTHORS file and .mailmap
added `LC_ALL=C.UTF-8` due to osx
http://www.inmotionhosting.com/support/website/ssh/speed-up-grep-searche
s-with-lc-all

Signed-off-by: Patrick Stapleton <github@gdi2290.com>
2015-02-02 13:30:10 -08:00
Josh Hawn
48c71787ed No longer compute checksum when installing images.
While checksums are verified when a layer is pulled from v2 registries,
there are known issues where the checksum may change when the layer diff
is computed again. To avoid these issues, the checksum should no longer
be computed and stored until after it has been extracted to the docker
storage driver. The checksums are instead computed lazily before they
are pushed to a v2 registry.

Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)
2015-02-02 13:30:10 -08:00
Jessica Frazelle
604731a930 Some small updates to the dev env docs.
Docker-DCO-1.1-Signed-off-by: Jessica Frazelle <jess@docker.com> (github: jfrazelle)
2015-02-02 13:30:09 -08:00
Derek McGowan
e8650e01f8 Defer creation of trust key file until needed
Fixes #10442

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
2015-02-02 13:30:09 -08:00
Sven Dowideit
817d04d992 DHE documentation placeholder and Navbar changes
Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>
2015-02-02 13:30:09 -08:00
Sven Dowideit
cdff91a01c comment out the docker and curl lines we'll run later
Docker-DCO-1.1-Signed-off-by: Sven Dowideit <SvenDowideit@docker.com> (github: SvenDowideit)
2015-02-02 13:30:09 -08:00
Mehul Kar
6f26bd0e16 Improve explanation of port mapping from containers
Signed-off-by: Mehul Kar <mehul.kar@gmail.com>
2015-02-02 13:30:09 -08:00
Tianon Gravi
3c090db4e9 Update .deb version numbers to be more sane
Example output:
```console
root@906b21a861fb:/go/src/github.com/docker/docker# ./hack/make.sh binary ubuntu
bundles/1.4.1-dev already exists. Removing.

---> Making bundle: binary (in bundles/1.4.1-dev/binary)
Created binary: /go/src/github.com/docker/docker/bundles/1.4.1-dev/binary/docker-1.4.1-dev

---> Making bundle: ubuntu (in bundles/1.4.1-dev/ubuntu)
Created package {:path=>"lxc-docker-1.4.1-dev_1.4.1~dev~git20150128.182847.0.17e840a_amd64.deb"}
Created package {:path=>"lxc-docker_1.4.1~dev~git20150128.182847.0.17e840a_amd64.deb"}

```

As noted in a comment in the code here, this sums up the reasoning for this change: (which is how APT and reprepro compare versions)
```console
$ dpkg --compare-versions 1.5.0 gt 1.5.0~rc1 && echo true || echo false
true
$ dpkg --compare-versions 1.5.0~rc1 gt 1.5.0~git20150128.112847.17e840a && echo true || echo false
true
$ dpkg --compare-versions 1.5.0~git20150128.112847.17e840a gt 1.5.0~dev~git20150128.112847.17e840a && echo true || echo false
true
```

ie, `1.5.0` > `1.5.0~rc1` > `1.5.0~git20150128.112847.17e840a` > `1.5.0~dev~git20150128.112847.17e840a`

Signed-off-by: Andrew "Tianon" Page <admwiggin@gmail.com>
2015-01-28 13:51:12 -08:00
Arnaud Porterie
b7c3fdfd0d Update fish completion for 1.5.0
Signed-off-by: Arnaud Porterie <arnaud.porterie@docker.com>
2015-01-28 10:29:29 -08:00
Phil Estes
aa682a845b Fix bridge initialization for IPv6 if IPv4-only docker0 exists
This fixes the daemon's failure to start when setting --ipv6=true for
the first time without deleting `docker0` bridge from a prior use with
only IPv4 addressing.

The addition of the IPv6 bridge address is factored out into a separate
initialization routine which is called even if the bridge exists but no
IPv6 addresses are found.

Docker-DCO-1.1-Signed-off-by: Phil Estes <estesp@linux.vnet.ibm.com> (github: estesp)
2015-01-28 10:29:29 -08:00
Jonathan Rudenberg
218d0dcc9d Fix missing err assignment in bridge creation
Signed-off-by: Jonathan Rudenberg <jonathan@titanous.com>
2015-01-28 10:29:29 -08:00
Stephen J Day
510d8f8634 Open up v2 http status code checks for put and head checks
Under certain cases, such as when putting a manifest or check for the existence
of a layer, the status code checks in session_v2.go were too narrow for their
purpose. In the case of putting a manifest, the handler only cares that an
error is not returned. Whether it is a 304 or 202 does not matter, as long as
the server reports success. Having the client only accept specific http codes
inhibits future protocol evolution.

Signed-off-by: Stephen J Day <stephen.day@docker.com>
2015-01-28 08:48:03 -08:00
Derek McGowan
b65600f6b6 Buffer tar file on v2 push
fixes #10312
fixes #10306

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
2015-01-28 08:48:03 -08:00
Jessica Frazelle
79dcea718c Add completion for stats.
Docker-DCO-1.1-Signed-off-by: Jessica Frazelle <jess@docker.com> (github: jfrazelle)
2015-01-28 08:45:57 -08:00
Sven Dowideit
072b09c45d Add the registry mirror document to the menu
Signed-off-by: Sven Dowideit <SvenDowideit@docker.com>

Docker-DCO-1.1-Signed-off-by: Sven Dowideit <SvenDowideit@docker.com> (github: SvenDowideit)
2015-01-27 19:35:26 -08:00
Derek McGowan
c2d9837745 Use layer checksum if calculated during manifest creation
Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
2015-01-27 19:35:26 -08:00
Josh Hawn
fa5dfbb18b Fix premature close of build output on pull
The build job will sometimes trigger a pull job when the base image
does not exist. Now that engine jobs properly close their output by default
the pull job would also close the build job's stdout in a cascading close
upon completion of the pull.

This patch corrects this by wrapping the `pull` job's stdout with a
nopCloseWriter which will not close the stdout of the `build` job.

Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)
2015-01-27 19:35:26 -08:00
Sven Dowideit
6532a075f3 tell users they can what IP range Hub webhooks can come from so they can filter
Docker-DCO-1.1-Signed-off-by: Sven Dowideit <SvenDowideit@docker.com> (github: SvenDowideit)

Signed-off-by: Sven Dowideit <SvenDowideit@docker.com>
2015-01-27 19:35:26 -08:00
Chen Hanxiao
3b4a4bf809 docs: fix a typo in docker-build man page
s/Dockefile/Dockerfile

Signed-off-by: Chen Hanxiao <chenhanxiao@cn.fujitsu.com>
2015-01-27 19:35:26 -08:00
Tony Miller
4602909566 fix /etc/host typo in remote API docs
Signed-off-by: Tony Miller <mcfiredrill@gmail.com>
2015-01-27 19:35:25 -08:00
Sven Dowideit
588f350b61 as we're not using the search suggestion feature only load the search_content when we have a search ?q= param
Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>

Docker-DCO-1.1-Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au> (github: SvenDowideit)
2015-01-27 19:35:25 -08:00
Sven Dowideit
6e5ff509b2 set the content-type for the search_content.json.gz
Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>

Docker-DCO-1.1-Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au> (github: SvenDowideit)
2015-01-27 19:35:25 -08:00
Sven Dowideit
61d341c2ca Change to load the json.gz file
Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>

Docker-DCO-1.1-Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au> (github: SvenDowideit)
2015-01-27 19:35:25 -08:00
unclejack
b996d379a1 docs: compress search_content.json for release
Signed-off-by: Cristian Staretu <cristian.staretu@gmail.com>

Docker-DCO-1.1-Signed-off-by: unclejack <unclejacksons@gmail.com> (github: SvenDowideit)
2015-01-27 19:35:25 -08:00
Derek McGowan
b0935ea730 Better error messaging and logging for v2 registry requests
Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
2015-01-27 19:35:25 -08:00
Derek McGowan
96fe13b49b Add file path to errors loading the key file
Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
2015-01-27 19:35:25 -08:00
Brian Goff
12ccde442a Do not return err on symlink eval
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2015-01-27 19:35:25 -08:00
Michael Crosby
4262cfe41f Remove omitempty json tags from stucts
When unmarshaling the json response from the API in languages to a
dynamic object having the omitempty field tag on types such as float64
case the key to be omitted on 0.0 values.  Various langages will
interpret this as a null when 0.0 is the actual value.

This patch removes the omitempty tags on fields that are not structs
where they can be safely omited.

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
2015-01-27 19:35:25 -08:00
Brian Goff
ddc2e25546 Fix bind-mounts only partially removed
When calling delete on a bind-mount volume, the config file was bing
removed, but it was not actually being removed from the volume index.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2015-01-27 19:35:25 -08:00
unclejack
6646cff646 docs: shrink sprites-small_360.png
Signed-off-by: Cristian Staretu <cristian.staretu@gmail.com>
2015-01-27 19:35:25 -08:00
Euan
ac8fd856c0 Allow empty layer configs in manifests
Before the V2 registry changes, images with no config could be pushed.
This change fixes a regression that made those images not able to be
pushed to a registry.

Signed-off-by: Euan Kemp <euank@euank.com>
2015-01-27 19:35:25 -08:00
DiuDiugirl
48754d673c Fix a minor typo
Docker inspect can also be used on images, this patch fixed the
minor typo in file docker/flags.go and docs/man/docker.1.md

Signed-off-by:  DiuDiugirl <sophia.wang@pku.edu.cn>
2015-01-27 19:35:25 -08:00
unclejack
723684525a pkg/archive: remove tar autodetection log line
Signed-off-by: Cristian Staretu <cristian.staretu@gmail.com>
2015-01-27 19:35:24 -08:00
Derek McGowan
32aceadbe6 Revert progressreader to not defer close
When progress reader closes it overwrites the progress line with the full progress bar, replaces the completed message.

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
2015-01-27 19:35:24 -08:00
Derek McGowan
c67d3e159c Use filepath instead of path
Currently loading the trust key uses path instead of filepath. This creates problems on some operating systems such as Windows.

Fixes #10319

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
2015-01-27 19:35:24 -08:00
Jessica Frazelle
a080e2add7 Make debugs logs suck less.
Docker-DCO-1.1-Signed-off-by: Jessica Frazelle <jess@docker.com> (github: jfrazelle)
2015-01-27 19:35:24 -08:00
Josh Hawn
24d81b0ddb Always store images with tarsum.v1 checksum added
Updates `image.StoreImage()` to always ensure that images
that are installed in Docker have a tarsum.v1 checksum.

Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)
2015-01-27 19:35:24 -08:00
Tony Miller
08f2fad40b document the ExtraHosts parameter for /containers/create for the remote API
I think this was added from version 1.15.

Signed-off-by: Tony Miller <mcfiredrill@gmail.com>
2015-01-27 19:35:24 -08:00
GennadySpb
f91fbe39ce Update using_supervisord.md
Fix factual error

change made by: GennadySpb <lipenkov@gmail.com>

Signed-off-by: Sven Dowideit <SvenDowideit@docker.com>
2015-01-27 19:35:24 -08:00
Tianon Gravi
018ab080bb Remove windows from the list of supported platforms
Since it can still be tested natively without this, this won't cause any harm while we fix the tests to actually work on Windows.

Signed-off-by: Andrew "Tianon" Page <admwiggin@gmail.com>
2015-01-27 19:35:24 -08:00
Tibor Vass
fe94ecb2c1 integration-cli: wait for container before sending ^D
Signed-off-by: Tibor Vass <teabee89@gmail.com>
2015-01-27 19:35:24 -08:00
Lorenz Leutgeb
7b2e67036f Fix inconsistent formatting
Colon was bold, but regular at other occurences.

Blame cf27b310c4

Signed-off-by: Lorenz Leutgeb <lorenz.leutgeb@gmail.com>
2015-01-27 19:35:24 -08:00
Lorenz Leutgeb
e130faea1b doc: Minor semantical/editorial fixes in HTTPS article
"read-only" vs. "only readable by you"

Refer to:
https://github.com/docker/docker/pull/9952#discussion_r22690266

Signed-off-by: Lorenz Leutgeb <lorenz.leutgeb@gmail.com>
2015-01-27 19:35:24 -08:00
Lorenz Leutgeb
38f09de334 doc: Editorial changes as suggested by @fredlf
Refer to:
 * https://github.com/docker/docker/pull/9952#discussion_r22686652
 * https://github.com/docker/docker/pull/9952#discussion_r22686804

Signed-off-by: Lorenz Leutgeb <lorenz.leutgeb@gmail.com>
2015-01-27 19:35:24 -08:00
Lorenz Leutgeb
f9ba68ddfb doc: Improve article on HTTPS
* Adjust header to match _page_title
 * Add instructions on deletion of CSRs and setting permissions
 * Simplify some path expressions and commands
 * Consqeuently use ~ instead of ${HOME}
 * Precise formulation ('key' vs. 'public key')
 * Fix wrong indentation of output of `openssl req`
 * Use dash ('--') instead of minus ('-')

Remark on permissions:

It's not a problem to `chmod 0400` the private keys, because the
Docker daemon runs as root (can read the file anyway) and the Docker
client runs as user.

Signed-off-by: Lorenz Leutgeb <lorenz.leutgeb@gmail.com>
2015-01-27 19:35:23 -08:00
Abin Shahab
16913455bd Fixes apparmor regression
Signed-off-by: Abin Shahab <ashahab@altiscale.com> (github: ashahab-altiscale)
Docker-DCO-1.1-Signed-off-by: Abin Shahab <ashahab@altiscale.com> (github: ashahab-altiscale)
2015-01-27 19:35:23 -08:00
Andrew C. Bodine
32f189cd08 Adds docs for /containers/(id)/attach/ws api endpoint
Signed-off-by: Andrew C. Bodine <acbodine@us.ibm.com>
2015-01-27 19:35:23 -08:00
Josh Hawn
526ca42282 Split API Version header when checking for v2
Since the Docker-Distribution-API-Version header value may contain multiple
space delimited versions as well as many instances of the header key, the
header value is now split on whitespace characters to iterate over all versions
that may be listed in one instance of the header.

Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)
2015-01-27 19:35:23 -08:00
Harald Albers
b98b42d843 Add bash completions for daemon flags, simplify with extglob
Implementing the deamon flags the traditional way introduced even more
redundancy than usual because the same list of options with flags
had to be added twice.

This can be avoided by using variables in the case statements when
using the extglob shell option.

Signed-off-by: Harald Albers <github@albersweb.de>
2015-01-27 19:35:23 -08:00
imre Fitos
7bf03dd132 fix typo 'setup/set up'
Signed-off-by: imre Fitos <imre.fitos+github@gmail.com>
2015-01-27 19:35:23 -08:00
imre Fitos
034aa3b2c4 start docker before checking for updated NAT rule
Signed-off-by: imre Fitos <imre.fitos+github@gmail.com>
2015-01-27 19:35:23 -08:00
imre Fitos
6da1e01e6c docs: remove NAT rule when removing bridge
Signed-off-by: imre Fitos <imre.fitos+github@gmail.com>
2015-01-27 19:35:23 -08:00
135 changed files with 2968 additions and 1341 deletions

View File

@@ -1,5 +1,42 @@
# Changelog
## 1.6.2 (2015-05-13)
#### Runtime
- Revert change prohibiting mounting into /sys
## 1.6.1 (2015-05-07)
#### Security
- Fix read/write /proc paths (CVE-2015-3630)
- Prohibit VOLUME /proc and VOLUME / (CVE-2015-3631)
- Fix opening of file-descriptor 1 (CVE-2015-3627)
- Fix symlink traversal on container respawn allowing local privilege escalation (CVE-2015-3629)
- Prohibit mount of /sys
#### Runtime
- Update Apparmor policy to not allow mounts
## 1.6.0 (2015-04-07)
#### Builder
+ Building images from an image ID
+ build containers with resource constraints, ie `docker build --cpu-shares=100 --memory=1024m...`
+ `commit --change` to apply specified Dockerfile instructions while committing the image
+ `import --change` to apply specified Dockerfile instructions while importing the image
+ basic build cancellation
#### Client
+ Windows Support
#### Runtime
+ Container and image Labels
+ `--cgroup-parent` for specifying a parent cgroup to place container cgroup within
+ Logging drivers, `json-file`, `syslog`, or `none`
+ Pulling images by ID
+ `--ulimit` to set the ulimit on a container
+ `--default-ulimit` option on the daemon which applies to all created containers (and overwritten by `--ulimit` on run)
## 1.5.0 (2015-02-10)
#### Builder

View File

@@ -1 +1 @@
1.5.0-dev
1.6.2

View File

@@ -441,7 +441,7 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
authconfig.ServerAddress = serverAddress
cli.configFile.Configs[serverAddress] = authconfig
stream, statusCode, err := cli.call("POST", "/auth", cli.configFile.Configs[serverAddress], false)
stream, statusCode, err := cli.call("POST", "/auth", cli.configFile.Configs[serverAddress], nil)
if statusCode == 401 {
delete(cli.configFile.Configs, serverAddress)
registry.SaveConfig(cli.configFile)
@@ -527,7 +527,7 @@ func (cli *DockerCli) CmdVersion(args ...string) error {
}
fmt.Fprintf(cli.out, "OS/Arch (client): %s/%s\n", runtime.GOOS, runtime.GOARCH)
body, _, err := readBody(cli.call("GET", "/version", nil, false))
body, _, err := readBody(cli.call("GET", "/version", nil, nil))
if err != nil {
return err
}
@@ -559,7 +559,7 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
cmd.Require(flag.Exact, 0)
utils.ParseFlags(cmd, args, false)
body, _, err := readBody(cli.call("GET", "/info", nil, false))
body, _, err := readBody(cli.call("GET", "/info", nil, nil))
if err != nil {
return err
}
@@ -696,7 +696,7 @@ func (cli *DockerCli) CmdStop(args ...string) error {
var encounteredError error
for _, name := range cmd.Args() {
_, _, err := readBody(cli.call("POST", "/containers/"+name+"/stop?"+v.Encode(), nil, false))
_, _, err := readBody(cli.call("POST", "/containers/"+name+"/stop?"+v.Encode(), nil, nil))
if err != nil {
fmt.Fprintf(cli.err, "%s\n", err)
encounteredError = fmt.Errorf("Error: failed to stop one or more containers")
@@ -719,7 +719,7 @@ func (cli *DockerCli) CmdRestart(args ...string) error {
var encounteredError error
for _, name := range cmd.Args() {
_, _, err := readBody(cli.call("POST", "/containers/"+name+"/restart?"+v.Encode(), nil, false))
_, _, err := readBody(cli.call("POST", "/containers/"+name+"/restart?"+v.Encode(), nil, nil))
if err != nil {
fmt.Fprintf(cli.err, "%s\n", err)
encounteredError = fmt.Errorf("Error: failed to restart one or more containers")
@@ -748,7 +748,7 @@ func (cli *DockerCli) forwardAllSignals(cid string) chan os.Signal {
if sig == "" {
log.Errorf("Unsupported signal: %v. Discarding.", s)
}
if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%s", cid, sig), nil, false)); err != nil {
if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%s", cid, sig), nil, nil)); err != nil {
log.Debugf("Error sending signal: %s", err)
}
}
@@ -769,24 +769,12 @@ func (cli *DockerCli) CmdStart(args ...string) error {
cmd.Require(flag.Min, 1)
utils.ParseFlags(cmd, args, true)
hijacked := make(chan io.Closer)
// Block the return until the chan gets closed
defer func() {
log.Debugf("CmdStart() returned, defer waiting for hijack to finish.")
if _, ok := <-hijacked; ok {
log.Errorf("Hijack did not finish (chan still open)")
}
if *openStdin || *attach {
cli.in.Close()
}
}()
if *attach || *openStdin {
if cmd.NArg() > 1 {
return fmt.Errorf("You cannot start and attach multiple containers at once.")
}
stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, false)
stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, nil)
if err != nil {
return err
}
@@ -816,29 +804,37 @@ func (cli *DockerCli) CmdStart(args ...string) error {
v.Set("stdout", "1")
v.Set("stderr", "1")
hijacked := make(chan io.Closer)
// Block the return until the chan gets closed
defer func() {
log.Debugf("CmdStart() returned, defer waiting for hijack to finish.")
if _, ok := <-hijacked; ok {
log.Errorf("Hijack did not finish (chan still open)")
}
cli.in.Close()
}()
cErr = promise.Go(func() error {
return cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), tty, in, cli.out, cli.err, hijacked, nil)
})
} else {
close(hijacked)
// Acknowledge the hijack before starting
select {
case closer := <-hijacked:
// Make sure that the hijack gets closed when returning (results
// in closing the hijack chan and freeing server's goroutines)
if closer != nil {
defer closer.Close()
}
case err := <-cErr:
if err != nil {
return err
}
}
}
// Acknowledge the hijack before starting
select {
case closer := <-hijacked:
// Make sure that the hijack gets closed when returning (results
// in closing the hijack chan and freeing server's goroutines)
if closer != nil {
defer closer.Close()
}
case err := <-cErr:
if err != nil {
return err
}
}
var encounteredError error
for _, name := range cmd.Args() {
_, _, err := readBody(cli.call("POST", "/containers/"+name+"/start", nil, false))
_, _, err := readBody(cli.call("POST", "/containers/"+name+"/start", nil, nil))
if err != nil {
if !*attach && !*openStdin {
// attach and openStdin is false means it could be starting multiple containers
@@ -886,7 +882,7 @@ func (cli *DockerCli) CmdUnpause(args ...string) error {
var encounteredError error
for _, name := range cmd.Args() {
if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/unpause", name), nil, false)); err != nil {
if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/unpause", name), nil, nil)); err != nil {
fmt.Fprintf(cli.err, "%s\n", err)
encounteredError = fmt.Errorf("Error: failed to unpause container named %s", name)
} else {
@@ -903,7 +899,7 @@ func (cli *DockerCli) CmdPause(args ...string) error {
var encounteredError error
for _, name := range cmd.Args() {
if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/pause", name), nil, false)); err != nil {
if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/pause", name), nil, nil)); err != nil {
fmt.Fprintf(cli.err, "%s\n", err)
encounteredError = fmt.Errorf("Error: failed to pause container named %s", name)
} else {
@@ -926,7 +922,7 @@ func (cli *DockerCli) CmdRename(args ...string) error {
old_name := cmd.Arg(0)
new_name := cmd.Arg(1)
if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/rename?name=%s", old_name, new_name), nil, false)); err != nil {
if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/rename?name=%s", old_name, new_name), nil, nil)); err != nil {
fmt.Fprintf(cli.err, "%s\n", err)
return fmt.Errorf("Error: failed to rename container named %s", old_name)
}
@@ -955,7 +951,7 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
status := 0
for _, name := range cmd.Args() {
obj, _, err := readBody(cli.call("GET", "/containers/"+name+"/json", nil, false))
obj, _, err := readBody(cli.call("GET", "/containers/"+name+"/json", nil, nil))
if err != nil {
if strings.Contains(err.Error(), "Too many") {
fmt.Fprintf(cli.err, "Error: %v", err)
@@ -963,7 +959,7 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
continue
}
obj, _, err = readBody(cli.call("GET", "/images/"+name+"/json", nil, false))
obj, _, err = readBody(cli.call("GET", "/images/"+name+"/json", nil, nil))
if err != nil {
if strings.Contains(err.Error(), "No such") {
fmt.Fprintf(cli.err, "Error: No such image or container: %s\n", name)
@@ -1026,7 +1022,7 @@ func (cli *DockerCli) CmdTop(args ...string) error {
val.Set("ps_args", strings.Join(cmd.Args()[1:], " "))
}
stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/top?"+val.Encode(), nil, false)
stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/top?"+val.Encode(), nil, nil)
if err != nil {
return err
}
@@ -1052,7 +1048,7 @@ func (cli *DockerCli) CmdPort(args ...string) error {
cmd.Require(flag.Min, 1)
utils.ParseFlags(cmd, args, true)
stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, false)
stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, nil)
if err != nil {
return err
}
@@ -1117,7 +1113,7 @@ func (cli *DockerCli) CmdRmi(args ...string) error {
var encounteredError error
for _, name := range cmd.Args() {
body, _, err := readBody(cli.call("DELETE", "/images/"+name+"?"+v.Encode(), nil, false))
body, _, err := readBody(cli.call("DELETE", "/images/"+name+"?"+v.Encode(), nil, nil))
if err != nil {
fmt.Fprintf(cli.err, "%s\n", err)
encounteredError = fmt.Errorf("Error: failed to remove one or more images")
@@ -1148,7 +1144,7 @@ func (cli *DockerCli) CmdHistory(args ...string) error {
utils.ParseFlags(cmd, args, true)
body, _, err := readBody(cli.call("GET", "/images/"+cmd.Arg(0)+"/history", nil, false))
body, _, err := readBody(cli.call("GET", "/images/"+cmd.Arg(0)+"/history", nil, nil))
if err != nil {
return err
}
@@ -1215,7 +1211,7 @@ func (cli *DockerCli) CmdRm(args ...string) error {
var encounteredError error
for _, name := range cmd.Args() {
_, _, err := readBody(cli.call("DELETE", "/containers/"+name+"?"+val.Encode(), nil, false))
_, _, err := readBody(cli.call("DELETE", "/containers/"+name+"?"+val.Encode(), nil, nil))
if err != nil {
fmt.Fprintf(cli.err, "%s\n", err)
encounteredError = fmt.Errorf("Error: failed to remove one or more containers")
@@ -1236,7 +1232,7 @@ func (cli *DockerCli) CmdKill(args ...string) error {
var encounteredError error
for _, name := range cmd.Args() {
if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%s", name, *signal), nil, false)); err != nil {
if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%s", name, *signal), nil, nil)); err != nil {
fmt.Fprintf(cli.err, "%s\n", err)
encounteredError = fmt.Errorf("Error: failed to kill one or more containers")
} else {
@@ -1321,32 +1317,8 @@ func (cli *DockerCli) CmdPush(args ...string) error {
v := url.Values{}
v.Set("tag", tag)
push := func(authConfig registry.AuthConfig) error {
buf, err := json.Marshal(authConfig)
if err != nil {
return err
}
registryAuthHeader := []string{
base64.URLEncoding.EncodeToString(buf),
}
return cli.stream("POST", "/images/"+remote+"/push?"+v.Encode(), nil, cli.out, map[string][]string{
"X-Registry-Auth": registryAuthHeader,
})
}
if err := push(authConfig); err != nil {
if strings.Contains(err.Error(), "Status 401") {
fmt.Fprintln(cli.out, "\nPlease login prior to push:")
if err := cli.CmdLogin(repoInfo.Index.GetAuthConfigKey()); err != nil {
return err
}
authConfig := cli.configFile.ResolveAuthConfig(repoInfo.Index)
return push(authConfig)
}
return err
}
return nil
_, _, err = cli.clientRequestAttemptLogin("POST", "/images/"+remote+"/push?"+v.Encode(), nil, cli.out, repoInfo.Index, "push")
return err
}
func (cli *DockerCli) CmdPull(args ...string) error {
@@ -1379,36 +1351,8 @@ func (cli *DockerCli) CmdPull(args ...string) error {
cli.LoadConfigFile()
// Resolve the Auth config relevant for this server
authConfig := cli.configFile.ResolveAuthConfig(repoInfo.Index)
pull := func(authConfig registry.AuthConfig) error {
buf, err := json.Marshal(authConfig)
if err != nil {
return err
}
registryAuthHeader := []string{
base64.URLEncoding.EncodeToString(buf),
}
return cli.stream("POST", "/images/create?"+v.Encode(), nil, cli.out, map[string][]string{
"X-Registry-Auth": registryAuthHeader,
})
}
if err := pull(authConfig); err != nil {
if strings.Contains(err.Error(), "Status 401") {
fmt.Fprintln(cli.out, "\nPlease login prior to pull:")
if err := cli.CmdLogin(repoInfo.Index.GetAuthConfigKey()); err != nil {
return err
}
authConfig := cli.configFile.ResolveAuthConfig(repoInfo.Index)
return pull(authConfig)
}
return err
}
return nil
_, _, err = cli.clientRequestAttemptLogin("POST", "/images/create?"+v.Encode(), nil, cli.out, repoInfo.Index, "pull")
return err
}
func (cli *DockerCli) CmdImages(args ...string) error {
@@ -1452,7 +1396,7 @@ func (cli *DockerCli) CmdImages(args ...string) error {
v.Set("filters", filterJson)
}
body, _, err := readBody(cli.call("GET", "/images/json?"+v.Encode(), nil, false))
body, _, err := readBody(cli.call("GET", "/images/json?"+v.Encode(), nil, nil))
if err != nil {
return err
}
@@ -1530,7 +1474,7 @@ func (cli *DockerCli) CmdImages(args ...string) error {
v.Set("all", "1")
}
body, _, err := readBody(cli.call("GET", "/images/json?"+v.Encode(), nil, false))
body, _, err := readBody(cli.call("GET", "/images/json?"+v.Encode(), nil, nil))
if err != nil {
return err
@@ -1728,7 +1672,7 @@ func (cli *DockerCli) CmdPs(args ...string) error {
v.Set("filters", filterJson)
}
body, _, err := readBody(cli.call("GET", "/containers/json?"+v.Encode(), nil, false))
body, _, err := readBody(cli.call("GET", "/containers/json?"+v.Encode(), nil, nil))
if err != nil {
return err
}
@@ -1869,7 +1813,7 @@ func (cli *DockerCli) CmdCommit(args ...string) error {
return err
}
}
stream, _, err := cli.call("POST", "/commit?"+v.Encode(), config, false)
stream, _, err := cli.call("POST", "/commit?"+v.Encode(), config, nil)
if err != nil {
return err
}
@@ -1980,7 +1924,7 @@ func (cli *DockerCli) CmdDiff(args ...string) error {
utils.ParseFlags(cmd, args, true)
body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/changes", nil, false))
body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/changes", nil, nil))
if err != nil {
return err
@@ -2018,7 +1962,7 @@ func (cli *DockerCli) CmdLogs(args ...string) error {
name := cmd.Arg(0)
stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, false)
stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, nil)
if err != nil {
return err
}
@@ -2059,7 +2003,7 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
utils.ParseFlags(cmd, args, true)
name := cmd.Arg(0)
stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, false)
stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, nil)
if err != nil {
return err
}
@@ -2130,16 +2074,27 @@ func (cli *DockerCli) CmdSearch(args ...string) error {
utils.ParseFlags(cmd, args, true)
name := cmd.Arg(0)
v := url.Values{}
v.Set("term", cmd.Arg(0))
body, _, err := readBody(cli.call("GET", "/images/search?"+v.Encode(), nil, true))
v.Set("term", name)
// Resolve the Repository name from fqn to hostname + name
taglessRemote, _ := parsers.ParseRepositoryTag(name)
repoInfo, err := registry.ParseRepositoryInfo(taglessRemote)
if err != nil {
return err
}
cli.LoadConfigFile()
body, statusCode, errReq := cli.clientRequestAttemptLogin("GET", "/images/search?"+v.Encode(), nil, nil, repoInfo.Index, "search")
rawBody, _, err := readBody(body, statusCode, errReq)
if err != nil {
return err
}
outs := engine.NewTable("star_count", 0)
if _, err := outs.ReadListFrom(body); err != nil {
if _, err := outs.ReadListFrom(rawBody); err != nil {
return err
}
w := tabwriter.NewWriter(cli.out, 10, 1, 3, ' ', 0)
@@ -2194,7 +2149,7 @@ func (cli *DockerCli) CmdTag(args ...string) error {
v.Set("force", "1")
}
if _, _, err := readBody(cli.call("POST", "/images/"+cmd.Arg(0)+"/tag?"+v.Encode(), nil, false)); err != nil {
if _, _, err := readBody(cli.call("POST", "/images/"+cmd.Arg(0)+"/tag?"+v.Encode(), nil, nil)); err != nil {
return err
}
return nil
@@ -2296,7 +2251,7 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc
}
//create the container
stream, statusCode, err := cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, false)
stream, statusCode, err := cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, nil)
//if image not found try to pull it
if statusCode == 404 {
repo, tag := parsers.ParseRepositoryTag(config.Image)
@@ -2310,7 +2265,7 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc
return nil, err
}
// Retry
if stream, _, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, false); err != nil {
if stream, _, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, nil); err != nil {
return nil, err
}
} else if err != nil {
@@ -2500,7 +2455,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
}
//start the container
if _, _, err = readBody(cli.call("POST", "/containers/"+createResponse.ID+"/start", nil, false)); err != nil {
if _, _, err = readBody(cli.call("POST", "/containers/"+createResponse.ID+"/start", nil, nil)); err != nil {
return err
}
@@ -2530,13 +2485,13 @@ func (cli *DockerCli) CmdRun(args ...string) error {
if *flAutoRemove {
// Autoremove: wait for the container to finish, retrieve
// the exit code and remove the container
if _, _, err := readBody(cli.call("POST", "/containers/"+createResponse.ID+"/wait", nil, false)); err != nil {
if _, _, err := readBody(cli.call("POST", "/containers/"+createResponse.ID+"/wait", nil, nil)); err != nil {
return err
}
if _, status, err = getExitCode(cli, createResponse.ID); err != nil {
return err
}
if _, _, err := readBody(cli.call("DELETE", "/containers/"+createResponse.ID+"?v=1", nil, false)); err != nil {
if _, _, err := readBody(cli.call("DELETE", "/containers/"+createResponse.ID+"?v=1", nil, nil)); err != nil {
return err
}
} else {
@@ -2576,7 +2531,7 @@ func (cli *DockerCli) CmdCp(args ...string) error {
copyData.Set("Resource", info[1])
copyData.Set("HostPath", cmd.Arg(1))
stream, statusCode, err := cli.call("POST", "/containers/"+info[0]+"/copy", copyData, false)
stream, statusCode, err := cli.call("POST", "/containers/"+info[0]+"/copy", copyData, nil)
if stream != nil {
defer stream.Close()
}
@@ -2671,7 +2626,7 @@ func (cli *DockerCli) CmdExec(args ...string) error {
return &utils.StatusError{StatusCode: 1}
}
stream, _, err := cli.call("POST", "/containers/"+execConfig.Container+"/exec", execConfig, false)
stream, _, err := cli.call("POST", "/containers/"+execConfig.Container+"/exec", execConfig, nil)
if err != nil {
return err
}
@@ -2693,7 +2648,7 @@ func (cli *DockerCli) CmdExec(args ...string) error {
return err
}
} else {
if _, _, err := readBody(cli.call("POST", "/exec/"+execID+"/start", execConfig, false)); err != nil {
if _, _, err := readBody(cli.call("POST", "/exec/"+execID+"/start", execConfig, nil)); err != nil {
return err
}
// For now don't print this - wait for when we support exec wait()
@@ -2785,7 +2740,7 @@ type containerStats struct {
}
func (s *containerStats) Collect(cli *DockerCli) {
stream, _, err := cli.call("GET", "/containers/"+s.Name+"/stats", nil, false)
stream, _, err := cli.call("GET", "/containers/"+s.Name+"/stats", nil, nil)
if err != nil {
s.err = err
return

View File

@@ -12,8 +12,10 @@ import (
"net/url"
"os"
gosignal "os/signal"
"runtime"
"strconv"
"strings"
"time"
log "github.com/Sirupsen/logrus"
"github.com/docker/docker/api"
@@ -54,124 +56,144 @@ func (cli *DockerCli) encodeData(data interface{}) (*bytes.Buffer, error) {
return params, nil
}
func (cli *DockerCli) call(method, path string, data interface{}, passAuthInfo bool) (io.ReadCloser, int, error) {
params, err := cli.encodeData(data)
if err != nil {
return nil, -1, err
}
req, err := http.NewRequest(method, fmt.Sprintf("/v%s%s", api.APIVERSION, path), params)
if err != nil {
return nil, -1, err
}
if passAuthInfo {
cli.LoadConfigFile()
// Resolve the Auth config relevant for this server
authConfig := cli.configFile.Configs[registry.IndexServerAddress()]
getHeaders := func(authConfig registry.AuthConfig) (map[string][]string, error) {
buf, err := json.Marshal(authConfig)
if err != nil {
return nil, err
}
registryAuthHeader := []string{
base64.URLEncoding.EncodeToString(buf),
}
return map[string][]string{"X-Registry-Auth": registryAuthHeader}, nil
}
if headers, err := getHeaders(authConfig); err == nil && headers != nil {
for k, v := range headers {
req.Header[k] = v
}
}
}
req.Header.Set("User-Agent", "Docker-Client/"+dockerversion.VERSION)
req.URL.Host = cli.addr
req.URL.Scheme = cli.scheme
if data != nil {
req.Header.Set("Content-Type", "application/json")
} else if method == "POST" {
req.Header.Set("Content-Type", "text/plain")
}
resp, err := cli.HTTPClient().Do(req)
if err != nil {
if strings.Contains(err.Error(), "connection refused") {
return nil, -1, ErrConnectionRefused
}
if cli.tlsConfig == nil {
return nil, -1, fmt.Errorf("%v. Are you trying to connect to a TLS-enabled daemon without TLS?", err)
}
return nil, -1, fmt.Errorf("An error occurred trying to connect: %v", err)
}
if resp.StatusCode < 200 || resp.StatusCode >= 400 {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, -1, err
}
if len(body) == 0 {
return nil, resp.StatusCode, fmt.Errorf("Error: request returned %s for API route and version %s, check if the server supports the requested API version", http.StatusText(resp.StatusCode), req.URL)
}
return nil, resp.StatusCode, fmt.Errorf("Error response from daemon: %s", bytes.TrimSpace(body))
}
return resp.Body, resp.StatusCode, nil
}
func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer, headers map[string][]string) error {
return cli.streamHelper(method, path, true, in, out, nil, headers)
}
func (cli *DockerCli) streamHelper(method, path string, setRawTerminal bool, in io.Reader, stdout, stderr io.Writer, headers map[string][]string) error {
if (method == "POST" || method == "PUT") && in == nil {
func (cli *DockerCli) clientRequest(method, path string, in io.Reader, headers map[string][]string) (io.ReadCloser, string, int, error) {
expectedPayload := (method == "POST" || method == "PUT")
if expectedPayload && in == nil {
in = bytes.NewReader([]byte{})
}
req, err := http.NewRequest(method, fmt.Sprintf("/v%s%s", api.APIVERSION, path), in)
if err != nil {
return err
return nil, "", -1, err
}
req.Header.Set("User-Agent", "Docker-Client/"+dockerversion.VERSION)
req.URL.Host = cli.addr
req.URL.Scheme = cli.scheme
if method == "POST" {
req.Header.Set("Content-Type", "text/plain")
}
if headers != nil {
for k, v := range headers {
req.Header[k] = v
}
}
if expectedPayload && req.Header.Get("Content-Type") == "" {
req.Header.Set("Content-Type", "text/plain")
}
resp, err := cli.HTTPClient().Do(req)
statusCode := -1
if resp != nil {
statusCode = resp.StatusCode
}
if err != nil {
if strings.Contains(err.Error(), "connection refused") {
return fmt.Errorf("Cannot connect to the Docker daemon. Is 'docker -d' running on this host?")
return nil, "", statusCode, ErrConnectionRefused
}
return err
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 400 {
if cli.tlsConfig == nil {
return nil, "", statusCode, fmt.Errorf("%v. Are you trying to connect to a TLS-enabled daemon without TLS?", err)
}
return nil, "", statusCode, fmt.Errorf("An error occurred trying to connect: %v", err)
}
if statusCode < 200 || statusCode >= 400 {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
return nil, "", statusCode, err
}
if len(body) == 0 {
return fmt.Errorf("Error :%s", http.StatusText(resp.StatusCode))
return nil, "", statusCode, fmt.Errorf("Error: request returned %s for API route and version %s, check if the server supports the requested API version", http.StatusText(statusCode), req.URL)
}
return fmt.Errorf("Error: %s", bytes.TrimSpace(body))
return nil, "", statusCode, fmt.Errorf("Error response from daemon: %s", bytes.TrimSpace(body))
}
if api.MatchesContentType(resp.Header.Get("Content-Type"), "application/json") {
return utils.DisplayJSONMessagesStream(resp.Body, stdout, cli.outFd, cli.isTerminalOut)
return resp.Body, resp.Header.Get("Content-Type"), statusCode, nil
}
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 registry.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
body, contentType, statusCode, 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(body, contentType, 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(), "status code 401") {
statusCode = http.StatusUnauthorized
}
}
return body, statusCode, err
}
// Resolve the Auth config relevant for this server
authConfig := cli.configFile.ResolveAuthConfig(index)
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 = cli.configFile.ResolveAuthConfig(index)
return cmdAttempt(authConfig)
}
return body, statusCode, err
}
func (cli *DockerCli) call(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
params, err := cli.encodeData(data)
if err != nil {
return nil, -1, err
}
if data != nil {
if headers == nil {
headers = make(map[string][]string)
}
headers["Content-Type"] = []string{"application/json"}
}
body, _, statusCode, err := cli.clientRequest(method, path, params, headers)
return body, statusCode, err
}
func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer, headers map[string][]string) error {
return cli.streamHelper(method, path, true, in, out, nil, headers)
}
func (cli *DockerCli) streamHelper(method, path string, setRawTerminal bool, in io.Reader, stdout, stderr io.Writer, headers map[string][]string) error {
body, contentType, _, err := cli.clientRequest(method, path, in, headers)
if err != nil {
return err
}
return cli.streamBody(body, contentType, setRawTerminal, stdout, stderr)
}
func (cli *DockerCli) streamBody(body io.ReadCloser, contentType string, setRawTerminal bool, stdout, stderr io.Writer) error {
defer body.Close()
if api.MatchesContentType(contentType, "application/json") {
return utils.DisplayJSONMessagesStream(body, stdout, cli.outFd, cli.isTerminalOut)
}
if stdout != nil || stderr != nil {
// When TTY is ON, use regular copy
var err error
if setRawTerminal {
_, err = io.Copy(stdout, resp.Body)
_, err = io.Copy(stdout, body)
} else {
_, err = stdcopy.StdCopy(stdout, stderr, resp.Body)
_, err = stdcopy.StdCopy(stdout, stderr, body)
}
log.Debugf("[stream] End of stdout")
return err
@@ -195,13 +217,13 @@ func (cli *DockerCli) resizeTty(id string, isExec bool) {
path = "/exec/" + id + "/resize?"
}
if _, _, err := readBody(cli.call("POST", path+v.Encode(), nil, false)); err != nil {
if _, _, err := readBody(cli.call("POST", path+v.Encode(), nil, nil)); err != nil {
log.Debugf("Error resize: %s", err)
}
}
func waitForExit(cli *DockerCli, containerId string) (int, error) {
stream, _, err := cli.call("POST", "/containers/"+containerId+"/wait", nil, false)
func waitForExit(cli *DockerCli, containerID string) (int, error) {
stream, _, err := cli.call("POST", "/containers/"+containerID+"/wait", nil, nil)
if err != nil {
return -1, err
}
@@ -215,8 +237,8 @@ func waitForExit(cli *DockerCli, containerId string) (int, error) {
// getExitCode perform an inspect on the container. It returns
// the running state and the exit code.
func getExitCode(cli *DockerCli, containerId string) (bool, int, error) {
stream, _, err := cli.call("GET", "/containers/"+containerId+"/json", nil, false)
func getExitCode(cli *DockerCli, containerID string) (bool, int, error) {
stream, _, err := cli.call("GET", "/containers/"+containerID+"/json", nil, nil)
if err != nil {
// If we can't connect, then the daemon probably died.
if err != ErrConnectionRefused {
@@ -236,8 +258,8 @@ func getExitCode(cli *DockerCli, containerId string) (bool, int, error) {
// getExecExitCode perform an inspect on the exec command. It returns
// the running state and the exit code.
func getExecExitCode(cli *DockerCli, execId string) (bool, int, error) {
stream, _, err := cli.call("GET", "/exec/"+execId+"/json", nil, false)
func getExecExitCode(cli *DockerCli, execID string) (bool, int, error) {
stream, _, err := cli.call("GET", "/exec/"+execID+"/json", nil, nil)
if err != nil {
// If we can't connect, then the daemon probably died.
if err != ErrConnectionRefused {
@@ -257,13 +279,29 @@ func getExecExitCode(cli *DockerCli, execId string) (bool, int, error) {
func (cli *DockerCli) monitorTtySize(id string, isExec bool) error {
cli.resizeTty(id, isExec)
sigchan := make(chan os.Signal, 1)
gosignal.Notify(sigchan, signal.SIGWINCH)
go func() {
for _ = range sigchan {
cli.resizeTty(id, isExec)
}
}()
if runtime.GOOS == "windows" {
go func() {
prevH, prevW := cli.getTtySize()
for {
time.Sleep(time.Millisecond * 250)
h, w := cli.getTtySize()
if prevW != w || prevH != h {
cli.resizeTty(id, isExec)
}
prevH = h
prevW = w
}
}()
} else {
sigchan := make(chan os.Signal, 1)
gosignal.Notify(sigchan, signal.SIGWINCH)
go func() {
for _ = range sigchan {
cli.resizeTty(id, isExec)
}
}()
}
return nil
}

View File

@@ -27,7 +27,7 @@ import (
log "github.com/Sirupsen/logrus"
"github.com/docker/docker/api"
"github.com/docker/docker/api/types"
"github.com/docker/docker/daemon/networkdriver/portallocator"
"github.com/docker/docker/daemon/networkdriver/bridge"
"github.com/docker/docker/engine"
"github.com/docker/docker/pkg/listenbuffer"
"github.com/docker/docker/pkg/parsers"
@@ -38,7 +38,7 @@ import (
)
var (
activationLock chan struct{}
activationLock chan struct{} = make(chan struct{})
)
type HttpServer struct {
@@ -1527,7 +1527,7 @@ func allocateDaemonPort(addr string) error {
}
for _, hostIP := range hostIPs {
if _, err := portallocator.RequestPort(hostIP, "tcp", intPort); err != nil {
if _, err := bridge.RequestPort(hostIP, "tcp", intPort); err != nil {
return fmt.Errorf("failed to allocate daemon listening port %d (err: %v)", intPort, err)
}
}
@@ -1578,7 +1578,6 @@ func ServeApi(job *engine.Job) engine.Status {
protoAddrs = job.Args
chErrors = make(chan error, len(protoAddrs))
)
activationLock = make(chan struct{})
for _, protoAddr := range protoAddrs {
protoAddrParts := strings.SplitN(protoAddr, "://", 2)

View File

@@ -95,7 +95,9 @@ func AcceptConnections(job *engine.Job) engine.Status {
go systemd.SdNotify("READY=1")
// close the lock so the listeners start accepting connections
if activationLock != nil {
select {
case <-activationLock:
default:
close(activationLock)
}

View File

@@ -312,7 +312,11 @@ func (b *Builder) dispatch(stepN int, ast *parser.Node) error {
var str string
str = ast.Value
if _, ok := replaceEnvAllowed[cmd]; ok {
str = b.replaceEnv(ast.Value)
var err error
str, err = ProcessWord(ast.Value, b.Config.Env)
if err != nil {
return err
}
}
strList[i+l] = str
msgList[i] = ast.Value

View File

@@ -90,7 +90,7 @@ func parseNameVal(rest string, key string) (*Node, map[string]bool, error) {
if blankOK || len(word) > 0 {
words = append(words, word)
// Look for = and if no there assume
// Look for = and if not there assume
// we're doing the old stuff and
// just read the rest of the line
if !strings.Contains(word, "=") {
@@ -107,12 +107,15 @@ func parseNameVal(rest string, key string) (*Node, map[string]bool, error) {
quote = ch
blankOK = true
phase = inQuote
continue
}
if ch == '\\' {
if pos+1 == len(rest) {
continue // just skip \ at end
}
// If we're not quoted and we see a \, then always just
// add \ plus the char to the word, even if the char
// is a quote.
word += string(ch)
pos++
ch = rune(rest[pos])
}
@@ -122,15 +125,17 @@ func parseNameVal(rest string, key string) (*Node, map[string]bool, error) {
if phase == inQuote {
if ch == quote {
phase = inWord
continue
}
if ch == '\\' {
// \ is special except for ' quotes - can't escape anything for '
if ch == '\\' && quote != '\'' {
if pos+1 == len(rest) {
phase = inWord
continue // just skip \ at end
}
pos++
ch = rune(rest[pos])
nextCh := rune(rest[pos])
word += string(ch)
ch = nextCh
}
word += string(ch)
}

View File

@@ -7,6 +7,14 @@ ENV name=value\ value2
ENV name="value'quote space'value2"
ENV name='value"double quote"value2'
ENV name=value\ value2 name2=value2\ value3
ENV name="a\"b"
ENV name="a\'b"
ENV name='a\'b'
ENV name='a\'b''
ENV name='a\"b'
ENV name="''"
# don't put anything after the next line - it must be the last line of the
# Dockerfile and it must end with \
ENV name=value \
name1=value1 \
name2="value2a \

View File

@@ -2,9 +2,15 @@
(env "name" "value")
(env "name" "value")
(env "name" "value" "name2" "value2")
(env "name" "value value1")
(env "name" "value value2")
(env "name" "value'quote space'value2")
(env "name" "value\"double quote\"value2")
(env "name" "value value2" "name2" "value2 value3")
(env "name" "value" "name1" "value1" "name2" "value2a value2b" "name3" "value3an\"value3b\"" "name4" "value4a\\nvalue4b")
(env "name" "\"value value1\"")
(env "name" "value\\ value2")
(env "name" "\"value'quote space'value2\"")
(env "name" "'value\"double quote\"value2'")
(env "name" "value\\ value2" "name2" "value2\\ value3")
(env "name" "\"a\\\"b\"")
(env "name" "\"a\\'b\"")
(env "name" "'a\\'b'")
(env "name" "'a\\'b''")
(env "name" "'a\\\"b'")
(env "name" "\"''\"")
(env "name" "value" "name1" "value1" "name2" "\"value2a value2b\"" "name3" "\"value3a\\n\\\"value3b\\\"\"" "name4" "\"value4a\\\\nvalue4b\"")

209
builder/shell_parser.go Normal file
View File

@@ -0,0 +1,209 @@
package builder
// This will take a single word and an array of env variables and
// process all quotes (" and ') as well as $xxx and ${xxx} env variable
// tokens. Tries to mimic bash shell process.
// It doesn't support all flavors of ${xx:...} formats but new ones can
// be added by adding code to the "special ${} format processing" section
import (
"fmt"
"strings"
"unicode"
)
type shellWord struct {
word string
envs []string
pos int
}
func ProcessWord(word string, env []string) (string, error) {
sw := &shellWord{
word: word,
envs: env,
pos: 0,
}
return sw.process()
}
func (sw *shellWord) process() (string, error) {
return sw.processStopOn('\000')
}
// Process the word, starting at 'pos', and stop when we get to the
// end of the word or the 'stopChar' character
func (sw *shellWord) processStopOn(stopChar rune) (string, error) {
var result string
var charFuncMapping = map[rune]func() (string, error){
'\'': sw.processSingleQuote,
'"': sw.processDoubleQuote,
'$': sw.processDollar,
}
for sw.pos < len(sw.word) {
ch := sw.peek()
if stopChar != '\000' && ch == stopChar {
sw.next()
break
}
if fn, ok := charFuncMapping[ch]; ok {
// Call special processing func for certain chars
tmp, err := fn()
if err != nil {
return "", err
}
result += tmp
} else {
// Not special, just add it to the result
ch = sw.next()
if ch == '\\' {
// '\' escapes, except end of line
ch = sw.next()
if ch == '\000' {
continue
}
}
result += string(ch)
}
}
return result, nil
}
func (sw *shellWord) peek() rune {
if sw.pos == len(sw.word) {
return '\000'
}
return rune(sw.word[sw.pos])
}
func (sw *shellWord) next() rune {
if sw.pos == len(sw.word) {
return '\000'
}
ch := rune(sw.word[sw.pos])
sw.pos++
return ch
}
func (sw *shellWord) processSingleQuote() (string, error) {
// All chars between single quotes are taken as-is
// Note, you can't escape '
var result string
sw.next()
for {
ch := sw.next()
if ch == '\000' || ch == '\'' {
break
}
result += string(ch)
}
return result, nil
}
func (sw *shellWord) processDoubleQuote() (string, error) {
// All chars up to the next " are taken as-is, even ', except any $ chars
// But you can escape " with a \
var result string
sw.next()
for sw.pos < len(sw.word) {
ch := sw.peek()
if ch == '"' {
sw.next()
break
}
if ch == '$' {
tmp, err := sw.processDollar()
if err != nil {
return "", err
}
result += tmp
} else {
ch = sw.next()
if ch == '\\' {
chNext := sw.peek()
if chNext == '\000' {
// Ignore \ at end of word
continue
}
if chNext == '"' || chNext == '$' {
// \" and \$ can be escaped, all other \'s are left as-is
ch = sw.next()
}
}
result += string(ch)
}
}
return result, nil
}
func (sw *shellWord) processDollar() (string, error) {
sw.next()
ch := sw.peek()
if ch == '{' {
sw.next()
name := sw.processName()
ch = sw.peek()
if ch == '}' {
// Normal ${xx} case
sw.next()
return sw.getEnv(name), nil
}
return "", fmt.Errorf("Unsupported ${} substitution: %s", sw.word)
} else {
// $xxx case
name := sw.processName()
if name == "" {
return "$", nil
}
return sw.getEnv(name), nil
}
}
func (sw *shellWord) processName() string {
// Read in a name (alphanumeric or _)
// If it starts with a numeric then just return $#
var name string
for sw.pos < len(sw.word) {
ch := sw.peek()
if len(name) == 0 && unicode.IsDigit(ch) {
ch = sw.next()
return string(ch)
}
if !unicode.IsLetter(ch) && !unicode.IsDigit(ch) && ch != '_' {
break
}
ch = sw.next()
name += string(ch)
}
return name
}
func (sw *shellWord) getEnv(name string) string {
for _, env := range sw.envs {
i := strings.Index(env, "=")
if i < 0 {
if name == env {
// Should probably never get here, but just in case treat
// it like "var" and "var=" are the same
return ""
}
continue
}
if name != env[:i] {
continue
}
return env[i+1:]
}
return ""
}

View File

@@ -0,0 +1,51 @@
package builder
import (
"bufio"
"os"
"strings"
"testing"
)
func TestShellParser(t *testing.T) {
file, err := os.Open("words")
if err != nil {
t.Fatalf("Can't open 'words': %s", err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
envs := []string{"PWD=/home", "SHELL=bash"}
for scanner.Scan() {
line := scanner.Text()
// Trim comments and blank lines
i := strings.Index(line, "#")
if i >= 0 {
line = line[:i]
}
line = strings.TrimSpace(line)
if line == "" {
continue
}
words := strings.Split(line, "|")
if len(words) != 2 {
t.Fatalf("Error in 'words' - should be 2 words:%q", words)
}
words[0] = strings.TrimSpace(words[0])
words[1] = strings.TrimSpace(words[1])
newWord, err := ProcessWord(words[0], envs)
if err != nil {
newWord = "error"
}
if newWord != words[1] {
t.Fatalf("Error. Src: %s Calc: %s Expected: %s", words[0], newWord, words[1])
}
}
}

View File

@@ -1,50 +1,9 @@
package builder
import (
"regexp"
"strings"
)
var (
// `\\\\+|[^\\]|\b|\A` - match any number of "\\" (ie, properly-escaped backslashes), or a single non-backslash character, or a word boundary, or beginning-of-line
// `\$` - match literal $
// `[[:alnum:]_]+` - match things like `$SOME_VAR`
// `{[[:alnum:]_]+}` - match things like `${SOME_VAR}`
tokenEnvInterpolation = regexp.MustCompile(`(\\|\\\\+|[^\\]|\b|\A)\$([[:alnum:]_]+|{[[:alnum:]_]+})`)
// this intentionally punts on more exotic interpolations like ${SOME_VAR%suffix} and lets the shell handle those directly
)
// handle environment replacement. Used in dispatcher.
func (b *Builder) replaceEnv(str string) string {
for _, match := range tokenEnvInterpolation.FindAllString(str, -1) {
idx := strings.Index(match, "\\$")
if idx != -1 {
if idx+2 >= len(match) {
str = strings.Replace(str, match, "\\$", -1)
continue
}
prefix := match[:idx]
stripped := match[idx+2:]
str = strings.Replace(str, match, prefix+"$"+stripped, -1)
continue
}
match = match[strings.Index(match, "$"):]
matchKey := strings.Trim(match, "${}")
for _, keyval := range b.Config.Env {
tmp := strings.SplitN(keyval, "=", 2)
if tmp[0] == matchKey {
str = strings.Replace(str, match, tmp[1], -1)
break
}
}
}
return str
}
func handleJsonArgs(args []string, attributes map[string]bool) []string {
if len(args) == 0 {
return []string{}

43
builder/words Normal file
View File

@@ -0,0 +1,43 @@
hello | hello
he'll'o | hello
he'llo | hello
he\'llo | he'llo
he\\'llo | he\llo
abc\tdef | abctdef
"abc\tdef" | abc\tdef
'abc\tdef' | abc\tdef
hello\ | hello
hello\\ | hello\
"hello | hello
"hello\" | hello"
"hel'lo" | hel'lo
'hello | hello
'hello\' | hello\
"''" | ''
$. | $.
$1 |
he$1x | hex
he$.x | he$.x
he$pwd. | he.
he$PWD | he/home
he\$PWD | he$PWD
he\\$PWD | he\/home
he\${} | he${}
he\${}xx | he${}xx
he${} | he
he${}xx | hexx
he${hi} | he
he${hi}xx | hexx
he${PWD} | he/home
he${.} | error
'he${XX}' | he${XX}
"he${PWD}" | he/home
"he'$PWD'" | he'/home'
"$PWD" | /home
'$PWD' | $PWD
'\$PWD' | \$PWD
'"hello"' | "hello"
he\$PWD | he$PWD
"he\$PWD" | he$PWD
'he\$PWD' | he\$PWD
he${PWD | error

View File

@@ -58,6 +58,18 @@ __docker_containers_unpauseable() {
__docker_containers_all '.State.Paused'
}
__docker_container_names() {
local containers=( $(__docker_q ps -aq --no-trunc) )
local names=( $(__docker_q inspect --format '{{.Name}}' "${containers[@]}") )
names=( "${names[@]#/}" ) # trim off the leading "/" from the container names
COMPREPLY=( $(compgen -W "${names[*]}" -- "$cur") )
}
__docker_container_ids() {
local containers=( $(__docker_q ps -aq) )
COMPREPLY=( $(compgen -W "${containers[*]}" -- "$cur") )
}
__docker_image_repos() {
local repos="$(__docker_q images | awk 'NR>1 && $1 != "<none>" { print $1 }')"
COMPREPLY=( $(compgen -W "$repos" -- "$cur") )
@@ -325,7 +337,7 @@ _docker_cp() {
(( counter++ ))
if [ $cword -eq $counter ]; then
_filedir
_filedir -d
return
fi
;;
@@ -437,7 +449,10 @@ _docker_history() {
_docker_images() {
case "$prev" in
--filter|-f)
COMPREPLY=( $( compgen -W "dangling=true" -- "$cur" ) )
COMPREPLY=( $( compgen -W "dangling=true label=" -- "$cur" ) )
if [ "$COMPREPLY" = "label=" ]; then
compopt -o nospace
fi
return
;;
esac
@@ -447,17 +462,20 @@ _docker_images() {
COMPREPLY=( $( compgen -W "true false" -- "${cur#=}" ) )
return
;;
*label=*)
return
;;
esac
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--all -a --filter -f --help --no-trunc --quiet -q" -- "$cur" ) )
;;
=)
return
;;
*)
local counter=$(__docker_pos_first_nonflag)
if [ $cword -eq $counter ]; then
__docker_image_repos
fi
__docker_image_repos
;;
esac
}
@@ -616,7 +634,7 @@ _docker_ps() {
__docker_containers_all
;;
--filter|-f)
COMPREPLY=( $( compgen -S = -W "exited status" -- "$cur" ) )
COMPREPLY=( $( compgen -S = -W "exited id label name status" -- "$cur" ) )
compopt -o nospace
return
;;
@@ -626,6 +644,16 @@ _docker_ps() {
esac
case "${words[$cword-2]}$prev=" in
*id=*)
cur="${cur#=}"
__docker_container_ids
return
;;
*name=*)
cur="${cur#=}"
__docker_container_names
return
;;
*status=*)
COMPREPLY=( $( compgen -W "exited paused restarting running" -- "${cur#=}" ) )
return
@@ -734,6 +762,7 @@ _docker_run() {
--attach -a
--cap-add
--cap-drop
--cgroup-parent
--cidfile
--cpuset
--cpu-shares -c
@@ -746,7 +775,10 @@ _docker_run() {
--expose
--hostname -h
--ipc
--label -l
--label-file
--link
--log-driver
--lxc-conf
--mac-address
--memory -m
@@ -798,7 +830,7 @@ _docker_run() {
__docker_capabilities
return
;;
--cidfile|--env-file)
--cidfile|--env-file|--label-file)
_filedir
return
;;
@@ -850,6 +882,10 @@ _docker_run() {
esac
return
;;
--log-driver)
COMPREPLY=( $( compgen -W "json-file syslog none" -- "$cur") )
return
;;
--net)
case "$cur" in
container:*)

View File

@@ -49,7 +49,7 @@ post-start script
fi
if ! printf "%s" "$DOCKER_OPTS" | grep -qE -e '-H|--host'; then
while ! [ -e /var/run/docker.sock ]; do
initctl status $UPSTART_JOB | grep -q "stop/" && exit 1
initctl status $UPSTART_JOB | grep -qE "(stop|respawn)/" && exit 1
echo "Waiting for /var/run/docker.sock"
sleep 0.1
done

View File

@@ -83,7 +83,7 @@ func (config *Config) InstallFlags() {
opts.LabelListVar(&config.Labels, []string{"-label"}, "Set key=value labels to the daemon")
config.Ulimits = make(map[string]*ulimit.Ulimit)
opts.UlimitMapVar(config.Ulimits, []string{"-default-ulimit"}, "Set default ulimits for containers")
flag.StringVar(&config.LogConfig.Type, []string{"-log-driver"}, "json-file", "Containers logging driver(json-file/none)")
flag.StringVar(&config.LogConfig.Type, []string{"-log-driver"}, "json-file", "Containers logging driver")
}
func getDefaultNetworkMtu() int {

View File

@@ -23,6 +23,7 @@ import (
"github.com/docker/docker/daemon/execdriver"
"github.com/docker/docker/daemon/logger"
"github.com/docker/docker/daemon/logger/jsonfilelog"
"github.com/docker/docker/daemon/logger/syslog"
"github.com/docker/docker/engine"
"github.com/docker/docker/image"
"github.com/docker/docker/links"
@@ -359,6 +360,10 @@ func (container *Container) Start() (err error) {
return nil
}
if container.removalInProgress || container.Dead {
return fmt.Errorf("Container is marked for removal and cannot be started.")
}
// if we encounter an error during start we need to ensure that any other
// setup has been cleaned up properly
defer func() {
@@ -1374,12 +1379,19 @@ func (container *Container) startLogging() error {
if err != nil {
return err
}
container.LogPath = pth
dl, err := jsonfilelog.New(pth)
if err != nil {
return err
}
l = dl
case "syslog":
dl, err := syslog.New(container.ID[:12])
if err != nil {
return err
}
l = dl
case "none":
return nil
default:

View File

@@ -25,7 +25,6 @@ import (
"github.com/docker/docker/daemon/graphdriver"
_ "github.com/docker/docker/daemon/graphdriver/vfs"
_ "github.com/docker/docker/daemon/networkdriver/bridge"
"github.com/docker/docker/daemon/networkdriver/portallocator"
"github.com/docker/docker/engine"
"github.com/docker/docker/graph"
"github.com/docker/docker/image"
@@ -288,19 +287,8 @@ func (daemon *Daemon) register(container *Container, updateSuffixarray bool) err
if err := container.ToDisk(); err != nil {
log.Debugf("saving stopped state to disk %s", err)
}
info := daemon.execDriver.Info(container.ID)
if !info.IsRunning() {
log.Debugf("Container %s was supposed to be running but is not.", container.ID)
log.Debugf("Marking as stopped")
container.SetStopped(&execdriver.ExitStatus{ExitCode: -127})
if err := container.ToDisk(); err != nil {
return err
}
}
}
return nil
}
@@ -827,12 +815,6 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine) (*Daemon, error)
}
config.DisableNetwork = config.BridgeIface == disableNetworkBridge
// register portallocator release on shutdown
eng.OnShutdown(func() {
if err := portallocator.ReleaseAll(); err != nil {
log.Errorf("portallocator.ReleaseAll(): %s", err)
}
})
// Claim the pidfile first, to avoid any and all unexpected race conditions.
// Some of the init doesn't need a pidfile lock - but let's not try to be smart.
if config.Pidfile != "" {
@@ -1012,7 +994,8 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine) (*Daemon, error)
}
sysInfo := sysinfo.New(false)
ed, err := execdrivers.NewDriver(config.ExecDriver, config.Root, sysInitPath, sysInfo)
const runDir = "/var/run/docker"
ed, err := execdrivers.NewDriver(config.ExecDriver, runDir, config.Root, sysInitPath, sysInfo)
if err != nil {
return nil, err
}

View File

@@ -61,8 +61,15 @@ func (daemon *Daemon) ContainerRm(job *engine.Job) engine.Status {
return job.Errorf("Conflict, You cannot remove a running container. Stop the container before attempting removal or use -f")
}
}
if err := daemon.Rm(container); err != nil {
return job.Errorf("Cannot destroy container %s: %s", name, err)
if forceRemove {
if err := daemon.ForceRm(container); err != nil {
log.Errorf("Cannot destroy container %s: %v", name, err)
}
} else {
if err := daemon.Rm(container); err != nil {
return job.Errorf("Cannot destroy container %s: %v", name, err)
}
}
container.LogEvent("destroy")
if removeVolume {
@@ -81,8 +88,16 @@ func (daemon *Daemon) DeleteVolumes(volumeIDs map[string]struct{}) {
}
}
func (daemon *Daemon) Rm(container *Container) (err error) {
return daemon.commonRm(container, false)
}
func (daemon *Daemon) ForceRm(container *Container) (err error) {
return daemon.commonRm(container, true)
}
// Destroy unregisters a container from the daemon and cleanly removes its contents from the filesystem.
func (daemon *Daemon) Rm(container *Container) error {
func (daemon *Daemon) commonRm(container *Container, forceRemove bool) (err error) {
if container == nil {
return fmt.Errorf("The given container is <nil>")
}
@@ -92,19 +107,40 @@ func (daemon *Daemon) Rm(container *Container) error {
return fmt.Errorf("Container %v not found - maybe it was already destroyed?", container.ID)
}
if err := container.Stop(3); err != nil {
// Container state RemovalInProgress should be used to avoid races.
if err = container.SetRemovalInProgress(); err != nil {
return fmt.Errorf("Failed to set container state to RemovalInProgress: %s", err)
}
defer container.ResetRemovalInProgress()
if err = container.Stop(3); err != nil {
return err
}
// Deregister the container before removing its directory, to avoid race conditions
daemon.idIndex.Delete(container.ID)
daemon.containers.Delete(container.ID)
// Mark container dead. We don't want anybody to be restarting it.
container.SetDead()
// Save container state to disk. So that if error happens before
// container meta file got removed from disk, then a restart of
// docker should not make a dead container alive.
container.ToDisk()
// If force removal is required, delete container from various
// indexes even if removal failed.
defer func() {
if err != nil && forceRemove {
daemon.idIndex.Delete(container.ID)
daemon.containers.Delete(container.ID)
}
}()
container.derefVolumes()
if _, err := daemon.containerGraph.Purge(container.ID); err != nil {
log.Debugf("Unable to remove container from link graph: %s", err)
}
if err := daemon.driver.Remove(container.ID); err != nil {
if err = daemon.driver.Remove(container.ID); err != nil {
return fmt.Errorf("Driver %s failed to remove root filesystem %s: %s", daemon.driver, container.ID, err)
}
@@ -113,15 +149,17 @@ func (daemon *Daemon) Rm(container *Container) error {
return fmt.Errorf("Driver %s failed to remove init filesystem %s: %s", daemon.driver, initID, err)
}
if err := os.RemoveAll(container.root); err != nil {
if err = os.RemoveAll(container.root); err != nil {
return fmt.Errorf("Unable to remove filesystem for %v: %v", container.ID, err)
}
if err := daemon.execDriver.Clean(container.ID); err != nil {
if err = daemon.execDriver.Clean(container.ID); err != nil {
return fmt.Errorf("Unable to remove execdriver data for %s: %s", container.ID, err)
}
selinuxFreeLxcContexts(container.ProcessLabel)
daemon.idIndex.Delete(container.ID)
daemon.containers.Delete(container.ID)
return nil
}

View File

@@ -10,13 +10,13 @@ import (
"github.com/docker/docker/pkg/sysinfo"
)
func NewDriver(name, root, initPath string, sysInfo *sysinfo.SysInfo) (execdriver.Driver, error) {
func NewDriver(name, root, libPath, initPath string, sysInfo *sysinfo.SysInfo) (execdriver.Driver, error) {
switch name {
case "lxc":
// we want to give the lxc driver the full docker root because it needs
// to access and write config and template files in /var/lib/docker/containers/*
// to be backwards compatible
return lxc.NewDriver(root, initPath, sysInfo.AppArmor)
return lxc.NewDriver(root, libPath, initPath, sysInfo.AppArmor)
case "native":
return native.NewDriver(path.Join(root, "execdriver", "native"), initPath)
}

View File

@@ -20,6 +20,7 @@ import (
"github.com/docker/docker/daemon/execdriver"
sysinfo "github.com/docker/docker/pkg/system"
"github.com/docker/docker/pkg/term"
"github.com/docker/docker/pkg/version"
"github.com/docker/docker/utils"
"github.com/docker/libcontainer"
"github.com/docker/libcontainer/cgroups"
@@ -35,6 +36,7 @@ var ErrExec = errors.New("Unsupported: Exec is not supported by the lxc driver")
type driver struct {
root string // root path for the driver to use
libPath string
initPath string
apparmor bool
sharedRoot bool
@@ -48,7 +50,10 @@ type activeContainer struct {
cmd *exec.Cmd
}
func NewDriver(root, initPath string, apparmor bool) (*driver, error) {
func NewDriver(root, libPath, initPath string, apparmor bool) (*driver, error) {
if err := os.MkdirAll(root, 0700); err != nil {
return nil, err
}
// setup unconfined symlink
if err := linkLxcStart(root); err != nil {
return nil, err
@@ -60,6 +65,7 @@ func NewDriver(root, initPath string, apparmor bool) (*driver, error) {
return &driver{
apparmor: apparmor,
root: root,
libPath: libPath,
initPath: initPath,
sharedRoot: rootIsShared(),
activeContainers: make(map[string]*activeContainer),
@@ -115,6 +121,13 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
"-n", c.ID,
"-f", configPath,
}
// From lxc>=1.1 the default behavior is to daemonize containers after start
lxcVersion := version.Version(d.version())
if lxcVersion.GreaterThanOrEqualTo(version.Version("1.1")) {
params = append(params, "-F")
}
if c.Network.ContainerID != "" {
params = append(params,
"--share-net", c.Network.ContainerID,
@@ -658,7 +671,7 @@ func rootIsShared() bool {
}
func (d *driver) containerDir(containerId string) string {
return path.Join(d.root, "containers", containerId)
return path.Join(d.libPath, "containers", containerId)
}
func (d *driver) generateLXCConfig(c *execdriver.Command) (string, error) {
@@ -688,7 +701,7 @@ func (d *driver) generateEnvConfig(c *execdriver.Command) error {
if err != nil {
return err
}
p := path.Join(d.root, "containers", c.ID, "config.env")
p := path.Join(d.libPath, "containers", c.ID, "config.env")
c.Mounts = append(c.Mounts, execdriver.Mount{
Source: p,
Destination: "/.dockerenv",
@@ -780,5 +793,8 @@ func (d *driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessCo
}
func (d *driver) Stats(id string) (*execdriver.ResourceStats, error) {
if _, ok := d.activeContainers[id]; !ok {
return nil, fmt.Errorf("%s is not a key in active containers", id)
}
return execdriver.Stats(d.containerDir(id), d.activeContainers[id].container.Cgroups.Memory, d.machineMemory)
}

View File

@@ -39,7 +39,7 @@ func TestLXCConfig(t *testing.T) {
cpu = cpuMin + rand.Intn(cpuMax-cpuMin)
)
driver, err := NewDriver(root, "", false)
driver, err := NewDriver(root, root, "", false)
if err != nil {
t.Fatal(err)
}
@@ -76,7 +76,7 @@ func TestCustomLxcConfig(t *testing.T) {
os.MkdirAll(path.Join(root, "containers", "1"), 0777)
driver, err := NewDriver(root, "", false)
driver, err := NewDriver(root, root, "", false)
if err != nil {
t.Fatal(err)
}
@@ -194,7 +194,7 @@ func TestCustomLxcConfigMounts(t *testing.T) {
}
os.MkdirAll(path.Join(root, "containers", "1"), 0777)
driver, err := NewDriver(root, "", false)
driver, err := NewDriver(root, root, "", false)
if err != nil {
t.Fatal(err)
}
@@ -248,7 +248,7 @@ func TestCustomLxcConfigMisc(t *testing.T) {
}
defer os.RemoveAll(root)
os.MkdirAll(path.Join(root, "containers", "1"), 0777)
driver, err := NewDriver(root, "", true)
driver, err := NewDriver(root, root, "", true)
if err != nil {
t.Fatal(err)
@@ -313,7 +313,7 @@ func TestCustomLxcConfigMiscOverride(t *testing.T) {
}
defer os.RemoveAll(root)
os.MkdirAll(path.Join(root, "containers", "1"), 0777)
driver, err := NewDriver(root, "", false)
driver, err := NewDriver(root, root, "", false)
if err != nil {
t.Fatal(err)
}

View File

@@ -6,12 +6,10 @@ import (
"errors"
"fmt"
"net"
"path/filepath"
"strings"
"syscall"
"github.com/docker/docker/daemon/execdriver"
"github.com/docker/docker/pkg/symlink"
"github.com/docker/libcontainer/apparmor"
"github.com/docker/libcontainer/configs"
"github.com/docker/libcontainer/devices"
@@ -228,10 +226,6 @@ func (d *driver) setupMounts(container *configs.Config, c *execdriver.Command) e
container.Mounts = defaultMounts
for _, m := range c.Mounts {
dest, err := symlink.FollowSymlinkInScope(filepath.Join(c.Rootfs, m.Destination), c.Rootfs)
if err != nil {
return err
}
flags := syscall.MS_BIND | syscall.MS_REC
if !m.Writable {
flags |= syscall.MS_RDONLY
@@ -239,10 +233,9 @@ func (d *driver) setupMounts(container *configs.Config, c *execdriver.Command) e
if m.Slave {
flags |= syscall.MS_SLAVE
}
container.Mounts = append(container.Mounts, &configs.Mount{
Source: m.Source,
Destination: dest,
Destination: m.Destination,
Device: "bind",
Flags: flags,
})

View File

@@ -64,7 +64,6 @@ func NewDriver(root, initPath string) (*driver, error) {
root,
cgm,
libcontainer.InitPath(reexec.Self(), DriverName),
libcontainer.TmpfsRoot,
)
if err != nil {
return nil, err
@@ -157,32 +156,68 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
startCallback(&c.ProcessConfig, pid)
}
oomKillNotification, err := cont.NotifyOOM()
if err != nil {
oomKillNotification = nil
log.Warnf("Your kernel does not support OOM notifications: %s", err)
}
oom := notifyOnOOM(cont)
waitF := p.Wait
if nss := cont.Config().Namespaces; nss.Contains(configs.NEWPID) {
if nss := cont.Config().Namespaces; !nss.Contains(configs.NEWPID) {
// we need such hack for tracking processes with inerited fds,
// because cmd.Wait() waiting for all streams to be copied
waitF = waitInPIDHost(p, cont)
}
ps, err := waitF()
if err != nil {
if err, ok := err.(*exec.ExitError); !ok {
execErr, ok := err.(*exec.ExitError)
if !ok {
return execdriver.ExitStatus{ExitCode: -1}, err
} else {
ps = err.ProcessState
}
ps = execErr.ProcessState
}
cont.Destroy()
_, oomKill := <-oomKillNotification
_, oomKill := <-oom
return execdriver.ExitStatus{ExitCode: utils.ExitStatus(ps.Sys().(syscall.WaitStatus)), OOMKilled: oomKill}, nil
}
// notifyOnOOM returns a channel that signals if the container received an OOM notification
// for any process. If it is unable to subscribe to OOM notifications then a closed
// channel is returned as it will be non-blocking and return the correct result when read.
func notifyOnOOM(container libcontainer.Container) <-chan struct{} {
oom, err := container.NotifyOOM()
if err != nil {
log.Warnf("Your kernel does not support OOM notifications: %s", err)
c := make(chan struct{})
close(c)
return c
}
return oom
}
func killCgroupProcs(c libcontainer.Container) {
var procs []*os.Process
if err := c.Pause(); err != nil {
log.Warn(err)
}
pids, err := c.Processes()
if err != nil {
// don't care about childs if we can't get them, this is mostly because cgroup already deleted
log.Warnf("Failed to get processes from container %s: %v", c.ID(), err)
}
for _, pid := range pids {
if p, err := os.FindProcess(pid); err == nil {
procs = append(procs, p)
if err := p.Kill(); err != nil {
log.Warn(err)
}
}
}
if err := c.Resume(); err != nil {
log.Warn(err)
}
for _, p := range procs {
if _, err := p.Wait(); err != nil {
log.Warn(err)
}
}
}
func waitInPIDHost(p *libcontainer.Process, c libcontainer.Container) func() (*os.ProcessState, error) {
return func() (*os.ProcessState, error) {
pid, err := p.Pid()
@@ -193,26 +228,13 @@ func waitInPIDHost(p *libcontainer.Process, c libcontainer.Container) func() (*o
process, err := os.FindProcess(pid)
s, err := process.Wait()
if err != nil {
if err, ok := err.(*exec.ExitError); !ok {
execErr, ok := err.(*exec.ExitError)
if !ok {
return s, err
} else {
s = err.ProcessState
}
s = execErr.ProcessState
}
processes, err := c.Processes()
if err != nil {
return s, err
}
for _, pid := range processes {
process, err := os.FindProcess(pid)
if err != nil {
log.Errorf("Failed to kill process: %d", pid)
continue
}
process.Kill()
}
killCgroupProcs(c)
p.Wait()
return s, err
}
@@ -248,29 +270,25 @@ func (d *driver) Unpause(c *execdriver.Command) error {
func (d *driver) Terminate(c *execdriver.Command) error {
defer d.cleanContainer(c.ID)
// lets check the start time for the process
active := d.activeContainers[c.ID]
if active == nil {
return fmt.Errorf("active container for %s does not exist", c.ID)
container, err := d.factory.Load(c.ID)
if err != nil {
return err
}
state, err := active.State()
defer container.Destroy()
state, err := container.State()
if err != nil {
return err
}
pid := state.InitProcessPid
currentStartTime, err := system.GetProcessStartTime(pid)
if err != nil {
return err
}
if state.InitProcessStartTime == currentStartTime {
err = syscall.Kill(pid, 9)
syscall.Wait4(pid, nil, 0, nil)
}
return err
}
func (d *driver) Info(id string) execdriver.Info {

View File

@@ -82,9 +82,16 @@ func New() *configs.Config {
},
MaskPaths: []string{
"/proc/kcore",
"/proc/latency_stats",
"/proc/timer_stats",
},
ReadonlyPaths: []string{
"/proc/sys", "/proc/sysrq-trigger", "/proc/irq", "/proc/bus",
"/proc/asound",
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger",
},
}

View File

@@ -23,6 +23,7 @@ package aufs
import (
"bufio"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path"
@@ -47,6 +48,9 @@ var (
graphdriver.FsMagicAufs,
}
backingFs = "<unknown>"
enableDirpermLock sync.Once
enableDirperm bool
)
func init() {
@@ -152,6 +156,7 @@ func (a *Driver) Status() [][2]string {
{"Root Dir", a.rootPath()},
{"Backing Filesystem", backingFs},
{"Dirs", fmt.Sprintf("%d", len(ids))},
{"Dirperm1 Supported", fmt.Sprintf("%v", useDirperm())},
}
}
@@ -422,7 +427,11 @@ func (a *Driver) aufsMount(ro []string, rw, target, mountLabel string) (err erro
// Mount options are clipped to page size(4096 bytes). If there are more
// layers then these are remounted individually using append.
b := make([]byte, syscall.Getpagesize()-len(mountLabel)-54) // room for xino & mountLabel
offset := 54
if useDirperm() {
offset += len("dirperm1")
}
b := make([]byte, syscall.Getpagesize()-len(mountLabel)-offset) // room for xino & mountLabel
bp := copy(b, fmt.Sprintf("br:%s=rw", rw))
firstMount := true
@@ -446,7 +455,11 @@ func (a *Driver) aufsMount(ro []string, rw, target, mountLabel string) (err erro
}
if firstMount {
data := label.FormatMountLabel(fmt.Sprintf("%s,dio,xino=/dev/shm/aufs.xino", string(b[:bp])), mountLabel)
opts := "dio,xino=/dev/shm/aufs.xino"
if useDirperm() {
opts += ",dirperm1"
}
data := label.FormatMountLabel(fmt.Sprintf("%s,%s", string(b[:bp]), opts), mountLabel)
if err = mount("none", target, "aufs", 0, data); err != nil {
return
}
@@ -460,3 +473,33 @@ func (a *Driver) aufsMount(ro []string, rw, target, mountLabel string) (err erro
return
}
// useDirperm checks dirperm1 mount option can be used with the current
// version of aufs.
func useDirperm() bool {
enableDirpermLock.Do(func() {
base, err := ioutil.TempDir("", "docker-aufs-base")
if err != nil {
log.Errorf("error checking dirperm1: %v", err)
return
}
defer os.RemoveAll(base)
union, err := ioutil.TempDir("", "docker-aufs-union")
if err != nil {
log.Errorf("error checking dirperm1: %v", err)
return
}
defer os.RemoveAll(union)
opts := fmt.Sprintf("br:%s,dirperm1,xino=/dev/shm/aufs.xino", base)
if err := mount("none", union, "aufs", 0, opts); err != nil {
return
}
enableDirperm = true
if err := Unmount(union); err != nil {
log.Errorf("error checking dirperm1: failed to unmount %v", err)
}
})
return enableDirperm
}

View File

@@ -5,20 +5,22 @@ package btrfs
/*
#include <btrfs/version.h>
// because around version 3.16, they did not define lib version yet
int my_btrfs_lib_version() {
#ifdef BTRFS_LIB_VERSION
return BTRFS_LIB_VERSION;
#else
return -1;
// around version 3.16, they did not define lib version yet
#ifndef BTRFS_LIB_VERSION
#define BTRFS_LIB_VERSION -1
#endif
// upstream had removed it, but now it will be coming back
#ifndef BTRFS_BUILD_VERSION
#define BTRFS_BUILD_VERSION "-"
#endif
}
*/
import "C"
func BtrfsBuildVersion() string {
return string(C.BTRFS_BUILD_VERSION)
}
func BtrfsLibVersion() int {
return int(C.BTRFS_LIB_VERSION)
}

View File

@@ -8,6 +8,7 @@ package btrfs
func BtrfsBuildVersion() string {
return "-"
}
func BtrfsLibVersion() int {
return -1
}

View File

@@ -1,4 +1,4 @@
// +build linux
// +build linux,!btrfs_noversion
package btrfs
@@ -6,8 +6,8 @@ import (
"testing"
)
func TestBuildVersion(t *testing.T) {
if len(BtrfsBuildVersion()) == 0 {
t.Errorf("expected output from btrfs build version, but got empty string")
func TestLibVersion(t *testing.T) {
if BtrfsLibVersion() <= 0 {
t.Errorf("expected output from btrfs lib version > 0")
}
}

View File

@@ -39,9 +39,8 @@ var (
"aufs",
"btrfs",
"devicemapper",
"vfs",
// experimental, has to be enabled manually for now
"overlay",
"vfs",
}
ErrNotSupported = errors.New("driver not supported")

View File

@@ -0,0 +1,45 @@
package syslog
import (
"fmt"
"log/syslog"
"os"
"path"
"sync"
"github.com/docker/docker/daemon/logger"
)
type Syslog struct {
writer *syslog.Writer
tag string
mu sync.Mutex
}
func New(tag string) (logger.Logger, error) {
log, err := syslog.New(syslog.LOG_DAEMON, fmt.Sprintf("%s/%s", path.Base(os.Args[0]), tag))
if err != nil {
return nil, err
}
return &Syslog{
writer: log,
}, nil
}
func (s *Syslog) Log(msg *logger.Message) error {
if msg.Source == "stderr" {
return s.writer.Err(string(msg.Line))
}
return s.writer.Info(string(msg.Line))
}
func (s *Syslog) Close() error {
if s.writer != nil {
return s.writer.Close()
}
return nil
}
func (s *Syslog) Name() string {
return "Syslog"
}

View File

@@ -7,6 +7,7 @@ import (
"io/ioutil"
"net"
"os"
"os/exec"
"strings"
"sync"
@@ -77,11 +78,19 @@ var (
bridgeIPv4Network *net.IPNet
bridgeIPv6Addr net.IP
globalIPv6Network *net.IPNet
portMapper *portmapper.PortMapper
once sync.Once
defaultBindingIP = net.ParseIP("0.0.0.0")
currentInterfaces = ifaces{c: make(map[string]*networkInterface)}
)
func initPortMapper() {
once.Do(func() {
portMapper = portmapper.New()
})
}
func InitDriver(job *engine.Job) engine.Status {
var (
networkv4 *net.IPNet
@@ -99,6 +108,14 @@ func InitDriver(job *engine.Job) engine.Status {
fixedCIDRv6 = job.Getenv("FixedCIDRv6")
)
// try to modprobe bridge first
// see gh#12177
if out, err := exec.Command("modprobe", "-va", "bridge", "nf_nat").Output(); err != nil {
log.Warnf("Running modprobe bridge nf_nat failed with message: %s, error: %v", out, err)
}
initPortMapper()
if defaultIP := job.Getenv("DefaultBindingIP"); defaultIP != "" {
defaultBindingIP = net.ParseIP(defaultIP)
}
@@ -234,7 +251,7 @@ func InitDriver(job *engine.Job) engine.Status {
if err != nil {
return job.Error(err)
}
portmapper.SetIptablesChain(chain)
portMapper.SetIptablesChain(chain)
}
bridgeIPv4Network = networkv4
@@ -349,6 +366,11 @@ func setupIPTables(addr net.Addr, icc, ipmasq bool) error {
return nil
}
func RequestPort(ip net.IP, proto string, port int) (int, error) {
initPortMapper()
return portMapper.Allocator.RequestPort(ip, proto, port)
}
// configureBridge attempts to create and configure a network bridge interface named `bridgeIface` on the host
// If bridgeIP is empty, it will try to find a non-conflicting IP from the Docker-specified private ranges
// If the bridge `bridgeIface` already exists, it will only perform the IP address association with the existing
@@ -586,7 +608,7 @@ func Release(job *engine.Job) engine.Status {
}
for _, nat := range containerInterface.PortMappings {
if err := portmapper.Unmap(nat); err != nil {
if err := portMapper.Unmap(nat); err != nil {
log.Infof("Unable to unmap port %s: %s", nat, err)
}
}
@@ -643,7 +665,7 @@ func AllocatePort(job *engine.Job) engine.Status {
var host net.Addr
for i := 0; i < MaxAllocatedPortAttempts; i++ {
if host, err = portmapper.Map(container, ip, hostPort); err == nil {
if host, err = portMapper.Map(container, ip, hostPort); err == nil {
break
}
// There is no point in immediately retrying to map an explicitly

View File

@@ -16,44 +16,12 @@ const (
DefaultPortRangeEnd = 65535
)
var (
beginPortRange = DefaultPortRangeStart
endPortRange = DefaultPortRangeEnd
)
type portMap struct {
p map[int]struct{}
last int
}
func newPortMap() *portMap {
return &portMap{
p: map[int]struct{}{},
last: endPortRange,
}
}
type protoMap map[string]*portMap
func newProtoMap() protoMap {
return protoMap{
"tcp": newPortMap(),
"udp": newPortMap(),
}
}
type ipMapping map[string]protoMap
var (
ErrAllPortsAllocated = errors.New("all ports are allocated")
ErrUnknownProtocol = errors.New("unknown protocol")
)
var (
mutex sync.Mutex
defaultIP = net.ParseIP("0.0.0.0")
globalMap = ipMapping{}
defaultIP = net.ParseIP("0.0.0.0")
)
type ErrPortAlreadyAllocated struct {
@@ -68,31 +36,6 @@ func NewErrPortAlreadyAllocated(ip string, port int) ErrPortAlreadyAllocated {
}
}
func init() {
const portRangeKernelParam = "/proc/sys/net/ipv4/ip_local_port_range"
file, err := os.Open(portRangeKernelParam)
if err != nil {
log.Warnf("Failed to read %s kernel parameter: %v", portRangeKernelParam, err)
return
}
var start, end int
n, err := fmt.Fscanf(bufio.NewReader(file), "%d\t%d", &start, &end)
if n != 2 || err != nil {
if err == nil {
err = fmt.Errorf("unexpected count of parsed numbers (%d)", n)
}
log.Errorf("Failed to parse port range from %s: %v", portRangeKernelParam, err)
return
}
beginPortRange = start
endPortRange = end
}
func PortRange() (int, int) {
return beginPortRange, endPortRange
}
func (e ErrPortAlreadyAllocated) IP() string {
return e.ip
}
@@ -109,12 +52,57 @@ func (e ErrPortAlreadyAllocated) Error() string {
return fmt.Sprintf("Bind for %s:%d failed: port is already allocated", e.ip, e.port)
}
type (
PortAllocator struct {
mutex sync.Mutex
ipMap ipMapping
Begin int
End int
}
portMap struct {
p map[int]struct{}
begin, end int
last int
}
protoMap map[string]*portMap
)
func New() *PortAllocator {
start, end, err := getDynamicPortRange()
if err != nil {
log.Warn(err)
start, end = DefaultPortRangeStart, DefaultPortRangeEnd
}
return &PortAllocator{
ipMap: ipMapping{},
Begin: start,
End: end,
}
}
func getDynamicPortRange() (start int, end int, err error) {
const portRangeKernelParam = "/proc/sys/net/ipv4/ip_local_port_range"
portRangeFallback := fmt.Sprintf("using fallback port range %d-%d", DefaultPortRangeStart, DefaultPortRangeEnd)
file, err := os.Open(portRangeKernelParam)
if err != nil {
return 0, 0, fmt.Errorf("port allocator - %s due to error: %v", portRangeFallback, err)
}
n, err := fmt.Fscanf(bufio.NewReader(file), "%d\t%d", &start, &end)
if n != 2 || err != nil {
if err == nil {
err = fmt.Errorf("unexpected count of parsed numbers (%d)", n)
}
return 0, 0, fmt.Errorf("port allocator - failed to parse system ephemeral port range from %s - %s: %v", portRangeKernelParam, portRangeFallback, err)
}
return start, end, nil
}
// RequestPort requests new port from global ports pool for specified ip and proto.
// If port is 0 it returns first free port. Otherwise it cheks port availability
// in pool and return that port or error if port is already busy.
func RequestPort(ip net.IP, proto string, port int) (int, error) {
mutex.Lock()
defer mutex.Unlock()
func (p *PortAllocator) RequestPort(ip net.IP, proto string, port int) (int, error) {
p.mutex.Lock()
defer p.mutex.Unlock()
if proto != "tcp" && proto != "udp" {
return 0, ErrUnknownProtocol
@@ -124,10 +112,14 @@ func RequestPort(ip net.IP, proto string, port int) (int, error) {
ip = defaultIP
}
ipstr := ip.String()
protomap, ok := globalMap[ipstr]
protomap, ok := p.ipMap[ipstr]
if !ok {
protomap = newProtoMap()
globalMap[ipstr] = protomap
protomap = protoMap{
"tcp": p.newPortMap(),
"udp": p.newPortMap(),
}
p.ipMap[ipstr] = protomap
}
mapping := protomap[proto]
if port > 0 {
@@ -146,14 +138,14 @@ func RequestPort(ip net.IP, proto string, port int) (int, error) {
}
// ReleasePort releases port from global ports pool for specified ip and proto.
func ReleasePort(ip net.IP, proto string, port int) error {
mutex.Lock()
defer mutex.Unlock()
func (p *PortAllocator) ReleasePort(ip net.IP, proto string, port int) error {
p.mutex.Lock()
defer p.mutex.Unlock()
if ip == nil {
ip = defaultIP
}
protomap, ok := globalMap[ip.String()]
protomap, ok := p.ipMap[ip.String()]
if !ok {
return nil
}
@@ -161,20 +153,29 @@ func ReleasePort(ip net.IP, proto string, port int) error {
return nil
}
func (p *PortAllocator) newPortMap() *portMap {
return &portMap{
p: map[int]struct{}{},
begin: p.Begin,
end: p.End,
last: p.End,
}
}
// ReleaseAll releases all ports for all ips.
func ReleaseAll() error {
mutex.Lock()
globalMap = ipMapping{}
mutex.Unlock()
func (p *PortAllocator) ReleaseAll() error {
p.mutex.Lock()
p.ipMap = ipMapping{}
p.mutex.Unlock()
return nil
}
func (pm *portMap) findPort() (int, error) {
port := pm.last
for i := 0; i <= endPortRange-beginPortRange; i++ {
for i := 0; i <= pm.end-pm.begin; i++ {
port++
if port > endPortRange {
port = beginPortRange
if port > pm.end {
port = pm.begin
}
if _, ok := pm.p[port]; !ok {

View File

@@ -5,32 +5,23 @@ import (
"testing"
)
func init() {
beginPortRange = DefaultPortRangeStart
endPortRange = DefaultPortRangeEnd
}
func reset() {
ReleaseAll()
}
func TestRequestNewPort(t *testing.T) {
defer reset()
p := New()
port, err := RequestPort(defaultIP, "tcp", 0)
port, err := p.RequestPort(defaultIP, "tcp", 0)
if err != nil {
t.Fatal(err)
}
if expected := beginPortRange; port != expected {
if expected := p.Begin; port != expected {
t.Fatalf("Expected port %d got %d", expected, port)
}
}
func TestRequestSpecificPort(t *testing.T) {
defer reset()
p := New()
port, err := RequestPort(defaultIP, "tcp", 5000)
port, err := p.RequestPort(defaultIP, "tcp", 5000)
if err != nil {
t.Fatal(err)
}
@@ -40,9 +31,9 @@ func TestRequestSpecificPort(t *testing.T) {
}
func TestReleasePort(t *testing.T) {
defer reset()
p := New()
port, err := RequestPort(defaultIP, "tcp", 5000)
port, err := p.RequestPort(defaultIP, "tcp", 5000)
if err != nil {
t.Fatal(err)
}
@@ -50,15 +41,15 @@ func TestReleasePort(t *testing.T) {
t.Fatalf("Expected port 5000 got %d", port)
}
if err := ReleasePort(defaultIP, "tcp", 5000); err != nil {
if err := p.ReleasePort(defaultIP, "tcp", 5000); err != nil {
t.Fatal(err)
}
}
func TestReuseReleasedPort(t *testing.T) {
defer reset()
p := New()
port, err := RequestPort(defaultIP, "tcp", 5000)
port, err := p.RequestPort(defaultIP, "tcp", 5000)
if err != nil {
t.Fatal(err)
}
@@ -66,20 +57,20 @@ func TestReuseReleasedPort(t *testing.T) {
t.Fatalf("Expected port 5000 got %d", port)
}
if err := ReleasePort(defaultIP, "tcp", 5000); err != nil {
if err := p.ReleasePort(defaultIP, "tcp", 5000); err != nil {
t.Fatal(err)
}
port, err = RequestPort(defaultIP, "tcp", 5000)
port, err = p.RequestPort(defaultIP, "tcp", 5000)
if err != nil {
t.Fatal(err)
}
}
func TestReleaseUnreadledPort(t *testing.T) {
defer reset()
p := New()
port, err := RequestPort(defaultIP, "tcp", 5000)
port, err := p.RequestPort(defaultIP, "tcp", 5000)
if err != nil {
t.Fatal(err)
}
@@ -87,7 +78,7 @@ func TestReleaseUnreadledPort(t *testing.T) {
t.Fatalf("Expected port 5000 got %d", port)
}
port, err = RequestPort(defaultIP, "tcp", 5000)
port, err = p.RequestPort(defaultIP, "tcp", 5000)
switch err.(type) {
case ErrPortAlreadyAllocated:
@@ -97,42 +88,40 @@ func TestReleaseUnreadledPort(t *testing.T) {
}
func TestUnknowProtocol(t *testing.T) {
defer reset()
if _, err := RequestPort(defaultIP, "tcpp", 0); err != ErrUnknownProtocol {
if _, err := New().RequestPort(defaultIP, "tcpp", 0); err != ErrUnknownProtocol {
t.Fatalf("Expected error %s got %s", ErrUnknownProtocol, err)
}
}
func TestAllocateAllPorts(t *testing.T) {
defer reset()
p := New()
for i := 0; i <= endPortRange-beginPortRange; i++ {
port, err := RequestPort(defaultIP, "tcp", 0)
for i := 0; i <= p.End-p.Begin; i++ {
port, err := p.RequestPort(defaultIP, "tcp", 0)
if err != nil {
t.Fatal(err)
}
if expected := beginPortRange + i; port != expected {
if expected := p.Begin + i; port != expected {
t.Fatalf("Expected port %d got %d", expected, port)
}
}
if _, err := RequestPort(defaultIP, "tcp", 0); err != ErrAllPortsAllocated {
if _, err := p.RequestPort(defaultIP, "tcp", 0); err != ErrAllPortsAllocated {
t.Fatalf("Expected error %s got %s", ErrAllPortsAllocated, err)
}
_, err := RequestPort(defaultIP, "udp", 0)
_, err := p.RequestPort(defaultIP, "udp", 0)
if err != nil {
t.Fatal(err)
}
// release a port in the middle and ensure we get another tcp port
port := beginPortRange + 5
if err := ReleasePort(defaultIP, "tcp", port); err != nil {
port := p.Begin + 5
if err := p.ReleasePort(defaultIP, "tcp", port); err != nil {
t.Fatal(err)
}
newPort, err := RequestPort(defaultIP, "tcp", 0)
newPort, err := p.RequestPort(defaultIP, "tcp", 0)
if err != nil {
t.Fatal(err)
}
@@ -142,10 +131,10 @@ func TestAllocateAllPorts(t *testing.T) {
// now pm.last == newPort, release it so that it's the only free port of
// the range, and ensure we get it back
if err := ReleasePort(defaultIP, "tcp", newPort); err != nil {
if err := p.ReleasePort(defaultIP, "tcp", newPort); err != nil {
t.Fatal(err)
}
port, err = RequestPort(defaultIP, "tcp", 0)
port, err = p.RequestPort(defaultIP, "tcp", 0)
if err != nil {
t.Fatal(err)
}
@@ -155,34 +144,34 @@ func TestAllocateAllPorts(t *testing.T) {
}
func BenchmarkAllocatePorts(b *testing.B) {
defer reset()
p := New()
for i := 0; i < b.N; i++ {
for i := 0; i <= endPortRange-beginPortRange; i++ {
port, err := RequestPort(defaultIP, "tcp", 0)
for i := 0; i <= p.End-p.Begin; i++ {
port, err := p.RequestPort(defaultIP, "tcp", 0)
if err != nil {
b.Fatal(err)
}
if expected := beginPortRange + i; port != expected {
if expected := p.Begin + i; port != expected {
b.Fatalf("Expected port %d got %d", expected, port)
}
}
reset()
p.ReleaseAll()
}
}
func TestPortAllocation(t *testing.T) {
defer reset()
p := New()
ip := net.ParseIP("192.168.0.1")
ip2 := net.ParseIP("192.168.0.2")
if port, err := RequestPort(ip, "tcp", 80); err != nil {
if port, err := p.RequestPort(ip, "tcp", 80); err != nil {
t.Fatal(err)
} else if port != 80 {
t.Fatalf("Acquire(80) should return 80, not %d", port)
}
port, err := RequestPort(ip, "tcp", 0)
port, err := p.RequestPort(ip, "tcp", 0)
if err != nil {
t.Fatal(err)
}
@@ -190,41 +179,41 @@ func TestPortAllocation(t *testing.T) {
t.Fatalf("Acquire(0) should return a non-zero port")
}
if _, err := RequestPort(ip, "tcp", port); err == nil {
if _, err := p.RequestPort(ip, "tcp", port); err == nil {
t.Fatalf("Acquiring a port already in use should return an error")
}
if newPort, err := RequestPort(ip, "tcp", 0); err != nil {
if newPort, err := p.RequestPort(ip, "tcp", 0); err != nil {
t.Fatal(err)
} else if newPort == port {
t.Fatalf("Acquire(0) allocated the same port twice: %d", port)
}
if _, err := RequestPort(ip, "tcp", 80); err == nil {
if _, err := p.RequestPort(ip, "tcp", 80); err == nil {
t.Fatalf("Acquiring a port already in use should return an error")
}
if _, err := RequestPort(ip2, "tcp", 80); err != nil {
if _, err := p.RequestPort(ip2, "tcp", 80); err != nil {
t.Fatalf("It should be possible to allocate the same port on a different interface")
}
if _, err := RequestPort(ip2, "tcp", 80); err == nil {
if _, err := p.RequestPort(ip2, "tcp", 80); err == nil {
t.Fatalf("Acquiring a port already in use should return an error")
}
if err := ReleasePort(ip, "tcp", 80); err != nil {
if err := p.ReleasePort(ip, "tcp", 80); err != nil {
t.Fatal(err)
}
if _, err := RequestPort(ip, "tcp", 80); err != nil {
if _, err := p.RequestPort(ip, "tcp", 80); err != nil {
t.Fatal(err)
}
port, err = RequestPort(ip, "tcp", 0)
port, err = p.RequestPort(ip, "tcp", 0)
if err != nil {
t.Fatal(err)
}
port2, err := RequestPort(ip, "tcp", port+1)
port2, err := p.RequestPort(ip, "tcp", port+1)
if err != nil {
t.Fatal(err)
}
port3, err := RequestPort(ip, "tcp", 0)
port3, err := p.RequestPort(ip, "tcp", 0)
if err != nil {
t.Fatal(err)
}
@@ -234,17 +223,17 @@ func TestPortAllocation(t *testing.T) {
}
func TestNoDuplicateBPR(t *testing.T) {
defer reset()
p := New()
if port, err := RequestPort(defaultIP, "tcp", beginPortRange); err != nil {
if port, err := p.RequestPort(defaultIP, "tcp", p.Begin); err != nil {
t.Fatal(err)
} else if port != beginPortRange {
t.Fatalf("Expected port %d got %d", beginPortRange, port)
} else if port != p.Begin {
t.Fatalf("Expected port %d got %d", p.Begin, port)
}
if port, err := RequestPort(defaultIP, "tcp", 0); err != nil {
if port, err := p.RequestPort(defaultIP, "tcp", 0); err != nil {
t.Fatal(err)
} else if port == beginPortRange {
} else if port == p.Begin {
t.Fatalf("Acquire(0) allocated the same port twice: %d", port)
}
}

View File

@@ -18,15 +18,7 @@ type mapping struct {
container net.Addr
}
var (
chain *iptables.Chain
lock sync.Mutex
// udp:ip:port
currentMappings = make(map[string]*mapping)
NewProxy = NewProxyCommand
)
var NewProxy = NewProxyCommand
var (
ErrUnknownBackendAddressType = errors.New("unknown container address type not supported")
@@ -34,13 +26,34 @@ var (
ErrPortNotMapped = errors.New("port is not mapped")
)
func SetIptablesChain(c *iptables.Chain) {
chain = c
type PortMapper struct {
chain *iptables.Chain
// udp:ip:port
currentMappings map[string]*mapping
lock sync.Mutex
Allocator *portallocator.PortAllocator
}
func Map(container net.Addr, hostIP net.IP, hostPort int) (host net.Addr, err error) {
lock.Lock()
defer lock.Unlock()
func New() *PortMapper {
return NewWithPortAllocator(portallocator.New())
}
func NewWithPortAllocator(allocator *portallocator.PortAllocator) *PortMapper {
return &PortMapper{
currentMappings: make(map[string]*mapping),
Allocator: allocator,
}
}
func (pm *PortMapper) SetIptablesChain(c *iptables.Chain) {
pm.chain = c
}
func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int) (host net.Addr, err error) {
pm.lock.Lock()
defer pm.lock.Unlock()
var (
m *mapping
@@ -52,7 +65,7 @@ func Map(container net.Addr, hostIP net.IP, hostPort int) (host net.Addr, err er
switch container.(type) {
case *net.TCPAddr:
proto = "tcp"
if allocatedHostPort, err = portallocator.RequestPort(hostIP, proto, hostPort); err != nil {
if allocatedHostPort, err = pm.Allocator.RequestPort(hostIP, proto, hostPort); err != nil {
return nil, err
}
@@ -65,7 +78,7 @@ func Map(container net.Addr, hostIP net.IP, hostPort int) (host net.Addr, err er
proxy = NewProxy(proto, hostIP, allocatedHostPort, container.(*net.TCPAddr).IP, container.(*net.TCPAddr).Port)
case *net.UDPAddr:
proto = "udp"
if allocatedHostPort, err = portallocator.RequestPort(hostIP, proto, hostPort); err != nil {
if allocatedHostPort, err = pm.Allocator.RequestPort(hostIP, proto, hostPort); err != nil {
return nil, err
}
@@ -83,25 +96,25 @@ func Map(container net.Addr, hostIP net.IP, hostPort int) (host net.Addr, err er
// release the allocated port on any further error during return.
defer func() {
if err != nil {
portallocator.ReleasePort(hostIP, proto, allocatedHostPort)
pm.Allocator.ReleasePort(hostIP, proto, allocatedHostPort)
}
}()
key := getKey(m.host)
if _, exists := currentMappings[key]; exists {
if _, exists := pm.currentMappings[key]; exists {
return nil, ErrPortMappedForIP
}
containerIP, containerPort := getIPAndPort(m.container)
if err := forward(iptables.Append, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil {
if err := pm.forward(iptables.Append, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil {
return nil, err
}
cleanup := func() error {
// need to undo the iptables rules before we return
proxy.Stop()
forward(iptables.Delete, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort)
if err := portallocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil {
pm.forward(iptables.Delete, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort)
if err := pm.Allocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil {
return err
}
@@ -115,35 +128,35 @@ func Map(container net.Addr, hostIP net.IP, hostPort int) (host net.Addr, err er
return nil, err
}
m.userlandProxy = proxy
currentMappings[key] = m
pm.currentMappings[key] = m
return m.host, nil
}
func Unmap(host net.Addr) error {
lock.Lock()
defer lock.Unlock()
func (pm *PortMapper) Unmap(host net.Addr) error {
pm.lock.Lock()
defer pm.lock.Unlock()
key := getKey(host)
data, exists := currentMappings[key]
data, exists := pm.currentMappings[key]
if !exists {
return ErrPortNotMapped
}
data.userlandProxy.Stop()
delete(currentMappings, key)
delete(pm.currentMappings, key)
containerIP, containerPort := getIPAndPort(data.container)
hostIP, hostPort := getIPAndPort(data.host)
if err := forward(iptables.Delete, data.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil {
if err := pm.forward(iptables.Delete, data.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil {
log.Errorf("Error on iptables delete: %s", err)
}
switch a := host.(type) {
case *net.TCPAddr:
return portallocator.ReleasePort(a.IP, "tcp", a.Port)
return pm.Allocator.ReleasePort(a.IP, "tcp", a.Port)
case *net.UDPAddr:
return portallocator.ReleasePort(a.IP, "udp", a.Port)
return pm.Allocator.ReleasePort(a.IP, "udp", a.Port)
}
return nil
}
@@ -168,9 +181,9 @@ func getIPAndPort(a net.Addr) (net.IP, int) {
return nil, 0
}
func forward(action iptables.Action, proto string, sourceIP net.IP, sourcePort int, containerIP string, containerPort int) error {
if chain == nil {
func (pm *PortMapper) forward(action iptables.Action, proto string, sourceIP net.IP, sourcePort int, containerIP string, containerPort int) error {
if pm.chain == nil {
return nil
}
return chain.Forward(action, sourceIP, sourcePort, proto, containerIP, containerPort)
return pm.chain.Forward(action, sourceIP, sourcePort, proto, containerIP, containerPort)
}

View File

@@ -4,7 +4,6 @@ import (
"net"
"testing"
"github.com/docker/docker/daemon/networkdriver/portallocator"
"github.com/docker/docker/pkg/iptables"
)
@@ -13,30 +12,26 @@ func init() {
NewProxy = NewMockProxyCommand
}
func reset() {
chain = nil
currentMappings = make(map[string]*mapping)
}
func TestSetIptablesChain(t *testing.T) {
defer reset()
pm := New()
c := &iptables.Chain{
Name: "TEST",
Bridge: "192.168.1.1",
}
if chain != nil {
if pm.chain != nil {
t.Fatal("chain should be nil at init")
}
SetIptablesChain(c)
if chain == nil {
pm.SetIptablesChain(c)
if pm.chain == nil {
t.Fatal("chain should not be nil after set")
}
}
func TestMapPorts(t *testing.T) {
pm := New()
dstIp1 := net.ParseIP("192.168.0.1")
dstIp2 := net.ParseIP("192.168.0.2")
dstAddr1 := &net.TCPAddr{IP: dstIp1, Port: 80}
@@ -49,34 +44,34 @@ func TestMapPorts(t *testing.T) {
return (addr1.Network() == addr2.Network()) && (addr1.String() == addr2.String())
}
if host, err := Map(srcAddr1, dstIp1, 80); err != nil {
if host, err := pm.Map(srcAddr1, dstIp1, 80); err != nil {
t.Fatalf("Failed to allocate port: %s", err)
} else if !addrEqual(dstAddr1, host) {
t.Fatalf("Incorrect mapping result: expected %s:%s, got %s:%s",
dstAddr1.String(), dstAddr1.Network(), host.String(), host.Network())
}
if _, err := Map(srcAddr1, dstIp1, 80); err == nil {
if _, err := pm.Map(srcAddr1, dstIp1, 80); err == nil {
t.Fatalf("Port is in use - mapping should have failed")
}
if _, err := Map(srcAddr2, dstIp1, 80); err == nil {
if _, err := pm.Map(srcAddr2, dstIp1, 80); err == nil {
t.Fatalf("Port is in use - mapping should have failed")
}
if _, err := Map(srcAddr2, dstIp2, 80); err != nil {
if _, err := pm.Map(srcAddr2, dstIp2, 80); err != nil {
t.Fatalf("Failed to allocate port: %s", err)
}
if Unmap(dstAddr1) != nil {
if pm.Unmap(dstAddr1) != nil {
t.Fatalf("Failed to release port")
}
if Unmap(dstAddr2) != nil {
if pm.Unmap(dstAddr2) != nil {
t.Fatalf("Failed to release port")
}
if Unmap(dstAddr2) == nil {
if pm.Unmap(dstAddr2) == nil {
t.Fatalf("Port already released, but no error reported")
}
}
@@ -115,6 +110,7 @@ func TestGetUDPIPAndPort(t *testing.T) {
}
func TestMapAllPortsSingleInterface(t *testing.T) {
pm := New()
dstIp1 := net.ParseIP("0.0.0.0")
srcAddr1 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")}
@@ -124,26 +120,26 @@ func TestMapAllPortsSingleInterface(t *testing.T) {
defer func() {
for _, val := range hosts {
Unmap(val)
pm.Unmap(val)
}
}()
for i := 0; i < 10; i++ {
start, end := portallocator.PortRange()
start, end := pm.Allocator.Begin, pm.Allocator.End
for i := start; i < end; i++ {
if host, err = Map(srcAddr1, dstIp1, 0); err != nil {
if host, err = pm.Map(srcAddr1, dstIp1, 0); err != nil {
t.Fatal(err)
}
hosts = append(hosts, host)
}
if _, err := Map(srcAddr1, dstIp1, start); err == nil {
if _, err := pm.Map(srcAddr1, dstIp1, start); err == nil {
t.Fatalf("Port %d should be bound but is not", start)
}
for _, val := range hosts {
if err := Unmap(val); err != nil {
if err := pm.Unmap(val); err != nil {
t.Fatal(err)
}
}

View File

@@ -11,16 +11,18 @@ import (
type State struct {
sync.Mutex
Running bool
Paused bool
Restarting bool
OOMKilled bool
Pid int
ExitCode int
Error string // contains last known error when starting the container
StartedAt time.Time
FinishedAt time.Time
waitChan chan struct{}
Running bool
Paused bool
Restarting bool
OOMKilled bool
removalInProgress bool // Not need for this to be persistent on disk.
Dead bool
Pid int
ExitCode int
Error string // contains last known error when starting the container
StartedAt time.Time
FinishedAt time.Time
waitChan chan struct{}
}
func NewState() *State {
@@ -42,6 +44,14 @@ func (s *State) String() string {
return fmt.Sprintf("Up %s", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt)))
}
if s.removalInProgress {
return "Removal In Progress"
}
if s.Dead {
return "Dead"
}
if s.FinishedAt.IsZero() {
return ""
}
@@ -60,6 +70,11 @@ func (s *State) StateString() string {
}
return "running"
}
if s.Dead {
return "dead"
}
return "exited"
}
@@ -217,3 +232,25 @@ func (s *State) IsPaused() bool {
s.Unlock()
return res
}
func (s *State) SetRemovalInProgress() error {
s.Lock()
defer s.Unlock()
if s.removalInProgress {
return fmt.Errorf("Status is already RemovalInProgress")
}
s.removalInProgress = true
return nil
}
func (s *State) ResetRemovalInProgress() {
s.Lock()
s.removalInProgress = false
s.Unlock()
}
func (s *State) SetDead() {
s.Lock()
s.Dead = true
s.Unlock()
}

View File

@@ -24,6 +24,7 @@ type Mount struct {
Writable bool
copyData bool
from *Container
isBind bool
}
func (mnt *Mount) Export(resource string) (io.ReadCloser, error) {
@@ -79,7 +80,7 @@ func (m *Mount) initialize() error {
if hostPath, exists := m.container.Volumes[m.MountToPath]; exists {
// If this is a bind-mount/volumes-from, maybe it was passed in at start instead of create
// We need to make sure bind-mounts/volumes-from passed on start can override existing ones.
if !m.volume.IsBindMount && m.from == nil {
if (!m.volume.IsBindMount && !m.isBind) && m.from == nil {
return nil
}
if m.volume.Path == hostPath {
@@ -172,6 +173,7 @@ func (container *Container) parseVolumeMountConfig() (map[string]*Mount, error)
volume: vol,
MountToPath: mountToPath,
Writable: writable,
isBind: true, // in case the volume itself is a normal volume, but is being mounted in as a bindmount here
}
}
@@ -187,10 +189,13 @@ func (container *Container) parseVolumeMountConfig() (map[string]*Mount, error)
if _, exists := container.Volumes[path]; exists {
continue
}
if stat, err := os.Stat(filepath.Join(container.basefs, path)); err == nil {
realPath, err := container.getResourcePath(path)
if err != nil {
return nil, fmt.Errorf("failed to evaluate the absolute path of symlink")
}
if stat, err := os.Stat(realPath); err == nil {
if !stat.IsDir() {
return nil, fmt.Errorf("file exists at %s, can't create volume there")
return nil, fmt.Errorf("file exists at %s, can't create volume there", realPath)
}
}

View File

@@ -4,11 +4,20 @@
FROM docs/base:latest
MAINTAINER Sven Dowideit <SvenDowideit@docker.com> (@SvenDowideit)
# This section ensures we pull the correct version of each
# sub project
ENV COMPOSE_BRANCH 1.2.0
ENV SWARM_BRANCH v0.2.0
ENV MACHINE_BRANCH master
ENV DISTRIB_BRANCH master
# TODO: need the full repo source to get the git version info
COPY . /src
# Reset the /docs dir so we can replace the theme meta with the new repo's git info
RUN git reset --hard
# RUN git reset --hard
# Then copy the desired docs into the /docs/sources/ dir
COPY ./sources/ /docs/sources
@@ -23,45 +32,77 @@ COPY ./mkdocs.yml mkdocs.yml
COPY ./s3_website.json s3_website.json
COPY ./release.sh release.sh
# Docker Distribution
#
#ADD https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/mkdocs.yml /docs/mkdocs-distribution.yml
ADD https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/images/notifications.png /docs/sources/registry/images/notifications.png
ADD https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/images/registry.png /docs/sources/registry/images/registry.png
ADD https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/overview.md /docs/sources/registry/overview.md
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/registry/overview.md
ADD https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/deploying.md /docs/sources/registry/deploying.md
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/registry/deploying.md
ADD https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/configuration.md /docs/sources/registry/configuration.md
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/registry/configuration.md
ADD https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/storagedrivers.md /docs/sources/registry/storagedrivers.md
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/registry/storagedrivers.md
ADD https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/notifications.md /docs/sources/registry/notifications.md
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/registry/notifications.md
ADD https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/spec/api.md /docs/sources/registry/spec/api.md
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/registry/spec/api.md
ADD https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/spec/json.md /docs/sources/registry/spec/json.md
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/registry/spec/json.md
ADD https://raw.githubusercontent.com/docker/distribution/${DISTRIB_BRANCH}/docs/spec/auth/token.md /docs/sources/registry/spec/auth/token.md
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/registry/spec/auth/token.md
# Docker Swarm
#ADD https://raw.githubusercontent.com/docker/swarm/master/docs/mkdocs.yml /docs/mkdocs-swarm.yml
ADD https://raw.githubusercontent.com/docker/swarm/master/docs/index.md /docs/sources/swarm/index.md
#ADD https://raw.githubusercontent.com/docker/swarm/${SWARM_BRANCH}/docs/mkdocs.yml /docs/mkdocs-swarm.yml
ADD https://raw.githubusercontent.com/docker/swarm/${SWARM_BRANCH}/docs/index.md /docs/sources/swarm/index.md
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/swarm/index.md
ADD https://raw.githubusercontent.com/docker/swarm/master/discovery/README.md /docs/sources/swarm/discovery.md
ADD https://raw.githubusercontent.com/docker/swarm/${SWARM_BRANCH}/discovery/README.md /docs/sources/swarm/discovery.md
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/swarm/discovery.md
ADD https://raw.githubusercontent.com/docker/swarm/master/api/README.md /docs/sources/swarm/API.md
ADD https://raw.githubusercontent.com/docker/swarm/${SWARM_BRANCH}/api/README.md /docs/sources/swarm/API.md
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/swarm/API.md
ADD https://raw.githubusercontent.com/docker/swarm/master/scheduler/filter/README.md /docs/sources/swarm/scheduler/filter.md
ADD https://raw.githubusercontent.com/docker/swarm/${SWARM_BRANCH}/scheduler/filter/README.md /docs/sources/swarm/scheduler/filter.md
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/swarm/scheduler/filter.md
ADD https://raw.githubusercontent.com/docker/swarm/master/scheduler/strategy/README.md /docs/sources/swarm/scheduler/strategy.md
ADD https://raw.githubusercontent.com/docker/swarm/${SWARM_BRANCH}/scheduler/strategy/README.md /docs/sources/swarm/scheduler/strategy.md
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/swarm/scheduler/strategy.md
# Docker Machine
#ADD https://raw.githubusercontent.com/docker/machine/master/docs/mkdocs.yml /docs/mkdocs-machine.yml
ADD https://raw.githubusercontent.com/docker/machine/master/docs/index.md /docs/sources/machine/index.md
#ADD https://raw.githubusercontent.com/docker/machine/${MACHINE_BRANCH}/docs/mkdocs.yml /docs/mkdocs-machine.yml
ADD https://raw.githubusercontent.com/docker/machine/${MACHINE_BRANCH}/docs/index.md /docs/sources/machine/index.md
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/machine/index.md
# Docker Compose
#ADD https://raw.githubusercontent.com/docker/compose/master/docs/mkdocs.yml /docs/mkdocs-compose.yml
ADD https://raw.githubusercontent.com/docker/compose/master/docs/index.md /docs/sources/compose/index.md
#ADD https://raw.githubusercontent.com/docker/compose/${COMPOSE_BRANCH}/docs/mkdocs.yml /docs/mkdocs-compose.yml
ADD https://raw.githubusercontent.com/docker/compose/${COMPOSE_BRANCH}/docs/index.md /docs/sources/compose/index.md
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/compose/index.md
ADD https://raw.githubusercontent.com/docker/compose/master/docs/install.md /docs/sources/compose/install.md
ADD https://raw.githubusercontent.com/docker/compose/${COMPOSE_BRANCH}/docs/install.md /docs/sources/compose/install.md
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/compose/install.md
ADD https://raw.githubusercontent.com/docker/compose/master/docs/cli.md /docs/sources/compose/cli.md
ADD https://raw.githubusercontent.com/docker/compose/${COMPOSE_BRANCH}/docs/cli.md /docs/sources/compose/cli.md
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/compose/cli.md
ADD https://raw.githubusercontent.com/docker/compose/master/docs/yml.md /docs/sources/compose/yml.md
ADD https://raw.githubusercontent.com/docker/compose/${COMPOSE_BRANCH}/docs/yml.md /docs/sources/compose/yml.md
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/compose/yml.md
ADD https://raw.githubusercontent.com/docker/compose/master/docs/env.md /docs/sources/compose/env.md
ADD https://raw.githubusercontent.com/docker/compose/${COMPOSE_BRANCH}/docs/env.md /docs/sources/compose/env.md
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/compose/env.md
ADD https://raw.githubusercontent.com/docker/compose/master/docs/completion.md /docs/sources/compose/completion.md
ADD https://raw.githubusercontent.com/docker/compose/${COMPOSE_BRANCH}/docs/completion.md /docs/sources/compose/completion.md
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/compose/completion.md
ADD https://raw.githubusercontent.com/docker/compose/master/docs/django.md /docs/sources/compose/django.md
ADD https://raw.githubusercontent.com/docker/compose/${COMPOSE_BRANCH}/docs/django.md /docs/sources/compose/django.md
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/compose/django.md
ADD https://raw.githubusercontent.com/docker/compose/master/docs/rails.md /docs/sources/compose/rails.md
ADD https://raw.githubusercontent.com/docker/compose/${COMPOSE_BRANCH}/docs/rails.md /docs/sources/compose/rails.md
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/compose/rails.md
ADD https://raw.githubusercontent.com/docker/compose/master/docs/wordpress.md /docs/sources/compose/wordpress.md
ADD https://raw.githubusercontent.com/docker/compose/${COMPOSE_BRANCH}/docs/wordpress.md /docs/sources/compose/wordpress.md
RUN sed -i.old '1s;^;no_version_dropdown: true;' /docs/sources/compose/wordpress.md
# Then build everything together, ready for mkdocs
RUN /docs/build.sh
RUN /docs/build.sh

View File

@@ -121,7 +121,7 @@ IMAGE [COMMAND] [ARG...]
**--lxc-conf**=[]
(lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"
**--log-driver**="|*json-file*|*none*"
**--log-driver**="|*json-file*|*syslog*|*none*"
Logging driver for container. Default is defined by daemon `--log-driver` flag.
**Warning**: `docker logs` command works only for `json-file` logging driver.

View File

@@ -2,7 +2,7 @@
% Docker Community
% JUNE 2014
# NAME
docker-login - Register or log in to a Docker registry server, if no server is specified "https://index.docker.io/v1/" is the default.
docker-login - Register or log in to a Docker registry.
# SYNOPSIS
**docker login**
@@ -13,9 +13,14 @@ docker-login - Register or log in to a Docker registry server, if no server is s
[SERVER]
# DESCRIPTION
Register or Login to a docker registry server, if no server is
specified "https://index.docker.io/v1/" is the default. If you want to
login to a private registry you can specify this by adding the server name.
Register or log in to a Docker Registry Service located on the specified
`SERVER`. You can specify a URL or a `hostname` for the `SERVER` value. If you
do not specify a `SERVER`, the command uses Docker's public registry located at
`https://registry-1.docker.io/` by default. To get a username/password for Docker's public registry, create an account on Docker Hub.
You can log into any public or private repository for which you have
credentials. When you log in, the command stores encoded credentials in
`$HOME/.dockercfg` on Linux or `%USERPROFILE%/.dockercfg` on Windows.
# OPTIONS
**-e**, **--email**=""
@@ -32,7 +37,7 @@ login to a private registry you can specify this by adding the server name.
# EXAMPLES
## Login to a local registry
## Login to a registry on your localhost
# docker login localhost:8080
@@ -43,3 +48,4 @@ login to a private registry you can specify this by adding the server name.
April 2014, Originally compiled by William Henry (whenry at redhat dot com)
based on docker.com source material and internal work.
June 2014, updated by Sven Dowideit <SvenDowideit@home.org.au>
April 2015, updated by Mary Anthony for v2 <mary@docker.com>

View File

@@ -2,23 +2,24 @@
% Docker Community
% JUNE 2014
# NAME
docker-logout - Log out from a Docker registry, if no server is specified "https://index.docker.io/v1/" is the default.
docker-logout - Log out from a Docker Registry Service.
# SYNOPSIS
**docker logout**
[SERVER]
# DESCRIPTION
Log the user out from a Docker registry, if no server is
specified "https://index.docker.io/v1/" is the default. If you want to
log out from a private registry you can specify this by adding the server name.
Log out of a Docker Registry Service located on the specified `SERVER`. You can
specify a URL or a `hostname` for the `SERVER` value. If you do not specify a
`SERVER`, the command attempts to log you out of Docker's public registry
located at `https://registry-1.docker.io/` by default.
# OPTIONS
There are no available options.
# EXAMPLES
## Log out from a local registry
## Log out from a registry on your localhost
# docker logout localhost:8080
@@ -28,3 +29,4 @@ There are no available options.
# HISTORY
June 2014, Originally compiled by Daniel, Dao Quang Minh (daniel at nitrous dot io)
July 2014, updated by Sven Dowideit <SvenDowideit@home.org.au>
April 2015, updated by Mary Anthony for v2 <mary@docker.com>

View File

@@ -2,7 +2,7 @@
% Docker Community
% JUNE 2014
# NAME
docker-pull - Pull an image or a repository from the registry
docker-pull - Pull an image or a repository from a registry
# SYNOPSIS
**docker pull**
@@ -12,10 +12,12 @@ NAME[:TAG]
# DESCRIPTION
This command pulls down an image or a repository from the registry. If
This command pulls down an image or a repository from a registry. If
there is more than one image for a repository (e.g., fedora) then all
images for that repository name are pulled down including any tags.
It is also possible to specify a non-default registry to pull from.
If you do not specify a `REGISTRY_HOST`, the command uses Docker's public
registry located at `registry-1.docker.io` by default.
# OPTIONS
**-a**, **--all-tags**=*true*|*false*
@@ -45,7 +47,7 @@ It is also possible to specify a non-default registry to pull from.
fedora heisenbug 105182bb5e8b 5 days ago 372.7 MB
fedora latest 105182bb5e8b 5 days ago 372.7 MB
# Pull an image, manually specifying path to the registry and tag
# Pull an image, manually specifying path to Docker's public registry and tag
# Note that if the image is previously downloaded then the status would be
# 'Status: Image is up to date for registry.hub.docker.com/fedora:20'
@@ -67,3 +69,5 @@ April 2014, Originally compiled by William Henry (whenry at redhat dot com)
based on docker.com source material and internal work.
June 2014, updated by Sven Dowideit <SvenDowideit@home.org.au>
August 2014, updated by Sven Dowideit <SvenDowideit@home.org.au>
April 2015, updated by John Willis <john.willis@docker.com>
April 2015, updated by Mary Anthony for v2 <mary@docker.com>

View File

@@ -2,18 +2,18 @@
% Docker Community
% JUNE 2014
# NAME
docker-push - Push an image or a repository to the registry
docker-push - Push an image or a repository to a registry
# SYNOPSIS
**docker push**
[**--help**]
NAME[:TAG]
NAME[:TAG] | [REGISTRY_HOST[:REGISTRY_PORT]/]NAME[:TAG]
# DESCRIPTION
Push an image or a repository to a registry. The default registry is the Docker
Hub located at [hub.docker.com](https://hub.docker.com/). However the
image can be pushed to another, perhaps private, registry as demonstrated in
the example below.
This command pushes an image or a repository to a registry. If you do not
specify a `REGISTRY_HOST`, the command uses Docker's public registry located at
`registry-1.docker.io` by default.
# OPTIONS
**--help**
@@ -28,12 +28,10 @@ and then committing it to a new image name:
# docker commit c16378f943fe rhel-httpd
Now push the image to the registry using the image ID. In this example
the registry is on host named registry-host and listening on port 5000.
Default Docker commands will push to the default `hub.docker.com`
registry. Instead, push to the local registry, which is on a host called
registry-host*. To do this, tag the image with the host name or IP
address, and the port of the registry:
Now, push the image to the registry using the image ID. In this example the
registry is on host named `registry-host` and listening on port `5000`. To do
this, tag the image with the host name or IP address, and the port of the
registry:
# docker tag rhel-httpd registry-host:5000/myadmin/rhel-httpd
# docker push registry-host:5000/myadmin/rhel-httpd
@@ -49,3 +47,5 @@ listed.
April 2014, Originally compiled by William Henry (whenry at redhat dot com)
based on docker.com source material and internal work.
June 2014, updated by Sven Dowideit <SvenDowideit@home.org.au>
April 2015, updated by Mary Anthony for v2 <mary@docker.com>

View File

@@ -13,10 +13,9 @@ IMAGE [IMAGE...]
# DESCRIPTION
This will remove one or more images from the host node. This does not
remove images from a registry. You cannot remove an image of a running
container unless you use the **-f** option. To see all images on a host
use the **docker images** command.
Removes one or more images from the host node. This does not remove images from
a registry. You cannot remove an image of a running container unless you use the
**-f** option. To see all images on a host use the **docker images** command.
# OPTIONS
**-f**, **--force**=*true*|*false*
@@ -40,3 +39,4 @@ Here is an example of removing and image:
April 2014, Originally compiled by William Henry (whenry at redhat dot com)
based on docker.com source material and internal work.
June 2014, updated by Sven Dowideit <SvenDowideit@home.org.au>
April 2015, updated by Mary Anthony for v2 <mary@docker.com>

View File

@@ -222,7 +222,7 @@ which interface and port to use.
**--lxc-conf**=[]
(lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"
**--log-driver**="|*json-file*|*none*"
**--log-driver**="|*json-file*|*syslog*|*none*"
Logging driver for container. Default is defined by daemon `--log-driver` flag.
**Warning**: `docker logs` command works only for `json-file` logging driver.

View File

@@ -14,10 +14,9 @@ TERM
# DESCRIPTION
Search an index for an image with that matches the term TERM. The table
of images returned displays the name, description (truncated by default),
number of stars awarded, whether the image is official, and whether it
is automated.
Search Docker Hub for an image with that matches the specified `TERM`. The table
of images returned displays the name, description (truncated by default), number
of stars awarded, whether the image is official, and whether it is automated.
*Note* - Search queries will only return up to 25 results
@@ -36,9 +35,9 @@ is automated.
# EXAMPLES
## Search the registry for ranked images
## Search Docker Hub for ranked images
Search the registry for the term 'fedora' and only display those images
Search a registry for the term 'fedora' and only display those images
ranked 3 or higher:
$ sudo docker search -s 3 fedora
@@ -48,9 +47,9 @@ ranked 3 or higher:
mattdm/fedora-small A small Fedora image on which to build. Co... 8
goldmann/wildfly A WildFly application server running on a ... 3 [OK]
## Search the registry for automated images
## Search Docker Hub for automated images
Search the registry for the term 'fedora' and only display automated images
Search Docker Hub for the term 'fedora' and only display automated images
ranked 1 or higher:
$ sudo docker search -s 1 -t fedora
@@ -62,3 +61,5 @@ ranked 1 or higher:
April 2014, Originally compiled by William Henry (whenry at redhat dot com)
based on docker.com source material and internal work.
June 2014, updated by Sven Dowideit <SvenDowideit@home.org.au>
April 2015, updated by Mary Anthony for v2 <mary@docker.com>

View File

@@ -8,11 +8,14 @@ docker-tag - Tag an image into a repository
**docker tag**
[**-f**|**--force**[=*false*]]
[**--help**]
IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]
IMAGE[:TAG] [REGISTRY_HOST/][USERNAME/]NAME[:TAG]
# DESCRIPTION
This will give a new alias to an image in the repository. This refers to the
entire image name including the optional TAG after the ':'.
Assigns a new alias to an image in a registry. An alias refers to the
entire image name including the optional `TAG` after the ':'.
If you do not specify a `REGISTRY_HOST`, the command uses Docker's public
registry located at `registry-1.docker.io` by default.
# "OPTIONS"
**-f**, **--force**=*true*|*false*
@@ -58,3 +61,5 @@ April 2014, Originally compiled by William Henry (whenry at redhat dot com)
based on docker.com source material and internal work.
June 2014, updated by Sven Dowideit <SvenDowideit@home.org.au>
July 2014, updated by Sven Dowideit <SvenDowideit@home.org.au>
April 2015, updated by Mary Anthony for v2 <mary@docker.com>

View File

@@ -89,7 +89,7 @@ unix://[/path/to/socket] to use.
**--label**="[]"
Set key=value labels to the daemon (displayed in `docker info`)
**--log-driver**="*json-file*|*none*"
**--log-driver**="*json-file*|*syslog*|*none*"
Container's logging driver. Default is `default`.
**Warning**: `docker logs` command works only for `json-file` logging driver.
@@ -172,10 +172,10 @@ inside it)
Load an image from a tar archive
**docker-login(1)**
Register or Login to a Docker registry server
Register or login to a Docker Registry Service
**docker-logout(1)**
Log the user out of a Docker registry server
Log the user out of a Docker Registry Service
**docker-logs(1)**
Fetch the logs of a container
@@ -190,10 +190,10 @@ inside it)
List containers
**docker-pull(1)**
Pull an image or a repository from a Docker registry server
Pull an image or a repository from a Docker Registry Service
**docker-push(1)**
Push an image or a repository to a Docker registry server
Push an image or a repository to a Docker Registry Service
**docker-restart(1)**
Restart a running container

View File

@@ -132,10 +132,19 @@ pages:
- ['swarm/scheduler/filter.md', 'Reference', 'Swarm filters']
- ['swarm/API.md', 'Reference', 'Swarm API']
- ['reference/api/index.md', '**HIDDEN**']
- ['registry/overview.md', 'Reference', 'Docker Registry 2.0']
- ['registry/deploying.md', 'Reference', '&nbsp;&nbsp;&nbsp;&nbsp;&blacksquare;&nbsp; Deploy a registry' ]
- ['registry/configuration.md', 'Reference', '&nbsp;&nbsp;&nbsp;&nbsp;&blacksquare;&nbsp; Configure a registry' ]
- ['registry/storagedrivers.md', 'Reference', '&nbsp;&nbsp;&nbsp;&nbsp;&blacksquare;&nbsp; Storage driver model' ]
- ['registry/notifications.md', 'Reference', '&nbsp;&nbsp;&nbsp;&nbsp;&blacksquare;&nbsp; Work with notifications' ]
- ['registry/spec/api.md', 'Reference', '&nbsp;&nbsp;&nbsp;&nbsp;&blacksquare;&nbsp; Registry Service API v2' ]
- ['registry/spec/json.md', 'Reference', '&nbsp;&nbsp;&nbsp;&nbsp;&blacksquare;&nbsp; JSON format' ]
- ['registry/spec/auth/token.md', 'Reference', '&nbsp;&nbsp;&nbsp;&nbsp;&blacksquare;&nbsp; Authenticate via central service' ]
- ['reference/api/hub_registry_spec.md', 'Reference', 'Docker Hub and Registry 1.0']
- ['reference/api/registry_api.md', 'Reference', '&nbsp;&nbsp;&nbsp;&nbsp;&blacksquare;&nbsp;Docker Registry API v1']
- ['reference/api/registry_api_client_libraries.md', 'Reference', '&nbsp;&nbsp;&nbsp;&nbsp;&blacksquare;&nbsp;Docker Registry 1.0 API Client Libraries']
#- ['reference/image-spec-v1.md', 'Reference', 'Docker Image Specification v1.0.0']
- ['reference/api/docker-io_api.md', 'Reference', 'Docker Hub API']
- ['reference/api/registry_api.md', 'Reference', 'Docker Registry API']
- ['reference/api/registry_api_client_libraries.md', 'Reference', 'Docker Registry API Client Libraries']
- ['reference/api/hub_registry_spec.md', 'Reference', 'Docker Hub and Registry Spec']
#- ['reference/image-spec-v1.md', 'Reference', 'Docker Image Specification v1.0.0']
- ['reference/api/docker_remote_api.md', 'Reference', 'Docker Remote API']
- ['reference/api/docker_remote_api_v1.18.md', 'Reference', 'Docker Remote API v1.18']

View File

@@ -22,10 +22,17 @@ EOF
}
create_robots_txt() {
cat > ./sources/robots.txt <<'EOF'
User-agent: *
Disallow: /
EOF
if [ "$AWS_S3_BUCKET" == "docs.docker.com" ]; then
cat > ./sources/robots.txt <<-'EOF'
User-agent: *
Allow: /
EOF
else
cat > ./sources/robots.txt <<-'EOF'
User-agent: *
Disallow: /
EOF
fi
}
setup_s3() {

View File

@@ -39,7 +39,8 @@
{ "Condition": { "KeyPrefixEquals": "installation/openSUSE/" }, "Redirect": { "HostName": "$BUCKET", "ReplaceKeyPrefixWith": "installation/SUSE/" } },
{ "Condition": { "KeyPrefixEquals": "contributing/contributing/" }, "Redirect": { "HostName": "$BUCKET", "ReplaceKeyPrefixWith": "project/who-written-for/" } },
{ "Condition": { "KeyPrefixEquals": "contributing/devenvironment/" }, "Redirect": { "HostName": "$BUCKET", "ReplaceKeyPrefixWith": "project/set-up-prereqs/" } },
{ "Condition": { "KeyPrefixEquals": "contributing/docs_style-guide/" }, "Redirect": { "HostName": "$BUCKET", "ReplaceKeyPrefixWith": "project/doc-style/" } }
{ "Condition": { "KeyPrefixEquals": "contributing/docs_style-guide/" }, "Redirect": { "HostName": "$BUCKET", "ReplaceKeyPrefixWith": "project/doc-style/" } },
{ "Condition": { "KeyPrefixEquals": "registry/" }, "Redirect": { "HostName": "$BUCKET", "ReplaceKeyPrefixWith": "registry/overview/" } }
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 187 KiB

View File

@@ -8,31 +8,95 @@ page_keywords: Docker, Docker documentation, Windows, requirements, virtualbox,
> Your processor needs to support hardware virtualization.
The Docker Engine uses Linux-specific kernel features, so to run it on Windows
we need to use a lightweight virtual machine (vm). You use the Windows Docker client to
control the virtualized Docker Engine to build, run, and manage Docker containers.
we need to use a lightweight virtual machine (VM). You use the **Windows Docker
Client** to control the virtualized Docker Engine to build, run, and manage
Docker containers.
To make this process easier, we've designed a helper application called
[Boot2Docker](https://github.com/boot2docker/boot2docker) that installs the
virtual machine and runs the Docker daemon.
[Boot2Docker](https://github.com/boot2docker/boot2docker) creates a Linux virtual
machine on Windows to run Docker on a Linux operating system.
Although you will be using Windows Docker client, the docker engine hosting the
containers will still be running on Linux. Until the Docker engine for Windows
is developed, you can launch only Linux containers from your Windows machine.
## Demonstration
<iframe width="640" height="480" src="//www.youtube.com/embed/oSHN8_uiZd4?rel=0" frameborder="0" allowfullscreen></iframe>
<iframe width="640" height="480" src="//www.youtube.com/embed/TjMU3bDX4vo?rel=0" frameborder="0" allowfullscreen></iframe>
## Installation
1. Download the latest release of the [Docker for Windows Installer](https://github.com/boot2docker/windows-installer/releases/latest)
2. Run the installer, which will install VirtualBox, MSYS-git, the boot2docker Linux ISO,
and the Boot2Docker management tool.
1. Download the latest release of the
[Docker for Windows Installer](https://github.com/boot2docker/windows-installer/releases/latest).
2. Run the installer, which will install Docker Client or Windows, VirtualBox,
Git for Windows (MSYS-git), the boot2docker Linux ISO, and the Boot2Docker
management tool.
![](/installation/images/windows-installer.png)
3. Run the `Boot2Docker Start` shell script from your Desktop or Program Files > Boot2Docker for Windows.
3. Run the **Boot2Docker Start** shortcut from your Desktop or Program Files
Boot2Docker for Windows”.
The Start script will ask you to enter an ssh key passphrase - the simplest
(but least secure) is to just hit [Enter].
![](/installation/images/windows-boot2docker-start.png)
4. The **Boot2Docker Start** will start a unix shell already configured to manage
Docker running inside the virtual machine. Run `docker version` to see
if it is working correctly:
The `Boot2Docker Start` script will connect you to a shell session in the virtual
machine. If needed, it will initialize a new VM and start it.
![](/installation/images/windows-boot2docker-start.png)
## Running Docker
{{ include "no-remote-sudo.md" }}
**Boot2Docker Start** will automatically start a shell with environment variables
correctly set so you can start using Docker right away:
Let's try the `hello-world` example image. Run
$ docker run hello-world
This should download the very small `hello-world` image and print a
`Hello from Docker.` message.
## Using docker from Windows Command Line Prompt (cmd.exe)
Launch a Windows Command Line Prompt (cmd.exe).
Boot2Docker command requires `ssh.exe` to be in the PATH, therefore we need to
include `bin` folder of the Git installation (which has ssh.exe) to the `%PATH%`
environment variable by running:
set PATH=%PATH%;"c:\Program Files (x86)\Git\bin"
and then we can run the `boot2docker start` command to start the Boot2Docker VM.
(Run `boot2docker init` command if you get an error saying machine does not
exist.) Then copy the instructions for cmd.exe to set the environment variables
to your console window and you are ready to run docker commands such as
`docker ps`:
![](/installation/images/windows-boot2docker-cmd.png)
## Using docker from PowerShell
Launch a PowerShell window, then you need to add `ssh.exe` to your PATH:
$Env:Path = "${Env:Path};c:\Program Files (x86)\Git\bin"
and after running `boot2docker start` command it will print PowerShell commands
to set the environment variables to connect Docker running inside VM. Run these
commands and you are ready to run docker commands such as `docker ps`:
![](/installation/images/windows-boot2docker-powershell.png)
> NOTE: You can alternatively run `boot2docker shellinit | Invoke-Expression`
> command to set the environment variables instead of copying and pasting on
> PowerShell.
# Further Details
The Boot2Docker management tool provides several commands:
$ boot2docker
Usage: boot2docker.exe [<options>] {help|init|up|ssh|save|down|poweroff|reset|restart|config|status|info|ip|shellinit|delete|download|upgrade|version} [<args>]
## Upgrading
@@ -47,46 +111,13 @@ and the Boot2Docker management tool.
boot2docker download
boot2docker start
## Running Docker
{{ include "no-remote-sudo.md" }}
Boot2Docker will log you in automatically so you can start using Docker right away.
Let's try the `hello-world` example image. Run
$ docker run hello-world
This should download the very small `hello-world` image and print a `Hello from Docker.` message.
## Login with PUTTY instead of using the CMD
Boot2Docker generates and uses the public/private key pair in your `%HOMEPATH%\.ssh`
directory so to log in you need to use the private key from this same directory.
The private key needs to be converted into the format PuTTY uses.
You can do this with
[puttygen](http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html):
- Open `puttygen.exe` and load ("File"->"Load" menu) the private key from
`%HOMEPATH%\.ssh\id_boot2docker`
- then click: "Save Private Key".
- Then use the saved file to login with PuTTY using `docker@127.0.0.1:2022`.
# Further Details
The Boot2Docker management tool provides several commands:
$ ./boot2docker
Usage: ./boot2docker [<options>] {help|init|up|ssh|save|down|poweroff|reset|restart|config|status|info|ip|delete|download|version} [<args>]
## Container port redirection
If you are curious, the username for the boot2docker default user is `docker` and the password is `tcuser`.
If you are curious, the username for the boot2docker default user is `docker`
and the password is `tcuser`.
The latest version of `boot2docker` sets up a host only network adaptor which provides access to the container's ports.
The latest version of `boot2docker` sets up a host only network adaptor which
provides access to the container's ports.
If you run a container with an exposed port:
@@ -101,3 +132,25 @@ Typically, it is 192.168.59.103, but it could get changed by Virtualbox's DHCP
implementation.
For further information or to report issues, please see the [Boot2Docker site](http://boot2docker.io)
## Login with PUTTY instead of using the CMD
Boot2Docker generates and uses the public/private key pair in your `%USERPROFILE%\.ssh`
directory so to log in you need to use the private key from this same directory.
The private key needs to be converted into the format PuTTY uses.
You can do this with
[puttygen](http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html):
- Open `puttygen.exe` and load ("File"->"Load" menu) the private key from
`%USERPROFILE%\.ssh\id_boot2docker`
- then click: "Save Private Key".
- Then use the saved file to login with PuTTY using `docker@127.0.0.1:2022`.
## References
If you have Docker hosts running and if you don't wish to do a
Boot2Docker installation, you can install the docker.exe using
unofficial Windows package manager Chocolately. For information
on how to do this, see [Docker package on Chocolatey](http://chocolatey.org/packages/docker).

View File

@@ -259,7 +259,7 @@ Json Parameters:
`Ulimits: { "Name": "nofile", "Soft": 1024, "Hard", 2048 }}`
- **LogConfig** - Logging configuration to container, format
`{ "Type": "<driver_name>", "Config": {"key1": "val1"}}
Available types: `json-file`, `none`.
Available types: `json-file`, `syslog`, `none`.
`json-file` logging driver.
- **CgroupParent** - Path to cgroups under which the cgroup for the container will be created. If the path is not absolute, the path is considered to be relative to the cgroups path of the init process. Cgroups will be created if they do not already exist.
@@ -359,7 +359,10 @@ Return low-level information on the container `id`
"MaximumRetryCount": 2,
"Name": "on-failure"
},
"LogConfig": { "Type": "json-file", Config: {} },
"LogConfig": {
"Config": null,
"Type": "json-file"
},
"SecurityOpt": null,
"VolumesFrom": null,
"Ulimits": [{}]

View File

@@ -2,7 +2,7 @@ page_title: Registry Documentation
page_description: Documentation for docker Registry and Registry API
page_keywords: docker, registry, api, hub
# The Docker Hub and the Registry spec
# The Docker Hub and the Registry 1.0 spec
## The three roles
@@ -28,9 +28,9 @@ The Docker Hub is authoritative for that information.
There is only one instance of the Docker Hub, run and
managed by Docker Inc.
### Registry
### Docker Registry 1.0
The registry has the following characteristics:
The 1.0 registry has the following characteristics:
- It stores the images and the graph for a set of repositories
- It does not have user accounts data

View File

@@ -2,11 +2,11 @@ page_title: Registry API
page_description: API Documentation for Docker Registry
page_keywords: API, Docker, index, registry, REST, documentation
# Docker Registry API
# Docker Registry API v1
## Introduction
- This is the REST API for the Docker Registry
- This is the REST API for the Docker Registry 1.0
- It stores the images and the graph for a set of repositories
- It does not have user accounts data
- It has no notion of user accounts or authorization

View File

@@ -2,7 +2,7 @@ page_title: Registry API Client Libraries
page_description: Various client libraries available to use with the Docker registry API
page_keywords: API, Docker, index, registry, REST, documentation, clients, C#, Erlang, Go, Groovy, Java, JavaScript, Perl, PHP, Python, Ruby, Rust, Scala
# Docker Registry API Client Libraries
# Docker Registry 1.0 API Client Libraries
These libraries have not been tested by the Docker maintainers for
compatibility. Please file issues with the library owners. If you find

View File

@@ -146,6 +146,17 @@ The instructions that handle environment variables in the `Dockerfile` are:
`ONBUILD` instructions are **NOT** supported for environment replacement, even
the instructions above.
Environment variable subtitution will use the same value for each variable
throughout the entire command. In other words, in this example:
ENV abc=hello
ENV abc=bye def=$abc
ENV ghi=$abc
will result in `def` having a value of `hello`, not `bye`. However,
`ghi` will have a value of `bye` because it is not part of the same command
that set `abc` to `bye`.
## The `.dockerignore` file
If a file named `.dockerignore` exists in the source repository, then it
@@ -269,8 +280,14 @@ The cache for `RUN` instructions can be invalidated by `ADD` instructions. See
- [Issue 783](https://github.com/docker/docker/issues/783) is about file
permissions problems that can occur when using the AUFS file system. You
might notice it during an attempt to `rm` a file, for example. The issue
describes a workaround.
might notice it during an attempt to `rm` a file, for example.
For systems that have recent aufs version (i.e., `dirperm1` mount option can
be set), docker will attempt to fix the issue automatically by mounting
the layers with `dirperm1` option. More details on `dirperm1` option can be
found at [`aufs` man page](http://aufs.sourceforge.net/aufs3/man.html)
If your system doesnt have support for `dirperm1`, the issue describes a workaround.
## CMD

View File

@@ -657,6 +657,11 @@ this driver.
Default logging driver for Docker. Writes JSON messages to file. `docker logs`
command is available only for this logging driver
## Logging driver: syslog
Syslog logging driver for Docker. Writes log messages to syslog. `docker logs`
command is not available for this logging driver
## Overriding Dockerfile image defaults
When a developer builds an image from a [*Dockerfile*](/reference/builder)

View File

@@ -57,7 +57,14 @@ impact on users. This list will be updated as issues are resolved.
* **Unexpected File Permissions in Containers**
An idiosyncrasy in AUFS prevents permissions from propagating predictably
between upper and lower layers. This can cause issues with accessing private
keys, database instances, etc. For complete information and workarounds see
keys, database instances, etc.
For systems that have recent aufs version (i.e., `dirperm1` mount option can
be set), docker will attempt to fix the issue automatically by mounting
the layers with `dirperm1` option. More details on `dirperm1` option can be
found at [`aufs` man page](http://aufs.sourceforge.net/aufs3/man.html)
For complete information and workarounds see
[Github Issue 783](https://github.com/docker/docker/issues/783).
* **Docker Hub incompatible with Safari 8**

View File

@@ -1,6 +1,8 @@
package graph
import (
"compress/gzip"
"crypto/sha256"
"fmt"
"io"
"io/ioutil"
@@ -13,6 +15,7 @@ import (
"time"
log "github.com/Sirupsen/logrus"
"github.com/docker/distribution/digest"
"github.com/docker/docker/autogen/dockerversion"
"github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/image"
@@ -241,18 +244,27 @@ func (graph *Graph) newTempFile() (*os.File, error) {
return ioutil.TempFile(tmp, "")
}
func bufferToFile(f *os.File, src io.Reader) (int64, error) {
n, err := io.Copy(f, src)
func bufferToFile(f *os.File, src io.Reader) (int64, digest.Digest, error) {
var (
h = sha256.New()
w = gzip.NewWriter(io.MultiWriter(f, h))
)
_, err := io.Copy(w, src)
w.Close()
if err != nil {
return n, err
return 0, "", err
}
if err = f.Sync(); err != nil {
return n, err
return 0, "", err
}
n, err := f.Seek(0, os.SEEK_CUR)
if err != nil {
return 0, "", err
}
if _, err := f.Seek(0, 0); err != nil {
return n, err
return 0, "", err
}
return n, nil
return n, digest.NewDigest("sha256", h), nil
}
// setupInitLayer populates a directory with mountpoints suitable

View File

@@ -1,7 +1,6 @@
package graph
import (
"crypto/sha256"
"encoding/json"
"errors"
"fmt"
@@ -13,7 +12,6 @@ import (
"sync"
log "github.com/Sirupsen/logrus"
"github.com/docker/distribution/digest"
"github.com/docker/docker/engine"
"github.com/docker/docker/image"
"github.com/docker/docker/pkg/common"
@@ -464,12 +462,7 @@ func (s *TagStore) pushV2Image(r *registry.Session, img *image.Image, endpoint *
os.Remove(tf.Name())
}()
h := sha256.New()
size, err := bufferToFile(tf, io.TeeReader(arch, h))
if err != nil {
return "", err
}
dgst := digest.NewDigest("sha256", h)
size, dgst, err := bufferToFile(tf, arch)
// Send the layer
log.Debugf("rendered layer for %s of [%d] size", img.ID, size)

View File

@@ -20,213 +20,230 @@ command_exists() {
command -v "$@" > /dev/null 2>&1
}
case "$(uname -m)" in
*64)
;;
*)
echo >&2 'Error: you are not using a 64bit platform.'
echo >&2 'Docker currently only supports 64bit platforms.'
exit 1
;;
esac
echo_docker_as_nonroot() {
your_user=your-user
[ "$user" != 'root' ] && your_user="$user"
# intentionally mixed spaces and tabs here -- tabs are stripped by "<<-EOF", spaces are kept in the output
cat <<-EOF
if command_exists docker || command_exists lxc-docker; then
echo >&2 'Warning: "docker" or "lxc-docker" command appears to already exist.'
echo >&2 'Please ensure that you do not already have docker installed.'
echo >&2 'You may press Ctrl+C now to abort this process and rectify this situation.'
( set -x; sleep 20 )
fi
If you would like to use Docker as a non-root user, you should now consider
adding your user to the "docker" group with something like:
user="$(id -un 2>/dev/null || true)"
sudo usermod -aG docker $your_user
sh_c='sh -c'
if [ "$user" != 'root' ]; then
if command_exists sudo; then
sh_c='sudo -E sh -c'
elif command_exists su; then
sh_c='su -c'
else
echo >&2 'Error: this installer needs the ability to run commands as root.'
echo >&2 'We are unable to find either "sudo" or "su" available to make this happen.'
exit 1
Remember that you will have to log out and back in for this to take effect!
EOF
}
do_install() {
case "$(uname -m)" in
*64)
;;
*)
cat >&2 <<-'EOF'
Error: you are not using a 64bit platform.
Docker currently only supports 64bit platforms.
EOF
exit 1
;;
esac
if command_exists docker || command_exists lxc-docker; then
cat >&2 <<-'EOF'
Warning: "docker" or "lxc-docker" command appears to already exist.
Please ensure that you do not already have docker installed.
You may press Ctrl+C now to abort this process and rectify this situation.
EOF
( set -x; sleep 20 )
fi
fi
curl=''
if command_exists curl; then
curl='curl -sSL'
elif command_exists wget; then
curl='wget -qO-'
elif command_exists busybox && busybox --list-modules | grep -q wget; then
curl='busybox wget -qO-'
fi
user="$(id -un 2>/dev/null || true)"
# perform some very rudimentary platform detection
lsb_dist=''
if command_exists lsb_release; then
lsb_dist="$(lsb_release -si)"
fi
if [ -z "$lsb_dist" ] && [ -r /etc/lsb-release ]; then
lsb_dist="$(. /etc/lsb-release && echo "$DISTRIB_ID")"
fi
if [ -z "$lsb_dist" ] && [ -r /etc/debian_version ]; then
lsb_dist='debian'
fi
if [ -z "$lsb_dist" ] && [ -r /etc/fedora-release ]; then
lsb_dist='fedora'
fi
if [ -z "$lsb_dist" ] && [ -r /etc/os-release ]; then
lsb_dist="$(. /etc/os-release && echo "$ID")"
fi
lsb_dist="$(echo "$lsb_dist" | tr '[:upper:]' '[:lower:]')"
case "$lsb_dist" in
amzn|fedora)
if [ "$lsb_dist" = 'amzn' ]; then
(
set -x
$sh_c 'sleep 3; yum -y -q install docker'
)
sh_c='sh -c'
if [ "$user" != 'root' ]; then
if command_exists sudo; then
sh_c='sudo -E sh -c'
elif command_exists su; then
sh_c='su -c'
else
(
set -x
$sh_c 'sleep 3; yum -y -q install docker-io'
)
fi
if command_exists docker && [ -e /var/run/docker.sock ]; then
(
set -x
$sh_c 'docker version'
) || true
fi
your_user=your-user
[ "$user" != 'root' ] && your_user="$user"
echo
echo 'If you would like to use Docker as a non-root user, you should now consider'
echo 'adding your user to the "docker" group with something like:'
echo
echo ' sudo usermod -aG docker' $your_user
echo
echo 'Remember that you will have to log out and back in for this to take effect!'
echo
exit 0
;;
ubuntu|debian|linuxmint)
export DEBIAN_FRONTEND=noninteractive
did_apt_get_update=
apt_get_update() {
if [ -z "$did_apt_get_update" ]; then
( set -x; $sh_c 'sleep 3; apt-get update' )
did_apt_get_update=1
fi
}
# aufs is preferred over devicemapper; try to ensure the driver is available.
if ! grep -q aufs /proc/filesystems && ! $sh_c 'modprobe aufs'; then
if uname -r | grep -q -- '-generic' && dpkg -l 'linux-image-*-generic' | grep -q '^ii' 2>/dev/null; then
kern_extras="linux-image-extra-$(uname -r) linux-image-extra-virtual"
apt_get_update
( set -x; $sh_c 'sleep 3; apt-get install -y -q '"$kern_extras" ) || true
if ! grep -q aufs /proc/filesystems && ! $sh_c 'modprobe aufs'; then
echo >&2 'Warning: tried to install '"$kern_extras"' (for AUFS)'
echo >&2 ' but we still have no AUFS. Docker may not work. Proceeding anyways!'
( set -x; sleep 10 )
fi
else
echo >&2 'Warning: current kernel is not supported by the linux-image-extra-virtual'
echo >&2 ' package. We have no AUFS support. Consider installing the packages'
echo >&2 ' linux-image-virtual kernel and linux-image-extra-virtual for AUFS support.'
( set -x; sleep 10 )
fi
fi
# install apparmor utils if they're missing and apparmor is enabled in the kernel
# otherwise Docker will fail to start
if [ "$(cat /sys/module/apparmor/parameters/enabled 2>/dev/null)" = 'Y' ]; then
if command -v apparmor_parser &> /dev/null; then
echo 'apparmor is enabled in the kernel and apparmor utils were already installed'
else
echo 'apparmor is enabled in the kernel, but apparmor_parser missing'
apt_get_update
( set -x; $sh_c 'sleep 3; apt-get install -y -q apparmor' )
fi
fi
if [ ! -e /usr/lib/apt/methods/https ]; then
apt_get_update
( set -x; $sh_c 'sleep 3; apt-get install -y -q apt-transport-https ca-certificates' )
fi
if [ -z "$curl" ]; then
apt_get_update
( set -x; $sh_c 'sleep 3; apt-get install -y -q curl ca-certificates' )
curl='curl -sSL'
fi
(
set -x
if [ "https://get.docker.com/" = "$url" ]; then
$sh_c "apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9"
elif [ "https://test.docker.com/" = "$url" ]; then
$sh_c "apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 740B314AE3941731B942C66ADF4FD13717AAD7D6"
else
$sh_c "$curl ${url}gpg | apt-key add -"
fi
$sh_c "echo deb ${url}ubuntu docker main > /etc/apt/sources.list.d/docker.list"
$sh_c 'sleep 3; apt-get update; apt-get install -y -q lxc-docker'
)
if command_exists docker && [ -e /var/run/docker.sock ]; then
(
set -x
$sh_c 'docker version'
) || true
fi
your_user=your-user
[ "$user" != 'root' ] && your_user="$user"
echo
echo 'If you would like to use Docker as a non-root user, you should now consider'
echo 'adding your user to the "docker" group with something like:'
echo
echo ' sudo usermod -aG docker' $your_user
echo
echo 'Remember that you will have to log out and back in for this to take effect!'
echo
exit 0
;;
gentoo)
if [ "$url" = "https://test.docker.com/" ]; then
echo >&2
echo >&2 ' You appear to be trying to install the latest nightly build in Gentoo.'
echo >&2 ' The portage tree should contain the latest stable release of Docker, but'
echo >&2 ' if you want something more recent, you can always use the live ebuild'
echo >&2 ' provided in the "docker" overlay available via layman. For more'
echo >&2 ' instructions, please see the following URL:'
echo >&2 ' https://github.com/tianon/docker-overlay#using-this-overlay'
echo >&2 ' After adding the "docker" overlay, you should be able to:'
echo >&2 ' emerge -av =app-emulation/docker-9999'
echo >&2
cat >&2 <<-'EOF'
Error: this installer needs the ability to run commands as root.
We are unable to find either "sudo" or "su" available to make this happen.
EOF
exit 1
fi
fi
(
set -x
$sh_c 'sleep 3; emerge app-emulation/docker'
)
exit 0
;;
esac
curl=''
if command_exists curl; then
curl='curl -sSL'
elif command_exists wget; then
curl='wget -qO-'
elif command_exists busybox && busybox --list-modules | grep -q wget; then
curl='busybox wget -qO-'
fi
cat >&2 <<'EOF'
# perform some very rudimentary platform detection
lsb_dist=''
if command_exists lsb_release; then
lsb_dist="$(lsb_release -si)"
fi
if [ -z "$lsb_dist" ] && [ -r /etc/lsb-release ]; then
lsb_dist="$(. /etc/lsb-release && echo "$DISTRIB_ID")"
fi
if [ -z "$lsb_dist" ] && [ -r /etc/debian_version ]; then
lsb_dist='debian'
fi
if [ -z "$lsb_dist" ] && [ -r /etc/fedora-release ]; then
lsb_dist='fedora'
fi
if [ -z "$lsb_dist" ] && [ -r /etc/os-release ]; then
lsb_dist="$(. /etc/os-release && echo "$ID")"
fi
Either your platform is not easily detectable, is not supported by this
installer script (yet - PRs welcome! [hack/install.sh]), or does not yet have
a package for Docker. Please visit the following URL for more detailed
installation instructions:
lsb_dist="$(echo "$lsb_dist" | tr '[:upper:]' '[:lower:]')"
case "$lsb_dist" in
amzn|fedora|centos)
if [ "$lsb_dist" = 'amzn' ]; then
(
set -x
$sh_c 'sleep 3; yum -y -q install docker'
)
else
(
set -x
$sh_c 'sleep 3; yum -y -q install docker-io'
)
fi
if command_exists docker && [ -e /var/run/docker.sock ]; then
(
set -x
$sh_c 'docker version'
) || true
fi
echo_docker_as_nonroot
exit 0
;;
https://docs.docker.com/en/latest/installation/
ubuntu|debian|linuxmint)
export DEBIAN_FRONTEND=noninteractive
EOF
exit 1
did_apt_get_update=
apt_get_update() {
if [ -z "$did_apt_get_update" ]; then
( set -x; $sh_c 'sleep 3; apt-get update' )
did_apt_get_update=1
fi
}
# aufs is preferred over devicemapper; try to ensure the driver is available.
if ! grep -q aufs /proc/filesystems && ! $sh_c 'modprobe aufs'; then
if uname -r | grep -q -- '-generic' && dpkg -l 'linux-image-*-generic' | grep -q '^ii' 2>/dev/null; then
kern_extras="linux-image-extra-$(uname -r) linux-image-extra-virtual"
apt_get_update
( set -x; $sh_c 'sleep 3; apt-get install -y -q '"$kern_extras" ) || true
if ! grep -q aufs /proc/filesystems && ! $sh_c 'modprobe aufs'; then
echo >&2 'Warning: tried to install '"$kern_extras"' (for AUFS)'
echo >&2 ' but we still have no AUFS. Docker may not work. Proceeding anyways!'
( set -x; sleep 10 )
fi
else
echo >&2 'Warning: current kernel is not supported by the linux-image-extra-virtual'
echo >&2 ' package. We have no AUFS support. Consider installing the packages'
echo >&2 ' linux-image-virtual kernel and linux-image-extra-virtual for AUFS support.'
( set -x; sleep 10 )
fi
fi
# install apparmor utils if they're missing and apparmor is enabled in the kernel
# otherwise Docker will fail to start
if [ "$(cat /sys/module/apparmor/parameters/enabled 2>/dev/null)" = 'Y' ]; then
if command -v apparmor_parser &> /dev/null; then
echo 'apparmor is enabled in the kernel and apparmor utils were already installed'
else
echo 'apparmor is enabled in the kernel, but apparmor_parser missing'
apt_get_update
( set -x; $sh_c 'sleep 3; apt-get install -y -q apparmor' )
fi
fi
if [ ! -e /usr/lib/apt/methods/https ]; then
apt_get_update
( set -x; $sh_c 'sleep 3; apt-get install -y -q apt-transport-https ca-certificates' )
fi
if [ -z "$curl" ]; then
apt_get_update
( set -x; $sh_c 'sleep 3; apt-get install -y -q curl ca-certificates' )
curl='curl -sSL'
fi
(
set -x
if [ "https://get.docker.com/" = "$url" ]; then
$sh_c "apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9"
elif [ "https://test.docker.com/" = "$url" ]; then
$sh_c "apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 740B314AE3941731B942C66ADF4FD13717AAD7D6"
else
$sh_c "$curl ${url}gpg | apt-key add -"
fi
$sh_c "echo deb ${url}ubuntu docker main > /etc/apt/sources.list.d/docker.list"
$sh_c 'sleep 3; apt-get update; apt-get install -y -q lxc-docker'
)
if command_exists docker && [ -e /var/run/docker.sock ]; then
(
set -x
$sh_c 'docker version'
) || true
fi
echo_docker_as_nonroot
exit 0
;;
gentoo)
if [ "$url" = "https://test.docker.com/" ]; then
# intentionally mixed spaces and tabs here -- tabs are stripped by "<<-'EOF'", spaces are kept in the output
cat >&2 <<-'EOF'
You appear to be trying to install the latest nightly build in Gentoo.'
The portage tree should contain the latest stable release of Docker, but'
if you want something more recent, you can always use the live ebuild'
provided in the "docker" overlay available via layman. For more'
instructions, please see the following URL:'
https://github.com/tianon/docker-overlay#using-this-overlay'
After adding the "docker" overlay, you should be able to:'
emerge -av =app-emulation/docker-9999'
EOF
exit 1
fi
(
set -x
$sh_c 'sleep 3; emerge app-emulation/docker'
)
exit 0
;;
esac
# intentionally mixed spaces and tabs here -- tabs are stripped by "<<-'EOF'", spaces are kept in the output
cat >&2 <<-'EOF'
Either your platform is not easily detectable, is not supported by this
installer script (yet - PRs welcome! [hack/install.sh]), or does not yet have
a package for Docker. Please visit the following URL for more detailed
installation instructions:
https://docs.docker.com/en/latest/installation/
EOF
exit 1
}
# wrapped up in a function so that we have some protection against only getting
# half the file during "curl | sh"
do_install

View File

@@ -265,9 +265,6 @@ main() {
bundle $SCRIPTDIR/make/$bundle
echo
done
# if we get all the way through successfully, let's delete our autogenerated code!
rm -r autogen
}
main "$@"

View File

@@ -75,7 +75,7 @@ rm -rf src/github.com/docker/distribution
mkdir -p src/github.com/docker/distribution
mv tmp-digest src/github.com/docker/distribution/digest
clone git github.com/docker/libcontainer 4a72e540feb67091156b907c4700e580a99f5a9d
clone git github.com/docker/libcontainer 227771c8f611f03639f0eeb169428761d9504ab5
# see src/github.com/docker/libcontainer/update-vendor.sh which is the "source of truth" for libcontainer deps (just like this file)
rm -rf src/github.com/docker/libcontainer/vendor
eval "$(grep '^clone ' src/github.com/docker/libcontainer/update-vendor.sh | grep -v 'github.com/codegangsta/cli' | grep -v 'github.com/Sirupsen/logrus')"

View File

@@ -516,3 +516,40 @@ func TestBuildApiDockerfileSymlink(t *testing.T) {
logDone("container REST API - check build w/bad Dockerfile symlink path")
}
// #9981 - Allow a docker created volume (ie, one in /var/lib/docker/volumes) to be used to overwrite (via passing in Binds on api start) an existing volume
func TestPostContainerBindNormalVolume(t *testing.T) {
defer deleteAllContainers()
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "create", "-v", "/foo", "--name=one", "busybox"))
if err != nil {
t.Fatal(err, out)
}
fooDir, err := inspectFieldMap("one", "Volumes", "/foo")
if err != nil {
t.Fatal(err)
}
out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "create", "-v", "/foo", "--name=two", "busybox"))
if err != nil {
t.Fatal(err, out)
}
bindSpec := map[string][]string{"Binds": {fooDir + ":/foo"}}
_, err = sockRequest("POST", "/containers/two/start", bindSpec)
if err != nil && !strings.Contains(err.Error(), "204 No Content") {
t.Fatal(err)
}
fooDir2, err := inspectFieldMap("two", "Volumes", "/foo")
if err != nil {
t.Fatal(err)
}
if fooDir2 != fooDir {
t.Fatal("expected volume path to be %s, got: %s", fooDir, fooDir2)
}
logDone("container REST API - can use path from normal volume as bind-mount to overwrite another volume")
}

View File

@@ -241,9 +241,18 @@ func TestBuildEnvironmentReplacementEnv(t *testing.T) {
_, err := buildImage(name,
`
FROM scratch
ENV foo foo
FROM busybox
ENV foo zzz
ENV bar ${foo}
ENV abc1='$foo'
ENV env1=$foo env2=${foo} env3="$foo" env4="${foo}"
RUN [ "$abc1" = '$foo' ] && (echo "$abc1" | grep -q foo)
ENV abc2="\$foo"
RUN [ "$abc2" = '$foo' ] && (echo "$abc2" | grep -q foo)
ENV abc3 '$foo'
RUN [ "$abc3" = '$foo' ] && (echo "$abc3" | grep -q foo)
ENV abc4 "\$foo"
RUN [ "$abc4" = '$foo' ] && (echo "$abc4" | grep -q foo)
`, true)
if err != nil {
@@ -262,13 +271,19 @@ func TestBuildEnvironmentReplacementEnv(t *testing.T) {
}
found := false
envCount := 0
for _, env := range envResult {
parts := strings.SplitN(env, "=", 2)
if parts[0] == "bar" {
found = true
if parts[1] != "foo" {
t.Fatalf("Could not find replaced var for env `bar`: got %q instead of `foo`", parts[1])
if parts[1] != "zzz" {
t.Fatalf("Could not find replaced var for env `bar`: got %q instead of `zzz`", parts[1])
}
} else if strings.HasPrefix(parts[0], "env") {
envCount++
if parts[1] != "zzz" {
t.Fatalf("%s should be 'foo' but instead its %q", parts[0], parts[1])
}
}
}
@@ -277,6 +292,10 @@ func TestBuildEnvironmentReplacementEnv(t *testing.T) {
t.Fatal("Never found the `bar` env variable")
}
if envCount != 4 {
t.Fatalf("Didn't find all env vars - only saw %d\n%s", envCount, envResult)
}
logDone("build - env environment replacement")
}
@@ -363,8 +382,8 @@ func TestBuildHandleEscapes(t *testing.T) {
t.Fatal(err)
}
if _, ok := result[`\\\\\\${FOO}`]; !ok {
t.Fatal(`Could not find volume \\\\\\${FOO} set from env foo in volumes table`)
if _, ok := result[`\\\${FOO}`]; !ok {
t.Fatal(`Could not find volume \\\${FOO} set from env foo in volumes table`, result)
}
logDone("build - handle escapes")
@@ -1939,6 +1958,7 @@ func TestBuildCancelationKillsSleep(t *testing.T) {
name := "testbuildcancelation"
defer deleteImages(name)
defer deleteAllContainers()
// (Note: one year, will never finish)
ctx, err := fakeContext("FROM busybox\nRUN sleep 31536000", nil)
@@ -2256,7 +2276,7 @@ func TestBuildRelativeWorkdir(t *testing.T) {
func TestBuildWorkdirWithEnvVariables(t *testing.T) {
name := "testbuildworkdirwithenvvariables"
expected := "/test1/test2/$MISSING_VAR"
expected := "/test1/test2"
defer deleteImages(name)
_, err := buildImage(name,
`FROM busybox
@@ -4025,9 +4045,9 @@ ENV abc=zzz TO=/docker/world/hello
ADD $FROM $TO
RUN [ "$(cat $TO)" = "hello" ]
ENV abc "zzz"
RUN [ $abc = \"zzz\" ]
RUN [ $abc = "zzz" ]
ENV abc 'yyy'
RUN [ $abc = \'yyy\' ]
RUN [ $abc = 'yyy' ]
ENV abc=
RUN [ "$abc" = "" ]
@@ -4043,13 +4063,34 @@ RUN [ "$abc" = "'foo'" ]
ENV abc=\"foo\"
RUN [ "$abc" = "\"foo\"" ]
ENV abc "foo"
RUN [ "$abc" = "\"foo\"" ]
RUN [ "$abc" = "foo" ]
ENV abc 'foo'
RUN [ "$abc" = "'foo'" ]
RUN [ "$abc" = 'foo' ]
ENV abc \'foo\'
RUN [ "$abc" = "\\'foo\\'" ]
RUN [ "$abc" = "'foo'" ]
ENV abc \"foo\"
RUN [ "$abc" = "\\\"foo\\\"" ]
RUN [ "$abc" = '"foo"' ]
ENV e1=bar
ENV e2=$e1
ENV e3=$e11
ENV e4=\$e1
ENV e5=\$e11
RUN [ "$e0,$e1,$e2,$e3,$e4,$e5" = ',bar,bar,,$e1,$e11' ]
ENV ee1 bar
ENV ee2 $ee1
ENV ee3 $ee11
ENV ee4 \$ee1
ENV ee5 \$ee11
RUN [ "$ee1,$ee2,$ee3,$ee4,$ee5" = 'bar,bar,,$ee1,$ee11' ]
ENV eee1="foo"
ENV eee2='foo'
ENV eee3 "foo"
ENV eee4 'foo'
RUN [ "$eee1,$eee2,$eee3,$eee4" = 'foo,foo,foo,foo' ]
`
ctx, err := fakeContext(dockerfile, map[string]string{
"hello/docker/world": "hello",

View File

@@ -55,8 +55,6 @@ func TestPullImageWithAliases(t *testing.T) {
// pulling library/hello-world should show verified message
func TestPullVerified(t *testing.T) {
t.Skip("problems verifying library/hello-world (to be fixed)")
// Image must be pulled from central repository to get verified message
// unless keychain is manually updated to contain the daemon's sign key.

View File

@@ -413,6 +413,7 @@ func TestRunLinkToContainerNetMode(t *testing.T) {
}
func TestRunModeNetContainerHostname(t *testing.T) {
testRequires(t, ExecSupport)
defer deleteAllContainers()
cmd := exec.Command(dockerBinary, "run", "-i", "-d", "--name", "parent", "busybox", "top")
out, _, err := runCommandWithOutput(cmd)
@@ -475,6 +476,39 @@ func TestRunWithVolumesFromExited(t *testing.T) {
logDone("run - regression test for #4979 - volumes-from on exited container")
}
// Volume path is a symlink which also exists on the host, and the host side is a file not a dir
// But the volume call is just a normal volume, not a bind mount
func TestRunCreateVolumesInSymlinkDir(t *testing.T) {
testRequires(t, SameHostDaemon)
testRequires(t, NativeExecDriver)
defer deleteAllContainers()
name := "test-volume-symlink"
dir, err := ioutil.TempDir("", name)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
f, err := os.OpenFile(filepath.Join(dir, "test"), os.O_CREATE, 0700)
if err != nil {
t.Fatal(err)
}
f.Close()
dockerFile := fmt.Sprintf("FROM busybox\nRUN mkdir -p %s\nRUN ln -s %s /test", dir, dir)
if _, err := buildImage(name, dockerFile, false); err != nil {
t.Fatal(err)
}
defer deleteImages(name)
if out, _, err := dockerCmd(t, "run", "-v", "/test/test", name); err != nil {
t.Fatal(err, out)
}
logDone("run - create volume in symlink directory")
}
// Regression test for #4830
func TestRunWithRelativePath(t *testing.T) {
defer deleteAllContainers()
@@ -3203,6 +3237,35 @@ func TestRunNetHost(t *testing.T) {
logDone("run - net host mode")
}
func TestRunNetContainerWhichHost(t *testing.T) {
testRequires(t, SameHostDaemon)
defer deleteAllContainers()
hostNet, err := os.Readlink("/proc/1/ns/net")
if err != nil {
t.Fatal(err)
}
cmd := exec.Command(dockerBinary, "run", "-d", "--net=host", "--name=test", "busybox", "top")
out, _, err := runCommandWithOutput(cmd)
if err != nil {
t.Fatal(err, out)
}
cmd = exec.Command(dockerBinary, "run", "--net=container:test", "busybox", "readlink", "/proc/self/ns/net")
out, _, err = runCommandWithOutput(cmd)
if err != nil {
t.Fatal(err, out)
}
out = strings.Trim(out, "\n")
if hostNet != out {
t.Fatalf("Container should have host network namespace")
}
logDone("run - net container mode, where container in host mode")
}
func TestRunAllowPortRangeThroughPublish(t *testing.T) {
defer deleteAllContainers()
@@ -3348,3 +3411,97 @@ func TestRunVolumesFromRestartAfterRemoved(t *testing.T) {
logDone("run - can restart a volumes-from container after producer is removed")
}
func TestRunPidHostWithChildIsKillable(t *testing.T) {
defer deleteAllContainers()
name := "ibuildthecloud"
if out, err := exec.Command(dockerBinary, "run", "-d", "--pid=host", "--name", name, "busybox", "sh", "-c", "sleep 30; echo hi").CombinedOutput(); err != nil {
t.Fatal(err, out)
}
time.Sleep(1 * time.Second)
errchan := make(chan error)
go func() {
if out, err := exec.Command(dockerBinary, "kill", name).CombinedOutput(); err != nil {
errchan <- fmt.Errorf("%v:\n%s", err, out)
}
close(errchan)
}()
select {
case err := <-errchan:
if err != nil {
t.Fatal(err)
}
case <-time.After(5 * time.Second):
t.Fatal("Kill container timed out")
}
logDone("run - can kill container with pid-host and some childs of pid 1")
}
func TestRunWithTooSmallMemoryLimit(t *testing.T) {
defer deleteAllContainers()
// this memory limit is 1 byte less than the min, which is 4MB
// https://github.com/docker/docker/blob/v1.5.0/daemon/create.go#L22
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-m", "4194303", "busybox"))
if err == nil || !strings.Contains(out, "Minimum memory limit allowed is 4MB") {
t.Fatalf("expected run to fail when using too low a memory limit: %q", out)
}
logDone("run - can't set too low memory limit")
}
func TestRunWriteToProcAsound(t *testing.T) {
defer deleteAllContainers()
code, err := runCommand(exec.Command(dockerBinary, "run", "busybox", "sh", "-c", "echo 111 >> /proc/asound/version"))
if err == nil || code == 0 {
t.Fatal("standard container should not be able to write to /proc/asound")
}
logDone("run - ro write to /proc/asound")
}
func TestRunReadProcTimer(t *testing.T) {
defer deleteAllContainers()
out, code, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "busybox", "cat", "/proc/timer_stats"))
if err != nil || code != 0 {
t.Fatal(err)
}
if strings.Trim(out, "\n ") != "" {
t.Fatalf("expected to receive no output from /proc/timer_stats but received %q", out)
}
logDone("run - read /proc/timer_stats")
}
func TestRunReadProcLatency(t *testing.T) {
// some kernels don't have this configured so skip the test if this file is not found
// on the host running the tests.
if _, err := os.Stat("/proc/latency_stats"); err != nil {
t.Skip()
return
}
defer deleteAllContainers()
out, code, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "busybox", "cat", "/proc/latency_stats"))
if err != nil || code != 0 {
t.Fatal(err)
}
if strings.Trim(out, "\n ") != "" {
t.Fatalf("expected to receive no output from /proc/latency_stats but received %q", out)
}
logDone("run - read /proc/latency_stats")
}
func TestMountIntoProc(t *testing.T) {
defer deleteAllContainers()
code, err := runCommand(exec.Command(dockerBinary, "run", "-v", "/proc//sys", "busybox", "true"))
if err == nil || code == 0 {
t.Fatal("container should not be able to mount into /proc")
}
logDone("run - mount into proc")
}
func TestMountIntoSys(t *testing.T) {
defer deleteAllContainers()
_, err := runCommand(exec.Command(dockerBinary, "run", "-v", "/sys/fs/cgroup", "busybox", "true"))
if err != nil {
t.Fatal("container should be able to mount into /sys")
}
logDone("run - mount into sys")
}

View File

@@ -240,3 +240,49 @@ func TestStartMultipleContainers(t *testing.T) {
logDone("start - start multiple containers continue on one failed")
}
func TestStartAttachMultipleContainers(t *testing.T) {
var cmd *exec.Cmd
defer deleteAllContainers()
// run multiple containers to test
for _, container := range []string{"test1", "test2", "test3"} {
cmd = exec.Command(dockerBinary, "run", "-d", "--name", container, "busybox", "top")
if out, _, err := runCommandWithOutput(cmd); err != nil {
t.Fatal(out, err)
}
}
// stop all the containers
for _, container := range []string{"test1", "test2", "test3"} {
cmd = exec.Command(dockerBinary, "stop", container)
if out, _, err := runCommandWithOutput(cmd); err != nil {
t.Fatal(out, err)
}
}
// test start and attach multiple containers at once, expected error
for _, option := range []string{"-a", "-i", "-ai"} {
cmd = exec.Command(dockerBinary, "start", option, "test1", "test2", "test3")
out, _, err := runCommandWithOutput(cmd)
if !strings.Contains(out, "You cannot start and attach multiple containers at once.") || err == nil {
t.Fatal("Expected error but got none")
}
}
// confirm the state of all the containers be stopped
for container, expected := range map[string]string{"test1": "false", "test2": "false", "test3": "false"} {
cmd = exec.Command(dockerBinary, "inspect", "-f", "{{.State.Running}}", container)
out, _, err := runCommandWithOutput(cmd)
if err != nil {
t.Fatal(out, err)
}
out = strings.Trim(out, "\r\n")
if out != expected {
t.Fatal("Container running state wrong")
}
}
logDone("start - error on start and attach multiple containers at once")
}

View File

@@ -17,11 +17,13 @@ var (
privateRegistryURL = "127.0.0.1:5000"
dockerBasePath = "/var/lib/docker"
execDriverPath = dockerBasePath + "/execdriver/native"
volumesConfigPath = dockerBasePath + "/volumes"
volumesStoragePath = dockerBasePath + "/vfs/dir"
containerStoragePath = dockerBasePath + "/containers"
runtimePath = "/var/run/docker"
execDriverPath = runtimePath + "/execdriver/native"
workingDirectory string
)

View File

@@ -6,6 +6,6 @@ const (
// identifies if test suite is running on a unix platform
isUnixCli = false
// this is the expected file permission set on windows: gh#11047
expectedFileChmod = "-rwx------"
// this is the expected file permission set on windows: gh#11395
expectedFileChmod = "-rwxr-xr-x"
)

View File

@@ -28,10 +28,9 @@ func CanonicalTarNameForPath(p string) (string, error) {
// chmodTarEntry is used to adjust the file permissions used in tar header based
// on the platform the archival is done.
func chmodTarEntry(perm os.FileMode) os.FileMode {
// Clear r/w on grp/others: no precise equivalen of group/others on NTFS.
perm &= 0711
perm &= 0755
// Add the x bit: make everything +x from windows
perm |= 0100
perm |= 0111
return perm
}

View File

@@ -51,11 +51,11 @@ func TestChmodTarEntry(t *testing.T) {
cases := []struct {
in, expected os.FileMode
}{
{0000, 0100},
{0777, 0711},
{0644, 0700},
{0755, 0711},
{0444, 0500},
{0000, 0111},
{0777, 0755},
{0644, 0755},
{0755, 0755},
{0444, 0555},
}
for _, v := range cases {
if out := chmodTarEntry(v.in); out != v.expected {

View File

@@ -220,8 +220,8 @@ func (info *FileInfo) addChanges(oldInfo *FileInfo, changes *[]Change) {
oldStat.Gid() != newStat.Gid() ||
oldStat.Rdev() != newStat.Rdev() ||
// Don't look at size for dirs, its not a good measure of change
(oldStat.Size() != newStat.Size() && oldStat.Mode()&syscall.S_IFDIR != syscall.S_IFDIR) ||
!sameFsTimeSpec(oldStat.Mtim(), newStat.Mtim()) ||
(oldStat.Mode()&syscall.S_IFDIR != syscall.S_IFDIR &&
(!sameFsTimeSpec(oldStat.Mtim(), newStat.Mtim()) || (oldStat.Size() != newStat.Size()))) ||
bytes.Compare(oldChild.capability, newChild.capability) != 0 {
change := Change{
Path: newChild.path(),

View File

@@ -218,7 +218,6 @@ func TestChangesDirsMutated(t *testing.T) {
expectedChanges := []Change{
{"/dir1", ChangeDelete},
{"/dir2", ChangeModify},
{"/dir3", ChangeModify},
{"/dirnew", ChangeAdd},
{"/file1", ChangeDelete},
{"/file2", ChangeModify},

View File

@@ -51,7 +51,7 @@ func (w *BroadcastWriter) Write(p []byte) (n int, err error) {
for {
line, err := w.buf.ReadString('\n')
if err != nil {
w.buf.Write([]byte(line))
w.buf.WriteString(line)
break
}
for stream, writers := range w.streams {

View File

@@ -2,8 +2,11 @@ package ioutils
import (
"bytes"
"crypto/rand"
"io"
"math/big"
"sync"
"time"
)
type readCloserWrapper struct {
@@ -42,20 +45,40 @@ func NewReaderErrWrapper(r io.Reader, closer func()) io.Reader {
}
}
// bufReader allows the underlying reader to continue to produce
// output by pre-emptively reading from the wrapped reader.
// This is achieved by buffering this data in bufReader's
// expanding buffer.
type bufReader struct {
sync.Mutex
buf *bytes.Buffer
reader io.Reader
err error
wait sync.Cond
drainBuf []byte
buf *bytes.Buffer
reader io.Reader
err error
wait sync.Cond
drainBuf []byte
reuseBuf []byte
maxReuse int64
resetTimeout time.Duration
bufLenResetThreshold int64
maxReadDataReset int64
}
func NewBufReader(r io.Reader) *bufReader {
var timeout int
if randVal, err := rand.Int(rand.Reader, big.NewInt(120)); err == nil {
timeout = int(randVal.Int64()) + 180
} else {
timeout = 300
}
reader := &bufReader{
buf: &bytes.Buffer{},
drainBuf: make([]byte, 1024),
reader: r,
buf: &bytes.Buffer{},
drainBuf: make([]byte, 1024),
reuseBuf: make([]byte, 4096),
maxReuse: 1000,
resetTimeout: time.Second * time.Duration(timeout),
bufLenResetThreshold: 100 * 1024,
maxReadDataReset: 10 * 1024 * 1024,
reader: r,
}
reader.wait.L = &reader.Mutex
go reader.drain()
@@ -74,14 +97,94 @@ func NewBufReaderWithDrainbufAndBuffer(r io.Reader, drainBuffer []byte, buffer *
}
func (r *bufReader) drain() {
var (
duration time.Duration
lastReset time.Time
now time.Time
reset bool
bufLen int64
dataSinceReset int64
maxBufLen int64
reuseBufLen int64
reuseCount int64
)
reuseBufLen = int64(len(r.reuseBuf))
lastReset = time.Now()
for {
n, err := r.reader.Read(r.drainBuf)
dataSinceReset += int64(n)
r.Lock()
bufLen = int64(r.buf.Len())
if bufLen > maxBufLen {
maxBufLen = bufLen
}
// Avoid unbounded growth of the buffer over time.
// This has been discovered to be the only non-intrusive
// solution to the unbounded growth of the buffer.
// Alternative solutions such as compression, multiple
// buffers, channels and other similar pieces of code
// were reducing throughput, overall Docker performance
// or simply crashed Docker.
// This solution releases the buffer when specific
// conditions are met to avoid the continuous resizing
// of the buffer for long lived containers.
//
// Move data to the front of the buffer if it's
// smaller than what reuseBuf can store
if bufLen > 0 && reuseBufLen >= bufLen {
n, _ := r.buf.Read(r.reuseBuf)
r.buf.Write(r.reuseBuf[0:n])
// Take action if the buffer has been reused too many
// times and if there's data in the buffer.
// The timeout is also used as means to avoid doing
// these operations more often or less often than
// required.
// The various conditions try to detect heavy activity
// in the buffer which might be indicators of heavy
// growth of the buffer.
} else if reuseCount >= r.maxReuse && bufLen > 0 {
now = time.Now()
duration = now.Sub(lastReset)
timeoutReached := duration >= r.resetTimeout
// The timeout has been reached and the
// buffered data couldn't be moved to the front
// of the buffer, so the buffer gets reset.
if timeoutReached && bufLen > reuseBufLen {
reset = true
}
// The amount of buffered data is too high now,
// reset the buffer.
if timeoutReached && maxBufLen >= r.bufLenResetThreshold {
reset = true
}
// Reset the buffer if a certain amount of
// data has gone through the buffer since the
// last reset.
if timeoutReached && dataSinceReset >= r.maxReadDataReset {
reset = true
}
// The buffered data is moved to a fresh buffer,
// swap the old buffer with the new one and
// reset all counters.
if reset {
newbuf := &bytes.Buffer{}
newbuf.ReadFrom(r.buf)
r.buf = newbuf
lastReset = now
reset = false
dataSinceReset = 0
maxBufLen = 0
reuseCount = 0
}
}
if err != nil {
r.err = err
} else {
r.buf.Write(r.drainBuf[0:n])
}
reuseCount++
r.wait.Signal()
r.Unlock()
if err != nil {

View File

@@ -32,3 +32,61 @@ func TestBufReader(t *testing.T) {
t.Error(string(output))
}
}
type repeatedReader struct {
readCount int
maxReads int
data []byte
}
func newRepeatedReader(max int, data []byte) *repeatedReader {
return &repeatedReader{0, max, data}
}
func (r *repeatedReader) Read(p []byte) (int, error) {
if r.readCount >= r.maxReads {
return 0, io.EOF
}
r.readCount++
n := copy(p, r.data)
return n, nil
}
func testWithData(data []byte, reads int) {
reader := newRepeatedReader(reads, data)
bufReader := NewBufReader(reader)
io.Copy(ioutil.Discard, bufReader)
}
func Benchmark1M10BytesReads(b *testing.B) {
reads := 1000000
readSize := int64(10)
data := make([]byte, readSize)
b.SetBytes(readSize * int64(reads))
b.ResetTimer()
for i := 0; i < b.N; i++ {
testWithData(data, reads)
}
}
func Benchmark1M1024BytesReads(b *testing.B) {
reads := 1000000
readSize := int64(1024)
data := make([]byte, readSize)
b.SetBytes(readSize * int64(reads))
b.ResetTimer()
for i := 0; i < b.N; i++ {
testWithData(data, reads)
}
}
func Benchmark10k32KBytesReads(b *testing.B) {
reads := 10000
readSize := int64(32 * 1024)
data := make([]byte, readSize)
b.SetBytes(readSize * int64(reads))
b.ResetTimer()
for i := 0; i < b.N; i++ {
testWithData(data, reads)
}
}

View File

@@ -64,6 +64,7 @@ func (config *Config) Read(p []byte) (n int, err error) {
return read, err
}
func (config *Config) Close() error {
config.Current = config.Size
config.Out.Write(config.Formatter.FormatProg(config.ID, config.Action, &JSONProg{Current: config.Current, Total: config.Size}))
return config.In.Close()
}

View File

@@ -3,7 +3,9 @@ package term
import (
"io"
"os"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/term/winconsole"
)
@@ -20,34 +22,49 @@ type Winsize struct {
y uint16
}
// GetWinsize gets the window size of the given terminal
func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
switch {
case os.Getenv("ConEmuANSI") == "ON":
// The ConEmu shell emulates ANSI well by default.
return os.Stdin, os.Stdout, os.Stderr
case os.Getenv("MSYSTEM") != "":
// MSYS (mingw) does not emulate ANSI well.
return winconsole.WinConsoleStreams()
default:
return winconsole.WinConsoleStreams()
}
}
// GetFdInfo returns file descriptor and bool indicating whether the file is a terminal.
func GetFdInfo(in interface{}) (uintptr, bool) {
return winconsole.GetHandleInfo(in)
}
// GetWinsize retrieves the window size of the terminal connected to the passed file descriptor.
func GetWinsize(fd uintptr) (*Winsize, error) {
ws := &Winsize{}
var info *winconsole.CONSOLE_SCREEN_BUFFER_INFO
info, err := winconsole.GetConsoleScreenBufferInfo(fd)
if err != nil {
return nil, err
}
ws.Width = uint16(info.Window.Right - info.Window.Left + 1)
ws.Height = uint16(info.Window.Bottom - info.Window.Top + 1)
ws.x = 0 // todo azlinux -- this is the pixel size of the Window, and not currently used by any caller
ws.y = 0
return ws, nil
// TODO(azlinux): Set the pixel width / height of the console (currently unused by any caller)
return &Winsize{
Width: uint16(info.Window.Right - info.Window.Left + 1),
Height: uint16(info.Window.Bottom - info.Window.Top + 1),
x: 0,
y: 0}, nil
}
// SetWinsize sets the terminal connected to the given file descriptor to a
// given size.
// SetWinsize sets the size of the given terminal connected to the passed file descriptor.
func SetWinsize(fd uintptr, ws *Winsize) error {
// TODO(azlinux): Implement SetWinsize
logrus.Debugf("[windows] SetWinsize: WARNING -- Unsupported method invoked")
return nil
}
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd uintptr) bool {
_, e := winconsole.GetConsoleMode(fd)
return e == nil
return winconsole.IsConsole(fd)
}
// RestoreTerminal restores the terminal connected to the given file descriptor to a
@@ -56,7 +73,7 @@ func RestoreTerminal(fd uintptr, state *State) error {
return winconsole.SetConsoleMode(fd, state.mode)
}
// SaveState saves the state of the given console
// SaveState saves the state of the terminal connected to the given file descriptor.
func SaveState(fd uintptr) (*State, error) {
mode, e := winconsole.GetConsoleMode(fd)
if e != nil {
@@ -65,54 +82,57 @@ func SaveState(fd uintptr) (*State, error) {
return &State{mode}, nil
}
// DisableEcho disbales the echo for given file descriptor and returns previous state
// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx for these flag settings
// DisableEcho disables echo for the terminal connected to the given file descriptor.
// -- See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx
func DisableEcho(fd uintptr, state *State) error {
state.mode &^= (winconsole.ENABLE_ECHO_INPUT)
state.mode |= (winconsole.ENABLE_PROCESSED_INPUT | winconsole.ENABLE_LINE_INPUT)
return winconsole.SetConsoleMode(fd, state.mode)
mode := state.mode
mode &^= winconsole.ENABLE_ECHO_INPUT
mode |= winconsole.ENABLE_PROCESSED_INPUT | winconsole.ENABLE_LINE_INPUT
// TODO(azlinux): Core code registers a goroutine to catch os.Interrupt and reset the terminal state.
return winconsole.SetConsoleMode(fd, mode)
}
// SetRawTerminal puts the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
// restored.
func SetRawTerminal(fd uintptr) (*State, error) {
oldState, err := MakeRaw(fd)
state, err := MakeRaw(fd)
if err != nil {
return nil, err
}
// TODO (azlinux): implement handling interrupt and restore state of terminal
return oldState, err
// TODO(azlinux): Core code registers a goroutine to catch os.Interrupt and reset the terminal state.
return state, err
}
// MakeRaw puts the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
// restored.
func MakeRaw(fd uintptr) (*State, error) {
var state *State
state, err := SaveState(fd)
if err != nil {
return nil, err
}
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx
// All three input modes, along with processed output mode, are designed to work together.
// It is best to either enable or disable all of these modes as a group.
// When all are enabled, the application is said to be in "cooked" mode, which means that most of the processing is handled for the application.
// When all are disabled, the application is in "raw" mode, which means that input is unfiltered and any processing is left to the application.
state.mode = 0
err = winconsole.SetConsoleMode(fd, state.mode)
// See
// -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
// -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx
mode := state.mode
// Disable these modes
mode &^= winconsole.ENABLE_ECHO_INPUT
mode &^= winconsole.ENABLE_LINE_INPUT
mode &^= winconsole.ENABLE_MOUSE_INPUT
mode &^= winconsole.ENABLE_WINDOW_INPUT
mode &^= winconsole.ENABLE_PROCESSED_INPUT
// Enable these modes
mode |= winconsole.ENABLE_EXTENDED_FLAGS
mode |= winconsole.ENABLE_INSERT_MODE
mode |= winconsole.ENABLE_QUICK_EDIT_MODE
err = winconsole.SetConsoleMode(fd, mode)
if err != nil {
return nil, err
}
return state, nil
}
// GetFdInfo returns file descriptor and bool indicating whether the file is a terminal
func GetFdInfo(in interface{}) (uintptr, bool) {
return winconsole.GetHandleInfo(in)
}
func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
return winconsole.StdStreams()
}

View File

@@ -12,18 +12,22 @@ import (
"sync"
"syscall"
"unsafe"
"github.com/Sirupsen/logrus"
)
const (
// Consts for Get/SetConsoleMode function
// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx
ENABLE_ECHO_INPUT = 0x0004
ENABLE_INSERT_MODE = 0x0020
ENABLE_LINE_INPUT = 0x0002
ENABLE_MOUSE_INPUT = 0x0010
// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
ENABLE_PROCESSED_INPUT = 0x0001
ENABLE_QUICK_EDIT_MODE = 0x0040
ENABLE_LINE_INPUT = 0x0002
ENABLE_ECHO_INPUT = 0x0004
ENABLE_WINDOW_INPUT = 0x0008
ENABLE_MOUSE_INPUT = 0x0010
ENABLE_INSERT_MODE = 0x0020
ENABLE_QUICK_EDIT_MODE = 0x0040
ENABLE_EXTENDED_FLAGS = 0x0080
// If parameter is a screen buffer handle, additional values
ENABLE_PROCESSED_OUTPUT = 0x0001
ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
@@ -97,27 +101,27 @@ const (
VK_HOME = 0x24 // HOME key
VK_LEFT = 0x25 // LEFT ARROW key
VK_UP = 0x26 // UP ARROW key
VK_RIGHT = 0x27 //RIGHT ARROW key
VK_DOWN = 0x28 //DOWN ARROW key
VK_SELECT = 0x29 //SELECT key
VK_PRINT = 0x2A //PRINT key
VK_EXECUTE = 0x2B //EXECUTE key
VK_SNAPSHOT = 0x2C //PRINT SCREEN key
VK_INSERT = 0x2D //INS key
VK_DELETE = 0x2E //DEL key
VK_HELP = 0x2F //HELP key
VK_F1 = 0x70 //F1 key
VK_F2 = 0x71 //F2 key
VK_F3 = 0x72 //F3 key
VK_F4 = 0x73 //F4 key
VK_F5 = 0x74 //F5 key
VK_F6 = 0x75 //F6 key
VK_F7 = 0x76 //F7 key
VK_F8 = 0x77 //F8 key
VK_F9 = 0x78 //F9 key
VK_F10 = 0x79 //F10 key
VK_F11 = 0x7A //F11 key
VK_F12 = 0x7B //F12 key
VK_RIGHT = 0x27 // RIGHT ARROW key
VK_DOWN = 0x28 // DOWN ARROW key
VK_SELECT = 0x29 // SELECT key
VK_PRINT = 0x2A // PRINT key
VK_EXECUTE = 0x2B // EXECUTE key
VK_SNAPSHOT = 0x2C // PRINT SCREEN key
VK_INSERT = 0x2D // INS key
VK_DELETE = 0x2E // DEL key
VK_HELP = 0x2F // HELP key
VK_F1 = 0x70 // F1 key
VK_F2 = 0x71 // F2 key
VK_F3 = 0x72 // F3 key
VK_F4 = 0x73 // F4 key
VK_F5 = 0x74 // F5 key
VK_F6 = 0x75 // F6 key
VK_F7 = 0x76 // F7 key
VK_F8 = 0x77 // F8 key
VK_F9 = 0x78 // F9 key
VK_F10 = 0x79 // F10 key
VK_F11 = 0x7A // F11 key
VK_F12 = 0x7B // F12 key
)
var kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
@@ -140,7 +144,12 @@ var (
// types for calling various windows API
// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms682093(v=vs.85).aspx
type (
SHORT int16
SHORT int16
BOOL int32
WORD uint16
WCHAR uint16
DWORD uint32
SMALL_RECT struct {
Left SHORT
Top SHORT
@@ -153,11 +162,6 @@ type (
Y SHORT
}
BOOL int32
WORD uint16
WCHAR uint16
DWORD uint32
CONSOLE_SCREEN_BUFFER_INFO struct {
Size COORD
CursorPosition COORD
@@ -192,6 +196,10 @@ type (
}
)
// TODO(azlinux): Basic type clean-up
// -- Convert all uses of uintptr to syscall.Handle to be consistent with Windows syscall
// -- Convert, as appropriate, types to use defined Windows types (e.g., DWORD instead of uint32)
// Implements the TerminalEmulator interface
type WindowsTerminal struct {
outMutex sync.Mutex
@@ -211,14 +219,14 @@ func getStdHandle(stdhandle int) uintptr {
return uintptr(handle)
}
func StdStreams() (stdIn io.ReadCloser, stdOut io.Writer, stdErr io.Writer) {
func WinConsoleStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
handler := &WindowsTerminal{
inputBuffer: make([]byte, MAX_INPUT_BUFFER),
inputEscapeSequence: []byte(KEY_ESC_CSI),
inputEvents: make([]INPUT_RECORD, MAX_INPUT_EVENTS),
}
if IsTerminal(os.Stdin.Fd()) {
if IsConsole(os.Stdin.Fd()) {
stdIn = &terminalReader{
wrappedReader: os.Stdin,
emulator: handler,
@@ -229,7 +237,7 @@ func StdStreams() (stdIn io.ReadCloser, stdOut io.Writer, stdErr io.Writer) {
stdIn = os.Stdin
}
if IsTerminal(os.Stdout.Fd()) {
if IsConsole(os.Stdout.Fd()) {
stdoutHandle := getStdHandle(syscall.STD_OUTPUT_HANDLE)
// Save current screen buffer info
@@ -241,8 +249,6 @@ func StdStreams() (stdIn io.ReadCloser, stdOut io.Writer, stdErr io.Writer) {
}
handler.screenBufferInfo = screenBufferInfo
// Set the window size
SetWindowSize(stdoutHandle, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_HEIGHT)
buffer = make([]CHAR_INFO, screenBufferInfo.MaximumWindowSize.X*screenBufferInfo.MaximumWindowSize.Y)
stdOut = &terminalWriter{
@@ -255,7 +261,7 @@ func StdStreams() (stdIn io.ReadCloser, stdOut io.Writer, stdErr io.Writer) {
stdOut = os.Stdout
}
if IsTerminal(os.Stderr.Fd()) {
if IsConsole(os.Stderr.Fd()) {
stdErr = &terminalWriter{
wrappedWriter: os.Stderr,
emulator: handler,
@@ -269,19 +275,21 @@ func StdStreams() (stdIn io.ReadCloser, stdOut io.Writer, stdErr io.Writer) {
return stdIn, stdOut, stdErr
}
// GetHandleInfo returns file descriptor and bool indicating whether the file is a terminal
// GetHandleInfo returns file descriptor and bool indicating whether the file is a console.
func GetHandleInfo(in interface{}) (uintptr, bool) {
var inFd uintptr
var isTerminalIn bool
switch t := in.(type) {
case *terminalReader:
in = t.wrappedReader
case *terminalWriter:
in = t.wrappedWriter
}
if file, ok := in.(*os.File); ok {
inFd = file.Fd()
isTerminalIn = IsTerminal(inFd)
}
if tr, ok := in.(*terminalReader); ok {
if file, ok := tr.wrappedReader.(*os.File); ok {
inFd = file.Fd()
isTerminalIn = IsTerminal(inFd)
}
isTerminalIn = IsConsole(inFd)
}
return inFd, isTerminalIn
}
@@ -314,12 +322,12 @@ func SetConsoleMode(handle uintptr, mode uint32) error {
// SetCursorVisible sets the cursor visbility
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms686019(v=vs.85).aspx
func SetCursorVisible(handle uintptr, isVisible BOOL) (bool, error) {
var cursorInfo CONSOLE_CURSOR_INFO
if err := getError(getConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(&cursorInfo)), 0)); err != nil {
var cursorInfo *CONSOLE_CURSOR_INFO = &CONSOLE_CURSOR_INFO{}
if err := getError(getConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)); err != nil {
return false, err
}
cursorInfo.Visible = isVisible
if err := getError(setConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(&cursorInfo)), 0)); err != nil {
if err := getError(setConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)); err != nil {
return false, err
}
return true, nil
@@ -404,25 +412,25 @@ func getNumberOfChars(fromCoord COORD, toCoord COORD, screenSize COORD) uint32 {
var buffer []CHAR_INFO
func clearDisplayRect(handle uintptr, fillChar rune, attributes WORD, fromCoord COORD, toCoord COORD, windowSize COORD) (uint32, error) {
func clearDisplayRect(handle uintptr, attributes WORD, fromCoord COORD, toCoord COORD) (uint32, error) {
var writeRegion SMALL_RECT
writeRegion.Top = fromCoord.Y
writeRegion.Left = fromCoord.X
writeRegion.Top = fromCoord.Y
writeRegion.Right = toCoord.X
writeRegion.Bottom = toCoord.Y
// allocate and initialize buffer
width := toCoord.X - fromCoord.X + 1
height := toCoord.Y - fromCoord.Y + 1
size := width * height
size := uint32(width) * uint32(height)
if size > 0 {
for i := 0; i < int(size); i++ {
buffer[i].UnicodeChar = WCHAR(fillChar)
buffer[i].Attributes = attributes
buffer := make([]CHAR_INFO, size)
for i := range buffer {
buffer[i] = CHAR_INFO{WCHAR(' '), attributes}
}
// Write to buffer
r, err := writeConsoleOutput(handle, buffer[:size], windowSize, COORD{X: 0, Y: 0}, &writeRegion)
r, err := writeConsoleOutput(handle, buffer, COORD{X: width, Y: height}, COORD{X: 0, Y: 0}, &writeRegion)
if !r {
if err != nil {
return 0, err
@@ -433,18 +441,18 @@ func clearDisplayRect(handle uintptr, fillChar rune, attributes WORD, fromCoord
return uint32(size), nil
}
func clearDisplayRange(handle uintptr, fillChar rune, attributes WORD, fromCoord COORD, toCoord COORD, windowSize COORD) (uint32, error) {
func clearDisplayRange(handle uintptr, attributes WORD, fromCoord COORD, toCoord COORD) (uint32, error) {
nw := uint32(0)
// start and end on same line
if fromCoord.Y == toCoord.Y {
return clearDisplayRect(handle, fillChar, attributes, fromCoord, toCoord, windowSize)
return clearDisplayRect(handle, attributes, fromCoord, toCoord)
}
// TODO(azlinux): if full screen, optimize
// spans more than one line
if fromCoord.Y < toCoord.Y {
// from start position till end of line for first line
n, err := clearDisplayRect(handle, fillChar, attributes, fromCoord, COORD{X: windowSize.X - 1, Y: fromCoord.Y}, windowSize)
n, err := clearDisplayRect(handle, attributes, fromCoord, COORD{X: toCoord.X, Y: fromCoord.Y})
if err != nil {
return nw, err
}
@@ -452,14 +460,14 @@ func clearDisplayRange(handle uintptr, fillChar rune, attributes WORD, fromCoord
// lines between
linesBetween := toCoord.Y - fromCoord.Y - 1
if linesBetween > 0 {
n, err = clearDisplayRect(handle, fillChar, attributes, COORD{X: 0, Y: fromCoord.Y + 1}, COORD{X: windowSize.X - 1, Y: toCoord.Y - 1}, windowSize)
n, err = clearDisplayRect(handle, attributes, COORD{X: 0, Y: fromCoord.Y + 1}, COORD{X: toCoord.X, Y: toCoord.Y - 1})
if err != nil {
return nw, err
}
nw += n
}
// lines at end
n, err = clearDisplayRect(handle, fillChar, attributes, COORD{X: 0, Y: toCoord.Y}, toCoord, windowSize)
n, err = clearDisplayRect(handle, attributes, COORD{X: 0, Y: toCoord.Y}, toCoord)
if err != nil {
return nw, err
}
@@ -489,7 +497,7 @@ func setConsoleCursorPosition(handle uintptr, isRelative bool, column int16, lin
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms683207(v=vs.85).aspx
func getNumberOfConsoleInputEvents(handle uintptr) (uint16, error) {
var n WORD
var n DWORD
if err := getError(getNumberOfConsoleInputEventsProc.Call(handle, uintptr(unsafe.Pointer(&n)))); err != nil {
return 0, err
}
@@ -498,7 +506,7 @@ func getNumberOfConsoleInputEvents(handle uintptr) (uint16, error) {
//http://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx
func readConsoleInputKey(handle uintptr, inputBuffer []INPUT_RECORD) (int, error) {
var nr WORD
var nr DWORD
if err := getError(readConsoleInputProc.Call(handle, uintptr(unsafe.Pointer(&inputBuffer[0])), uintptr(len(inputBuffer)), uintptr(unsafe.Pointer(&nr)))); err != nil {
return 0, err
}
@@ -587,6 +595,7 @@ func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte)
n = len(command)
parsedCommand := parseAnsiCommand(command)
logrus.Debugf("[windows] HandleOutputCommand: %v", parsedCommand)
// console settings changes need to happen in atomic way
term.outMutex.Lock()
@@ -632,16 +641,17 @@ func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte)
return n, err
}
if line > int16(screenBufferInfo.Window.Bottom) {
line = int16(screenBufferInfo.Window.Bottom)
line = int16(screenBufferInfo.Window.Bottom) + 1
}
column, err := parseInt16OrDefault(parsedCommand.getParam(1), 1)
if err != nil {
return n, err
}
if column > int16(screenBufferInfo.Window.Right) {
column = int16(screenBufferInfo.Window.Right)
column = int16(screenBufferInfo.Window.Right) + 1
}
// The numbers are not 0 based, but 1 based
logrus.Debugf("[windows] HandleOutputCommmand: Moving cursor to (%v,%v)", column-1, line-1)
if err := setConsoleCursorPosition(handle, false, column-1, line-1); err != nil {
return n, err
}
@@ -709,9 +719,9 @@ func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte)
switch value {
case 0:
start = screenBufferInfo.CursorPosition
// end of the screen
end.X = screenBufferInfo.MaximumWindowSize.X - 1
end.Y = screenBufferInfo.MaximumWindowSize.Y - 1
// end of the buffer
end.X = screenBufferInfo.Size.X - 1
end.Y = screenBufferInfo.Size.Y - 1
// cursor
cursor = screenBufferInfo.CursorPosition
case 1:
@@ -727,20 +737,21 @@ func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte)
// start of the screen
start.X = 0
start.Y = 0
// end of the screen
end.X = screenBufferInfo.MaximumWindowSize.X - 1
end.Y = screenBufferInfo.MaximumWindowSize.Y - 1
// end of the buffer
end.X = screenBufferInfo.Size.X - 1
end.Y = screenBufferInfo.Size.Y - 1
// cursor
cursor.X = 0
cursor.Y = 0
}
if _, err := clearDisplayRange(uintptr(handle), ' ', term.screenBufferInfo.Attributes, start, end, screenBufferInfo.MaximumWindowSize); err != nil {
if _, err := clearDisplayRange(uintptr(handle), term.screenBufferInfo.Attributes, start, end); err != nil {
return n, err
}
// remember the the cursor position is 1 based
if err := setConsoleCursorPosition(handle, false, int16(cursor.X), int16(cursor.Y)); err != nil {
return n, err
}
case "K":
// [K
// Clears all characters from the cursor position to the end of the line (including the character at the cursor position).
@@ -760,7 +771,7 @@ func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte)
// start is where cursor is
start = screenBufferInfo.CursorPosition
// end of line
end.X = screenBufferInfo.MaximumWindowSize.X - 1
end.X = screenBufferInfo.Size.X - 1
end.Y = screenBufferInfo.CursorPosition.Y
// cursor remains the same
cursor = screenBufferInfo.CursorPosition
@@ -776,15 +787,15 @@ func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte)
case 2:
// start of the line
start.X = 0
start.Y = screenBufferInfo.MaximumWindowSize.Y - 1
start.Y = screenBufferInfo.CursorPosition.Y - 1
// end of the line
end.X = screenBufferInfo.MaximumWindowSize.X - 1
end.Y = screenBufferInfo.MaximumWindowSize.Y - 1
end.X = screenBufferInfo.Size.X - 1
end.Y = screenBufferInfo.CursorPosition.Y - 1
// cursor
cursor.X = 0
cursor.Y = screenBufferInfo.MaximumWindowSize.Y - 1
cursor.Y = screenBufferInfo.CursorPosition.Y - 1
}
if _, err := clearDisplayRange(uintptr(handle), ' ', term.screenBufferInfo.Attributes, start, end, screenBufferInfo.MaximumWindowSize); err != nil {
if _, err := clearDisplayRange(uintptr(handle), term.screenBufferInfo.Attributes, start, end); err != nil {
return n, err
}
// remember the the cursor position is 1 based
@@ -1031,12 +1042,12 @@ func (term *WindowsTerminal) HandleInputSequence(fd uintptr, command []byte) (n
}
func marshal(c COORD) uintptr {
// works only on intel-endian machines
return uintptr(uint32(uint32(uint16(c.Y))<<16 | uint32(uint16(c.X))))
return uintptr(*((*DWORD)(unsafe.Pointer(&c))))
}
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd uintptr) bool {
// IsConsole returns true if the given file descriptor is a terminal.
// -- The code assumes that GetConsoleMode will return an error for file descriptors that are not a console.
func IsConsole(fd uintptr) bool {
_, e := GetConsoleMode(fd)
return e == nil
}

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